• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.BiometricAuthenticator.TYPE_NONE;
22 import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
23 import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT;
24 
25 import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_FACE_SCANNING;
26 import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_FP_SCANNING;
27 import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_SWITCHING;
28 import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_UNKNOWN;
29 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTHENTICATED_PENDING_SYSUI;
30 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_CALLED;
31 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_IDLE;
32 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PAUSED;
33 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PAUSED_RESUMING;
34 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PENDING_CONFIRM;
35 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED;
36 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED_UI_SHOWING;
37 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_CLIENT_DIED_CANCELLING;
38 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_ERROR_PENDING_SYSUI;
39 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_SHOWING_DEVICE_CREDENTIAL;
40 
41 import android.annotation.IntDef;
42 import android.annotation.NonNull;
43 import android.annotation.Nullable;
44 import android.content.Context;
45 import android.hardware.biometrics.BiometricAuthenticator;
46 import android.hardware.biometrics.BiometricAuthenticator.Modality;
47 import android.hardware.biometrics.BiometricConstants;
48 import android.hardware.biometrics.BiometricManager;
49 import android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
50 import android.hardware.biometrics.BiometricPrompt;
51 import android.hardware.biometrics.BiometricsProtoEnums;
52 import android.hardware.biometrics.IBiometricSensorReceiver;
53 import android.hardware.biometrics.IBiometricServiceReceiver;
54 import android.hardware.biometrics.IBiometricSysuiReceiver;
55 import android.hardware.biometrics.PromptInfo;
56 import android.hardware.face.FaceManager;
57 import android.hardware.fingerprint.FingerprintManager;
58 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
59 import android.os.IBinder;
60 import android.os.RemoteException;
61 import android.security.KeyStore;
62 import android.util.Slog;
63 
64 import com.android.internal.annotations.VisibleForTesting;
65 import com.android.internal.statusbar.IStatusBarService;
66 import com.android.internal.util.FrameworkStatsLog;
67 
68 import java.lang.annotation.Retention;
69 import java.lang.annotation.RetentionPolicy;
70 import java.util.Collection;
71 import java.util.List;
72 import java.util.Random;
73 import java.util.function.Function;
74 
75 /**
76  * Class that defines the states of an authentication session invoked via
77  * {@link android.hardware.biometrics.BiometricPrompt}, as well as all of the necessary
78  * state information for such a session.
79  */
80 public final class AuthSession implements IBinder.DeathRecipient {
81     private static final String TAG = "BiometricService/AuthSession";
82     private static final boolean DEBUG = false;
83 
84     /*
85      * Defined in biometrics.proto
86      */
87     @IntDef({
88             STATE_AUTH_IDLE,
89             STATE_AUTH_CALLED,
90             STATE_AUTH_STARTED,
91             STATE_AUTH_STARTED_UI_SHOWING,
92             STATE_AUTH_PAUSED,
93             STATE_AUTH_PAUSED_RESUMING,
94             STATE_AUTH_PENDING_CONFIRM,
95             STATE_AUTHENTICATED_PENDING_SYSUI,
96             STATE_ERROR_PENDING_SYSUI,
97             STATE_SHOWING_DEVICE_CREDENTIAL})
98     @Retention(RetentionPolicy.SOURCE)
99     @interface SessionState {}
100 
101     /** Defined in biometrics.proto */
102     @IntDef({
103             MULTI_SENSOR_STATE_UNKNOWN,
104             MULTI_SENSOR_STATE_FACE_SCANNING,
105             MULTI_SENSOR_STATE_FP_SCANNING})
106     @Retention(RetentionPolicy.SOURCE)
107     @interface MultiSensorState {}
108 
109     /**
110      * Notify the holder of the AuthSession that the caller/client's binder has died. The
111      * holder (BiometricService) should schedule {@link AuthSession#onClientDied()} to be run
112      * on its handler (instead of whatever thread invokes the death recipient callback).
113      */
114     interface ClientDeathReceiver {
onClientDied()115         void onClientDied();
116     }
117 
118     private final Context mContext;
119     private final IStatusBarService mStatusBarService;
120     private final IBiometricSysuiReceiver mSysuiReceiver;
121     private final KeyStore mKeyStore;
122     private final Random mRandom;
123     private final ClientDeathReceiver mClientDeathReceiver;
124     final PreAuthInfo mPreAuthInfo;
125 
126     // The following variables are passed to authenticateInternal, which initiates the
127     // appropriate <Biometric>Services.
128     @VisibleForTesting final IBinder mToken;
129     // Info to be shown on BiometricDialog when all cookies are returned.
130     @VisibleForTesting final PromptInfo mPromptInfo;
131     private final long mOperationId;
132     private final int mUserId;
133     private final IBiometricSensorReceiver mSensorReceiver;
134     // Original receiver from BiometricPrompt.
135     private final IBiometricServiceReceiver mClientReceiver;
136     private final String mOpPackageName;
137     private final boolean mDebugEnabled;
138     private final List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties;
139 
140     // The current state, which can be either idle, called, or started
141     private @SessionState int mState = STATE_AUTH_IDLE;
142     private @BiometricMultiSensorMode int mMultiSensorMode;
143     private @MultiSensorState int mMultiSensorState;
144     private int[] mSensors;
145     // For explicit confirmation, do not send to keystore until the user has confirmed
146     // the authentication.
147     private byte[] mTokenEscrow;
148     // Waiting for SystemUI to complete animation
149     private int mErrorEscrow;
150     private int mVendorCodeEscrow;
151 
152     // Timestamp when authentication started
153     private long mStartTimeMs;
154     // Timestamp when hardware authentication occurred
155     private long mAuthenticatedTimeMs;
156 
AuthSession(@onNull Context context, @NonNull IStatusBarService statusBarService, @NonNull IBiometricSysuiReceiver sysuiReceiver, @NonNull KeyStore keystore, @NonNull Random random, @NonNull ClientDeathReceiver clientDeathReceiver, @NonNull PreAuthInfo preAuthInfo, @NonNull IBinder token, long operationId, int userId, @NonNull IBiometricSensorReceiver sensorReceiver, @NonNull IBiometricServiceReceiver clientReceiver, @NonNull String opPackageName, @NonNull PromptInfo promptInfo, boolean debugEnabled, @NonNull List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties)157     AuthSession(@NonNull Context context,
158             @NonNull IStatusBarService statusBarService,
159             @NonNull IBiometricSysuiReceiver sysuiReceiver,
160             @NonNull KeyStore keystore,
161             @NonNull Random random,
162             @NonNull ClientDeathReceiver clientDeathReceiver,
163             @NonNull PreAuthInfo preAuthInfo,
164             @NonNull IBinder token,
165             long operationId,
166             int userId,
167             @NonNull IBiometricSensorReceiver sensorReceiver,
168             @NonNull IBiometricServiceReceiver clientReceiver,
169             @NonNull String opPackageName,
170             @NonNull PromptInfo promptInfo,
171             boolean debugEnabled,
172             @NonNull List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties) {
173         Slog.d(TAG, "Creating AuthSession with: " + preAuthInfo);
174         mContext = context;
175         mStatusBarService = statusBarService;
176         mSysuiReceiver = sysuiReceiver;
177         mKeyStore = keystore;
178         mRandom = random;
179         mClientDeathReceiver = clientDeathReceiver;
180         mPreAuthInfo = preAuthInfo;
181         mToken = token;
182         mOperationId = operationId;
183         mUserId = userId;
184         mSensorReceiver = sensorReceiver;
185         mClientReceiver = clientReceiver;
186         mOpPackageName = opPackageName;
187         mPromptInfo = promptInfo;
188         mDebugEnabled = debugEnabled;
189         mFingerprintSensorProperties = fingerprintSensorProperties;
190 
191         try {
192             mClientReceiver.asBinder().linkToDeath(this, 0 /* flags */);
193         } catch (RemoteException e) {
194             Slog.w(TAG, "Unable to link to death");
195         }
196 
197         setSensorsToStateUnknown();
198     }
199 
200     @Override
binderDied()201     public void binderDied() {
202         Slog.e(TAG, "Binder died, session: " + this);
203         mClientDeathReceiver.onClientDied();
204     }
205 
206     /**
207      * @return bitmask representing the modalities that are running or could be running for the
208      * current session.
209      */
getEligibleModalities()210     private @BiometricAuthenticator.Modality int getEligibleModalities() {
211         return mPreAuthInfo.getEligibleModalities();
212     }
213 
setSensorsToStateUnknown()214     private void setSensorsToStateUnknown() {
215         // Generate random cookies to pass to the services that should prepare to start
216         // authenticating. Store the cookie here and wait for all services to "ack"
217         // with the cookie. Once all cookies are received, we can show the prompt
218         // and let the services start authenticating. The cookie should be non-zero.
219         for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
220             if (DEBUG) {
221                 Slog.v(TAG, "set to unknown state sensor: " + sensor.id);
222             }
223             sensor.goToStateUnknown();
224         }
225     }
226 
setSensorsToStateWaitingForCookie()227     private void setSensorsToStateWaitingForCookie() throws RemoteException {
228         for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
229             final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
230             final boolean requireConfirmation = isConfirmationRequired(sensor);
231 
232             if (DEBUG) {
233                 Slog.v(TAG, "waiting for cooking for sensor: " + sensor.id);
234             }
235             sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId,
236                     mUserId, mSensorReceiver, mOpPackageName, cookie,
237                     mPromptInfo.isAllowBackgroundAuthentication());
238         }
239     }
240 
goToInitialState()241     void goToInitialState() throws RemoteException {
242         if (mPreAuthInfo.credentialAvailable && mPreAuthInfo.eligibleSensors.isEmpty()) {
243             // Only device credential should be shown. In this case, we don't need to wait,
244             // since LockSettingsService/Gatekeeper is always ready to check for credential.
245             // SystemUI invokes that path.
246             mState = STATE_SHOWING_DEVICE_CREDENTIAL;
247             mSensors = new int[0];
248             mMultiSensorMode = BIOMETRIC_MULTI_SENSOR_DEFAULT;
249             mMultiSensorState = MULTI_SENSOR_STATE_UNKNOWN;
250 
251             mStatusBarService.showAuthenticationDialog(
252                     mPromptInfo,
253                     mSysuiReceiver,
254                     mSensors /* sensorIds */,
255                     true /* credentialAllowed */,
256                     false /* requireConfirmation */,
257                     mUserId,
258                     mOpPackageName,
259                     mOperationId,
260                     mMultiSensorMode);
261         } else if (!mPreAuthInfo.eligibleSensors.isEmpty()) {
262             // Some combination of biometric or biometric|credential is requested
263             setSensorsToStateWaitingForCookie();
264             mState = STATE_AUTH_CALLED;
265         } else {
266             // No authenticators requested. This should never happen - an exception should have
267             // been thrown earlier in the pipeline.
268             throw new IllegalStateException("No authenticators requested");
269         }
270     }
271 
onCookieReceived(int cookie)272     void onCookieReceived(int cookie) {
273         for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
274             sensor.goToStateCookieReturnedIfCookieMatches(cookie);
275         }
276 
277         if (allCookiesReceived()) {
278             mStartTimeMs = System.currentTimeMillis();
279 
280             // Do not start fingerprint sensors until BiometricPrompt UI is shown. Otherwise,
281             // the affordance may be shown before the BP UI is finished animating in.
282             startAllPreparedSensorsExceptFingerprint();
283 
284             // No need to request the UI if we're coming from the paused state.
285             if (mState != STATE_AUTH_PAUSED_RESUMING) {
286                 try {
287                     // If any sensor requires confirmation, request it to be shown.
288                     final boolean requireConfirmation = isConfirmationRequiredByAnyEligibleSensor();
289 
290                     mSensors = new int[mPreAuthInfo.eligibleSensors.size()];
291                     for (int i = 0; i < mPreAuthInfo.eligibleSensors.size(); i++) {
292                         mSensors[i] = mPreAuthInfo.eligibleSensors.get(i).id;
293                     }
294                     mMultiSensorMode = getMultiSensorModeForNewSession(
295                             mPreAuthInfo.eligibleSensors);
296                     mMultiSensorState = MULTI_SENSOR_STATE_UNKNOWN;
297 
298                     mStatusBarService.showAuthenticationDialog(mPromptInfo,
299                             mSysuiReceiver,
300                             mSensors,
301                             mPreAuthInfo.shouldShowCredential(),
302                             requireConfirmation,
303                             mUserId,
304                             mOpPackageName,
305                             mOperationId,
306                             mMultiSensorMode);
307                     mState = STATE_AUTH_STARTED;
308                 } catch (RemoteException e) {
309                     Slog.e(TAG, "Remote exception", e);
310                 }
311             } else {
312                 // The UI was already showing :)
313                 mState = STATE_AUTH_STARTED_UI_SHOWING;
314             }
315         } else {
316             Slog.v(TAG, "onCookieReceived: still waiting");
317         }
318     }
319 
isConfirmationRequired(BiometricSensor sensor)320     private boolean isConfirmationRequired(BiometricSensor sensor) {
321         return sensor.confirmationSupported()
322                 && (sensor.confirmationAlwaysRequired(mUserId)
323                 || mPreAuthInfo.confirmationRequested);
324     }
325 
isConfirmationRequiredByAnyEligibleSensor()326     private boolean isConfirmationRequiredByAnyEligibleSensor() {
327         for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
328             if (isConfirmationRequired(sensor)) {
329                 return true;
330             }
331         }
332         return false;
333     }
334 
startAllPreparedSensorsExceptFingerprint()335     private void startAllPreparedSensorsExceptFingerprint() {
336         startAllPreparedSensors(sensor -> sensor.modality != TYPE_FINGERPRINT);
337     }
338 
startAllPreparedFingerprintSensors()339     private void startAllPreparedFingerprintSensors() {
340         startAllPreparedSensors(sensor -> sensor.modality == TYPE_FINGERPRINT);
341     }
342 
startAllPreparedSensors(Function<BiometricSensor, Boolean> filter)343     private void startAllPreparedSensors(Function<BiometricSensor, Boolean> filter) {
344         for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
345             if (filter.apply(sensor)) {
346                 try {
347                     if (DEBUG) {
348                         Slog.v(TAG, "Starting sensor: " + sensor.id);
349                     }
350                     sensor.startSensor();
351                 } catch (RemoteException e) {
352                     Slog.e(TAG, "Unable to start prepared client, sensor: " + sensor, e);
353                 }
354             }
355         }
356     }
357 
cancelAllSensors()358     private void cancelAllSensors() {
359         cancelAllSensors(sensor -> true);
360     }
361 
cancelAllSensors(Function<BiometricSensor, Boolean> filter)362     private void cancelAllSensors(Function<BiometricSensor, Boolean> filter) {
363         // TODO: For multiple modalities, send a single ERROR_CANCELED only when all
364         // drivers have canceled authentication. We'd probably have to add a state for
365         // STATE_CANCELING for when we're waiting for final ERROR_CANCELED before
366         // sending the final error callback to the application.
367         for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
368             try {
369                 final boolean shouldCancel = filter.apply(sensor);
370                 Slog.d(TAG, "sensorId: " + sensor.id + ", shouldCancel: " + shouldCancel);
371                 if (shouldCancel) {
372                     sensor.goToStateCancelling(mToken, mOpPackageName);
373                 }
374             } catch (RemoteException e) {
375                 Slog.e(TAG, "Unable to cancel authentication");
376             }
377         }
378     }
379 
380     /**
381      * @return true if this AuthSession is finished, e.g. should be set to null.
382      */
onErrorReceived(int sensorId, int cookie, @BiometricConstants.Errors int error, int vendorCode)383     boolean onErrorReceived(int sensorId, int cookie, @BiometricConstants.Errors int error,
384             int vendorCode) throws RemoteException {
385         Slog.d(TAG, "onErrorReceived sensor: " + sensorId + " error: " + error);
386 
387         if (!containsCookie(cookie)) {
388             Slog.e(TAG, "Unknown/expired cookie: " + cookie);
389             return false;
390         }
391 
392         // TODO: The sensor-specific state is not currently used, this would need to be updated if
393         // multiple authenticators are running.
394         for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
395             if (sensor.getSensorState() == BiometricSensor.STATE_AUTHENTICATING) {
396                 sensor.goToStoppedStateIfCookieMatches(cookie, error);
397             }
398         }
399 
400         mErrorEscrow = error;
401         mVendorCodeEscrow = vendorCode;
402 
403         final @BiometricAuthenticator.Modality int modality = sensorIdToModality(sensorId);
404 
405         switch (mState) {
406             case STATE_AUTH_CALLED: {
407                 // If any error is received while preparing the auth session (lockout, etc),
408                 // and if device credential is allowed, just show the credential UI.
409                 if (isAllowDeviceCredential()) {
410                     @BiometricManager.Authenticators.Types int authenticators =
411                             mPromptInfo.getAuthenticators();
412                     // Disallow biometric and notify SystemUI to show the authentication prompt.
413                     authenticators = Utils.removeBiometricBits(authenticators);
414                     mPromptInfo.setAuthenticators(authenticators);
415 
416                     mState = STATE_SHOWING_DEVICE_CREDENTIAL;
417                     mMultiSensorMode = BIOMETRIC_MULTI_SENSOR_DEFAULT;
418                     mMultiSensorState = MULTI_SENSOR_STATE_UNKNOWN;
419                     mSensors = new int[0];
420 
421                     mStatusBarService.showAuthenticationDialog(
422                             mPromptInfo,
423                             mSysuiReceiver,
424                             mSensors /* sensorIds */,
425                             true /* credentialAllowed */,
426                             false /* requireConfirmation */,
427                             mUserId,
428                             mOpPackageName,
429                             mOperationId,
430                             mMultiSensorMode);
431                 } else {
432                     mClientReceiver.onError(modality, error, vendorCode);
433                     return true;
434                 }
435                 break;
436             }
437 
438             case STATE_AUTH_STARTED:
439             case STATE_AUTH_STARTED_UI_SHOWING: {
440                 final boolean errorLockout = error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
441                         || error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
442                 if (isAllowDeviceCredential() && errorLockout) {
443                     // SystemUI handles transition from biometric to device credential.
444                     mState = STATE_SHOWING_DEVICE_CREDENTIAL;
445                     mStatusBarService.onBiometricError(modality, error, vendorCode);
446                 } else if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
447                     mStatusBarService.hideAuthenticationDialog();
448                     // TODO: If multiple authenticators are simultaneously running, this will
449                     // need to be modified. Send the error to the client here, instead of doing
450                     // a round trip to SystemUI.
451                     mClientReceiver.onError(modality, error, vendorCode);
452                     return true;
453                 } else {
454                     mState = STATE_ERROR_PENDING_SYSUI;
455                     if (mMultiSensorMode == BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT
456                             && mMultiSensorState == MULTI_SENSOR_STATE_FACE_SCANNING) {
457                         // wait for the UI to signal when modality should switch
458                         Slog.d(TAG, "onErrorReceived: waiting for modality switch callback");
459                         mMultiSensorState = MULTI_SENSOR_STATE_SWITCHING;
460                     }
461                     mStatusBarService.onBiometricError(modality, error, vendorCode);
462                 }
463                 break;
464             }
465 
466             case STATE_AUTH_PAUSED: {
467                 // In the "try again" state, we should forward canceled errors to
468                 // the client and clean up. The only error we should get here is
469                 // ERROR_CANCELED due to another client kicking us out.
470                 mClientReceiver.onError(modality, error, vendorCode);
471                 mStatusBarService.hideAuthenticationDialog();
472                 return true;
473             }
474 
475             case STATE_SHOWING_DEVICE_CREDENTIAL:
476                 Slog.d(TAG, "Biometric canceled, ignoring from state: " + mState);
477                 break;
478 
479             case STATE_CLIENT_DIED_CANCELLING:
480                 mStatusBarService.hideAuthenticationDialog();
481                 return true;
482 
483             default:
484                 Slog.e(TAG, "Unhandled error state, mState: " + mState);
485                 break;
486         }
487 
488         return false;
489     }
490 
onAcquired(int sensorId, int acquiredInfo, int vendorCode)491     void onAcquired(int sensorId, int acquiredInfo, int vendorCode) {
492         final String message = getAcquiredMessageForSensor(sensorId, acquiredInfo, vendorCode);
493         Slog.d(TAG, "sensorId: " + sensorId + " acquiredInfo: " + acquiredInfo
494                 + " message: " + message);
495         if (message == null) {
496             return;
497         }
498 
499         try {
500             mStatusBarService.onBiometricHelp(sensorIdToModality(sensorId), message);
501         } catch (RemoteException e) {
502             Slog.e(TAG, "Remote exception", e);
503         }
504     }
505 
onSystemEvent(int event)506     void onSystemEvent(int event) {
507         if (!mPromptInfo.isReceiveSystemEvents()) {
508             return;
509         }
510 
511         try {
512             mClientReceiver.onSystemEvent(event);
513         } catch (RemoteException e) {
514             Slog.e(TAG, "RemoteException", e);
515         }
516     }
517 
onDialogAnimatedIn()518     void onDialogAnimatedIn() {
519         if (mState != STATE_AUTH_STARTED) {
520             Slog.w(TAG, "onDialogAnimatedIn, unexpected state: " + mState);
521         }
522 
523         mState = STATE_AUTH_STARTED_UI_SHOWING;
524 
525         if (mMultiSensorMode == BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT) {
526             mMultiSensorState = MULTI_SENSOR_STATE_FACE_SCANNING;
527         } else {
528             startFingerprintSensorsNow();
529         }
530     }
531 
532     // call anytime after onDialogAnimatedIn() to indicate it's appropriate to start the
533     // fingerprint sensor (i.e. face auth has failed or is not available)
onStartFingerprint()534     void onStartFingerprint() {
535         if (mMultiSensorMode != BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT) {
536             Slog.e(TAG, "onStartFingerprint, unexpected mode: " + mMultiSensorMode);
537             return;
538         }
539 
540         if (mState != STATE_AUTH_STARTED
541                 && mState != STATE_AUTH_STARTED_UI_SHOWING
542                 && mState != STATE_AUTH_PAUSED
543                 && mState != STATE_ERROR_PENDING_SYSUI) {
544             Slog.w(TAG, "onStartFingerprint, started from unexpected state: " + mState);
545         }
546 
547         mMultiSensorState = MULTI_SENSOR_STATE_FP_SCANNING;
548         startFingerprintSensorsNow();
549     }
550 
551     // unguarded helper for the above methods only
startFingerprintSensorsNow()552     private void startFingerprintSensorsNow() {
553         startAllPreparedFingerprintSensors();
554         mState = STATE_AUTH_STARTED_UI_SHOWING;
555     }
556 
onTryAgainPressed()557     void onTryAgainPressed() {
558         if (mState != STATE_AUTH_PAUSED) {
559             Slog.w(TAG, "onTryAgainPressed, state: " + mState);
560         }
561 
562         try {
563             setSensorsToStateWaitingForCookie();
564             mState = STATE_AUTH_PAUSED_RESUMING;
565         } catch (RemoteException e) {
566             Slog.e(TAG, "RemoteException: " + e);
567         }
568     }
569 
onAuthenticationSucceeded(int sensorId, boolean strong, byte[] token)570     void onAuthenticationSucceeded(int sensorId, boolean strong,
571             byte[] token) {
572         if (strong) {
573             mTokenEscrow = token;
574         } else {
575             if (token != null) {
576                 Slog.w(TAG, "Dropping authToken for non-strong biometric, id: " + sensorId);
577             }
578         }
579 
580         try {
581             // Notify SysUI that the biometric has been authenticated. SysUI already knows
582             // the implicit/explicit state and will react accordingly.
583             mStatusBarService.onBiometricAuthenticated();
584 
585             final boolean requireConfirmation = isConfirmationRequiredByAnyEligibleSensor();
586 
587             if (!requireConfirmation) {
588                 mState = STATE_AUTHENTICATED_PENDING_SYSUI;
589             } else {
590                 mAuthenticatedTimeMs = System.currentTimeMillis();
591                 mState = STATE_AUTH_PENDING_CONFIRM;
592             }
593         } catch (RemoteException e) {
594             Slog.e(TAG, "RemoteException", e);
595         }
596     }
597 
onAuthenticationRejected()598     void onAuthenticationRejected() {
599         try {
600             mStatusBarService.onBiometricError(TYPE_NONE,
601                     BiometricConstants.BIOMETRIC_PAUSED_REJECTED, 0 /* vendorCode */);
602 
603             // TODO: This logic will need to be updated if BP is multi-modal
604             if (hasPausableBiometric()) {
605                 // Pause authentication. onBiometricAuthenticated(false) causes the
606                 // dialog to show a "try again" button for passive modalities.
607                 mState = STATE_AUTH_PAUSED;
608             }
609 
610             mClientReceiver.onAuthenticationFailed();
611         } catch (RemoteException e) {
612             Slog.e(TAG, "RemoteException", e);
613         }
614     }
615 
onAuthenticationTimedOut(int sensorId, int cookie, int error, int vendorCode)616     void onAuthenticationTimedOut(int sensorId, int cookie, int error, int vendorCode) {
617         try {
618             mStatusBarService.onBiometricError(sensorIdToModality(sensorId), error, vendorCode);
619             mState = STATE_AUTH_PAUSED;
620         } catch (RemoteException e) {
621             Slog.e(TAG, "RemoteException", e);
622         }
623     }
624 
onDeviceCredentialPressed()625     void onDeviceCredentialPressed() {
626         // Cancel authentication. Skip the token/package check since we are cancelling
627         // from system server. The interface is permission protected so this is fine.
628         cancelAllSensors();
629         mState = STATE_SHOWING_DEVICE_CREDENTIAL;
630     }
631 
632     /**
633      * @return true if this session is finished and should be set to null.
634      */
onClientDied()635     boolean onClientDied() {
636         try {
637             switch (mState) {
638                 case STATE_AUTH_STARTED:
639                 case STATE_AUTH_STARTED_UI_SHOWING:
640                     mState = STATE_CLIENT_DIED_CANCELLING;
641                     cancelAllSensors();
642                     return false;
643                 default:
644                     mStatusBarService.hideAuthenticationDialog();
645                     return true;
646             }
647         } catch (RemoteException e) {
648             Slog.e(TAG, "Remote Exception: " + e);
649             return true;
650         }
651     }
652 
logOnDialogDismissed(@iometricPrompt.DismissedReason int reason)653     private void logOnDialogDismissed(@BiometricPrompt.DismissedReason int reason) {
654         if (reason == BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED) {
655             // Explicit auth, authentication confirmed.
656             // Latency in this case is authenticated -> confirmed. <Biometric>Service
657             // should have the first half (first acquired -> authenticated).
658             final long latency = System.currentTimeMillis() - mAuthenticatedTimeMs;
659 
660             if (DEBUG) {
661                 Slog.v(TAG, "Confirmed! Modality: " + statsModality()
662                         + ", User: " + mUserId
663                         + ", IsCrypto: " + isCrypto()
664                         + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
665                         + ", RequireConfirmation: " + mPreAuthInfo.confirmationRequested
666                         + ", State: " + FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED
667                         + ", Latency: " + latency);
668             }
669 
670             FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_AUTHENTICATED,
671                     statsModality(),
672                     mUserId,
673                     isCrypto(),
674                     BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
675                     mPreAuthInfo.confirmationRequested,
676                     FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED,
677                     latency,
678                     mDebugEnabled,
679                     -1 /* sensorId */,
680                     -1f /* ambientLightLux */);
681         } else {
682             final long latency = System.currentTimeMillis() - mStartTimeMs;
683 
684             int error = reason == BiometricPrompt.DISMISSED_REASON_NEGATIVE
685                     ? BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON
686                     : reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL
687                             ? BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED
688                             : 0;
689             if (DEBUG) {
690                 Slog.v(TAG, "Dismissed! Modality: " + statsModality()
691                         + ", User: " + mUserId
692                         + ", IsCrypto: " + isCrypto()
693                         + ", Action: " + BiometricsProtoEnums.ACTION_AUTHENTICATE
694                         + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
695                         + ", Reason: " + reason
696                         + ", Error: " + error
697                         + ", Latency: " + latency);
698             }
699             // Auth canceled
700             FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED,
701                     statsModality(),
702                     mUserId,
703                     isCrypto(),
704                     BiometricsProtoEnums.ACTION_AUTHENTICATE,
705                     BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
706                     error,
707                     0 /* vendorCode */,
708                     mDebugEnabled,
709                     latency,
710                     -1 /* sensorId */);
711         }
712     }
713 
onDialogDismissed(@iometricPrompt.DismissedReason int reason, @Nullable byte[] credentialAttestation)714     void onDialogDismissed(@BiometricPrompt.DismissedReason int reason,
715             @Nullable byte[] credentialAttestation) {
716         logOnDialogDismissed(reason);
717         try {
718             switch (reason) {
719                 case BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED:
720                     if (credentialAttestation != null) {
721                         mKeyStore.addAuthToken(credentialAttestation);
722                     } else {
723                         Slog.e(TAG, "credentialAttestation is null");
724                     }
725                 case BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED:
726                 case BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED:
727                     if (mTokenEscrow != null) {
728                         final int result = mKeyStore.addAuthToken(mTokenEscrow);
729                         Slog.d(TAG, "addAuthToken: " + result);
730                     } else {
731                         Slog.e(TAG, "mTokenEscrow is null");
732                     }
733                     mClientReceiver.onAuthenticationSucceeded(
734                             Utils.getAuthenticationTypeForResult(reason));
735                     break;
736 
737                 case BiometricPrompt.DISMISSED_REASON_NEGATIVE:
738                     mClientReceiver.onDialogDismissed(reason);
739                     break;
740 
741                 case BiometricPrompt.DISMISSED_REASON_USER_CANCEL:
742                     mClientReceiver.onError(
743                             getEligibleModalities(),
744                             BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
745                             0 /* vendorCode */
746                     );
747                     break;
748 
749                 case BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED:
750                 case BiometricPrompt.DISMISSED_REASON_ERROR:
751                     mClientReceiver.onError(
752                             getEligibleModalities(),
753                             mErrorEscrow,
754                             mVendorCodeEscrow
755                     );
756                     break;
757 
758                 default:
759                     Slog.w(TAG, "Unhandled reason: " + reason);
760                     break;
761             }
762         } catch (RemoteException e) {
763             Slog.e(TAG, "Remote exception", e);
764         } finally {
765             // ensure everything is cleaned up when dismissed
766             cancelAllSensors();
767         }
768     }
769 
770     /**
771      * Cancels authentication for the entire authentication session. The caller will receive
772      * {@link BiometricPrompt#BIOMETRIC_ERROR_CANCELED} at some point.
773      *
774      * @param force if true, will immediately dismiss the dialog and send onError to the client
775      * @return true if this AuthSession is finished, e.g. should be set to null
776      */
onCancelAuthSession(boolean force)777     boolean onCancelAuthSession(boolean force) {
778         final boolean authStarted = mState == STATE_AUTH_CALLED
779                 || mState == STATE_AUTH_STARTED
780                 || mState == STATE_AUTH_STARTED_UI_SHOWING;
781 
782         cancelAllSensors();
783         if (authStarted && !force) {
784             // Wait for ERROR_CANCELED to be returned from the sensors
785             return false;
786         } else {
787             // If we're in a state where biometric sensors are not running (e.g. pending confirm,
788             // showing device credential, etc), we need to dismiss the dialog and send our own
789             // ERROR_CANCELED to the client, since we won't be getting an onError from the driver.
790             try {
791                 // Send error to client
792                 mClientReceiver.onError(
793                         getEligibleModalities(),
794                         BiometricConstants.BIOMETRIC_ERROR_CANCELED,
795                         0 /* vendorCode */
796                 );
797                 mStatusBarService.hideAuthenticationDialog();
798                 return true;
799             } catch (RemoteException e) {
800                 Slog.e(TAG, "Remote exception", e);
801             }
802         }
803         return false;
804     }
805 
isCrypto()806     boolean isCrypto() {
807         return mOperationId != 0;
808     }
809 
containsCookie(int cookie)810     private boolean containsCookie(int cookie) {
811         for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
812             if (sensor.getCookie() == cookie) {
813                 return true;
814             }
815         }
816         return false;
817     }
818 
isAllowDeviceCredential()819     private boolean isAllowDeviceCredential() {
820         return Utils.isCredentialRequested(mPromptInfo);
821     }
822 
allCookiesReceived()823     boolean allCookiesReceived() {
824         final int remainingCookies = mPreAuthInfo.numSensorsWaitingForCookie();
825         Slog.d(TAG, "Remaining cookies: " + remainingCookies);
826         return remainingCookies == 0;
827     }
828 
hasPausableBiometric()829     private boolean hasPausableBiometric() {
830         for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
831             if (sensor.modality == TYPE_FACE) {
832                 return true;
833             }
834         }
835         return false;
836     }
837 
getState()838     @SessionState int getState() {
839         return mState;
840     }
841 
statsModality()842     private int statsModality() {
843         int modality = 0;
844 
845         for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
846             if ((sensor.modality & BiometricAuthenticator.TYPE_FINGERPRINT) != 0) {
847                 modality |= BiometricsProtoEnums.MODALITY_FINGERPRINT;
848             }
849             if ((sensor.modality & BiometricAuthenticator.TYPE_IRIS) != 0) {
850                 modality |= BiometricsProtoEnums.MODALITY_IRIS;
851             }
852             if ((sensor.modality & BiometricAuthenticator.TYPE_FACE) != 0) {
853                 modality |= BiometricsProtoEnums.MODALITY_FACE;
854             }
855         }
856 
857         return modality;
858     }
859 
sensorIdToModality(int sensorId)860     private @Modality int sensorIdToModality(int sensorId) {
861         for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
862             if (sensorId == sensor.id) {
863                 return sensor.modality;
864             }
865         }
866         Slog.e(TAG, "Unknown sensor: " + sensorId);
867         return TYPE_NONE;
868     }
869 
getAcquiredMessageForSensor(int sensorId, int acquiredInfo, int vendorCode)870     private String getAcquiredMessageForSensor(int sensorId, int acquiredInfo, int vendorCode) {
871         final @Modality int modality = sensorIdToModality(sensorId);
872         switch (modality) {
873             case BiometricAuthenticator.TYPE_FINGERPRINT:
874                 return FingerprintManager.getAcquiredString(mContext, acquiredInfo, vendorCode);
875             case BiometricAuthenticator.TYPE_FACE:
876                 return FaceManager.getAuthHelpMessage(mContext, acquiredInfo, vendorCode);
877             default:
878                 return null;
879         }
880     }
881 
882     @BiometricMultiSensorMode
getMultiSensorModeForNewSession(Collection<BiometricSensor> sensors)883     private static int getMultiSensorModeForNewSession(Collection<BiometricSensor> sensors) {
884         boolean hasFace = false;
885         boolean hasFingerprint = false;
886 
887         for (BiometricSensor sensor: sensors) {
888             if (sensor.modality == TYPE_FACE) {
889                 hasFace = true;
890             } else if (sensor.modality == TYPE_FINGERPRINT) {
891                 hasFingerprint = true;
892             }
893         }
894 
895         if (hasFace && hasFingerprint) {
896             return BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT;
897         }
898         return BIOMETRIC_MULTI_SENSOR_DEFAULT;
899     }
900 
901     @Override
toString()902     public String toString() {
903         return "State: " + mState
904                 + ", isCrypto: " + isCrypto()
905                 + ", PreAuthInfo: " + mPreAuthInfo;
906     }
907 }
908