blob: 89fa2de92c1c68ade199ebb0373626603c695b0f [file] [log] [blame]
Kevin Chyn037c4d52018-06-11 19:17:32 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
Jim Millercb2ce6f2016-04-13 20:28:18 -07003 *
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
Kevin Chyn037c4d52018-06-11 19:17:32 -070014 * limitations under the License
Jim Millercb2ce6f2016-04-13 20:28:18 -070015 */
16
Kevin Chyn836f2cf2018-08-27 11:06:39 -070017package com.android.server.biometrics;
Jim Millercb2ce6f2016-04-13 20:28:18 -070018
Jim Millercb2ce6f2016-04-13 20:28:18 -070019import android.content.Context;
Kevin Chyna56dff72018-06-19 18:41:12 -070020import android.hardware.biometrics.BiometricAuthenticator;
Kevin Chyn037c4d52018-06-11 19:17:32 -070021import android.hardware.biometrics.BiometricConstants;
Beverlyd9ec6df2018-03-20 17:19:07 -040022import android.media.AudioAttributes;
Jim Millercb2ce6f2016-04-13 20:28:18 -070023import android.os.IBinder;
24import android.os.RemoteException;
Michael Wright6726fd52017-06-27 00:41:45 +010025import android.os.VibrationEffect;
26import android.os.Vibrator;
Jim Millercb2ce6f2016-04-13 20:28:18 -070027import android.util.Slog;
28
Kevin Chyn037c4d52018-06-11 19:17:32 -070029import com.android.internal.logging.MetricsLogger;
30
Kevin Chyn6cf54e82018-09-18 19:13:27 -070031import java.util.ArrayList;
Jim Millercb2ce6f2016-04-13 20:28:18 -070032import java.util.NoSuchElementException;
33
34/**
Kevin Chyn037c4d52018-06-11 19:17:32 -070035 * Abstract base class for keeping track and dispatching events from the biometric's HAL to the
Jim Millercb2ce6f2016-04-13 20:28:18 -070036 * the current client. Subclasses are responsible for coordinating the interaction with
Kevin Chyn037c4d52018-06-11 19:17:32 -070037 * the biometric's HAL for the specific action (e.g. authenticate, enroll, enumerate, etc.).
Jim Millercb2ce6f2016-04-13 20:28:18 -070038 */
Kevin Chyn7782d142019-01-18 12:51:33 -080039public abstract class ClientMonitor extends LoggableMonitor implements IBinder.DeathRecipient {
Kevin Chyn037c4d52018-06-11 19:17:32 -070040 protected static final int ERROR_ESRCH = 3; // Likely HAL is dead. See errno.h.
Kevin Chyn355c6bf2018-09-20 22:14:19 -070041 protected static final boolean DEBUG = BiometricServiceBase.DEBUG;
Beverlyd9ec6df2018-03-20 17:19:07 -040042 private static final AudioAttributes FINGERPRINT_SONFICATION_ATTRIBUTES =
43 new AudioAttributes.Builder()
44 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
45 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
46 .build();
Kevin Chyn037c4d52018-06-11 19:17:32 -070047
Michael Wright6726fd52017-06-27 00:41:45 +010048 private final Context mContext;
49 private final long mHalDeviceId;
50 private final int mTargetUserId;
51 private final int mGroupId;
52 // True if client does not have MANAGE_FINGERPRINT permission
53 private final boolean mIsRestricted;
54 private final String mOwner;
55 private final VibrationEffect mSuccessVibrationEffect;
56 private final VibrationEffect mErrorVibrationEffect;
Kevin Chyn355c6bf2018-09-20 22:14:19 -070057 private final BiometricServiceBase.DaemonWrapper mDaemon;
Kevin Chyn037c4d52018-06-11 19:17:32 -070058
Jim Millercb2ce6f2016-04-13 20:28:18 -070059 private IBinder mToken;
Kevin Chyn355c6bf2018-09-20 22:14:19 -070060 private BiometricServiceBase.ServiceListener mListener;
Kevin Chyn87f257a2018-11-27 16:26:07 -080061 // Currently only used for authentication client. The cookie generated by BiometricService
62 // is never 0.
63 private final int mCookie;
Kevin Chyn037c4d52018-06-11 19:17:32 -070064
65 protected final MetricsLogger mMetricsLogger;
66 protected final Metrics mMetrics;
67
Kevin Chyn37368582017-05-19 17:15:38 -070068 protected boolean mAlreadyCancelled;
Kevin Chync79856b2018-10-05 18:57:35 -070069 protected boolean mAlreadyDone;
Jim Millercb2ce6f2016-04-13 20:28:18 -070070
71 /**
Kevin Chyn037c4d52018-06-11 19:17:32 -070072 * @param context context of BiometricService
73 * @param daemon interface to call back to a specific biometric's daemon
74 * @param halDeviceId the HAL device ID of the associated biometric hardware
Jim Millercb2ce6f2016-04-13 20:28:18 -070075 * @param token a unique token for the client
Kevin Chyn037c4d52018-06-11 19:17:32 -070076 * @param listener recipient of related events (e.g. authentication)
Jim Miller8f2aca02016-04-20 13:34:11 -070077 * @param userId target user id for operation
Jim Millercb2ce6f2016-04-13 20:28:18 -070078 * @param groupId groupId for the fingerprint set
Kevin Chyn037c4d52018-06-11 19:17:32 -070079 * @param restricted whether or not client has the MANAGE_* permission
Jim Millercb2ce6f2016-04-13 20:28:18 -070080 * permission
81 * @param owner name of the client that owns this
82 */
Kevin Chyn355c6bf2018-09-20 22:14:19 -070083 public ClientMonitor(Context context, Metrics metrics,
84 BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
85 BiometricServiceBase.ServiceListener listener, int userId, int groupId,
Kevin Chyn87f257a2018-11-27 16:26:07 -080086 boolean restricted, String owner, int cookie) {
Jim Millercb2ce6f2016-04-13 20:28:18 -070087 mContext = context;
Kevin Chyn037c4d52018-06-11 19:17:32 -070088 mMetrics = metrics;
89 mDaemon = daemon;
Jim Millercb2ce6f2016-04-13 20:28:18 -070090 mHalDeviceId = halDeviceId;
91 mToken = token;
Kevin Chyn037c4d52018-06-11 19:17:32 -070092 mListener = listener;
Jim Miller8f2aca02016-04-20 13:34:11 -070093 mTargetUserId = userId;
Jim Millercb2ce6f2016-04-13 20:28:18 -070094 mGroupId = groupId;
95 mIsRestricted = restricted;
96 mOwner = owner;
Kevin Chyn87f257a2018-11-27 16:26:07 -080097 mCookie = cookie;
Ilya Matyukhin21a0d1e2018-04-26 15:57:29 -070098 mSuccessVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
Michael Wright6726fd52017-06-27 00:41:45 +010099 mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700100 mMetricsLogger = new MetricsLogger();
Jim Millercb2ce6f2016-04-13 20:28:18 -0700101 try {
Jim Miller7e1cb552017-02-27 17:37:32 -0800102 if (token != null) {
103 token.linkToDeath(this, 0);
104 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700105 } catch (RemoteException e) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700106 Slog.w(getLogTag(), "caught remote exception in linkToDeath: ", e);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700107 }
108 }
109
Kevin Chyn037c4d52018-06-11 19:17:32 -0700110 protected String getLogTag() {
111 return mMetrics.logTag();
112 }
113
Kevin Chyn87f257a2018-11-27 16:26:07 -0800114 public int getCookie() {
115 return mCookie;
116 }
117
Jim Millercb2ce6f2016-04-13 20:28:18 -0700118 /**
Kevin Chyn037c4d52018-06-11 19:17:32 -0700119 * Contacts the biometric's HAL to start the client.
Michael Wright6726fd52017-06-27 00:41:45 +0100120 * @return 0 on success, errno from driver on failure
Jim Millercb2ce6f2016-04-13 20:28:18 -0700121 */
122 public abstract int start();
123
124 /**
Kevin Chyn037c4d52018-06-11 19:17:32 -0700125 * Contacts the biometric's HAL to stop the client.
Jim Millercb2ce6f2016-04-13 20:28:18 -0700126 * @param initiatedByClient whether the operation is at the request of a client
127 */
128 public abstract int stop(boolean initiatedByClient);
129
130 /**
131 * Method to explicitly poke powermanager on events
132 */
133 public abstract void notifyUserActivity();
134
Jim Millercb2ce6f2016-04-13 20:28:18 -0700135 // Event callbacks from driver. Inappropriate calls is flagged/logged by the
136 // respective client (e.g. enrolling shouldn't get authenticate events).
137 // All of these return 'true' if the operation is completed and it's ok to move
Kevin Chyn037c4d52018-06-11 19:17:32 -0700138 // to the next client (e.g. authentication accepts or rejects a biometric).
Kevin Chyna56dff72018-06-19 18:41:12 -0700139 public abstract boolean onEnrollResult(BiometricAuthenticator.Identifier identifier,
140 int remaining);
Kevin Chynb528d692018-07-20 11:53:14 -0700141 public abstract boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
Kevin Chyn6cf54e82018-09-18 19:13:27 -0700142 boolean authenticated, ArrayList<Byte> token);
Kevin Chyna56dff72018-06-19 18:41:12 -0700143 public abstract boolean onRemoved(BiometricAuthenticator.Identifier identifier,
144 int remaining);
145 public abstract boolean onEnumerationResult(
146 BiometricAuthenticator.Identifier identifier, int remaining);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700147
Kevin Chync79856b2018-10-05 18:57:35 -0700148
149 public boolean isAlreadyDone() {
150 return mAlreadyDone;
151 }
152
Jim Millercb2ce6f2016-04-13 20:28:18 -0700153 /**
Kevin Chyn037c4d52018-06-11 19:17:32 -0700154 * Called when we get notification from the biometric's HAL that an image has been acquired.
Jim Millercb2ce6f2016-04-13 20:28:18 -0700155 * Common to authenticate and enroll.
156 * @param acquiredInfo info about the current image acquisition
157 * @return true if client should be removed
158 */
Jim Miller40e46452016-12-16 18:38:53 -0800159 public boolean onAcquired(int acquiredInfo, int vendorCode) {
Kevin Chyn7782d142019-01-18 12:51:33 -0800160 super.logOnAcquired(acquiredInfo, vendorCode, getTargetUserId());
Jim Millercb2ce6f2016-04-13 20:28:18 -0700161 try {
Kevin Chyna56dff72018-06-19 18:41:12 -0700162 if (mListener != null) {
163 mListener.onAcquired(getHalDeviceId(), acquiredInfo, vendorCode);
164 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700165 return false; // acquisition continues...
166 } catch (RemoteException e) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700167 Slog.w(getLogTag(), "Failed to invoke sendAcquired", e);
168 return true;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700169 } finally {
170 // Good scans will keep the device awake
Kevin Chyn037c4d52018-06-11 19:17:32 -0700171 if (acquiredInfo == BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700172 notifyUserActivity();
173 }
174 }
175 }
176
177 /**
Kevin Chyn037c4d52018-06-11 19:17:32 -0700178 * Called when we get notification from the biometric's HAL that an error has occurred with the
Jim Millercb2ce6f2016-04-13 20:28:18 -0700179 * current operation. Common to authenticate, enroll, enumerate and remove.
180 * @param error
181 * @return true if client should be removed
182 */
Kevin Chyna56dff72018-06-19 18:41:12 -0700183 public boolean onError(long deviceId, int error, int vendorCode) {
Kevin Chyn7782d142019-01-18 12:51:33 -0800184 super.logOnError(error, vendorCode, getTargetUserId());
Kevin Chyn037c4d52018-06-11 19:17:32 -0700185 try {
Kevin Chyna56dff72018-06-19 18:41:12 -0700186 if (mListener != null) {
Kevin Chyn87f257a2018-11-27 16:26:07 -0800187 mListener.onError(deviceId, error, vendorCode, getCookie());
Kevin Chyna56dff72018-06-19 18:41:12 -0700188 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700189 } catch (RemoteException e) {
190 Slog.w(getLogTag(), "Failed to invoke sendError", e);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700191 }
192 return true; // errors always remove current client
193 }
194
195 public void destroy() {
196 if (mToken != null) {
197 try {
198 mToken.unlinkToDeath(this, 0);
199 } catch (NoSuchElementException e) {
200 // TODO: remove when duplicate call bug is found
Kevin Chyn037c4d52018-06-11 19:17:32 -0700201 Slog.e(getLogTag(), "destroy(): " + this + ":", new Exception("here"));
Jim Millercb2ce6f2016-04-13 20:28:18 -0700202 }
203 mToken = null;
204 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700205 mListener = null;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700206 }
207
208 @Override
209 public void binderDied() {
Kevin Chyn9e7b89a2018-11-20 11:24:49 -0800210 // If the current client dies we should cancel the current operation.
211 Slog.e(getLogTag(), "Binder died, cancelling client");
Kevin Chyn1417f1f2019-02-25 11:38:57 -0800212 stop(false /* initiatedByClient */);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700213 mToken = null;
Kevin Chyn037c4d52018-06-11 19:17:32 -0700214 mListener = null;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700215 }
216
217 @Override
218 protected void finalize() throws Throwable {
219 try {
220 if (mToken != null) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700221 if (DEBUG) Slog.w(getLogTag(), "removing leaked reference: " + mToken);
Kevin Chyna56dff72018-06-19 18:41:12 -0700222 onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
223 0 /* vendorCode */);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700224 }
225 } finally {
226 super.finalize();
227 }
228 }
229
230 public final Context getContext() {
231 return mContext;
232 }
233
234 public final long getHalDeviceId() {
235 return mHalDeviceId;
236 }
237
238 public final String getOwnerString() {
239 return mOwner;
240 }
241
Kevin Chyn355c6bf2018-09-20 22:14:19 -0700242 public final BiometricServiceBase.ServiceListener getListener() {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700243 return mListener;
244 }
245
Kevin Chyn355c6bf2018-09-20 22:14:19 -0700246 public final BiometricServiceBase.DaemonWrapper getDaemonWrapper() {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700247 return mDaemon;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700248 }
249
250 public final boolean getIsRestricted() {
251 return mIsRestricted;
252 }
253
Jim Miller8f2aca02016-04-20 13:34:11 -0700254 public final int getTargetUserId() {
255 return mTargetUserId;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700256 }
257
258 public final int getGroupId() {
259 return mGroupId;
260 }
261
262 public final IBinder getToken() {
263 return mToken;
264 }
Michael Wright6726fd52017-06-27 00:41:45 +0100265
266 public final void vibrateSuccess() {
267 Vibrator vibrator = mContext.getSystemService(Vibrator.class);
268 if (vibrator != null) {
Beverlyd9ec6df2018-03-20 17:19:07 -0400269 vibrator.vibrate(mSuccessVibrationEffect, FINGERPRINT_SONFICATION_ATTRIBUTES);
Michael Wright6726fd52017-06-27 00:41:45 +0100270 }
271 }
272
273 public final void vibrateError() {
274 Vibrator vibrator = mContext.getSystemService(Vibrator.class);
275 if (vibrator != null) {
Beverlyd9ec6df2018-03-20 17:19:07 -0400276 vibrator.vibrate(mErrorVibrationEffect, FINGERPRINT_SONFICATION_ATTRIBUTES);
Michael Wright6726fd52017-06-27 00:41:45 +0100277 }
278 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700279}