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というパッケージで呼び出されているのが主な原因のようです。
ただ、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なはずです。