1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.biometrics; 18 19 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; 20 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; 21 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON; 22 import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED; 23 import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED; 24 import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_NEGATIVE; 25 26 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_CALLED; 27 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED; 28 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED_UI_SHOWING; 29 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_ERROR_PENDING_SYSUI; 30 31 import static junit.framework.Assert.assertEquals; 32 import static junit.framework.Assert.assertFalse; 33 import static junit.framework.Assert.assertTrue; 34 35 import static org.mockito.ArgumentMatchers.any; 36 import static org.mockito.ArgumentMatchers.anyBoolean; 37 import static org.mockito.ArgumentMatchers.anyInt; 38 import static org.mockito.ArgumentMatchers.anyLong; 39 import static org.mockito.ArgumentMatchers.anyObject; 40 import static org.mockito.ArgumentMatchers.eq; 41 import static org.mockito.Mockito.mock; 42 import static org.mockito.Mockito.never; 43 import static org.mockito.Mockito.times; 44 import static org.mockito.Mockito.verify; 45 import static org.mockito.Mockito.when; 46 47 import android.annotation.NonNull; 48 import android.app.admin.DevicePolicyManager; 49 import android.app.trust.ITrustManager; 50 import android.content.Context; 51 import android.content.res.Resources; 52 import android.hardware.biometrics.BiometricConstants; 53 import android.hardware.biometrics.BiometricManager.Authenticators; 54 import android.hardware.biometrics.BiometricsProtoEnums; 55 import android.hardware.biometrics.ComponentInfoInternal; 56 import android.hardware.biometrics.IBiometricAuthenticator; 57 import android.hardware.biometrics.IBiometricSensorReceiver; 58 import android.hardware.biometrics.IBiometricServiceReceiver; 59 import android.hardware.biometrics.IBiometricSysuiReceiver; 60 import android.hardware.biometrics.PromptInfo; 61 import android.hardware.biometrics.SensorProperties; 62 import android.hardware.fingerprint.FingerprintManager; 63 import android.hardware.fingerprint.FingerprintSensorProperties; 64 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 65 import android.os.Binder; 66 import android.os.IBinder; 67 import android.os.RemoteException; 68 import android.platform.test.annotations.Presubmit; 69 import android.security.KeyStore; 70 71 import androidx.test.filters.SmallTest; 72 73 import com.android.internal.statusbar.IStatusBarService; 74 import com.android.internal.util.FrameworkStatsLog; 75 import com.android.server.biometrics.log.BiometricContext; 76 import com.android.server.biometrics.log.BiometricFrameworkStatsLogger; 77 import com.android.server.biometrics.log.OperationContextExt; 78 79 import org.junit.Before; 80 import org.junit.Test; 81 import org.mockito.Mock; 82 import org.mockito.MockitoAnnotations; 83 84 import java.util.ArrayList; 85 import java.util.List; 86 import java.util.Random; 87 import java.util.function.Consumer; 88 89 @Presubmit 90 @SmallTest 91 public class AuthSessionTest { 92 93 private static final String TEST_PACKAGE = "test_package"; 94 private static final long TEST_REQUEST_ID = 22; 95 96 @Mock private Context mContext; 97 @Mock private Resources mResources; 98 @Mock private BiometricContext mBiometricContext; 99 @Mock private ITrustManager mTrustManager; 100 @Mock private DevicePolicyManager mDevicePolicyManager; 101 @Mock private BiometricService.SettingObserver mSettingObserver; 102 @Mock private IBiometricSensorReceiver mSensorReceiver; 103 @Mock private IBiometricServiceReceiver mClientReceiver; 104 @Mock private IStatusBarService mStatusBarService; 105 @Mock private IBiometricSysuiReceiver mSysuiReceiver; 106 @Mock private KeyStore mKeyStore; 107 @Mock private AuthSession.ClientDeathReceiver mClientDeathReceiver; 108 @Mock private BiometricFrameworkStatsLogger mBiometricFrameworkStatsLogger; 109 @Mock private BiometricCameraManager mBiometricCameraManager; 110 111 private Random mRandom; 112 private IBinder mToken; 113 114 // Assume all tests can be done with the same set of sensors for now. 115 @NonNull private List<BiometricSensor> mSensors; 116 @NonNull private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProps; 117 118 @Before setUp()119 public void setUp() throws Exception { 120 MockitoAnnotations.initMocks(this); 121 when(mContext.getResources()).thenReturn(mResources); 122 when(mClientReceiver.asBinder()).thenReturn(mock(Binder.class)); 123 when(mBiometricContext.updateContext(any(), anyBoolean())) 124 .thenAnswer(invocation -> invocation.getArgument(0)); 125 mRandom = new Random(); 126 mToken = new Binder(); 127 mSensors = new ArrayList<>(); 128 mFingerprintSensorProps = new ArrayList<>(); 129 } 130 131 @Test testNewAuthSession_eligibleSensorsSetToStateUnknown()132 public void testNewAuthSession_eligibleSensorsSetToStateUnknown() throws RemoteException { 133 setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_REAR); 134 setupFace(1 /* id */, false /* confirmationAlwaysRequired */, 135 mock(IBiometricAuthenticator.class)); 136 137 final AuthSession session = createAuthSession(mSensors, 138 false /* checkDevicePolicyManager */, 139 Authenticators.BIOMETRIC_STRONG, 140 TEST_REQUEST_ID, 141 0 /* operationId */, 142 0 /* userId */); 143 144 for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { 145 assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState()); 146 } 147 } 148 149 @Test testStartNewAuthSession()150 public void testStartNewAuthSession() throws RemoteException { 151 setupFace(0 /* id */, false /* confirmationAlwaysRequired */, 152 mock(IBiometricAuthenticator.class)); 153 setupFingerprint(1 /* id */, FingerprintSensorProperties.TYPE_REAR); 154 155 final boolean requireConfirmation = true; 156 final long operationId = 123; 157 final int userId = 10; 158 159 final AuthSession session = createAuthSession(mSensors, 160 false /* checkDevicePolicyManager */, 161 Authenticators.BIOMETRIC_STRONG, 162 TEST_REQUEST_ID, 163 operationId, 164 userId); 165 assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size()); 166 167 for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { 168 assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState()); 169 assertEquals(0, sensor.getCookie()); 170 } 171 172 session.goToInitialState(); 173 for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { 174 assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState()); 175 assertTrue("Cookie must be >0", sensor.getCookie() > 0); 176 verify(sensor.impl).prepareForAuthentication( 177 eq(sensor.confirmationSupported() && requireConfirmation), 178 eq(mToken), 179 eq(operationId), 180 eq(userId), 181 eq(mSensorReceiver), 182 eq(TEST_PACKAGE), 183 eq(TEST_REQUEST_ID), 184 eq(sensor.getCookie()), 185 anyBoolean() /* allowBackgroundAuthentication */, 186 anyBoolean() /* isForLegacyFingerprintManager */); 187 } 188 189 final int cookie1 = session.mPreAuthInfo.eligibleSensors.get(0).getCookie(); 190 session.onCookieReceived(cookie1); 191 for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { 192 if (cookie1 == sensor.getCookie()) { 193 assertEquals(BiometricSensor.STATE_COOKIE_RETURNED, sensor.getSensorState()); 194 } else { 195 assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState()); 196 } 197 } 198 assertFalse(session.allCookiesReceived()); 199 200 final int cookie2 = session.mPreAuthInfo.eligibleSensors.get(1).getCookie(); 201 session.onCookieReceived(cookie2); 202 assertTrue(session.allCookiesReceived()); 203 204 205 // for multi-sensor face then fingerprint is the default policy 206 for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { 207 if (sensor.modality == TYPE_FACE) { 208 verify(sensor.impl).startPreparedClient(eq(sensor.getCookie())); 209 assertEquals(BiometricSensor.STATE_AUTHENTICATING, sensor.getSensorState()); 210 } else if (sensor.modality == TYPE_FINGERPRINT) { 211 assertEquals(BiometricSensor.STATE_COOKIE_RETURNED, sensor.getSensorState()); 212 } 213 } 214 } 215 216 @Test testOnErrorReceived_lockoutError()217 public void testOnErrorReceived_lockoutError() throws RemoteException { 218 setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_REAR); 219 setupFace(1 /* id */, false /* confirmationAlwaysRequired */, 220 mock(IBiometricAuthenticator.class)); 221 final AuthSession session = createAuthSession(mSensors, 222 false /* checkDevicePolicyManager */, 223 Authenticators.BIOMETRIC_STRONG, 224 TEST_REQUEST_ID, 225 0 /* operationId */, 226 0 /* userId */); 227 session.goToInitialState(); 228 for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { 229 assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState()); 230 session.onCookieReceived( 231 session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie()); 232 } 233 assertTrue(session.allCookiesReceived()); 234 assertEquals(STATE_AUTH_STARTED, session.getState()); 235 236 // Either of strong sensor's lockout should cancel both sensors. 237 final int cookie1 = session.mPreAuthInfo.eligibleSensors.get(0).getCookie(); 238 session.onErrorReceived(0, cookie1, BiometricConstants.BIOMETRIC_ERROR_LOCKOUT, 0); 239 for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { 240 assertEquals(BiometricSensor.STATE_CANCELING, sensor.getSensorState()); 241 } 242 assertEquals(STATE_ERROR_PENDING_SYSUI, session.getState()); 243 244 // If the sensor is STATE_CANCELING, delayed onAuthenticationRejected() shouldn't change the 245 // session state to STATE_AUTH_PAUSED. 246 session.onAuthenticationRejected(1); 247 assertEquals(STATE_ERROR_PENDING_SYSUI, session.getState()); 248 } 249 250 @Test testCancelReducesAppetiteForCookies()251 public void testCancelReducesAppetiteForCookies() throws Exception { 252 setupFace(0 /* id */, false /* confirmationAlwaysRequired */, 253 mock(IBiometricAuthenticator.class)); 254 setupFingerprint(1 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL); 255 256 final AuthSession session = createAuthSession(mSensors, 257 false /* checkDevicePolicyManager */, 258 Authenticators.BIOMETRIC_STRONG, 259 TEST_REQUEST_ID, 260 44 /* operationId */, 261 2 /* userId */); 262 263 session.goToInitialState(); 264 265 for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { 266 assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState()); 267 } 268 269 session.onCancelAuthSession(false /* force */); 270 271 for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { 272 session.onCookieReceived(sensor.getCookie()); 273 assertEquals(BiometricSensor.STATE_CANCELING, sensor.getSensorState()); 274 } 275 } 276 277 @Test testMultiAuth_singleSensor_fingerprintSensorStartsAfterDialogAnimationCompletes()278 public void testMultiAuth_singleSensor_fingerprintSensorStartsAfterDialogAnimationCompletes() 279 throws Exception { 280 setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL); 281 testMultiAuth_fingerprintSensorStartsAfterUINotifies(true /* startFingerprintNow */); 282 } 283 284 @Test testMultiAuth_singleSensor_fingerprintSensorDoesNotStartAfterDialogAnimationCompletes()285 public void testMultiAuth_singleSensor_fingerprintSensorDoesNotStartAfterDialogAnimationCompletes() 286 throws Exception { 287 setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL); 288 testMultiAuth_fingerprintSensorStartsAfterUINotifies(false /* startFingerprintNow */); 289 } 290 291 @Test testMultiAuth_fingerprintSensorStartsAfterDialogAnimationCompletes()292 public void testMultiAuth_fingerprintSensorStartsAfterDialogAnimationCompletes() 293 throws Exception { 294 setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL); 295 setupFace(1 /* id */, false, mock(IBiometricAuthenticator.class)); 296 testMultiAuth_fingerprintSensorStartsAfterUINotifies(true /* startFingerprintNow */); 297 } 298 299 @Test testMultiAuth_fingerprintSensorDoesNotStartAfterDialogAnimationCompletes()300 public void testMultiAuth_fingerprintSensorDoesNotStartAfterDialogAnimationCompletes() 301 throws Exception { 302 setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL); 303 setupFace(1 /* id */, false, mock(IBiometricAuthenticator.class)); 304 testMultiAuth_fingerprintSensorStartsAfterUINotifies(false /* startFingerprintNow */); 305 } 306 testMultiAuth_fingerprintSensorStartsAfterUINotifies(boolean startFingerprintNow)307 public void testMultiAuth_fingerprintSensorStartsAfterUINotifies(boolean startFingerprintNow) 308 throws Exception { 309 final long operationId = 123; 310 final int userId = 10; 311 final int fingerprintSensorId = mSensors.stream() 312 .filter(s -> s.modality == TYPE_FINGERPRINT) 313 .map(s -> s.id) 314 .findFirst() 315 .orElse(-1); 316 317 final AuthSession session = createAuthSession(mSensors, 318 false /* checkDevicePolicyManager */, 319 Authenticators.BIOMETRIC_STRONG, 320 TEST_REQUEST_ID, 321 operationId, 322 userId); 323 assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size()); 324 325 for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { 326 assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState()); 327 assertEquals(0, sensor.getCookie()); 328 } 329 330 session.goToInitialState(); 331 332 for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { 333 assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState()); 334 session.onCookieReceived( 335 session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie()); 336 if (fingerprintSensorId == sensor.id) { 337 assertEquals(BiometricSensor.STATE_COOKIE_RETURNED, sensor.getSensorState()); 338 } else { 339 assertEquals(BiometricSensor.STATE_AUTHENTICATING, sensor.getSensorState()); 340 } 341 } 342 assertTrue(session.allCookiesReceived()); 343 344 // fingerprint sensor does not start even if all cookies are received 345 assertEquals(STATE_AUTH_STARTED, session.getState()); 346 verify(mStatusBarService).showAuthenticationDialog(any(), any(), any(), 347 anyBoolean(), anyBoolean(), anyInt(), anyLong(), any(), anyLong()); 348 349 // Notify AuthSession that the UI is shown. Then, fingerprint sensor should be started. 350 session.onDialogAnimatedIn(startFingerprintNow); 351 assertEquals(STATE_AUTH_STARTED_UI_SHOWING, session.getState()); 352 assertEquals(startFingerprintNow ? BiometricSensor.STATE_AUTHENTICATING 353 : BiometricSensor.STATE_COOKIE_RETURNED, 354 session.mPreAuthInfo.eligibleSensors.get(fingerprintSensorId).getSensorState()); 355 verify(mBiometricContext).updateContext((OperationContextExt) anyObject(), 356 eq(session.isCrypto())); 357 358 // start fingerprint sensor if it was delayed 359 if (!startFingerprintNow) { 360 session.onStartFingerprint(); 361 assertEquals(BiometricSensor.STATE_AUTHENTICATING, 362 session.mPreAuthInfo.eligibleSensors.get(fingerprintSensorId).getSensorState()); 363 } 364 } 365 366 @Test testOnDialogAnimatedInDoesNothingDuringInvalidState()367 public void testOnDialogAnimatedInDoesNothingDuringInvalidState() throws Exception { 368 setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL); 369 final long operationId = 123; 370 final int userId = 10; 371 372 final AuthSession session = createAuthSession(mSensors, 373 false /* checkDevicePolicyManager */, 374 Authenticators.BIOMETRIC_STRONG, 375 TEST_REQUEST_ID, 376 operationId, 377 userId); 378 final IBiometricAuthenticator impl = session.mPreAuthInfo.eligibleSensors.get(0).impl; 379 380 session.goToInitialState(); 381 for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { 382 assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState()); 383 session.onCookieReceived( 384 session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie()); 385 } 386 assertTrue(session.allCookiesReceived()); 387 assertEquals(STATE_AUTH_STARTED, session.getState()); 388 verify(impl, never()).startPreparedClient(anyInt()); 389 390 // First invocation should start the client monitor. 391 session.onDialogAnimatedIn(true /* startFingerprintNow */); 392 assertEquals(STATE_AUTH_STARTED_UI_SHOWING, session.getState()); 393 verify(impl).startPreparedClient(anyInt()); 394 395 // Subsequent invocations should not start the client monitor again. 396 session.onDialogAnimatedIn(true /* startFingerprintNow */); 397 session.onDialogAnimatedIn(false /* startFingerprintNow */); 398 session.onDialogAnimatedIn(true /* startFingerprintNow */); 399 assertEquals(STATE_AUTH_STARTED_UI_SHOWING, session.getState()); 400 verify(impl, times(1)).startPreparedClient(anyInt()); 401 } 402 403 @Test testCancelAuthentication_whenStateAuthCalled_invokesCancel()404 public void testCancelAuthentication_whenStateAuthCalled_invokesCancel() 405 throws RemoteException { 406 testInvokesCancel(session -> session.onCancelAuthSession(false /* force */)); 407 } 408 409 @Test testCancelAuthentication_whenStateAuthForcedCalled_invokesCancel()410 public void testCancelAuthentication_whenStateAuthForcedCalled_invokesCancel() 411 throws RemoteException { 412 testInvokesCancel(session -> session.onCancelAuthSession(true /* force */)); 413 } 414 415 @Test testCancelAuthentication_whenDialogDismissed()416 public void testCancelAuthentication_whenDialogDismissed() throws RemoteException { 417 testInvokesCancel(session -> session.onDialogDismissed(DISMISSED_REASON_NEGATIVE, null)); 418 } 419 420 @Test testCallbackOnAcquired()421 public void testCallbackOnAcquired() throws RemoteException { 422 final String acquiredStr = "test_acquired_info_callback"; 423 final String acquiredStrVendor = "test_acquired_info_callback_vendor"; 424 setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_REAR); 425 426 final AuthSession session = createAuthSession(mSensors, 427 false /* checkDevicePolicyManager */, 428 Authenticators.BIOMETRIC_STRONG, 429 TEST_REQUEST_ID, 430 0 /* operationId */, 431 0 /* userId */); 432 433 when(mContext.getString(com.android.internal.R.string.fingerprint_acquired_partial)) 434 .thenReturn(acquiredStr); 435 session.onAcquired(0, FingerprintManager.FINGERPRINT_ACQUIRED_PARTIAL, 0); 436 verify(mStatusBarService).onBiometricHelp(anyInt(), eq(acquiredStr)); 437 verify(mClientReceiver).onAcquired(eq(1), eq(acquiredStr)); 438 439 when(mResources.getStringArray(com.android.internal.R.array.fingerprint_acquired_vendor)) 440 .thenReturn(new String[]{acquiredStrVendor}); 441 session.onAcquired(0, FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR, 0); 442 verify(mStatusBarService).onBiometricHelp(anyInt(), eq(acquiredStrVendor)); 443 verify(mClientReceiver).onAcquired( 444 eq(FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR_BASE), eq(acquiredStrVendor)); 445 } 446 447 @Test testLogOnDialogDismissed_authenticatedWithConfirmation()448 public void testLogOnDialogDismissed_authenticatedWithConfirmation() throws RemoteException { 449 final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class); 450 451 setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator); 452 final AuthSession session = createAuthSession(mSensors, 453 false /* checkDevicePolicyManager */, 454 Authenticators.BIOMETRIC_STRONG, 455 TEST_REQUEST_ID, 456 0 /* operationId */, 457 0 /* userId */); 458 session.goToInitialState(); 459 assertEquals(STATE_AUTH_CALLED, session.getState()); 460 461 session.onDialogDismissed(DISMISSED_REASON_BIOMETRIC_CONFIRMED, null); 462 verify(mBiometricFrameworkStatsLogger, times(1)).authenticate( 463 (OperationContextExt) anyObject(), 464 eq(BiometricsProtoEnums.MODALITY_FACE), 465 eq(BiometricsProtoEnums.ACTION_UNKNOWN), 466 eq(BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT), 467 eq(false), /* debugEnabled */ 468 anyLong(), /* latency */ 469 eq(FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED), 470 eq(true), /* confirmationRequired */ 471 eq(0) /* userId */, 472 eq(-1f) /* ambientLightLux */); 473 } 474 475 @Test testLogOnDialogDismissed_authenticatedWithoutConfirmation()476 public void testLogOnDialogDismissed_authenticatedWithoutConfirmation() throws RemoteException { 477 final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class); 478 479 setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator); 480 final AuthSession session = createAuthSession(mSensors, 481 false /* checkDevicePolicyManager */, 482 Authenticators.BIOMETRIC_STRONG, 483 TEST_REQUEST_ID, 484 0 /* operationId */, 485 0 /* userId */); 486 session.goToInitialState(); 487 assertEquals(STATE_AUTH_CALLED, session.getState()); 488 489 session.onDialogDismissed(DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED, null); 490 verify(mBiometricFrameworkStatsLogger, never()).authenticate( 491 anyObject(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyLong(), anyInt(), 492 anyBoolean(), anyInt(), eq(-1f)); 493 verify(mBiometricFrameworkStatsLogger, never()).error( 494 anyObject(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyLong(), anyInt(), 495 anyInt(), anyInt()); 496 } 497 498 @Test testLogOnDialogDismissed_error()499 public void testLogOnDialogDismissed_error() throws RemoteException { 500 final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class); 501 502 setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator); 503 final AuthSession session = createAuthSession(mSensors, 504 false /* checkDevicePolicyManager */, 505 Authenticators.BIOMETRIC_STRONG, 506 TEST_REQUEST_ID, 507 0 /* operationId */, 508 0 /* userId */); 509 session.goToInitialState(); 510 assertEquals(STATE_AUTH_CALLED, session.getState()); 511 512 session.onDialogDismissed(DISMISSED_REASON_NEGATIVE, null); 513 verify(mBiometricFrameworkStatsLogger, times(1)).error( 514 (OperationContextExt) anyObject(), 515 eq(BiometricsProtoEnums.MODALITY_FACE), 516 eq(BiometricsProtoEnums.ACTION_AUTHENTICATE), 517 eq(BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT), 518 eq(false), 519 anyLong(), 520 eq(BIOMETRIC_ERROR_NEGATIVE_BUTTON), 521 eq(0) /* vendorCode */, 522 eq(0) /* userId */); 523 } 524 525 // TODO (b/208484275) : Enable these tests 526 // @Test 527 // public void testPreAuth_canAuthAndPrivacyDisabled() throws Exception { 528 // SensorPrivacyManager manager = ExtendedMockito.mock(SensorPrivacyManager.class); 529 // when(manager 530 // .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, anyInt())) 531 // .thenReturn(false); 532 // when(mContext.getSystemService(SensorPrivacyManager.class)) 533 // .thenReturn(manager); 534 // setupFace(1 /* id */, false /* confirmationAlwaysRequired */, 535 // mock(IBiometricAuthenticator.class)); 536 // final PromptInfo promptInfo = createPromptInfo(Authenticators.BIOMETRIC_STRONG); 537 // final PreAuthInfo preAuthInfo = createPreAuthInfo(mSensors, 0, promptInfo, false); 538 // assertEquals(BiometricManager.BIOMETRIC_SUCCESS, preAuthInfo.getCanAuthenticateResult()); 539 // for (BiometricSensor sensor : preAuthInfo.eligibleSensors) { 540 // assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState()); 541 // } 542 // } 543 544 // @Test 545 // public void testPreAuth_cannotAuthAndPrivacyEnabled() throws Exception { 546 // SensorPrivacyManager manager = ExtendedMockito.mock(SensorPrivacyManager.class); 547 // when(manager 548 // .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, anyInt())) 549 // .thenReturn(true); 550 // when(mContext.getSystemService(SensorPrivacyManager.class)) 551 // .thenReturn(manager); 552 // setupFace(1 /* id */, false /* confirmationAlwaysRequired */, 553 // mock(IBiometricAuthenticator.class)); 554 // final PromptInfo promptInfo = createPromptInfo(Authenticators.BIOMETRIC_STRONG); 555 // final PreAuthInfo preAuthInfo = createPreAuthInfo(mSensors, 0, promptInfo, false); 556 // assertEquals(BiometricManager.BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED, 557 // preAuthInfo.getCanAuthenticateResult()); 558 // // Even though canAuth returns privacy enabled, we should still be able to authenticate. 559 // for (BiometricSensor sensor : preAuthInfo.eligibleSensors) { 560 // assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState()); 561 // } 562 // } 563 564 // @Test 565 // public void testPreAuth_canAuthAndPrivacyEnabledCredentialEnabled() throws Exception { 566 // SensorPrivacyManager manager = ExtendedMockito.mock(SensorPrivacyManager.class); 567 // when(manager 568 // .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, anyInt())) 569 // .thenReturn(true); 570 // when(mContext.getSystemService(SensorPrivacyManager.class)) 571 // .thenReturn(manager); 572 // setupFace(1 /* id */, false /* confirmationAlwaysRequired */, 573 // mock(IBiometricAuthenticator.class)); 574 // final PromptInfo promptInfo = 575 // createPromptInfo(Authenticators.BIOMETRIC_STRONG 576 // | Authenticators. DEVICE_CREDENTIAL); 577 // final PreAuthInfo preAuthInfo = createPreAuthInfo(mSensors, 0, promptInfo, false); 578 // assertEquals(BiometricManager.BIOMETRIC_SUCCESS, preAuthInfo.getCanAuthenticateResult()); 579 // for (BiometricSensor sensor : preAuthInfo.eligibleSensors) { 580 // assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState()); 581 // } 582 // } 583 testInvokesCancel(Consumer<AuthSession> sessionConsumer)584 private void testInvokesCancel(Consumer<AuthSession> sessionConsumer) throws RemoteException { 585 final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class); 586 587 setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator); 588 final AuthSession session = createAuthSession(mSensors, 589 false /* checkDevicePolicyManager */, 590 Authenticators.BIOMETRIC_STRONG, 591 TEST_REQUEST_ID, 592 0 /* operationId */, 593 0 /* userId */); 594 595 session.goToInitialState(); 596 assertEquals(STATE_AUTH_CALLED, session.getState()); 597 598 sessionConsumer.accept(session); 599 600 verify(faceAuthenticator).cancelAuthenticationFromService( 601 eq(mToken), eq(TEST_PACKAGE), eq(TEST_REQUEST_ID)); 602 } 603 createPreAuthInfo(List<BiometricSensor> sensors, int userId, PromptInfo promptInfo, boolean checkDevicePolicyManager)604 private PreAuthInfo createPreAuthInfo(List<BiometricSensor> sensors, int userId, 605 PromptInfo promptInfo, boolean checkDevicePolicyManager) throws RemoteException { 606 return PreAuthInfo.create(mTrustManager, 607 mDevicePolicyManager, 608 mSettingObserver, 609 sensors, 610 userId, 611 promptInfo, 612 TEST_PACKAGE, 613 checkDevicePolicyManager, 614 mContext, 615 mBiometricCameraManager); 616 } 617 createAuthSession(List<BiometricSensor> sensors, boolean checkDevicePolicyManager, @Authenticators.Types int authenticators, long requestId, long operationId, int userId)618 private AuthSession createAuthSession(List<BiometricSensor> sensors, 619 boolean checkDevicePolicyManager, @Authenticators.Types int authenticators, 620 long requestId, long operationId, int userId) throws RemoteException { 621 622 final PromptInfo promptInfo = createPromptInfo(authenticators); 623 624 final PreAuthInfo preAuthInfo = createPreAuthInfo(sensors, userId, promptInfo, 625 checkDevicePolicyManager); 626 return new AuthSession(mContext, mBiometricContext, mStatusBarService, mSysuiReceiver, 627 mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, mToken, requestId, 628 operationId, userId, mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo, 629 false /* debugEnabled */, mFingerprintSensorProps, mBiometricFrameworkStatsLogger); 630 } 631 createPromptInfo(@uthenticators.Types int authenticators)632 private PromptInfo createPromptInfo(@Authenticators.Types int authenticators) { 633 PromptInfo promptInfo = new PromptInfo(); 634 promptInfo.setAuthenticators(authenticators); 635 return promptInfo; 636 } 637 setupFingerprint(int id, @FingerprintSensorProperties.SensorType int type)638 private void setupFingerprint(int id, @FingerprintSensorProperties.SensorType int type) 639 throws RemoteException { 640 IBiometricAuthenticator fingerprintAuthenticator = mock(IBiometricAuthenticator.class); 641 when(fingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true); 642 when(fingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true); 643 mSensors.add(new BiometricSensor(mContext, id, 644 TYPE_FINGERPRINT /* modality */, 645 Authenticators.BIOMETRIC_STRONG /* strength */, 646 fingerprintAuthenticator) { 647 @Override 648 boolean confirmationAlwaysRequired(int userId) { 649 return false; // no-op / unsupported 650 } 651 652 @Override 653 boolean confirmationSupported() { 654 return false; // fingerprint does not support confirmation 655 } 656 }); 657 658 final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); 659 componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */, 660 "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */, 661 "00000001" /* serialNumber */, "" /* softwareVersion */)); 662 componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */, 663 "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */, 664 "vendor/version/revision" /* softwareVersion */)); 665 666 mFingerprintSensorProps.add(new FingerprintSensorPropertiesInternal(id, 667 SensorProperties.STRENGTH_STRONG, 668 5 /* maxEnrollmentsPerUser */, 669 componentInfo, 670 type, 671 false /* resetLockoutRequiresHardwareAuthToken */)); 672 673 when(mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true); 674 } 675 setupFace(int id, boolean confirmationAlwaysRequired, IBiometricAuthenticator authenticator)676 private void setupFace(int id, boolean confirmationAlwaysRequired, 677 IBiometricAuthenticator authenticator) throws RemoteException { 678 when(authenticator.isHardwareDetected(any())).thenReturn(true); 679 when(authenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true); 680 mSensors.add(new BiometricSensor(mContext, id, 681 TYPE_FACE /* modality */, 682 Authenticators.BIOMETRIC_STRONG /* strength */, 683 authenticator) { 684 @Override 685 boolean confirmationAlwaysRequired(int userId) { 686 return confirmationAlwaysRequired; 687 } 688 689 @Override 690 boolean confirmationSupported() { 691 return true; 692 } 693 }); 694 695 when(mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true); 696 } 697 } 698