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.BiometricManager.Authenticators;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.content.Context;
24 import android.hardware.biometrics.BiometricConstants;
25 import android.hardware.biometrics.IBiometricAuthenticator;
26 import android.hardware.biometrics.IBiometricSensorReceiver;
27 import android.os.IBinder;
28 import android.os.RemoteException;
29 import android.util.Slog;
30 
31 import java.lang.annotation.Retention;
32 import java.lang.annotation.RetentionPolicy;
33 
34 /**
35  * Wraps IBiometricAuthenticator implementation and stores information about the authenticator,
36  * including its current state.
37  * TODO(b/141025588): Consider refactoring the tests to not rely on this implementation detail.
38  */
39 public abstract class BiometricSensor {
40     private static final String TAG = "BiometricService/Sensor";
41 
42     // State is unknown. Usually this means we need the sensor but have not requested for
43     // it to be used yet (cookie not sent yet)
44     static final int STATE_UNKNOWN = 0;
45     // Cookie has been generated, and the relevant sensor service has been asked to prepare
46     // for authentication. Awaiting "ack" from the sensor.
47     static final int STATE_WAITING_FOR_COOKIE = 1;
48     // The appropriate sensor service has "acked" notifying us that it's ready to be
49     // started for authentication.
50     static final int STATE_COOKIE_RETURNED = 2;
51     // The sensor is being used for authentication.
52     static final int STATE_AUTHENTICATING = 3;
53     // Cancel has been requested, waiting for ERROR_CANCELED to be received from the HAL
54     static final int STATE_CANCELING = 4;
55     static final int STATE_STOPPED = 5;
56 
57     @IntDef({STATE_UNKNOWN,
58             STATE_WAITING_FOR_COOKIE,
59             STATE_COOKIE_RETURNED,
60             STATE_AUTHENTICATING,
61             STATE_CANCELING,
62             STATE_STOPPED})
63     @Retention(RetentionPolicy.SOURCE)
64     @interface SensorState {}
65 
66     @NonNull private final Context mContext;
67     public final int id;
68     public final @Authenticators.Types int oemStrength; // strength as configured by the OEM
69     public final int modality;
70     public final IBiometricAuthenticator impl;
71 
72     private @Authenticators.Types int mUpdatedStrength; // updated by BiometricStrengthController
73     private @SensorState int mSensorState;
74     private @BiometricConstants.Errors int mError;
75 
76     private int mCookie; // invalid during STATE_UNKNOWN
77 
78     /**
79      * @return true if the user's system settings specifies that this sensor always requires
80      * confirmation.
81      */
confirmationAlwaysRequired(int userId)82     abstract boolean confirmationAlwaysRequired(int userId);
83 
84     /**
85      * @return true if confirmation is supported by this sensor.
86      */
confirmationSupported()87     abstract boolean confirmationSupported();
88 
BiometricSensor(@onNull Context context, int id, int modality, @Authenticators.Types int strength, IBiometricAuthenticator impl)89     BiometricSensor(@NonNull Context context, int id, int modality,
90             @Authenticators.Types int strength, IBiometricAuthenticator impl) {
91         this.mContext = context;
92         this.id = id;
93         this.modality = modality;
94         this.oemStrength = strength;
95         this.impl = impl;
96 
97         mUpdatedStrength = strength;
98         goToStateUnknown();
99     }
100 
goToStateUnknown()101     void goToStateUnknown() {
102         mSensorState = STATE_UNKNOWN;
103         mCookie = 0;
104         mError = BiometricConstants.BIOMETRIC_SUCCESS;
105     }
106 
goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication, boolean isForLegacyFingerprintManager)107     void goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId,
108             int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
109             long requestId, int cookie, boolean allowBackgroundAuthentication,
110             boolean isForLegacyFingerprintManager)
111             throws RemoteException {
112         mCookie = cookie;
113         impl.prepareForAuthentication(requireConfirmation, token,
114                 sessionId, userId, sensorReceiver, opPackageName, requestId, mCookie,
115                 allowBackgroundAuthentication, isForLegacyFingerprintManager);
116         mSensorState = STATE_WAITING_FOR_COOKIE;
117     }
118 
goToStateCookieReturnedIfCookieMatches(int cookie)119     void goToStateCookieReturnedIfCookieMatches(int cookie) {
120         if (cookie == mCookie) {
121             Slog.d(TAG, "Sensor(" + id + ") matched cookie: " + cookie);
122             mSensorState = STATE_COOKIE_RETURNED;
123         }
124     }
125 
startSensor()126     void startSensor() throws RemoteException {
127         impl.startPreparedClient(mCookie);
128         mSensorState = STATE_AUTHENTICATING;
129     }
130 
goToStateCancelling(IBinder token, String opPackageName, long requestId)131     void goToStateCancelling(IBinder token, String opPackageName, long requestId)
132             throws RemoteException {
133         if (mSensorState != STATE_CANCELING) {
134             impl.cancelAuthenticationFromService(token, opPackageName, requestId);
135             mSensorState = STATE_CANCELING;
136         }
137     }
138 
goToStoppedStateIfCookieMatches(int cookie, int error)139     void goToStoppedStateIfCookieMatches(int cookie, int error) {
140         if (cookie == mCookie) {
141             Slog.d(TAG, "Sensor(" + id + ") now in STATE_STOPPED");
142             mError = error;
143             mSensorState = STATE_STOPPED;
144         }
145     }
146 
147     /**
148      * Returns the actual strength, taking any updated strengths into effect. Since more bits
149      * means lower strength, the resulting strength is never stronger than the OEM's configured
150      * strength.
151      * @return a bitfield, see {@link android.hardware.biometrics.BiometricManager.Authenticators}
152      */
getCurrentStrength()153     @Authenticators.Types int getCurrentStrength() {
154         return oemStrength | mUpdatedStrength;
155     }
156 
getSensorState()157     @SensorState int getSensorState() {
158         return mSensorState;
159     }
160 
getCookie()161     int getCookie() {
162         return mCookie;
163     }
164 
165     /**
166      * Stores the updated strength, which takes effect whenever {@link #getCurrentStrength()}
167      * is checked.
168      * @param newStrength
169      */
updateStrength(@uthenticators.Types int newStrength)170     void updateStrength(@Authenticators.Types int newStrength) {
171         String log = "updateStrength: Before(" + this + ")";
172         mUpdatedStrength = newStrength;
173         log += " After(" + this + ")";
174         Slog.d(TAG, log);
175     }
176 
177     @Override
toString()178     public String toString() {
179         return "ID(" + id + ")"
180                 + ", oemStrength: " + oemStrength
181                 + ", updatedStrength: " + mUpdatedStrength
182                 + ", modality " + modality
183                 + ", state: " + mSensorState
184                 + ", cookie: " + mCookie;
185     }
186 }
187