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