blob: 24fd1b7a6daf7bcbdc5b434af65848c4b79724a0 [file] [log] [blame]
Charles He959ac8e2017-03-27 21:16:20 +01001/*
Jim Millera75961472014-06-06 15:00:49 -07002 * Copyright (C) 2014 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
Kevin Chyn95d628e2018-06-11 11:58:15 -070017package com.android.server.biometrics.fingerprint;
Jim Millera75961472014-06-06 15:00:49 -070018
Charles He959ac8e2017-03-27 21:16:20 +010019import static android.Manifest.permission.INTERACT_ACROSS_USERS;
Kevin Chyna24e9fd2018-08-27 12:39:17 -070020import static android.Manifest.permission.MANAGE_BIOMETRIC;
Charles He959ac8e2017-03-27 21:16:20 +010021import static android.Manifest.permission.MANAGE_FINGERPRINT;
22import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
Vishwath Mohancf87df12018-03-20 22:57:17 -070023import static android.Manifest.permission.USE_BIOMETRIC;
Charles He959ac8e2017-03-27 21:16:20 +010024import static android.Manifest.permission.USE_FINGERPRINT;
25
Sasha Levitskiy80db9ba2015-05-08 14:31:48 -070026import android.app.ActivityManager;
Kevin Chyna38653c2019-02-11 17:46:21 -080027import android.app.AlarmManager;
Svetoslav4af76a52015-04-29 15:29:46 -070028import android.app.AppOpsManager;
Kevin Chyna38653c2019-02-11 17:46:21 -080029import android.app.PendingIntent;
30import android.content.BroadcastReceiver;
Jim Millera75961472014-06-06 15:00:49 -070031import android.content.Context;
Kevin Chyna38653c2019-02-11 17:46:21 -080032import android.content.Intent;
33import android.content.IntentFilter;
Jim Millerf501b582015-06-03 16:36:31 -070034import android.content.pm.PackageManager;
Jim Millercb7d9e92015-06-16 15:05:48 -070035import android.content.pm.UserInfo;
Kevin Chyn037c4d52018-06-11 19:17:32 -070036import android.hardware.biometrics.BiometricAuthenticator;
37import android.hardware.biometrics.BiometricConstants;
Kevin Chyn7782d142019-01-18 12:51:33 -080038import android.hardware.biometrics.BiometricsProtoEnums;
Kevin Chyna56dff72018-06-19 18:41:12 -070039import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
Kevin Chyn23289ef2018-11-28 16:32:36 -080040import android.hardware.biometrics.IBiometricServiceReceiverInternal;
Charles He959ac8e2017-03-27 21:16:20 +010041import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
42import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
43import android.hardware.fingerprint.Fingerprint;
Kevin Chyna24e9fd2018-08-27 12:39:17 -070044import android.hardware.fingerprint.FingerprintManager;
Phil Weaver27fcd9c2017-01-20 15:57:24 -080045import android.hardware.fingerprint.IFingerprintClientActiveCallback;
Charles He959ac8e2017-03-27 21:16:20 +010046import android.hardware.fingerprint.IFingerprintService;
Charles He959ac8e2017-03-27 21:16:20 +010047import android.hardware.fingerprint.IFingerprintServiceReceiver;
Svetoslav4af76a52015-04-29 15:29:46 -070048import android.os.Binder;
Andreas Huber7fe20532018-01-22 11:26:44 -080049import android.os.Build;
Sasha Levitskiy80db9ba2015-05-08 14:31:48 -070050import android.os.Environment;
Jim Millera75961472014-06-06 15:00:49 -070051import android.os.IBinder;
Jim Millera75961472014-06-06 15:00:49 -070052import android.os.RemoteException;
Jim Miller16ef71f2015-05-21 17:02:21 -070053import android.os.SELinux;
Kevin Chyna38653c2019-02-11 17:46:21 -080054import android.os.SystemClock;
Jim Miller599ef0e2015-06-15 20:39:44 -070055import android.os.UserHandle;
Jim Millercb7d9e92015-06-16 15:05:48 -070056import android.os.UserManager;
Jim Millera75961472014-06-06 15:00:49 -070057import android.util.Slog;
Kevin Chyna38653c2019-02-11 17:46:21 -080058import android.util.SparseBooleanArray;
59import android.util.SparseIntArray;
Joe Onorato1754d742016-11-21 17:51:35 -080060import android.util.proto.ProtoOutputStream;
Jim Millera75961472014-06-06 15:00:49 -070061
Fyodor Kupolov449e7082016-10-31 15:06:12 -070062import com.android.internal.annotations.GuardedBy;
Chris Wrenc510ad52015-08-14 15:43:15 -040063import com.android.internal.logging.MetricsLogger;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060064import com.android.internal.util.DumpUtils;
Fyodor Kupolove29a5a12016-12-16 16:14:17 -080065import com.android.server.SystemServerInitThreadPool;
Kevin Chyna38653c2019-02-11 17:46:21 -080066import com.android.server.biometrics.AuthenticationClient;
Kevin Chyn355c6bf2018-09-20 22:14:19 -070067import com.android.server.biometrics.BiometricServiceBase;
Kevin Chyn836f2cf2018-08-27 11:06:39 -070068import com.android.server.biometrics.BiometricUtils;
69import com.android.server.biometrics.ClientMonitor;
Kevin Chyn4cc49f72019-04-24 13:53:35 -070070import com.android.server.biometrics.Constants;
Kevin Chyn0ce70852019-05-10 10:29:18 -070071import com.android.server.biometrics.EnumerateClient;
Kevin Chyn6737c572019-02-08 16:10:54 -080072import com.android.server.biometrics.RemovalClient;
Jim Millera75961472014-06-06 15:00:49 -070073
Chris Wrenc510ad52015-08-14 15:43:15 -040074import org.json.JSONArray;
75import org.json.JSONException;
76import org.json.JSONObject;
77
Sasha Levitskiy80db9ba2015-05-08 14:31:48 -070078import java.io.File;
Chris Wrenc510ad52015-08-14 15:43:15 -040079import java.io.FileDescriptor;
80import java.io.PrintWriter;
Jorim Jaggi3a464782015-08-28 16:59:13 -070081import java.util.ArrayList;
Svetoslav4af76a52015-04-29 15:29:46 -070082import java.util.Collections;
Jim Miller9f0753f2015-03-23 23:59:22 -070083import java.util.List;
Phil Weaver27fcd9c2017-01-20 15:57:24 -080084import java.util.concurrent.CopyOnWriteArrayList;
Jim Millera75961472014-06-06 15:00:49 -070085
86/**
87 * A service to manage multiple clients that want to access the fingerprint HAL API.
88 * The service is responsible for maintaining a list of clients and dispatching all
Kevin Chynedd71f92017-09-01 16:09:57 -070089 * fingerprint-related events.
Jim Millera75961472014-06-06 15:00:49 -070090 *
91 * @hide
92 */
Kevin Chyn355c6bf2018-09-20 22:14:19 -070093public class FingerprintService extends BiometricServiceBase {
Kevin Chyn037c4d52018-06-11 19:17:32 -070094
95 protected static final String TAG = "FingerprintService";
96 private static final boolean DEBUG = true;
Jim Millerbe675422015-05-11 20:45:25 -070097 private static final String FP_DATA_DIR = "fpdata";
Jorim Jaggi5e354222015-09-04 14:17:58 -070098 private static final String ACTION_LOCKOUT_RESET =
Kevin Chyn95d628e2018-06-11 11:58:15 -070099 "com.android.server.biometrics.fingerprint.ACTION_LOCKOUT_RESET";
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700100 private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5;
101 private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;
Kevin Chyna38653c2019-02-11 17:46:21 -0800102 private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30 * 1000;
103 private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
104
105 private final class ResetFailedAttemptsForUserRunnable implements Runnable {
106 @Override
107 public void run() {
108 resetFailedAttemptsForUser(true /* clearAttemptCounter */,
109 ActivityManager.getCurrentUser());
110 }
111 }
112
113 private final class LockoutReceiver extends BroadcastReceiver {
114 @Override
115 public void onReceive(Context context, Intent intent) {
116 Slog.v(getTag(), "Resetting lockout: " + intent.getAction());
117 if (getLockoutResetIntent().equals(intent.getAction())) {
118 final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
119 resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
120 }
121 }
122 }
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700123
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700124 private final class FingerprintAuthClient extends AuthenticationClientImpl {
Kevin Chyn7782d142019-01-18 12:51:33 -0800125 @Override
126 protected boolean isFingerprint() {
127 return true;
128 }
129
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700130 public FingerprintAuthClient(Context context,
131 DaemonWrapper daemon, long halDeviceId, IBinder token,
132 ServiceListener listener, int targetUserId, int groupId, long opId,
Kevin Chyn87f257a2018-11-27 16:26:07 -0800133 boolean restricted, String owner, int cookie,
Kevin Chyn6cf54e82018-09-18 19:13:27 -0700134 boolean requireConfirmation) {
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700135 super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId,
Kevin Chyn87f257a2018-11-27 16:26:07 -0800136 restricted, owner, cookie, requireConfirmation);
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700137 }
Kevin Chyn7782d142019-01-18 12:51:33 -0800138
139 @Override
140 protected int statsModality() {
141 return FingerprintService.this.statsModality();
142 }
Kevin Chyna38653c2019-02-11 17:46:21 -0800143
144 @Override
145 public void resetFailedAttempts() {
146 resetFailedAttemptsForUser(true /* clearAttemptCounter */,
147 ActivityManager.getCurrentUser());
148 }
149
150 @Override
151 public boolean shouldFrameworkHandleLockout() {
152 return true;
153 }
154
155 @Override
Kevin Chyn0ce70852019-05-10 10:29:18 -0700156 public boolean wasUserDetected() {
157 // TODO: Return a proper value for devices that use ERROR_TIMEOUT
158 return false;
159 }
160
161 @Override
Kevin Chyna38653c2019-02-11 17:46:21 -0800162 public int handleFailedAttempt() {
163 final int currentUser = ActivityManager.getCurrentUser();
164 mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
165 mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
166
167 if (getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
168 scheduleLockoutResetForUser(currentUser);
169 }
170
171 return super.handleFailedAttempt();
172 }
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700173 }
174
Kevin Chyn037c4d52018-06-11 19:17:32 -0700175 /**
176 * Receives the incoming binder calls from FingerprintManager.
177 */
178 private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
Jim Millerbcc100a2016-07-06 14:16:49 -0700179
Kevin Chyn037c4d52018-06-11 19:17:32 -0700180 /**
181 * The following methods contain common code which is shared in biometrics/common.
182 */
Jim Millerce7eb6d2015-04-03 19:29:13 -0700183
Kevin Chyn037c4d52018-06-11 19:17:32 -0700184 @Override // Binder call
185 public long preEnroll(IBinder token) {
186 checkPermission(MANAGE_FINGERPRINT);
187 return startPreEnroll(token);
188 }
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -0700189
Kevin Chyn037c4d52018-06-11 19:17:32 -0700190 @Override // Binder call
191 public int postEnroll(IBinder token) {
192 checkPermission(MANAGE_FINGERPRINT);
193 return startPostEnroll(token);
194 }
195
196 @Override // Binder call
197 public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
198 final IFingerprintServiceReceiver receiver, final int flags,
199 final String opPackageName) {
200 checkPermission(MANAGE_FINGERPRINT);
201
202 final boolean restricted = isRestricted();
203 final int groupId = userId; // default group for fingerprint enrollment
204 final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
205 mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId,
Kevin Chyn1429a312019-01-28 16:08:09 -0800206 cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */) {
207 @Override
208 public boolean shouldVibrate() {
209 return true;
210 }
Kevin Chyn7782d142019-01-18 12:51:33 -0800211
212 @Override
213 protected int statsModality() {
214 return FingerprintService.this.statsModality();
215 }
Kevin Chyn1429a312019-01-28 16:08:09 -0800216 };
Kevin Chyn037c4d52018-06-11 19:17:32 -0700217
Kevin Chyn037c4d52018-06-11 19:17:32 -0700218 enrollInternal(client, userId);
219 }
220
221 @Override // Binder call
222 public void cancelEnrollment(final IBinder token) {
223 checkPermission(MANAGE_FINGERPRINT);
224 cancelEnrollmentInternal(token);
225 }
226
227 @Override // Binder call
228 public void authenticate(final IBinder token, final long opId, final int groupId,
229 final IFingerprintServiceReceiver receiver, final int flags,
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700230 final String opPackageName) {
Kevin Chyn747e29b2019-01-11 17:01:53 -0800231 updateActiveGroup(groupId, opPackageName);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700232 final boolean restricted = isRestricted();
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700233 final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
Kevin Chyn037c4d52018-06-11 19:17:32 -0700234 mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
Kevin Chyne92cdae2018-11-21 16:35:04 -0800235 mCurrentUserId, groupId, opId, restricted, opPackageName,
Kevin Chyn87f257a2018-11-27 16:26:07 -0800236 0 /* cookie */, false /* requireConfirmation */);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700237 authenticateInternal(client, opId, opPackageName);
238 }
239
240 @Override // Binder call
Kevin Chyn87f257a2018-11-27 16:26:07 -0800241 public void prepareForAuthentication(IBinder token, long opId, int groupId,
Kevin Chyn23289ef2018-11-28 16:32:36 -0800242 IBiometricServiceReceiverInternal wrapperReceiver, String opPackageName,
Kevin Chyn87f257a2018-11-27 16:26:07 -0800243 int cookie, int callingUid, int callingPid, int callingUserId) {
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700244 checkPermission(MANAGE_BIOMETRIC);
Kevin Chyn41a80902019-02-06 08:12:15 -0800245 updateActiveGroup(groupId, opPackageName);
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700246 final boolean restricted = true; // BiometricPrompt is always restricted
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700247 final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700248 mDaemonWrapper, mHalDeviceId, token,
Kevin Chyn87f257a2018-11-27 16:26:07 -0800249 new BiometricPromptServiceListenerImpl(wrapperReceiver),
250 mCurrentUserId, groupId, opId, restricted, opPackageName, cookie,
Kevin Chyne92cdae2018-11-21 16:35:04 -0800251 false /* requireConfirmation */);
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700252 authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
253 callingUserId);
254 }
255
256 @Override // Binder call
Kevin Chyn87f257a2018-11-27 16:26:07 -0800257 public void startPreparedClient(int cookie) {
258 checkPermission(MANAGE_BIOMETRIC);
259 startCurrentClient(cookie);
260 }
261
262
263 @Override // Binder call
Kevin Chyn037c4d52018-06-11 19:17:32 -0700264 public void cancelAuthentication(final IBinder token, final String opPackageName) {
265 cancelAuthenticationInternal(token, opPackageName);
266 }
267
268 @Override // Binder call
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700269 public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
Kevin Chyne92cdae2018-11-21 16:35:04 -0800270 int callingUid, int callingPid, int callingUserId, boolean fromClient) {
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700271 checkPermission(MANAGE_BIOMETRIC);
Kevin Chyne92cdae2018-11-21 16:35:04 -0800272 cancelAuthenticationInternal(token, opPackageName, callingUid, callingPid,
273 callingUserId, fromClient);
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700274 }
275
276 @Override // Binder call
Kevin Chyn037c4d52018-06-11 19:17:32 -0700277 public void setActiveUser(final int userId) {
278 checkPermission(MANAGE_FINGERPRINT);
279 setActiveUserInternal(userId);
280 }
281
282 @Override // Binder call
283 public void remove(final IBinder token, final int fingerId, final int groupId,
284 final int userId, final IFingerprintServiceReceiver receiver) {
285 checkPermission(MANAGE_FINGERPRINT);
286
287 if (token == null) {
288 Slog.w(TAG, "remove(): token is null");
289 return;
Jim Millera75961472014-06-06 15:00:49 -0700290 }
Jim Millerbe675422015-05-11 20:45:25 -0700291
Kevin Chyn037c4d52018-06-11 19:17:32 -0700292 final boolean restricted = isRestricted();
Kevin Chyn4cc49f72019-04-24 13:53:35 -0700293 final RemovalClient client = new RemovalClient(getContext(), getConstants(),
Kevin Chyn6737c572019-02-08 16:10:54 -0800294 mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
295 fingerId, groupId, userId, restricted, token.toString(), getBiometricUtils()) {
Kevin Chyn7782d142019-01-18 12:51:33 -0800296 @Override
297 protected int statsModality() {
298 return FingerprintService.this.statsModality();
299 }
300 };
Kevin Chyn037c4d52018-06-11 19:17:32 -0700301 removeInternal(client);
302 }
303
304 @Override // Binder call
305 public void enumerate(final IBinder token, final int userId,
306 final IFingerprintServiceReceiver receiver) {
307 checkPermission(MANAGE_FINGERPRINT);
308
309 final boolean restricted = isRestricted();
Kevin Chyn4cc49f72019-04-24 13:53:35 -0700310 final EnumerateClient client = new EnumerateClient(getContext(), getConstants(),
Kevin Chyn6737c572019-02-08 16:10:54 -0800311 mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), userId,
312 userId, restricted, getContext().getOpPackageName()) {
Kevin Chyn7782d142019-01-18 12:51:33 -0800313 @Override
314 protected int statsModality() {
315 return FingerprintService.this.statsModality();
316 }
317 };
Kevin Chyn037c4d52018-06-11 19:17:32 -0700318 enumerateInternal(client);
319 }
320
Kevin Chyna56dff72018-06-19 18:41:12 -0700321 @Override
322 public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback)
323 throws RemoteException {
324 FingerprintService.super.addLockoutResetCallback(callback);
325 }
326
Kevin Chyn037c4d52018-06-11 19:17:32 -0700327 @Override // Binder call
328 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700329 if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700330 return;
Jorim Jaggi5e354222015-09-04 14:17:58 -0700331 }
Jorim Jaggi5e354222015-09-04 14:17:58 -0700332
Kevin Chyn037c4d52018-06-11 19:17:32 -0700333 final long ident = Binder.clearCallingIdentity();
Kevin Chyn09da2942018-03-09 13:13:11 -0800334 try {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700335 if (args.length > 0 && "--proto".equals(args[0])) {
336 dumpProto(fd);
337 } else {
338 dumpInternal(pw);
Kevin Chyn09da2942018-03-09 13:13:11 -0800339 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700340 } finally {
341 Binder.restoreCallingIdentity(ident);
342 }
343 }
344
345 /**
346 * The following methods don't use any common code from BiometricService
347 */
348
Kevin Chyna56dff72018-06-19 18:41:12 -0700349 // TODO: refactor out common code here
Kevin Chyn037c4d52018-06-11 19:17:32 -0700350 @Override // Binder call
351 public boolean isHardwareDetected(long deviceId, String opPackageName) {
352 if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
353 Binder.getCallingUid(), Binder.getCallingPid(),
354 UserHandle.getCallingUserId())) {
355 return false;
356 }
357
358 final long token = Binder.clearCallingIdentity();
359 try {
360 IBiometricsFingerprint daemon = getFingerprintDaemon();
361 return daemon != null && mHalDeviceId != 0;
362 } finally {
363 Binder.restoreCallingIdentity(token);
364 }
365 }
366
367 @Override // Binder call
368 public void rename(final int fingerId, final int groupId, final String name) {
369 checkPermission(MANAGE_FINGERPRINT);
370 if (!isCurrentUserOrProfile(groupId)) {
371 return;
372 }
373 mHandler.post(new Runnable() {
374 @Override
375 public void run() {
Kevin Chyna56dff72018-06-19 18:41:12 -0700376 getBiometricUtils().renameBiometricForUser(getContext(), groupId,
377 fingerId, name);
Kevin Chyn09da2942018-03-09 13:13:11 -0800378 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700379 });
380 }
381
382 @Override // Binder call
383 public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
384 if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
385 Binder.getCallingUid(), Binder.getCallingPid(),
386 UserHandle.getCallingUserId())) {
387 return Collections.emptyList();
388 }
389
Kevin Chyn6737c572019-02-08 16:10:54 -0800390 return FingerprintService.this.getEnrolledTemplates(userId);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700391 }
392
393 @Override // Binder call
394 public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
395 if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
396 Binder.getCallingUid(), Binder.getCallingPid(),
397 UserHandle.getCallingUserId())) {
398 return false;
399 }
400
401 return FingerprintService.this.hasEnrolledBiometrics(userId);
402 }
403
404 @Override // Binder call
405 public long getAuthenticatorId(String opPackageName) {
406 // In this method, we're not checking whether the caller is permitted to use fingerprint
407 // API because current authenticator ID is leaked (in a more contrived way) via Android
408 // Keystore (android.security.keystore package): the user of that API can create a key
409 // which requires fingerprint authentication for its use, and then query the key's
410 // characteristics (hidden API) which returns, among other things, fingerprint
411 // authenticator ID which was active at key creation time.
412 //
413 // Reason: The part of Android Keystore which runs inside an app's process invokes this
414 // method in certain cases. Those cases are not always where the developer demonstrates
415 // explicit intent to use fingerprint functionality. Thus, to avoiding throwing an
416 // unexpected SecurityException this method does not check whether its caller is
417 // permitted to use fingerprint API.
418 //
419 // The permission check should be restored once Android Keystore no longer invokes this
420 // method from inside app processes.
421
Kevin Chyna56dff72018-06-19 18:41:12 -0700422 return FingerprintService.super.getAuthenticatorId(opPackageName);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700423 }
424
425 @Override // Binder call
426 public void resetTimeout(byte [] token) {
427 checkPermission(RESET_FINGERPRINT_LOCKOUT);
Kevin Chyn1d6a2862019-04-02 16:20:21 -0700428
429 if (!FingerprintService.this.hasEnrolledBiometrics(mCurrentUserId)) {
430 Slog.w(TAG, "Ignoring lockout reset, no templates enrolled");
431 return;
432 }
433
Kevin Chyn037c4d52018-06-11 19:17:32 -0700434 // TODO: confirm security token when we move timeout management into the HAL layer.
435 mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
436 }
437
438 @Override
Kevin Chyn037c4d52018-06-11 19:17:32 -0700439 public boolean isClientActive() {
440 checkPermission(MANAGE_FINGERPRINT);
441 synchronized(FingerprintService.this) {
442 return (getCurrentClient() != null) || (getPendingClient() != null);
443 }
444 }
445
446 @Override
447 public void addClientActiveCallback(IFingerprintClientActiveCallback callback) {
448 checkPermission(MANAGE_FINGERPRINT);
449 mClientActiveCallbacks.add(callback);
450 }
451
452 @Override
453 public void removeClientActiveCallback(IFingerprintClientActiveCallback callback) {
454 checkPermission(MANAGE_FINGERPRINT);
455 mClientActiveCallbacks.remove(callback);
456 }
457 }
458
459 /**
460 * Receives callbacks from the ClientMonitor implementations. The results are forwarded to
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700461 * BiometricPrompt.
462 */
Kevin Chyne92cdae2018-11-21 16:35:04 -0800463 private class BiometricPromptServiceListenerImpl extends BiometricServiceListener {
Kevin Chyn23289ef2018-11-28 16:32:36 -0800464 BiometricPromptServiceListenerImpl(IBiometricServiceReceiverInternal wrapperReceiver) {
Kevin Chyn87f257a2018-11-27 16:26:07 -0800465 super(wrapperReceiver);
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700466 }
467
468 @Override
469 public void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
470 throws RemoteException {
Kevin Chyne92cdae2018-11-21 16:35:04 -0800471 if (getWrapperReceiver() != null) {
472 getWrapperReceiver().onAcquired(acquiredInfo, FingerprintManager.getAcquiredString(
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700473 getContext(), acquiredInfo, vendorCode));
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700474 }
475 }
476
477 @Override
Kevin Chyn87f257a2018-11-27 16:26:07 -0800478 public void onError(long deviceId, int error, int vendorCode, int cookie)
479 throws RemoteException {
Kevin Chyne92cdae2018-11-21 16:35:04 -0800480 if (getWrapperReceiver() != null) {
Kevin Chyn23289ef2018-11-28 16:32:36 -0800481 getWrapperReceiver().onError(cookie, error,
482 FingerprintManager.getErrorString(getContext(), error, vendorCode));
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700483 }
484 }
485 }
486
487 /**
488 * Receives callbacks from the ClientMonitor implementations. The results are forwarded to
Kevin Chyn037c4d52018-06-11 19:17:32 -0700489 * the FingerprintManager.
490 */
491 private class ServiceListenerImpl implements ServiceListener {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700492 private IFingerprintServiceReceiver mFingerprintServiceReceiver;
493
494 public ServiceListenerImpl(IFingerprintServiceReceiver receiver) {
495 mFingerprintServiceReceiver = receiver;
496 }
497
498 @Override
Kevin Chyna56dff72018-06-19 18:41:12 -0700499 public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining)
Kevin Chyn037c4d52018-06-11 19:17:32 -0700500 throws RemoteException {
501 if (mFingerprintServiceReceiver != null) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700502 final Fingerprint fp = (Fingerprint) identifier;
503 mFingerprintServiceReceiver.onEnrollResult(fp.getDeviceId(), fp.getBiometricId(),
504 fp.getGroupId(), remaining);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700505 }
506 }
507
508 @Override
509 public void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
510 throws RemoteException {
511 if (mFingerprintServiceReceiver != null) {
512 mFingerprintServiceReceiver.onAcquired(deviceId, acquiredInfo, vendorCode);
513 }
514 }
515
516 @Override
517 public void onAuthenticationSucceeded(long deviceId,
Kevin Chyna56dff72018-06-19 18:41:12 -0700518 BiometricAuthenticator.Identifier biometric, int userId)
Kevin Chyn037c4d52018-06-11 19:17:32 -0700519 throws RemoteException {
520 if (mFingerprintServiceReceiver != null) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700521 if (biometric == null || biometric instanceof Fingerprint) {
522 mFingerprintServiceReceiver
523 .onAuthenticationSucceeded(deviceId, (Fingerprint) biometric, userId);
524 } else {
525 Slog.e(TAG, "onAuthenticationSucceeded received non-fingerprint biometric");
526 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700527 }
528 }
529
530 @Override
531 public void onAuthenticationFailed(long deviceId) throws RemoteException {
532 if (mFingerprintServiceReceiver != null) {
533 mFingerprintServiceReceiver.onAuthenticationFailed(deviceId);
534 }
535 }
536
537 @Override
Kevin Chyn87f257a2018-11-27 16:26:07 -0800538 public void onError(long deviceId, int error, int vendorCode, int cookie)
539 throws RemoteException {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700540 if (mFingerprintServiceReceiver != null) {
541 mFingerprintServiceReceiver.onError(deviceId, error, vendorCode);
542 }
543 }
544
545 @Override
Kevin Chyna56dff72018-06-19 18:41:12 -0700546 public void onRemoved(BiometricAuthenticator.Identifier identifier, int remaining)
Kevin Chyn037c4d52018-06-11 19:17:32 -0700547 throws RemoteException {
548 if (mFingerprintServiceReceiver != null) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700549 final Fingerprint fp = (Fingerprint) identifier;
550 mFingerprintServiceReceiver.onRemoved(fp.getDeviceId(), fp.getBiometricId(),
551 fp.getGroupId(), remaining);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700552 }
553 }
554
555 @Override
Kevin Chyna56dff72018-06-19 18:41:12 -0700556 public void onEnumerated(BiometricAuthenticator.Identifier identifier, int remaining)
Kevin Chyn037c4d52018-06-11 19:17:32 -0700557 throws RemoteException {
558 if (mFingerprintServiceReceiver != null) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700559 final Fingerprint fp = (Fingerprint) identifier;
560 mFingerprintServiceReceiver.onEnumerated(fp.getDeviceId(), fp.getBiometricId(),
561 fp.getGroupId(), remaining);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700562 }
563 }
564 }
565
Kevin Chyn4cc49f72019-04-24 13:53:35 -0700566 private final FingerprintConstants mFingerprintConstants = new FingerprintConstants();
Kevin Chyn037c4d52018-06-11 19:17:32 -0700567 private final CopyOnWriteArrayList<IFingerprintClientActiveCallback> mClientActiveCallbacks =
568 new CopyOnWriteArrayList<>();
Kevin Chyn037c4d52018-06-11 19:17:32 -0700569
570 @GuardedBy("this")
571 private IBiometricsFingerprint mDaemon;
Kevin Chyna38653c2019-02-11 17:46:21 -0800572 private final SparseBooleanArray mTimedLockoutCleared;
573 private final SparseIntArray mFailedAttempts;
574 private final AlarmManager mAlarmManager;
575 private final LockoutReceiver mLockoutReceiver = new LockoutReceiver();
576 protected final ResetFailedAttemptsForUserRunnable mResetFailedAttemptsForCurrentUserRunnable =
577 new ResetFailedAttemptsForUserRunnable();
Kevin Chyn037c4d52018-06-11 19:17:32 -0700578
Kevin Chyn037c4d52018-06-11 19:17:32 -0700579 /**
580 * Receives callbacks from the HAL.
581 */
582 private IBiometricsFingerprintClientCallback mDaemonCallback =
583 new IBiometricsFingerprintClientCallback.Stub() {
584 @Override
585 public void onEnrollResult(final long deviceId, final int fingerId, final int groupId,
586 final int remaining) {
587 mHandler.post(() -> {
Kevin Chyna56dff72018-06-19 18:41:12 -0700588 final Fingerprint fingerprint =
589 new Fingerprint(getBiometricUtils().getUniqueName(getContext(), groupId),
590 groupId, fingerId, deviceId);
591 FingerprintService.super.handleEnrollResult(fingerprint, remaining);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700592 });
593 }
594
595 @Override
596 public void onAcquired(final long deviceId, final int acquiredInfo, final int vendorCode) {
597 mHandler.post(() -> {
598 FingerprintService.super.handleAcquired(deviceId, acquiredInfo, vendorCode);
599 });
600 }
601
602 @Override
603 public void onAuthenticated(final long deviceId, final int fingerId, final int groupId,
604 ArrayList<Byte> token) {
605 mHandler.post(() -> {
Kevin Chynb528d692018-07-20 11:53:14 -0700606 Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
607 FingerprintService.super.handleAuthenticated(fp, token);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700608 });
609 }
610
611 @Override
612 public void onError(final long deviceId, final int error, final int vendorCode) {
613 mHandler.post(() -> {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700614 FingerprintService.super.handleError(deviceId, error, vendorCode);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700615 // TODO: this chunk of code should be common to all biometric services
616 if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) {
617 // If we get HW_UNAVAILABLE, try to connect again later...
618 Slog.w(TAG, "Got ERROR_HW_UNAVAILABLE; try reconnecting next client.");
619 synchronized (this) {
620 mDaemon = null;
621 mHalDeviceId = 0;
622 mCurrentUserId = UserHandle.USER_NULL;
Kevin Chyn09da2942018-03-09 13:13:11 -0800623 }
624 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700625 });
626 }
627
628 @Override
629 public void onRemoved(final long deviceId, final int fingerId, final int groupId,
630 final int remaining) {
631 mHandler.post(() -> {
632 ClientMonitor client = getCurrentClient();
Kevin Chyna56dff72018-06-19 18:41:12 -0700633 final Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
634 FingerprintService.super.handleRemoved(fp, remaining);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700635 });
636 }
637
638 @Override
639 public void onEnumerate(final long deviceId, final int fingerId, final int groupId,
640 final int remaining) {
641 mHandler.post(() -> {
Kevin Chyna56dff72018-06-19 18:41:12 -0700642 final Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
Kevin Chyn6737c572019-02-08 16:10:54 -0800643 FingerprintService.super.handleEnumerate(fp, remaining);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700644 });
645
646 }
647 };
648
649 /**
650 * Wraps the HAL-specific code and is passed to the ClientMonitor implementations so that they
651 * can be shared between the multiple biometric services.
652 */
653 private final DaemonWrapper mDaemonWrapper = new DaemonWrapper() {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700654 @Override
655 public int authenticate(long operationId, int groupId) throws RemoteException {
656 IBiometricsFingerprint daemon = getFingerprintDaemon();
657 if (daemon == null) {
658 Slog.w(TAG, "authenticate(): no fingerprint HAL!");
659 return ERROR_ESRCH;
Kevin Chyn09da2942018-03-09 13:13:11 -0800660 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700661 return daemon.authenticate(operationId, groupId);
662 }
663
664 @Override
665 public int cancel() throws RemoteException {
666 IBiometricsFingerprint daemon = getFingerprintDaemon();
667 if (daemon == null) {
668 Slog.w(TAG, "cancel(): no fingerprint HAL!");
669 return ERROR_ESRCH;
670 }
671 return daemon.cancel();
672 }
673
674 @Override
675 public int remove(int groupId, int biometricId) throws RemoteException {
676 IBiometricsFingerprint daemon = getFingerprintDaemon();
677 if (daemon == null) {
678 Slog.w(TAG, "remove(): no fingerprint HAL!");
679 return ERROR_ESRCH;
680 }
681 return daemon.remove(groupId, biometricId);
682 }
683
684 @Override
685 public int enumerate() throws RemoteException {
686 IBiometricsFingerprint daemon = getFingerprintDaemon();
687 if (daemon == null) {
688 Slog.w(TAG, "enumerate(): no fingerprint HAL!");
689 return ERROR_ESRCH;
690 }
691 return daemon.enumerate();
692 }
693
694 @Override
Kevin Chyn1f16c2d2018-12-07 13:06:08 -0800695 public int enroll(byte[] cryptoToken, int groupId, int timeout,
696 ArrayList<Integer> disabledFeatures) throws RemoteException {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700697 IBiometricsFingerprint daemon = getFingerprintDaemon();
698 if (daemon == null) {
699 Slog.w(TAG, "enroll(): no fingerprint HAL!");
700 return ERROR_ESRCH;
701 }
702 return daemon.enroll(cryptoToken, groupId, timeout);
Kevin Chyn09da2942018-03-09 13:13:11 -0800703 }
Kevin Chyna38653c2019-02-11 17:46:21 -0800704
705 @Override
706 public void resetLockout(byte[] token) throws RemoteException {
707 // TODO: confirm security token when we move timeout management into the HAL layer.
708 Slog.e(TAG, "Not supported");
709 return;
710 }
Kevin Chyn09da2942018-03-09 13:13:11 -0800711 };
712
Jim Millera75961472014-06-06 15:00:49 -0700713 public FingerprintService(Context context) {
714 super(context);
Kevin Chyna38653c2019-02-11 17:46:21 -0800715 mTimedLockoutCleared = new SparseBooleanArray();
716 mFailedAttempts = new SparseIntArray();
717 mAlarmManager = context.getSystemService(AlarmManager.class);
718 context.registerReceiver(mLockoutReceiver, new IntentFilter(getLockoutResetIntent()),
719 getLockoutBroadcastPermission(), null /* handler */);
Jim Millera75961472014-06-06 15:00:49 -0700720 }
721
Jim Millerbe675422015-05-11 20:45:25 -0700722 @Override
Kevin Chyn037c4d52018-06-11 19:17:32 -0700723 public void onStart() {
724 super.onStart();
725 publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
726 SystemServerInitThreadPool.get().submit(this::getFingerprintDaemon, TAG + ".onStart");
Jim Millera75961472014-06-06 15:00:49 -0700727 }
728
Kevin Chyn037c4d52018-06-11 19:17:32 -0700729 @Override
730 protected String getTag() {
731 return TAG;
732 }
733
734 @Override
Kevin Chyn6737c572019-02-08 16:10:54 -0800735 protected DaemonWrapper getDaemonWrapper() {
736 return mDaemonWrapper;
737 }
738
739 @Override
Kevin Chyna56dff72018-06-19 18:41:12 -0700740 protected BiometricUtils getBiometricUtils() {
741 return FingerprintUtils.getInstance();
742 }
743
744 @Override
Kevin Chyn4cc49f72019-04-24 13:53:35 -0700745 protected Constants getConstants() {
746 return mFingerprintConstants;
Kevin Chyn037c4d52018-06-11 19:17:32 -0700747 }
748
749 @Override
750 protected boolean hasReachedEnrollmentLimit(int userId) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700751 final int limit = getContext().getResources().getInteger(
Kevin Chyn037c4d52018-06-11 19:17:32 -0700752 com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
Kevin Chyn6737c572019-02-08 16:10:54 -0800753 final int enrolled = FingerprintService.this.getEnrolledTemplates(userId).size();
Kevin Chyn037c4d52018-06-11 19:17:32 -0700754 if (enrolled >= limit) {
755 Slog.w(TAG, "Too many fingerprints registered");
756 return true;
757 }
758 return false;
759 }
760
761 @Override
Kevin Chyn9ba99912019-01-16 16:24:36 -0800762 public void serviceDied(long cookie) {
763 super.serviceDied(cookie);
764 mDaemon = null;
765 }
766
767 @Override
Kevin Chyn037c4d52018-06-11 19:17:32 -0700768 protected void updateActiveGroup(int userId, String clientPackage) {
769 IBiometricsFingerprint daemon = getFingerprintDaemon();
770
771 if (daemon != null) {
772 try {
773 userId = getUserOrWorkProfileId(clientPackage, userId);
774 if (userId != mCurrentUserId) {
775 int firstSdkInt = Build.VERSION.FIRST_SDK_INT;
776 if (firstSdkInt < Build.VERSION_CODES.BASE) {
777 Slog.e(TAG, "First SDK version " + firstSdkInt + " is invalid; must be " +
778 "at least VERSION_CODES.BASE");
779 }
780 File baseDir;
781 if (firstSdkInt <= Build.VERSION_CODES.O_MR1) {
782 baseDir = Environment.getUserSystemDirectory(userId);
783 } else {
784 baseDir = Environment.getDataVendorDeDirectory(userId);
785 }
786
787 File fpDir = new File(baseDir, FP_DATA_DIR);
788 if (!fpDir.exists()) {
789 if (!fpDir.mkdir()) {
790 Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath());
791 return;
792 }
793 // Calling mkdir() from this process will create a directory with our
794 // permissions (inherited from the containing dir). This command fixes
795 // the label.
796 if (!SELinux.restorecon(fpDir)) {
797 Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
798 return;
799 }
800 }
801
802 daemon.setActiveGroup(userId, fpDir.getAbsolutePath());
803 mCurrentUserId = userId;
804 }
805 mAuthenticatorIds.put(userId,
806 hasEnrolledBiometrics(userId) ? daemon.getAuthenticatorId() : 0L);
807 } catch (RemoteException e) {
808 Slog.e(TAG, "Failed to setActiveGroup():", e);
809 }
810 }
811 }
812
813 @Override
814 protected String getLockoutResetIntent() {
815 return ACTION_LOCKOUT_RESET;
816 }
817
818 @Override
819 protected String getLockoutBroadcastPermission() {
820 return RESET_FINGERPRINT_LOCKOUT;
821 }
822
823 @Override
824 protected long getHalDeviceId() {
825 return mHalDeviceId;
826 }
827
828 @Override
Kevin Chyn037c4d52018-06-11 19:17:32 -0700829 protected boolean hasEnrolledBiometrics(int userId) {
830 if (userId != UserHandle.getCallingUserId()) {
831 checkPermission(INTERACT_ACROSS_USERS);
832 }
Kevin Chyna56dff72018-06-19 18:41:12 -0700833 return getBiometricUtils().getBiometricsForUser(getContext(), userId).size() > 0;
Kevin Chyn037c4d52018-06-11 19:17:32 -0700834 }
835
836 @Override
837 protected String getManageBiometricPermission() {
838 return MANAGE_FINGERPRINT;
839 }
840
841 @Override
842 protected void checkUseBiometricPermission() {
843 if (getContext().checkCallingPermission(USE_FINGERPRINT)
844 != PackageManager.PERMISSION_GRANTED) {
845 checkPermission(USE_BIOMETRIC);
846 }
847 }
848
849 @Override
Kevin Chynb3c05aa2018-09-21 16:50:32 -0700850 protected boolean checkAppOps(int uid, String opPackageName) {
851 boolean appOpsOk = false;
852 if (mAppOps.noteOp(AppOpsManager.OP_USE_BIOMETRIC, uid, opPackageName)
853 == AppOpsManager.MODE_ALLOWED) {
854 appOpsOk = true;
855 } else if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
856 == AppOpsManager.MODE_ALLOWED) {
857 appOpsOk = true;
858 }
859 return appOpsOk;
Kevin Chyn037c4d52018-06-11 19:17:32 -0700860 }
861
862 @Override
Kevin Chyn6737c572019-02-08 16:10:54 -0800863 protected List<Fingerprint> getEnrolledTemplates(int userId) {
Kevin Chyn8addd4f2019-04-25 12:34:15 -0700864 if (userId != UserHandle.getCallingUserId()) {
865 checkPermission(INTERACT_ACROSS_USERS);
866 }
Kevin Chyn6737c572019-02-08 16:10:54 -0800867 return getBiometricUtils().getBiometricsForUser(getContext(), userId);
868 }
869
870 @Override
Kevin Chyn037c4d52018-06-11 19:17:32 -0700871 protected void notifyClientActiveCallbacks(boolean isActive) {
872 List<IFingerprintClientActiveCallback> callbacks = mClientActiveCallbacks;
873 for (int i = 0; i < callbacks.size(); i++) {
874 try {
875 callbacks.get(i).onClientActiveChanged(isActive);
876 } catch (RemoteException re) {
877 // If the remote is dead, stop notifying it
878 mClientActiveCallbacks.remove(callbacks.get(i));
879 }
880 }
881 }
882
Kevin Chyn7782d142019-01-18 12:51:33 -0800883 @Override
884 protected int statsModality() {
885 return BiometricsProtoEnums.MODALITY_FINGERPRINT;
886 }
887
Kevin Chyna38653c2019-02-11 17:46:21 -0800888 @Override
889 protected int getLockoutMode() {
890 final int currentUser = ActivityManager.getCurrentUser();
891 final int failedAttempts = mFailedAttempts.get(currentUser, 0);
892 if (failedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) {
893 return AuthenticationClient.LOCKOUT_PERMANENT;
894 } else if (failedAttempts > 0
895 && !mTimedLockoutCleared.get(currentUser, false)
896 && (failedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) {
897 return AuthenticationClient.LOCKOUT_TIMED;
898 }
899 return AuthenticationClient.LOCKOUT_NONE;
900 }
901
Kevin Chyn037c4d52018-06-11 19:17:32 -0700902 /** Gets the fingerprint daemon */
903 private synchronized IBiometricsFingerprint getFingerprintDaemon() {
Jim Miller40e46452016-12-16 18:38:53 -0800904 if (mDaemon == null) {
Kevin Chynedd71f92017-09-01 16:09:57 -0700905 Slog.v(TAG, "mDaemon was null, reconnect to fingerprint");
Jim Miller40e46452016-12-16 18:38:53 -0800906 try {
Yifan Hong25d5eaa2017-03-16 15:25:43 -0700907 mDaemon = IBiometricsFingerprint.getService();
Jim Miller40e46452016-12-16 18:38:53 -0800908 } catch (java.util.NoSuchElementException e) {
909 // Service doesn't exist or cannot be opened. Logged below.
910 } catch (RemoteException e) {
911 Slog.e(TAG, "Failed to get biometric interface", e);
Jim Millera75961472014-06-06 15:00:49 -0700912 }
Jim Miller40e46452016-12-16 18:38:53 -0800913 if (mDaemon == null) {
914 Slog.w(TAG, "fingerprint HIDL not available");
915 return null;
916 }
917
918 mDaemon.asBinder().linkToDeath(this, 0);
919
920 try {
921 mHalDeviceId = mDaemon.setNotify(mDaemonCallback);
922 } catch (RemoteException e) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700923 Slog.e(TAG, "Failed to open fingerprint HAL", e);
Jim Miller40e46452016-12-16 18:38:53 -0800924 mDaemon = null; // try again later!
925 }
926
927 if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
928 if (mHalDeviceId != 0) {
Charles Heda88f0e2017-02-02 18:29:13 +0000929 loadAuthenticatorIds();
Jim Miller40e46452016-12-16 18:38:53 -0800930 updateActiveGroup(ActivityManager.getCurrentUser(), null);
Kevin Chyn6737c572019-02-08 16:10:54 -0800931 doTemplateCleanupForUser(ActivityManager.getCurrentUser());
Jim Miller40e46452016-12-16 18:38:53 -0800932 } else {
933 Slog.w(TAG, "Failed to open Fingerprint HAL!");
Kevin Chyna56dff72018-06-19 18:41:12 -0700934 MetricsLogger.count(getContext(), "fingerprintd_openhal_error", 1);
Jim Miller40e46452016-12-16 18:38:53 -0800935 mDaemon = null;
936 }
Jim Millerce7eb6d2015-04-03 19:29:13 -0700937 }
Jim Miller40e46452016-12-16 18:38:53 -0800938 return mDaemon;
Jim Millerbe675422015-05-11 20:45:25 -0700939 }
940
Kevin Chyn037c4d52018-06-11 19:17:32 -0700941 private long startPreEnroll(IBinder token) {
Jim Miller40e46452016-12-16 18:38:53 -0800942 IBiometricsFingerprint daemon = getFingerprintDaemon();
Jim Millerbe675422015-05-11 20:45:25 -0700943 if (daemon == null) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700944 Slog.w(TAG, "startPreEnroll: no fingerprint HAL!");
Jim Millerbe675422015-05-11 20:45:25 -0700945 return 0;
946 }
947 try {
948 return daemon.preEnroll();
949 } catch (RemoteException e) {
950 Slog.e(TAG, "startPreEnroll failed", e);
951 }
952 return 0;
Jim Millerce7eb6d2015-04-03 19:29:13 -0700953 }
954
Kevin Chyn037c4d52018-06-11 19:17:32 -0700955 private int startPostEnroll(IBinder token) {
Jim Miller40e46452016-12-16 18:38:53 -0800956 IBiometricsFingerprint daemon = getFingerprintDaemon();
Sasha Levitskiye0943cf2015-07-08 13:22:20 -0700957 if (daemon == null) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700958 Slog.w(TAG, "startPostEnroll: no fingerprint HAL!");
Sasha Levitskiye0943cf2015-07-08 13:22:20 -0700959 return 0;
960 }
961 try {
962 return daemon.postEnroll();
963 } catch (RemoteException e) {
964 Slog.e(TAG, "startPostEnroll failed", e);
965 }
966 return 0;
967 }
968
Kevin Chyna38653c2019-02-11 17:46:21 -0800969 // Attempt counter should only be cleared when Keyguard goes away or when
970 // a biometric is successfully authenticated. Lockout should eventually be done below the HAL.
971 // See AuthenticationClient#shouldFrameworkHandleLockout().
972 private void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
973 if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
974 Slog.v(getTag(), "Reset biometric lockout, clearAttemptCounter=" + clearAttemptCounter);
975 }
976 if (clearAttemptCounter) {
977 mFailedAttempts.put(userId, 0);
978 }
979 mTimedLockoutCleared.put(userId, true);
980 // If we're asked to reset failed attempts externally (i.e. from Keyguard),
981 // the alarm might still be pending; remove it.
982 cancelLockoutResetForUser(userId);
983 notifyLockoutResetMonitors();
984 }
985
986
987 private void cancelLockoutResetForUser(int userId) {
988 mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
989 }
990
991 private void scheduleLockoutResetForUser(int userId) {
992 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
993 SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
994 getLockoutResetIntentForUser(userId));
995 }
996
997 private PendingIntent getLockoutResetIntentForUser(int userId) {
998 return PendingIntent.getBroadcast(getContext(), userId,
999 new Intent(getLockoutResetIntent()).putExtra(KEY_LOCKOUT_RESET_USER, userId),
1000 PendingIntent.FLAG_UPDATE_CURRENT);
1001 }
1002
Chris Wrenc510ad52015-08-14 15:43:15 -04001003 private void dumpInternal(PrintWriter pw) {
1004 JSONObject dump = new JSONObject();
1005 try {
1006 dump.put("service", "Fingerprint Manager");
1007
1008 JSONArray sets = new JSONArray();
1009 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1010 final int userId = user.getUserHandle().getIdentifier();
Kevin Chyna56dff72018-06-19 18:41:12 -07001011 final int N = getBiometricUtils().getBiometricsForUser(getContext(), userId).size();
Jim Millerbcc100a2016-07-06 14:16:49 -07001012 PerformanceStats stats = mPerformanceMap.get(userId);
1013 PerformanceStats cryptoStats = mCryptoPerformanceMap.get(userId);
Chris Wrenc510ad52015-08-14 15:43:15 -04001014 JSONObject set = new JSONObject();
1015 set.put("id", userId);
1016 set.put("count", N);
Jim Millerbcc100a2016-07-06 14:16:49 -07001017 set.put("accept", (stats != null) ? stats.accept : 0);
1018 set.put("reject", (stats != null) ? stats.reject : 0);
1019 set.put("acquire", (stats != null) ? stats.acquire : 0);
1020 set.put("lockout", (stats != null) ? stats.lockout : 0);
Kevin Chyndf9d33e2017-05-03 21:40:12 -07001021 set.put("permanentLockout", (stats != null) ? stats.permanentLockout : 0);
Jim Millerbcc100a2016-07-06 14:16:49 -07001022 // cryptoStats measures statistics about secure fingerprint transactions
1023 // (e.g. to unlock password storage, make secure purchases, etc.)
1024 set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0);
1025 set.put("rejectCrypto", (cryptoStats != null) ? cryptoStats.reject : 0);
1026 set.put("acquireCrypto", (cryptoStats != null) ? cryptoStats.acquire : 0);
1027 set.put("lockoutCrypto", (cryptoStats != null) ? cryptoStats.lockout : 0);
Kweku Adamscd7c35c2017-09-14 16:45:06 -07001028 set.put("permanentLockoutCrypto",
1029 (cryptoStats != null) ? cryptoStats.permanentLockout : 0);
Chris Wrenc510ad52015-08-14 15:43:15 -04001030 sets.put(set);
1031 }
1032
1033 dump.put("prints", sets);
1034 } catch (JSONException e) {
1035 Slog.e(TAG, "dump formatting failure", e);
1036 }
1037 pw.println(dump);
Kevin Chyn9ba99912019-01-16 16:24:36 -08001038 pw.println("HAL Deaths: " + mHALDeathCount);
1039 mHALDeathCount = 0;
Jim Millera75961472014-06-06 15:00:49 -07001040 }
1041
Joe Onorato1754d742016-11-21 17:51:35 -08001042 private void dumpProto(FileDescriptor fd) {
1043 final ProtoOutputStream proto = new ProtoOutputStream(fd);
1044 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1045 final int userId = user.getUserHandle().getIdentifier();
1046
1047 final long userToken = proto.start(FingerprintServiceDumpProto.USERS);
1048
1049 proto.write(FingerprintUserStatsProto.USER_ID, userId);
1050 proto.write(FingerprintUserStatsProto.NUM_FINGERPRINTS,
Kevin Chyna56dff72018-06-19 18:41:12 -07001051 getBiometricUtils().getBiometricsForUser(getContext(), userId).size());
Joe Onorato1754d742016-11-21 17:51:35 -08001052
1053 // Normal fingerprint authentications (e.g. lockscreen)
1054 final PerformanceStats normal = mPerformanceMap.get(userId);
1055 if (normal != null) {
1056 final long countsToken = proto.start(FingerprintUserStatsProto.NORMAL);
Kweku Adamsfd257d62017-10-25 17:53:50 -07001057 proto.write(PerformanceStatsProto.ACCEPT, normal.accept);
1058 proto.write(PerformanceStatsProto.REJECT, normal.reject);
1059 proto.write(PerformanceStatsProto.ACQUIRE, normal.acquire);
1060 proto.write(PerformanceStatsProto.LOCKOUT, normal.lockout);
1061 proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, normal.permanentLockout);
Joe Onorato1754d742016-11-21 17:51:35 -08001062 proto.end(countsToken);
1063 }
1064
1065 // Statistics about secure fingerprint transactions (e.g. to unlock password
1066 // storage, make secure purchases, etc.)
Kevin Chyn9310f5c2017-02-21 17:22:54 -08001067 final PerformanceStats crypto = mCryptoPerformanceMap.get(userId);
Joe Onorato1754d742016-11-21 17:51:35 -08001068 if (crypto != null) {
1069 final long countsToken = proto.start(FingerprintUserStatsProto.CRYPTO);
Kweku Adamsfd257d62017-10-25 17:53:50 -07001070 proto.write(PerformanceStatsProto.ACCEPT, crypto.accept);
1071 proto.write(PerformanceStatsProto.REJECT, crypto.reject);
1072 proto.write(PerformanceStatsProto.ACQUIRE, crypto.acquire);
1073 proto.write(PerformanceStatsProto.LOCKOUT, crypto.lockout);
1074 proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, crypto.permanentLockout);
Joe Onorato1754d742016-11-21 17:51:35 -08001075 proto.end(countsToken);
1076 }
1077
1078 proto.end(userToken);
1079 }
1080 proto.flush();
Kevin Chyn89a55cb2018-03-29 14:52:59 -07001081 mPerformanceMap.clear();
1082 mCryptoPerformanceMap.clear();
Joe Onorato1754d742016-11-21 17:51:35 -08001083 }
Jim Millera75961472014-06-06 15:00:49 -07001084}