1 /** 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 17 package com.android.server.fingerprint; 18 19 import android.Manifest; 20 import android.content.Context; 21 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; 22 import android.hardware.fingerprint.FingerprintManager; 23 import android.hardware.fingerprint.IFingerprintServiceReceiver; 24 import android.media.AudioAttributes; 25 import android.os.IBinder; 26 import android.os.RemoteException; 27 import android.os.VibrationEffect; 28 import android.os.Vibrator; 29 import android.util.Slog; 30 31 import java.util.NoSuchElementException; 32 33 /** 34 * Abstract base class for keeping track and dispatching events from fingerprint HAL to the 35 * the current client. Subclasses are responsible for coordinating the interaction with 36 * fingerprint HAL for the specific action (e.g. authenticate, enroll, enumerate, etc.). 37 */ 38 public abstract class ClientMonitor implements IBinder.DeathRecipient { 39 protected static final String TAG = FingerprintService.TAG; // TODO: get specific name 40 protected static final int ERROR_ESRCH = 3; // Likely fingerprint HAL is dead. See errno.h. 41 protected static final boolean DEBUG = FingerprintService.DEBUG; 42 private static final long[] DEFAULT_SUCCESS_VIBRATION_PATTERN = new long[] {0, 30}; 43 private static final AudioAttributes FINGERPRINT_SONFICATION_ATTRIBUTES = 44 new AudioAttributes.Builder() 45 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 46 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) 47 .build(); 48 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; 57 private IBinder mToken; 58 private IFingerprintServiceReceiver mReceiver; 59 protected boolean mAlreadyCancelled; 60 61 /** 62 * @param context context of FingerprintService 63 * @param halDeviceId the HAL device ID of the associated fingerprint hardware 64 * @param token a unique token for the client 65 * @param receiver recipient of related events (e.g. authentication) 66 * @param userId target user id for operation 67 * @param groupId groupId for the fingerprint set 68 * @param restricted whether or not client has the {@link Manifest#MANAGE_FINGERPRINT} 69 * permission 70 * @param owner name of the client that owns this 71 */ 72 public ClientMonitor(Context context, long halDeviceId, IBinder token, 73 IFingerprintServiceReceiver receiver, int userId, int groupId,boolean restricted, 74 String owner) { 75 mContext = context; 76 mHalDeviceId = halDeviceId; 77 mToken = token; 78 mReceiver = receiver; 79 mTargetUserId = userId; 80 mGroupId = groupId; 81 mIsRestricted = restricted; 82 mOwner = owner; 83 mSuccessVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); 84 mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK); 85 try { 86 if (token != null) { 87 token.linkToDeath(this, 0); 88 } 89 } catch (RemoteException e) { 90 Slog.w(TAG, "caught remote exception in linkToDeath: ", e); 91 } 92 } 93 94 /** 95 * Contacts fingerprint HAL to start the client. 96 * @return 0 on success, errno from driver on failure 97 */ 98 public abstract int start(); 99 100 /** 101 * Contacts fingerprint HAL to stop the client. 102 * @param initiatedByClient whether the operation is at the request of a client 103 */ 104 public abstract int stop(boolean initiatedByClient); 105 106 /** 107 * Method to explicitly poke powermanager on events 108 */ 109 public abstract void notifyUserActivity(); 110 111 /** 112 * Gets the fingerprint daemon from the cached state in the container class. 113 */ 114 public abstract IBiometricsFingerprint getFingerprintDaemon(); 115 116 // Event callbacks from driver. Inappropriate calls is flagged/logged by the 117 // respective client (e.g. enrolling shouldn't get authenticate events). 118 // All of these return 'true' if the operation is completed and it's ok to move 119 // to the next client (e.g. authentication accepts or rejects a fingerprint). 120 public abstract boolean onEnrollResult(int fingerId, int groupId, int rem); 121 public abstract boolean onAuthenticated(int fingerId, int groupId); 122 public abstract boolean onRemoved(int fingerId, int groupId, int remaining); 123 public abstract boolean onEnumerationResult(int fingerId, int groupId, int remaining); 124 125 /** 126 * Called when we get notification from fingerprint HAL that an image has been acquired. 127 * Common to authenticate and enroll. 128 * @param acquiredInfo info about the current image acquisition 129 * @return true if client should be removed 130 */ 131 public boolean onAcquired(int acquiredInfo, int vendorCode) { 132 if (mReceiver == null) 133 return true; // client not connected 134 try { 135 mReceiver.onAcquired(getHalDeviceId(), acquiredInfo, vendorCode); 136 return false; // acquisition continues... 137 } catch (RemoteException e) { 138 Slog.w(TAG, "Failed to invoke sendAcquired:", e); 139 return true; // client failed 140 } finally { 141 // Good scans will keep the device awake 142 if (acquiredInfo == FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) { 143 notifyUserActivity(); 144 } 145 } 146 } 147 148 /** 149 * Called when we get notification from fingerprint HAL that an error has occurred with the 150 * current operation. Common to authenticate, enroll, enumerate and remove. 151 * @param error 152 * @return true if client should be removed 153 */ 154 public boolean onError(int error, int vendorCode) { 155 if (mReceiver != null) { 156 try { 157 mReceiver.onError(getHalDeviceId(), error, vendorCode); 158 } catch (RemoteException e) { 159 Slog.w(TAG, "Failed to invoke sendError:", e); 160 } 161 } 162 return true; // errors always remove current client 163 } 164 165 public void destroy() { 166 if (mToken != null) { 167 try { 168 mToken.unlinkToDeath(this, 0); 169 } catch (NoSuchElementException e) { 170 // TODO: remove when duplicate call bug is found 171 Slog.e(TAG, "destroy(): " + this + ":", new Exception("here")); 172 } 173 mToken = null; 174 } 175 mReceiver = null; 176 } 177 178 @Override 179 public void binderDied() { 180 mToken = null; 181 mReceiver = null; 182 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); 183 } 184 185 @Override 186 protected void finalize() throws Throwable { 187 try { 188 if (mToken != null) { 189 if (DEBUG) Slog.w(TAG, "removing leaked reference: " + mToken); 190 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); 191 } 192 } finally { 193 super.finalize(); 194 } 195 } 196 197 public final Context getContext() { 198 return mContext; 199 } 200 201 public final long getHalDeviceId() { 202 return mHalDeviceId; 203 } 204 205 public final String getOwnerString() { 206 return mOwner; 207 } 208 209 public final IFingerprintServiceReceiver getReceiver() { 210 return mReceiver; 211 } 212 213 public final boolean getIsRestricted() { 214 return mIsRestricted; 215 } 216 217 public final int getTargetUserId() { 218 return mTargetUserId; 219 } 220 221 public final int getGroupId() { 222 return mGroupId; 223 } 224 225 public final IBinder getToken() { 226 return mToken; 227 } 228 229 public final void vibrateSuccess() { 230 Vibrator vibrator = mContext.getSystemService(Vibrator.class); 231 if (vibrator != null) { 232 vibrator.vibrate(mSuccessVibrationEffect, FINGERPRINT_SONFICATION_ATTRIBUTES); 233 } 234 } 235 236 public final void vibrateError() { 237 Vibrator vibrator = mContext.getSystemService(Vibrator.class); 238 if (vibrator != null) { 239 vibrator.vibrate(mErrorVibrationEffect, FINGERPRINT_SONFICATION_ATTRIBUTES); 240 } 241 } 242 } 243