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.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 */ 84 public 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 = 3000; // 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 FingerprintService(Context context)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 binderDied()178 public void binderDied() { 179 Slog.v(TAG, "fingerprintd died"); 180 mDaemon = null; 181 handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); 182 } 183 getFingerprintDaemon()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 handleEnumerate(long deviceId, int[] fingerIds, int[] groupIds)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 handleError(long deviceId, int error)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 handleRemoved(long deviceId, int fingerId, int groupId)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 handleAuthenticated(long deviceId, int fingerId, int groupId)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 handleAcquired(long deviceId, int acquiredInfo)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 handleEnrollResult(long deviceId, int fingerId, int groupId, int remaining)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 userActivity()265 private void userActivity() { 266 long now = SystemClock.uptimeMillis(); 267 mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0); 268 } 269 handleUserSwitching(int userId)270 void handleUserSwitching(int userId) { 271 updateActiveGroup(userId, null); 272 } 273 removeClient(ClientMonitor client)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 inLockoutMode()288 private boolean inLockoutMode() { 289 return mFailedAttempts >= MAX_FAILED_ATTEMPTS; 290 } 291 scheduleLockoutReset()292 private void scheduleLockoutReset() { 293 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 294 SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS, getLockoutResetIntent()); 295 } 296 cancelLockoutReset()297 private void cancelLockoutReset() { 298 mAlarmManager.cancel(getLockoutResetIntent()); 299 } 300 getLockoutResetIntent()301 private PendingIntent getLockoutResetIntent() { 302 return PendingIntent.getBroadcast(mContext, 0, 303 new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT); 304 } 305 startPreEnroll(IBinder token)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 startPostEnroll(IBinder token)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 */ startClient(ClientMonitor newClient, boolean initiatedByClient)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 startRemove(IBinder token, int fingerId, int groupId, int userId, IFingerprintServiceReceiver receiver, boolean restricted)359 void startRemove(IBinder token, int fingerId, int groupId, int userId, 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, fingerId, groupId, userId, 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 getEnrolledFingerprints(int userId)381 public List<Fingerprint> getEnrolledFingerprints(int userId) { 382 return mFingerprintUtils.getFingerprintsForUser(mContext, userId); 383 } 384 hasEnrolledFingerprints(int userId)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 hasPermission(String permission)392 boolean hasPermission(String permission) { 393 return getContext().checkCallingOrSelfPermission(permission) 394 == PackageManager.PERMISSION_GRANTED; 395 } 396 checkPermission(String permission)397 void checkPermission(String permission) { 398 getContext().enforceCallingOrSelfPermission(permission, 399 "Must have " + permission + " permission."); 400 } 401 getEffectiveUserId(int userId)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 isCurrentUserOrProfile(int userId)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 isForegroundActivity(int uid, int pid)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 */ canUseFingerprint(String opPackageName, boolean foregroundOnly, int uid, int pid)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 */ isKeyguard(String clientPackage)475 private boolean isKeyguard(String clientPackage) { 476 return mKeyguardPackage.equals(clientPackage); 477 } 478 addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor)479 private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) { 480 if (!mLockoutMonitors.contains(monitor)) { 481 mLockoutMonitors.add(monitor); 482 } 483 } 484 removeLockoutResetCallback( FingerprintServiceLockoutResetMonitor monitor)485 private void removeLockoutResetCallback( 486 FingerprintServiceLockoutResetMonitor monitor) { 487 mLockoutMonitors.remove(monitor); 488 } 489 notifyLockoutResetMonitors()490 private void notifyLockoutResetMonitors() { 491 for (int i = 0; i < mLockoutMonitors.size(); i++) { 492 mLockoutMonitors.get(i).sendLockoutReset(); 493 } 494 } 495 startAuthentication(IBinder token, long opId, int callingUserId, int groupId, IFingerprintServiceReceiver receiver, int flags, boolean restricted, String opPackageName)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 startEnrollment(IBinder token, byte [] cryptoToken, int userId, IFingerprintServiceReceiver receiver, int flags, boolean restricted, String opPackageName)543 private void startEnrollment(IBinder token, byte [] cryptoToken, int userId, 544 IFingerprintServiceReceiver receiver, int flags, boolean restricted, 545 String opPackageName) { 546 updateActiveGroup(userId, opPackageName); 547 548 final int groupId = userId; // default group for fingerprint enrollment 549 550 EnrollClient client = new EnrollClient(getContext(), mHalDeviceId, token, receiver, 551 userId, groupId, cryptoToken, restricted, opPackageName) { 552 553 @Override 554 public IFingerprintDaemon getFingerprintDaemon() { 555 return FingerprintService.this.getFingerprintDaemon(); 556 } 557 558 @Override 559 public void notifyUserActivity() { 560 FingerprintService.this.userActivity(); 561 } 562 }; 563 startClient(client, true /* initiatedByClient */); 564 } 565 resetFailedAttempts()566 protected void resetFailedAttempts() { 567 if (DEBUG && inLockoutMode()) { 568 Slog.v(TAG, "Reset fingerprint lockout"); 569 } 570 mFailedAttempts = 0; 571 // If we're asked to reset failed attempts externally (i.e. from Keyguard), 572 // the alarm might still be pending; remove it. 573 cancelLockoutReset(); 574 notifyLockoutResetMonitors(); 575 } 576 577 private class FingerprintServiceLockoutResetMonitor { 578 579 private final IFingerprintServiceLockoutResetCallback mCallback; 580 FingerprintServiceLockoutResetMonitor( IFingerprintServiceLockoutResetCallback callback)581 public FingerprintServiceLockoutResetMonitor( 582 IFingerprintServiceLockoutResetCallback callback) { 583 mCallback = callback; 584 } 585 sendLockoutReset()586 public void sendLockoutReset() { 587 if (mCallback != null) { 588 try { 589 mCallback.onLockoutReset(mHalDeviceId); 590 } catch (DeadObjectException e) { 591 Slog.w(TAG, "Death object while invoking onLockoutReset: ", e); 592 mHandler.post(mRemoveCallbackRunnable); 593 } catch (RemoteException e) { 594 Slog.w(TAG, "Failed to invoke onLockoutReset: ", e); 595 } 596 } 597 } 598 599 private final Runnable mRemoveCallbackRunnable = new Runnable() { 600 @Override 601 public void run() { 602 removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this); 603 } 604 }; 605 } 606 607 private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() { 608 609 @Override 610 public void onEnrollResult(final long deviceId, final int fingerId, final int groupId, 611 final int remaining) { 612 mHandler.post(new Runnable() { 613 @Override 614 public void run() { 615 handleEnrollResult(deviceId, fingerId, groupId, remaining); 616 } 617 }); 618 } 619 620 @Override 621 public void onAcquired(final long deviceId, final int acquiredInfo) { 622 mHandler.post(new Runnable() { 623 @Override 624 public void run() { 625 handleAcquired(deviceId, acquiredInfo); 626 } 627 }); 628 } 629 630 @Override 631 public void onAuthenticated(final long deviceId, final int fingerId, final int groupId) { 632 mHandler.post(new Runnable() { 633 @Override 634 public void run() { 635 handleAuthenticated(deviceId, fingerId, groupId); 636 } 637 }); 638 } 639 640 @Override 641 public void onError(final long deviceId, final int error) { 642 mHandler.post(new Runnable() { 643 @Override 644 public void run() { 645 handleError(deviceId, error); 646 } 647 }); 648 } 649 650 @Override 651 public void onRemoved(final long deviceId, final int fingerId, final int groupId) { 652 mHandler.post(new Runnable() { 653 @Override 654 public void run() { 655 handleRemoved(deviceId, fingerId, groupId); 656 } 657 }); 658 } 659 660 @Override 661 public void onEnumerate(final long deviceId, final int[] fingerIds, final int[] groupIds) { 662 mHandler.post(new Runnable() { 663 @Override 664 public void run() { 665 handleEnumerate(deviceId, fingerIds, groupIds); 666 } 667 }); 668 } 669 }; 670 671 private final class FingerprintServiceWrapper extends IFingerprintService.Stub { 672 @Override // Binder call preEnroll(IBinder token)673 public long preEnroll(IBinder token) { 674 checkPermission(MANAGE_FINGERPRINT); 675 return startPreEnroll(token); 676 } 677 678 @Override // Binder call postEnroll(IBinder token)679 public int postEnroll(IBinder token) { 680 checkPermission(MANAGE_FINGERPRINT); 681 return startPostEnroll(token); 682 } 683 684 @Override // Binder call enroll(final IBinder token, final byte[] cryptoToken, final int userId, final IFingerprintServiceReceiver receiver, final int flags, final String opPackageName)685 public void enroll(final IBinder token, final byte[] cryptoToken, final int userId, 686 final IFingerprintServiceReceiver receiver, final int flags, 687 final String opPackageName) { 688 checkPermission(MANAGE_FINGERPRINT); 689 final int limit = mContext.getResources().getInteger( 690 com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser); 691 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(userId)) { 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, receiver, flags, 709 restricted, opPackageName); 710 } 711 }); 712 } 713 isRestricted()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 cancelEnrollment(final IBinder token)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 authenticate(final IBinder token, final long opId, final int groupId, final IFingerprintServiceReceiver receiver, final int flags, final String opPackageName)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 callingUid = Binder.getCallingUid(); 739 final int callingUserId = UserHandle.getCallingUserId(); 740 final int pid = Binder.getCallingPid(); 741 final boolean restricted = isRestricted(); 742 mHandler.post(new Runnable() { 743 @Override 744 public void run() { 745 MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0); 746 if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, 747 callingUid, pid)) { 748 if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName); 749 return; 750 } 751 startAuthentication(token, opId, callingUserId, groupId, receiver, 752 flags, restricted, opPackageName); 753 } 754 }); 755 } 756 757 @Override // Binder call cancelAuthentication(final IBinder token, final String opPackageName)758 public void cancelAuthentication(final IBinder token, final String opPackageName) { 759 final int uid = Binder.getCallingUid(); 760 final int pid = Binder.getCallingPid(); 761 mHandler.post(new Runnable() { 762 @Override 763 public void run() { 764 if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, uid, pid)) { 765 if (DEBUG) Slog.v(TAG, "cancelAuthentication(): reject " + opPackageName); 766 } else { 767 ClientMonitor client = mCurrentClient; 768 if (client instanceof AuthenticationClient) { 769 if (client.getToken() == token) { 770 if (DEBUG) Slog.v(TAG, "stop client " + client.getOwnerString()); 771 client.stop(client.getToken() == token); 772 } else { 773 if (DEBUG) Slog.v(TAG, "can't stop client " 774 + client.getOwnerString() + " since tokens don't match"); 775 } 776 } else if (client != null) { 777 if (DEBUG) Slog.v(TAG, "can't cancel non-authenticating client " 778 + client.getOwnerString()); 779 } 780 } 781 } 782 }); 783 } 784 785 @Override // Binder call setActiveUser(final int userId)786 public void setActiveUser(final int userId) { 787 checkPermission(MANAGE_FINGERPRINT); 788 mHandler.post(new Runnable() { 789 @Override 790 public void run() { 791 updateActiveGroup(userId, null); 792 } 793 }); 794 } 795 796 @Override // Binder call remove(final IBinder token, final int fingerId, final int groupId, final int userId, final IFingerprintServiceReceiver receiver)797 public void remove(final IBinder token, final int fingerId, final int groupId, 798 final int userId, final IFingerprintServiceReceiver receiver) { 799 checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission 800 final boolean restricted = isRestricted(); 801 mHandler.post(new Runnable() { 802 @Override 803 public void run() { 804 startRemove(token, fingerId, groupId, userId, receiver, restricted); 805 } 806 }); 807 808 } 809 810 @Override // Binder call isHardwareDetected(long deviceId, String opPackageName)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 rename(final int fingerId, final int groupId, final String name)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 getEnrolledFingerprints(int userId, String opPackageName)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 hasEnrolledFingerprints(int userId, String opPackageName)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 getAuthenticatorId(String opPackageName)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 dump(FileDescriptor fd, PrintWriter pw, String[] args)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 resetTimeout(byte [] token)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 addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback)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 dumpInternal(PrintWriter pw)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 onStart()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 updateActiveGroup(int userId, String clientPackage)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 } 972 mCurrentAuthenticatorId = daemon.getAuthenticatorId(); 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 */ getUserOrWorkProfileId(String clientPackage, int userId)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 */ isWorkProfile(int userId)994 private boolean isWorkProfile(int userId) { 995 UserInfo info = mUserManager.getUserInfo(userId); 996 return info != null && info.isManagedProfile(); 997 } 998 listenForUserSwitches()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 /*** 1023 * @param opPackageName the name of the calling package 1024 * @return authenticator id for the current user 1025 */ getAuthenticatorId(String opPackageName)1026 public long getAuthenticatorId(String opPackageName) { 1027 return mCurrentAuthenticatorId; 1028 } 1029 1030 } 1031