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