Android 8.1 Unable to create application data 问题分析

崩溃堆栈

1
java.lang.RuntimeException:javax.net.ssl.SSLException: Unable to create application data
2
com.android.org.conscrypt.ConscryptFileDescriptorSocket.newSsl(ConscryptFileDescriptorSocket.java:161)
3
......
4
Caused by:
5
javax.net.ssl.SSLException:Unable to create application data
6
com.android.org.conscrypt.NativeCrypto.SSL_new(Native Method)
7
com.android.org.conscrypt.SslWrapper.newInstance(SslWrapper.java:58)
8
com.android.org.conscrypt.ConscryptFileDescriptorSocket.newSsl(ConscryptFileDescriptorSocket.java:159)
9
com.android.org.conscrypt.ConscryptFileDescriptorSocket.<init>(ConscryptFileDescriptorSocket.java:152)
10
com.android.org.conscrypt.OpenSSLSocketFactoryImpl.createSocket(OpenSSLSocketFactoryImpl.java:155)
11
okhttp3.internal.connection.RealConnection.void connectTls(okhttp3.internal.connection.ConnectionSpecSelector)(RealConnection.java:369)
12
okhttp3.internal.connection.RealConnection.void establishProtocol(okhttp3.internal.connection.ConnectionSpecSelector,int,okhttp3.Call,okhttp3.EventListener)(RealConnection.java:337)
13
okhttp3.internal.connection.RealConnection.void connect(int,int,int,int,boolean,okhttp3.Call,okhttp3.EventListener)(RealConnection.java:209)
14
okhttp3.internal.connection.ExchangeFinder.okhttp3.internal.connection.RealConnection findConnection(int,int,int,int,boolean)(ExchangeFinder.java:226)
15
okhttp3.internal.connection.ExchangeFinder.okhttp3.internal.connection.RealConnection findHealthyConnection(int,int,int,int,boolean,boolean)(ExchangeFinder.java:106)
16
okhttp3.internal.connection.ExchangeFinder.okhttp3.internal.http.ExchangeCodec find(okhttp3.OkHttpClient,okhttp3.internal.http.RealInterceptorChain)(ExchangeFinder.java:74)
17
okhttp3.internal.connection.RealCall.okhttp3.internal.connection.Exchange initExchange$okhttp(okhttp3.internal.http.RealInterceptorChain)(RealCall.java:255)
18
okhttp3.internal.connection.ConnectInterceptor.okhttp3.Response intercept(okhttp3.Interceptor$Chain)(ConnectInterceptor.java:32)
19
okhttp3.internal.http.RealInterceptorChain.okhttp3.Response proceed(okhttp3.Request)(RealInterceptorChain.java:109)
20
okhttp3.internal.cache.CacheInterceptor.okhttp3.Response intercept(okhttp3.Interceptor$Chain)(CacheInterceptor.java:95)
21
okhttp3.internal.http.RealInterceptorChain.okhttp3.Response proceed(okhttp3.Request)(RealInterceptorChain.java:109)
22
okhttp3.internal.http.BridgeInterceptor.okhttp3.Response intercept(okhttp3.Interceptor$Chain)(BridgeInterceptor.java:83)
23
okhttp3.internal.http.RealInterceptorChain.okhttp3.Response proceed(okhttp3.Request)(RealInterceptorChain.java:109)
24
okhttp3.internal.http.RetryAndFollowUpInterceptor.okhttp3.Response intercept(okhttp3.Interceptor$Chain)(RetryAndFollowUpInterceptor.java:76)
25
okhttp3.internal.http.RealInterceptorChain.okhttp3.Response proceed(okhttp3.Request)(RealInterceptorChain.java:109)
26
okhttp3.logging.HttpLoggingInterceptor.okhttp3.Response intercept(okhttp3.Interceptor$Chain)(HttpLoggingInterceptor.java:219)
27
okhttp3.internal.http.RealInterceptorChain.okhttp3.Response proceed(okhttp3.Request)(RealInterceptorChain.java:109)
28
okhttp3.internal.connection.RealCall.okhttp3.Response getResponseWithInterceptorChain$okhttp()(RealCall.java:201)
29
okhttp3.internal.connection.RealCall$AsyncCall.void run()(RealCall.java:517)
30
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
31
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
32
java.lang.Thread.run(Thread.java:784)

分析

看安卓8.1的源码,ConscryptFileDescriptorSocket创建SslWrapper,所有SSL异常都被封装成了运行时异常,导致在拦截器里执行时无法catch直接崩溃:

https://android.googlesource.com/platform/external/conscrypt/+/refs/tags/android-8.1.0_r12/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java

    private static SslWrapper newSsl(SSLParametersImpl sslParameters,
            ConscryptFileDescriptorSocket engine) {
        try {
            return SslWrapper.newInstance(sslParameters, engine, engine, engine);
        } catch (SSLException e) {
            throw new RuntimeException(e);
        }
    }

SslWrapper实例化涉及NativeCrypto,依赖C++代码:

https://android.googlesource.com/platform/external/conscrypt/+/refs/tags/android-8.1.0_r12/common/src/main/java/org/conscrypt/SslWrapper.java

    static SslWrapper newInstance(SSLParametersImpl parameters,
            SSLHandshakeCallbacks handshakeCallbacks, AliasChooser chooser,
            PSKCallbacks pskCallbacks) throws SSLException {
        long ctx = parameters.getSessionContext().sslCtxNativePointer;
        long ssl = NativeCrypto.SSL_new(ctx);
        return new SslWrapper(ssl, parameters, handshakeCallbacks, chooser, pskCallbacks);
    }

新版本:

https://android.googlesource.com/platform/external/conscrypt/+/refs/tags/android-cts-9.0_r18/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java

    private static NativeSsl newSsl(SSLParametersImpl sslParameters,
            ConscryptFileDescriptorSocket engine) throws SSLException {
        return NativeSsl.newInstance(sslParameters, engine, engine, engine);
    }

可用的修复方案

https://stackoverflow.com/questions/55143564/anr-and-crash-in-an-android-app-android-8-1-90-huawei-devices

方案中直接依赖了:

implementation 'org.conscrypt:conscrypt-android:2.5.2'

启动时初始化:

if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1) {
    Security.insertProviderAt(Conscrypt.newProvider(), 1);
    Log.e("sslProvider", SSLSocketFactory.getDefault()::class.java.getName())
}

方案会引入新的so,三个架构so总共7.75m,平均一个2.5m,修复这个bug的代价是安装包总体变大。

然而这个crash对crash率贡献量较小,有点不划算。

更新

对拦截器进行包装,将运行时异常转化成IO异常。

class Android81RuntimeExceptionHandlerWrapperInterceptor private constructor(
    private val interceptor: Interceptor
) : Interceptor {
    companion object {
        private const val TAG = "Android81RuntimeExceptionHandlerWrapperInterceptor"

        fun Interceptor.wrappedIssue7792484(): Interceptor {
            return Android81RuntimeExceptionHandlerWrapperInterceptor(this)
        }
    }

    override fun intercept(chain: Interceptor.Chain): Response {
        try {
            return interceptor.intercept(chain)
        } catch (e: RuntimeException) {
            val cause = e.cause
            if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1 && cause is SSLException) {
                HLLog.e(TAG, "Caught and converted Android 8.1 SSL RuntimeException")
                throw IOException("SSL handshake failed on Android 8.1", e)
            } else {
                throw e
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值