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 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 195 public void binderDied() { 196 Slog.v(TAG, "fingerprintd died"); 197 mDaemon = null; 198 handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); 199 } 200 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 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 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 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 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 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 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 292 private void userActivity() { 293 long now = SystemClock.uptimeMillis(); 294 mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0); 295 } 296 297 void handleUserSwitching(int userId) { 298 updateActiveGroup(userId, null); 299 } 300 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 315 private boolean inLockoutMode() { 316 return mFailedAttempts >= MAX_FAILED_ATTEMPTS; 317 } 318 319 private void scheduleLockoutReset() { 320 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 321 SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS, getLockoutResetIntent()); 322 } 323 324 private void cancelLockoutReset() { 325 mAlarmManager.cancel(getLockoutResetIntent()); 326 } 327 328 private PendingIntent getLockoutResetIntent() { 329 return PendingIntent.getBroadcast(mContext, 0, 330 new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT); 331 } 332 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 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 */ 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 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 408 public List<Fingerprint> getEnrolledFingerprints(int userId) { 409 return mFingerprintUtils.getFingerprintsForUser(mContext, userId); 410 } 411 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 419 boolean hasPermission(String permission) { 420 return getContext().checkCallingOrSelfPermission(permission) 421 == PackageManager.PERMISSION_GRANTED; 422 } 423 424 void checkPermission(String permission) { 425 getContext().enforceCallingOrSelfPermission(permission, 426 "Must have " + permission + " permission."); 427 } 428 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 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 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 */ 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 */ 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 */ 510 private boolean isKeyguard(String clientPackage) { 511 return mKeyguardPackage.equals(clientPackage); 512 } 513 514 private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) { 515 if (!mLockoutMonitors.contains(monitor)) { 516 mLockoutMonitors.add(monitor); 517 } 518 } 519 520 private void removeLockoutResetCallback( 521 FingerprintServiceLockoutResetMonitor monitor) { 522 mLockoutMonitors.remove(monitor); 523 } 524 525 private void notifyLockoutResetMonitors() { 526 for (int i = 0; i < mLockoutMonitors.size(); i++) { 527 mLockoutMonitors.get(i).sendLockoutReset(); 528 } 529 } 530 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 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 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 619 public FingerprintServiceLockoutResetMonitor( 620 IFingerprintServiceLockoutResetCallback callback) { 621 mCallback = callback; 622 } 623 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 711 public long preEnroll(IBinder token) { 712 checkPermission(MANAGE_FINGERPRINT); 713 return startPreEnroll(token); 714 } 715 716 @Override // Binder call 717 public int postEnroll(IBinder token) { 718 checkPermission(MANAGE_FINGERPRINT); 719 return startPostEnroll(token); 720 } 721 722 @Override // Binder call 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 1057 private boolean isWorkProfile(int userId) { 1058 UserInfo info = mUserManager.getUserInfo(userId); 1059 return info != null && info.isManagedProfile(); 1060 } 1061 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 */ 1089 public long getAuthenticatorId(String opPackageName) { 1090 return mCurrentAuthenticatorId; 1091 } 1092 1093 } 1094