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