blob: 2489f64f498f5c006f6d872fe1a1375db3bd5eda [file] [log] [blame]
Gilad Brettercb51b8b2018-03-22 17:04:51 +02001/*
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
17package com.android.server.face;
18
19import static android.Manifest.permission.INTERACT_ACROSS_USERS;
20import static android.Manifest.permission.MANAGE_FACE;
21import static android.Manifest.permission.RESET_FACE_LOCKOUT;
22import static android.Manifest.permission.USE_BIOMETRIC;
23import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
24
25import android.app.ActivityManager;
26import android.app.ActivityManager.RunningAppProcessInfo;
27import android.app.AlarmManager;
28import android.app.AppOpsManager;
29import android.app.PendingIntent;
30import android.app.SynchronousUserSwitchObserver;
31import android.content.BroadcastReceiver;
32import android.content.ComponentName;
33import android.content.Context;
34import android.content.Intent;
35import android.content.IntentFilter;
36import android.content.pm.PackageManager;
37import android.content.pm.UserInfo;
38import android.hardware.biometrics.face.V1_0.IBiometricsFace;
39import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
40import android.hardware.face.Face;
41import android.hardware.face.FaceManager;
42import android.hardware.face.IFaceService;
43import android.hardware.face.IFaceServiceLockoutResetCallback;
44import android.hardware.face.IFaceServiceReceiver;
45import android.os.Binder;
46import android.os.Bundle;
47import android.os.DeadObjectException;
48import android.os.Environment;
49import android.os.Handler;
50import android.os.IBinder;
51import android.os.IHwBinder;
52import android.os.IRemoteCallback;
53import android.os.PowerManager;
54import android.os.PowerManager.WakeLock;
55import android.os.RemoteException;
56import android.os.SELinux;
57import android.os.SystemClock;
58import android.os.UserHandle;
59import android.os.UserManager;
60import android.security.KeyStore;
61import android.service.face.FaceActionStatsProto;
62import android.service.face.FaceServiceDumpProto;
63import android.service.face.FaceUserStatsProto;
64import android.util.Slog;
65import android.util.proto.ProtoOutputStream;
66
67import com.android.internal.annotations.GuardedBy;
68import com.android.internal.logging.MetricsLogger;
69import com.android.internal.util.DumpUtils;
70import com.android.server.SystemServerInitThreadPool;
71import com.android.server.SystemService;
72
73import org.json.JSONArray;
74import org.json.JSONException;
75import org.json.JSONObject;
76
77import java.io.File;
78import java.io.FileDescriptor;
79import java.io.PrintWriter;
80import java.util.ArrayList;
81import java.util.Collections;
82import java.util.HashMap;
83import java.util.List;
84import java.util.Map;
85
86/**
87 * A service to manage multiple clients that want to access the face HAL API.
88 * The service is responsible for maintaining a list of clients and dispatching all
89 * face -related events.
90 *
91 * @hide
92 */
93public class FaceService extends SystemService implements IHwBinder.DeathRecipient {
94 static final String TAG = "FaceService";
95 static final boolean DEBUG = true;
96 private static final String FACE_DATA_DIR = "facedata";
97 private static final int MSG_USER_SWITCHING = 10;
98 private static final String ACTION_LOCKOUT_RESET =
99 "com.android.server.face.ACTION_LOCKOUT_RESET";
100
101 private class PerformanceStats {
102 int accept; // number of accepted faces
103 int reject; // number of rejected faces
104 int acquire; // total number of acquisitions. Should be >= accept+reject due to poor image
105 // acquisition in some cases (too high, too low, poor gaze, etc.)
106 int lockout; // total number of lockouts
107 int permanentLockout; // total number of permanent lockouts
108 }
109
110 private final ArrayList<FaceServiceLockoutResetMonitor> mLockoutMonitors =
111 new ArrayList<>();
112 private final Map<Integer, Long> mAuthenticatorIds =
113 Collections.synchronizedMap(new HashMap<>());
114 private final AppOpsManager mAppOps;
115 private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
116 private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5;
117 private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;
118
119 private static final long CANCEL_TIMEOUT_LIMIT_MS = 3000; // max wait for onCancel() from HAL,in ms
120 private final String mKeyguardPackage;
121 private int mCurrentUserId = UserHandle.USER_NULL;
122 private final FaceUtils mFaceUtils = FaceUtils.getInstance();
123 private Context mContext;
124 private long mHalDeviceId;
125 private boolean mTimedLockoutCleared;
126 private int mFailedAttempts;
127 @GuardedBy("this")
128 private IBiometricsFace mDaemon;
129 private final PowerManager mPowerManager;
130 private final AlarmManager mAlarmManager;
131 private final UserManager mUserManager;
132 private ClientMonitor mCurrentClient;
133 private ClientMonitor mPendingClient;
134 private PerformanceStats mPerformanceStats;
135
136
137 private IBinder mToken = new Binder(); // used for internal FaceService enumeration
138
139 private class UserFace {
140 Face f;
141 int userId;
142 public UserFace(Face f, int userId) {
143 this.f = f;
144 this.userId = userId;
145 }
146 }
147
148 // Normal face authentications are tracked by mPerformanceMap.
149 private HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
150
151 // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
152 private HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
153
154 private Handler mHandler = new Handler() {
155 @Override
156 public void handleMessage(android.os.Message msg) {
157 switch (msg.what) {
158 case MSG_USER_SWITCHING:
159 handleUserSwitching(msg.arg1);
160 break;
161
162 default:
163 Slog.w(TAG, "Unknown message:" + msg.what);
164 }
165 }
166 };
167
168 private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
169 @Override
170 public void onReceive(Context context, Intent intent) {
171 if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
172 resetFailedAttempts(false /* clearAttemptCounter */);
173 }
174 }
175 };
176
177 private final Runnable mResetFailedAttemptsRunnable = new Runnable() {
178 @Override
179 public void run() {
180 resetFailedAttempts(true /* clearAttemptCounter */);
181 }
182 };
183
184 private final Runnable mResetClientState = new Runnable() {
185 @Override
186 public void run() {
187 // Warning: if we get here, the driver never confirmed our call to cancel the current
188 // operation (authenticate, enroll, remove, enumerate, etc), which is
189 // really bad. The result will be a 3-second delay in starting each new client.
190 // If you see this on a device, make certain the driver notifies with
191 // {@link FaceAuthenticationManager#FACE_ERROR_CANCEL} in response to cancel()
192 // once it has successfully switched to the IDLE state in the face HAL.
193 // Additionally,{@link FaceAuthenticationManager#FACE_ERROR_CANCEL} should only be sent
194 // in response to an actual cancel() call.
195 Slog.w(TAG, "Client "
196 + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
197 + " failed to respond to cancel, starting client "
198 + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
199
200 mCurrentClient = null;
201 startClient(mPendingClient, false);
202 }
203 };
204
205 public FaceService(Context context) {
206 super(context);
207 mContext = context;
208 mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
209 com.android.internal.R.string.config_keyguardComponent)).getPackageName();
210 mAppOps = context.getSystemService(AppOpsManager.class);
211 mPowerManager = mContext.getSystemService(PowerManager.class);
212 mAlarmManager = mContext.getSystemService(AlarmManager.class);
213 mContext.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
214 RESET_FACE_LOCKOUT, null /* handler */);
215 mUserManager = UserManager.get(mContext);
216 }
217
218 @Override
219 public void serviceDied(long cookie) {
220 Slog.v(TAG, "face HAL died");
221 MetricsLogger.count(mContext, "faced_died", 1);
222 handleError(mHalDeviceId, FaceManager.FACE_ERROR_HW_UNAVAILABLE,
223 0 /*vendorCode */);
224 }
225
226 public synchronized IBiometricsFace getFaceDaemon() {
227 if (mDaemon == null) {
228 Slog.v(TAG, "mDaemon was null, reconnect to face");
229 try {
230 mDaemon = IBiometricsFace.getService();
231 } catch (java.util.NoSuchElementException e) {
232 // Service doesn't exist or cannot be opened. Logged below.
233 } catch (RemoteException e) {
234 Slog.e(TAG, "Failed to get biometric interface", e);
235 }
236 if (mDaemon == null) {
237 Slog.w(TAG, "face HIDL not available");
238 return null;
239 }
240
241 mDaemon.asBinder().linkToDeath(this, 0);
242
243 try {
244 mHalDeviceId = mDaemon.setCallback(mDaemonCallback).value;
245 } catch (RemoteException e) {
246 Slog.e(TAG, "Failed to open face HAL", e);
247 mDaemon = null; // try again later!
248 }
249
250 if (DEBUG) Slog.v(TAG, "face HAL id: " + mHalDeviceId);
251 if (mHalDeviceId != 0) {
252 loadAuthenticatorIds();
253 updateActiveGroup(ActivityManager.getCurrentUser(), null);
254 } else {
255 Slog.w(TAG, "Failed to open Face HAL!");
256 MetricsLogger.count(mContext, "faced_openhal_error", 1);
257 mDaemon = null;
258 }
259 }
260 return mDaemon;
261 }
262
263 /** Populates existing authenticator ids. To be used only during the start of the service. */
264 private void loadAuthenticatorIds() {
265 // This operation can be expensive, so keep track of the elapsed time. Might need to move to
266 // background if it takes too long.
267 long t = System.currentTimeMillis();
268 mAuthenticatorIds.clear();
269 for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) {
270 int userId = getUserOrWorkProfileId(null, user.id);
271 if (!mAuthenticatorIds.containsKey(userId)) {
272 updateActiveGroup(userId, null);
273 }
274 }
275
276 t = System.currentTimeMillis() - t;
277 if (t > 1000) {
278 Slog.w(TAG, "loadAuthenticatorIds() taking too long: " + t + "ms");
279 }
280 }
281
282 protected void handleError(long deviceId, int error, int vendorCode) {
283 ClientMonitor client = mCurrentClient;
284 if (client != null && client.onError(error, vendorCode)) {
285 removeClient(client);
286 }
287
288 if (DEBUG) Slog.v(TAG, "handleError(client="
289 + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
290 // This is the magic code that starts the next client when the old client finishes.
291 if (error == FaceManager.FACE_ERROR_CANCELED) {
292 mHandler.removeCallbacks(mResetClientState);
293 if (mPendingClient != null) {
294 if (DEBUG) Slog.v(TAG, "start pending client " + mPendingClient.getOwnerString());
295 startClient(mPendingClient, false);
296 mPendingClient = null;
297 }
298 } else if (error == FaceManager.FACE_ERROR_HW_UNAVAILABLE) {
299 // If we get HW_UNAVAILABLE, try to connect again later...
300 Slog.w(TAG, "Got ERROR_HW_UNAVAILABLE; try reconnecting next client.");
301 synchronized (this) {
302 mDaemon = null;
303 mHalDeviceId = 0;
304 mCurrentUserId = UserHandle.USER_NULL;
305 }
306 }
307 }
308
309 protected void handleRemoved(long deviceId, int faceId, int userId, int remaining) {
310 if (DEBUG) Slog.w(TAG, "Removed: fid=" + faceId
311 + ", uid=" + userId
312 + ", dev=" + deviceId
313 + ", rem=" + remaining);
314
315 ClientMonitor client = mCurrentClient;
316 if (client != null && client.onRemoved(faceId, remaining)) {
317 removeClient(client);
318 }
319 }
320
321 protected void handleAuthenticated(long deviceId, int faceId, int userId,
322 ArrayList<Byte> token) {
323 ClientMonitor client = mCurrentClient;
324 if (faceId != 0) {
325 // Ugh...
326 final byte[] byteToken = new byte[token.size()];
327 for (int i = 0; i < token.size(); i++) {
328 byteToken[i] = token.get(i);
329 }
330 // Send to Keystore
331 KeyStore.getInstance().addAuthToken(byteToken);
332 }
333 if (client != null && client.onAuthenticated(faceId)) {
334 removeClient(client);
335 }
336 if (faceId != 0) {
337 mPerformanceStats.accept++;
338 } else {
339 mPerformanceStats.reject++;
340 }
341 }
342
343 protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
344 ClientMonitor client = mCurrentClient;
345 if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
346 removeClient(client);
347 }
348 if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
349 && client instanceof AuthenticationClient) {
350 // ignore enrollment acquisitions or acquisitions when we're locked out
351 mPerformanceStats.acquire++;
352 }
353 }
354
355 protected void handleEnrollResult(long deviceId, int faceId, int userId, int remaining) {
356 ClientMonitor client = mCurrentClient;
357 if (client != null && client.onEnrollResult(faceId, remaining)) {
358 removeClient(client);
359 }
360 }
361
362 private void userActivity() {
363 long now = SystemClock.uptimeMillis();
364 mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
365 }
366
367 void handleUserSwitching(int userId) {
368 updateActiveGroup(userId, null);
369 }
370
371 private void removeClient(ClientMonitor client) {
372 if (client != null) {
373 client.destroy();
374 if (client != mCurrentClient && mCurrentClient != null) {
375 Slog.w(TAG, "Unexpected client: " + client.getOwnerString() + "expected: "
376 + mCurrentClient != null ? mCurrentClient.getOwnerString() : "null");
377 }
378 }
379 if (mCurrentClient != null) {
380 if (DEBUG) Slog.v(TAG, "Done with client: " + client.getOwnerString());
381 mCurrentClient = null;
382 }
383 }
384
385 private int getLockoutMode() {
386 if (mFailedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) {
387 return AuthenticationClient.LOCKOUT_PERMANENT;
388 } else if (mFailedAttempts > 0 && mTimedLockoutCleared == false &&
389 (mFailedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) {
390 return AuthenticationClient.LOCKOUT_TIMED;
391 }
392 return AuthenticationClient.LOCKOUT_NONE;
393 }
394
395 private void scheduleLockoutReset() {
396 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
397 SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS, getLockoutResetIntent());
398 }
399
400 private void cancelLockoutReset() {
401 mAlarmManager.cancel(getLockoutResetIntent());
402 }
403
404 private PendingIntent getLockoutResetIntent() {
405 return PendingIntent.getBroadcast(mContext, 0,
406 new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT);
407 }
408
409 public long startPreEnroll(IBinder token) {
410 IBiometricsFace daemon = getFaceDaemon();
411 if (daemon == null) {
412 Slog.w(TAG, "startPreEnroll: no face HAL!");
413 return 0;
414 }
415 try {
416 return daemon.preEnroll().value;
417 } catch (RemoteException e) {
418 Slog.e(TAG, "startPreEnroll failed", e);
419 }
420 return 0;
421 }
422
423 public int startPostEnroll(IBinder token) {
424 IBiometricsFace daemon = getFaceDaemon();
425 if (daemon == null) {
426 Slog.w(TAG, "startPostEnroll: no face HAL!");
427 return 0;
428 }
429 try {
430 return daemon.postEnroll();
431 } catch (RemoteException e) {
432 Slog.e(TAG, "startPostEnroll failed", e);
433 }
434 return 0;
435 }
436
437 /**
438 * Calls face HAL to switch states to the new task. If there's already a current task,
439 * it calls cancel() and sets mPendingClient to begin when the current task finishes
440 * ({@link FaceManager#FACE_ERROR_CANCELED}).
441 * @param newClient the new client that wants to connect
442 * @param initiatedByClient true for authenticate, remove and enroll
443 */
444 private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
445 ClientMonitor currentClient = mCurrentClient;
446 if (currentClient != null) {
447 if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString());
448 if (currentClient instanceof InternalRemovalClient) {
449 // This condition means we're currently running internal diagnostics to
450 // remove a face in the hardware and/or the software
451 // TODO: design an escape hatch in case client never finishes
452 }
453 else {
454 currentClient.stop(initiatedByClient);
455 }
456 mPendingClient = newClient;
457 mHandler.removeCallbacks(mResetClientState);
458 mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT_MS);
459 } else if (newClient != null) {
460 mCurrentClient = newClient;
461 if (DEBUG) Slog.v(TAG, "starting client "
462 + newClient.getClass().getSuperclass().getSimpleName()
463 + "(" + newClient.getOwnerString() + ")"
464 + ", initiatedByClient = " + initiatedByClient + ")");
465 newClient.start();
466 }
467 }
468
469 void startRemove(IBinder token, int userId, IFaceServiceReceiver receiver, boolean restricted,
470 boolean internal) {
471 IBiometricsFace daemon = getFaceDaemon();
472 if (daemon == null) {
473 Slog.w(TAG, "startRemove: no face HAL!");
474 return;
475 }
476
477 if (internal) {
478 Context context = getContext();
479 InternalRemovalClient client = new InternalRemovalClient(context, mHalDeviceId,
480 token, receiver, userId, restricted, context.getOpPackageName()) {
481 @Override
482 public void notifyUserActivity() {
483
484 }
485 @Override
486 public IBiometricsFace getFaceDaemon() {
487 return FaceService.this.getFaceDaemon();
488 }
489 };
490 startClient(client, true);
491 }
492 else {
493 RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token,
494 receiver, userId, restricted, token.toString()) {
495 @Override
496 public void notifyUserActivity() {
497 FaceService.this.userActivity();
498 }
499
500 @Override
501 public IBiometricsFace getFaceDaemon() {
502 return FaceService.this.getFaceDaemon();
503 }
504 };
505 startClient(client, true);
506 }
507 }
508
509 /*
510 * @hide
511 */
512 public Face getEnrolledFace(int userId) {
513 return mFaceUtils.getFaceForUser(mContext, userId);
514 }
515
516 public boolean hasEnrolledFace(int userId) {
517 if (userId != UserHandle.getCallingUserId()) {
518 checkPermission(INTERACT_ACROSS_USERS);
519 }
520 return mFaceUtils.getFaceForUser(mContext, userId) != null;
521 }
522
523 boolean hasPermission(String permission) {
524 return getContext().checkCallingOrSelfPermission(permission)
525 == PackageManager.PERMISSION_GRANTED;
526 }
527
528 void checkPermission(String permission) {
529 getContext().enforceCallingOrSelfPermission(permission,
530 "Must have " + permission + " permission.");
531 }
532
533 int getEffectiveUserId(int userId) {
534 UserManager um = UserManager.get(mContext);
535 if (um != null) {
536 final long callingIdentity = Binder.clearCallingIdentity();
537 userId = um.getCredentialOwnerProfile(userId);
538 Binder.restoreCallingIdentity(callingIdentity);
539 } else {
540 Slog.e(TAG, "Unable to acquire UserManager");
541 }
542 return userId;
543 }
544
545 boolean isCurrentUserOrProfile(int userId) {
546 UserManager um = UserManager.get(mContext);
547 if (um == null) {
548 Slog.e(TAG, "Unable to acquire UserManager");
549 return false;
550 }
551
552 final long token = Binder.clearCallingIdentity();
553 try {
554 // Allow current user or profiles of the current user...
555 for (int profileId : um.getEnabledProfileIds(ActivityManager.getCurrentUser())) {
556 if (profileId == userId) {
557 return true;
558 }
559 }
560 } finally {
561 Binder.restoreCallingIdentity(token);
562 }
563
564 return false;
565 }
566
567 private boolean isForegroundActivity(int uid, int pid) {
568 try {
569 List<RunningAppProcessInfo> procs =
570 ActivityManager.getService().getRunningAppProcesses();
571 int N = procs.size();
572 for (int i = 0; i < N; i++) {
573 RunningAppProcessInfo proc = procs.get(i);
574 if (proc.pid == pid && proc.uid == uid
575 && proc.importance == IMPORTANCE_FOREGROUND) {
576 return true;
577 }
578 }
579 } catch (RemoteException e) {
580 Slog.w(TAG, "am.getRunningAppProcesses() failed");
581 }
582 return false;
583 }
584
585 /**
586 * @param opPackageName name of package for caller
587 * @param requireForeground only allow this call while app is in the foreground
588 * @return true if caller can use face API
589 */
590 private boolean canUseFace(String opPackageName, boolean requireForeground, int uid,
591 int pid, int userId) {
592 checkPermission(USE_BIOMETRIC);
593 if (isKeyguard(opPackageName)) {
594 return true; // Keyguard is always allowed
595 }
596 if (!isCurrentUserOrProfile(userId)) {
597 Slog.w(TAG,"Rejecting " + opPackageName + " ; not a current user or profile");
598 return false;
599 }
600 if (mAppOps.noteOp(AppOpsManager.OP_USE_FACE, uid, opPackageName)
601 != AppOpsManager.MODE_ALLOWED) {
602 Slog.w(TAG, "Rejecting " + opPackageName + " ; permission denied");
603 return false;
604 }
605 if (requireForeground && !(isForegroundActivity(uid, pid) || currentClient(opPackageName))){
606 Slog.w(TAG, "Rejecting " + opPackageName + " ; not in foreground");
607 return false;
608 }
609 return true;
610 }
611
612 /**
613 * @param opPackageName package of the caller
614 * @return true if this is the same client currently using face
615 */
616 private boolean currentClient(String opPackageName) {
617 return mCurrentClient != null && mCurrentClient.getOwnerString().equals(opPackageName);
618 }
619
620 /**
621 * @param clientPackage
622 * @return true if this is keyguard package
623 */
624 private boolean isKeyguard(String clientPackage) {
625 return mKeyguardPackage.equals(clientPackage);
626 }
627
628 private void addLockoutResetMonitor(FaceServiceLockoutResetMonitor monitor) {
629 if (!mLockoutMonitors.contains(monitor)) {
630 mLockoutMonitors.add(monitor);
631 }
632 }
633
634 private void removeLockoutResetCallback(
635 FaceServiceLockoutResetMonitor monitor) {
636 mLockoutMonitors.remove(monitor);
637 }
638
639 private void notifyLockoutResetMonitors() {
640 for (int i = 0; i < mLockoutMonitors.size(); i++) {
641 mLockoutMonitors.get(i).sendLockoutReset();
642 }
643 }
644
645 private void startAuthentication(IBinder token, long opId, int callingUserId,
646 IFaceServiceReceiver receiver, int flags, boolean restricted,
647 String opPackageName) {
648 updateActiveGroup(callingUserId, opPackageName);
649
650 if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")");
651
652 AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token,
653 receiver, mCurrentUserId, opId, restricted, opPackageName) {
654 @Override
655 public int handleFailedAttempt() {
656 mFailedAttempts++;
657 mTimedLockoutCleared = false;
658 final int lockoutMode = getLockoutMode();
659 if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
660 mPerformanceStats.permanentLockout++;
661 } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
662 mPerformanceStats.lockout++;
663 }
664
665 // Failing multiple times will continue to push out the lockout time
666 if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
667 scheduleLockoutReset();
668 return lockoutMode;
669 }
670 return AuthenticationClient.LOCKOUT_NONE;
671 }
672
673 @Override
674 public void resetFailedAttempts() {
675 FaceService.this.resetFailedAttempts(true /* clearAttemptCounter */);
676 }
677
678 @Override
679 public void notifyUserActivity() {
680 FaceService.this.userActivity();
681 }
682
683 @Override
684 public IBiometricsFace getFaceDaemon() {
685 return FaceService.this.getFaceDaemon();
686 }
687 };
688
689 int lockoutMode = getLockoutMode();
690 if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
691 Slog.v(TAG, "In lockout mode(" + lockoutMode +
692 ") ; disallowing authentication");
693 int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
694 FaceManager.FACE_ERROR_LOCKOUT :
695 FaceManager.FACE_ERROR_LOCKOUT_PERMANENT;
696 if (!client.onError(errorCode, 0 /* vendorCode */)) {
697 Slog.w(TAG, "Cannot send permanent lockout message to client");
698 }
699 return;
700 }
701 startClient(client, true /* initiatedByClient */);
702 }
703
704 private void startEnrollment(IBinder token, byte [] cryptoToken, int userId,
705 IFaceServiceReceiver receiver, int flags, boolean restricted,
706 String opPackageName) {
707 updateActiveGroup(userId, opPackageName);
708
709 EnrollClient client = new EnrollClient(getContext(), mHalDeviceId, token, receiver,
710 userId, cryptoToken, restricted, opPackageName) {
711
712 @Override
713 public IBiometricsFace getFaceDaemon() {
714 return FaceService.this.getFaceDaemon();
715 }
716
717 @Override
718 public void notifyUserActivity() {
719 FaceService.this.userActivity();
720 }
721 };
722 startClient(client, true /* initiatedByClient */);
723 }
724
725 // attempt counter should only be cleared when Keyguard goes away or when
726 // a face is successfully authenticated
727 protected void resetFailedAttempts(boolean clearAttemptCounter) {
728 if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
729 Slog.v(TAG, "Reset face lockout, clearAttemptCounter=" + clearAttemptCounter);
730 }
731 if (clearAttemptCounter) {
732 mFailedAttempts = 0;
733 }
734 mTimedLockoutCleared = true;
735 // If we're asked to reset failed attempts externally (i.e. from Keyguard),
736 // the alarm might still be pending; remove it.
737 cancelLockoutReset();
738 notifyLockoutResetMonitors();
739 }
740
741 private class FaceServiceLockoutResetMonitor {
742
743 private static final long WAKELOCK_TIMEOUT_MS = 2000;
744 private final IFaceServiceLockoutResetCallback mCallback;
745 private final WakeLock mWakeLock;
746
747 public FaceServiceLockoutResetMonitor(
748 IFaceServiceLockoutResetCallback callback) {
749 mCallback = callback;
750 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
751 "lockout reset callback");
752 }
753
754 public void sendLockoutReset() {
755 if (mCallback != null) {
756 try {
757 mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
758 mCallback.onLockoutReset(mHalDeviceId, new IRemoteCallback.Stub() {
759
760 @Override
761 public void sendResult(Bundle data) throws RemoteException {
762 if (mWakeLock.isHeld()) {
763 mWakeLock.release();
764 }
765 }
766 });
767 } catch (DeadObjectException e) {
768 Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
769 mHandler.post(mRemoveCallbackRunnable);
770 } catch (RemoteException e) {
771 Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
772 }
773 }
774 }
775
776 private final Runnable mRemoveCallbackRunnable = new Runnable() {
777 @Override
778 public void run() {
779 if (mWakeLock.isHeld()) {
780 mWakeLock.release();
781 }
782 removeLockoutResetCallback(FaceServiceLockoutResetMonitor.this);
783 }
784 };
785 }
786
787 private IBiometricsFaceClientCallback mDaemonCallback =
788 new IBiometricsFaceClientCallback.Stub() {
789
790 @Override
791 public void onEnrollResult(final long deviceId, int faceId, int userId, int remaining) {
792 mHandler.post(new Runnable() {
793 @Override
794 public void run() {
795 handleEnrollResult(deviceId, faceId, userId, remaining);
796 }
797 });
798 }
799
800 @Override
801 public void onAcquired(final long deviceId, final int userId, final int acquiredInfo,
802 final int vendorCode) {
803 mHandler.post(new Runnable() {
804 @Override
805 public void run() {
806 handleAcquired(deviceId, acquiredInfo, vendorCode);
807 }
808 });
809 }
810
811 @Override
812 public void onAuthenticated(final long deviceId, final int faceId, final int userId,
813 ArrayList<Byte> token) {
814 mHandler.post(new Runnable() {
815 @Override
816 public void run() {
817 handleAuthenticated(deviceId, faceId, userId, token);
818 }
819 });
820 }
821
822 @Override
823 public void onError(final long deviceId, final int userId, final int error,
824 final int vendorCode) {
825 mHandler.post(new Runnable() {
826 @Override
827 public void run() {
828 handleError(deviceId, error, vendorCode);
829 }
830 });
831 }
832
833 @Override
834 public void onRemoved(final long deviceId, final int faceId, final int userId,
835 final int remaining) {
836 mHandler.post(new Runnable() {
837 @Override
838 public void run() {
839 handleRemoved(deviceId, faceId, userId, remaining);
840 }
841 });
842 }
843
844 @Override
845 public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId)
846 throws RemoteException {
847
848 }
849 };
850
851 private final class FaceServiceWrapper extends IFaceService.Stub {
852 @Override // Binder call
853 public long preEnroll(IBinder token) {
854 checkPermission(MANAGE_FACE);
855 return startPreEnroll(token);
856 }
857
858 @Override // Binder call
859 public int postEnroll(IBinder token) {
860 checkPermission(MANAGE_FACE);
861 return startPostEnroll(token);
862 }
863
864 @Override // Binder call
865 public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
866 final IFaceServiceReceiver receiver, final int flags,
867 final String opPackageName) {
868 checkPermission(MANAGE_FACE);
869
870 Face enrolledFace = FaceService.this.getEnrolledFace(userId);
871
872 if (enrolledFace != null) {
873 Slog.w(TAG, "Multiple faces enrollment is not supported");
874 return;
875 }
876
877
878 final boolean restricted = isRestricted();
879 mHandler.post(new Runnable() {
880 @Override
881 public void run() {
882 startEnrollment(token, cryptoToken, userId, receiver, flags,
883 restricted, opPackageName);
884 }
885 });
886 }
887
888 private boolean isRestricted() {
889 // Only give privileged apps (like Settings) access to faces info
890 final boolean restricted = !hasPermission(MANAGE_FACE);
891 return restricted;
892 }
893
894 @Override // Binder call
895 public void cancelEnrollment(final IBinder token) {
896 checkPermission(MANAGE_FACE);
897 mHandler.post(new Runnable() {
898 @Override
899 public void run() {
900 ClientMonitor client = mCurrentClient;
901 if (client instanceof EnrollClient && client.getToken() == token) {
902 client.stop(client.getToken() == token);
903 }
904 }
905 });
906 }
907
908 @Override // Binder call
909 public void authenticate(final IBinder token, final long opId,
910 final IFaceServiceReceiver receiver, final int flags,
911 final String opPackageName) {
912 final int callingUid = Binder.getCallingUid();
913 final int callingUserId = UserHandle.getCallingUserId();
914 final int pid = Binder.getCallingPid();
915 final boolean restricted = isRestricted();
916 mHandler.post(new Runnable() {
917 @Override
918 public void run() {
919 if (!canUseFace(opPackageName, true /* foregroundOnly */,
920 callingUid, pid, callingUserId)) {
921 if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
922 return;
923 }
924
925 MetricsLogger.histogram(mContext, "faces_token", opId != 0L ? 1 : 0);
926
927 // Get performance stats object for this user.
928 HashMap<Integer, PerformanceStats> pmap
929 = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
930 PerformanceStats stats = pmap.get(mCurrentUserId);
931 if (stats == null) {
932 stats = new PerformanceStats();
933 pmap.put(mCurrentUserId, stats);
934 }
935 mPerformanceStats = stats;
936
937 startAuthentication(token, opId, callingUserId, receiver,
938 flags, restricted, opPackageName);
939 }
940 });
941 }
942
943 @Override // Binder call
944 public void cancelAuthentication(final IBinder token, final String opPackageName) {
945 final int uid = Binder.getCallingUid();
946 final int pid = Binder.getCallingPid();
947 final int callingUserId = UserHandle.getCallingUserId();
948 mHandler.post(new Runnable() {
949 @Override
950 public void run() {
951 if (!canUseFace(opPackageName, true /* foregroundOnly */, uid, pid,
952 callingUserId)) {
953 if (DEBUG) Slog.v(TAG, "cancelAuthentication(): reject " + opPackageName);
954 } else {
955 ClientMonitor client = mCurrentClient;
956 if (client instanceof AuthenticationClient) {
957 if (client.getToken() == token) {
958 if (DEBUG) Slog.v(TAG, "stop client " + client.getOwnerString());
959 client.stop(client.getToken() == token);
960 } else {
961 if (DEBUG) Slog.v(TAG, "can't stop client "
962 + client.getOwnerString() + " since tokens don't match");
963 }
964 } else if (client != null) {
965 if (DEBUG) Slog.v(TAG, "can't cancel non-authenticating client "
966 + client.getOwnerString());
967 }
968 }
969 }
970 });
971 }
972
973 @Override // Binder call
974 public void setActiveUser(final int userId) {
975 checkPermission(MANAGE_FACE);
976 mHandler.post(new Runnable() {
977 @Override
978 public void run() {
979 updateActiveGroup(userId, null);
980 }
981 });
982 }
983
984 @Override // Binder call
985 public void remove(final IBinder token, final int userId,
986 final IFaceServiceReceiver receiver) {
987 checkPermission(MANAGE_FACE); // TODO: Maybe have another permission
988 final boolean restricted = isRestricted();
989 mHandler.post(new Runnable() {
990 @Override
991 public void run() {
992 startRemove(token, userId, receiver, restricted, false /* internal */);
993 }
994 });
995 }
996
997 @Override // Binder call
998 public boolean isHardwareDetected(long deviceId, String opPackageName) {
999 if (!canUseFace(opPackageName, false /* foregroundOnly */,
1000 Binder.getCallingUid(), Binder.getCallingPid(),
1001 UserHandle.getCallingUserId())) {
1002 return false;
1003 }
1004
1005 final long token = Binder.clearCallingIdentity();
1006 try {
1007 IBiometricsFace daemon = getFaceDaemon();
1008 return daemon != null && mHalDeviceId != 0;
1009 } finally {
1010 Binder.restoreCallingIdentity(token);
1011 }
1012 }
1013
1014 @Override // Binder call
1015 public Face getEnrolledFace(int userId, String opPackageName) {
1016 if (!canUseFace(opPackageName, false /* foregroundOnly */,
1017 Binder.getCallingUid(), Binder.getCallingPid(),
1018 UserHandle.getCallingUserId())) {
1019 return null;
1020 }
1021
1022 return FaceService.this.getEnrolledFace(userId);
1023 }
1024
1025 @Override // Binder call
1026 public boolean hasEnrolledFace(int userId, String opPackageName) {
1027 if (!canUseFace(opPackageName, false /* foregroundOnly */,
1028 Binder.getCallingUid(), Binder.getCallingPid(),
1029 UserHandle.getCallingUserId())) {
1030 return false;
1031 }
1032
1033 return FaceService.this.hasEnrolledFace(userId);
1034 }
1035
1036 @Override // Binder call
1037 public long getAuthenticatorId(String opPackageName) {
1038 // In this method, we're not checking whether the caller is permitted to use face
1039 // API because current authenticator ID is leaked (in a more contrived way) via Android
1040 // Keystore (android.security.keystore package): the user of that API can create a key
1041 // which requires face authentication for its use, and then query the key's
1042 // characteristics (hidden API) which returns, among other things, face
1043 // authenticator ID which was active at key creation time.
1044 //
1045 // Reason: The part of Android Keystore which runs inside an app's process invokes this
1046 // method in certain cases. Those cases are not always where the developer demonstrates
1047 // explicit intent to use face functionality. Thus, to avoiding throwing an
1048 // unexpected SecurityException this method does not check whether its caller is
1049 // permitted to use face API.
1050 //
1051 // The permission check should be restored once Android Keystore no longer invokes this
1052 // method from inside app processes.
1053
1054 return FaceService.this.getAuthenticatorId(opPackageName);
1055 }
1056
1057 @Override // Binder call
1058 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1059 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
1060
1061 final long ident = Binder.clearCallingIdentity();
1062 try {
1063 if (args.length > 0 && "--proto".equals(args[0])) {
1064 dumpProto(fd);
1065 } else {
1066 dumpInternal(pw);
1067 }
1068 } finally {
1069 Binder.restoreCallingIdentity(ident);
1070 }
1071 }
1072
1073 @Override // Binder call
1074 public void resetTimeout(byte [] token) {
1075 checkPermission(RESET_FACE_LOCKOUT);
1076 // TODO: confirm security token when we move timeout management into the HAL layer.
1077 mHandler.post(mResetFailedAttemptsRunnable);
1078 }
1079
1080 @Override
1081 public void addLockoutResetCallback(final IFaceServiceLockoutResetCallback callback)
1082 throws RemoteException {
1083 mHandler.post(new Runnable() {
1084 @Override
1085 public void run() {
1086 addLockoutResetMonitor(
1087 new FaceServiceLockoutResetMonitor(callback));
1088 }
1089 });
1090 }
1091 }
1092
1093 private void dumpInternal(PrintWriter pw) {
1094 JSONObject dump = new JSONObject();
1095 try {
1096 dump.put("service", "Face Manager");
1097
1098 JSONArray sets = new JSONArray();
1099 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1100 final int userId = user.getUserHandle().getIdentifier();
1101 PerformanceStats stats = mPerformanceMap.get(userId);
1102 PerformanceStats cryptoStats = mCryptoPerformanceMap.get(userId);
1103 JSONObject set = new JSONObject();
1104 set.put("id", userId);
1105 set.put("accept", (stats != null) ? stats.accept : 0);
1106 set.put("reject", (stats != null) ? stats.reject : 0);
1107 set.put("acquire", (stats != null) ? stats.acquire : 0);
1108 set.put("lockout", (stats != null) ? stats.lockout : 0);
1109 set.put("permanentLockout", (stats != null) ? stats.permanentLockout : 0);
1110 // cryptoStats measures statistics about secure face transactions
1111 // (e.g. to unlock password storage, make secure purchases, etc.)
1112 set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0);
1113 set.put("rejectCrypto", (cryptoStats != null) ? cryptoStats.reject : 0);
1114 set.put("acquireCrypto", (cryptoStats != null) ? cryptoStats.acquire : 0);
1115 set.put("lockoutCrypto", (cryptoStats != null) ? cryptoStats.lockout : 0);
1116 sets.put(set);
1117 }
1118
1119 dump.put("prints", sets);
1120 } catch (JSONException e) {
1121 Slog.e(TAG, "dump formatting failure", e);
1122 }
1123 pw.println(dump);
1124 }
1125
1126 private void dumpProto(FileDescriptor fd) {
1127 final ProtoOutputStream proto = new ProtoOutputStream(fd);
1128 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1129 final int userId = user.getUserHandle().getIdentifier();
1130
1131 final long userToken = proto.start(FaceServiceDumpProto.USERS);
1132
1133 proto.write(FaceUserStatsProto.USER_ID, userId);
1134
1135 // Normal face authentications (e.g. lockscreen)
1136 final PerformanceStats normal = mPerformanceMap.get(userId);
1137 if (normal != null) {
1138 final long countsToken = proto.start(FaceUserStatsProto.NORMAL);
1139 proto.write(FaceActionStatsProto.ACCEPT, normal.accept);
1140 proto.write(FaceActionStatsProto.REJECT, normal.reject);
1141 proto.write(FaceActionStatsProto.ACQUIRE, normal.acquire);
1142 proto.write(FaceActionStatsProto.LOCKOUT, normal.lockout);
1143 proto.write(FaceActionStatsProto.LOCKOUT_PERMANENT, normal.lockout);
1144 proto.end(countsToken);
1145 }
1146
1147 // Statistics about secure face transactions (e.g. to unlock password
1148 // storage, make secure purchases, etc.)
1149 final PerformanceStats crypto = mCryptoPerformanceMap.get(userId);
1150 if (crypto != null) {
1151 final long countsToken = proto.start(FaceUserStatsProto.CRYPTO);
1152 proto.write(FaceActionStatsProto.ACCEPT, crypto.accept);
1153 proto.write(FaceActionStatsProto.REJECT, crypto.reject);
1154 proto.write(FaceActionStatsProto.ACQUIRE, crypto.acquire);
1155 proto.write(FaceActionStatsProto.LOCKOUT, crypto.lockout);
1156 proto.write(FaceActionStatsProto.LOCKOUT_PERMANENT, crypto.lockout);
1157 proto.end(countsToken);
1158 }
1159
1160 proto.end(userToken);
1161 }
1162 proto.flush();
1163 }
1164
1165 @Override
1166 public void onStart() {
1167 publishBinderService(Context.FACE_SERVICE, new FaceServiceWrapper());
1168 SystemServerInitThreadPool.get().submit(this::getFaceDaemon, TAG + ".onStart");
1169 listenForUserSwitches();
1170 }
1171
1172 private void updateActiveGroup(int userId, String clientPackage) {
1173 IBiometricsFace daemon = getFaceDaemon();
1174
1175 if (daemon != null) {
1176 try {
1177 userId = getUserOrWorkProfileId(clientPackage, userId);
1178 if (userId != mCurrentUserId) {
1179 final File systemDir = Environment.getUserSystemDirectory(userId);
1180 final File faceDir = new File(systemDir, FACE_DATA_DIR);
1181 if (!faceDir.exists()) {
1182 if (!faceDir.mkdir()) {
1183 Slog.v(TAG, "Cannot make directory: " + faceDir.getAbsolutePath());
1184 return;
1185 }
1186 // Calling mkdir() from this process will create a directory with our
1187 // permissions (inherited from the containing dir). This command fixes
1188 // the label.
1189 if (!SELinux.restorecon(faceDir)) {
1190 Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
1191 return;
1192 }
1193 }
1194 daemon.setActiveUser(userId, faceDir.getAbsolutePath());
1195 mCurrentUserId = userId;
1196 }
1197 mAuthenticatorIds.put(userId,
1198 hasEnrolledFace(userId) ? daemon.getAuthenticatorId().value : 0L);
1199 } catch (RemoteException e) {
1200 Slog.e(TAG, "Failed to setActiveUser():", e);
1201 }
1202 }
1203 }
1204
1205 /**
1206 * @param clientPackage the package of the caller
1207 * @return the profile id
1208 */
1209 private int getUserOrWorkProfileId(String clientPackage, int userId) {
1210 if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
1211 return userId;
1212 }
1213 return getEffectiveUserId(userId);
1214 }
1215
1216 /**
1217 * @param userId
1218 * @return true if this is a work profile
1219 */
1220 private boolean isWorkProfile(int userId) {
1221 UserInfo userInfo = null;
1222 final long token = Binder.clearCallingIdentity();
1223 try {
1224 userInfo = mUserManager.getUserInfo(userId);
1225 } finally {
1226 Binder.restoreCallingIdentity(token);
1227 }
1228 return userInfo != null && userInfo.isManagedProfile();
1229 }
1230
1231 private void listenForUserSwitches() {
1232 try {
1233 ActivityManager.getService().registerUserSwitchObserver(
1234 new SynchronousUserSwitchObserver() {
1235 @Override
1236 public void onUserSwitching(int newUserId) throws RemoteException {
1237 mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
1238 .sendToTarget();
1239 }
1240 }, TAG);
1241 } catch (RemoteException e) {
1242 Slog.w(TAG, "Failed to listen for user switching event" ,e);
1243 }
1244 }
1245
1246 /***
1247 * @param opPackageName the name of the calling package
1248 * @return authenticator id for the calling user
1249 */
1250 public long getAuthenticatorId(String opPackageName) {
1251 final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
1252 return mAuthenticatorIds.getOrDefault(userId, 0L);
1253 }
1254}