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