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