blob: 74d742af5b84783cdce71e56119095ee6c003fb7 [file] [log] [blame]
Kevin Chyn037c4d52018-06-11 19:17:32 -07001/*
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
Kevin Chyn05c21502018-09-18 13:07:19 -070014 * limitations under the License.
Kevin Chyn037c4d52018-06-11 19:17:32 -070015 */
16
Kevin Chyn836f2cf2018-08-27 11:06:39 -070017package com.android.server.biometrics;
Kevin Chyn037c4d52018-06-11 19:17:32 -070018
Kevin Chyn3a0187192018-10-08 15:40:05 -070019import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
Kevin Chyn037c4d52018-06-11 19:17:32 -070020import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
21
22import android.app.ActivityManager;
23import android.app.ActivityTaskManager;
24import android.app.AlarmManager;
25import android.app.AppOpsManager;
26import android.app.IActivityTaskManager;
27import android.app.PendingIntent;
28import android.app.SynchronousUserSwitchObserver;
29import android.app.TaskStackListener;
30import android.content.BroadcastReceiver;
31import android.content.ComponentName;
32import android.content.Context;
33import android.content.Intent;
34import android.content.IntentFilter;
35import android.content.pm.PackageManager;
36import android.content.pm.UserInfo;
37import android.hardware.biometrics.BiometricAuthenticator;
38import android.hardware.biometrics.BiometricConstants;
39import android.hardware.biometrics.IBiometricPromptReceiver;
Kevin Chyna56dff72018-06-19 18:41:12 -070040import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
41import android.hardware.fingerprint.Fingerprint;
Kevin Chyn037c4d52018-06-11 19:17:32 -070042import android.os.Binder;
43import android.os.Bundle;
Kevin Chyna56dff72018-06-19 18:41:12 -070044import android.os.DeadObjectException;
Kevin Chyn037c4d52018-06-11 19:17:32 -070045import android.os.Handler;
46import android.os.IBinder;
47import android.os.IHwBinder;
Kevin Chyna56dff72018-06-19 18:41:12 -070048import android.os.IRemoteCallback;
Kevin Chyn037c4d52018-06-11 19:17:32 -070049import android.os.PowerManager;
50import android.os.RemoteException;
Kevin Chyn5a2ff5d2018-08-29 19:07:30 -070051import android.os.ServiceManager;
Kevin Chyn037c4d52018-06-11 19:17:32 -070052import android.os.SystemClock;
53import android.os.UserHandle;
54import android.os.UserManager;
Kevin Chyn037c4d52018-06-11 19:17:32 -070055import android.util.Slog;
56import android.util.SparseBooleanArray;
57import android.util.SparseIntArray;
58
Kevin Chyn3a0187192018-10-08 15:40:05 -070059import com.android.internal.R;
Kevin Chyn037c4d52018-06-11 19:17:32 -070060import com.android.internal.logging.MetricsLogger;
61import com.android.internal.statusbar.IStatusBarService;
62import com.android.server.SystemService;
63import com.android.server.biometrics.fingerprint.FingerprintService;
64
65import java.util.ArrayList;
Kevin Chyna56dff72018-06-19 18:41:12 -070066import java.util.Collections;
Kevin Chyn037c4d52018-06-11 19:17:32 -070067import java.util.HashMap;
68import java.util.List;
Kevin Chyna56dff72018-06-19 18:41:12 -070069import java.util.Map;
Kevin Chyn037c4d52018-06-11 19:17:32 -070070
71/**
72 * Abstract base class containing all of the business logic for biometric services, e.g.
73 * Fingerprint, Face, Iris.
74 *
75 * @hide
76 */
Kevin Chyn355c6bf2018-09-20 22:14:19 -070077public abstract class BiometricServiceBase extends SystemService
78 implements IHwBinder.DeathRecipient {
Kevin Chyn037c4d52018-06-11 19:17:32 -070079
80 protected static final boolean DEBUG = true;
81
82 private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
83 private static final int MSG_USER_SWITCHING = 10;
84 private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30 * 1000;
85 private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
86
87 private final Context mContext;
88 private final String mKeyguardPackage;
Kevin Chyn037c4d52018-06-11 19:17:32 -070089 private final SparseBooleanArray mTimedLockoutCleared;
90 private final SparseIntArray mFailedAttempts;
91 private final IActivityTaskManager mActivityTaskManager;
92 private final AlarmManager mAlarmManager;
93 private final PowerManager mPowerManager;
94 private final UserManager mUserManager;
95 private final MetricsLogger mMetricsLogger;
96 private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener();
97 private final ResetClientStateRunnable mResetClientState = new ResetClientStateRunnable();
98 private final LockoutReceiver mLockoutReceiver = new LockoutReceiver();
Kevin Chyna56dff72018-06-19 18:41:12 -070099 private final ArrayList<LockoutResetMonitor> mLockoutMonitors = new ArrayList<>();
Kevin Chyn037c4d52018-06-11 19:17:32 -0700100
Kevin Chyn5a2ff5d2018-08-29 19:07:30 -0700101 protected final IStatusBarService mStatusBarService;
Kevin Chyna56dff72018-06-19 18:41:12 -0700102 protected final Map<Integer, Long> mAuthenticatorIds =
103 Collections.synchronizedMap(new HashMap<>());
104 protected final ResetFailedAttemptsForUserRunnable mResetFailedAttemptsForCurrentUserRunnable =
105 new ResetFailedAttemptsForUserRunnable();
Kevin Chynb3c05aa2018-09-21 16:50:32 -0700106 protected final AppOpsManager mAppOps;
Kevin Chyn037c4d52018-06-11 19:17:32 -0700107 protected final H mHandler = new H();
108
109 private ClientMonitor mCurrentClient;
110 private ClientMonitor mPendingClient;
111 private PerformanceStats mPerformanceStats;
112 protected int mCurrentUserId = UserHandle.USER_NULL;
Tej Singhd6d6d772018-09-05 17:41:25 -0700113 // Tracks if the current authentication makes use of CryptoObjects.
114 protected boolean mIsCrypto;
Kevin Chyn037c4d52018-06-11 19:17:32 -0700115 // Normal authentications are tracked by mPerformanceMap.
116 protected HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
117 // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
118 protected HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
119
120 protected class PerformanceStats {
121 public int accept; // number of accepted biometrics
122 public int reject; // number of rejected biometrics
123 public int acquire; // total number of acquisitions. Should be >= accept+reject due to poor
124 // image acquisition in some cases (too fast, too slow, dirty sensor, etc.)
125 public int lockout; // total number of lockouts
126 public int permanentLockout; // total number of permanent lockouts
127 }
128
129 /**
130 * @return the log tag.
131 */
132 protected abstract String getTag();
133
134 /**
Kevin Chyna56dff72018-06-19 18:41:12 -0700135 * @return the biometric utilities for a specific implementation.
136 */
137 protected abstract BiometricUtils getBiometricUtils();
138
139 /**
Kevin Chyn037c4d52018-06-11 19:17:32 -0700140 * @return the number of failed attempts after which the user will be temporarily locked out
141 * from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
142 */
143 protected abstract int getFailedAttemptsLockoutTimed();
144
145 /**
146 * @return the number of failed attempts after which the user will be permanently locked out
147 * from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
148 */
149 protected abstract int getFailedAttemptsLockoutPermanent();
150
151 /**
152 * @return the metrics constants for a biometric implementation.
153 */
154 protected abstract Metrics getMetrics();
155
156 /**
157 * @param userId
158 * @return true if the enrollment limit has been reached.
159 */
160 protected abstract boolean hasReachedEnrollmentLimit(int userId);
161
162 /**
163 * Notifies the HAL that the user has changed.
164 * @param userId
165 * @param clientPackage
166 */
167 protected abstract void updateActiveGroup(int userId, String clientPackage);
168
169 /**
170 * @return The protected intent to reset lockout for a specific biometric.
171 */
172 protected abstract String getLockoutResetIntent();
173
174 /**
175 * @return The permission the sender is required to have in order for the lockout reset intent
176 * to be received by the BiometricService implementation.
177 */
178 protected abstract String getLockoutBroadcastPermission();
179
180 /**
181 * @return The HAL ID.
182 */
183 protected abstract long getHalDeviceId();
184
185 /**
186 * This method is called when the user switches. Implementations should probably notify the
187 * HAL.
188 * @param userId
189 */
190 protected abstract void handleUserSwitching(int userId);
191
192 /**
193 * @param userId
194 * @return Returns true if the user has any enrolled biometrics.
195 */
196 protected abstract boolean hasEnrolledBiometrics(int userId);
197
198 /**
199 * @return Returns the MANAGE_* permission string, which is required for enrollment, removal
200 * etc.
201 */
202 protected abstract String getManageBiometricPermission();
203
204 /**
205 * Checks if the caller has permission to use the biometric service - throws a SecurityException
206 * if not.
207 */
208 protected abstract void checkUseBiometricPermission();
209
210 /**
Kevin Chynb3c05aa2018-09-21 16:50:32 -0700211 * Checks if the caller passes the app ops check
Kevin Chyn037c4d52018-06-11 19:17:32 -0700212 */
Kevin Chynb3c05aa2018-09-21 16:50:32 -0700213 protected abstract boolean checkAppOps(int uid, String opPackageName);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700214
215 /**
216 * Notifies clients of any change in the biometric state (active / idle). This is mainly for
217 * Fingerprint navigation gestures.
218 * @param isActive
219 */
220 protected void notifyClientActiveCallbacks(boolean isActive) {}
221
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700222 protected abstract class AuthenticationClientImpl extends AuthenticationClient {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700223
224 public AuthenticationClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
225 IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId,
226 boolean restricted, String owner, Bundle bundle,
227 IBiometricPromptReceiver dialogReceiver,
Kevin Chyn6cf54e82018-09-18 19:13:27 -0700228 IStatusBarService statusBarService, boolean requireConfirmation) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700229 super(context, getMetrics(), daemon, halDeviceId, token, listener,
230 targetUserId, groupId, opId, restricted, owner, bundle, dialogReceiver,
Kevin Chyn6cf54e82018-09-18 19:13:27 -0700231 statusBarService, requireConfirmation);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700232 }
233
234 @Override
235 public void onStart() {
236 try {
237 mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
238 } catch (RemoteException e) {
239 Slog.e(getTag(), "Could not register task stack listener", e);
240 }
241 }
242
243 @Override
244 public void onStop() {
245 try {
246 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
247 } catch (RemoteException e) {
248 Slog.e(getTag(), "Could not unregister task stack listener", e);
249 }
250 }
251
252 @Override
253 public void resetFailedAttempts() {
254 resetFailedAttemptsForUser(true /* clearAttemptCounter */,
255 ActivityManager.getCurrentUser());
256 }
257
258 @Override
259 public void notifyUserActivity() {
260 userActivity();
261 }
262
263 @Override
264 public int handleFailedAttempt() {
265 final int currentUser = ActivityManager.getCurrentUser();
266 mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
267 mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
268 final int lockoutMode = getLockoutMode();
269 if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
270 mPerformanceStats.permanentLockout++;
271 } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
272 mPerformanceStats.lockout++;
273 }
274
275 // Failing multiple times will continue to push out the lockout time
276 if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
277 scheduleLockoutResetForUser(currentUser);
278 return lockoutMode;
279 }
280 return AuthenticationClient.LOCKOUT_NONE;
281 }
Kevin Chyn6cf54e82018-09-18 19:13:27 -0700282
283 @Override
284 public void onAuthenticationConfirmed() {
285 removeClient(mCurrentClient);
286 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700287 }
288
289 protected class EnrollClientImpl extends EnrollClient {
290
291 public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
292 IBinder token, ServiceListener listener, int userId, int groupId,
293 byte[] cryptoToken, boolean restricted, String owner) {
294 super(context, getMetrics(), daemon, halDeviceId, token, listener,
Kevin Chyna56dff72018-06-19 18:41:12 -0700295 userId, groupId, cryptoToken, restricted, owner, getBiometricUtils());
Kevin Chyn037c4d52018-06-11 19:17:32 -0700296 }
297
298 @Override
299 public void notifyUserActivity() {
300 userActivity();
301 }
302 }
303
304 protected class RemovalClientImpl extends RemovalClient {
305 private boolean mShouldNotify;
306
307 public RemovalClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
308 IBinder token, ServiceListener listener, int fingerId, int groupId, int userId,
309 boolean restricted, String owner) {
310 super(context, getMetrics(), daemon, halDeviceId, token, listener, fingerId, groupId,
Kevin Chyna56dff72018-06-19 18:41:12 -0700311 userId, restricted, owner, getBiometricUtils());
Kevin Chyn037c4d52018-06-11 19:17:32 -0700312 }
313
314 public void setShouldNotifyUserActivity(boolean shouldNotify) {
315 mShouldNotify = shouldNotify;
316 }
317
318 @Override
319 public void notifyUserActivity() {
320 if (mShouldNotify) {
321 userActivity();
322 }
323 }
324 }
325
326 protected class EnumerateClientImpl extends EnumerateClient {
327
328 public EnumerateClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
329 IBinder token, ServiceListener listener, int groupId, int userId,
330 boolean restricted, String owner) {
331 super(context, getMetrics(), daemon, halDeviceId, token, listener, groupId, userId,
332 restricted, owner);
333 }
334
335 @Override
336 public void notifyUserActivity() {
337 userActivity();
338 }
339 }
340
341 /**
342 * Wraps the callback interface from Service -> Manager
343 */
344 protected interface ServiceListener {
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700345 default void onEnrollResult(BiometricAuthenticator.Identifier identifier,
346 int remaining) throws RemoteException {};
Kevin Chyn037c4d52018-06-11 19:17:32 -0700347
348 void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
349 throws RemoteException;
350
351 void onAuthenticationSucceeded(long deviceId,
Kevin Chyna56dff72018-06-19 18:41:12 -0700352 BiometricAuthenticator.Identifier biometric, int userId)
Kevin Chyn037c4d52018-06-11 19:17:32 -0700353 throws RemoteException;
354
355 void onAuthenticationFailed(long deviceId)
356 throws RemoteException;
357
358 void onError(long deviceId, int error, int vendorCode)
359 throws RemoteException;
360
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700361 default void onRemoved(BiometricAuthenticator.Identifier identifier,
362 int remaining) throws RemoteException {};
Kevin Chyn037c4d52018-06-11 19:17:32 -0700363
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700364 default void onEnumerated(BiometricAuthenticator.Identifier identifier,
365 int remaining) throws RemoteException {};
Kevin Chyn037c4d52018-06-11 19:17:32 -0700366 }
367
368 /**
369 * Wraps a portion of the interface from Service -> Daemon that is used by the ClientMonitor
370 * subclasses.
371 */
372 protected interface DaemonWrapper {
Kevin Chyna56dff72018-06-19 18:41:12 -0700373 int ERROR_ESRCH = 3; // Likely fingerprint HAL is dead. see errno.h.
Kevin Chyn037c4d52018-06-11 19:17:32 -0700374 int authenticate(long operationId, int groupId) throws RemoteException;
375 int cancel() throws RemoteException;
376 int remove(int groupId, int biometricId) throws RemoteException;
377 int enumerate() throws RemoteException;
378 int enroll(byte[] cryptoToken, int groupId, int timeout) throws RemoteException;
379 }
380
381 /**
382 * Handler which all subclasses should post events to.
383 */
384 protected final class H extends Handler {
385 @Override
386 public void handleMessage(android.os.Message msg) {
387 switch (msg.what) {
388 case MSG_USER_SWITCHING:
389 handleUserSwitching(msg.arg1);
390 break;
391
392 default:
393 Slog.w(getTag(), "Unknown message:" + msg.what);
394 }
395 }
Kevin Chyna56dff72018-06-19 18:41:12 -0700396 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700397
398 private final class BiometricTaskStackListener extends TaskStackListener {
399 @Override
400 public void onTaskStackChanged() {
401 try {
402 if (!(mCurrentClient instanceof AuthenticationClient)) {
403 return;
404 }
405 final String currentClient = mCurrentClient.getOwnerString();
406 if (isKeyguard(currentClient)) {
407 return; // Keyguard is always allowed
408 }
409 List<ActivityManager.RunningTaskInfo> runningTasks =
410 mActivityTaskManager.getTasks(1);
411 if (!runningTasks.isEmpty()) {
412 final String topPackage = runningTasks.get(0).topActivity.getPackageName();
Kevin Chync79856b2018-10-05 18:57:35 -0700413 if (!topPackage.contentEquals(currentClient)
414 && !mCurrentClient.isAlreadyDone()) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700415 Slog.e(getTag(), "Stopping background authentication, top: " + topPackage
416 + " currentClient: " + currentClient);
417 mCurrentClient.stop(false /* initiatedByClient */);
418 }
419 }
420 } catch (RemoteException e) {
421 Slog.e(getTag(), "Unable to get running tasks", e);
422 }
423 }
Kevin Chyna56dff72018-06-19 18:41:12 -0700424 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700425
426 private final class ResetClientStateRunnable implements Runnable {
427 @Override
428 public void run() {
429 /**
430 * Warning: if we get here, the driver never confirmed our call to cancel the current
431 * operation (authenticate, enroll, remove, enumerate, etc), which is
432 * really bad. The result will be a 3-second delay in starting each new client.
433 * If you see this on a device, make certain the driver notifies with
434 * {@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} in response to cancel()
435 * once it has successfully switched to the IDLE state in the HAL.
436 * Additionally,{@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} should only be sent
437 * in response to an actual cancel() call.
438 */
439 Slog.w(getTag(), "Client "
440 + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
441 + " failed to respond to cancel, starting client "
442 + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
443
444 mCurrentClient = null;
445 startClient(mPendingClient, false);
446 }
Kevin Chyna56dff72018-06-19 18:41:12 -0700447 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700448
449 private final class LockoutReceiver extends BroadcastReceiver {
450 @Override
451 public void onReceive(Context context, Intent intent) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700452 Slog.v(getTag(), "Resetting lockout: " + intent.getAction());
Kevin Chyn037c4d52018-06-11 19:17:32 -0700453 if (getLockoutResetIntent().equals(intent.getAction())) {
454 final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
455 resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
456 }
457 }
Kevin Chyna56dff72018-06-19 18:41:12 -0700458 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700459
Kevin Chyna56dff72018-06-19 18:41:12 -0700460 private final class ResetFailedAttemptsForUserRunnable implements Runnable {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700461 @Override
462 public void run() {
463 resetFailedAttemptsForUser(true /* clearAttemptCounter */,
464 ActivityManager.getCurrentUser());
465 }
Kevin Chyna56dff72018-06-19 18:41:12 -0700466 }
467
468 private final class LockoutResetMonitor implements IBinder.DeathRecipient {
469 private static final long WAKELOCK_TIMEOUT_MS = 2000;
470 private final IBiometricServiceLockoutResetCallback mCallback;
471 private final PowerManager.WakeLock mWakeLock;
472
473 public LockoutResetMonitor(IBiometricServiceLockoutResetCallback callback) {
474 mCallback = callback;
475 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
476 "lockout reset callback");
477 try {
478 mCallback.asBinder().linkToDeath(LockoutResetMonitor.this, 0);
479 } catch (RemoteException e) {
480 Slog.w(getTag(), "caught remote exception in linkToDeath", e);
481 }
482 }
483
484 public void sendLockoutReset() {
485 if (mCallback != null) {
486 try {
487 mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
488 mCallback.onLockoutReset(getHalDeviceId(), new IRemoteCallback.Stub() {
489 @Override
490 public void sendResult(Bundle data) throws RemoteException {
491 releaseWakelock();
492 }
493 });
494 } catch (DeadObjectException e) {
495 Slog.w(getTag(), "Death object while invoking onLockoutReset: ", e);
496 mHandler.post(mRemoveCallbackRunnable);
497 } catch (RemoteException e) {
498 Slog.w(getTag(), "Failed to invoke onLockoutReset: ", e);
499 releaseWakelock();
500 }
501 }
502 }
503
504 private final Runnable mRemoveCallbackRunnable = new Runnable() {
505 @Override
506 public void run() {
507 releaseWakelock();
508 removeLockoutResetCallback(LockoutResetMonitor.this);
509 }
510 };
511
512 @Override
513 public void binderDied() {
514 Slog.e(getTag(), "Lockout reset callback binder died");
515 mHandler.post(mRemoveCallbackRunnable);
516 }
517
518 private void releaseWakelock() {
519 if (mWakeLock.isHeld()) {
520 mWakeLock.release();
521 }
522 }
523 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700524
525 /**
526 * Initializes the system service.
527 * <p>
528 * Subclasses must define a single argument constructor that accepts the context
529 * and passes it to super.
530 * </p>
531 *
532 * @param context The system server context.
533 */
Kevin Chyn355c6bf2018-09-20 22:14:19 -0700534 public BiometricServiceBase(Context context) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700535 super(context);
536 mContext = context;
Kevin Chyn5a2ff5d2018-08-29 19:07:30 -0700537 mStatusBarService = IStatusBarService.Stub.asInterface(
538 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
Kevin Chyn037c4d52018-06-11 19:17:32 -0700539 mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
540 com.android.internal.R.string.config_keyguardComponent)).getPackageName();
541 mAppOps = context.getSystemService(AppOpsManager.class);
542 mTimedLockoutCleared = new SparseBooleanArray();
543 mFailedAttempts = new SparseIntArray();
544 mActivityTaskManager = ((ActivityTaskManager) context.getSystemService(
545 Context.ACTIVITY_TASK_SERVICE)).getService();
546 mPowerManager = mContext.getSystemService(PowerManager.class);
547 mAlarmManager = mContext.getSystemService(AlarmManager.class);
548 mUserManager = UserManager.get(mContext);
549 mMetricsLogger = new MetricsLogger();
550 mContext.registerReceiver(mLockoutReceiver, new IntentFilter(getLockoutResetIntent()),
551 getLockoutBroadcastPermission(), null /* handler */);
552 }
553
554 @Override
555 public void onStart() {
556 listenForUserSwitches();
557 }
558
559 @Override
560 public void serviceDied(long cookie) {
561 Slog.e(getTag(), "HAL died");
562 mMetricsLogger.count(getMetrics().tagHalDied(), 1);
563 handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
564 0 /*vendorCode */);
565 }
566
567 protected ClientMonitor getCurrentClient() {
568 return mCurrentClient;
569 }
570
571 protected ClientMonitor getPendingClient() {
572 return mPendingClient;
573 }
574
575 /**
576 * Callback handlers from the daemon. The caller must put this on a handler.
577 */
578
579 protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
580 ClientMonitor client = mCurrentClient;
581 if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
582 removeClient(client);
583 }
584 if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
585 && client instanceof AuthenticationClient) {
586 // ignore enrollment acquisitions or acquisitions when we're locked out
587 mPerformanceStats.acquire++;
588 }
589 }
590
Kevin Chynb528d692018-07-20 11:53:14 -0700591 protected void handleAuthenticated(BiometricAuthenticator.Identifier identifier,
Kevin Chyn037c4d52018-06-11 19:17:32 -0700592 ArrayList<Byte> token) {
593 ClientMonitor client = mCurrentClient;
Kevin Chynb528d692018-07-20 11:53:14 -0700594 final boolean authenticated = identifier.getBiometricId() != 0;
595
Kevin Chyn6cf54e82018-09-18 19:13:27 -0700596 if (client != null && client.onAuthenticated(identifier, authenticated, token)) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700597 removeClient(client);
598 }
Kevin Chynb528d692018-07-20 11:53:14 -0700599 if (authenticated) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700600 mPerformanceStats.accept++;
601 } else {
602 mPerformanceStats.reject++;
603 }
604 }
605
Kevin Chyna56dff72018-06-19 18:41:12 -0700606 protected void handleEnrollResult(BiometricAuthenticator.Identifier identifier,
607 int remaining) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700608 ClientMonitor client = mCurrentClient;
Kevin Chyna56dff72018-06-19 18:41:12 -0700609 if (client != null && client.onEnrollResult(identifier, remaining)) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700610 removeClient(client);
611 // When enrollment finishes, update this group's authenticator id, as the HAL has
612 // already generated a new authenticator id when the new biometric is enrolled.
Kevin Chyna56dff72018-06-19 18:41:12 -0700613 if (identifier instanceof Fingerprint) {
614 updateActiveGroup(((Fingerprint)identifier).getGroupId(), null);
615 } else {
616 updateActiveGroup(mCurrentUserId, null);
617 }
618
Kevin Chyn037c4d52018-06-11 19:17:32 -0700619 }
620 }
621
622 protected void handleError(long deviceId, int error, int vendorCode) {
623 final ClientMonitor client = mCurrentClient;
624
625 if (DEBUG) Slog.v(getTag(), "handleError(client="
626 + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
627
Kevin Chyna56dff72018-06-19 18:41:12 -0700628 if (client != null && client.onError(deviceId, error, vendorCode)) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700629 removeClient(client);
630 }
631
632 if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
633 mHandler.removeCallbacks(mResetClientState);
634 if (mPendingClient != null) {
Kevin Chyn355c6bf2018-09-20 22:14:19 -0700635 if (DEBUG) Slog.v(getTag(), "start pending client " +
636 mPendingClient.getOwnerString());
Kevin Chyn037c4d52018-06-11 19:17:32 -0700637 startClient(mPendingClient, false);
638 mPendingClient = null;
639 }
640 }
641 }
642
Kevin Chyna56dff72018-06-19 18:41:12 -0700643 protected void handleRemoved(BiometricAuthenticator.Identifier identifier,
Kevin Chyn037c4d52018-06-11 19:17:32 -0700644 final int remaining) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700645 if (DEBUG) Slog.w(getTag(), "Removed: fid=" + identifier.getBiometricId()
646 + ", dev=" + identifier.getDeviceId()
Kevin Chyn037c4d52018-06-11 19:17:32 -0700647 + ", rem=" + remaining);
648
649 ClientMonitor client = mCurrentClient;
Kevin Chyna56dff72018-06-19 18:41:12 -0700650 if (client != null && client.onRemoved(identifier, remaining)) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700651 removeClient(client);
652 // When the last biometric of a group is removed, update the authenticator id
Kevin Chyna56dff72018-06-19 18:41:12 -0700653 int userId = mCurrentUserId;
654 if (identifier instanceof Fingerprint) {
655 userId = ((Fingerprint) identifier).getGroupId();
656 }
657 if (!hasEnrolledBiometrics(userId)) {
658 updateActiveGroup(userId, null);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700659 }
660 }
661 }
662
663 /**
664 * Calls from the Manager. These are still on the calling binder's thread.
665 */
666
667 protected void enrollInternal(EnrollClientImpl client, int userId) {
668 if (hasReachedEnrollmentLimit(userId)) {
669 return;
670 }
671
672 // Group ID is arbitrarily set to parent profile user ID. It just represents
673 // the default biometrics for the user.
674 if (!isCurrentUserOrProfile(userId)) {
675 return;
676 }
677
678 mHandler.post(() -> {
679 startClient(client, true /* initiatedByClient */);
680 });
681 }
682
683 protected void cancelEnrollmentInternal(IBinder token) {
684 mHandler.post(() -> {
685 ClientMonitor client = mCurrentClient;
686 if (client instanceof EnrollClient && client.getToken() == token) {
687 client.stop(client.getToken() == token);
688 }
689 });
690 }
691
692 protected void authenticateInternal(AuthenticationClientImpl client, long opId,
693 String opPackageName) {
694 final int callingUid = Binder.getCallingUid();
695 final int callingPid = Binder.getCallingPid();
696 final int callingUserId = UserHandle.getCallingUserId();
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700697 authenticateInternal(client, opId, opPackageName, callingUid, callingPid, callingUserId);
698 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700699
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700700 protected void authenticateInternal(AuthenticationClientImpl client, long opId,
701 String opPackageName, int callingUid, int callingPid, int callingUserId) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700702 if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
703 callingUserId)) {
704 if (DEBUG) Slog.v(getTag(), "authenticate(): reject " + opPackageName);
705 return;
706 }
707
708 mHandler.post(() -> {
Kevin Chyn3a0187192018-10-08 15:40:05 -0700709 if (client.isBiometricPrompt()) {
710 try {
711 final List<ActivityManager.RunningAppProcessInfo> procs =
712 ActivityManager.getService().getRunningAppProcesses();
713 for (int i = 0; i < procs.size(); i++) {
714 final ActivityManager.RunningAppProcessInfo info = procs.get(i);
715 if (info.uid == callingUid && info.importance == IMPORTANCE_FOREGROUND) {
716 PackageManager pm = getContext().getPackageManager();
717 final CharSequence label = pm.getApplicationLabel(
718 pm.getApplicationInfo(info.processName,
719 PackageManager.GET_META_DATA));
720 final String title = getContext()
721 .getString(R.string.biometric_dialog_default_title, label);
722 client.setTitleIfEmpty(title);
723 break;
724 }
725 }
726 } catch (RemoteException e) {
727 Slog.e(getTag(), "Unable to get application name", e);
728 } catch (PackageManager.NameNotFoundException e) {
729 Slog.e(getTag(), "Unable to get application name", e);
730 }
731 }
732
Kevin Chyn037c4d52018-06-11 19:17:32 -0700733 mMetricsLogger.histogram(getMetrics().tagAuthToken(), opId != 0L ? 1 : 0);
734
735 // Get performance stats object for this user.
736 HashMap<Integer, PerformanceStats> pmap
737 = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
738 PerformanceStats stats = pmap.get(mCurrentUserId);
739 if (stats == null) {
740 stats = new PerformanceStats();
741 pmap.put(mCurrentUserId, stats);
742 }
743 mPerformanceStats = stats;
Tej Singhd6d6d772018-09-05 17:41:25 -0700744 mIsCrypto = (opId != 0);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700745
746 startAuthentication(client, opPackageName);
747 });
748 }
749
750 protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName) {
751 final int callingUid = Binder.getCallingUid();
752 final int callingPid = Binder.getCallingPid();
753 final int callingUserId = UserHandle.getCallingUserId();
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700754 cancelAuthenticationInternal(token, opPackageName, callingUid, callingPid, callingUserId);
755 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700756
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700757 protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName,
758 int callingUid, int callingPid, int callingUserId) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700759 if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
760 callingUserId)) {
761 if (DEBUG) Slog.v(getTag(), "cancelAuthentication(): reject " + opPackageName);
762 return;
763 }
764
765 mHandler.post(() -> {
766 ClientMonitor client = mCurrentClient;
767 if (client instanceof AuthenticationClient) {
768 if (client.getToken() == token) {
769 if (DEBUG) Slog.v(getTag(), "stop client " + client.getOwnerString());
770 client.stop(client.getToken() == token);
771 } else {
772 if (DEBUG) Slog.v(getTag(), "can't stop client "
773 + client.getOwnerString() + " since tokens don't match");
774 }
775 } else if (client != null) {
776 if (DEBUG) Slog.v(getTag(), "can't cancel non-authenticating client "
777 + client.getOwnerString());
778 }
779 });
780 }
781
782 protected void setActiveUserInternal(int userId) {
783 mHandler.post(() -> {
784 updateActiveGroup(userId, null /* clientPackage */);
785 });
786 }
787
788 protected void removeInternal(RemovalClientImpl client) {
789 mHandler.post(() -> {
790 startClient(client, true /* initiatedByClient */);
791 });
792 }
793
794 protected void enumerateInternal(EnumerateClientImpl client) {
795 mHandler.post(() -> {
796 startClient(client, true /* initiatedByClient */);
797 });
798 }
799
800 // Should be done on a handler thread - not on the Binder's thread.
801 private void startAuthentication(AuthenticationClientImpl client, String opPackageName) {
802 updateActiveGroup(client.getGroupId(), opPackageName);
803
804 if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")");
805
806 int lockoutMode = getLockoutMode();
807 if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
808 Slog.v(getTag(), "In lockout mode(" + lockoutMode +
809 ") ; disallowing authentication");
810 int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
811 BiometricConstants.BIOMETRIC_ERROR_LOCKOUT :
812 BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
Kevin Chyna56dff72018-06-19 18:41:12 -0700813 if (!client.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */)) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700814 Slog.w(getTag(), "Cannot send permanent lockout message to client");
815 }
816 return;
817 }
818 startClient(client, true /* initiatedByClient */);
819 }
820
Kevin Chyna56dff72018-06-19 18:41:12 -0700821 protected void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback) {
822 mHandler.post(() -> {
823 final LockoutResetMonitor monitor = new LockoutResetMonitor(callback);
824 if (!mLockoutMonitors.contains(monitor)) {
825 mLockoutMonitors.add(monitor);
826 }
827 });
828 }
829
Kevin Chyn037c4d52018-06-11 19:17:32 -0700830 /**
831 * Helper methods.
832 */
833
834 /**
835 * @param opPackageName name of package for caller
836 * @param requireForeground only allow this call while app is in the foreground
837 * @return true if caller can use the biometric API
838 */
839 protected boolean canUseBiometric(String opPackageName, boolean requireForeground, int uid,
840 int pid, int userId) {
841 checkUseBiometricPermission();
842
843 if (isKeyguard(opPackageName)) {
844 return true; // Keyguard is always allowed
845 }
846 if (!isCurrentUserOrProfile(userId)) {
847 Slog.w(getTag(), "Rejecting " + opPackageName + "; not a current user or profile");
848 return false;
849 }
Kevin Chynb3c05aa2018-09-21 16:50:32 -0700850 if (!checkAppOps(uid, opPackageName)) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700851 Slog.w(getTag(), "Rejecting " + opPackageName + "; permission denied");
852 return false;
853 }
Kevin Chynb3c05aa2018-09-21 16:50:32 -0700854
Kevin Chyn037c4d52018-06-11 19:17:32 -0700855 if (requireForeground && !(isForegroundActivity(uid, pid) || isCurrentClient(
856 opPackageName))) {
857 Slog.w(getTag(), "Rejecting " + opPackageName + "; not in foreground");
858 return false;
859 }
860 return true;
861 }
862
863 /**
864 * @param opPackageName package of the caller
865 * @return true if this is the same client currently using the biometric
866 */
867 private boolean isCurrentClient(String opPackageName) {
868 return mCurrentClient != null && mCurrentClient.getOwnerString().equals(opPackageName);
869 }
870
871 /**
872 * @return true if this is keyguard package
873 */
874 private boolean isKeyguard(String clientPackage) {
875 return mKeyguardPackage.equals(clientPackage);
876 }
877
Tej Singhd6d6d772018-09-05 17:41:25 -0700878 protected int getLockoutMode() {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700879 final int currentUser = ActivityManager.getCurrentUser();
880 final int failedAttempts = mFailedAttempts.get(currentUser, 0);
881 if (failedAttempts >= getFailedAttemptsLockoutPermanent()) {
882 return AuthenticationClient.LOCKOUT_PERMANENT;
883 } else if (failedAttempts > 0 &&
884 mTimedLockoutCleared.get(currentUser, false) == false
885 && (failedAttempts % getFailedAttemptsLockoutTimed() == 0)) {
886 return AuthenticationClient.LOCKOUT_TIMED;
887 }
888 return AuthenticationClient.LOCKOUT_NONE;
889 }
890
891 private boolean isForegroundActivity(int uid, int pid) {
892 try {
893 List<ActivityManager.RunningAppProcessInfo> procs =
894 ActivityManager.getService().getRunningAppProcesses();
895 int N = procs.size();
896 for (int i = 0; i < N; i++) {
897 ActivityManager.RunningAppProcessInfo proc = procs.get(i);
898 if (proc.pid == pid && proc.uid == uid
899 && proc.importance <= IMPORTANCE_FOREGROUND_SERVICE) {
900 return true;
901 }
902 }
903 } catch (RemoteException e) {
904 Slog.w(getTag(), "am.getRunningAppProcesses() failed");
905 }
906 return false;
907 }
908
909 /**
910 * Calls the HAL to switch states to the new task. If there's already a current task,
911 * it calls cancel() and sets mPendingClient to begin when the current task finishes
912 * ({@link BiometricConstants#BIOMETRIC_ERROR_CANCELED}).
913 *
914 * @param newClient the new client that wants to connect
915 * @param initiatedByClient true for authenticate, remove and enroll
916 */
917 private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
918 ClientMonitor currentClient = mCurrentClient;
919 if (currentClient != null) {
920 if (DEBUG) Slog.v(getTag(), "request stop current client " +
921 currentClient.getOwnerString());
922
923 // This check only matters for FingerprintService, since enumerate may call back
924 // multiple times.
925 if (currentClient instanceof FingerprintService.EnumerateClientImpl ||
926 currentClient instanceof FingerprintService.RemovalClientImpl) {
927 // This condition means we're currently running internal diagnostics to
928 // remove extra fingerprints in the hardware and/or the software
929 // TODO: design an escape hatch in case client never finishes
930 if (newClient != null) {
931 Slog.w(getTag(), "Internal cleanup in progress but trying to start client "
932 + newClient.getClass().getSuperclass().getSimpleName()
933 + "(" + newClient.getOwnerString() + ")"
934 + ", initiatedByClient = " + initiatedByClient);
935 }
936 } else {
937 currentClient.stop(initiatedByClient);
938 }
939 mPendingClient = newClient;
940 mHandler.removeCallbacks(mResetClientState);
941 mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
942 } else if (newClient != null) {
943 mCurrentClient = newClient;
944 if (DEBUG) Slog.v(getTag(), "starting client "
945 + newClient.getClass().getSuperclass().getSimpleName()
946 + "(" + newClient.getOwnerString() + ")"
947 + ", initiatedByClient = " + initiatedByClient);
948 notifyClientActiveCallbacks(true);
949
950 newClient.start();
951 }
952 }
953
954 protected void removeClient(ClientMonitor client) {
955 if (client != null) {
956 client.destroy();
957 if (client != mCurrentClient && mCurrentClient != null) {
958 Slog.w(getTag(), "Unexpected client: " + client.getOwnerString() + "expected: "
959 + mCurrentClient.getOwnerString());
960 }
961 }
962 if (mCurrentClient != null) {
963 if (DEBUG) Slog.v(getTag(), "Done with client: " + client.getOwnerString());
964 mCurrentClient = null;
965 }
966 if (mPendingClient == null) {
967 notifyClientActiveCallbacks(false);
968 }
969 }
970
971 /**
Kevin Chyna56dff72018-06-19 18:41:12 -0700972 * Populates existing authenticator ids. To be used only during the start of the service.
973 */
974 protected void loadAuthenticatorIds() {
975 // This operation can be expensive, so keep track of the elapsed time. Might need to move to
976 // background if it takes too long.
977 long t = System.currentTimeMillis();
978 mAuthenticatorIds.clear();
979 for (UserInfo user : UserManager.get(getContext()).getUsers(true /* excludeDying */)) {
980 int userId = getUserOrWorkProfileId(null, user.id);
981 if (!mAuthenticatorIds.containsKey(userId)) {
982 updateActiveGroup(userId, null);
983 }
984 }
985
986 t = System.currentTimeMillis() - t;
987 if (t > 1000) {
988 Slog.w(getTag(), "loadAuthenticatorIds() taking too long: " + t + "ms");
989 }
990 }
991
992 /**
Kevin Chyn037c4d52018-06-11 19:17:32 -0700993 * @param clientPackage the package of the caller
994 * @return the profile id
995 */
996 protected int getUserOrWorkProfileId(String clientPackage, int userId) {
997 if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
998 return userId;
999 }
1000 return getEffectiveUserId(userId);
1001 }
1002
1003 protected boolean isRestricted() {
1004 // Only give privileged apps (like Settings) access to biometric info
1005 final boolean restricted = !hasPermission(getManageBiometricPermission());
1006 return restricted;
1007 }
1008
1009 protected boolean hasPermission(String permission) {
1010 return getContext().checkCallingOrSelfPermission(permission)
1011 == PackageManager.PERMISSION_GRANTED;
1012 }
1013
1014 protected void checkPermission(String permission) {
1015 getContext().enforceCallingOrSelfPermission(permission,
1016 "Must have " + permission + " permission.");
1017 }
1018
1019 protected boolean isCurrentUserOrProfile(int userId) {
1020 UserManager um = UserManager.get(mContext);
1021 if (um == null) {
1022 Slog.e(getTag(), "Unable to acquire UserManager");
1023 return false;
1024 }
1025
1026 final long token = Binder.clearCallingIdentity();
1027 try {
1028 // Allow current user or profiles of the current user...
1029 for (int profileId : um.getEnabledProfileIds(ActivityManager.getCurrentUser())) {
1030 if (profileId == userId) {
1031 return true;
1032 }
1033 }
1034 } finally {
1035 Binder.restoreCallingIdentity(token);
1036 }
1037
1038 return false;
1039 }
1040
Kevin Chyna56dff72018-06-19 18:41:12 -07001041 /***
1042 * @param opPackageName the name of the calling package
1043 * @return authenticator id for the calling user
1044 */
1045 protected long getAuthenticatorId(String opPackageName) {
1046 final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
1047 return mAuthenticatorIds.getOrDefault(userId, 0L);
1048 }
1049
Kevin Chyn037c4d52018-06-11 19:17:32 -07001050 private void scheduleLockoutResetForUser(int userId) {
1051 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1052 SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
1053 getLockoutResetIntentForUser(userId));
1054 }
1055
1056 private PendingIntent getLockoutResetIntentForUser(int userId) {
1057 return PendingIntent.getBroadcast(mContext, userId,
1058 new Intent(getLockoutResetIntent()).putExtra(KEY_LOCKOUT_RESET_USER, userId),
1059 PendingIntent.FLAG_UPDATE_CURRENT);
1060 }
1061
1062 private void userActivity() {
1063 long now = SystemClock.uptimeMillis();
1064 mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
1065 }
1066
1067 /**
1068 * @param userId
1069 * @return true if this is a work profile
1070 */
1071 private boolean isWorkProfile(int userId) {
1072 UserInfo userInfo = null;
1073 final long token = Binder.clearCallingIdentity();
1074 try {
1075 userInfo = mUserManager.getUserInfo(userId);
1076 } finally {
1077 Binder.restoreCallingIdentity(token);
1078 }
1079 return userInfo != null && userInfo.isManagedProfile();
1080 }
1081
1082
1083 private int getEffectiveUserId(int userId) {
1084 UserManager um = UserManager.get(mContext);
1085 if (um != null) {
1086 final long callingIdentity = Binder.clearCallingIdentity();
1087 userId = um.getCredentialOwnerProfile(userId);
1088 Binder.restoreCallingIdentity(callingIdentity);
1089 } else {
1090 Slog.e(getTag(), "Unable to acquire UserManager");
1091 }
1092 return userId;
1093 }
1094
1095 // Attempt counter should only be cleared when Keyguard goes away or when
1096 // a biometric is successfully authenticated.
1097 private void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
1098 if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
1099 Slog.v(getTag(), "Reset biometric lockout, clearAttemptCounter=" + clearAttemptCounter);
1100 }
1101 if (clearAttemptCounter) {
1102 mFailedAttempts.put(userId, 0);
1103 }
1104 mTimedLockoutCleared.put(userId, true);
1105 // If we're asked to reset failed attempts externally (i.e. from Keyguard),
1106 // the alarm might still be pending; remove it.
1107 cancelLockoutResetForUser(userId);
1108 notifyLockoutResetMonitors();
1109 }
1110
1111 private void cancelLockoutResetForUser(int userId) {
1112 mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
1113 }
1114
1115 private void listenForUserSwitches() {
1116 try {
1117 ActivityManager.getService().registerUserSwitchObserver(
1118 new SynchronousUserSwitchObserver() {
1119 @Override
1120 public void onUserSwitching(int newUserId) throws RemoteException {
1121 mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
1122 .sendToTarget();
1123 }
1124 }, getTag());
1125 } catch (RemoteException e) {
1126 Slog.w(getTag(), "Failed to listen for user switching event" ,e);
1127 }
1128 }
1129
Kevin Chyna56dff72018-06-19 18:41:12 -07001130 private void notifyLockoutResetMonitors() {
1131 for (int i = 0; i < mLockoutMonitors.size(); i++) {
1132 mLockoutMonitors.get(i).sendLockoutReset();
1133 }
1134 }
1135
1136 private void removeLockoutResetCallback(
1137 LockoutResetMonitor monitor) {
1138 mLockoutMonitors.remove(monitor);
1139 }
Kevin Chyn8b7a0372018-09-17 15:06:05 -07001140}