Merge "RESTRICT AUTOMERGE Fix detect biometric logic." into tm-qpr-dev

This commit is contained in:
Beverly Tai
2023-02-27 18:57:46 +00:00
committed by Android (Google) Code Review
7 changed files with 196 additions and 85 deletions

View File

@@ -814,6 +814,19 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
}
private void onBiometricDetected(int userId, BiometricSourceType biometricSourceType,
boolean isStrongBiometric) {
Assert.isMainThread();
Trace.beginSection("KeyGuardUpdateMonitor#onBiometricDetected");
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onBiometricDetected(userId, biometricSourceType, isStrongBiometric);
}
}
Trace.endSection();
}
@VisibleForTesting
protected void onFingerprintAuthenticated(int userId, boolean isStrongBiometric) {
Assert.isMainThread();
@@ -890,6 +903,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
}
private void handleBiometricDetected(int authUserId, BiometricSourceType biometricSourceType,
boolean isStrongBiometric) {
Trace.beginSection("KeyGuardUpdateMonitor#handlerBiometricDetected");
onBiometricDetected(authUserId, biometricSourceType, isStrongBiometric);
if (biometricSourceType == FINGERPRINT) {
mLogger.logFingerprintDetected(authUserId, isStrongBiometric);
} else if (biometricSourceType == FACE) {
mLogger.logFaceDetected(authUserId, isStrongBiometric);
setFaceRunningState(BIOMETRIC_STATE_STOPPED);
}
Trace.endSection();
}
private void handleFingerprintAuthenticated(int authUserId, boolean isStrongBiometric) {
Trace.beginSection("KeyGuardUpdateMonitor#handlerFingerPrintAuthenticated");
if (mHandler.hasCallbacks(mFpCancelNotReceived)) {
@@ -941,8 +968,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private void onFingerprintCancelNotReceived() {
mLogger.e("Fp cancellation not received, transitioning to STOPPED");
final boolean wasCancellingRestarting = mFingerprintRunningState
== BIOMETRIC_STATE_CANCELLING_RESTARTING;
mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
KeyguardUpdateMonitor.this.updateFingerprintListeningState(BIOMETRIC_ACTION_STOP);
if (wasCancellingRestarting) {
KeyguardUpdateMonitor.this.updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
} else {
KeyguardUpdateMonitor.this.updateFingerprintListeningState(BIOMETRIC_ACTION_STOP);
}
}
private void handleFingerprintError(int msgId, String errString) {
@@ -1029,6 +1062,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
() -> updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE),
getBiometricLockoutDelay());
} else {
boolean temporaryLockoutReset = wasLockout && !mFingerprintLockedOut;
if (temporaryLockoutReset) {
mLogger.d("temporaryLockoutReset - stopListeningForFingerprint() to stop"
+ " detectFingerprint");
stopListeningForFingerprint();
}
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
@@ -1728,10 +1767,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
};
private final FingerprintManager.FingerprintDetectionCallback mFingerprintDetectionCallback =
(sensorId, userId, isStrongBiometric) -> {
// Trigger the fingerprint detected path so the bouncer can be shown
handleBiometricDetected(userId, FINGERPRINT, isStrongBiometric);
};
private final FaceManager.FaceDetectionCallback mFaceDetectionCallback
= (sensorId, userId, isStrongBiometric) -> {
// Trigger the face success path so the bouncer can be shown
handleFaceAuthenticated(userId, isStrongBiometric);
// Trigger the face detected path so the bouncer can be shown
handleBiometricDetected(userId, FACE, isStrongBiometric);
};
@VisibleForTesting
@@ -2759,8 +2804,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
boolean shouldListen = shouldListenKeyguardState && shouldListenUserState
&& shouldListenBouncerState && shouldListenUdfpsState
&& shouldListenSideFpsState
&& !isFingerprintLockedOut();
&& shouldListenSideFpsState;
logListenerModelData(
new KeyguardFingerprintListenModel(
System.currentTimeMillis(),
@@ -2819,8 +2863,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
final boolean supportsDetect = !mFaceSensorProperties.isEmpty()
&& mFaceSensorProperties.get(0).supportsFaceDetection
&& canBypass && !mPrimaryBouncerIsOrWillBeShowing
&& !isUserInLockdown(user)
&& !isFingerprintLockedOut();
&& !isUserInLockdown(user);
final boolean faceAuthAllowedOrDetectionIsNeeded = faceAuthAllowed || supportsDetect;
// If the face or fp has recently been authenticated do not attempt to authenticate again.
@@ -2916,11 +2959,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mLogger.v("startListeningForFingerprint - detect");
mFpm.detectFingerprint(
mFingerprintCancelSignal,
(sensorId, user, isStrongBiometric) -> {
mLogger.d("fingerprint detected");
// Trigger the fingerprint success path so the bouncer can be shown
handleFingerprintAuthenticated(user, isStrongBiometric);
},
mFingerprintDetectionCallback,
userId);
} else {
mLogger.v("startListeningForFingerprint - authenticate");

View File

@@ -214,13 +214,21 @@ public class KeyguardUpdateMonitorCallback {
public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) { }
/**
* Called when a biometric is recognized.
* Called when a biometric is authenticated.
* @param userId the user id for which the biometric sample was authenticated
* @param biometricSourceType
*/
public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
boolean isStrongBiometric) { }
/**
* Called when a biometric is detected but not successfully authenticated.
* @param userId the user id for which the biometric sample was detected
* @param biometricSourceType
*/
public void onBiometricDetected(int userId, BiometricSourceType biometricSourceType,
boolean isStrongBiometric) { }
/**
* Called when biometric authentication provides help string (e.g. "Try again")
* @param msgId

View File

@@ -167,6 +167,20 @@ class KeyguardUpdateMonitorLogger @Inject constructor(
}, {"Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1"})
}
fun logFaceDetected(userId: Int, isStrongBiometric: Boolean) {
logBuffer.log(TAG, DEBUG, {
int1 = userId
bool1 = isStrongBiometric
}, {"Face detected: userId: $int1, isStrongBiometric: $bool1"})
}
fun logFingerprintDetected(userId: Int, isStrongBiometric: Boolean) {
logBuffer.log(TAG, DEBUG, {
int1 = userId
bool1 = isStrongBiometric
}, {"Fingerprint detected: userId: $int1, isStrongBiometric: $bool1"})
}
fun logFingerprintError(msgId: Int, originalErrMsg: String) {
logBuffer.log(TAG, DEBUG, {
str1 = originalErrMsg

View File

@@ -382,6 +382,17 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
Trace.endSection();
}
@Override
public void onBiometricDetected(int userId, BiometricSourceType biometricSourceType,
boolean isStrongBiometric) {
Trace.beginSection("BiometricUnlockController#onBiometricDetected");
if (mUpdateMonitor.isGoingToSleep()) {
Trace.endSection();
return;
}
startWakeAndUnlock(MODE_SHOW_BOUNCER);
}
@Override
public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
boolean isStrongBiometric) {

View File

@@ -29,7 +29,6 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.keyguard.FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_CANCELLING;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_CANCELLING_RESTARTING;
import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.HAL_POWER_PRESS_TIMEOUT;
@@ -614,19 +613,47 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Test
public void testOnlyDetectFingerprint_whenFingerprintUnlockNotAllowed() {
// Clear invocations, since previous setup (e.g. registering BiometricManager callbacks)
// will trigger updateBiometricListeningState();
clearInvocations(mFingerprintManager);
mKeyguardUpdateMonitor.resetBiometricListeningState();
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
mTestableLooper.processAllMessages();
givenDetectFingerprintWithClearingFingerprintManagerInvocations();
verifyFingerprintAuthenticateNeverCalled();
verifyFingerprintDetectCall();
}
@Test
public void whenDetectFingerprint_biometricDetectCallback() {
ArgumentCaptor<FingerprintManager.FingerprintDetectionCallback> fpDetectCallbackCaptor =
ArgumentCaptor.forClass(FingerprintManager.FingerprintDetectionCallback.class);
givenDetectFingerprintWithClearingFingerprintManagerInvocations();
verify(mFingerprintManager).detectFingerprint(
any(), fpDetectCallbackCaptor.capture(), anyInt());
fpDetectCallbackCaptor.getValue().onFingerprintDetected(0, 0, true);
// THEN verify keyguardUpdateMonitorCallback receives a detect callback
// and NO authenticate callbacks
verify(mTestCallback).onBiometricDetected(
eq(0), eq(BiometricSourceType.FINGERPRINT), eq(true));
verify(mTestCallback, never()).onBiometricAuthenticated(
anyInt(), any(), anyBoolean());
}
@Test
public void whenDetectFace_biometricDetectCallback() {
ArgumentCaptor<FaceManager.FaceDetectionCallback> faceDetectCallbackCaptor =
ArgumentCaptor.forClass(FaceManager.FaceDetectionCallback.class);
givenDetectFace();
verify(mFaceManager).detectFace(any(), faceDetectCallbackCaptor.capture(), anyInt());
faceDetectCallbackCaptor.getValue().onFaceDetected(0, 0, false);
// THEN verify keyguardUpdateMonitorCallback receives a detect callback
// and NO authenticate callbacks
verify(mTestCallback).onBiometricDetected(
eq(0), eq(BiometricSourceType.FACE), eq(false));
verify(mTestCallback, never()).onBiometricAuthenticated(
anyInt(), any(), anyBoolean());
}
@Test
public void testUnlockingWithFaceAllowed_strongAuthTrackerUnlockingWithBiometricAllowed() {
// GIVEN unlocking with biometric is allowed
@@ -655,7 +682,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
strongAuthNotRequired();
// WHEN fingerprint is locked out
fingerprintErrorLockedOut();
fingerprintErrorTemporaryLockedOut();
// THEN unlocking with face is not allowed
Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
@@ -678,7 +705,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
strongAuthNotRequired();
// WHEN fingerprint is locked out
fingerprintErrorLockedOut();
fingerprintErrorTemporaryLockedOut();
// THEN unlocking with fingerprint is not allowed
Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
@@ -702,7 +729,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
Assert.assertTrue(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser()));
// WHEN fingerprint is locked out
fingerprintErrorLockedOut();
fingerprintErrorTemporaryLockedOut();
// THEN user is NOT considered as "having trust" and bouncer cannot be skipped
Assert.assertFalse(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser()));
@@ -764,11 +791,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Test
public void nofaceDetect_whenStrongAuthRequiredAndBypassUdfpsSupportedAndFpRunning() {
// GIVEN mocked keyguardUpdateMonitorCallback
KeyguardUpdateMonitorCallback keyguardUpdateMonitorCallback =
mock(KeyguardUpdateMonitorCallback.class);
mKeyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback);
// GIVEN bypass is enabled, face detection is supported
lockscreenBypassIsAllowed();
supportsFaceDetection();
@@ -787,22 +809,13 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
verifyFaceAuthenticateNeverCalled();
// THEN biometric help message sent to callback
verify(keyguardUpdateMonitorCallback).onBiometricHelp(
verify(mTestCallback).onBiometricHelp(
eq(BIOMETRIC_HELP_FACE_NOT_AVAILABLE), anyString(), eq(BiometricSourceType.FACE));
}
@Test
public void faceDetect_whenStrongAuthRequiredAndBypass() {
// GIVEN bypass is enabled, face detection is supported and strong auth is required
lockscreenBypassIsAllowed();
supportsFaceDetection();
strongAuthRequiredEncrypted();
keyguardIsVisible();
// fingerprint is NOT running, UDFPS is NOT supported
// WHEN the device wakes up
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
givenDetectFace();
// FACE detect is triggered, not authenticate
verifyFaceDetectCall();
@@ -818,39 +831,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
verifyFaceDetectNeverCalled();
}
@Test
public void noFaceRun_whenFpLockout() {
// GIVEN bypass is enabled, face detection is supported and strong auth is required
lockscreenBypassIsAllowed();
supportsFaceDetection();
strongAuthRequiredEncrypted();
keyguardIsVisible();
// fingerprint is NOT running, UDFPS is NOT supported
// GIVEN fp is locked out
when(mFingerprintManager.getLockoutModeForUser(eq(FINGERPRINT_SENSOR_ID), anyInt()))
.thenReturn(BIOMETRIC_LOCKOUT_TIMED);
mKeyguardUpdateMonitor.handleUserSwitchComplete(0);
assertThat(mKeyguardUpdateMonitor.isFingerprintLockedOut()).isEqualTo(true);
// WHEN the device wakes up
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
// FACE detect is NOT triggered and face authenticate is NOT triggered
verifyFaceDetectNeverCalled();
verifyFaceAuthenticateNeverCalled();
// WHEN bouncer becomes visible
setKeyguardBouncerVisibility(true);
clearInvocations(mFaceManager);
// THEN face scanning is not run
mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
verifyFaceAuthenticateNeverCalled();
verifyFaceDetectNeverCalled();
}
@Test
public void noFaceDetect_whenStrongAuthRequiredAndBypass_faceDetectionUnsupported() {
// GIVEN bypass is enabled, face detection is NOT supported and strong auth is required
@@ -1159,8 +1139,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
// Fingerprint should be cancelled on lockout if going to lockout state, else
// restarted if it's not
assertThat(mKeyguardUpdateMonitor.mFingerprintRunningState)
.isEqualTo(fpLocked
? BIOMETRIC_STATE_CANCELLING : BIOMETRIC_STATE_CANCELLING_RESTARTING);
.isEqualTo(BIOMETRIC_STATE_CANCELLING_RESTARTING);
}
@Test
@@ -1619,7 +1598,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
// Fingerprint is locked out.
fingerprintErrorLockedOut();
fingerprintErrorTemporaryLockedOut();
assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
}
@@ -2428,6 +2407,29 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
eq(false));
}
@Test
public void detectFingerprint_onTemporaryLockoutReset_authenticateFingerprint() {
ArgumentCaptor<FingerprintManager.LockoutResetCallback> fpLockoutResetCallbackCaptor =
ArgumentCaptor.forClass(FingerprintManager.LockoutResetCallback.class);
verify(mFingerprintManager).addLockoutResetCallback(fpLockoutResetCallbackCaptor.capture());
// GIVEN device is locked out
fingerprintErrorTemporaryLockedOut();
// GIVEN FP detection is running
givenDetectFingerprintWithClearingFingerprintManagerInvocations();
verifyFingerprintDetectCall();
verifyFingerprintAuthenticateNeverCalled();
// WHEN temporary lockout resets
fpLockoutResetCallbackCaptor.getValue().onLockoutReset(0);
mTestableLooper.processAllMessages();
// THEN fingerprint detect state should cancel & then restart (for authenticate call)
assertThat(mKeyguardUpdateMonitor.mFingerprintRunningState)
.isEqualTo(BIOMETRIC_STATE_CANCELLING_RESTARTING);
}
private void verifyFingerprintAuthenticateNeverCalled() {
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyInt(), anyInt());
@@ -2532,7 +2534,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.setSwitchingUser(true);
}
private void fingerprintErrorLockedOut() {
private void fingerprintErrorTemporaryLockedOut() {
mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
.onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT, "Fingerprint locked out");
}
@@ -2672,6 +2674,30 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
receiver.setPendingResult(pendingResult);
}
private void givenDetectFingerprintWithClearingFingerprintManagerInvocations() {
// Clear invocations, since previous setup (e.g. registering BiometricManager callbacks)
// will trigger updateBiometricListeningState();
clearInvocations(mFingerprintManager);
mKeyguardUpdateMonitor.resetBiometricListeningState();
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
mTestableLooper.processAllMessages();
}
private void givenDetectFace() {
// GIVEN bypass is enabled, face detection is supported and strong auth is required
lockscreenBypassIsAllowed();
supportsFaceDetection();
strongAuthRequiredEncrypted();
keyguardIsVisible();
// fingerprint is NOT running, UDFPS is NOT supported
// WHEN the device wakes up
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
}
private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) {
int subscription = simInited
? 1/* mock subid=1 */ : SubscriptionManager.PLACEHOLDER_SUBSCRIPTION_ID_BASE;

View File

@@ -537,6 +537,26 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
verify(mVibratorHelper).vibrateAuthError(anyString());
}
@Test
public void onFingerprintDetect_showBouncer() {
// WHEN fingerprint detect occurs
mBiometricUnlockController.onBiometricDetected(UserHandle.USER_CURRENT,
BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
// THEN shows primary bouncer
verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(anyBoolean());
}
@Test
public void onFaceDetect_showBouncer() {
// WHEN face detect occurs
mBiometricUnlockController.onBiometricDetected(UserHandle.USER_CURRENT,
BiometricSourceType.FACE, false /* isStrongBiometric */);
// THEN shows primary bouncer
verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(anyBoolean());
}
private void givenFingerprintModeUnlockCollapsing() {
when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);

View File

@@ -452,13 +452,6 @@ public class FingerprintService extends SystemService {
return -1;
}
if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
// If this happens, something in KeyguardUpdateMonitor is wrong. This should only
// ever be invoked when the user is encrypted or lockdown.
Slog.e(TAG, "detectFingerprint invoked when user is not encrypted or lockdown");
return -1;
}
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for detectFingerprint");