getGenericPassword on Android sometimes fails and crashes app
getGenericPassword on android sometimes fails. I can't figure out why, it just crashes the app.
in my android it does not do anything code stopes on "await Keychain.getGenericPassword" and thats it
@jm90m @kriit24 Could you folks please share more info on your environments?
Android version, Keychain options that you pass to the getGenericPassword would help investigating the issue.
@jm90m @kriit24 Did you manage to find a fix for this?
Getting a similar experience as well but can't seem to figure out what exactly is causing it or how to reproduce.
Only hacky workaround that I could find is if I run async code before calling getGenericPassword() that forces a state update + some delay. Otherwise app freezes until I eventually get an "App isn't responding" alert.
Example:
setLoading(true);
await delay(500);
const credentials = await Keychain.getGenericPassword();
setLoading(false);
For more context:
- Android version
12 - react-native-keychain version
8.1.1 - Not passing any options to
getGenericPassword
Lmk if there's any other information I can give to debug this.
I've dug deeper into this issue and have been able to consistently reproduce it.
TLDR: It seems to occur when biometrics is triggered in the middle of unfinished UI navigation or rendering; which blocks the main thread and makes the app unresponsive and eventually it crashes.
Reproduction steps:
In an Android device try these:
- Invoke
Keychain.getGenericPassword - Without awaiting the promise, close the current screen and immediately navigate to a new screen that takes some time to render i.e. contains some UI operation.
- When the Biometrics prompt shows up, you'll notice in the overlay that the ongoing rendering in the background is already frozen.
- Either fail or pass the Biometrics. Both will crash the app.
Why?
Looking through the android device logs, I've seen this occur only in cases where biometrics is triggered in the middle of navigation/rendering or when a UI operation is in-progress but not complete, and then the biometrics prompt is presented just in time.
When the prompt is presented, the underlying logic blocks the main activity thread while waiting to capture user’s biometrics and this freezes the main thread in the middle of ongoing UI operation which leads to it being unresponsive even after user’s biometrics input is done.
And once it is frozen, regardless of the result – success or failure – the app always crashes.
Additionally, it is also susceptible to race conditions which makes it harder to reproduce. This means if the main thread UI operation completes quickly enough before the thread is frozen, it would work but otherwise, it always crashes.
Android Logs
Regular flow logs (no crash)
2022-09-19 00:22:50.226 25048-25048/com.myapp W/unknown:ReactContext: initializeMessageQueueThreads() is called.
2022-09-19 00:22:50.229 25048-25048/com.myapp D/SoLoader: libyoga.so found on /data/app/~~19AIo1aFY8KYmv5T_rODKg==/com.myapp-s7IQZfzxCAla_qyvQQRtLw==/lib/arm64
2022-09-19 00:22:50.229 25048-25048/com.myapp D/SoLoader: Not resolving dependencies for libyoga.so
2022-09-19 00:22:50.234 25048-25048/com.myapp I/DecorView: notifyKeepScreenOnChanged: keepScreenOn=false
2022-09-19 00:22:50.239 25048-25258/com.myapp I/ReactNativeJS: Running "myapp/ROUTE1" with {"initialProps":{"componentId":"myapp/ROUTE1"},"rootTag":1}
2022-09-19 00:22:50.249 25048-25048/com.myapp I/ViewRootImpl@5bc5c04[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=8 res=0x1 s={true 531055612176} ch=false fn=2
2022-09-19 00:22:50.266 25048-25048/com.myapp D/PhoneWindow: forceLight changed to false [com.myapp/com.myapp.MainActivity] from com.android.internal.policy.PhoneWindow.updateForceLightNavigationBar:4319 com.android.internal.policy.PhoneWindow.setNavigationBarColor:4011 com.reactnativenavigation.utils.SystemUiUtils.setNavigationBarBackgroundColor:165 com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter.setNavigationBarBackgroundColor:232 com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter.applyNavigationBarOptions:206
2022-09-19 00:22:50.266 25048-25048/com.myapp I/DecorView: notifyKeepScreenOnChanged: keepScreenOn=false
2022-09-19 00:22:50.278 25048-25048/com.myapp D/PhoneWindow: forceLight changed to true [com.myapp/com.myapp.MainActivity] from com.android.internal.policy.PhoneWindow.updateForceLightNavigationBar:4315 com.android.internal.policy.PhoneWindow.setNavigationBarColor:4011 com.reactnativenavigation.utils.SystemUiUtils.setNavigationBarBackgroundColor:165 com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter.setNavigationBarBackgroundColor:232 com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter.applyNavigationBarOptions:206
2022-09-19 00:22:50.279 25048-25048/com.myapp I/DecorView: notifyKeepScreenOnChanged: keepScreenOn=false
2022-09-19 00:22:50.363 25048-25048/com.myapp I/ViewRootImpl@5bc5c04[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=9 res=0x1 s={true 531055612176} ch=false fn=3
2022-09-19 00:22:50.371 25048-25048/com.myapp I/DecorView: notifyKeepScreenOnChanged: keepScreenOn=false
2022-09-19 00:22:50.410 25048-25048/com.myapp I/ViewRootImpl@5bc5c04[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=14 res=0x1 s={true 531055612176} ch=false fn=4
2022-09-19 00:22:50.686 25048-25048/com.myapp I/ViewRootImpl@5bc5c04[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=10 res=0x1 s={true 531055612176} ch=false fn=7
2022-09-19 00:22:50.693 25048-25048/com.myapp I/ReactNative: [GESTURE HANDLER] Initialize gesture handler for root view com.reactnativenavigation.react.ReactView{6e9054f V.E...... ......ID 0,0-1080,2154 #1}
---
2022-09-19 00:22:51.223 25048-25258/com.myapp I/ReactNativeJS: TEST --------------------------> GETTING BIOMETRICS SECRET
2022-09-19 00:22:52.276 25048-25258/com.myapp I/ReactNativeJS: TEST -> Invoking Keychain.getGenericPassword
---
2022-09-19 00:22:52.312 25048-25259/com.myapp W/CipherStorageBase: User not authenticated
android.security.keystore.UserNotAuthenticatedException: User not authenticated
at android.security.keystore2.KeyStoreCryptoOperationUtils.getInvalidKeyException(KeyStoreCryptoOperationUtils.java:128)
at android.security.keystore2.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:154)
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:345)
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:177)
at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:2984)
at javax.crypto.Cipher.tryCombinations(Cipher.java:2891)
at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider(Cipher.java:2796)
at javax.crypto.Cipher.chooseProvider(Cipher.java:773)
at javax.crypto.Cipher.init(Cipher.java:1143)
at javax.crypto.Cipher.init(Cipher.java:1084)
at com.oblador.keychain.cipherStorage.CipherStorageBase$Defaults.lambda$static$1(CipherStorageBase.java:533)
at com.oblador.keychain.cipherStorage.CipherStorageBase$Defaults$$ExternalSyntheticLambda0.initialize(Unknown Source:0)
at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:382)
at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:337)
at com.oblador.keychain.cipherStorage.CipherStorageKeystoreRsaEcb.decrypt(CipherStorageKeystoreRsaEcb.java:129)
at com.oblador.keychain.KeychainModule.decryptToResult(KeychainModule.java:679)
at com.oblador.keychain.KeychainModule.decryptCredentials(KeychainModule.java:646)
at com.oblador.keychain.KeychainModule.getGenericPassword(KeychainModule.java:306)
at com.oblador.keychain.KeychainModule.getGenericPasswordForOptions(KeychainModule.java:367)
at java.lang.reflect.Method.invoke(Native Method)
at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:188)
at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:228)
at java.lang.Thread.run(Thread.java:920)
2022-09-19 00:22:52.315 25048-25259/com.myapp D/CipherStorageBase: Unlock of keystore is needed. Error: User not authenticated
android.security.keystore.UserNotAuthenticatedException: User not authenticated
at android.security.keystore2.KeyStoreCryptoOperationUtils.getInvalidKeyException(KeyStoreCryptoOperationUtils.java:128)
at android.security.keystore2.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:154)
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:345)
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:177)
at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:2984)
at javax.crypto.Cipher.tryCombinations(Cipher.java:2891)
at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider(Cipher.java:2796)
at javax.crypto.Cipher.chooseProvider(Cipher.java:773)
at javax.crypto.Cipher.init(Cipher.java:1143)
at javax.crypto.Cipher.init(Cipher.java:1084)
at com.oblador.keychain.cipherStorage.CipherStorageBase$Defaults.lambda$static$1(CipherStorageBase.java:533)
at com.oblador.keychain.cipherStorage.CipherStorageBase$Defaults$$ExternalSyntheticLambda0.initialize(Unknown Source:0)
at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:382)
at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:337)
at com.oblador.keychain.cipherStorage.CipherStorageKeystoreRsaEcb.decrypt(CipherStorageKeystoreRsaEcb.java:129)
at com.oblador.keychain.KeychainModule.decryptToResult(KeychainModule.java:679)
at com.oblador.keychain.KeychainModule.decryptCredentials(KeychainModule.java:646)
at com.oblador.keychain.KeychainModule.getGenericPassword(KeychainModule.java:306)
at com.oblador.keychain.KeychainModule.getGenericPasswordForOptions(KeychainModule.java:367)
at java.lang.reflect.Method.invoke(Native Method)
at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:188)
at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:228)
at java.lang.Thread.run(Thread.java:920)
2022-09-19 00:22:52.321 25048-25259/com.myapp I/DecryptionResultHandlerInteractiveBiometric: blocking thread. waiting for done UI operation.
2022-09-19 00:22:52.575 25048-25048/com.myapp I/ViewRootImpl@5bc5c04[MainActivity]: MSG_WINDOW_FOCUS_CHANGED 0 1
2022-09-19 00:22:52.617 25048-25048/com.myapp D/InputTransport: Input channel destroyed: 'ClientS', fd=157
2022-09-19 00:22:57.978 25048-25070/com.myapp I/BiometricPrompt: onAuthenticationSucceeded: 2
2022-09-19 00:22:58.029 25048-25048/com.myapp D/InsetsSourceConsumer: ensureControlAlpha: for ITYPE_NAVIGATION_BAR on com.myapp/com.myapp.MainActivity
2022-09-19 00:22:58.030 25048-25048/com.myapp D/InsetsSourceConsumer: ensureControlAlpha: for ITYPE_STATUS_BAR on com.myapp/com.myapp.MainActivity
2022-09-19 00:22:58.045 25048-25048/com.myapp I/ViewRootImpl@5bc5c04[MainActivity]: MSG_WINDOW_FOCUS_CHANGED 1 1
2022-09-19 00:22:58.049 25048-25048/com.myapp D/InputMethodManager: startInputInner - Id : 0
2022-09-19 00:22:58.049 25048-25048/com.myapp I/InputMethodManager: startInputInner - mService.startInputOrWindowGainedFocus
2022-09-19 00:22:58.108 25048-25259/com.myapp I/DecryptionResultHandlerInteractiveBiometric: unblocking thread.
2022-09-19 00:22:58.109 25048-25258/com.myapp I/ReactNativeJS: 'TEST -> RESOLVED Keychain.getGenericPassword'
2022-09-19 00:22:58.110 25048-25258/com.myapp I/ReactNativeJS: '--------------------------> RETRIEVED BIOMETRICS SECRET', { result: 'cf86f6a6-743f-4307-b96e-eb00e2b35c7a' }
Logs during the crash
2022-09-18 23:32:22.096 11615-11615/com.myapp W/unknown:ReactContext: initializeMessageQueueThreads() is called.
2022-09-18 23:32:22.127 11615-11615/com.myapp I/ReactNative: [GESTURE HANDLER] Tearing down gesture handler registered for root view com.reactnativenavigation.react.ReactView{da7299e V.E...... ......ID 0,0-1080,2154 #51}
2022-09-18 23:32:22.129 11615-11615/com.myapp I/ReactNative: [GESTURE HANDLER] Tearing down gesture handler registered for root view com.reactnativenavigation.react.ReactView{4fcf8bb V.E...... ......ID 0,0-1080,2154 #5b}
2022-09-18 23:32:22.143 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=7 res=0x1 s={true 531055507536} ch=false fn=921
2022-09-18 23:32:22.145 11615-11826/com.myapp I/ReactNativeJS: Running "myapp/ROUTE1" with {"initialProps":{"componentId":"myapp/ROUTE1"},"rootTag":101}
2022-09-18 23:32:22.155 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=5 res=0x1 s={true 531055507536} ch=false fn=921
2022-09-18 23:32:22.188 11615-11615/com.myapp I/ReactNative: [GESTURE HANDLER] Initialize gesture handler for root view com.reactnativenavigation.react.ReactView{9a90135 V.E...... ......ID 0,0-1080,2154 #65}
2022-09-18 23:32:22.223 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=3 res=0x1 s={true 531055507536} ch=false fn=922
2022-09-18 23:32:22.234 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=5 res=0x1 s={true 531055507536} ch=false fn=923
2022-09-18 23:32:22.399 11615-11827/com.myapp D/RNKeychainManager: Probe cipher storage: CipherStorageFacebookConceal
2022-09-18 23:32:22.399 11615-11827/com.myapp D/RNKeychainManager: Probe cipher storage: CipherStorageKeystoreAesCbc
2022-09-18 23:32:22.399 11615-11827/com.myapp D/RNKeychainManager: Probe cipher storage: CipherStorageKeystoreRsaEcb
2022-09-18 23:32:22.399 11615-11827/com.myapp D/RNKeychainManager: Selected storage: CipherStorageKeystoreAesCbc
2022-09-18 23:32:22.412 11615-11827/com.myapp D/libmdf: libmdf v3.0.0.0 On 64bit PLATFORM
2022-09-18 23:32:22.611 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=9 res=0x1 s={true 531055507536} ch=false fn=945
---
2022-09-18 23:32:22.892 11615-11826/com.myapp I/ReactNativeJS: TEST --------------------------> GETTING BIOMETRICS SECRET
2022-09-18 23:32:22.918 11615-11826/com.myapp I/ReactNativeJS: TEST -> Invoking Keychain.getGenericPassword
---
2022-09-18 23:32:22.919 11615-11615/com.myapp W/unknown:ReactContext: initializeMessageQueueThreads() is called.
2022-09-18 23:32:22.919 11615-11826/com.myapp I/ReactNativeJS: Running "myapp/ROUTE2" with {"initialProps":{"componentId":"myapp/ROUTE2"},"rootTag":111}
---
2022-09-18 23:32:22.937 11615-11827/com.myapp W/CipherStorageBase: User not authenticated
android.security.keystore.UserNotAuthenticatedException: User not authenticated
at android.security.keystore2.KeyStoreCryptoOperationUtils.getInvalidKeyException(KeyStoreCryptoOperationUtils.java:128)
at android.security.keystore2.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:154)
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:345)
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:177)
at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:2984)
at javax.crypto.Cipher.tryCombinations(Cipher.java:2891)
at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider(Cipher.java:2796)
at javax.crypto.Cipher.chooseProvider(Cipher.java:773)
at javax.crypto.Cipher.init(Cipher.java:1143)
at javax.crypto.Cipher.init(Cipher.java:1084)
at com.oblador.keychain.cipherStorage.CipherStorageBase$Defaults.lambda$static$1(CipherStorageBase.java:533)
at com.oblador.keychain.cipherStorage.CipherStorageBase$Defaults$$ExternalSyntheticLambda0.initialize(Unknown Source:0)
at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:382)
at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:337)
at com.oblador.keychain.cipherStorage.CipherStorageKeystoreRsaEcb.decrypt(CipherStorageKeystoreRsaEcb.java:129)
at com.oblador.keychain.KeychainModule.decryptToResult(KeychainModule.java:679)
at com.oblador.keychain.KeychainModule.decryptCredentials(KeychainModule.java:646)
at com.oblador.keychain.KeychainModule.getGenericPassword(KeychainModule.java:306)
at com.oblador.keychain.KeychainModule.getGenericPasswordForOptions(KeychainModule.java:367)
at java.lang.reflect.Method.invoke(Native Method)
at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:188)
at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:228)
at java.lang.Thread.run(Thread.java:920)
2022-09-18 23:32:22.938 11615-11827/com.myapp D/CipherStorageBase: Unlock of keystore is needed. Error: User not authenticated
android.security.keystore.UserNotAuthenticatedException: User not authenticated
at android.security.keystore2.KeyStoreCryptoOperationUtils.getInvalidKeyException(KeyStoreCryptoOperationUtils.java:128)
at android.security.keystore2.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:154)
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:345)
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:177)
at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:2984)
at javax.crypto.Cipher.tryCombinations(Cipher.java:2891)
at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider(Cipher.java:2796)
at javax.crypto.Cipher.chooseProvider(Cipher.java:773)
at javax.crypto.Cipher.init(Cipher.java:1143)
at javax.crypto.Cipher.init(Cipher.java:1084)
at com.oblador.keychain.cipherStorage.CipherStorageBase$Defaults.lambda$static$1(CipherStorageBase.java:533)
at com.oblador.keychain.cipherStorage.CipherStorageBase$Defaults$$ExternalSyntheticLambda0.initialize(Unknown Source:0)
at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:382)
at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:337)
at com.oblador.keychain.cipherStorage.CipherStorageKeystoreRsaEcb.decrypt(CipherStorageKeystoreRsaEcb.java:129)
at com.oblador.keychain.KeychainModule.decryptToResult(KeychainModule.java:679)
at com.oblador.keychain.KeychainModule.decryptCredentials(KeychainModule.java:646)
at com.oblador.keychain.KeychainModule.getGenericPassword(KeychainModule.java:306)
at com.oblador.keychain.KeychainModule.getGenericPasswordForOptions(KeychainModule.java:367)
at java.lang.reflect.Method.invoke(Native Method)
at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:188)
at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:228)
at java.lang.Thread.run(Thread.java:920)
2022-09-18 23:32:22.940 11615-11827/com.myapp I/DecryptionResultHandlerInteractiveBiometric: blocking thread. waiting for done UI operation.
2022-09-18 23:32:23.035 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=9 res=0x1 s={true 531055507536} ch=false fn=961
2022-09-18 23:32:23.072 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=9 res=0x1 s={true 531055507536} ch=false fn=962
2022-09-18 23:32:23.251 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: MSG_WINDOW_FOCUS_CHANGED 0 1
2022-09-18 23:32:23.289 11615-11615/com.myapp D/InputTransport: Input channel destroyed: 'ClientS', fd=215
2022-09-18 23:32:26.715 11615-11899/com.myapp I/BiometricPrompt: onAuthenticationSucceeded: 2
2022-09-18 23:32:37.423 11615-11620/com.myapp I/com.myapp: Thread[4,tid=11620,WaitingInMainSignalCatcherLoop,Thread*=0x7b956236a0,peer=0x15f00228,"Signal Catcher"]: reacting to signal 3
2022-09-18 23:32:37.423 11615-11620/com.myapp I/com.myapp:
2022-09-18 23:32:37.846 11615-11620/com.myapp I/com.myapp: Wrote stack traces to tombstoned
You can see in that there are 2 main differences in the above logs:
- In both cases,
onAuthenticationSucceededhandler was triggered. But in the second case, you cannot see the thread being unblocked after that. The entryunblocking thread.is seen only in the first case. - In the second case you can see a UI rendering started right after the
getGenericPasswordcall from this lineReactContext: initializeMessageQueueThreads() is called. This is the cause of this unresponsiveness as the main thread didn't get chance to complete it before it was blocked.
Same problem occurs in our app on Android. No particular version - seems to occur on any device.
We reproduce it like so:
import Keychain from 'react-native-keychain';
async function getBiometryPassword() {
console.log(1);
/*
// Optionally, we can block the thread for a couple of seconds,
// just to not have to be quick with minimizing the app.
const start = Date.now();
while (Date.now() < start + 2000) {}
console.log(2);
*/
const value = await Keychain.getGenericPassword({
service: 'our-bio-password-key',
accessible: Keychain.ACCESSIBLE.WHEN_PASSCODE_SET_THIS_DEVICE_ONLY,
securityLevel: Keychain.SECURITY_LEVEL.SECURE_HARDWARE,
accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_CURRENT_SET,
authenticationType: Keychain.AUTHENTICATION_TYPE.BIOMETRICS
}).catch(error => {
console.log(3);
throw error;
});
console.log(4);
return value;
}
If you start the app, call getBiometryPassword and immediately minimize the app (gotta be quick), then open back, you get only 1 & 2(optionally) printed to the console, and the app is frozen.
Also, we don't get app state change event fired (handleAppStateChange called) in this case.
import { AppState } from 'react-native';
AppState.addEventListener('change', handleAppStateChange);
I'm having the same issue. As soon as I call getGenericPassword the app freezes and a few seconds later "App not responding" pop-up shows up! This is a serious issue guys!
This will help https://www.youtube.com/watch?v=J0OSn7s9YiA&list=PLQhQEGkwKZUrempLnmxjt7ZCZJu1W3p2i&index=15
@BraveEvidence Thanks, I'll take a look at it for sure but the thing is I had to prepare a release for pen-testing so wouldn't have time to deal with this stuff :/ thanks to @hazim-j the solution he found worked for me!
@tsdmrfth what was the fix ?
This is happening for me as well - dev and prod - unsure of what the conditions are, but it typically seems to hang most if called relatively quickly after an app background -> foreground . Killing the app and restarting always fixes the issue.