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