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