Okhttp: ExceptionInitializerError with new Android 11 version (DP1)

Created on 21 Feb 2020  路  18Comments  路  Source: square/okhttp

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.(OkHttpClient.java:229)
at okhttp3.OkHttpClient.(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.(Platform.java:79)
at okhttp3.internal.platform.Platform.get(Platform.java:85)聽
at okhttp3.OkHttpClient.newSslSocketFactory(OkHttpClient.java:263)聽
at okhttp3.OkHttpClient.(OkHttpClient.java:229)聽
at okhttp3.OkHttpClient.(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

bug

All 18 comments

Thank you for the very detailed report!

You are very welcome 馃憤

@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.

n.b. We don't have a robolectric preview release yet, so the ideal codepath is off limits. Currently we use an alternative code path via android.net.SSLCertificateSocketFactory

https://github.com/robolectric/robolectric/tags

@swankjesse I'm not keen to backport a lot of code to 3.14. I'll use SSLSockets public API via reflection in AndroidPlatform on R+?

https://github.com/square/okhttp/blob/okhttp_3.14.x/okhttp/src/main/java/okhttp3/internal/platform/AndroidPlatform.java

Yep. Seems like the best fix.

Might need to do 3.12.x also!

migrating to 4.4.0 has fixed the issue

Thanks for looking into this so quickly!

Confirmed, in 4.4.0 things are working, issue is seen in 3.14.4 which is what Retrofit2 is using atm.

Best,
Alex

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.

Likewise the other methods are now accessible without reflection

I only cross referenced the offending usage from 3.x to the list of public replacements. Didn't look at 4.x.

Yep, thanks for the guidance.

This PR should fix it for 3.14.x, and I'll work on 3.12.x

https://github.com/square/okhttp/pull/5820/files

Fixed in 3.14.7 and 3.12.9.

I have the same problem running my app targeted to API 30 on API 30 emulator. I am not using OkHttp3 directly, but some third party libs in my gradle config use it. Is it possible to override OkHttp3 version from 3.X.X to 4.4 or higher in gradle config?

Yes it is!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

HyakYegoryaln picture HyakYegoryaln  路  3Comments

sargunv picture sargunv  路  3Comments

SandroMachado picture SandroMachado  路  3Comments

nikunjgundaniya picture nikunjgundaniya  路  3Comments

yschimke picture yschimke  路  3Comments