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 */ ClientMonitor(Context context, long halDeviceId, IBinder token, IFingerprintServiceReceiver receiver, int userId, int groupId,boolean restricted, String owner)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 */ start()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 */ stop(boolean initiatedByClient)104 public abstract int stop(boolean initiatedByClient); 105 106 /** 107 * Method to explicitly poke powermanager on events 108 */ notifyUserActivity()109 public abstract void notifyUserActivity(); 110 111 /** 112 * Gets the fingerprint daemon from the cached state in the container class. 113 */ getFingerprintDaemon()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). onEnrollResult(int fingerId, int groupId, int rem)120 public abstract boolean onEnrollResult(int fingerId, int groupId, int rem); onAuthenticated(int fingerId, int groupId)121 public abstract boolean onAuthenticated(int fingerId, int groupId); onRemoved(int fingerId, int groupId, int remaining)122 public abstract boolean onRemoved(int fingerId, int groupId, int remaining); onEnumerationResult(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 */ onAcquired(int acquiredInfo, int vendorCode)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 */ onError(int error, int vendorCode)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 destroy()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 binderDied()179 public void binderDied() { 180 mToken = null; 181 mReceiver = null; 182 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); 183 } 184 185 @Override finalize()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 getContext()197 public final Context getContext() { 198 return mContext; 199 } 200 getHalDeviceId()201 public final long getHalDeviceId() { 202 return mHalDeviceId; 203 } 204 getOwnerString()205 public final String getOwnerString() { 206 return mOwner; 207 } 208 getReceiver()209 public final IFingerprintServiceReceiver getReceiver() { 210 return mReceiver; 211 } 212 getIsRestricted()213 public final boolean getIsRestricted() { 214 return mIsRestricted; 215 } 216 getTargetUserId()217 public final int getTargetUserId() { 218 return mTargetUserId; 219 } 220 getGroupId()221 public final int getGroupId() { 222 return mGroupId; 223 } 224 getToken()225 public final IBinder getToken() { 226 return mToken; 227 } 228 vibrateSuccess()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 vibrateError()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