Merge "Retry face auth whenever there is a hardware error" into udc-dev
This commit is contained in:
@@ -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>) {
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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" }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user