1 /* 2 * Copyright (C) 2018 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.biometrics; 18 19 import android.content.Context; 20 import android.hardware.biometrics.BiometricAuthenticator; 21 import android.hardware.biometrics.BiometricConstants; 22 import android.media.AudioAttributes; 23 import android.os.IBinder; 24 import android.os.RemoteException; 25 import android.os.VibrationEffect; 26 import android.os.Vibrator; 27 import android.util.Slog; 28 29 import com.android.internal.logging.MetricsLogger; 30 31 import java.util.ArrayList; 32 import java.util.NoSuchElementException; 33 34 /** 35 * Abstract base class for keeping track and dispatching events from the biometric's HAL to the 36 * the current client. Subclasses are responsible for coordinating the interaction with 37 * the biometric's HAL for the specific action (e.g. authenticate, enroll, enumerate, etc.). 38 */ 39 public abstract class ClientMonitor extends LoggableMonitor implements IBinder.DeathRecipient { 40 protected static final int ERROR_ESRCH = 3; // Likely HAL is dead. See errno.h. 41 protected static final boolean DEBUG = BiometricServiceBase.DEBUG; 42 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(); 47 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 final BiometricServiceBase.DaemonWrapper mDaemon; 58 59 private IBinder mToken; 60 private BiometricServiceBase.ServiceListener mListener; 61 // Currently only used for authentication client. The cookie generated by BiometricService 62 // is never 0. 63 private final int mCookie; 64 65 protected final MetricsLogger mMetricsLogger; 66 protected final Constants mConstants; 67 68 protected boolean mAlreadyCancelled; 69 protected boolean mAlreadyDone; 70 71 /** 72 * @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 75 * @param token a unique token for the client 76 * @param listener recipient of related events (e.g. authentication) 77 * @param userId target user id for operation 78 * @param groupId groupId for the fingerprint set 79 * @param restricted whether or not client has the MANAGE_* permission 80 * permission 81 * @param owner name of the client that owns this 82 */ ClientMonitor(Context context, Constants constants, BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token, BiometricServiceBase.ServiceListener listener, int userId, int groupId, boolean restricted, String owner, int cookie)83 public ClientMonitor(Context context, Constants constants, 84 BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token, 85 BiometricServiceBase.ServiceListener listener, int userId, int groupId, 86 boolean restricted, String owner, int cookie) { 87 mContext = context; 88 mConstants = constants; 89 mDaemon = daemon; 90 mHalDeviceId = halDeviceId; 91 mToken = token; 92 mListener = listener; 93 mTargetUserId = userId; 94 mGroupId = groupId; 95 mIsRestricted = restricted; 96 mOwner = owner; 97 mCookie = cookie; 98 mSuccessVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); 99 mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK); 100 mMetricsLogger = new MetricsLogger(); 101 try { 102 if (token != null) { 103 token.linkToDeath(this, 0); 104 } 105 } catch (RemoteException e) { 106 Slog.w(getLogTag(), "caught remote exception in linkToDeath: ", e); 107 } 108 } 109 getLogTag()110 protected String getLogTag() { 111 return mConstants.logTag(); 112 } 113 getCookie()114 public int getCookie() { 115 return mCookie; 116 } 117 118 /** 119 * Contacts the biometric's HAL to start the client. 120 * @return 0 on success, errno from driver on failure 121 */ start()122 public abstract int start(); 123 124 /** 125 * Contacts the biometric's HAL to stop the client. 126 * @param initiatedByClient whether the operation is at the request of a client 127 */ stop(boolean initiatedByClient)128 public abstract int stop(boolean initiatedByClient); 129 130 /** 131 * Method to explicitly poke powermanager on events 132 */ notifyUserActivity()133 public abstract void notifyUserActivity(); 134 135 // 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 138 // to the next client (e.g. authentication accepts or rejects a biometric). onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining)139 public abstract boolean onEnrollResult(BiometricAuthenticator.Identifier identifier, 140 int remaining); onAuthenticated(BiometricAuthenticator.Identifier identifier, boolean authenticated, ArrayList<Byte> token)141 public abstract boolean onAuthenticated(BiometricAuthenticator.Identifier identifier, 142 boolean authenticated, ArrayList<Byte> token); onRemoved(BiometricAuthenticator.Identifier identifier, int remaining)143 public abstract boolean onRemoved(BiometricAuthenticator.Identifier identifier, 144 int remaining); onEnumerationResult( BiometricAuthenticator.Identifier identifier, int remaining)145 public abstract boolean onEnumerationResult( 146 BiometricAuthenticator.Identifier identifier, int remaining); 147 getAcquireIgnorelist()148 public int[] getAcquireIgnorelist() { 149 return new int[0]; 150 } getAcquireVendorIgnorelist()151 public int[] getAcquireVendorIgnorelist() { 152 return new int[0]; 153 } 154 blacklistContains(int acquiredInfo, int vendorCode)155 private boolean blacklistContains(int acquiredInfo, int vendorCode) { 156 if (acquiredInfo == mConstants.acquireVendorCode()) { 157 for (int i = 0; i < getAcquireVendorIgnorelist().length; i++) { 158 if (getAcquireVendorIgnorelist()[i] == vendorCode) { 159 if (DEBUG) Slog.v(getLogTag(), "Ignoring vendor message: " + vendorCode); 160 return true; 161 } 162 } 163 } else { 164 for (int i = 0; i < getAcquireIgnorelist().length; i++) { 165 if (getAcquireIgnorelist()[i] == acquiredInfo) { 166 if (DEBUG) Slog.v(getLogTag(), "Ignoring message: " + acquiredInfo); 167 return true; 168 } 169 } 170 } 171 return false; 172 } 173 isAlreadyDone()174 public boolean isAlreadyDone() { 175 return mAlreadyDone; 176 } 177 178 /** 179 * Called when we get notification from the biometric's HAL that an image has been acquired. 180 * Common to authenticate and enroll. 181 * @param acquiredInfo info about the current image acquisition 182 * @return true if client should be removed 183 */ onAcquired(int acquiredInfo, int vendorCode)184 public boolean onAcquired(int acquiredInfo, int vendorCode) { 185 super.logOnAcquired(mContext, acquiredInfo, vendorCode, getTargetUserId()); 186 if (DEBUG) Slog.v(getLogTag(), "Acquired: " + acquiredInfo + " " + vendorCode); 187 try { 188 if (mListener != null && !blacklistContains(acquiredInfo, vendorCode)) { 189 mListener.onAcquired(getHalDeviceId(), acquiredInfo, vendorCode); 190 } 191 return false; // acquisition continues... 192 } catch (RemoteException e) { 193 Slog.w(getLogTag(), "Failed to invoke sendAcquired", e); 194 return true; 195 } finally { 196 // Good scans will keep the device awake 197 if (acquiredInfo == BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) { 198 notifyUserActivity(); 199 } 200 } 201 } 202 203 /** 204 * Called when we get notification from the biometric's HAL that an error has occurred with the 205 * current operation. Common to authenticate, enroll, enumerate and remove. 206 * @param error 207 * @return true if client should be removed 208 */ onError(long deviceId, int error, int vendorCode)209 public boolean onError(long deviceId, int error, int vendorCode) { 210 super.logOnError(mContext, error, vendorCode, getTargetUserId()); 211 try { 212 if (mListener != null) { 213 mListener.onError(deviceId, error, vendorCode, getCookie()); 214 } 215 } catch (RemoteException e) { 216 Slog.w(getLogTag(), "Failed to invoke sendError", e); 217 } 218 return true; // errors always remove current client 219 } 220 destroy()221 public void destroy() { 222 if (mToken != null) { 223 try { 224 mToken.unlinkToDeath(this, 0); 225 } catch (NoSuchElementException e) { 226 // TODO: remove when duplicate call bug is found 227 Slog.e(getLogTag(), "destroy(): " + this + ":", new Exception("here")); 228 } 229 mToken = null; 230 } 231 mListener = null; 232 } 233 234 @Override binderDied()235 public void binderDied() { 236 // If the current client dies we should cancel the current operation. 237 Slog.e(getLogTag(), "Binder died, cancelling client"); 238 stop(false /* initiatedByClient */); 239 mToken = null; 240 mListener = null; 241 } 242 243 @Override finalize()244 protected void finalize() throws Throwable { 245 try { 246 if (mToken != null) { 247 if (DEBUG) Slog.w(getLogTag(), "removing leaked reference: " + mToken); 248 onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 249 0 /* vendorCode */); 250 } 251 } finally { 252 super.finalize(); 253 } 254 } 255 getContext()256 public final Context getContext() { 257 return mContext; 258 } 259 getHalDeviceId()260 public final long getHalDeviceId() { 261 return mHalDeviceId; 262 } 263 getOwnerString()264 public final String getOwnerString() { 265 return mOwner; 266 } 267 getListener()268 public final BiometricServiceBase.ServiceListener getListener() { 269 return mListener; 270 } 271 getDaemonWrapper()272 public final BiometricServiceBase.DaemonWrapper getDaemonWrapper() { 273 return mDaemon; 274 } 275 getIsRestricted()276 public final boolean getIsRestricted() { 277 return mIsRestricted; 278 } 279 getTargetUserId()280 public final int getTargetUserId() { 281 return mTargetUserId; 282 } 283 getGroupId()284 public final int getGroupId() { 285 return mGroupId; 286 } 287 getToken()288 public final IBinder getToken() { 289 return mToken; 290 } 291 vibrateSuccess()292 public final void vibrateSuccess() { 293 Vibrator vibrator = mContext.getSystemService(Vibrator.class); 294 if (vibrator != null) { 295 vibrator.vibrate(mSuccessVibrationEffect, FINGERPRINT_SONFICATION_ATTRIBUTES); 296 } 297 } 298 vibrateError()299 public final void vibrateError() { 300 Vibrator vibrator = mContext.getSystemService(Vibrator.class); 301 if (vibrator != null) { 302 vibrator.vibrate(mErrorVibrationEffect, FINGERPRINT_SONFICATION_ATTRIBUTES); 303 } 304 } 305 } 306