okhttp: ExceptionInitializerError with new Android 11 version (DP1)

OKHTTP 3.14.4 Retrofit 2.7.1 Device: Pixel 3 XL Android Build: crosshatch-rpp1.200123.016-factory-5808a1e6.zip

Note: Issue is not reproducible on Android 10 or earlier versions.

Found this issue when running my sample app using latest version of Retrofit (2.7.1) and targeting newly released Android 11 (targetSdkVersion = 30).

When attempting to run the app in Android 11, the app immediately crashes with the following exception:

2020-02-20 14:26:08.386 22962-22962/com.my.example.retrofit2 E/AndroidRuntime: FATAL EXCEPTION: main Process: com.my.example.retrofit2, PID: 22962 java.lang.ExceptionInInitializerError at okhttp3.internal.platform.Platform.get(Platform.java:85) at okhttp3.OkHttpClient.newSslSocketFactory(OkHttpClient.java:263) at okhttp3.OkHttpClient.<init>(OkHttpClient.java:229) at okhttp3.OkHttpClient.<init>(OkHttpClient.java:202) at retrofit2.Retrofit$Builder.build(Retrofit.java:614) at com.my.example.retrofit2.network.RetrofitInstance.getRetrofitInstance(RetrofitInstance.java:37) at com.my.example.retrofit2.main.IntractorImpl.getMarsPhotosArrayList(IntractorImpl.java:21) at com.my.example.retrofit2.main.MainPresenterImpl.requestDataFromServer(MainPresenterImpl.java:29) at com.my.example.retrofit2.main.MainActivity.onCreate(MainActivity.java:37) at android.app.Activity.performCreate(Activity.java:7970) at android.app.Activity.performCreate(Activity.java:7959) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3311) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3480) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2041) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:216) at android.app.ActivityThread.main(ActivityThread.java:7472) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:956) Caused by: java.lang.IllegalStateException: Expected Android API level 21+ but was 29 at okhttp3.internal.platform.AndroidPlatform.buildIfSupported(AndroidPlatform.java:238) at okhttp3.internal.platform.Platform.findPlatform(Platform.java:202) at okhttp3.internal.platform.Platform.<clinit>(Platform.java:79) at okhttp3.internal.platform.Platform.get(Platform.java:85)  at okhttp3.OkHttpClient.newSslSocketFactory(OkHttpClient.java:263)  at okhttp3.OkHttpClient.<init>(OkHttpClient.java:229)  at okhttp3.OkHttpClient.<init>(OkHttpClient.java:202)  at retrofit2.Retrofit$Builder.build(Retrofit.java:614)  at com.my.example.retrofit2.network.RetrofitInstance.getRetrofitInstance(RetrofitInstance.java:37)  at com.my.example.retrofit2.main.IntractorImpl.getMarsPhotosArrayList(IntractorImpl.java:21)  at com.my.example.retrofit2.main.MainPresenterImpl.requestDataFromServer(MainPresenterImpl.java:29)  at com.my.example.retrofit2.main.MainActivity.onCreate(MainActivity.java:37)  at android.app.Activity.performCreate(Activity.java:7970)  at android.app.Activity.performCreate(Activity.java:7959)  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3311)  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3480)  at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)  at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)  at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2041)  at android.os.Handler.dispatchMessage(Handler.java:106)  at android.os.Looper.loop(Looper.java:216)  at android.app.ActivityThread.main(ActivityThread.java:7472)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:956)

My retrofit code is very simple and not attempting to do any custom initialization or setting a different OKHTTP client (see code for reference below):

`    public static Retrofit getRetrofitInstance(){

        if(retrofit == null){
            retrofit = new retrofit2.Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }

        return retrofit;
    }`

After doing some digging into the OKHTTP code, noticed the following warning coming from adb logcat:

2020-02-20 14:26:08.382 22962-22962/com.my.example.retrofit2 D/NetworkSecurityConfig: No Network Security Config specified, using platform default 2020-02-20 14:26:08.384 22962-22962/com.my.example.retrofit2 W/DebugTag: Accessing hidden method Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setUseSessionTickets(Z)V (greylist-max-q,core-platform-api, reflection, denied)

Per official documentation found here, Android 11 no longer allows Reflection API calls to setUseSessionTickets, which appears to be used in a few places when initializing AndroidSocketAdapter:

https://github.com/square/okhttp/blob/ff0dee1c34fc06084357c93dc480f6ad89fef24a/okhttp/src/main/java/okhttp3/internal/platform/android/AndroidSocketAdapter.kt#L34

Looking at the other reflection calls done in the AndroidSocketAdapter, the following methods have also been blacklisted in Android 11 and will cause exceptions to be thrown:

1.   private val getAlpnSelectedProtocol = sslSocketClass.getMethod("getAlpnSelectedProtocol")
2.   private val setHostname = sslSocketClass.getMethod("setHostname", String::class.java)

Looks like OKHTTP will need to avoid these reflection calls and instead use available public APIs in Android 11 where applicable. Until then, applications may experience Fatal Runtime Exceptions when initializing OKHTTP. I noticed there is an Android10SocketAdapter, perhaps whats needed here would be an Android11SocketAdapter with specific implementation around these changes?

Let me know if more information is needed.

Best, Alex

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 4
  • Comments: 18 (7 by maintainers)

Most upvoted comments

In addition to the two others mentioned setHostname and getAlpnSelectedProtocol, setAlpnProtocols is used which is also on the list.

Their replacements are:

Lcom/android/org/conscrypt/AbstractConscryptSocket;->getAlpnSelectedProtocol()[B   # Use javax.net.ssl.SSLSocket#getApplicationProtocol().
Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setHostname(Ljava/lang/String;)V   # Use javax.net.ssl.SSLParameters#setServerNames.
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setAlpnProtocols([Ljava/lang/String;)V   # Use javax.net.ssl.SSLParameters#setApplicationProtocols(java.lang.String[]).

The ALPN ones are a direct replacement, the setHostname one is a bit more complicated.

migrating to 4.4.0 has fixed the issue

Might need to do 3.12.x also!

@arocha55 Can you provide a stacktrace of the failure from 4.4.0. It worked fine for me (after fixing a few tests).

I suspect the fix situation is

  1. OkHttp 4.4.0 - working
  2. OkHttp 3.14.4 - failing but requires big backport, or simple fix to disable Android awareness on Android R+ for 3.14 branch.