blob: 3eae157c53aa930a97c381e93c44d8971334456e [file] [log] [blame]
Jim Millercb2ce6f2016-04-13 20:28:18 -07001/**
2 * Copyright (C) 2016 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
17package com.android.server.fingerprint;
18
19import android.Manifest;
20import android.content.Context;
Jim Miller40e46452016-12-16 18:38:53 -080021import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
Jim Millercb2ce6f2016-04-13 20:28:18 -070022import android.hardware.fingerprint.FingerprintManager;
Jim Millercb2ce6f2016-04-13 20:28:18 -070023import android.hardware.fingerprint.IFingerprintServiceReceiver;
24import android.os.IBinder;
25import android.os.RemoteException;
Michael Wright6726fd52017-06-27 00:41:45 +010026import android.os.VibrationEffect;
27import android.os.Vibrator;
Jim Millercb2ce6f2016-04-13 20:28:18 -070028import android.util.Slog;
29
30import java.util.NoSuchElementException;
31
32/**
Kevin Chyn80e40cc2017-03-14 12:31:17 -070033 * Abstract base class for keeping track and dispatching events from fingerprint HAL to the
Jim Millercb2ce6f2016-04-13 20:28:18 -070034 * the current client. Subclasses are responsible for coordinating the interaction with
Kevin Chyn80e40cc2017-03-14 12:31:17 -070035 * fingerprint HAL for the specific action (e.g. authenticate, enroll, enumerate, etc.).
Jim Millercb2ce6f2016-04-13 20:28:18 -070036 */
37public abstract class ClientMonitor implements IBinder.DeathRecipient {
38 protected static final String TAG = FingerprintService.TAG; // TODO: get specific name
Kevin Chyn80e40cc2017-03-14 12:31:17 -070039 protected static final int ERROR_ESRCH = 3; // Likely fingerprint HAL is dead. See errno.h.
Jim Millercb2ce6f2016-04-13 20:28:18 -070040 protected static final boolean DEBUG = FingerprintService.DEBUG;
Michael Wright6726fd52017-06-27 00:41:45 +010041 private static final long[] DEFAULT_SUCCESS_VIBRATION_PATTERN = new long[] {0, 30};
42 private final Context mContext;
43 private final long mHalDeviceId;
44 private final int mTargetUserId;
45 private final int mGroupId;
46 // True if client does not have MANAGE_FINGERPRINT permission
47 private final boolean mIsRestricted;
48 private final String mOwner;
49 private final VibrationEffect mSuccessVibrationEffect;
50 private final VibrationEffect mErrorVibrationEffect;
Jim Millercb2ce6f2016-04-13 20:28:18 -070051 private IBinder mToken;
52 private IFingerprintServiceReceiver mReceiver;
Kevin Chyn37368582017-05-19 17:15:38 -070053 protected boolean mAlreadyCancelled;
Jim Millercb2ce6f2016-04-13 20:28:18 -070054
55 /**
56 * @param context context of FingerprintService
57 * @param halDeviceId the HAL device ID of the associated fingerprint hardware
58 * @param token a unique token for the client
59 * @param receiver recipient of related events (e.g. authentication)
Jim Miller8f2aca02016-04-20 13:34:11 -070060 * @param userId target user id for operation
Jim Millercb2ce6f2016-04-13 20:28:18 -070061 * @param groupId groupId for the fingerprint set
62 * @param restricted whether or not client has the {@link Manifest#MANAGE_FINGERPRINT}
63 * permission
64 * @param owner name of the client that owns this
65 */
66 public ClientMonitor(Context context, long halDeviceId, IBinder token,
Jim Miller8f2aca02016-04-20 13:34:11 -070067 IFingerprintServiceReceiver receiver, int userId, int groupId,boolean restricted,
Jim Millercb2ce6f2016-04-13 20:28:18 -070068 String owner) {
69 mContext = context;
70 mHalDeviceId = halDeviceId;
71 mToken = token;
72 mReceiver = receiver;
Jim Miller8f2aca02016-04-20 13:34:11 -070073 mTargetUserId = userId;
Jim Millercb2ce6f2016-04-13 20:28:18 -070074 mGroupId = groupId;
75 mIsRestricted = restricted;
76 mOwner = owner;
Michael Wright6726fd52017-06-27 00:41:45 +010077 mSuccessVibrationEffect = getSuccessVibrationEffect(context);
78 mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
Jim Millercb2ce6f2016-04-13 20:28:18 -070079 try {
Jim Miller7e1cb552017-02-27 17:37:32 -080080 if (token != null) {
81 token.linkToDeath(this, 0);
82 }
Jim Millercb2ce6f2016-04-13 20:28:18 -070083 } catch (RemoteException e) {
84 Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
85 }
86 }
87
88 /**
Kevin Chyn80e40cc2017-03-14 12:31:17 -070089 * Contacts fingerprint HAL to start the client.
Michael Wright6726fd52017-06-27 00:41:45 +010090 * @return 0 on success, errno from driver on failure
Jim Millercb2ce6f2016-04-13 20:28:18 -070091 */
92 public abstract int start();
93
94 /**
Kevin Chyn80e40cc2017-03-14 12:31:17 -070095 * Contacts fingerprint HAL to stop the client.
Jim Millercb2ce6f2016-04-13 20:28:18 -070096 * @param initiatedByClient whether the operation is at the request of a client
97 */
98 public abstract int stop(boolean initiatedByClient);
99
100 /**
101 * Method to explicitly poke powermanager on events
102 */
103 public abstract void notifyUserActivity();
104
105 /**
106 * Gets the fingerprint daemon from the cached state in the container class.
107 */
Jim Miller40e46452016-12-16 18:38:53 -0800108 public abstract IBiometricsFingerprint getFingerprintDaemon();
Jim Millercb2ce6f2016-04-13 20:28:18 -0700109
110 // Event callbacks from driver. Inappropriate calls is flagged/logged by the
111 // respective client (e.g. enrolling shouldn't get authenticate events).
112 // All of these return 'true' if the operation is completed and it's ok to move
113 // to the next client (e.g. authentication accepts or rejects a fingerprint).
114 public abstract boolean onEnrollResult(int fingerId, int groupId, int rem);
115 public abstract boolean onAuthenticated(int fingerId, int groupId);
Jim Miller40e46452016-12-16 18:38:53 -0800116 public abstract boolean onRemoved(int fingerId, int groupId, int remaining);
117 public abstract boolean onEnumerationResult(int fingerId, int groupId, int remaining);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700118
119 /**
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700120 * Called when we get notification from fingerprint HAL that an image has been acquired.
Jim Millercb2ce6f2016-04-13 20:28:18 -0700121 * Common to authenticate and enroll.
122 * @param acquiredInfo info about the current image acquisition
123 * @return true if client should be removed
124 */
Jim Miller40e46452016-12-16 18:38:53 -0800125 public boolean onAcquired(int acquiredInfo, int vendorCode) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700126 if (mReceiver == null)
127 return true; // client not connected
128 try {
Jim Miller40e46452016-12-16 18:38:53 -0800129 mReceiver.onAcquired(getHalDeviceId(), acquiredInfo, vendorCode);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700130 return false; // acquisition continues...
131 } catch (RemoteException e) {
132 Slog.w(TAG, "Failed to invoke sendAcquired:", e);
133 return true; // client failed
134 } finally {
135 // Good scans will keep the device awake
136 if (acquiredInfo == FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) {
137 notifyUserActivity();
138 }
139 }
140 }
141
142 /**
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700143 * Called when we get notification from fingerprint HAL that an error has occurred with the
Jim Millercb2ce6f2016-04-13 20:28:18 -0700144 * current operation. Common to authenticate, enroll, enumerate and remove.
145 * @param error
146 * @return true if client should be removed
147 */
Jim Miller40e46452016-12-16 18:38:53 -0800148 public boolean onError(int error, int vendorCode) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700149 if (mReceiver != null) {
150 try {
Jim Miller40e46452016-12-16 18:38:53 -0800151 mReceiver.onError(getHalDeviceId(), error, vendorCode);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700152 } catch (RemoteException e) {
153 Slog.w(TAG, "Failed to invoke sendError:", e);
154 }
155 }
156 return true; // errors always remove current client
157 }
158
159 public void destroy() {
160 if (mToken != null) {
161 try {
162 mToken.unlinkToDeath(this, 0);
163 } catch (NoSuchElementException e) {
164 // TODO: remove when duplicate call bug is found
165 Slog.e(TAG, "destroy(): " + this + ":", new Exception("here"));
166 }
167 mToken = null;
168 }
169 mReceiver = null;
170 }
171
172 @Override
173 public void binderDied() {
174 mToken = null;
175 mReceiver = null;
Jim Miller40e46452016-12-16 18:38:53 -0800176 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700177 }
178
179 @Override
180 protected void finalize() throws Throwable {
181 try {
182 if (mToken != null) {
183 if (DEBUG) Slog.w(TAG, "removing leaked reference: " + mToken);
Jim Miller40e46452016-12-16 18:38:53 -0800184 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700185 }
186 } finally {
187 super.finalize();
188 }
189 }
190
191 public final Context getContext() {
192 return mContext;
193 }
194
195 public final long getHalDeviceId() {
196 return mHalDeviceId;
197 }
198
199 public final String getOwnerString() {
200 return mOwner;
201 }
202
203 public final IFingerprintServiceReceiver getReceiver() {
204 return mReceiver;
205 }
206
207 public final boolean getIsRestricted() {
208 return mIsRestricted;
209 }
210
Jim Miller8f2aca02016-04-20 13:34:11 -0700211 public final int getTargetUserId() {
212 return mTargetUserId;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700213 }
214
215 public final int getGroupId() {
216 return mGroupId;
217 }
218
219 public final IBinder getToken() {
220 return mToken;
221 }
Michael Wright6726fd52017-06-27 00:41:45 +0100222
223 public final void vibrateSuccess() {
224 Vibrator vibrator = mContext.getSystemService(Vibrator.class);
225 if (vibrator != null) {
226 vibrator.vibrate(mSuccessVibrationEffect);
227 }
228 }
229
230 public final void vibrateError() {
231 Vibrator vibrator = mContext.getSystemService(Vibrator.class);
232 if (vibrator != null) {
233 vibrator.vibrate(mErrorVibrationEffect);
234 }
235 }
236
237 private static VibrationEffect getSuccessVibrationEffect(Context ctx) {
238 int[] arr = ctx.getResources().getIntArray(
239 com.android.internal.R.array.config_longPressVibePattern);
240 final long[] vibePattern;
241 if (arr == null || arr.length == 0) {
242 vibePattern = DEFAULT_SUCCESS_VIBRATION_PATTERN;
243 } else {
244 vibePattern = new long[arr.length];
245 for (int i = 0; i < arr.length; i++) {
246 vibePattern[i] = arr[i];
247 }
248 }
249 if (vibePattern.length == 1) {
250 return VibrationEffect.createOneShot(
251 vibePattern[0], VibrationEffect.DEFAULT_AMPLITUDE);
252 } else {
253 return VibrationEffect.createWaveform(vibePattern, -1);
254 }
255 }
256
Jim Millercb2ce6f2016-04-13 20:28:18 -0700257}