1 /** 2 * Copyright (C) 2014 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.app.ActivityManager; 21 import android.app.ActivityManager.RunningAppProcessInfo; 22 import android.app.ActivityManagerNative; 23 import android.app.AlarmManager; 24 import android.app.AppOpsManager; 25 import android.app.PendingIntent; 26 import android.app.SynchronousUserSwitchObserver; 27 import android.content.ComponentName; 28 import android.content.BroadcastReceiver; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.IntentFilter; 32 import android.content.pm.PackageManager; 33 import android.content.pm.UserInfo; 34 import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback; 35 import android.os.Binder; 36 import android.os.DeadObjectException; 37 import android.os.Environment; 38 import android.os.Handler; 39 import android.os.IBinder; 40 import android.os.PowerManager; 41 import android.os.RemoteException; 42 import android.os.SELinux; 43 import android.os.ServiceManager; 44 import android.os.SystemClock; 45 import android.os.UserHandle; 46 import android.os.UserManager; 47 import android.util.Slog; 48 49 import com.android.internal.logging.MetricsLogger; 50 import com.android.server.SystemService; 51 52 import org.json.JSONArray; 53 import org.json.JSONException; 54 import org.json.JSONObject; 55 56 import android.hardware.fingerprint.Fingerprint; 57 import android.hardware.fingerprint.FingerprintManager; 58 import android.hardware.fingerprint.IFingerprintService; 59 import android.hardware.fingerprint.IFingerprintDaemon; 60 import android.hardware.fingerprint.IFingerprintDaemonCallback; 61 import android.hardware.fingerprint.IFingerprintServiceReceiver; 62 63 import static android.Manifest.permission.INTERACT_ACROSS_USERS; 64 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; 65 import static android.Manifest.permission.MANAGE_FINGERPRINT; 66 import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT; 67 import static android.Manifest.permission.USE_FINGERPRINT; 68 69 import java.io.File; 70 import java.io.FileDescriptor; 71 import java.io.PrintWriter; 72 import java.util.ArrayList; 73 import java.util.Arrays; 74 import java.util.Collections; 75 import java.util.HashMap; 76 import java.util.List; 77 78 /** 79 * A service to manage multiple clients that want to access the fingerprint HAL API. 80 * The service is responsible for maintaining a list of clients and dispatching all 81 * fingerprint -related events. 82 * 83 * @hide 84 */ 85 public class FingerprintService extends SystemService implements IBinder.DeathRecipient { 86 static final String TAG = "FingerprintService"; 87 static final boolean DEBUG = true; 88 private static final String FP_DATA_DIR = "fpdata"; 89 private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon"; 90 private static final int MSG_USER_SWITCHING = 10; 91 private static final String ACTION_LOCKOUT_RESET = 92 "com.android.server.fingerprint.ACTION_LOCKOUT_RESET"; 93 94 private class PerformanceStats { 95 int accept; // number of accepted fingerprints 96 int reject; // number of rejected fingerprints 97 int acquire; // total number of acquisitions. Should be >= accept+reject due to poor image 98 // acquisition in some cases (too fast, too slow, dirty sensor, etc.) 99 int lockout; // total number of lockouts 100 } 101 102 private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors = 103 new ArrayList<>(); 104 private final AppOpsManager mAppOps; 105 private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000; 106 private static final int MAX_FAILED_ATTEMPTS = 5; 107 private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms 108 private final String mKeyguardPackage; 109 private int mCurrentUserId = UserHandle.USER_CURRENT; 110 private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance(); 111 private Context mContext; 112 private long mHalDeviceId; 113 private int mFailedAttempts; 114 private IFingerprintDaemon mDaemon; 115 private final PowerManager mPowerManager; 116 private final AlarmManager mAlarmManager; 117 private final UserManager mUserManager; 118 private ClientMonitor mCurrentClient; 119 private ClientMonitor mPendingClient; 120 private long mCurrentAuthenticatorId; 121 private PerformanceStats mPerformanceStats; 122 123 // Normal fingerprint authentications are tracked by mPerformanceMap. 124 private HashMap<Integer, PerformanceStats> mPerformanceMap 125 = new HashMap<Integer, PerformanceStats>(); 126 127 // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap. 128 private HashMap<Integer, PerformanceStats> mCryptoPerformanceMap 129 = new HashMap<Integer, PerformanceStats>(); 130 131 private Handler mHandler = new Handler() { 132 @Override 133 public void handleMessage(android.os.Message msg) { 134 switch (msg.what) { 135 case MSG_USER_SWITCHING: 136 handleUserSwitching(msg.arg1); 137 break; 138 139 default: 140 Slog.w(TAG, "Unknown message:" + msg.what); 141 } 142 } 143 }; 144 145 private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() { 146 @Override 147 public void onReceive(Context context, Intent intent) { 148 if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) { 149 resetFailedAttempts(); 150 } 151 } 152 }; 153 154 private final Runnable mResetFailedAttemptsRunnable = new Runnable() { 155 @Override 156 public void run() { 157 resetFailedAttempts(); 158 } 159 }; 160 161 private final Runnable mResetClientState = new Runnable() { 162 @Override 163 public void run() { 164 // Warning: if we get here, the driver never confirmed our call to cancel the current 165 // operation (authenticate, enroll, remove, enumerate, etc), which is 166 // really bad. The result will be a 3-second delay in starting each new client. 167 // If you see this on a device, make certain the driver notifies with 168 // {@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} in response to cancel() 169 // once it has successfully switched to the IDLE state in the fingerprint HAL. 170 // Additionally,{@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} should only be sent 171 // in response to an actual cancel() call. 172 Slog.w(TAG, "Client " 173 + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null") 174 + " failed to respond to cancel, starting client " 175 + (mPendingClient != null ? mPendingClient.getOwnerString() : "null")); 176 mCurrentClient = null; 177 startClient(mPendingClient, false); 178 } 179 }; 180 FingerprintService(Context context)181 public FingerprintService(Context context) { 182 super(context); 183 mContext = context; 184 mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString( 185 com.android.internal.R.string.config_keyguardComponent)).getPackageName(); 186 mAppOps = context.getSystemService(AppOpsManager.class); 187 mPowerManager = mContext.getSystemService(PowerManager.class); 188 mAlarmManager = mContext.getSystemService(AlarmManager.class); 189 mContext.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET), 190 RESET_FINGERPRINT_LOCKOUT, null /* handler */); 191 mUserManager = UserManager.get(mContext); 192 } 193 194 @Override binderDied()195 public void binderDied() { 196 Slog.v(TAG, "fingerprintd died"); 197 mDaemon = null; 198 handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); 199 } 200 getFingerprintDaemon()201 public IFingerprintDaemon getFingerprintDaemon() { 202 if (mDaemon == null) { 203 mDaemon = IFingerprintDaemon.Stub.asInterface(ServiceManager.getService(FINGERPRINTD)); 204 if (mDaemon != null) { 205 try { 206 mDaemon.asBinder().linkToDeath(this, 0); 207 mDaemon.init(mDaemonCallback); 208 mHalDeviceId = mDaemon.openHal(); 209 if (mHalDeviceId != 0) { 210 updateActiveGroup(ActivityManager.getCurrentUser(), null); 211 } else { 212 Slog.w(TAG, "Failed to open Fingerprint HAL!"); 213 mDaemon = null; 214 } 215 } catch (RemoteException e) { 216 Slog.e(TAG, "Failed to open fingeprintd HAL", e); 217 mDaemon = null; // try again later! 218 } 219 } else { 220 Slog.w(TAG, "fingerprint service not available"); 221 } 222 } 223 return mDaemon; 224 } 225 handleEnumerate(long deviceId, int[] fingerIds, int[] groupIds)226 protected void handleEnumerate(long deviceId, int[] fingerIds, int[] groupIds) { 227 if (fingerIds.length != groupIds.length) { 228 Slog.w(TAG, "fingerIds and groupIds differ in length: f[]=" 229 + Arrays.toString(fingerIds) + ", g[]=" + Arrays.toString(groupIds)); 230 return; 231 } 232 if (DEBUG) Slog.w(TAG, "Enumerate: f[]=" + fingerIds + ", g[]=" + groupIds); 233 // TODO: update fingerprint/name pairs 234 } 235 handleError(long deviceId, int error)236 protected void handleError(long deviceId, int error) { 237 ClientMonitor client = mCurrentClient; 238 if (client != null && client.onError(error)) { 239 removeClient(client); 240 } 241 if (DEBUG) Slog.v(TAG, "handleError(client=" 242 + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")"); 243 // This is the magic code that starts the next client when the old client finishes. 244 if (error == FingerprintManager.FINGERPRINT_ERROR_CANCELED) { 245 mHandler.removeCallbacks(mResetClientState); 246 if (mPendingClient != null) { 247 if (DEBUG) Slog.v(TAG, "start pending client " + mPendingClient.getOwnerString()); 248 startClient(mPendingClient, false); 249 mPendingClient = null; 250 } 251 } 252 } 253 handleRemoved(long deviceId, int fingerId, int groupId)254 protected void handleRemoved(long deviceId, int fingerId, int groupId) { 255 ClientMonitor client = mCurrentClient; 256 if (client != null && client.onRemoved(fingerId, groupId)) { 257 removeClient(client); 258 } 259 } 260 handleAuthenticated(long deviceId, int fingerId, int groupId)261 protected void handleAuthenticated(long deviceId, int fingerId, int groupId) { 262 ClientMonitor client = mCurrentClient; 263 if (client != null && client.onAuthenticated(fingerId, groupId)) { 264 removeClient(client); 265 } 266 if (fingerId != 0) { 267 mPerformanceStats.accept++; 268 } else { 269 mPerformanceStats.reject++; 270 } 271 } 272 handleAcquired(long deviceId, int acquiredInfo)273 protected void handleAcquired(long deviceId, int acquiredInfo) { 274 ClientMonitor client = mCurrentClient; 275 if (client != null && client.onAcquired(acquiredInfo)) { 276 removeClient(client); 277 } 278 if (mPerformanceStats != null && !inLockoutMode() 279 && client instanceof AuthenticationClient) { 280 // ignore enrollment acquisitions or acquisitions when we're locked out 281 mPerformanceStats.acquire++; 282 } 283 } 284 handleEnrollResult(long deviceId, int fingerId, int groupId, int remaining)285 protected void handleEnrollResult(long deviceId, int fingerId, int groupId, int remaining) { 286 ClientMonitor client = mCurrentClient; 287 if (client != null && client.onEnrollResult(fingerId, groupId, remaining)) { 288 removeClient(client); 289 } 290 } 291 userActivity()292 private void userActivity() { 293 long now = SystemClock.uptimeMillis(); 294 mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0); 295 } 296 handleUserSwitching(int userId)297 void handleUserSwitching(int userId) { 298 updateActiveGroup(userId, null); 299 } 300 removeClient(ClientMonitor client)301 private void removeClient(ClientMonitor client) { 302 if (client != null) { 303 client.destroy(); 304 if (client != mCurrentClient && mCurrentClient != null) { 305 Slog.w(TAG, "Unexpected client: " + client.getOwnerString() + "expected: " 306 + mCurrentClient != null ? mCurrentClient.getOwnerString() : "null"); 307 } 308 } 309 if (mCurrentClient != null) { 310 if (DEBUG) Slog.v(TAG, "Done with client: " + client.getOwnerString()); 311 mCurrentClient = null; 312 } 313 } 314 inLockoutMode()315 private boolean inLockoutMode() { 316 return mFailedAttempts >= MAX_FAILED_ATTEMPTS; 317 } 318 scheduleLockoutReset()319 private void scheduleLockoutReset() { 320 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 321 SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS, getLockoutResetIntent()); 322 } 323 cancelLockoutReset()324 private void cancelLockoutReset() { 325 mAlarmManager.cancel(getLockoutResetIntent()); 326 } 327 getLockoutResetIntent()328 private PendingIntent getLockoutResetIntent() { 329 return PendingIntent.getBroadcast(mContext, 0, 330 new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT); 331 } 332 startPreEnroll(IBinder token)333 public long startPreEnroll(IBinder token) { 334 IFingerprintDaemon daemon = getFingerprintDaemon(); 335 if (daemon == null) { 336 Slog.w(TAG, "startPreEnroll: no fingeprintd!"); 337 return 0; 338 } 339 try { 340 return daemon.preEnroll(); 341 } catch (RemoteException e) { 342 Slog.e(TAG, "startPreEnroll failed", e); 343 } 344 return 0; 345 } 346 startPostEnroll(IBinder token)347 public int startPostEnroll(IBinder token) { 348 IFingerprintDaemon daemon = getFingerprintDaemon(); 349 if (daemon == null) { 350 Slog.w(TAG, "startPostEnroll: no fingeprintd!"); 351 return 0; 352 } 353 try { 354 return daemon.postEnroll(); 355 } catch (RemoteException e) { 356 Slog.e(TAG, "startPostEnroll failed", e); 357 } 358 return 0; 359 } 360 361 /** 362 * Calls fingerprintd to switch states to the new task. If there's already a current task, 363 * it calls cancel() and sets mPendingClient to begin when the current task finishes 364 * ({@link FingerprintManager#FINGERPRINT_ERROR_CANCELED}). 365 * @param newClient the new client that wants to connect 366 * @param initiatedByClient true for authenticate, remove and enroll 367 */ startClient(ClientMonitor newClient, boolean initiatedByClient)368 private void startClient(ClientMonitor newClient, boolean initiatedByClient) { 369 ClientMonitor currentClient = mCurrentClient; 370 if (currentClient != null) { 371 if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString()); 372 currentClient.stop(initiatedByClient); 373 mPendingClient = newClient; 374 mHandler.removeCallbacks(mResetClientState); 375 mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT); 376 } else if (newClient != null) { 377 mCurrentClient = newClient; 378 if (DEBUG) Slog.v(TAG, "starting client " 379 + newClient.getClass().getSuperclass().getSimpleName() 380 + "(" + newClient.getOwnerString() + ")" 381 + ", initiatedByClient = " + initiatedByClient + ")"); 382 newClient.start(); 383 } 384 } 385 startRemove(IBinder token, int fingerId, int groupId, int userId, IFingerprintServiceReceiver receiver, boolean restricted)386 void startRemove(IBinder token, int fingerId, int groupId, int userId, 387 IFingerprintServiceReceiver receiver, boolean restricted) { 388 IFingerprintDaemon daemon = getFingerprintDaemon(); 389 if (daemon == null) { 390 Slog.w(TAG, "startRemove: no fingeprintd!"); 391 return; 392 } 393 RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token, 394 receiver, fingerId, groupId, userId, restricted, token.toString()) { 395 @Override 396 public void notifyUserActivity() { 397 FingerprintService.this.userActivity(); 398 } 399 400 @Override 401 public IFingerprintDaemon getFingerprintDaemon() { 402 return FingerprintService.this.getFingerprintDaemon(); 403 } 404 }; 405 startClient(client, true); 406 } 407 getEnrolledFingerprints(int userId)408 public List<Fingerprint> getEnrolledFingerprints(int userId) { 409 return mFingerprintUtils.getFingerprintsForUser(mContext, userId); 410 } 411 hasEnrolledFingerprints(int userId)412 public boolean hasEnrolledFingerprints(int userId) { 413 if (userId != UserHandle.getCallingUserId()) { 414 checkPermission(INTERACT_ACROSS_USERS); 415 } 416 return mFingerprintUtils.getFingerprintsForUser(mContext, userId).size() > 0; 417 } 418 hasPermission(String permission)419 boolean hasPermission(String permission) { 420 return getContext().checkCallingOrSelfPermission(permission) 421 == PackageManager.PERMISSION_GRANTED; 422 } 423 checkPermission(String permission)424 void checkPermission(String permission) { 425 getContext().enforceCallingOrSelfPermission(permission, 426 "Must have " + permission + " permission."); 427 } 428 getEffectiveUserId(int userId)429 int getEffectiveUserId(int userId) { 430 UserManager um = UserManager.get(mContext); 431 if (um != null) { 432 final long callingIdentity = Binder.clearCallingIdentity(); 433 userId = um.getCredentialOwnerProfile(userId); 434 Binder.restoreCallingIdentity(callingIdentity); 435 } else { 436 Slog.e(TAG, "Unable to acquire UserManager"); 437 } 438 return userId; 439 } 440 isCurrentUserOrProfile(int userId)441 boolean isCurrentUserOrProfile(int userId) { 442 UserManager um = UserManager.get(mContext); 443 444 // Allow current user or profiles of the current user... 445 for (int profileId : um.getEnabledProfileIds(userId)) { 446 if (profileId == userId) { 447 return true; 448 } 449 } 450 return false; 451 } 452 isForegroundActivity(int uid, int pid)453 private boolean isForegroundActivity(int uid, int pid) { 454 try { 455 List<RunningAppProcessInfo> procs = 456 ActivityManagerNative.getDefault().getRunningAppProcesses(); 457 int N = procs.size(); 458 for (int i = 0; i < N; i++) { 459 RunningAppProcessInfo proc = procs.get(i); 460 if (proc.pid == pid && proc.uid == uid 461 && proc.importance == IMPORTANCE_FOREGROUND) { 462 return true; 463 } 464 } 465 } catch (RemoteException e) { 466 Slog.w(TAG, "am.getRunningAppProcesses() failed"); 467 } 468 return false; 469 } 470 471 /** 472 * @param opPackageName name of package for caller 473 * @param requireForeground only allow this call while app is in the foreground 474 * @return true if caller can use fingerprint API 475 */ canUseFingerprint(String opPackageName, boolean requireForeground, int uid, int pid)476 private boolean canUseFingerprint(String opPackageName, boolean requireForeground, int uid, 477 int pid) { 478 checkPermission(USE_FINGERPRINT); 479 if (isKeyguard(opPackageName)) { 480 return true; // Keyguard is always allowed 481 } 482 if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) { 483 Slog.w(TAG,"Rejecting " + opPackageName + " ; not a current user or profile"); 484 return false; 485 } 486 if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName) 487 != AppOpsManager.MODE_ALLOWED) { 488 Slog.w(TAG, "Rejecting " + opPackageName + " ; permission denied"); 489 return false; 490 } 491 if (requireForeground && !(isForegroundActivity(uid, pid) || currentClient(opPackageName))){ 492 Slog.w(TAG, "Rejecting " + opPackageName + " ; not in foreground"); 493 return false; 494 } 495 return true; 496 } 497 498 /** 499 * @param opPackageName package of the caller 500 * @return true if this is the same client currently using fingerprint 501 */ currentClient(String opPackageName)502 private boolean currentClient(String opPackageName) { 503 return mCurrentClient != null && mCurrentClient.getOwnerString().equals(opPackageName); 504 } 505 506 /** 507 * @param clientPackage 508 * @return true if this is keyguard package 509 */ isKeyguard(String clientPackage)510 private boolean isKeyguard(String clientPackage) { 511 return mKeyguardPackage.equals(clientPackage); 512 } 513 addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor)514 private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) { 515 if (!mLockoutMonitors.contains(monitor)) { 516 mLockoutMonitors.add(monitor); 517 } 518 } 519 removeLockoutResetCallback( FingerprintServiceLockoutResetMonitor monitor)520 private void removeLockoutResetCallback( 521 FingerprintServiceLockoutResetMonitor monitor) { 522 mLockoutMonitors.remove(monitor); 523 } 524 notifyLockoutResetMonitors()525 private void notifyLockoutResetMonitors() { 526 for (int i = 0; i < mLockoutMonitors.size(); i++) { 527 mLockoutMonitors.get(i).sendLockoutReset(); 528 } 529 } 530 startAuthentication(IBinder token, long opId, int callingUserId, int groupId, IFingerprintServiceReceiver receiver, int flags, boolean restricted, String opPackageName)531 private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId, 532 IFingerprintServiceReceiver receiver, int flags, boolean restricted, 533 String opPackageName) { 534 updateActiveGroup(groupId, opPackageName); 535 536 if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")"); 537 538 AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token, 539 receiver, mCurrentUserId, groupId, opId, restricted, opPackageName) { 540 @Override 541 public boolean handleFailedAttempt() { 542 mFailedAttempts++; 543 if (mFailedAttempts == MAX_FAILED_ATTEMPTS) { 544 mPerformanceStats.lockout++; 545 } 546 if (inLockoutMode()) { 547 // Failing multiple times will continue to push out the lockout time. 548 scheduleLockoutReset(); 549 return true; 550 } 551 return false; 552 } 553 554 @Override 555 public void resetFailedAttempts() { 556 FingerprintService.this.resetFailedAttempts(); 557 } 558 559 @Override 560 public void notifyUserActivity() { 561 FingerprintService.this.userActivity(); 562 } 563 564 @Override 565 public IFingerprintDaemon getFingerprintDaemon() { 566 return FingerprintService.this.getFingerprintDaemon(); 567 } 568 }; 569 570 if (inLockoutMode()) { 571 Slog.v(TAG, "In lockout mode; disallowing authentication"); 572 // Don't bother starting the client. Just send the error message. 573 if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) { 574 Slog.w(TAG, "Cannot send timeout message to client"); 575 } 576 return; 577 } 578 startClient(client, true /* initiatedByClient */); 579 } 580 startEnrollment(IBinder token, byte [] cryptoToken, int userId, IFingerprintServiceReceiver receiver, int flags, boolean restricted, String opPackageName)581 private void startEnrollment(IBinder token, byte [] cryptoToken, int userId, 582 IFingerprintServiceReceiver receiver, int flags, boolean restricted, 583 String opPackageName) { 584 updateActiveGroup(userId, opPackageName); 585 586 final int groupId = userId; // default group for fingerprint enrollment 587 588 EnrollClient client = new EnrollClient(getContext(), mHalDeviceId, token, receiver, 589 userId, groupId, cryptoToken, restricted, opPackageName) { 590 591 @Override 592 public IFingerprintDaemon getFingerprintDaemon() { 593 return FingerprintService.this.getFingerprintDaemon(); 594 } 595 596 @Override 597 public void notifyUserActivity() { 598 FingerprintService.this.userActivity(); 599 } 600 }; 601 startClient(client, true /* initiatedByClient */); 602 } 603 resetFailedAttempts()604 protected void resetFailedAttempts() { 605 if (DEBUG && inLockoutMode()) { 606 Slog.v(TAG, "Reset fingerprint lockout"); 607 } 608 mFailedAttempts = 0; 609 // If we're asked to reset failed attempts externally (i.e. from Keyguard), 610 // the alarm might still be pending; remove it. 611 cancelLockoutReset(); 612 notifyLockoutResetMonitors(); 613 } 614 615 private class FingerprintServiceLockoutResetMonitor { 616 617 private final IFingerprintServiceLockoutResetCallback mCallback; 618 FingerprintServiceLockoutResetMonitor( IFingerprintServiceLockoutResetCallback callback)619 public FingerprintServiceLockoutResetMonitor( 620 IFingerprintServiceLockoutResetCallback callback) { 621 mCallback = callback; 622 } 623 sendLockoutReset()624 public void sendLockoutReset() { 625 if (mCallback != null) { 626 try { 627 mCallback.onLockoutReset(mHalDeviceId); 628 } catch (DeadObjectException e) { 629 Slog.w(TAG, "Death object while invoking onLockoutReset: ", e); 630 mHandler.post(mRemoveCallbackRunnable); 631 } catch (RemoteException e) { 632 Slog.w(TAG, "Failed to invoke onLockoutReset: ", e); 633 } 634 } 635 } 636 637 private final Runnable mRemoveCallbackRunnable = new Runnable() { 638 @Override 639 public void run() { 640 removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this); 641 } 642 }; 643 } 644 645 private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() { 646 647 @Override 648 public void onEnrollResult(final long deviceId, final int fingerId, final int groupId, 649 final int remaining) { 650 mHandler.post(new Runnable() { 651 @Override 652 public void run() { 653 handleEnrollResult(deviceId, fingerId, groupId, remaining); 654 } 655 }); 656 } 657 658 @Override 659 public void onAcquired(final long deviceId, final int acquiredInfo) { 660 mHandler.post(new Runnable() { 661 @Override 662 public void run() { 663 handleAcquired(deviceId, acquiredInfo); 664 } 665 }); 666 } 667 668 @Override 669 public void onAuthenticated(final long deviceId, final int fingerId, final int groupId) { 670 mHandler.post(new Runnable() { 671 @Override 672 public void run() { 673 handleAuthenticated(deviceId, fingerId, groupId); 674 } 675 }); 676 } 677 678 @Override 679 public void onError(final long deviceId, final int error) { 680 mHandler.post(new Runnable() { 681 @Override 682 public void run() { 683 handleError(deviceId, error); 684 } 685 }); 686 } 687 688 @Override 689 public void onRemoved(final long deviceId, final int fingerId, final int groupId) { 690 mHandler.post(new Runnable() { 691 @Override 692 public void run() { 693 handleRemoved(deviceId, fingerId, groupId); 694 } 695 }); 696 } 697 698 @Override 699 public void onEnumerate(final long deviceId, final int[] fingerIds, final int[] groupIds) { 700 mHandler.post(new Runnable() { 701 @Override 702 public void run() { 703 handleEnumerate(deviceId, fingerIds, groupIds); 704 } 705 }); 706 } 707 }; 708 709 private final class FingerprintServiceWrapper extends IFingerprintService.Stub { 710 @Override // Binder call preEnroll(IBinder token)711 public long preEnroll(IBinder token) { 712 checkPermission(MANAGE_FINGERPRINT); 713 return startPreEnroll(token); 714 } 715 716 @Override // Binder call postEnroll(IBinder token)717 public int postEnroll(IBinder token) { 718 checkPermission(MANAGE_FINGERPRINT); 719 return startPostEnroll(token); 720 } 721 722 @Override // Binder call enroll(final IBinder token, final byte[] cryptoToken, final int userId, final IFingerprintServiceReceiver receiver, final int flags, final String opPackageName)723 public void enroll(final IBinder token, final byte[] cryptoToken, final int userId, 724 final IFingerprintServiceReceiver receiver, final int flags, 725 final String opPackageName) { 726 checkPermission(MANAGE_FINGERPRINT); 727 final int limit = mContext.getResources().getInteger( 728 com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser); 729 730 final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size(); 731 if (enrolled >= limit) { 732 Slog.w(TAG, "Too many fingerprints registered"); 733 return; 734 } 735 736 // Group ID is arbitrarily set to parent profile user ID. It just represents 737 // the default fingerprints for the user. 738 if (!isCurrentUserOrProfile(userId)) { 739 return; 740 } 741 742 final boolean restricted = isRestricted(); 743 mHandler.post(new Runnable() { 744 @Override 745 public void run() { 746 startEnrollment(token, cryptoToken, userId, receiver, flags, 747 restricted, opPackageName); 748 } 749 }); 750 } 751 isRestricted()752 private boolean isRestricted() { 753 // Only give privileged apps (like Settings) access to fingerprint info 754 final boolean restricted = !hasPermission(MANAGE_FINGERPRINT); 755 return restricted; 756 } 757 758 @Override // Binder call cancelEnrollment(final IBinder token)759 public void cancelEnrollment(final IBinder token) { 760 checkPermission(MANAGE_FINGERPRINT); 761 mHandler.post(new Runnable() { 762 @Override 763 public void run() { 764 ClientMonitor client = mCurrentClient; 765 if (client instanceof EnrollClient && client.getToken() == token) { 766 client.stop(client.getToken() == token); 767 } 768 } 769 }); 770 } 771 772 @Override // Binder call authenticate(final IBinder token, final long opId, final int groupId, final IFingerprintServiceReceiver receiver, final int flags, final String opPackageName)773 public void authenticate(final IBinder token, final long opId, final int groupId, 774 final IFingerprintServiceReceiver receiver, final int flags, 775 final String opPackageName) { 776 final int callingUid = Binder.getCallingUid(); 777 final int callingUserId = UserHandle.getCallingUserId(); 778 final int pid = Binder.getCallingPid(); 779 final boolean restricted = isRestricted(); 780 mHandler.post(new Runnable() { 781 @Override 782 public void run() { 783 if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, 784 callingUid, pid)) { 785 if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName); 786 return; 787 } 788 789 MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0); 790 791 // Get performance stats object for this user. 792 HashMap<Integer, PerformanceStats> pmap 793 = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap; 794 PerformanceStats stats = pmap.get(mCurrentUserId); 795 if (stats == null) { 796 stats = new PerformanceStats(); 797 pmap.put(mCurrentUserId, stats); 798 } 799 mPerformanceStats = stats; 800 801 startAuthentication(token, opId, callingUserId, groupId, receiver, 802 flags, restricted, opPackageName); 803 } 804 }); 805 } 806 807 @Override // Binder call cancelAuthentication(final IBinder token, final String opPackageName)808 public void cancelAuthentication(final IBinder token, final String opPackageName) { 809 final int uid = Binder.getCallingUid(); 810 final int pid = Binder.getCallingPid(); 811 mHandler.post(new Runnable() { 812 @Override 813 public void run() { 814 if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, uid, pid)) { 815 if (DEBUG) Slog.v(TAG, "cancelAuthentication(): reject " + opPackageName); 816 } else { 817 ClientMonitor client = mCurrentClient; 818 if (client instanceof AuthenticationClient) { 819 if (client.getToken() == token) { 820 if (DEBUG) Slog.v(TAG, "stop client " + client.getOwnerString()); 821 client.stop(client.getToken() == token); 822 } else { 823 if (DEBUG) Slog.v(TAG, "can't stop client " 824 + client.getOwnerString() + " since tokens don't match"); 825 } 826 } else if (client != null) { 827 if (DEBUG) Slog.v(TAG, "can't cancel non-authenticating client " 828 + client.getOwnerString()); 829 } 830 } 831 } 832 }); 833 } 834 835 @Override // Binder call setActiveUser(final int userId)836 public void setActiveUser(final int userId) { 837 checkPermission(MANAGE_FINGERPRINT); 838 mHandler.post(new Runnable() { 839 @Override 840 public void run() { 841 updateActiveGroup(userId, null); 842 } 843 }); 844 } 845 846 @Override // Binder call remove(final IBinder token, final int fingerId, final int groupId, final int userId, final IFingerprintServiceReceiver receiver)847 public void remove(final IBinder token, final int fingerId, final int groupId, 848 final int userId, final IFingerprintServiceReceiver receiver) { 849 checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission 850 final boolean restricted = isRestricted(); 851 mHandler.post(new Runnable() { 852 @Override 853 public void run() { 854 startRemove(token, fingerId, groupId, userId, receiver, restricted); 855 } 856 }); 857 858 } 859 860 @Override // Binder call isHardwareDetected(long deviceId, String opPackageName)861 public boolean isHardwareDetected(long deviceId, String opPackageName) { 862 if (!canUseFingerprint(opPackageName, false /* foregroundOnly */, 863 Binder.getCallingUid(), Binder.getCallingPid())) { 864 return false; 865 } 866 return mHalDeviceId != 0; 867 } 868 869 @Override // Binder call rename(final int fingerId, final int groupId, final String name)870 public void rename(final int fingerId, final int groupId, final String name) { 871 checkPermission(MANAGE_FINGERPRINT); 872 if (!isCurrentUserOrProfile(groupId)) { 873 return; 874 } 875 mHandler.post(new Runnable() { 876 @Override 877 public void run() { 878 mFingerprintUtils.renameFingerprintForUser(mContext, fingerId, 879 groupId, name); 880 } 881 }); 882 } 883 884 @Override // Binder call getEnrolledFingerprints(int userId, String opPackageName)885 public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) { 886 if (!canUseFingerprint(opPackageName, false /* foregroundOnly */, 887 Binder.getCallingUid(), Binder.getCallingPid())) { 888 return Collections.emptyList(); 889 } 890 if (!isCurrentUserOrProfile(userId)) { 891 return Collections.emptyList(); 892 } 893 894 return FingerprintService.this.getEnrolledFingerprints(userId); 895 } 896 897 @Override // Binder call hasEnrolledFingerprints(int userId, String opPackageName)898 public boolean hasEnrolledFingerprints(int userId, String opPackageName) { 899 if (!canUseFingerprint(opPackageName, false /* foregroundOnly */, 900 Binder.getCallingUid(), Binder.getCallingPid())) { 901 return false; 902 } 903 904 if (!isCurrentUserOrProfile(userId)) { 905 return false; 906 } 907 return FingerprintService.this.hasEnrolledFingerprints(userId); 908 } 909 910 @Override // Binder call getAuthenticatorId(String opPackageName)911 public long getAuthenticatorId(String opPackageName) { 912 // In this method, we're not checking whether the caller is permitted to use fingerprint 913 // API because current authenticator ID is leaked (in a more contrived way) via Android 914 // Keystore (android.security.keystore package): the user of that API can create a key 915 // which requires fingerprint authentication for its use, and then query the key's 916 // characteristics (hidden API) which returns, among other things, fingerprint 917 // authenticator ID which was active at key creation time. 918 // 919 // Reason: The part of Android Keystore which runs inside an app's process invokes this 920 // method in certain cases. Those cases are not always where the developer demonstrates 921 // explicit intent to use fingerprint functionality. Thus, to avoiding throwing an 922 // unexpected SecurityException this method does not check whether its caller is 923 // permitted to use fingerprint API. 924 // 925 // The permission check should be restored once Android Keystore no longer invokes this 926 // method from inside app processes. 927 928 return FingerprintService.this.getAuthenticatorId(opPackageName); 929 } 930 931 @Override // Binder call dump(FileDescriptor fd, PrintWriter pw, String[] args)932 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 933 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 934 != PackageManager.PERMISSION_GRANTED) { 935 pw.println("Permission Denial: can't dump Fingerprint from from pid=" 936 + Binder.getCallingPid() 937 + ", uid=" + Binder.getCallingUid()); 938 return; 939 } 940 941 final long ident = Binder.clearCallingIdentity(); 942 try { 943 dumpInternal(pw); 944 } finally { 945 Binder.restoreCallingIdentity(ident); 946 } 947 } 948 @Override // Binder call resetTimeout(byte [] token)949 public void resetTimeout(byte [] token) { 950 checkPermission(RESET_FINGERPRINT_LOCKOUT); 951 // TODO: confirm security token when we move timeout management into the HAL layer. 952 mHandler.post(mResetFailedAttemptsRunnable); 953 } 954 955 @Override addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback)956 public void addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback) 957 throws RemoteException { 958 mHandler.post(new Runnable() { 959 @Override 960 public void run() { 961 addLockoutResetMonitor( 962 new FingerprintServiceLockoutResetMonitor(callback)); 963 } 964 }); 965 } 966 } 967 dumpInternal(PrintWriter pw)968 private void dumpInternal(PrintWriter pw) { 969 JSONObject dump = new JSONObject(); 970 try { 971 dump.put("service", "Fingerprint Manager"); 972 973 JSONArray sets = new JSONArray(); 974 for (UserInfo user : UserManager.get(getContext()).getUsers()) { 975 final int userId = user.getUserHandle().getIdentifier(); 976 final int N = mFingerprintUtils.getFingerprintsForUser(mContext, userId).size(); 977 PerformanceStats stats = mPerformanceMap.get(userId); 978 PerformanceStats cryptoStats = mCryptoPerformanceMap.get(userId); 979 JSONObject set = new JSONObject(); 980 set.put("id", userId); 981 set.put("count", N); 982 set.put("accept", (stats != null) ? stats.accept : 0); 983 set.put("reject", (stats != null) ? stats.reject : 0); 984 set.put("acquire", (stats != null) ? stats.acquire : 0); 985 set.put("lockout", (stats != null) ? stats.lockout : 0); 986 // cryptoStats measures statistics about secure fingerprint transactions 987 // (e.g. to unlock password storage, make secure purchases, etc.) 988 set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0); 989 set.put("rejectCrypto", (cryptoStats != null) ? cryptoStats.reject : 0); 990 set.put("acquireCrypto", (cryptoStats != null) ? cryptoStats.acquire : 0); 991 set.put("lockoutCrypto", (cryptoStats != null) ? cryptoStats.lockout : 0); 992 sets.put(set); 993 } 994 995 dump.put("prints", sets); 996 } catch (JSONException e) { 997 Slog.e(TAG, "dump formatting failure", e); 998 } 999 pw.println(dump); 1000 } 1001 1002 @Override onStart()1003 public void onStart() { 1004 publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper()); 1005 IFingerprintDaemon daemon = getFingerprintDaemon(); 1006 if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId); 1007 listenForUserSwitches(); 1008 } 1009 updateActiveGroup(int userId, String clientPackage)1010 private void updateActiveGroup(int userId, String clientPackage) { 1011 IFingerprintDaemon daemon = getFingerprintDaemon(); 1012 1013 if (daemon != null) { 1014 try { 1015 userId = getUserOrWorkProfileId(clientPackage, userId); 1016 if (userId != mCurrentUserId) { 1017 final File systemDir = Environment.getUserSystemDirectory(userId); 1018 final File fpDir = new File(systemDir, FP_DATA_DIR); 1019 if (!fpDir.exists()) { 1020 if (!fpDir.mkdir()) { 1021 Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath()); 1022 return; 1023 } 1024 // Calling mkdir() from this process will create a directory with our 1025 // permissions (inherited from the containing dir). This command fixes 1026 // the label. 1027 if (!SELinux.restorecon(fpDir)) { 1028 Slog.w(TAG, "Restorecons failed. Directory will have wrong label."); 1029 return; 1030 } 1031 } 1032 daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes()); 1033 mCurrentUserId = userId; 1034 } 1035 mCurrentAuthenticatorId = daemon.getAuthenticatorId(); 1036 } catch (RemoteException e) { 1037 Slog.e(TAG, "Failed to setActiveGroup():", e); 1038 } 1039 } 1040 } 1041 1042 /** 1043 * @param clientPackage the package of the caller 1044 * @return the profile id 1045 */ getUserOrWorkProfileId(String clientPackage, int userId)1046 private int getUserOrWorkProfileId(String clientPackage, int userId) { 1047 if (!isKeyguard(clientPackage) && isWorkProfile(userId)) { 1048 return userId; 1049 } 1050 return getEffectiveUserId(userId); 1051 } 1052 1053 /** 1054 * @param userId 1055 * @return true if this is a work profile 1056 */ isWorkProfile(int userId)1057 private boolean isWorkProfile(int userId) { 1058 UserInfo info = mUserManager.getUserInfo(userId); 1059 return info != null && info.isManagedProfile(); 1060 } 1061 listenForUserSwitches()1062 private void listenForUserSwitches() { 1063 try { 1064 ActivityManagerNative.getDefault().registerUserSwitchObserver( 1065 new SynchronousUserSwitchObserver() { 1066 @Override 1067 public void onUserSwitching(int newUserId) throws RemoteException { 1068 mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */) 1069 .sendToTarget(); 1070 } 1071 @Override 1072 public void onUserSwitchComplete(int newUserId) throws RemoteException { 1073 // Ignore. 1074 } 1075 @Override 1076 public void onForegroundProfileSwitch(int newProfileId) { 1077 // Ignore. 1078 } 1079 }, TAG); 1080 } catch (RemoteException e) { 1081 Slog.w(TAG, "Failed to listen for user switching event" ,e); 1082 } 1083 } 1084 1085 /*** 1086 * @param opPackageName the name of the calling package 1087 * @return authenticator id for the current user 1088 */ getAuthenticatorId(String opPackageName)1089 public long getAuthenticatorId(String opPackageName) { 1090 return mCurrentAuthenticatorId; 1091 } 1092 1093 } 1094