diff options
| author | 2023-04-17 19:54:52 +0000 | |
|---|---|---|
| committer | 2023-04-17 19:54:52 +0000 | |
| commit | 0889fb51c230d2867f8fa3ccf4c8a9f51a8a3dcd (patch) | |
| tree | 7cb6ff8c81536a71cb8cf65bd39516c66c47e38c | |
| parent | e47c0ec08586b227b746622709d8e1434bc82905 (diff) | |
| parent | 0d775341acabae950eff92f336d57ddab2d03e0e (diff) | |
Merge "Retry face auth whenever there is a hardware error" into udc-dev
4 files changed, 92 insertions, 8 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt index 5f6098b8758f..05ab01bf2b9a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt @@ -140,8 +140,10 @@ constructor( private var authCancellationSignal: CancellationSignal? = null private var detectCancellationSignal: CancellationSignal? = null private var faceAcquiredInfoIgnoreList: Set<Int> + private var retryCount = 0 private var cancelNotReceivedHandlerJob: Job? = null + private var halErrorRetryJob: Job? = null private val _authenticationStatus: MutableStateFlow<AuthenticationStatus?> = MutableStateFlow(null) @@ -228,6 +230,8 @@ constructor( .onEach { goingAwayOrUserSwitchingInProgress -> if (goingAwayOrUserSwitchingInProgress) { _isAuthenticated.value = false + retryCount = 0 + halErrorRetryJob?.cancel() } } .launchIn(applicationScope) @@ -385,14 +389,11 @@ constructor( _authenticationStatus.value = errorStatus _isAuthenticated.value = false if (errorStatus.isCancellationError()) { - cancelNotReceivedHandlerJob?.cancel() - applicationScope.launch { - faceAuthLogger.launchingQueuedFaceAuthRequest( - faceAuthRequestedWhileCancellation - ) - faceAuthRequestedWhileCancellation?.let { authenticate(it) } - faceAuthRequestedWhileCancellation = null - } + handleFaceCancellationError() + } + if (errorStatus.isHardwareError()) { + faceAuthLogger.hardwareError(errorStatus) + handleFaceHardwareError() } faceAuthLogger.authenticationError( errorCode, @@ -418,6 +419,35 @@ constructor( } } + private fun handleFaceCancellationError() { + cancelNotReceivedHandlerJob?.cancel() + applicationScope.launch { + faceAuthRequestedWhileCancellation?.let { + faceAuthLogger.launchingQueuedFaceAuthRequest(it) + authenticate(it) + } + faceAuthRequestedWhileCancellation = null + } + } + + private fun handleFaceHardwareError() { + if (retryCount < HAL_ERROR_RETRY_MAX) { + retryCount++ + halErrorRetryJob?.cancel() + halErrorRetryJob = + applicationScope.launch { + delay(HAL_ERROR_RETRY_TIMEOUT) + if (retryCount < HAL_ERROR_RETRY_MAX) { + faceAuthLogger.attemptingRetryAfterHardwareError(retryCount) + authenticate( + FaceAuthUiEvent.FACE_AUTH_TRIGGERED_RETRY_AFTER_HW_UNAVAILABLE, + fallbackToDetection = false + ) + } + } + } + } + private fun onFaceAuthRequestCompleted() { cancellationInProgress = false _isAuthRunning.value = false @@ -558,6 +588,12 @@ constructor( * cancelled. */ const val DEFAULT_CANCEL_SIGNAL_TIMEOUT = 3000L + + /** Number of allowed retries whenever there is a face hardware error */ + const val HAL_ERROR_RETRY_MAX = 20 + + /** Timeout before retries whenever there is a HAL error. */ + const val HAL_ERROR_RETRY_TIMEOUT = 500L // ms } override fun dump(pw: PrintWriter, args: Array<out String>) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt index eded9c1454f2..c8bd958615cf 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt @@ -50,6 +50,11 @@ data class ErrorAuthenticationStatus(val msgId: Int, val msg: String?) : Authent * was cancelled before it completed. */ fun isCancellationError() = msgId == FaceManager.FACE_ERROR_CANCELED + + /** Method that checks if [msgId] is a hardware error. */ + fun isHardwareError() = + msgId == FaceManager.FACE_ERROR_HW_UNAVAILABLE || + msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS } /** Face detection success message. */ diff --git a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt index 7f6e4a903d76..efd3ad620de0 100644 --- a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt @@ -4,6 +4,7 @@ import android.hardware.face.FaceManager import android.hardware.face.FaceSensorPropertiesInternal import com.android.keyguard.FaceAuthUiEvent import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.log.dagger.FaceAuthLog import com.android.systemui.plugins.log.LogBuffer @@ -239,4 +240,25 @@ constructor( { "Requesting face auth for trigger: $str1" } ) } + + fun hardwareError(errorStatus: ErrorAuthenticationStatus) { + logBuffer.log( + TAG, + DEBUG, + { + str1 = "${errorStatus.msg}" + int1 = errorStatus.msgId + }, + { "Received face hardware error: $str1 , code: $int1" } + ) + } + + fun attemptingRetryAfterHardwareError(retryCount: Int) { + logBuffer.log( + TAG, + DEBUG, + { int1 = retryCount }, + { "Attempting face auth again because of HW error: retry attempt $int1" } + ) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt index fc75d47c01b7..a76d03b8ba93 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt @@ -21,6 +21,7 @@ import android.app.StatusBarManager.SESSION_KEYGUARD import android.content.pm.UserInfo import android.content.pm.UserInfo.FLAG_PRIMARY import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_CANCELED +import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT import android.hardware.biometrics.ComponentInfoInternal import android.hardware.face.FaceAuthenticateOptions @@ -824,6 +825,26 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { verify(faceManager).scheduleWatchdog() } + @Test + fun retryFaceIfThereIsAHardwareError() = + testScope.runTest { + initCollectors() + allPreconditionsToRunFaceAuthAreTrue() + + triggerFaceAuth(fallbackToDetect = false) + clearInvocations(faceManager) + + authenticationCallback.value.onAuthenticationError( + FACE_ERROR_HW_UNAVAILABLE, + "HW unavailable" + ) + + advanceTimeBy(DeviceEntryFaceAuthRepositoryImpl.HAL_ERROR_RETRY_TIMEOUT) + runCurrent() + + faceAuthenticateIsCalled() + } + private suspend fun TestScope.testGatingCheckForFaceAuth(gatingCheckModifier: () -> Unit) { initCollectors() allPreconditionsToRunFaceAuthAreTrue() |