FingerprintService.java revision 93d828de59986a990bfd2fffcfc399deae5ba6ba
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 userId, 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, userId, groupId, fingerId, restricted, token.toString()) { 368 @Override 369 public void notifyUserActivity() { 370 FingerprintService.this.userActivity(); 371 } 372 373 @Override 374 public IFingerprintDaemon getFingerprintDaemon() { 375 FingerprintService.this.getFingerprintDaemon(); 376 return null; 377 } 378 }; 379 startClient(client, true); 380 } 381 382 public List<Fingerprint> getEnrolledFingerprints(int userId) { 383 return mFingerprintUtils.getFingerprintsForUser(mContext, userId); 384 } 385 386 public boolean hasEnrolledFingerprints(int userId) { 387 if (userId != UserHandle.getCallingUserId()) { 388 checkPermission(INTERACT_ACROSS_USERS); 389 } 390 return mFingerprintUtils.getFingerprintsForUser(mContext, userId).size() > 0; 391 } 392 393 boolean hasPermission(String permission) { 394 return getContext().checkCallingOrSelfPermission(permission) 395 == PackageManager.PERMISSION_GRANTED; 396 } 397 398 void checkPermission(String permission) { 399 getContext().enforceCallingOrSelfPermission(permission, 400 "Must have " + permission + " permission."); 401 } 402 403 int getEffectiveUserId(int userId) { 404 UserManager um = UserManager.get(mContext); 405 if (um != null) { 406 final long callingIdentity = Binder.clearCallingIdentity(); 407 userId = um.getCredentialOwnerProfile(userId); 408 Binder.restoreCallingIdentity(callingIdentity); 409 } else { 410 Slog.e(TAG, "Unable to acquire UserManager"); 411 } 412 return userId; 413 } 414 415 boolean isCurrentUserOrProfile(int userId) { 416 UserManager um = UserManager.get(mContext); 417 418 // Allow current user or profiles of the current user... 419 for (int profileId : um.getEnabledProfileIds(userId)) { 420 if (profileId == userId) { 421 return true; 422 } 423 } 424 return false; 425 } 426 427 private boolean isForegroundActivity(int uid, int pid) { 428 try { 429 List<RunningAppProcessInfo> procs = 430 ActivityManagerNative.getDefault().getRunningAppProcesses(); 431 int N = procs.size(); 432 for (int i = 0; i < N; i++) { 433 RunningAppProcessInfo proc = procs.get(i); 434 if (proc.pid == pid && proc.uid == uid 435 && proc.importance == IMPORTANCE_FOREGROUND) { 436 return true; 437 } 438 } 439 } catch (RemoteException e) { 440 Slog.w(TAG, "am.getRunningAppProcesses() failed"); 441 } 442 return false; 443 } 444 445 /** 446 * @param opPackageName name of package for caller 447 * @param foregroundOnly only allow this call while app is in the foreground 448 * @return true if caller can use fingerprint API 449 */ 450 private boolean canUseFingerprint(String opPackageName, boolean foregroundOnly, int uid, 451 int pid) { 452 checkPermission(USE_FINGERPRINT); 453 if (isKeyguard(opPackageName)) { 454 return true; // Keyguard is always allowed 455 } 456 if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) { 457 Slog.w(TAG,"Rejecting " + opPackageName + " ; not a current user or profile"); 458 return false; 459 } 460 if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName) 461 != AppOpsManager.MODE_ALLOWED) { 462 Slog.w(TAG, "Rejecting " + opPackageName + " ; permission denied"); 463 return false; 464 } 465 if (foregroundOnly && !isForegroundActivity(uid, pid)) { 466 Slog.w(TAG, "Rejecting " + opPackageName + " ; not in foreground"); 467 return false; 468 } 469 return true; 470 } 471 472 /** 473 * @param clientPackage 474 * @return true if this is keyguard package 475 */ 476 private boolean isKeyguard(String clientPackage) { 477 return mKeyguardPackage.equals(clientPackage); 478 } 479 480 private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) { 481 if (!mLockoutMonitors.contains(monitor)) { 482 mLockoutMonitors.add(monitor); 483 } 484 } 485 486 private void removeLockoutResetCallback( 487 FingerprintServiceLockoutResetMonitor monitor) { 488 mLockoutMonitors.remove(monitor); 489 } 490 491 private void notifyLockoutResetMonitors() { 492 for (int i = 0; i < mLockoutMonitors.size(); i++) { 493 mLockoutMonitors.get(i).sendLockoutReset(); 494 } 495 } 496 497 private void startAuthentication(IBinder token, long opId, int realUserId, int groupId, 498 IFingerprintServiceReceiver receiver, int flags, boolean restricted, 499 String opPackageName) { 500 updateActiveGroup(groupId, opPackageName); 501 502 if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")"); 503 504 AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token, 505 receiver, realUserId, groupId, opId, restricted, opPackageName) { 506 @Override 507 public boolean handleFailedAttempt() { 508 mFailedAttempts++; 509 if (inLockoutMode()) { 510 // Failing multiple times will continue to push out the lockout time. 511 scheduleLockoutReset(); 512 return true; 513 } 514 return false; 515 } 516 517 @Override 518 public void resetFailedAttempts() { 519 FingerprintService.this.resetFailedAttempts(); 520 } 521 522 @Override 523 public void notifyUserActivity() { 524 FingerprintService.this.userActivity(); 525 } 526 527 @Override 528 public IFingerprintDaemon getFingerprintDaemon() { 529 return FingerprintService.this.getFingerprintDaemon(); 530 } 531 }; 532 533 if (inLockoutMode()) { 534 Slog.v(TAG, "In lockout mode; disallowing authentication"); 535 // Don't bother starting the client. Just send the error message. 536 if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) { 537 Slog.w(TAG, "Cannot send timeout message to client"); 538 } 539 return; 540 } 541 startClient(client, true /* initiatedByClient */); 542 } 543 544 private void startEnrollment(IBinder token, byte [] cryptoToken, int userId, int groupId, 545 IFingerprintServiceReceiver receiver, int flags, boolean restricted, 546 String opPackageName) { 547 updateActiveGroup(groupId, opPackageName); 548 549 EnrollClient client = new EnrollClient(getContext(), mHalDeviceId, token, receiver, 550 userId, groupId, cryptoToken, restricted, opPackageName) { 551 552 @Override 553 public IFingerprintDaemon getFingerprintDaemon() { 554 return FingerprintService.this.getFingerprintDaemon(); 555 } 556 557 @Override 558 public void notifyUserActivity() { 559 FingerprintService.this.userActivity(); 560 } 561 }; 562 startClient(client, true /* initiatedByClient */); 563 } 564 565 protected void resetFailedAttempts() { 566 if (DEBUG && inLockoutMode()) { 567 Slog.v(TAG, "Reset fingerprint lockout"); 568 } 569 mFailedAttempts = 0; 570 // If we're asked to reset failed attempts externally (i.e. from Keyguard), 571 // the alarm might still be pending; remove it. 572 cancelLockoutReset(); 573 notifyLockoutResetMonitors(); 574 } 575 576 private class FingerprintServiceLockoutResetMonitor { 577 578 private final IFingerprintServiceLockoutResetCallback mCallback; 579 580 public FingerprintServiceLockoutResetMonitor( 581 IFingerprintServiceLockoutResetCallback callback) { 582 mCallback = callback; 583 } 584 585 public void sendLockoutReset() { 586 if (mCallback != null) { 587 try { 588 mCallback.onLockoutReset(mHalDeviceId); 589 } catch (DeadObjectException e) { 590 Slog.w(TAG, "Death object while invoking onLockoutReset: ", e); 591 mHandler.post(mRemoveCallbackRunnable); 592 } catch (RemoteException e) { 593 Slog.w(TAG, "Failed to invoke onLockoutReset: ", e); 594 } 595 } 596 } 597 598 private final Runnable mRemoveCallbackRunnable = new Runnable() { 599 @Override 600 public void run() { 601 removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this); 602 } 603 }; 604 } 605 606 private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() { 607 608 @Override 609 public void onEnrollResult(final long deviceId, final int fingerId, final int groupId, 610 final int remaining) { 611 mHandler.post(new Runnable() { 612 @Override 613 public void run() { 614 handleEnrollResult(deviceId, fingerId, groupId, remaining); 615 } 616 }); 617 } 618 619 @Override 620 public void onAcquired(final long deviceId, final int acquiredInfo) { 621 mHandler.post(new Runnable() { 622 @Override 623 public void run() { 624 handleAcquired(deviceId, acquiredInfo); 625 } 626 }); 627 } 628 629 @Override 630 public void onAuthenticated(final long deviceId, final int fingerId, final int groupId) { 631 mHandler.post(new Runnable() { 632 @Override 633 public void run() { 634 handleAuthenticated(deviceId, fingerId, groupId); 635 } 636 }); 637 } 638 639 @Override 640 public void onError(final long deviceId, final int error) { 641 mHandler.post(new Runnable() { 642 @Override 643 public void run() { 644 handleError(deviceId, error); 645 } 646 }); 647 } 648 649 @Override 650 public void onRemoved(final long deviceId, final int fingerId, final int groupId) { 651 mHandler.post(new Runnable() { 652 @Override 653 public void run() { 654 handleRemoved(deviceId, fingerId, groupId); 655 } 656 }); 657 } 658 659 @Override 660 public void onEnumerate(final long deviceId, final int[] fingerIds, final int[] groupIds) { 661 mHandler.post(new Runnable() { 662 @Override 663 public void run() { 664 handleEnumerate(deviceId, fingerIds, groupIds); 665 } 666 }); 667 } 668 }; 669 670 private final class FingerprintServiceWrapper extends IFingerprintService.Stub { 671 @Override // Binder call 672 public long preEnroll(IBinder token) { 673 checkPermission(MANAGE_FINGERPRINT); 674 return startPreEnroll(token); 675 } 676 677 @Override // Binder call 678 public int postEnroll(IBinder token) { 679 checkPermission(MANAGE_FINGERPRINT); 680 return startPostEnroll(token); 681 } 682 683 @Override // Binder call 684 public void enroll(final IBinder token, final byte[] cryptoToken, final int groupId, 685 final IFingerprintServiceReceiver receiver, final int flags, 686 final String opPackageName) { 687 checkPermission(MANAGE_FINGERPRINT); 688 final int limit = mContext.getResources().getInteger( 689 com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser); 690 final int callingUid = Binder.getCallingUid(); 691 final int userId = UserHandle.getUserId(callingUid); 692 final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size(); 693 if (enrolled >= limit) { 694 Slog.w(TAG, "Too many fingerprints registered"); 695 return; 696 } 697 698 // Group ID is arbitrarily set to parent profile user ID. It just represents 699 // the default fingerprints for the user. 700 if (!isCurrentUserOrProfile(groupId)) { 701 return; 702 } 703 704 final boolean restricted = isRestricted(); 705 mHandler.post(new Runnable() { 706 @Override 707 public void run() { 708 startEnrollment(token, cryptoToken, userId, groupId, receiver, flags, 709 restricted, opPackageName); 710 } 711 }); 712 } 713 714 private boolean isRestricted() { 715 // Only give privileged apps (like Settings) access to fingerprint info 716 final boolean restricted = !hasPermission(MANAGE_FINGERPRINT); 717 return restricted; 718 } 719 720 @Override // Binder call 721 public void cancelEnrollment(final IBinder token) { 722 checkPermission(MANAGE_FINGERPRINT); 723 mHandler.post(new Runnable() { 724 @Override 725 public void run() { 726 ClientMonitor client = mCurrentClient; 727 if (client instanceof EnrollClient && client.getToken() == token) { 728 client.stop(client.getToken() == token); 729 } 730 } 731 }); 732 } 733 734 @Override // Binder call 735 public void authenticate(final IBinder token, final long opId, final int groupId, 736 final IFingerprintServiceReceiver receiver, final int flags, 737 final String opPackageName) { 738 final int realUserId = Binder.getCallingUid(); 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 realUserId, pid)) { 747 if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName); 748 return; 749 } 750 startAuthentication(token, opId, realUserId, 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 realUserId = Binder.getCallingUid(); 801 mHandler.post(new Runnable() { 802 @Override 803 public void run() { 804 startRemove(token, fingerId, realUserId, 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