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