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