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.sensors; 18 19 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED; 20 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_SUCCESS; 21 22 import static com.google.common.truth.Truth.assertThat; 23 24 import static junit.framework.Assert.assertTrue; 25 import static junit.framework.Assert.fail; 26 27 import static org.junit.Assert.assertEquals; 28 import static org.junit.Assert.assertFalse; 29 import static org.junit.Assert.assertNotEquals; 30 import static org.junit.Assert.assertNotNull; 31 import static org.junit.Assert.assertNull; 32 import static org.mockito.ArgumentMatchers.any; 33 import static org.mockito.ArgumentMatchers.anyBoolean; 34 import static org.mockito.ArgumentMatchers.anyInt; 35 import static org.mockito.ArgumentMatchers.eq; 36 import static org.mockito.Mockito.mock; 37 import static org.mockito.Mockito.never; 38 import static org.mockito.Mockito.verify; 39 import static org.mockito.Mockito.when; 40 41 import android.content.Context; 42 import android.hardware.biometrics.AuthenticateOptions; 43 import android.hardware.biometrics.BiometricAuthenticator; 44 import android.hardware.biometrics.BiometricConstants; 45 import android.hardware.biometrics.BiometricsProtoEnums; 46 import android.hardware.biometrics.IBiometricService; 47 import android.hardware.fingerprint.Fingerprint; 48 import android.os.Binder; 49 import android.os.Handler; 50 import android.os.IBinder; 51 import android.os.RemoteException; 52 import android.platform.test.annotations.Presubmit; 53 import android.testing.AndroidTestingRunner; 54 import android.testing.TestableContext; 55 import android.testing.TestableLooper; 56 import android.util.Slog; 57 58 import androidx.annotation.NonNull; 59 import androidx.annotation.Nullable; 60 import androidx.test.InstrumentationRegistry; 61 import androidx.test.filters.SmallTest; 62 63 import com.android.server.biometrics.log.BiometricContext; 64 import com.android.server.biometrics.log.BiometricLogger; 65 import com.android.server.biometrics.nano.BiometricSchedulerProto; 66 import com.android.server.biometrics.nano.BiometricsProto; 67 import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils; 68 import com.android.server.biometrics.sensors.fingerprint.aidl.AidlSession; 69 70 import org.junit.Before; 71 import org.junit.Rule; 72 import org.junit.Test; 73 import org.junit.runner.RunWith; 74 import org.mockito.Mock; 75 import org.mockito.MockitoAnnotations; 76 77 import java.util.ArrayList; 78 import java.util.HashMap; 79 import java.util.List; 80 import java.util.Map; 81 import java.util.function.Supplier; 82 83 @Presubmit 84 @SmallTest 85 @RunWith(AndroidTestingRunner.class) 86 @TestableLooper.RunWithLooper(setAsMainLooper = true) 87 public class BiometricSchedulerTest { 88 89 private static final String TAG = "BiometricSchedulerTest"; 90 private static final int TEST_SENSOR_ID = 1; 91 private static final int LOG_NUM_RECENT_OPERATIONS = 2; 92 private static final Fingerprint TEST_FINGERPRINT = new Fingerprint("" /* name */, 93 1 /* fingerId */, TEST_SENSOR_ID); 94 95 @Rule 96 public final TestableContext mContext = new TestableContext( 97 InstrumentationRegistry.getContext(), null); 98 private BiometricScheduler mScheduler; 99 private IBinder mToken; 100 @Mock 101 private IBiometricService mBiometricService; 102 @Mock 103 private BiometricContext mBiometricContext; 104 @Mock 105 private AuthSessionCoordinator mAuthSessionCoordinator; 106 107 @Before setUp()108 public void setUp() { 109 MockitoAnnotations.initMocks(this); 110 mToken = new Binder(); 111 when(mAuthSessionCoordinator.getLockoutStateFor(anyInt(), anyInt())).thenReturn( 112 BIOMETRIC_SUCCESS); 113 when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator); 114 mScheduler = new BiometricScheduler(TAG, new Handler(TestableLooper.get(this).getLooper()), 115 BiometricScheduler.SENSOR_TYPE_UNKNOWN, null /* gestureAvailabilityTracker */, 116 mBiometricService, LOG_NUM_RECENT_OPERATIONS); 117 } 118 119 @Test testClientDuplicateFinish_ignoredBySchedulerAndDoesNotCrash()120 public void testClientDuplicateFinish_ignoredBySchedulerAndDoesNotCrash() { 121 final Supplier<Object> nonNullDaemon = () -> mock(Object.class); 122 123 final HalClientMonitor<Object> client1 = new TestHalClientMonitor(mContext, mToken, 124 nonNullDaemon); 125 final HalClientMonitor<Object> client2 = new TestHalClientMonitor(mContext, mToken, 126 nonNullDaemon); 127 mScheduler.scheduleClientMonitor(client1); 128 mScheduler.scheduleClientMonitor(client2); 129 130 client1.mCallback.onClientFinished(client1, true /* success */); 131 client1.mCallback.onClientFinished(client1, true /* success */); 132 } 133 134 @Test testRemovesPendingOperations_whenNullHal_andNotBiometricPrompt()135 public void testRemovesPendingOperations_whenNullHal_andNotBiometricPrompt() { 136 // Even if second client has a non-null daemon, it needs to be canceled. 137 final TestHalClientMonitor client1 = new TestHalClientMonitor(mContext, mToken, () -> null); 138 final TestHalClientMonitor client2 = new TestHalClientMonitor(mContext, mToken, 139 () -> mock(Object.class)); 140 141 final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class); 142 final ClientMonitorCallback callback2 = mock(ClientMonitorCallback.class); 143 144 // Pretend the scheduler is busy so the first operation doesn't start right away. We want 145 // to pretend like there are two operations in the queue before kicking things off 146 mScheduler.mCurrentOperation = new BiometricSchedulerOperation( 147 mock(BaseClientMonitor.class), mock(ClientMonitorCallback.class)); 148 149 mScheduler.scheduleClientMonitor(client1, callback1); 150 assertEquals(1, mScheduler.mPendingOperations.size()); 151 // client1 is pending. Allow the scheduler to start once second client is added. 152 mScheduler.mCurrentOperation = null; 153 mScheduler.scheduleClientMonitor(client2, callback2); 154 waitForIdle(); 155 156 assertTrue(client1.mUnableToStart); 157 verify(callback1).onClientFinished(eq(client1), eq(false) /* success */); 158 verify(callback1, never()).onClientStarted(any()); 159 160 assertTrue(client2.mUnableToStart); 161 verify(callback2).onClientFinished(eq(client2), eq(false) /* success */); 162 verify(callback2, never()).onClientStarted(any()); 163 164 assertTrue(mScheduler.mPendingOperations.isEmpty()); 165 } 166 167 @Test testRemovesOnlyBiometricPromptOperation_whenNullHal()168 public void testRemovesOnlyBiometricPromptOperation_whenNullHal() throws Exception { 169 // Second non-BiometricPrompt client has a valid daemon 170 final Object daemon2 = mock(Object.class); 171 172 final ClientMonitorCallbackConverter listener1 = mock(ClientMonitorCallbackConverter.class); 173 174 final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext, () -> null, 175 mToken, listener1, mBiometricContext); 176 final TestHalClientMonitor client2 = new TestHalClientMonitor(mContext, mToken, 177 () -> daemon2); 178 179 final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class); 180 final ClientMonitorCallback callback2 = mock(ClientMonitorCallback.class); 181 182 // Pretend the scheduler is busy so the first operation doesn't start right away. We want 183 // to pretend like there are two operations in the queue before kicking things off 184 mScheduler.mCurrentOperation = new BiometricSchedulerOperation( 185 mock(BaseClientMonitor.class), mock(ClientMonitorCallback.class)); 186 187 mScheduler.scheduleClientMonitor(client1, callback1); 188 assertEquals(1, mScheduler.mPendingOperations.size()); 189 // client1 is pending. Allow the scheduler to start once second client is added. 190 mScheduler.mCurrentOperation = null; 191 mScheduler.scheduleClientMonitor(client2, callback2); 192 waitForIdle(); 193 194 // Simulate that the BiometricPrompt client's sensor is ready 195 mScheduler.startPreparedClient(client1.getCookie()); 196 197 // Client 1 cleans up properly 198 verify(listener1).onError(eq(TEST_SENSOR_ID), anyInt(), 199 eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE), eq(0)); 200 verify(callback1).onClientFinished(eq(client1), eq(false) /* success */); 201 verify(callback1, never()).onClientStarted(any()); 202 203 // Client 2 was able to start 204 assertFalse(client2.mUnableToStart); 205 assertTrue(client2.mStarted); 206 verify(callback2).onClientStarted(eq(client2)); 207 } 208 209 @Test testCancelNotInvoked_whenOperationWaitingForCookie()210 public void testCancelNotInvoked_whenOperationWaitingForCookie() { 211 final Supplier<Object> lazyDaemon1 = () -> mock(Object.class); 212 final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext, lazyDaemon1, 213 mToken, mock(ClientMonitorCallbackConverter.class), mBiometricContext); 214 final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class); 215 216 // Schedule a BiometricPrompt authentication request 217 mScheduler.scheduleClientMonitor(client1, callback1); 218 219 assertNotEquals(0, 220 mScheduler.mCurrentOperation.isReadyToStart(mock(ClientMonitorCallback.class))); 221 assertEquals(client1, mScheduler.mCurrentOperation.getClientMonitor()); 222 assertEquals(0, mScheduler.mPendingOperations.size()); 223 224 // Request it to be canceled. The operation can be canceled immediately, and the scheduler 225 // should go back to idle, since in this case the framework has not even requested the HAL 226 // to authenticate yet. 227 mScheduler.cancelAuthenticationOrDetection(mToken, 1 /* requestId */); 228 waitForIdle(); 229 assertTrue(client1.isAlreadyDone()); 230 assertTrue(client1.mDestroyed); 231 assertFalse(client1.mStartedHal); 232 assertNull(mScheduler.mCurrentOperation); 233 } 234 235 @Test testProtoDump_singleCurrentOperation()236 public void testProtoDump_singleCurrentOperation() throws Exception { 237 // Nothing so far 238 BiometricSchedulerProto bsp = getDump(true /* clearSchedulerBuffer */); 239 assertEquals(BiometricsProto.CM_NONE, bsp.currentOperation); 240 assertEquals(0, bsp.totalOperations); 241 // TODO:(b/178828362) See bug and/or commit message :/ 242 // assertEquals(0, bsp.recentOperations.length); 243 244 // Pretend the scheduler is busy enrolling, and check the proto dump again. 245 final TestHalClientMonitor client = new TestHalClientMonitor(mContext, mToken, 246 () -> mock(Object.class), 0, BiometricsProto.CM_ENROLL); 247 mScheduler.scheduleClientMonitor(client); 248 waitForIdle(); 249 bsp = getDump(true /* clearSchedulerBuffer */); 250 assertEquals(BiometricsProto.CM_ENROLL, bsp.currentOperation); 251 // No operations have completed yet 252 assertEquals(0, bsp.totalOperations); 253 254 // TODO:(b/178828362) See bug and/or commit message :/ 255 assertEquals(1, bsp.recentOperations.length); 256 assertEquals(BiometricsProto.CM_NONE, bsp.recentOperations[0]); 257 258 // Finish this operation, so the next scheduled one can start 259 client.getCallback().onClientFinished(client, true); 260 } 261 262 @Test testProtoDump_fifo()263 public void testProtoDump_fifo() throws Exception { 264 // Add the first operation 265 final TestHalClientMonitor client = new TestHalClientMonitor(mContext, mToken, 266 () -> mock(Object.class), 0, BiometricsProto.CM_ENROLL); 267 mScheduler.scheduleClientMonitor(client); 268 waitForIdle(); 269 BiometricSchedulerProto bsp = getDump(false /* clearSchedulerBuffer */); 270 assertEquals(BiometricsProto.CM_ENROLL, bsp.currentOperation); 271 // No operations have completed yet 272 assertEquals(0, bsp.totalOperations); 273 // TODO:(b/178828362) See bug and/or commit message :/ 274 // assertEquals(0, bsp.recentOperations.length); 275 // Finish this operation, so the next scheduled one can start 276 client.getCallback().onClientFinished(client, true); 277 278 // Add another operation 279 final TestHalClientMonitor client2 = new TestHalClientMonitor(mContext, mToken, 280 () -> mock(Object.class), 0, BiometricsProto.CM_REMOVE); 281 mScheduler.scheduleClientMonitor(client2); 282 waitForIdle(); 283 bsp = getDump(false /* clearSchedulerBuffer */); 284 assertEquals(BiometricsProto.CM_REMOVE, bsp.currentOperation); 285 assertEquals(1, bsp.totalOperations); // Enroll finished 286 assertEquals(1, bsp.recentOperations.length); 287 assertEquals(BiometricsProto.CM_ENROLL, bsp.recentOperations[0]); 288 client2.getCallback().onClientFinished(client2, true); 289 290 // And another operation 291 final TestHalClientMonitor client3 = new TestHalClientMonitor(mContext, mToken, 292 () -> mock(Object.class), 0, BiometricsProto.CM_AUTHENTICATE); 293 mScheduler.scheduleClientMonitor(client3); 294 waitForIdle(); 295 bsp = getDump(false /* clearSchedulerBuffer */); 296 assertEquals(BiometricsProto.CM_AUTHENTICATE, bsp.currentOperation); 297 assertEquals(2, bsp.totalOperations); 298 assertEquals(2, bsp.recentOperations.length); 299 assertEquals(BiometricsProto.CM_ENROLL, bsp.recentOperations[0]); 300 assertEquals(BiometricsProto.CM_REMOVE, bsp.recentOperations[1]); 301 302 // Finish the last operation, and check that the first operation is removed from the FIFO. 303 // The test initializes the scheduler with "LOG_NUM_RECENT_OPERATIONS = 2" :) 304 client3.getCallback().onClientFinished(client3, true); 305 waitForIdle(); 306 bsp = getDump(true /* clearSchedulerBuffer */); 307 assertEquals(3, bsp.totalOperations); 308 assertEquals(2, bsp.recentOperations.length); 309 assertEquals(BiometricsProto.CM_REMOVE, bsp.recentOperations[0]); 310 assertEquals(BiometricsProto.CM_AUTHENTICATE, bsp.recentOperations[1]); 311 // Nothing is currently running anymore 312 assertEquals(BiometricsProto.CM_NONE, bsp.currentOperation); 313 314 // RecentOperations queue is cleared (by the previous dump) 315 bsp = getDump(true /* clearSchedulerBuffer */); 316 317 // TODO:(b/178828362) See bug and/or commit message :/ 318 assertEquals(1, bsp.recentOperations.length); 319 assertEquals(BiometricsProto.CM_NONE, bsp.recentOperations[0]); 320 } 321 322 @Test testCancelPendingAuth()323 public void testCancelPendingAuth() throws RemoteException { 324 final Supplier<Object> lazyDaemon = () -> mock(Object.class); 325 final TestHalClientMonitor client1 = new TestHalClientMonitor(mContext, mToken, lazyDaemon); 326 final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); 327 final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext, lazyDaemon, 328 mToken, callback, mBiometricContext); 329 330 // Add a non-cancellable client, then add the auth client 331 mScheduler.scheduleClientMonitor(client1); 332 mScheduler.scheduleClientMonitor(client2); 333 waitForIdle(); 334 335 assertEquals(mScheduler.getCurrentClient(), client1); 336 assertFalse(mScheduler.mPendingOperations.getFirst().isStarted()); 337 338 // Request cancel before the authentication client has started 339 mScheduler.cancelAuthenticationOrDetection(mToken, 1 /* requestId */); 340 waitForIdle(); 341 assertTrue(mScheduler.mPendingOperations.getFirst().isMarkedCanceling()); 342 343 // Finish the blocking client. The authentication client should send ERROR_CANCELED 344 client1.getCallback().onClientFinished(client1, true /* success */); 345 waitForIdle(); 346 verify(callback).onError(anyInt(), anyInt(), 347 eq(BIOMETRIC_ERROR_CANCELED), 348 eq(0) /* vendorCode */); 349 assertNull(mScheduler.getCurrentClient()); 350 assertTrue(client1.isAlreadyDone()); 351 assertTrue(client1.mDestroyed); 352 assertTrue(client2.isAlreadyDone()); 353 assertTrue(client2.mDestroyed); 354 } 355 356 @Test testCancels_whenAuthRequestIdNotSet()357 public void testCancels_whenAuthRequestIdNotSet() { 358 testCancelsAuthDetectWhenRequestId(null /* requestId */, 2, true /* started */); 359 } 360 361 @Test testCancels_whenAuthRequestIdNotSet_notStarted()362 public void testCancels_whenAuthRequestIdNotSet_notStarted() { 363 testCancelsAuthDetectWhenRequestId(null /* requestId */, 2, false /* started */); 364 } 365 366 @Test testCancels_whenAuthRequestIdMatches()367 public void testCancels_whenAuthRequestIdMatches() { 368 testCancelsAuthDetectWhenRequestId(200L, 200, true /* started */); 369 } 370 371 @Test testCancels_whenAuthRequestIdMatches_noStarted()372 public void testCancels_whenAuthRequestIdMatches_noStarted() { 373 testCancelsAuthDetectWhenRequestId(200L, 200, false /* started */); 374 } 375 376 @Test testDoesNotCancel_whenAuthRequestIdMismatched()377 public void testDoesNotCancel_whenAuthRequestIdMismatched() { 378 testCancelsAuthDetectWhenRequestId(10L, 20, true /* started */); 379 } 380 381 @Test testDoesNotCancel_whenAuthRequestIdMismatched_notStarted()382 public void testDoesNotCancel_whenAuthRequestIdMismatched_notStarted() { 383 testCancelsAuthDetectWhenRequestId(10L, 20, false /* started */); 384 } 385 testCancelsAuthDetectWhenRequestId(@ullable Long requestId, long cancelRequestId, boolean started)386 private void testCancelsAuthDetectWhenRequestId(@Nullable Long requestId, long cancelRequestId, 387 boolean started) { 388 final Supplier<Object> lazyDaemon = () -> mock(Object.class); 389 final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); 390 testCancelsWhenRequestId(requestId, cancelRequestId, started, 391 new TestAuthenticationClient(mContext, lazyDaemon, mToken, callback, 392 mBiometricContext)); 393 } 394 395 @Test testCancels_whenEnrollRequestIdNotSet()396 public void testCancels_whenEnrollRequestIdNotSet() { 397 testCancelsEnrollWhenRequestId(null /* requestId */, 2, false /* started */); 398 } 399 400 @Test testCancels_whenEnrollRequestIdMatches()401 public void testCancels_whenEnrollRequestIdMatches() { 402 testCancelsEnrollWhenRequestId(200L, 200, false /* started */); 403 } 404 405 @Test testDoesNotCancel_whenEnrollRequestIdMismatched()406 public void testDoesNotCancel_whenEnrollRequestIdMismatched() { 407 testCancelsEnrollWhenRequestId(10L, 20, false /* started */); 408 } 409 410 @Test testCancelAuthenticationClientWithoutStarting()411 public void testCancelAuthenticationClientWithoutStarting() { 412 final Supplier<Object> lazyDaemon = () -> mock(Object.class); 413 final TestHalClientMonitor client1 = new TestHalClientMonitor(mContext, mToken, lazyDaemon); 414 final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); 415 final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext, lazyDaemon, 416 mToken, callback, mBiometricContext); 417 418 //Schedule authentication client to the pending queue 419 mScheduler.scheduleClientMonitor(client1); 420 mScheduler.scheduleClientMonitor(client2); 421 waitForIdle(); 422 423 assertThat(mScheduler.getCurrentClient()).isEqualTo(client1); 424 425 client2.cancel(); 426 waitForIdle(); 427 428 assertThat(client2.isAlreadyCancelled()).isTrue(); 429 430 client1.getCallback().onClientFinished(client1, false); 431 waitForIdle(); 432 433 assertThat(mScheduler.getCurrentClient()).isNull(); 434 } 435 436 @Test testCancelAuthenticationClientWithoutStarting_whenAppCrashes()437 public void testCancelAuthenticationClientWithoutStarting_whenAppCrashes() { 438 final Supplier<Object> lazyDaemon = () -> mock(Object.class); 439 final TestHalClientMonitor client1 = new TestHalClientMonitor(mContext, mToken, lazyDaemon); 440 final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); 441 final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext, lazyDaemon, 442 mToken, callback, mBiometricContext); 443 444 //Schedule authentication client to the pending queue 445 mScheduler.scheduleClientMonitor(client1); 446 mScheduler.scheduleClientMonitor(client2); 447 waitForIdle(); 448 449 assertThat(mScheduler.getCurrentClient()).isEqualTo(client1); 450 451 //App crashes 452 client2.binderDied(); 453 waitForIdle(); 454 455 assertThat(client2.isAlreadyCancelled()).isTrue(); 456 457 client1.getCallback().onClientFinished(client1, false); 458 waitForIdle(); 459 460 assertThat(mScheduler.getCurrentClient()).isNull(); 461 } 462 testCancelsEnrollWhenRequestId(@ullable Long requestId, long cancelRequestId, boolean started)463 private void testCancelsEnrollWhenRequestId(@Nullable Long requestId, long cancelRequestId, 464 boolean started) { 465 final Supplier<Object> lazyDaemon = () -> mock(Object.class); 466 final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); 467 testCancelsWhenRequestId(requestId, cancelRequestId, started, 468 new TestEnrollClient(mContext, lazyDaemon, mToken, callback)); 469 } 470 testCancelsWhenRequestId(@ullable Long requestId, long cancelRequestId, boolean started, HalClientMonitor<?> client)471 private void testCancelsWhenRequestId(@Nullable Long requestId, long cancelRequestId, 472 boolean started, HalClientMonitor<?> client) { 473 final boolean matches = requestId == null || requestId == cancelRequestId; 474 if (requestId != null) { 475 client.setRequestId(requestId); 476 } 477 478 final boolean isAuth = client instanceof TestAuthenticationClient; 479 final boolean isEnroll = client instanceof TestEnrollClient; 480 481 mScheduler.scheduleClientMonitor(client); 482 if (started) { 483 mScheduler.startPreparedClient(client.getCookie()); 484 } 485 waitForIdle(); 486 if (isAuth) { 487 mScheduler.cancelAuthenticationOrDetection(mToken, cancelRequestId); 488 } else if (isEnroll) { 489 mScheduler.cancelEnrollment(mToken, cancelRequestId); 490 } else { 491 fail("unexpected operation type"); 492 } 493 waitForIdle(); 494 495 if (isAuth) { 496 // auth clients that were waiting for cookie when canceled should never invoke the hal 497 final TestAuthenticationClient authClient = (TestAuthenticationClient) client; 498 assertEquals(matches && started ? 1 : 0, authClient.mNumCancels); 499 assertEquals(started, authClient.mStartedHal); 500 } else if (isEnroll) { 501 final TestEnrollClient enrollClient = (TestEnrollClient) client; 502 assertEquals(matches ? 1 : 0, enrollClient.mNumCancels); 503 assertTrue(enrollClient.mStartedHal); 504 } 505 506 if (matches) { 507 if (started || isEnroll) { // prep'd auth clients and enroll clients 508 assertTrue(mScheduler.mCurrentOperation.isCanceling()); 509 } 510 } else { 511 if (started || isEnroll) { // prep'd auth clients and enroll clients 512 assertTrue(mScheduler.mCurrentOperation.isStarted()); 513 } else { 514 assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart( 515 mock(ClientMonitorCallback.class))); 516 } 517 } 518 } 519 520 @Test testCancelsPending_whenAuthRequestIdsSet()521 public void testCancelsPending_whenAuthRequestIdsSet() { 522 final long requestId1 = 10; 523 final long requestId2 = 20; 524 final Supplier<Object> lazyDaemon = () -> mock(Object.class); 525 final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); 526 final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext, lazyDaemon, 527 mToken, callback, mBiometricContext); 528 client1.setRequestId(requestId1); 529 final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext, lazyDaemon, 530 mToken, callback, mBiometricContext); 531 client2.setRequestId(requestId2); 532 533 mScheduler.scheduleClientMonitor(client1); 534 mScheduler.scheduleClientMonitor(client2); 535 mScheduler.startPreparedClient(client1.getCookie()); 536 waitForIdle(); 537 mScheduler.cancelAuthenticationOrDetection(mToken, 9999); 538 waitForIdle(); 539 540 assertTrue(mScheduler.mCurrentOperation.isStarted()); 541 assertFalse(mScheduler.mPendingOperations.getFirst().isStarted()); 542 543 mScheduler.cancelAuthenticationOrDetection(mToken, requestId2); 544 waitForIdle(); 545 546 assertTrue(mScheduler.mCurrentOperation.isStarted()); 547 assertTrue(mScheduler.mPendingOperations.getFirst().isMarkedCanceling()); 548 } 549 550 @Test testInterruptPrecedingClients_whenExpected()551 public void testInterruptPrecedingClients_whenExpected() { 552 final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class); 553 when(interruptableMonitor.isInterruptable()).thenReturn(true); 554 555 final BaseClientMonitor interrupter = mock(BaseClientMonitor.class); 556 when(interrupter.interruptsPrecedingClients()).thenReturn(true); 557 558 mScheduler.scheduleClientMonitor(interruptableMonitor); 559 mScheduler.scheduleClientMonitor(interrupter); 560 waitForIdle(); 561 562 verify(interruptableMonitor).cancel(); 563 mScheduler.getInternalCallback().onClientFinished(interruptableMonitor, true /* success */); 564 } 565 566 @Test testDoesNotInterruptPrecedingClients_whenNotExpected()567 public void testDoesNotInterruptPrecedingClients_whenNotExpected() { 568 final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class); 569 when(interruptableMonitor.isInterruptable()).thenReturn(true); 570 571 final BaseClientMonitor interrupter = mock(BaseClientMonitor.class); 572 when(interrupter.interruptsPrecedingClients()).thenReturn(false); 573 574 mScheduler.scheduleClientMonitor(interruptableMonitor); 575 mScheduler.scheduleClientMonitor(interrupter); 576 waitForIdle(); 577 578 verify(interruptableMonitor, never()).cancel(); 579 } 580 581 @Test testClientDestroyed_afterFinish()582 public void testClientDestroyed_afterFinish() { 583 final Supplier<Object> nonNullDaemon = () -> mock(Object.class); 584 final TestHalClientMonitor client = new TestHalClientMonitor(mContext, mToken, 585 nonNullDaemon); 586 mScheduler.scheduleClientMonitor(client); 587 client.mCallback.onClientFinished(client, true /* success */); 588 waitForIdle(); 589 assertTrue(client.mDestroyed); 590 } 591 592 @Test testClearBiometricQueue_clearsHungAuthOperation()593 public void testClearBiometricQueue_clearsHungAuthOperation() { 594 // Creating a hung client 595 final TestableLooper looper = TestableLooper.get(this); 596 final Supplier<Object> lazyDaemon1 = () -> mock(Object.class); 597 final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext, 598 lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class), 0 /* cookie */, 599 mBiometricContext); 600 final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class); 601 602 mScheduler.scheduleClientMonitor(client1, callback1); 603 waitForIdle(); 604 605 mScheduler.startWatchdog(); 606 waitForIdle(); 607 608 //Checking client is hung 609 verify(callback1).onClientStarted(client1); 610 verify(callback1, never()).onClientFinished(any(), anyBoolean()); 611 assertNotNull(mScheduler.mCurrentOperation); 612 assertEquals(0, mScheduler.getCurrentPendingCount()); 613 614 looper.moveTimeForward(10000); 615 waitForIdle(); 616 looper.moveTimeForward(3000); 617 waitForIdle(); 618 619 // The hung client did not honor this operation, verify onError and authenticated 620 // were never called. 621 assertFalse(client1.mOnErrorCalled); 622 assertFalse(client1.mAuthenticateCalled); 623 verify(callback1).onClientFinished(client1, false /* success */); 624 assertNull(mScheduler.mCurrentOperation); 625 assertEquals(0, mScheduler.getCurrentPendingCount()); 626 } 627 628 @Test testAuthWorks_afterClearBiometricQueue()629 public void testAuthWorks_afterClearBiometricQueue() { 630 // Creating a hung client 631 final TestableLooper looper = TestableLooper.get(this); 632 final Supplier<Object> lazyDaemon1 = () -> mock(Object.class); 633 final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext, 634 lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class), 0 /* cookie */, 635 mBiometricContext); 636 final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class); 637 638 mScheduler.scheduleClientMonitor(client1, callback1); 639 640 assertEquals(client1, mScheduler.mCurrentOperation.getClientMonitor()); 641 assertEquals(0, mScheduler.getCurrentPendingCount()); 642 643 //Checking client is hung 644 waitForIdle(); 645 verify(callback1, never()).onClientFinished(any(), anyBoolean()); 646 647 //Start watchdog 648 mScheduler.startWatchdog(); 649 waitForIdle(); 650 651 // The watchdog should kick off the cancellation 652 looper.moveTimeForward(10000); 653 waitForIdle(); 654 // After 10 seconds the HAL has 3 seconds to respond to a cancel 655 looper.moveTimeForward(3000); 656 waitForIdle(); 657 658 // The hung client did not honor this operation, verify onError and authenticated 659 // were never called. 660 assertFalse(client1.mOnErrorCalled); 661 assertFalse(client1.mAuthenticateCalled); 662 verify(callback1).onClientFinished(client1, false /* success */); 663 assertEquals(0, mScheduler.getCurrentPendingCount()); 664 assertNull(mScheduler.mCurrentOperation); 665 666 667 //Run additional auth client 668 final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext, 669 lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class), 0 /* cookie */, 670 mBiometricContext); 671 final ClientMonitorCallback callback2 = mock(ClientMonitorCallback.class); 672 673 mScheduler.scheduleClientMonitor(client2, callback2); 674 675 assertEquals(client2, mScheduler.mCurrentOperation.getClientMonitor()); 676 assertEquals(0, mScheduler.getCurrentPendingCount()); 677 678 //Start watchdog 679 mScheduler.startWatchdog(); 680 waitForIdle(); 681 mScheduler.scheduleClientMonitor(mock(BaseClientMonitor.class), 682 mock(ClientMonitorCallback.class)); 683 waitForIdle(); 684 685 //Ensure auth client passes 686 verify(callback2).onClientStarted(client2); 687 client2.getCallback().onClientFinished(client2, true); 688 waitForIdle(); 689 690 looper.moveTimeForward(10000); 691 waitForIdle(); 692 // After 10 seconds the HAL has 3 seconds to respond to a cancel 693 looper.moveTimeForward(3000); 694 waitForIdle(); 695 696 //Asserting auth client passes 697 assertTrue(client2.isAlreadyDone()); 698 assertNotNull(mScheduler.mCurrentOperation); 699 } 700 701 @Test testClearBiometricQueue_doesNotClearOperationsWhenQueueNotStuck()702 public void testClearBiometricQueue_doesNotClearOperationsWhenQueueNotStuck() { 703 //Creating clients 704 final TestableLooper looper = TestableLooper.get(this); 705 final Supplier<Object> lazyDaemon1 = () -> mock(Object.class); 706 final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext, 707 lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class), 0 /* cookie */, 708 mBiometricContext); 709 final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class); 710 711 mScheduler.scheduleClientMonitor(client1, callback1); 712 //Start watchdog 713 mScheduler.startWatchdog(); 714 waitForIdle(); 715 mScheduler.scheduleClientMonitor(mock(BaseClientMonitor.class), 716 mock(ClientMonitorCallback.class)); 717 mScheduler.scheduleClientMonitor(mock(BaseClientMonitor.class), 718 mock(ClientMonitorCallback.class)); 719 waitForIdle(); 720 721 assertEquals(client1, mScheduler.mCurrentOperation.getClientMonitor()); 722 assertEquals(2, mScheduler.getCurrentPendingCount()); 723 verify(callback1, never()).onClientFinished(any(), anyBoolean()); 724 verify(callback1).onClientStarted(client1); 725 726 //Client finishes successfully 727 client1.getCallback().onClientFinished(client1, true); 728 waitForIdle(); 729 730 // The watchdog should kick off the cancellation 731 looper.moveTimeForward(10000); 732 waitForIdle(); 733 // After 10 seconds the HAL has 3 seconds to respond to a cancel 734 looper.moveTimeForward(3000); 735 waitForIdle(); 736 737 //Watchdog does not clear pending operations 738 assertEquals(1, mScheduler.getCurrentPendingCount()); 739 assertNotNull(mScheduler.mCurrentOperation); 740 741 } 742 743 @Test testTwoInternalCleanupOps_withFirstFavorHalEnrollment()744 public void testTwoInternalCleanupOps_withFirstFavorHalEnrollment() throws Exception { 745 final String owner = "test.owner"; 746 final int userId = 1; 747 final Supplier<Object> daemon = () -> mock(AidlSession.class); 748 final FingerprintUtils utils = mock(FingerprintUtils.class); 749 final Map<Integer, Long> authenticatorIds = new HashMap<>(); 750 final ClientMonitorCallback callback0 = mock(ClientMonitorCallback.class); 751 final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class); 752 final ClientMonitorCallback callback2 = mock(ClientMonitorCallback.class); 753 754 final TestInternalCleanupClient client1 = new 755 TestInternalCleanupClient(mContext, daemon, userId, 756 owner, TEST_SENSOR_ID, mock(BiometricLogger.class), 757 mBiometricContext, utils, authenticatorIds); 758 final TestInternalCleanupClient client2 = new 759 TestInternalCleanupClient(mContext, daemon, userId, 760 owner, TEST_SENSOR_ID, mock(BiometricLogger.class), 761 mBiometricContext, utils, authenticatorIds); 762 763 //add initial start client to scheduler, so later clients will be on pending operation queue 764 final TestHalClientMonitor startClient = new TestHalClientMonitor(mContext, mToken, 765 daemon); 766 mScheduler.scheduleClientMonitor(startClient, callback0); 767 768 //add first cleanup client which favors enrollments from HAL 769 client1.setFavorHalEnrollments(); 770 mScheduler.scheduleClientMonitor(client1, callback1); 771 assertEquals(1, mScheduler.mPendingOperations.size()); 772 773 when(utils.getBiometricsForUser(mContext, userId)).thenAnswer(i -> 774 new ArrayList<>(client1.getFingerprints())); 775 776 //add second cleanup client 777 mScheduler.scheduleClientMonitor(client2, callback2); 778 779 //finish the start client, so other pending clients are processed 780 startClient.getCallback().onClientFinished(startClient, true); 781 782 waitForIdle(); 783 784 assertTrue(client1.isAlreadyDone()); 785 assertTrue(client2.isAlreadyDone()); 786 assertNull(mScheduler.mCurrentOperation); 787 verify(utils, never()).removeBiometricForUser(mContext, userId, 788 TEST_FINGERPRINT.getBiometricId()); 789 assertEquals(1, client1.getFingerprints().size()); 790 } 791 792 getDump(boolean clearSchedulerBuffer)793 private BiometricSchedulerProto getDump(boolean clearSchedulerBuffer) throws Exception { 794 return BiometricSchedulerProto.parseFrom(mScheduler.dumpProtoState(clearSchedulerBuffer)); 795 } 796 waitForIdle()797 private void waitForIdle() { 798 TestableLooper.get(this).processAllMessages(); 799 } 800 801 private static class TestAuthenticateOptions implements AuthenticateOptions { 802 @Override getUserId()803 public int getUserId() { 804 return 0; 805 } 806 807 @Override getSensorId()808 public int getSensorId() { 809 return TEST_SENSOR_ID; 810 } 811 812 @Override getDisplayState()813 public int getDisplayState() { 814 return DISPLAY_STATE_UNKNOWN; 815 } 816 817 @NonNull 818 @Override getOpPackageName()819 public String getOpPackageName() { 820 return "some.test.name"; 821 } 822 823 @Nullable 824 @Override getAttributionTag()825 public String getAttributionTag() { 826 return null; 827 } 828 } 829 830 private static class TestAuthenticationClient 831 extends AuthenticationClient<Object, TestAuthenticateOptions> { 832 boolean mStartedHal = false; 833 boolean mStoppedHal = false; 834 boolean mDestroyed = false; 835 int mNumCancels = 0; 836 boolean mAuthenticateCalled = false; 837 boolean mOnErrorCalled = false; 838 TestAuthenticationClient(@onNull Context context, @NonNull Supplier<Object> lazyDaemon, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, BiometricContext biometricContext)839 TestAuthenticationClient(@NonNull Context context, 840 @NonNull Supplier<Object> lazyDaemon, @NonNull IBinder token, 841 @NonNull ClientMonitorCallbackConverter listener, 842 BiometricContext biometricContext) { 843 this(context, lazyDaemon, token, listener, 1 /* cookie */, biometricContext); 844 } 845 TestAuthenticationClient(@onNull Context context, @NonNull Supplier<Object> lazyDaemon, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int cookie, @NonNull BiometricContext biometricContext)846 TestAuthenticationClient(@NonNull Context context, 847 @NonNull Supplier<Object> lazyDaemon, @NonNull IBinder token, 848 @NonNull ClientMonitorCallbackConverter listener, int cookie, 849 @NonNull BiometricContext biometricContext) { 850 super(context, lazyDaemon, token, listener, 0 /* operationId */, 851 false /* restricted */, new TestAuthenticateOptions(), cookie, 852 false /* requireConfirmation */, 853 mock(BiometricLogger.class), biometricContext, 854 true /* isStrongBiometric */, null /* taskStackListener */, 855 null /* lockoutTracker */, false /* isKeyguard */, 856 true /* shouldVibrate */, 857 0 /* sensorStrength */); 858 } 859 860 @Override stopHalOperation()861 protected void stopHalOperation() { 862 mStoppedHal = true; 863 } 864 865 @Override startHalOperation()866 protected void startHalOperation() { 867 mStartedHal = true; 868 } 869 870 @Override handleLifecycleAfterAuth(boolean authenticated)871 protected void handleLifecycleAfterAuth(boolean authenticated) { 872 } 873 874 @Override onAuthenticated(BiometricAuthenticator.Identifier identifier, boolean authenticated, ArrayList<Byte> hardwareAuthToken)875 public void onAuthenticated(BiometricAuthenticator.Identifier identifier, 876 boolean authenticated, ArrayList<Byte> hardwareAuthToken) { 877 mAuthenticateCalled = true; 878 } 879 880 @Override onErrorInternal(int errorCode, int vendorCode, boolean finish)881 protected void onErrorInternal(int errorCode, int vendorCode, boolean finish) { 882 mOnErrorCalled = true; 883 } 884 885 @Override wasUserDetected()886 public boolean wasUserDetected() { 887 return false; 888 } 889 890 @Override destroy()891 public void destroy() { 892 mDestroyed = true; 893 super.destroy(); 894 } 895 896 @Override cancel()897 public void cancel() { 898 mNumCancels++; 899 super.cancel(); 900 } 901 } 902 903 private static class TestEnrollClient extends EnrollClient<Object> { 904 boolean mStartedHal = false; 905 boolean mStoppedHal = false; 906 int mNumCancels = 0; 907 TestEnrollClient(@onNull Context context, @NonNull Supplier<Object> lazyDaemon, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener)908 TestEnrollClient(@NonNull Context context, @NonNull Supplier<Object> lazyDaemon, 909 @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener) { 910 super(context, lazyDaemon, token, listener, 0 /* userId */, new byte[69], 911 "test" /* owner */, mock(BiometricUtils.class), 5 /* timeoutSec */, 912 TEST_SENSOR_ID, true /* shouldVibrate */, mock(BiometricLogger.class), 913 mock(BiometricContext.class)); 914 } 915 916 @Override stopHalOperation()917 protected void stopHalOperation() { 918 mStoppedHal = true; 919 } 920 921 @Override startHalOperation()922 protected void startHalOperation() { 923 mStartedHal = true; 924 } 925 926 @Override hasReachedEnrollmentLimit()927 protected boolean hasReachedEnrollmentLimit() { 928 return false; 929 } 930 931 @Override cancel()932 public void cancel() { 933 mNumCancels++; 934 super.cancel(); 935 } 936 } 937 938 private static class TestHalClientMonitor extends HalClientMonitor<Object> { 939 private final int mProtoEnum; 940 private boolean mUnableToStart; 941 private boolean mStarted; 942 private boolean mDestroyed; 943 TestHalClientMonitor(@onNull Context context, @NonNull IBinder token, @NonNull Supplier<Object> lazyDaemon)944 TestHalClientMonitor(@NonNull Context context, @NonNull IBinder token, 945 @NonNull Supplier<Object> lazyDaemon) { 946 this(context, token, lazyDaemon, 0 /* cookie */, BiometricsProto.CM_UPDATE_ACTIVE_USER); 947 } 948 TestHalClientMonitor(@onNull Context context, @NonNull IBinder token, @NonNull Supplier<Object> lazyDaemon, int cookie, int protoEnum)949 TestHalClientMonitor(@NonNull Context context, @NonNull IBinder token, 950 @NonNull Supplier<Object> lazyDaemon, int cookie, int protoEnum) { 951 super(context, lazyDaemon, token /* token */, null /* listener */, 0 /* userId */, TAG, 952 cookie, TEST_SENSOR_ID, mock(BiometricLogger.class), 953 mock(BiometricContext.class)); 954 mProtoEnum = protoEnum; 955 } 956 957 @Override unableToStart()958 public void unableToStart() { 959 assertFalse(mUnableToStart); 960 mUnableToStart = true; 961 } 962 963 @Override getProtoEnum()964 public int getProtoEnum() { 965 return mProtoEnum; 966 } 967 968 @Override start(@onNull ClientMonitorCallback callback)969 public void start(@NonNull ClientMonitorCallback callback) { 970 super.start(callback); 971 assertFalse(mStarted); 972 mStarted = true; 973 } 974 975 @Override startHalOperation()976 protected void startHalOperation() { 977 mStarted = true; 978 } 979 980 @Override destroy()981 public void destroy() { 982 super.destroy(); 983 mDestroyed = true; 984 } 985 } 986 987 private static class TestInternalEnumerateClient extends InternalEnumerateClient<Object> { 988 private static final String TAG = "TestInternalEnumerateClient"; 989 990 TestInternalEnumerateClient(@onNull Context context, @NonNull Supplier<Object> lazyDaemon, @NonNull IBinder token, int userId, @NonNull String owner, @NonNull List<Fingerprint> enrolledList, @NonNull BiometricUtils<Fingerprint> utils, int sensorId, @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext)991 protected TestInternalEnumerateClient(@NonNull Context context, 992 @NonNull Supplier<Object> lazyDaemon, @NonNull IBinder token, int userId, 993 @NonNull String owner, @NonNull List<Fingerprint> enrolledList, 994 @NonNull BiometricUtils<Fingerprint> utils, int sensorId, 995 @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext) { 996 super(context, lazyDaemon, token, userId, owner, enrolledList, utils, sensorId, 997 logger, biometricContext); 998 } 999 1000 @Override startHalOperation()1001 protected void startHalOperation() { 1002 Slog.d(TAG, "TestInternalEnumerateClient#startHalOperation"); 1003 onEnumerationResult(TEST_FINGERPRINT, 0 /* remaining */); 1004 } 1005 } 1006 1007 private static class TestRemovalClient extends RemovalClient<Fingerprint, Object> { 1008 private static final String TAG = "TestRemovalClient"; 1009 TestRemovalClient(@onNull Context context, @NonNull Supplier<Object> lazyDaemon, @NonNull IBinder token, @Nullable ClientMonitorCallbackConverter listener, int[] biometricIds, int userId, @NonNull String owner, @NonNull BiometricUtils<Fingerprint> utils, int sensorId, @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, @NonNull Map<Integer, Long> authenticatorIds)1010 TestRemovalClient(@NonNull Context context, 1011 @NonNull Supplier<Object> lazyDaemon, @NonNull IBinder token, 1012 @Nullable ClientMonitorCallbackConverter listener, int[] biometricIds, int userId, 1013 @NonNull String owner, @NonNull BiometricUtils<Fingerprint> utils, int sensorId, 1014 @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, 1015 @NonNull Map<Integer, Long> authenticatorIds) { 1016 super(context, lazyDaemon, token, listener, userId, owner, utils, sensorId, 1017 logger, biometricContext, authenticatorIds); 1018 } 1019 1020 @Override startHalOperation()1021 protected void startHalOperation() { 1022 Slog.d(TAG, "Removing template from hw"); 1023 onRemoved(TEST_FINGERPRINT, 0); 1024 } 1025 } 1026 1027 private static class TestInternalCleanupClient extends 1028 InternalCleanupClient<Fingerprint, Object> { 1029 private List<Fingerprint> mFingerprints = new ArrayList<>(); 1030 TestInternalCleanupClient(@onNull Context context, @NonNull Supplier<Object> lazyDaemon, int userId, @NonNull String owner, int sensorId, @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, @NonNull FingerprintUtils utils, @NonNull Map<Integer, Long> authenticatorIds)1031 TestInternalCleanupClient(@NonNull Context context, 1032 @NonNull Supplier<Object> lazyDaemon, 1033 int userId, @NonNull String owner, int sensorId, 1034 @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, 1035 @NonNull FingerprintUtils utils, @NonNull Map<Integer, Long> authenticatorIds) { 1036 super(context, lazyDaemon, userId, owner, sensorId, logger, biometricContext, 1037 utils, authenticatorIds); 1038 } 1039 1040 @Override getEnumerateClient(Context context, Supplier<Object> lazyDaemon, IBinder token, int userId, String owner, List<Fingerprint> enrolledList, BiometricUtils<Fingerprint> utils, int sensorId, @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext)1041 protected InternalEnumerateClient<Object> getEnumerateClient(Context context, 1042 Supplier<Object> lazyDaemon, IBinder token, int userId, String owner, 1043 List<Fingerprint> enrolledList, BiometricUtils<Fingerprint> utils, int sensorId, 1044 @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext) { 1045 return new TestInternalEnumerateClient(context, lazyDaemon, token, userId, owner, 1046 enrolledList, utils, sensorId, 1047 logger.swapAction(context, BiometricsProtoEnums.ACTION_ENUMERATE), 1048 biometricContext); 1049 } 1050 1051 @Override getRemovalClient(Context context, Supplier<Object> lazyDaemon, IBinder token, int biometricId, int userId, String owner, BiometricUtils<Fingerprint> utils, int sensorId, @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, Map<Integer, Long> authenticatorIds)1052 protected RemovalClient<Fingerprint, Object> getRemovalClient(Context context, 1053 Supplier<Object> lazyDaemon, IBinder token, int biometricId, int userId, 1054 String owner, BiometricUtils<Fingerprint> utils, int sensorId, 1055 @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, 1056 Map<Integer, Long> authenticatorIds) { 1057 return new TestRemovalClient(context, lazyDaemon, token, null, 1058 new int[]{biometricId}, userId, owner, utils, sensorId, logger, 1059 biometricContext, authenticatorIds); 1060 } 1061 1062 @Override onAddUnknownTemplate(int userId, @NonNull BiometricAuthenticator.Identifier identifier)1063 protected void onAddUnknownTemplate(int userId, 1064 @NonNull BiometricAuthenticator.Identifier identifier) { 1065 mFingerprints.add((Fingerprint) identifier); 1066 } 1067 getFingerprints()1068 public List<Fingerprint> getFingerprints() { 1069 return mFingerprints; 1070 } 1071 } 1072 } 1073