Status Update
Comments
kc...@google.com <kc...@google.com> #2
java.security.ProviderException: Keystore operation failed
at android.security.keystore.AndroidKeyStoreKeyGeneratorSpi.engineGenerateKey(AndroidKeyStoreKeyGeneratorSpi.java:386)
at javax.crypto.KeyGenerator.generateKey(KeyGenerator.java:612)
at androidx.biometric.CryptoObjectUtils.createFakeCryptoObject(CryptoObjectUtils.java:256)
at androidx.biometric.BiometricManager.canAuthenticateWithStrongBiometricOnApi29(BiometricManager.java:419)
at androidx.biometric.BiometricManager.canAuthenticateCompat(BiometricManager.java:386)
at {packageName}.fingerprint.BiometricUtils.getBiometricSupportLevelForLogin(BiometricUtils.java:3343)
at androidx.biometric.BiometricManager.canAuthenticate(BiometricManager.java:343)
at {packageName}.fingerprint.BiometricUtils.getBiometricSupportLevelForLogin(BiometricUtils.java:19)
at {packageName}.domain.biometrics.GetBiometricsSupportForLoginInteractor.execute(GetBiometricsSupportForLoginInteractor.java:13)
at {packageName}.ui.settings.SettingsViewModel$$special$$inlined$apply$lambda$1$1.invoke(SettingsViewModel.java:85)
at {packageName}.ui.settings.SettingsViewModel$$special$$inlined$apply$lambda$1$1.invokeSuspend(SettingsViewModel.java:85)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(BaseContinuationImpl.java:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.java:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.submitToLocalQueue(CoroutineScheduler.java:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.java:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.java:9738)
Caused by: android.security.KeyStoreException: 16
at android.security.KeyStore.getKeyStoreException(KeyStore.java:1552)
at android.security.keystore.AndroidKeyStoreKeyGeneratorSpi.engineGenerateKey(AndroidKeyStoreKeyGeneratorSpi.java:386)
at javax.crypto.KeyGenerator.generateKey(KeyGenerator.java:612)
at androidx.biometric.CryptoObjectUtils.createFakeCryptoObject(CryptoObjectUtils.java:256)
at androidx.biometric.BiometricManager.canAuthenticateWithStrongBiometricOnApi29(BiometricManager.java:419)
at androidx.biometric.BiometricManager.canAuthenticateCompat(BiometricManager.java:386)
at {packageName}.fingerprint.BiometricUtils.getBiometricSupportLevelForLogin(BiometricUtils.java:3343)
at androidx.biometric.BiometricManager.canAuthenticate(BiometricManager.java:343)
at {packageName}.fingerprint.BiometricUtils.getBiometricSupportLevelForLogin(BiometricUtils.java:19)
at {packageName}.domain.biometrics.GetBiometricsSupportForLoginInteractor.execute(GetBiometricsSupportForLoginInteractor.java:13)
at {packageName}.ui.settings.SettingsViewModel$$special$$inlined$apply$lambda$1$1.invoke(SettingsViewModel.java:85)
at {packageName}.ui.settings.SettingsViewModel$$special$$inlined$apply$lambda$1$1.invokeSuspend(SettingsViewModel.java:85)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(BaseContinuationImpl.java:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.java:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.submitToLocalQueue(CoroutineScheduler.java:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.java:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.java:9738)
ga...@gtempaccount.com <ga...@gtempaccount.com> #3
Again: Android: 10 Android Build: QP1A.190711.020 Manufacturer: samsung Model: SM-G781W
It seems that this issue happens on Samsung phones running Android 10.
kc...@google.com <kc...@google.com> #4
I was able to reproduce the same issue using a Samsung Galaxy S20 running Android 10.
Basically, what I have to do to reproduce this issue was to register only Face Recognition (which is a weak authenticator) in the phone and then try to use the app that I'm implementing.
As soon as I registered a Fingerprint in the device, I was not able to reproduce this issue anymore.
Also, I've noticed that my app was also calling the same method twice because of the logic that I had on my observables.
In summary, the issue with BiometricManager.canAuthenticate(BIOMETRIC_STRONG)
is easier to reproduce if the method is called more than once in a row and on a Samsung phone with only Face Recognition registered.
I don't think that calling the method multiple times is the root cause of this issue, but I think it makes easier to the reproduce the issue. Possibly, the error occurs because the biometrics framework is not ready/busy to process the request and returns a KeyStoreException: 16
.
ga...@gtempaccount.com <ga...@gtempaccount.com> #5
kc...@google.com <kc...@google.com> #6
ga...@gtempaccount.com <ga...@gtempaccount.com> #7
kc...@google.com <kc...@google.com> #8
The ERROR_TIMEOUT message isn't propagated by the framework to the android.hardware.BiometricPrompt API (and thus also not propagated to BiometricX library)
It should be safe to say that any error received through onAuthenticationError API will be a terminal state (e.g. BiometricX will dismiss the dialog).
It should also be safe to say that ERROR_TIMEOUT will never be received by clients of BiometricX
Let me know if the above helps. Below is a more in-depth answer regarding ERROR_TIMEOUT:
ERROR_TIMEOUT is defined in the fingerprint HIDL interface (android framework's interface to the fingerprint sensor). FingerprintManager's API was a very thin API that provided basic lifecycle wrapping of the HIDL interface, thus ERROR_TIMEOUT was passed to clients. BiometricPrompt extends the functionality of FingerprintManager, and other biometric modalities such as face, in-display fingerprint, by providing a system UI. In providing a system ui, the system also takes care of the ERROR_TIMEOUT that the hardware/sensor emits. Thus, for BiometricPrompt, this error makes no sense.
We'll re-purpose this bug to ensure that ERROR_TIMEOUT is handled properly by the support library and not propagated to the client, to avoid ambiguous behavior between the current API and its documentation.
kc...@google.com <kc...@google.com> #9
I'm not aware of any capacitive fingerprint devices that emit this value, we can probably check in the dashboards that Josh has. Let's discuss when you have a few cycles
Description
Called when a recoverable error has been encountered during authentication. The help string is provided to give the user guidance for what went wrong, such as "Sensor dirty, please clean it."
open fun onAuthenticationError(errorCode: Int, errString: CharSequence!): Unit
Called when an unrecoverable error has been encountered and the operation is complete. No further actions will be made on this object.
Only the latter is in the support lib, not the former. If they are merged, please correct the documentation to state that.