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