blob: 87b9eaaa9cbbe4cb33bf57991925b14bfb15b3f1 [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());
Kevin Chyn8db1a552019-02-28 14:53:34 -0800161 if (DEBUG) Slog.v(getLogTag(), "Acquired: " + acquiredInfo + " " + vendorCode);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700162 try {
Kevin Chyna56dff72018-06-19 18:41:12 -0700163 if (mListener != null) {
164 mListener.onAcquired(getHalDeviceId(), acquiredInfo, vendorCode);
165 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700166 return false; // acquisition continues...
167 } catch (RemoteException e) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700168 Slog.w(getLogTag(), "Failed to invoke sendAcquired", e);
169 return true;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700170 } finally {
171 // Good scans will keep the device awake
Kevin Chyn037c4d52018-06-11 19:17:32 -0700172 if (acquiredInfo == BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700173 notifyUserActivity();
174 }
175 }
176 }
177
178 /**
Kevin Chyn037c4d52018-06-11 19:17:32 -0700179 * Called when we get notification from the biometric's HAL that an error has occurred with the
Jim Millercb2ce6f2016-04-13 20:28:18 -0700180 * current operation. Common to authenticate, enroll, enumerate and remove.
181 * @param error
182 * @return true if client should be removed
183 */
Kevin Chyna56dff72018-06-19 18:41:12 -0700184 public boolean onError(long deviceId, int error, int vendorCode) {
Kevin Chyn7782d142019-01-18 12:51:33 -0800185 super.logOnError(error, vendorCode, getTargetUserId());
Kevin Chyn037c4d52018-06-11 19:17:32 -0700186 try {
Kevin Chyna56dff72018-06-19 18:41:12 -0700187 if (mListener != null) {
Kevin Chyn87f257a2018-11-27 16:26:07 -0800188 mListener.onError(deviceId, error, vendorCode, getCookie());
Kevin Chyna56dff72018-06-19 18:41:12 -0700189 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700190 } catch (RemoteException e) {
191 Slog.w(getLogTag(), "Failed to invoke sendError", e);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700192 }
193 return true; // errors always remove current client
194 }
195
196 public void destroy() {
197 if (mToken != null) {
198 try {
199 mToken.unlinkToDeath(this, 0);
200 } catch (NoSuchElementException e) {
201 // TODO: remove when duplicate call bug is found
Kevin Chyn037c4d52018-06-11 19:17:32 -0700202 Slog.e(getLogTag(), "destroy(): " + this + ":", new Exception("here"));
Jim Millercb2ce6f2016-04-13 20:28:18 -0700203 }
204 mToken = null;
205 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700206 mListener = null;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700207 }
208
209 @Override
210 public void binderDied() {
Kevin Chyn9e7b89a2018-11-20 11:24:49 -0800211 // If the current client dies we should cancel the current operation.
212 Slog.e(getLogTag(), "Binder died, cancelling client");
Kevin Chyn1417f1f2019-02-25 11:38:57 -0800213 stop(false /* initiatedByClient */);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700214 mToken = null;
Kevin Chyn037c4d52018-06-11 19:17:32 -0700215 mListener = null;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700216 }
217
218 @Override
219 protected void finalize() throws Throwable {
220 try {
221 if (mToken != null) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700222 if (DEBUG) Slog.w(getLogTag(), "removing leaked reference: " + mToken);
Kevin Chyna56dff72018-06-19 18:41:12 -0700223 onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
224 0 /* vendorCode */);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700225 }
226 } finally {
227 super.finalize();
228 }
229 }
230
231 public final Context getContext() {
232 return mContext;
233 }
234
235 public final long getHalDeviceId() {
236 return mHalDeviceId;
237 }
238
239 public final String getOwnerString() {
240 return mOwner;
241 }
242
Kevin Chyn355c6bf2018-09-20 22:14:19 -0700243 public final BiometricServiceBase.ServiceListener getListener() {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700244 return mListener;
245 }
246
Kevin Chyn355c6bf2018-09-20 22:14:19 -0700247 public final BiometricServiceBase.DaemonWrapper getDaemonWrapper() {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700248 return mDaemon;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700249 }
250
251 public final boolean getIsRestricted() {
252 return mIsRestricted;
253 }
254
Jim Miller8f2aca02016-04-20 13:34:11 -0700255 public final int getTargetUserId() {
256 return mTargetUserId;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700257 }
258
259 public final int getGroupId() {
260 return mGroupId;
261 }
262
263 public final IBinder getToken() {
264 return mToken;
265 }
Michael Wright6726fd52017-06-27 00:41:45 +0100266
267 public final void vibrateSuccess() {
268 Vibrator vibrator = mContext.getSystemService(Vibrator.class);
269 if (vibrator != null) {
Beverlyd9ec6df2018-03-20 17:19:07 -0400270 vibrator.vibrate(mSuccessVibrationEffect, FINGERPRINT_SONFICATION_ATTRIBUTES);
Michael Wright6726fd52017-06-27 00:41:45 +0100271 }
272 }
273
274 public final void vibrateError() {
275 Vibrator vibrator = mContext.getSystemService(Vibrator.class);
276 if (vibrator != null) {
Beverlyd9ec6df2018-03-20 17:19:07 -0400277 vibrator.vibrate(mErrorVibrationEffect, FINGERPRINT_SONFICATION_ATTRIBUTES);
Michael Wright6726fd52017-06-27 00:41:45 +0100278 }
279 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700280}