Android Firestore: grpc-javaのバグ

FlutterのプロジェクトでGoogle Playが入ってないエミュレータかつAndroid11で例外が発生するということをメンバーが見つけてくれました。

こんな感じのスタックトレースになってます。

W/GooglePlayServicesUtil( 3931): com.example.debug requires the Google Play Store, but it is missing.
E/GooglePlayServicesUtil( 3931): GooglePlayServices not available due to error 9
W/Firestore( 3931): (23.0.3) [GrpcCallProvider]: Failed to update ssl context: com.google.android.gms.common.GooglePlayServicesNotAvailableException
I/.learning.debu( 3931): NativeAlloc concurrent copying GC freed 68025(3478KB) AllocSpace objects, 17(532KB) LOS objects, 49% free, 3278KB/6556KB, paused 2.569ms total 126.063ms
W/.learning.debu( 3931): Accessing hidden method Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B (greylist-max-q,core-platform-api, reflection, denied)
W/.learning.debu( 3931): Accessing hidden method Lcom/android/org/conscrypt/AbstractConscryptSocket;->getAlpnSelectedProtocol()[B (greylist-max-q, reflection, denied)
E/AndroidRuntime( 3931): FATAL EXCEPTION: grpc-okhttp-0
E/AndroidRuntime( 3931): Process: com.example.debug, PID: 3931
E/AndroidRuntime( 3931): java.lang.AssertionError: Method getAlpnSelectedProtocol not supported for object SSL socket over Socket[address=firestore.googleapis.com/172.217.31.138,port=443,localPort=53942]
E/AndroidRuntime( 3931):    at io.grpc.okhttp.internal.OptionalMethod.invoke(OptionalMethod.java:114)
E/AndroidRuntime( 3931):    at io.grpc.okhttp.internal.OptionalMethod.invokeWithoutCheckedException(OptionalMethod.java:135)
E/AndroidRuntime( 3931):    at io.grpc.okhttp.OkHttpProtocolNegotiator$AndroidNegotiator.getSelectedProtocol(OkHttpProtocolNegotiator.java:183)
E/AndroidRuntime( 3931):    at io.grpc.okhttp.OkHttpProtocolNegotiator$AndroidNegotiator.negotiate(OkHttpProtocolNegotiator.java:145)
E/AndroidRuntime( 3931):    at io.grpc.okhttp.OkHttpTlsUpgrader.upgrade(OkHttpTlsUpgrader.java:63)
E/AndroidRuntime( 3931):    at io.grpc.okhttp.OkHttpClientTransport$4.run(OkHttpClientTransport.java:571)
E/AndroidRuntime( 3931):    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
E/AndroidRuntime( 3931):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/AndroidRuntime( 3931):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/AndroidRuntime( 3931):    at java.lang.Thread.run(Thread.java:923)
I/Process ( 3931): Sending signal. PID: 3931 SIG: 9
Lost connection to device.
Exited (sigterm)

playの入ってないエミュレータでもAndroid10なら例外は発生しませんでした。

リリースの必須要件にplayの定期購入があるので、気にしなくても大丈夫だと思いますが、 念の為調べました。

getAlpnSelectedProtocolはAndroid 11 からブロック対象

https://developer.android.com/about/versions/11/non-sdk-11?hl=ja

このメソッドがio.grpc.okhttpというパッケージで呼び出されているのが主な原因のようです。

該当箇所はここですね
https://github.com/grpc/grpc-java/blob/v1.28.x/okhttp/src/main/java/io/grpc/okhttp/OkHttpProtocolNegotiator.java#L183

ただ、playが入っているAndroid11でも例外が発生してもよさそう。

ログに出ているGrpcCallProviderとは

どうやらこの辺りの処理のようです。
firebase-android-sdk/GrpcCallProvider.java at ac3276ce7d5f5181b1c419731495eb88a98537af · firebase/firebase-android-sdk · GitHub

ここで呼び出されているinstallIfNeededというメソッドは下記で説明があります。
セキュリティ プロバイダを更新して SSL エクスプロイトから保護する  |  Android デベロッパー  |  Android Developers

ここだけ読んでも良くわかりませんが、どうやらSSLの強度を上げてくれるものっぽいですね。

grpc-java側でもOkHttpTlsUpgraderというクラスがありますが、 firebase sdk側の処理が失敗した時だけ動くんだと予想できます。

その辺りの詳細は調べ切れてませんが、下記のissueを辿っていけば grpc-javaの新しいバージョンで 新しいメソッドのgetApplicationProtocolが呼ばれるような修正が入っていることがわかります。 Crash due to use of getAlpnSelectedProtocol on Android 11 · Issue #7519 · grpc/grpc-java · GitHub

これに伴って、firebase sdk側もアップデートされてますので、 それを利用するようにすればOKなはずです。