Merge "Retry face auth whenever there is a hardware error" into udc-dev

This commit is contained in:
Chandru S
2023-04-17 19:54:52 +00:00
committed by Android (Google) Code Review
4 changed files with 92 additions and 8 deletions

View File

@@ -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>) {

View File

@@ -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. */

View File

@@ -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" }
)
}
}

View File

@@ -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()