1 /* 2 * Copyright (C) 2018 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.biometrics.face; 18 19 import static android.Manifest.permission.INTERACT_ACROSS_USERS; 20 import static android.Manifest.permission.MANAGE_BIOMETRIC; 21 import static android.Manifest.permission.RESET_FACE_LOCKOUT; 22 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; 23 24 import android.app.ActivityManager; 25 import android.app.AppOpsManager; 26 import android.app.Notification; 27 import android.app.NotificationChannel; 28 import android.app.NotificationManager; 29 import android.app.PendingIntent; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.pm.UserInfo; 33 import android.hardware.biometrics.BiometricAuthenticator; 34 import android.hardware.biometrics.BiometricConstants; 35 import android.hardware.biometrics.BiometricsProtoEnums; 36 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; 37 import android.hardware.biometrics.IBiometricServiceReceiverInternal; 38 import android.hardware.biometrics.face.V1_0.IBiometricsFace; 39 import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback; 40 import android.hardware.biometrics.face.V1_0.OptionalBool; 41 import android.hardware.biometrics.face.V1_0.Status; 42 import android.hardware.face.Face; 43 import android.hardware.face.FaceManager; 44 import android.hardware.face.IFaceService; 45 import android.hardware.face.IFaceServiceReceiver; 46 import android.os.Binder; 47 import android.os.Build; 48 import android.os.Environment; 49 import android.os.IBinder; 50 import android.os.NativeHandle; 51 import android.os.RemoteException; 52 import android.os.SELinux; 53 import android.os.SystemProperties; 54 import android.os.UserHandle; 55 import android.os.UserManager; 56 import android.provider.Settings; 57 import android.util.Slog; 58 59 import com.android.internal.R; 60 import com.android.internal.annotations.GuardedBy; 61 import com.android.internal.logging.MetricsLogger; 62 import com.android.internal.util.DumpUtils; 63 import com.android.server.SystemServerInitThreadPool; 64 import com.android.server.biometrics.AuthenticationClient; 65 import com.android.server.biometrics.BiometricServiceBase; 66 import com.android.server.biometrics.BiometricUtils; 67 import com.android.server.biometrics.ClientMonitor; 68 import com.android.server.biometrics.Constants; 69 import com.android.server.biometrics.EnumerateClient; 70 import com.android.server.biometrics.RemovalClient; 71 72 import org.json.JSONArray; 73 import org.json.JSONException; 74 import org.json.JSONObject; 75 76 import java.io.File; 77 import java.io.FileDescriptor; 78 import java.io.FileOutputStream; 79 import java.io.IOException; 80 import java.io.PrintWriter; 81 import java.util.ArrayList; 82 import java.util.Arrays; 83 import java.util.HashMap; 84 import java.util.List; 85 import java.util.Map; 86 87 /** 88 * A service to manage multiple clients that want to access the face HAL API. 89 * The service is responsible for maintaining a list of clients and dispatching all 90 * face-related events. 91 * 92 * @hide 93 */ 94 public class FaceService extends BiometricServiceBase { 95 96 protected static final String TAG = "FaceService"; 97 private static final boolean DEBUG = true; 98 private static final String FACE_DATA_DIR = "facedata"; 99 private static final String ACTION_LOCKOUT_RESET = 100 "com.android.server.biometrics.face.ACTION_LOCKOUT_RESET"; 101 private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes 102 103 private static final String NOTIFICATION_TAG = "FaceService"; 104 private static final int NOTIFICATION_ID = 1; 105 106 /** 107 * Events for bugreports. 108 */ 109 public static final class AuthenticationEvent { 110 private long mStartTime; 111 private long mLatency; 112 // Only valid if mError is 0 113 private boolean mAuthenticated; 114 private int mError; 115 // Only valid if mError is ERROR_VENDOR 116 private int mVendorError; 117 AuthenticationEvent(long startTime, long latency, boolean authenticated, int error, int vendorError)118 AuthenticationEvent(long startTime, long latency, boolean authenticated, int error, 119 int vendorError) { 120 mStartTime = startTime; 121 mLatency = latency; 122 mAuthenticated = authenticated; 123 mError = error; 124 mVendorError = vendorError; 125 } 126 toString(Context context)127 public String toString(Context context) { 128 return "Start: " + mStartTime 129 + "\tLatency: " + mLatency 130 + "\tAuthenticated: " + mAuthenticated 131 + "\tError: " + mError 132 + "\tVendorCode: " + mVendorError 133 + "\t" + FaceManager.getErrorString(context, mError, mVendorError); 134 } 135 } 136 137 /** 138 * Keep a short historical buffer of stats, with an aggregated usage time. 139 */ 140 private class UsageStats { 141 static final int EVENT_LOG_SIZE = 100; 142 143 Context mContext; 144 List<AuthenticationEvent> mAuthenticationEvents; 145 146 int acceptCount; 147 int rejectCount; 148 Map<Integer, Integer> mErrorCount; 149 150 long acceptLatency; 151 long rejectLatency; 152 Map<Integer, Long> mErrorLatency; 153 UsageStats(Context context)154 UsageStats(Context context) { 155 mAuthenticationEvents = new ArrayList<>(); 156 mErrorCount = new HashMap<>(); 157 mErrorLatency = new HashMap<>(); 158 mContext = context; 159 } 160 addEvent(AuthenticationEvent event)161 void addEvent(AuthenticationEvent event) { 162 if (mAuthenticationEvents.size() >= EVENT_LOG_SIZE) { 163 mAuthenticationEvents.remove(0); 164 } 165 mAuthenticationEvents.add(event); 166 167 if (event.mAuthenticated) { 168 acceptCount++; 169 acceptLatency += event.mLatency; 170 } else if (event.mError == 0) { 171 rejectCount++; 172 rejectLatency += event.mLatency; 173 } else { 174 mErrorCount.put(event.mError, mErrorCount.getOrDefault(event.mError, 0) + 1); 175 mErrorLatency.put(event.mError, 176 mErrorLatency.getOrDefault(event.mError, 0l) + event.mLatency); 177 } 178 } 179 print(PrintWriter pw)180 void print(PrintWriter pw) { 181 pw.println("Events since last reboot: " + mAuthenticationEvents.size()); 182 for (int i = 0; i < mAuthenticationEvents.size(); i++) { 183 pw.println(mAuthenticationEvents.get(i).toString(mContext)); 184 } 185 186 // Dump aggregated usage stats 187 // TODO: Remove or combine with json dump in a future release 188 pw.println("Accept\tCount: " + acceptCount + "\tLatency: " + acceptLatency 189 + "\tAverage: " + (acceptCount > 0 ? acceptLatency / acceptCount : 0)); 190 pw.println("Reject\tCount: " + rejectCount + "\tLatency: " + rejectLatency 191 + "\tAverage: " + (rejectCount > 0 ? rejectLatency / rejectCount : 0)); 192 193 for (Integer key : mErrorCount.keySet()) { 194 final int count = mErrorCount.get(key); 195 pw.println("Error" + key + "\tCount: " + count 196 + "\tLatency: " + mErrorLatency.getOrDefault(key, 0l) 197 + "\tAverage: " + (count > 0 ? mErrorLatency.getOrDefault(key, 0l) / count 198 : 0) 199 + "\t" + FaceManager.getErrorString(mContext, key, 0 /* vendorCode */)); 200 } 201 } 202 } 203 204 private final class FaceAuthClient extends AuthenticationClientImpl { 205 private int mLastAcquire; 206 FaceAuthClient(Context context, DaemonWrapper daemon, long halDeviceId, IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId, boolean restricted, String owner, int cookie, boolean requireConfirmation)207 public FaceAuthClient(Context context, 208 DaemonWrapper daemon, long halDeviceId, IBinder token, 209 ServiceListener listener, int targetUserId, int groupId, long opId, 210 boolean restricted, String owner, int cookie, boolean requireConfirmation) { 211 super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId, 212 restricted, owner, cookie, requireConfirmation); 213 } 214 215 @Override statsModality()216 protected int statsModality() { 217 return FaceService.this.statsModality(); 218 } 219 220 @Override shouldFrameworkHandleLockout()221 public boolean shouldFrameworkHandleLockout() { 222 return false; 223 } 224 225 @Override wasUserDetected()226 public boolean wasUserDetected() { 227 return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED 228 && mLastAcquire != FaceManager.FACE_ACQUIRED_SENSOR_DIRTY; 229 } 230 231 @Override onAuthenticated(BiometricAuthenticator.Identifier identifier, boolean authenticated, ArrayList<Byte> token)232 public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier, 233 boolean authenticated, ArrayList<Byte> token) { 234 final boolean result = super.onAuthenticated(identifier, authenticated, token); 235 236 mUsageStats.addEvent(new AuthenticationEvent( 237 getStartTimeMs(), 238 System.currentTimeMillis() - getStartTimeMs() /* latency */, 239 authenticated, 240 0 /* error */, 241 0 /* vendorError */)); 242 243 // For face, the authentication lifecycle ends either when 244 // 1) Authenticated == true 245 // 2) Error occurred 246 // 3) Authenticated == false 247 // Fingerprint currently does not end when the third condition is met which is a bug, 248 // but let's leave it as-is for now. 249 return result || !authenticated; 250 } 251 252 @Override onError(long deviceId, int error, int vendorCode)253 public boolean onError(long deviceId, int error, int vendorCode) { 254 mUsageStats.addEvent(new AuthenticationEvent( 255 getStartTimeMs(), 256 System.currentTimeMillis() - getStartTimeMs() /* latency */, 257 false /* authenticated */, 258 error, 259 vendorCode)); 260 261 return super.onError(deviceId, error, vendorCode); 262 } 263 264 @Override getAcquireIgnorelist()265 public int[] getAcquireIgnorelist() { 266 if (isBiometricPrompt()) { 267 return mBiometricPromptIgnoreList; 268 } else { 269 // Keyguard 270 return mKeyguardIgnoreList; 271 } 272 } 273 274 @Override getAcquireVendorIgnorelist()275 public int[] getAcquireVendorIgnorelist() { 276 if (isBiometricPrompt()) { 277 return mBiometricPromptIgnoreListVendor; 278 } else { 279 // Keyguard 280 return mKeyguardIgnoreListVendor; 281 } 282 } 283 284 @Override onAcquired(int acquireInfo, int vendorCode)285 public boolean onAcquired(int acquireInfo, int vendorCode) { 286 287 mLastAcquire = acquireInfo; 288 289 if (acquireInfo == FaceManager.FACE_ACQUIRED_RECALIBRATE) { 290 final String name = 291 getContext().getString(R.string.face_recalibrate_notification_name); 292 final String title = 293 getContext().getString(R.string.face_recalibrate_notification_title); 294 final String content = 295 getContext().getString(R.string.face_recalibrate_notification_content); 296 297 final Intent intent = new Intent("android.settings.FACE_SETTINGS"); 298 intent.setPackage("com.android.settings"); 299 300 final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(getContext(), 301 0 /* requestCode */, intent, 0 /* flags */, null /* options */, 302 UserHandle.CURRENT); 303 304 final String channelName = "FaceEnrollNotificationChannel"; 305 306 NotificationChannel channel = new NotificationChannel(channelName, name, 307 NotificationManager.IMPORTANCE_HIGH); 308 Notification notification = new Notification.Builder(getContext(), channelName) 309 .setSmallIcon(R.drawable.ic_lock) 310 .setContentTitle(title) 311 .setContentText(content) 312 .setSubText(name) 313 .setOnlyAlertOnce(true) 314 .setLocalOnly(true) 315 .setAutoCancel(true) 316 .setCategory(Notification.CATEGORY_SYSTEM) 317 .setContentIntent(pendingIntent) 318 .setVisibility(Notification.VISIBILITY_SECRET) 319 .build(); 320 321 mNotificationManager.createNotificationChannel(channel); 322 mNotificationManager.notifyAsUser(NOTIFICATION_TAG, NOTIFICATION_ID, notification, 323 UserHandle.CURRENT); 324 } 325 326 return super.onAcquired(acquireInfo, vendorCode); 327 } 328 } 329 330 /** 331 * Receives the incoming binder calls from FaceManager. 332 */ 333 private final class FaceServiceWrapper extends IFaceService.Stub { 334 private static final int ENROLL_TIMEOUT_SEC = 75; 335 336 /** 337 * The following methods contain common code which is shared in biometrics/common. 338 */ 339 340 @Override // Binder call generateChallenge(IBinder token)341 public long generateChallenge(IBinder token) { 342 checkPermission(MANAGE_BIOMETRIC); 343 return startGenerateChallenge(token); 344 } 345 346 @Override // Binder call revokeChallenge(IBinder token)347 public int revokeChallenge(IBinder token) { 348 checkPermission(MANAGE_BIOMETRIC); 349 mHandler.post(() -> { 350 // TODO(b/137106905): Schedule binder calls in FaceService to avoid deadlocks. 351 if (getCurrentClient() == null) { 352 // if we aren't handling any other HIDL calls (mCurrentClient == null), revoke 353 // the challenge right away. 354 startRevokeChallenge(token); 355 } else { 356 // postpone revoking the challenge until we finish processing the current HIDL 357 // call. 358 mRevokeChallengePending = true; 359 } 360 }); 361 return Status.OK; 362 } 363 364 @Override // Binder call enroll(int userId, final IBinder token, final byte[] cryptoToken, final IFaceServiceReceiver receiver, final String opPackageName, final int[] disabledFeatures)365 public void enroll(int userId, final IBinder token, final byte[] cryptoToken, 366 final IFaceServiceReceiver receiver, final String opPackageName, 367 final int[] disabledFeatures) { 368 checkPermission(MANAGE_BIOMETRIC); 369 updateActiveGroup(userId, opPackageName); 370 371 mNotificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID, 372 UserHandle.CURRENT); 373 374 final boolean restricted = isRestricted(); 375 final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper, 376 mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, 377 0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures, 378 ENROLL_TIMEOUT_SEC) { 379 380 @Override 381 public int[] getAcquireIgnorelist() { 382 return mEnrollIgnoreList; 383 } 384 385 @Override 386 public int[] getAcquireVendorIgnorelist() { 387 return mEnrollIgnoreListVendor; 388 } 389 390 @Override 391 public boolean shouldVibrate() { 392 return false; 393 } 394 395 @Override 396 protected int statsModality() { 397 return FaceService.this.statsModality(); 398 } 399 }; 400 401 enrollInternal(client, mCurrentUserId); 402 } 403 404 @Override // Binder call cancelEnrollment(final IBinder token)405 public void cancelEnrollment(final IBinder token) { 406 checkPermission(MANAGE_BIOMETRIC); 407 cancelEnrollmentInternal(token); 408 } 409 410 @Override // Binder call authenticate(final IBinder token, final long opId, int userId, final IFaceServiceReceiver receiver, final int flags, final String opPackageName)411 public void authenticate(final IBinder token, final long opId, int userId, 412 final IFaceServiceReceiver receiver, final int flags, 413 final String opPackageName) { 414 checkPermission(USE_BIOMETRIC_INTERNAL); 415 updateActiveGroup(userId, opPackageName); 416 final boolean restricted = isRestricted(); 417 final AuthenticationClientImpl client = new FaceAuthClient(getContext(), 418 mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), 419 mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName, 420 0 /* cookie */, false /* requireConfirmation */); 421 authenticateInternal(client, opId, opPackageName); 422 } 423 424 @Override // Binder call prepareForAuthentication(boolean requireConfirmation, IBinder token, long opId, int groupId, IBiometricServiceReceiverInternal wrapperReceiver, String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId)425 public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long opId, 426 int groupId, IBiometricServiceReceiverInternal wrapperReceiver, 427 String opPackageName, int cookie, int callingUid, int callingPid, 428 int callingUserId) { 429 checkPermission(USE_BIOMETRIC_INTERNAL); 430 updateActiveGroup(groupId, opPackageName); 431 final boolean restricted = true; // BiometricPrompt is always restricted 432 final AuthenticationClientImpl client = new FaceAuthClient(getContext(), 433 mDaemonWrapper, mHalDeviceId, token, 434 new BiometricPromptServiceListenerImpl(wrapperReceiver), 435 mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName, cookie, 436 requireConfirmation); 437 authenticateInternal(client, opId, opPackageName, callingUid, callingPid, 438 callingUserId); 439 } 440 441 @Override // Binder call startPreparedClient(int cookie)442 public void startPreparedClient(int cookie) { 443 checkPermission(MANAGE_BIOMETRIC); 444 startCurrentClient(cookie); 445 } 446 447 @Override // Binder call cancelAuthentication(final IBinder token, final String opPackageName)448 public void cancelAuthentication(final IBinder token, final String opPackageName) { 449 checkPermission(USE_BIOMETRIC_INTERNAL); 450 cancelAuthenticationInternal(token, opPackageName); 451 } 452 453 @Override // Binder call cancelAuthenticationFromService(final IBinder token, final String opPackageName, int callingUid, int callingPid, int callingUserId, boolean fromClient)454 public void cancelAuthenticationFromService(final IBinder token, final String opPackageName, 455 int callingUid, int callingPid, int callingUserId, boolean fromClient) { 456 checkPermission(USE_BIOMETRIC_INTERNAL); 457 cancelAuthenticationInternal(token, opPackageName, callingUid, callingPid, 458 callingUserId, fromClient); 459 } 460 461 @Override // Binder call setActiveUser(final int userId)462 public void setActiveUser(final int userId) { 463 checkPermission(MANAGE_BIOMETRIC); 464 setActiveUserInternal(userId); 465 } 466 467 @Override // Binder call remove(final IBinder token, final int faceId, final int userId, final IFaceServiceReceiver receiver, final String opPackageName)468 public void remove(final IBinder token, final int faceId, final int userId, 469 final IFaceServiceReceiver receiver, final String opPackageName) { 470 checkPermission(MANAGE_BIOMETRIC); 471 updateActiveGroup(userId, opPackageName); 472 473 if (token == null) { 474 Slog.w(TAG, "remove(): token is null"); 475 return; 476 } 477 478 final boolean restricted = isRestricted(); 479 final RemovalClient client = new RemovalClient(getContext(), getConstants(), 480 mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), faceId, 481 0 /* groupId */, userId, restricted, token.toString(), getBiometricUtils()) { 482 @Override 483 protected int statsModality() { 484 return FaceService.this.statsModality(); 485 } 486 }; 487 removeInternal(client); 488 } 489 490 @Override enumerate(final IBinder token, final int userId, final IFaceServiceReceiver receiver)491 public void enumerate(final IBinder token, final int userId, 492 final IFaceServiceReceiver receiver) { 493 checkPermission(MANAGE_BIOMETRIC); 494 495 final boolean restricted = isRestricted(); 496 final EnumerateClient client = new EnumerateClient(getContext(), getConstants(), 497 mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), userId, 498 userId, restricted, getContext().getOpPackageName()) { 499 @Override 500 protected int statsModality() { 501 return FaceService.this.statsModality(); 502 } 503 }; 504 enumerateInternal(client); 505 } 506 507 @Override addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback)508 public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback) 509 throws RemoteException { 510 checkPermission(USE_BIOMETRIC_INTERNAL); 511 FaceService.super.addLockoutResetCallback(callback); 512 } 513 514 @Override // Binder call dump(FileDescriptor fd, PrintWriter pw, String[] args)515 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 516 if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) { 517 return; 518 } 519 520 final long ident = Binder.clearCallingIdentity(); 521 try { 522 if (args.length > 1 && "--hal".equals(args[0])) { 523 dumpHal(fd, Arrays.copyOfRange(args, 1, args.length, args.getClass())); 524 } else { 525 dumpInternal(pw); 526 } 527 } finally { 528 Binder.restoreCallingIdentity(ident); 529 } 530 } 531 532 /** 533 * The following methods don't use any common code from BiometricService 534 */ 535 536 // TODO: refactor out common code here 537 @Override // Binder call isHardwareDetected(long deviceId, String opPackageName)538 public boolean isHardwareDetected(long deviceId, String opPackageName) { 539 checkPermission(USE_BIOMETRIC_INTERNAL); 540 if (!canUseBiometric(opPackageName, false /* foregroundOnly */, 541 Binder.getCallingUid(), Binder.getCallingPid(), 542 UserHandle.getCallingUserId())) { 543 return false; 544 } 545 546 final long token = Binder.clearCallingIdentity(); 547 try { 548 IBiometricsFace daemon = getFaceDaemon(); 549 return daemon != null && mHalDeviceId != 0; 550 } finally { 551 Binder.restoreCallingIdentity(token); 552 } 553 } 554 555 @Override // Binder call rename(final int faceId, final String name)556 public void rename(final int faceId, final String name) { 557 checkPermission(MANAGE_BIOMETRIC); 558 if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) { 559 return; 560 } 561 mHandler.post(new Runnable() { 562 @Override 563 public void run() { 564 getBiometricUtils().renameBiometricForUser(getContext(), mCurrentUserId, 565 faceId, name); 566 } 567 }); 568 } 569 570 @Override // Binder call getEnrolledFaces(int userId, String opPackageName)571 public List<Face> getEnrolledFaces(int userId, String opPackageName) { 572 checkPermission(MANAGE_BIOMETRIC); 573 if (!canUseBiometric(opPackageName, false /* foregroundOnly */, 574 Binder.getCallingUid(), Binder.getCallingPid(), 575 UserHandle.getCallingUserId())) { 576 return null; 577 } 578 579 return FaceService.this.getEnrolledTemplates(userId); 580 } 581 582 @Override // Binder call hasEnrolledFaces(int userId, String opPackageName)583 public boolean hasEnrolledFaces(int userId, String opPackageName) { 584 checkPermission(USE_BIOMETRIC_INTERNAL); 585 if (!canUseBiometric(opPackageName, false /* foregroundOnly */, 586 Binder.getCallingUid(), Binder.getCallingPid(), 587 UserHandle.getCallingUserId())) { 588 return false; 589 } 590 591 return FaceService.this.hasEnrolledBiometrics(userId); 592 } 593 594 @Override // Binder call getAuthenticatorId(String opPackageName)595 public long getAuthenticatorId(String opPackageName) { 596 // In this method, we're not checking whether the caller is permitted to use face 597 // API because current authenticator ID is leaked (in a more contrived way) via Android 598 // Keystore (android.security.keystore package): the user of that API can create a key 599 // which requires face authentication for its use, and then query the key's 600 // characteristics (hidden API) which returns, among other things, face 601 // authenticator ID which was active at key creation time. 602 // 603 // Reason: The part of Android Keystore which runs inside an app's process invokes this 604 // method in certain cases. Those cases are not always where the developer demonstrates 605 // explicit intent to use face functionality. Thus, to avoiding throwing an 606 // unexpected SecurityException this method does not check whether its caller is 607 // permitted to use face API. 608 // 609 // The permission check should be restored once Android Keystore no longer invokes this 610 // method from inside app processes. 611 612 return FaceService.this.getAuthenticatorId(opPackageName); 613 } 614 615 @Override // Binder call resetLockout(byte[] token)616 public void resetLockout(byte[] token) { 617 checkPermission(MANAGE_BIOMETRIC); 618 619 mHandler.post(() -> { 620 if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) { 621 Slog.w(TAG, "Ignoring lockout reset, no templates enrolled"); 622 return; 623 } 624 625 Slog.d(TAG, "Resetting lockout for user: " + mCurrentUserId); 626 627 try { 628 mDaemonWrapper.resetLockout(token); 629 } catch (RemoteException e) { 630 Slog.e(getTag(), "Unable to reset lockout", e); 631 } 632 }); 633 } 634 635 @Override setFeature(int userId, int feature, boolean enabled, final byte[] token, IFaceServiceReceiver receiver, final String opPackageName)636 public void setFeature(int userId, int feature, boolean enabled, final byte[] token, 637 IFaceServiceReceiver receiver, final String opPackageName) { 638 checkPermission(MANAGE_BIOMETRIC); 639 640 mHandler.post(() -> { 641 if (DEBUG) { 642 Slog.d(TAG, "setFeature for user(" + userId + ")"); 643 } 644 updateActiveGroup(userId, opPackageName); 645 if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) { 646 Slog.e(TAG, "No enrolled biometrics while setting feature: " + feature); 647 return; 648 } 649 650 final ArrayList<Byte> byteToken = new ArrayList<>(); 651 for (int i = 0; i < token.length; i++) { 652 byteToken.add(token[i]); 653 } 654 655 // TODO: Support multiple faces 656 final int faceId = getFirstTemplateForUser(mCurrentUserId); 657 658 if (mDaemon != null) { 659 try { 660 final int result = mDaemon.setFeature(feature, enabled, byteToken, faceId); 661 receiver.onFeatureSet(result == Status.OK, feature); 662 } catch (RemoteException e) { 663 Slog.e(getTag(), "Unable to set feature: " + feature 664 + " to enabled:" + enabled, e); 665 } 666 } 667 }); 668 669 } 670 671 @Override getFeature(int userId, int feature, IFaceServiceReceiver receiver, final String opPackageName)672 public void getFeature(int userId, int feature, IFaceServiceReceiver receiver, 673 final String opPackageName) { 674 checkPermission(MANAGE_BIOMETRIC); 675 676 mHandler.post(() -> { 677 if (DEBUG) { 678 Slog.d(TAG, "getFeature for user(" + userId + ")"); 679 } 680 updateActiveGroup(userId, opPackageName); 681 // This should ideally return tri-state, but the user isn't shown settings unless 682 // they are enrolled so it's fine for now. 683 if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) { 684 Slog.e(TAG, "No enrolled biometrics while getting feature: " + feature); 685 return; 686 } 687 688 // TODO: Support multiple faces 689 final int faceId = getFirstTemplateForUser(mCurrentUserId); 690 691 if (mDaemon != null) { 692 try { 693 OptionalBool result = mDaemon.getFeature(feature, faceId); 694 receiver.onFeatureGet(result.status == Status.OK, feature, result.value); 695 } catch (RemoteException e) { 696 Slog.e(getTag(), "Unable to getRequireAttention", e); 697 } 698 } 699 }); 700 701 } 702 703 @Override userActivity()704 public void userActivity() { 705 checkPermission(MANAGE_BIOMETRIC); 706 707 if (mDaemon != null) { 708 try { 709 mDaemon.userActivity(); 710 } catch (RemoteException e) { 711 Slog.e(getTag(), "Unable to send userActivity", e); 712 } 713 } 714 } 715 716 // TODO: Support multiple faces getFirstTemplateForUser(int user)717 private int getFirstTemplateForUser(int user) { 718 final List<Face> faces = FaceService.this.getEnrolledTemplates(user); 719 if (!faces.isEmpty()) { 720 return faces.get(0).getBiometricId(); 721 } 722 return 0; 723 } 724 } 725 726 /** 727 * Receives callbacks from the ClientMonitor implementations. The results are forwarded to 728 * BiometricPrompt. 729 */ 730 private class BiometricPromptServiceListenerImpl extends BiometricServiceListener { BiometricPromptServiceListenerImpl(IBiometricServiceReceiverInternal wrapperReceiver)731 BiometricPromptServiceListenerImpl(IBiometricServiceReceiverInternal wrapperReceiver) { 732 super(wrapperReceiver); 733 } 734 735 @Override onAcquired(long deviceId, int acquiredInfo, int vendorCode)736 public void onAcquired(long deviceId, int acquiredInfo, int vendorCode) 737 throws RemoteException { 738 /** 739 * Map the acquired codes onto existing {@link BiometricConstants} acquired codes. 740 */ 741 if (getWrapperReceiver() != null) { 742 getWrapperReceiver().onAcquired( 743 FaceManager.getMappedAcquiredInfo(acquiredInfo, vendorCode), 744 FaceManager.getAcquiredString(getContext(), acquiredInfo, vendorCode)); 745 } 746 } 747 748 @Override onError(long deviceId, int error, int vendorCode, int cookie)749 public void onError(long deviceId, int error, int vendorCode, int cookie) 750 throws RemoteException { 751 if (getWrapperReceiver() != null) { 752 getWrapperReceiver().onError(cookie, error, 753 FaceManager.getErrorString(getContext(), error, vendorCode)); 754 } 755 } 756 } 757 758 /** 759 * Receives callbacks from the ClientMonitor implementations. The results are forwarded to 760 * the FaceManager. 761 */ 762 private class ServiceListenerImpl implements ServiceListener { 763 private IFaceServiceReceiver mFaceServiceReceiver; 764 ServiceListenerImpl(IFaceServiceReceiver receiver)765 public ServiceListenerImpl(IFaceServiceReceiver receiver) { 766 mFaceServiceReceiver = receiver; 767 } 768 769 @Override onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining)770 public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) 771 throws RemoteException { 772 if (mFaceServiceReceiver != null) { 773 mFaceServiceReceiver.onEnrollResult(identifier.getDeviceId(), 774 identifier.getBiometricId(), 775 remaining); 776 } 777 } 778 779 @Override onAcquired(long deviceId, int acquiredInfo, int vendorCode)780 public void onAcquired(long deviceId, int acquiredInfo, int vendorCode) 781 throws RemoteException { 782 if (mFaceServiceReceiver != null) { 783 mFaceServiceReceiver.onAcquired(deviceId, acquiredInfo, vendorCode); 784 } 785 } 786 787 @Override onAuthenticationSucceeded(long deviceId, BiometricAuthenticator.Identifier biometric, int userId)788 public void onAuthenticationSucceeded(long deviceId, 789 BiometricAuthenticator.Identifier biometric, int userId) 790 throws RemoteException { 791 if (mFaceServiceReceiver != null) { 792 if (biometric == null || biometric instanceof Face) { 793 mFaceServiceReceiver.onAuthenticationSucceeded(deviceId, (Face) biometric, 794 userId); 795 } else { 796 Slog.e(TAG, "onAuthenticationSucceeded received non-face biometric"); 797 } 798 } 799 } 800 801 @Override onAuthenticationFailed(long deviceId)802 public void onAuthenticationFailed(long deviceId) throws RemoteException { 803 if (mFaceServiceReceiver != null) { 804 mFaceServiceReceiver.onAuthenticationFailed(deviceId); 805 } 806 } 807 808 @Override onError(long deviceId, int error, int vendorCode, int cookie)809 public void onError(long deviceId, int error, int vendorCode, int cookie) 810 throws RemoteException { 811 if (mFaceServiceReceiver != null) { 812 mFaceServiceReceiver.onError(deviceId, error, vendorCode); 813 } 814 } 815 816 @Override onRemoved(BiometricAuthenticator.Identifier identifier, int remaining)817 public void onRemoved(BiometricAuthenticator.Identifier identifier, 818 int remaining) throws RemoteException { 819 if (mFaceServiceReceiver != null) { 820 mFaceServiceReceiver.onRemoved(identifier.getDeviceId(), 821 identifier.getBiometricId(), remaining); 822 } 823 } 824 825 @Override onEnumerated(BiometricAuthenticator.Identifier identifier, int remaining)826 public void onEnumerated(BiometricAuthenticator.Identifier identifier, int remaining) 827 throws RemoteException { 828 if (mFaceServiceReceiver != null) { 829 mFaceServiceReceiver.onEnumerated(identifier.getDeviceId(), 830 identifier.getBiometricId(), remaining); 831 } 832 } 833 } 834 835 private final FaceConstants mFaceConstants = new FaceConstants(); 836 837 @GuardedBy("this") 838 private IBiometricsFace mDaemon; 839 private UsageStats mUsageStats; 840 private boolean mRevokeChallengePending = false; 841 // One of the AuthenticationClient constants 842 private int mCurrentUserLockoutMode; 843 844 private NotificationManager mNotificationManager; 845 846 private int[] mBiometricPromptIgnoreList; 847 private int[] mBiometricPromptIgnoreListVendor; 848 private int[] mKeyguardIgnoreList; 849 private int[] mKeyguardIgnoreListVendor; 850 private int[] mEnrollIgnoreList; 851 private int[] mEnrollIgnoreListVendor; 852 853 /** 854 * Receives callbacks from the HAL. 855 */ 856 private IBiometricsFaceClientCallback mDaemonCallback = 857 new IBiometricsFaceClientCallback.Stub() { 858 @Override 859 public void onEnrollResult(final long deviceId, int faceId, int userId, 860 int remaining) { 861 mHandler.post(() -> { 862 final Face face = new Face(getBiometricUtils() 863 .getUniqueName(getContext(), userId), faceId, deviceId); 864 FaceService.super.handleEnrollResult(face, remaining); 865 866 // Enrollment changes the authenticatorId, so update it here. 867 IBiometricsFace daemon = getFaceDaemon(); 868 if (remaining == 0 && daemon != null) { 869 try { 870 mAuthenticatorIds.put(userId, 871 hasEnrolledBiometrics(userId) ? daemon.getAuthenticatorId().value 872 : 0L); 873 } catch (RemoteException e) { 874 Slog.e(TAG, "Unable to get authenticatorId", e); 875 } 876 } 877 }); 878 } 879 880 @Override 881 public void onAcquired(final long deviceId, final int userId, 882 final int acquiredInfo, 883 final int vendorCode) { 884 mHandler.post(() -> { 885 FaceService.super.handleAcquired(deviceId, acquiredInfo, vendorCode); 886 }); 887 } 888 889 @Override 890 public void onAuthenticated(final long deviceId, final int faceId, final int userId, 891 ArrayList<Byte> token) { 892 mHandler.post(() -> { 893 Face face = new Face("", faceId, deviceId); 894 FaceService.super.handleAuthenticated(face, token); 895 }); 896 } 897 898 @Override 899 public void onError(final long deviceId, final int userId, final int error, 900 final int vendorCode) { 901 mHandler.post(() -> { 902 FaceService.super.handleError(deviceId, error, vendorCode); 903 904 // TODO: this chunk of code should be common to all biometric services 905 if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) { 906 // If we get HW_UNAVAILABLE, try to connect again later... 907 Slog.w(TAG, "Got ERROR_HW_UNAVAILABLE; try reconnecting next client."); 908 synchronized (this) { 909 mDaemon = null; 910 mHalDeviceId = 0; 911 mCurrentUserId = UserHandle.USER_NULL; 912 } 913 } 914 }); 915 } 916 917 @Override 918 public void onRemoved(final long deviceId, ArrayList<Integer> faceIds, final int userId) { 919 mHandler.post(() -> { 920 if (!faceIds.isEmpty()) { 921 for (int i = 0; i < faceIds.size(); i++) { 922 final Face face = new Face("", faceIds.get(i), deviceId); 923 // Convert to old behavior 924 FaceService.super.handleRemoved(face, faceIds.size() - i - 1); 925 } 926 } else { 927 final Face face = new Face("", 0 /* identifier */, deviceId); 928 FaceService.super.handleRemoved(face, 0 /* remaining */); 929 } 930 Settings.Secure.putIntForUser(getContext().getContentResolver(), 931 Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT); 932 }); 933 } 934 935 @Override 936 public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId) 937 throws RemoteException { 938 mHandler.post(() -> { 939 if (!faceIds.isEmpty()) { 940 for (int i = 0; i < faceIds.size(); i++) { 941 final Face face = new Face("", faceIds.get(i), deviceId); 942 // Convert to old old behavior 943 FaceService.super.handleEnumerate(face, faceIds.size() - i - 1); 944 } 945 } else { 946 // For face, the HIDL contract is to receive an empty list when there are no 947 // templates enrolled. Send a null identifier since we don't consume them 948 // anywhere, and send remaining == 0 to plumb this with existing common code. 949 FaceService.super.handleEnumerate(null /* identifier */, 0); 950 } 951 }); 952 } 953 954 @Override 955 public void onLockoutChanged(long duration) { 956 Slog.d(TAG, "onLockoutChanged: " + duration); 957 if (duration == 0) { 958 mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_NONE; 959 } else if (duration == Long.MAX_VALUE) { 960 mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_PERMANENT; 961 } else { 962 mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_TIMED; 963 } 964 965 mHandler.post(() -> { 966 if (duration == 0) { 967 notifyLockoutResetMonitors(); 968 } 969 }); 970 } 971 }; 972 973 /** 974 * Wraps the HAL-specific code and is passed to the ClientMonitor implementations so that they 975 * can be shared between the multiple biometric services. 976 */ 977 private final DaemonWrapper mDaemonWrapper = new DaemonWrapper() { 978 @Override 979 public int authenticate(long operationId, int groupId) throws RemoteException { 980 IBiometricsFace daemon = getFaceDaemon(); 981 if (daemon == null) { 982 Slog.w(TAG, "authenticate(): no face HAL!"); 983 return ERROR_ESRCH; 984 } 985 return daemon.authenticate(operationId); 986 } 987 988 @Override 989 public int cancel() throws RemoteException { 990 IBiometricsFace daemon = getFaceDaemon(); 991 if (daemon == null) { 992 Slog.w(TAG, "cancel(): no face HAL!"); 993 return ERROR_ESRCH; 994 } 995 return daemon.cancel(); 996 } 997 998 @Override 999 public int remove(int groupId, int biometricId) throws RemoteException { 1000 IBiometricsFace daemon = getFaceDaemon(); 1001 if (daemon == null) { 1002 Slog.w(TAG, "remove(): no face HAL!"); 1003 return ERROR_ESRCH; 1004 } 1005 return daemon.remove(biometricId); 1006 } 1007 1008 @Override 1009 public int enumerate() throws RemoteException { 1010 IBiometricsFace daemon = getFaceDaemon(); 1011 if (daemon == null) { 1012 Slog.w(TAG, "enumerate(): no face HAL!"); 1013 return ERROR_ESRCH; 1014 } 1015 return daemon.enumerate(); 1016 } 1017 1018 @Override 1019 public int enroll(byte[] cryptoToken, int groupId, int timeout, 1020 ArrayList<Integer> disabledFeatures) throws RemoteException { 1021 IBiometricsFace daemon = getFaceDaemon(); 1022 if (daemon == null) { 1023 Slog.w(TAG, "enroll(): no face HAL!"); 1024 return ERROR_ESRCH; 1025 } 1026 final ArrayList<Byte> token = new ArrayList<>(); 1027 for (int i = 0; i < cryptoToken.length; i++) { 1028 token.add(cryptoToken[i]); 1029 } 1030 return daemon.enroll(token, timeout, disabledFeatures); 1031 } 1032 1033 @Override 1034 public void resetLockout(byte[] cryptoToken) throws RemoteException { 1035 IBiometricsFace daemon = getFaceDaemon(); 1036 if (daemon == null) { 1037 Slog.w(TAG, "resetLockout(): no face HAL!"); 1038 return; 1039 } 1040 final ArrayList<Byte> token = new ArrayList<>(); 1041 for (int i = 0; i < cryptoToken.length; i++) { 1042 token.add(cryptoToken[i]); 1043 } 1044 daemon.resetLockout(token); 1045 } 1046 }; 1047 1048 FaceService(Context context)1049 public FaceService(Context context) { 1050 super(context); 1051 1052 mUsageStats = new UsageStats(context); 1053 1054 mNotificationManager = getContext().getSystemService(NotificationManager.class); 1055 1056 mBiometricPromptIgnoreList = getContext().getResources() 1057 .getIntArray(R.array.config_face_acquire_biometricprompt_ignorelist); 1058 mBiometricPromptIgnoreListVendor = getContext().getResources() 1059 .getIntArray(R.array.config_face_acquire_vendor_biometricprompt_ignorelist); 1060 mKeyguardIgnoreList = getContext().getResources() 1061 .getIntArray(R.array.config_face_acquire_keyguard_ignorelist); 1062 mKeyguardIgnoreListVendor = getContext().getResources() 1063 .getIntArray(R.array.config_face_acquire_vendor_keyguard_ignorelist); 1064 mEnrollIgnoreList = getContext().getResources() 1065 .getIntArray(R.array.config_face_acquire_enroll_ignorelist); 1066 mEnrollIgnoreListVendor = getContext().getResources() 1067 .getIntArray(R.array.config_face_acquire_vendor_enroll_ignorelist); 1068 } 1069 1070 @Override removeClient(ClientMonitor client)1071 protected void removeClient(ClientMonitor client) { 1072 super.removeClient(client); 1073 if (mRevokeChallengePending) { 1074 startRevokeChallenge(null); 1075 mRevokeChallengePending = false; 1076 } 1077 } 1078 1079 @Override onStart()1080 public void onStart() { 1081 super.onStart(); 1082 publishBinderService(Context.FACE_SERVICE, new FaceServiceWrapper()); 1083 // Get the face daemon on FaceService's on thread so SystemServerInitThreadPool isn't 1084 // blocked 1085 SystemServerInitThreadPool.get().submit(() -> mHandler.post(this::getFaceDaemon), 1086 TAG + ".onStart"); 1087 } 1088 1089 @Override getTag()1090 public String getTag() { 1091 return TAG; 1092 } 1093 1094 @Override getDaemonWrapper()1095 protected DaemonWrapper getDaemonWrapper() { 1096 return mDaemonWrapper; 1097 } 1098 1099 @Override getBiometricUtils()1100 protected BiometricUtils getBiometricUtils() { 1101 return FaceUtils.getInstance(); 1102 } 1103 1104 @Override getConstants()1105 protected Constants getConstants() { 1106 return mFaceConstants; 1107 } 1108 1109 @Override hasReachedEnrollmentLimit(int userId)1110 protected boolean hasReachedEnrollmentLimit(int userId) { 1111 final int limit = getContext().getResources().getInteger( 1112 com.android.internal.R.integer.config_faceMaxTemplatesPerUser); 1113 final int enrolled = FaceService.this.getEnrolledTemplates(userId).size(); 1114 if (enrolled >= limit) { 1115 Slog.w(TAG, "Too many faces registered, user: " + userId); 1116 return true; 1117 } 1118 return false; 1119 } 1120 1121 @Override serviceDied(long cookie)1122 public void serviceDied(long cookie) { 1123 super.serviceDied(cookie); 1124 mDaemon = null; 1125 1126 mCurrentUserId = UserHandle.USER_NULL; // Force updateActiveGroup() to re-evaluate 1127 } 1128 1129 @Override updateActiveGroup(int userId, String clientPackage)1130 protected void updateActiveGroup(int userId, String clientPackage) { 1131 IBiometricsFace daemon = getFaceDaemon(); 1132 1133 if (daemon != null) { 1134 try { 1135 userId = getUserOrWorkProfileId(clientPackage, userId); 1136 if (userId != mCurrentUserId) { 1137 final File baseDir = Environment.getDataVendorDeDirectory(userId); 1138 final File faceDir = new File(baseDir, FACE_DATA_DIR); 1139 if (!faceDir.exists()) { 1140 if (!faceDir.mkdir()) { 1141 Slog.v(TAG, "Cannot make directory: " + faceDir.getAbsolutePath()); 1142 return; 1143 } 1144 // Calling mkdir() from this process will create a directory with our 1145 // permissions (inherited from the containing dir). This command fixes 1146 // the label. 1147 if (!SELinux.restorecon(faceDir)) { 1148 Slog.w(TAG, "Restorecons failed. Directory will have wrong label."); 1149 return; 1150 } 1151 } 1152 1153 daemon.setActiveUser(userId, faceDir.getAbsolutePath()); 1154 mCurrentUserId = userId; 1155 mAuthenticatorIds.put(userId, 1156 hasEnrolledBiometrics(userId) ? daemon.getAuthenticatorId().value : 0L); 1157 } 1158 } catch (RemoteException e) { 1159 Slog.e(TAG, "Failed to setActiveUser():", e); 1160 } 1161 } 1162 } 1163 1164 @Override getLockoutResetIntent()1165 protected String getLockoutResetIntent() { 1166 return ACTION_LOCKOUT_RESET; 1167 } 1168 1169 @Override getLockoutBroadcastPermission()1170 protected String getLockoutBroadcastPermission() { 1171 return RESET_FACE_LOCKOUT; 1172 } 1173 1174 @Override getHalDeviceId()1175 protected long getHalDeviceId() { 1176 return mHalDeviceId; 1177 } 1178 1179 @Override handleUserSwitching(int userId)1180 protected void handleUserSwitching(int userId) { 1181 super.handleUserSwitching(userId); 1182 // Will be updated when we get the callback from HAL 1183 mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_NONE; 1184 } 1185 1186 @Override hasEnrolledBiometrics(int userId)1187 protected boolean hasEnrolledBiometrics(int userId) { 1188 if (userId != UserHandle.getCallingUserId()) { 1189 checkPermission(INTERACT_ACROSS_USERS); 1190 } 1191 return getBiometricUtils().getBiometricsForUser(getContext(), userId).size() > 0; 1192 } 1193 1194 @Override getManageBiometricPermission()1195 protected String getManageBiometricPermission() { 1196 return MANAGE_BIOMETRIC; 1197 } 1198 1199 @Override checkUseBiometricPermission()1200 protected void checkUseBiometricPermission() { 1201 // noop for Face. The permission checks are all done on the incoming binder call. 1202 } 1203 1204 @Override checkAppOps(int uid, String opPackageName)1205 protected boolean checkAppOps(int uid, String opPackageName) { 1206 return mAppOps.noteOp(AppOpsManager.OP_USE_BIOMETRIC, uid, opPackageName) 1207 == AppOpsManager.MODE_ALLOWED; 1208 } 1209 1210 @Override getEnrolledTemplates(int userId)1211 protected List<Face> getEnrolledTemplates(int userId) { 1212 return getBiometricUtils().getBiometricsForUser(getContext(), userId); 1213 } 1214 1215 @Override notifyClientActiveCallbacks(boolean isActive)1216 protected void notifyClientActiveCallbacks(boolean isActive) { 1217 // noop for Face. 1218 } 1219 1220 @Override statsModality()1221 protected int statsModality() { 1222 return BiometricsProtoEnums.MODALITY_FACE; 1223 } 1224 1225 @Override getLockoutMode()1226 protected int getLockoutMode() { 1227 return mCurrentUserLockoutMode; 1228 } 1229 1230 /** Gets the face daemon */ getFaceDaemon()1231 private synchronized IBiometricsFace getFaceDaemon() { 1232 if (mDaemon == null) { 1233 Slog.v(TAG, "mDaemon was null, reconnect to face"); 1234 try { 1235 mDaemon = IBiometricsFace.getService(); 1236 } catch (java.util.NoSuchElementException e) { 1237 // Service doesn't exist or cannot be opened. Logged below. 1238 } catch (RemoteException e) { 1239 Slog.e(TAG, "Failed to get biometric interface", e); 1240 } 1241 if (mDaemon == null) { 1242 Slog.w(TAG, "face HIDL not available"); 1243 return null; 1244 } 1245 1246 mDaemon.asBinder().linkToDeath(this, 0); 1247 1248 try { 1249 mHalDeviceId = mDaemon.setCallback(mDaemonCallback).value; 1250 } catch (RemoteException e) { 1251 Slog.e(TAG, "Failed to open face HAL", e); 1252 mDaemon = null; // try again later! 1253 } 1254 1255 if (DEBUG) Slog.v(TAG, "Face HAL id: " + mHalDeviceId); 1256 if (mHalDeviceId != 0) { 1257 loadAuthenticatorIds(); 1258 updateActiveGroup(ActivityManager.getCurrentUser(), null); 1259 doTemplateCleanupForUser(ActivityManager.getCurrentUser()); 1260 } else { 1261 Slog.w(TAG, "Failed to open Face HAL!"); 1262 MetricsLogger.count(getContext(), "faced_openhal_error", 1); 1263 mDaemon = null; 1264 } 1265 } 1266 return mDaemon; 1267 } 1268 startGenerateChallenge(IBinder token)1269 private long startGenerateChallenge(IBinder token) { 1270 IBiometricsFace daemon = getFaceDaemon(); 1271 if (daemon == null) { 1272 Slog.w(TAG, "startGenerateChallenge: no face HAL!"); 1273 return 0; 1274 } 1275 try { 1276 return daemon.generateChallenge(CHALLENGE_TIMEOUT_SEC).value; 1277 } catch (RemoteException e) { 1278 Slog.e(TAG, "startGenerateChallenge failed", e); 1279 } 1280 return 0; 1281 } 1282 startRevokeChallenge(IBinder token)1283 private int startRevokeChallenge(IBinder token) { 1284 IBiometricsFace daemon = getFaceDaemon(); 1285 if (daemon == null) { 1286 Slog.w(TAG, "startRevokeChallenge: no face HAL!"); 1287 return 0; 1288 } 1289 try { 1290 final int res = daemon.revokeChallenge(); 1291 if (res != Status.OK) { 1292 Slog.e(TAG, "revokeChallenge returned " + res); 1293 } 1294 return res; 1295 } catch (RemoteException e) { 1296 Slog.e(TAG, "startRevokeChallenge failed", e); 1297 } 1298 return 0; 1299 } 1300 dumpInternal(PrintWriter pw)1301 private void dumpInternal(PrintWriter pw) { 1302 JSONObject dump = new JSONObject(); 1303 try { 1304 dump.put("service", "Face Manager"); 1305 1306 JSONArray sets = new JSONArray(); 1307 for (UserInfo user : UserManager.get(getContext()).getUsers()) { 1308 final int userId = user.getUserHandle().getIdentifier(); 1309 final int N = getBiometricUtils().getBiometricsForUser(getContext(), userId).size(); 1310 PerformanceStats stats = mPerformanceMap.get(userId); 1311 PerformanceStats cryptoStats = mCryptoPerformanceMap.get(userId); 1312 JSONObject set = new JSONObject(); 1313 set.put("id", userId); 1314 set.put("count", N); 1315 set.put("accept", (stats != null) ? stats.accept : 0); 1316 set.put("reject", (stats != null) ? stats.reject : 0); 1317 set.put("acquire", (stats != null) ? stats.acquire : 0); 1318 set.put("lockout", (stats != null) ? stats.lockout : 0); 1319 set.put("permanentLockout", (stats != null) ? stats.permanentLockout : 0); 1320 // cryptoStats measures statistics about secure face transactions 1321 // (e.g. to unlock password storage, make secure purchases, etc.) 1322 set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0); 1323 set.put("rejectCrypto", (cryptoStats != null) ? cryptoStats.reject : 0); 1324 set.put("acquireCrypto", (cryptoStats != null) ? cryptoStats.acquire : 0); 1325 set.put("lockoutCrypto", (cryptoStats != null) ? cryptoStats.lockout : 0); 1326 set.put("permanentLockoutCrypto", 1327 (cryptoStats != null) ? cryptoStats.permanentLockout : 0); 1328 sets.put(set); 1329 } 1330 1331 dump.put("prints", sets); 1332 } catch (JSONException e) { 1333 Slog.e(TAG, "dump formatting failure", e); 1334 } 1335 pw.println(dump); 1336 pw.println("HAL deaths since last reboot: " + mHALDeathCount); 1337 1338 mUsageStats.print(pw); 1339 } 1340 dumpHal(FileDescriptor fd, String[] args)1341 private void dumpHal(FileDescriptor fd, String[] args) { 1342 // WARNING: CDD restricts image data from leaving TEE unencrypted on 1343 // production devices: 1344 // [C-1-10] MUST not allow unencrypted access to identifiable biometric 1345 // data or any data derived from it (such as embeddings) to the 1346 // Application Processor outside the context of the TEE. 1347 // As such, this API should only be enabled for testing purposes on 1348 // engineering and userdebug builds. All modules in the software stack 1349 // MUST enforce final build products do NOT have this functionality. 1350 // Additionally, the following check MUST NOT be removed. 1351 if (!(Build.IS_ENG || Build.IS_USERDEBUG)) { 1352 return; 1353 } 1354 1355 // Additionally, this flag allows turning off face for a device 1356 // (either permanently through the build or on an individual device). 1357 if (SystemProperties.getBoolean("ro.face.disable_debug_data", false) 1358 || SystemProperties.getBoolean("persist.face.disable_debug_data", false)) { 1359 return; 1360 } 1361 1362 // The debug method takes two file descriptors. The first is for text 1363 // output, which we will drop. The second is for binary data, which 1364 // will be the protobuf data. 1365 final IBiometricsFace daemon = getFaceDaemon(); 1366 if (daemon != null) { 1367 FileOutputStream devnull = null; 1368 try { 1369 devnull = new FileOutputStream("/dev/null"); 1370 final NativeHandle handle = new NativeHandle( 1371 new FileDescriptor[] { devnull.getFD(), fd }, 1372 new int[0], false); 1373 daemon.debug(handle, new ArrayList<String>(Arrays.asList(args))); 1374 } catch (IOException | RemoteException ex) { 1375 Slog.d(TAG, "error while reading face debugging data", ex); 1376 } finally { 1377 if (devnull != null) { 1378 try { 1379 devnull.close(); 1380 } catch (IOException ex) { 1381 } 1382 } 1383 } 1384 } 1385 } 1386 } 1387