Prioritize lockout error over not enrolled error.

Bug: 286923477
Test: atest BiometricServiceTest
Test: manual test - 1. enroll only one biometric 2. try enough failed
attempts to lock it out on biometric prompt 3. try to launch biometric
prompt and the error message should be lockout error

Change-Id: Ie14909ba9beca8f946d5abde7d690693529a8917
This commit is contained in:
Hao Dong
2023-06-12 22:25:19 +00:00
parent eb68481407
commit ea1d5ca74f
2 changed files with 58 additions and 7 deletions

View File

@@ -267,17 +267,30 @@ class PreAuthInfo {
}
private Pair<BiometricSensor, Integer> calculateErrorByPriority() {
// If the caller requested STRONG, and the device contains both STRONG and non-STRONG
// sensors, prioritize BIOMETRIC_NOT_ENROLLED over the weak sensor's
// BIOMETRIC_INSUFFICIENT_STRENGTH error. Pretty sure we can always prioritize
// BIOMETRIC_NOT_ENROLLED over any other error (unless of course its calculation is
// wrong, in which case we should fix that instead).
Pair<BiometricSensor, Integer> sensorNotEnrolled = null;
Pair<BiometricSensor, Integer> sensorLockout = null;
for (Pair<BiometricSensor, Integer> pair : ineligibleSensors) {
int status = pair.second;
if (status == BIOMETRIC_LOCKOUT_TIMED || status == BIOMETRIC_LOCKOUT_PERMANENT) {
sensorLockout = pair;
}
if (pair.second == BIOMETRIC_NOT_ENROLLED) {
return pair;
sensorNotEnrolled = pair;
}
}
// If there is a sensor locked out, prioritize lockout over other sensor's error.
// See b/286923477.
if (sensorLockout != null) {
return sensorLockout;
}
// If the caller requested STRONG, and the device contains both STRONG and non-STRONG
// sensors, prioritize BIOMETRIC_NOT_ENROLLED over the weak sensor's
// BIOMETRIC_INSUFFICIENT_STRENGTH error.
if (sensorNotEnrolled != null) {
return sensorNotEnrolled;
}
return ineligibleSensors.get(0);
}

View File

@@ -18,7 +18,6 @@ package com.android.server.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.Authenticators;
import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTHENTICATED_PENDING_SYSUI;
@@ -902,6 +901,45 @@ public class BiometricServiceTest {
eq(biometricPromptError), eq(0) /* vendorCode */);
}
@Test
public void testMultiBiometricAuth_whenLockoutTimed_sendsErrorAndModality()
throws Exception {
testMultiBiometricAuth_whenLockout(LockoutTracker.LOCKOUT_TIMED,
BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT);
}
@Test
public void testMultiBiometricAuth_whenLockoutPermanent_sendsErrorAndModality()
throws Exception {
testMultiBiometricAuth_whenLockout(LockoutTracker.LOCKOUT_PERMANENT,
BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT_PERMANENT);
}
private void testMultiBiometricAuth_whenLockout(@LockoutTracker.LockoutMode int lockoutMode,
int biometricPromptError) throws Exception {
final int[] modalities = new int[] {
TYPE_FINGERPRINT,
BiometricAuthenticator.TYPE_FACE,
};
final int[] strengths = new int[] {
Authenticators.BIOMETRIC_STRONG,
Authenticators.BIOMETRIC_STRONG,
};
setupAuthForMultiple(modalities, strengths);
when(mFingerprintAuthenticator.getLockoutModeForUser(anyInt()))
.thenReturn(lockoutMode);
when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(false);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, null /* authenticators */);
waitForIdle();
// The lockout error should be sent, instead of ERROR_NONE_ENROLLED. See b/286923477.
verify(mReceiver1).onError(eq(TYPE_FINGERPRINT),
eq(biometricPromptError), eq(0) /* vendorCode */);
}
@Test
public void testBiometricOrCredentialAuth_whenBiometricLockout_showsCredential()
throws Exception {