blob: 9bb927eff291dd4c4f2d14d4a09aa2ff70dc2f80 [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;
Kevin Chyn7d07c892020-02-18 18:18:17 -080024import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
Charles He959ac8e2017-03-27 21:16:20 +010025import static android.Manifest.permission.USE_FINGERPRINT;
Ilya Matyukhin0f9da352019-10-03 14:10:01 -070026import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
Charles He959ac8e2017-03-27 21:16:20 +010027
Sasha Levitskiy80db9ba2015-05-08 14:31:48 -070028import android.app.ActivityManager;
Kevin Chyna38653c2019-02-11 17:46:21 -080029import android.app.AlarmManager;
Svetoslav4af76a52015-04-29 15:29:46 -070030import android.app.AppOpsManager;
Kevin Chyna38653c2019-02-11 17:46:21 -080031import android.app.PendingIntent;
32import android.content.BroadcastReceiver;
Jim Millera75961472014-06-06 15:00:49 -070033import android.content.Context;
Kevin Chyna38653c2019-02-11 17:46:21 -080034import android.content.Intent;
35import android.content.IntentFilter;
Jim Millerf501b582015-06-03 16:36:31 -070036import android.content.pm.PackageManager;
Jim Millercb7d9e92015-06-16 15:05:48 -070037import android.content.pm.UserInfo;
Kevin Chyn037c4d52018-06-11 19:17:32 -070038import android.hardware.biometrics.BiometricAuthenticator;
39import android.hardware.biometrics.BiometricConstants;
Kevin Chyn7782d142019-01-18 12:51:33 -080040import android.hardware.biometrics.BiometricsProtoEnums;
Ilya Matyukhinef410e32020-02-04 13:39:48 -080041import android.hardware.biometrics.IBiometricNativeHandle;
Kevin Chyna56dff72018-06-19 18:41:12 -070042import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
Kevin Chyn23289ef2018-11-28 16:32:36 -080043import android.hardware.biometrics.IBiometricServiceReceiverInternal;
Charles He959ac8e2017-03-27 21:16:20 +010044import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
Ilya Matyukhind9343702020-02-06 15:34:24 -080045import android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprintClientCallback;
Charles He959ac8e2017-03-27 21:16:20 +010046import android.hardware.fingerprint.Fingerprint;
Kevin Chyna24e9fd2018-08-27 12:39:17 -070047import android.hardware.fingerprint.FingerprintManager;
Phil Weaver27fcd9c2017-01-20 15:57:24 -080048import android.hardware.fingerprint.IFingerprintClientActiveCallback;
Charles He959ac8e2017-03-27 21:16:20 +010049import android.hardware.fingerprint.IFingerprintService;
Charles He959ac8e2017-03-27 21:16:20 +010050import android.hardware.fingerprint.IFingerprintServiceReceiver;
Svetoslav4af76a52015-04-29 15:29:46 -070051import android.os.Binder;
Andreas Huber7fe20532018-01-22 11:26:44 -080052import android.os.Build;
Sasha Levitskiy80db9ba2015-05-08 14:31:48 -070053import android.os.Environment;
Jim Millera75961472014-06-06 15:00:49 -070054import android.os.IBinder;
Ilya Matyukhinef410e32020-02-04 13:39:48 -080055import android.os.NativeHandle;
Jim Millera75961472014-06-06 15:00:49 -070056import android.os.RemoteException;
Jim Miller16ef71f2015-05-21 17:02:21 -070057import android.os.SELinux;
Kevin Chyna38653c2019-02-11 17:46:21 -080058import android.os.SystemClock;
Jim Miller599ef0e2015-06-15 20:39:44 -070059import android.os.UserHandle;
Jim Millercb7d9e92015-06-16 15:05:48 -070060import android.os.UserManager;
Jim Millera75961472014-06-06 15:00:49 -070061import android.util.Slog;
Kevin Chyna38653c2019-02-11 17:46:21 -080062import android.util.SparseBooleanArray;
63import android.util.SparseIntArray;
Joe Onorato1754d742016-11-21 17:51:35 -080064import android.util.proto.ProtoOutputStream;
Jim Millera75961472014-06-06 15:00:49 -070065
Fyodor Kupolov449e7082016-10-31 15:06:12 -070066import com.android.internal.annotations.GuardedBy;
Chris Wrenc510ad52015-08-14 15:43:15 -040067import com.android.internal.logging.MetricsLogger;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060068import com.android.internal.util.DumpUtils;
Fyodor Kupolove29a5a12016-12-16 16:14:17 -080069import com.android.server.SystemServerInitThreadPool;
Kevin Chyna38653c2019-02-11 17:46:21 -080070import com.android.server.biometrics.AuthenticationClient;
Kevin Chyn355c6bf2018-09-20 22:14:19 -070071import com.android.server.biometrics.BiometricServiceBase;
Kevin Chyn836f2cf2018-08-27 11:06:39 -070072import com.android.server.biometrics.BiometricUtils;
73import com.android.server.biometrics.ClientMonitor;
Kevin Chyn4cc49f72019-04-24 13:53:35 -070074import com.android.server.biometrics.Constants;
Kevin Chyn0ce70852019-05-10 10:29:18 -070075import com.android.server.biometrics.EnumerateClient;
Kevin Chyn6737c572019-02-08 16:10:54 -080076import com.android.server.biometrics.RemovalClient;
Jim Millera75961472014-06-06 15:00:49 -070077
Chris Wrenc510ad52015-08-14 15:43:15 -040078import org.json.JSONArray;
79import org.json.JSONException;
80import org.json.JSONObject;
81
Sasha Levitskiy80db9ba2015-05-08 14:31:48 -070082import java.io.File;
Chris Wrenc510ad52015-08-14 15:43:15 -040083import java.io.FileDescriptor;
84import java.io.PrintWriter;
Jorim Jaggi3a464782015-08-28 16:59:13 -070085import java.util.ArrayList;
Svetoslav4af76a52015-04-29 15:29:46 -070086import java.util.Collections;
Jim Miller9f0753f2015-03-23 23:59:22 -070087import java.util.List;
Phil Weaver27fcd9c2017-01-20 15:57:24 -080088import java.util.concurrent.CopyOnWriteArrayList;
Jim Millera75961472014-06-06 15:00:49 -070089
90/**
91 * A service to manage multiple clients that want to access the fingerprint HAL API.
92 * The service is responsible for maintaining a list of clients and dispatching all
Kevin Chynedd71f92017-09-01 16:09:57 -070093 * fingerprint-related events.
Jim Millera75961472014-06-06 15:00:49 -070094 *
95 * @hide
96 */
Kevin Chyn355c6bf2018-09-20 22:14:19 -070097public class FingerprintService extends BiometricServiceBase {
Kevin Chyn037c4d52018-06-11 19:17:32 -070098
99 protected static final String TAG = "FingerprintService";
100 private static final boolean DEBUG = true;
Jim Millerbe675422015-05-11 20:45:25 -0700101 private static final String FP_DATA_DIR = "fpdata";
Jorim Jaggi5e354222015-09-04 14:17:58 -0700102 private static final String ACTION_LOCKOUT_RESET =
Kevin Chyn95d628e2018-06-11 11:58:15 -0700103 "com.android.server.biometrics.fingerprint.ACTION_LOCKOUT_RESET";
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700104 private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5;
105 private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;
Kevin Chyna38653c2019-02-11 17:46:21 -0800106 private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30 * 1000;
107 private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
108
109 private final class ResetFailedAttemptsForUserRunnable implements Runnable {
110 @Override
111 public void run() {
112 resetFailedAttemptsForUser(true /* clearAttemptCounter */,
113 ActivityManager.getCurrentUser());
114 }
115 }
116
117 private final class LockoutReceiver extends BroadcastReceiver {
118 @Override
119 public void onReceive(Context context, Intent intent) {
120 Slog.v(getTag(), "Resetting lockout: " + intent.getAction());
121 if (getLockoutResetIntent().equals(intent.getAction())) {
122 final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
123 resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
124 }
125 }
126 }
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700127
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700128 private final class FingerprintAuthClient extends AuthenticationClientImpl {
Kevin Chyn7782d142019-01-18 12:51:33 -0800129 @Override
130 protected boolean isFingerprint() {
131 return true;
132 }
133
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700134 public FingerprintAuthClient(Context context,
135 DaemonWrapper daemon, long halDeviceId, IBinder token,
136 ServiceListener listener, int targetUserId, int groupId, long opId,
Kevin Chyn87f257a2018-11-27 16:26:07 -0800137 boolean restricted, String owner, int cookie,
Ilya Matyukhinef410e32020-02-04 13:39:48 -0800138 boolean requireConfirmation, IBiometricNativeHandle windowId) {
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700139 super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId,
Ilya Matyukhinef410e32020-02-04 13:39:48 -0800140 restricted, owner, cookie, requireConfirmation, windowId);
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700141 }
Kevin Chyn7782d142019-01-18 12:51:33 -0800142
143 @Override
144 protected int statsModality() {
145 return FingerprintService.this.statsModality();
146 }
Kevin Chyna38653c2019-02-11 17:46:21 -0800147
148 @Override
149 public void resetFailedAttempts() {
150 resetFailedAttemptsForUser(true /* clearAttemptCounter */,
151 ActivityManager.getCurrentUser());
152 }
153
154 @Override
155 public boolean shouldFrameworkHandleLockout() {
156 return true;
157 }
158
159 @Override
Kevin Chyn0ce70852019-05-10 10:29:18 -0700160 public boolean wasUserDetected() {
161 // TODO: Return a proper value for devices that use ERROR_TIMEOUT
162 return false;
163 }
164
165 @Override
Kevin Chyna38653c2019-02-11 17:46:21 -0800166 public int handleFailedAttempt() {
167 final int currentUser = ActivityManager.getCurrentUser();
168 mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
169 mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
170
171 if (getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
172 scheduleLockoutResetForUser(currentUser);
173 }
174
175 return super.handleFailedAttempt();
176 }
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700177 }
178
Kevin Chyn037c4d52018-06-11 19:17:32 -0700179 /**
180 * Receives the incoming binder calls from FingerprintManager.
181 */
182 private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
Curtis Belmonte45788542019-07-23 11:07:27 -0700183 private static final int ENROLL_TIMEOUT_SEC = 60;
Jim Millerbcc100a2016-07-06 14:16:49 -0700184
Kevin Chyn037c4d52018-06-11 19:17:32 -0700185 /**
186 * The following methods contain common code which is shared in biometrics/common.
187 */
Jim Millerce7eb6d2015-04-03 19:29:13 -0700188
Kevin Chyn037c4d52018-06-11 19:17:32 -0700189 @Override // Binder call
190 public long preEnroll(IBinder token) {
191 checkPermission(MANAGE_FINGERPRINT);
192 return startPreEnroll(token);
193 }
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -0700194
Kevin Chyn037c4d52018-06-11 19:17:32 -0700195 @Override // Binder call
196 public int postEnroll(IBinder token) {
197 checkPermission(MANAGE_FINGERPRINT);
198 return startPostEnroll(token);
199 }
200
201 @Override // Binder call
202 public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
203 final IFingerprintServiceReceiver receiver, final int flags,
Ilya Matyukhinef410e32020-02-04 13:39:48 -0800204 final String opPackageName, IBiometricNativeHandle windowId) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700205 checkPermission(MANAGE_FINGERPRINT);
206
207 final boolean restricted = isRestricted();
208 final int groupId = userId; // default group for fingerprint enrollment
209 final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
210 mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId,
Curtis Belmonte45788542019-07-23 11:07:27 -0700211 cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */,
Ilya Matyukhinef410e32020-02-04 13:39:48 -0800212 ENROLL_TIMEOUT_SEC, windowId) {
Kevin Chyn1429a312019-01-28 16:08:09 -0800213 @Override
214 public boolean shouldVibrate() {
215 return true;
216 }
Kevin Chyn7782d142019-01-18 12:51:33 -0800217
218 @Override
219 protected int statsModality() {
220 return FingerprintService.this.statsModality();
221 }
Kevin Chyn1429a312019-01-28 16:08:09 -0800222 };
Kevin Chyn037c4d52018-06-11 19:17:32 -0700223
Kevin Chyn037c4d52018-06-11 19:17:32 -0700224 enrollInternal(client, userId);
225 }
226
227 @Override // Binder call
228 public void cancelEnrollment(final IBinder token) {
229 checkPermission(MANAGE_FINGERPRINT);
230 cancelEnrollmentInternal(token);
231 }
232
233 @Override // Binder call
234 public void authenticate(final IBinder token, final long opId, final int groupId,
235 final IFingerprintServiceReceiver receiver, final int flags,
Ilya Matyukhinef410e32020-02-04 13:39:48 -0800236 final String opPackageName, IBiometricNativeHandle windowId) {
Kevin Chyn747e29b2019-01-11 17:01:53 -0800237 updateActiveGroup(groupId, opPackageName);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700238 final boolean restricted = isRestricted();
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700239 final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
Kevin Chyn037c4d52018-06-11 19:17:32 -0700240 mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
Kevin Chyne92cdae2018-11-21 16:35:04 -0800241 mCurrentUserId, groupId, opId, restricted, opPackageName,
Ilya Matyukhinef410e32020-02-04 13:39:48 -0800242 0 /* cookie */, false /* requireConfirmation */,
243 windowId);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700244 authenticateInternal(client, opId, opPackageName);
245 }
246
247 @Override // Binder call
Kevin Chyn87f257a2018-11-27 16:26:07 -0800248 public void prepareForAuthentication(IBinder token, long opId, int groupId,
Kevin Chyn23289ef2018-11-28 16:32:36 -0800249 IBiometricServiceReceiverInternal wrapperReceiver, String opPackageName,
Ilya Matyukhinef410e32020-02-04 13:39:48 -0800250 int cookie, int callingUid, int callingPid, int callingUserId,
251 IBiometricNativeHandle windowId) {
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700252 checkPermission(MANAGE_BIOMETRIC);
Kevin Chyn41a80902019-02-06 08:12:15 -0800253 updateActiveGroup(groupId, opPackageName);
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700254 final boolean restricted = true; // BiometricPrompt is always restricted
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700255 final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700256 mDaemonWrapper, mHalDeviceId, token,
Kevin Chyn87f257a2018-11-27 16:26:07 -0800257 new BiometricPromptServiceListenerImpl(wrapperReceiver),
258 mCurrentUserId, groupId, opId, restricted, opPackageName, cookie,
Ilya Matyukhinef410e32020-02-04 13:39:48 -0800259 false /* requireConfirmation */,
260 windowId);
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700261 authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
262 callingUserId);
263 }
264
265 @Override // Binder call
Kevin Chyn87f257a2018-11-27 16:26:07 -0800266 public void startPreparedClient(int cookie) {
267 checkPermission(MANAGE_BIOMETRIC);
268 startCurrentClient(cookie);
269 }
270
271
272 @Override // Binder call
Kevin Chyn037c4d52018-06-11 19:17:32 -0700273 public void cancelAuthentication(final IBinder token, final String opPackageName) {
274 cancelAuthenticationInternal(token, opPackageName);
275 }
276
277 @Override // Binder call
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700278 public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
Kevin Chyne92cdae2018-11-21 16:35:04 -0800279 int callingUid, int callingPid, int callingUserId, boolean fromClient) {
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700280 checkPermission(MANAGE_BIOMETRIC);
Kevin Chyne92cdae2018-11-21 16:35:04 -0800281 cancelAuthenticationInternal(token, opPackageName, callingUid, callingPid,
282 callingUserId, fromClient);
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700283 }
284
285 @Override // Binder call
Kevin Chyn037c4d52018-06-11 19:17:32 -0700286 public void setActiveUser(final int userId) {
287 checkPermission(MANAGE_FINGERPRINT);
288 setActiveUserInternal(userId);
289 }
290
291 @Override // Binder call
292 public void remove(final IBinder token, final int fingerId, final int groupId,
293 final int userId, final IFingerprintServiceReceiver receiver) {
294 checkPermission(MANAGE_FINGERPRINT);
295
296 if (token == null) {
297 Slog.w(TAG, "remove(): token is null");
298 return;
Jim Millera75961472014-06-06 15:00:49 -0700299 }
Jim Millerbe675422015-05-11 20:45:25 -0700300
Kevin Chyn037c4d52018-06-11 19:17:32 -0700301 final boolean restricted = isRestricted();
Kevin Chyn4cc49f72019-04-24 13:53:35 -0700302 final RemovalClient client = new RemovalClient(getContext(), getConstants(),
Kevin Chyn6737c572019-02-08 16:10:54 -0800303 mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
304 fingerId, groupId, userId, restricted, token.toString(), getBiometricUtils()) {
Kevin Chyn7782d142019-01-18 12:51:33 -0800305 @Override
306 protected int statsModality() {
307 return FingerprintService.this.statsModality();
308 }
309 };
Kevin Chyn037c4d52018-06-11 19:17:32 -0700310 removeInternal(client);
311 }
312
313 @Override // Binder call
314 public void enumerate(final IBinder token, final int userId,
315 final IFingerprintServiceReceiver receiver) {
316 checkPermission(MANAGE_FINGERPRINT);
317
318 final boolean restricted = isRestricted();
Kevin Chyn4cc49f72019-04-24 13:53:35 -0700319 final EnumerateClient client = new EnumerateClient(getContext(), getConstants(),
Kevin Chyn6737c572019-02-08 16:10:54 -0800320 mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), userId,
321 userId, restricted, getContext().getOpPackageName()) {
Kevin Chyn7782d142019-01-18 12:51:33 -0800322 @Override
323 protected int statsModality() {
324 return FingerprintService.this.statsModality();
325 }
326 };
Kevin Chyn037c4d52018-06-11 19:17:32 -0700327 enumerateInternal(client);
328 }
329
Kevin Chyna56dff72018-06-19 18:41:12 -0700330 @Override
331 public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback)
332 throws RemoteException {
333 FingerprintService.super.addLockoutResetCallback(callback);
334 }
335
Kevin Chyn037c4d52018-06-11 19:17:32 -0700336 @Override // Binder call
337 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700338 if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700339 return;
Jorim Jaggi5e354222015-09-04 14:17:58 -0700340 }
Jorim Jaggi5e354222015-09-04 14:17:58 -0700341
Kevin Chyn037c4d52018-06-11 19:17:32 -0700342 final long ident = Binder.clearCallingIdentity();
Kevin Chyn09da2942018-03-09 13:13:11 -0800343 try {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700344 if (args.length > 0 && "--proto".equals(args[0])) {
345 dumpProto(fd);
346 } else {
347 dumpInternal(pw);
Kevin Chyn09da2942018-03-09 13:13:11 -0800348 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700349 } finally {
350 Binder.restoreCallingIdentity(ident);
351 }
352 }
353
354 /**
355 * The following methods don't use any common code from BiometricService
356 */
357
Kevin Chyna56dff72018-06-19 18:41:12 -0700358 // TODO: refactor out common code here
Kevin Chyn037c4d52018-06-11 19:17:32 -0700359 @Override // Binder call
Ilya Matyukhinf2da1a12019-09-25 15:31:03 -0700360 public boolean isHardwareDetected(String opPackageName) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700361 if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
362 Binder.getCallingUid(), Binder.getCallingPid(),
363 UserHandle.getCallingUserId())) {
364 return false;
365 }
366
367 final long token = Binder.clearCallingIdentity();
368 try {
369 IBiometricsFingerprint daemon = getFingerprintDaemon();
370 return daemon != null && mHalDeviceId != 0;
371 } finally {
372 Binder.restoreCallingIdentity(token);
373 }
374 }
375
376 @Override // Binder call
377 public void rename(final int fingerId, final int groupId, final String name) {
378 checkPermission(MANAGE_FINGERPRINT);
379 if (!isCurrentUserOrProfile(groupId)) {
380 return;
381 }
382 mHandler.post(new Runnable() {
383 @Override
384 public void run() {
Kevin Chyna56dff72018-06-19 18:41:12 -0700385 getBiometricUtils().renameBiometricForUser(getContext(), groupId,
386 fingerId, name);
Kevin Chyn09da2942018-03-09 13:13:11 -0800387 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700388 });
389 }
390
391 @Override // Binder call
392 public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
393 if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
394 Binder.getCallingUid(), Binder.getCallingPid(),
395 UserHandle.getCallingUserId())) {
396 return Collections.emptyList();
397 }
398
Kevin Chyn6737c572019-02-08 16:10:54 -0800399 return FingerprintService.this.getEnrolledTemplates(userId);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700400 }
401
402 @Override // Binder call
403 public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
404 if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
405 Binder.getCallingUid(), Binder.getCallingPid(),
406 UserHandle.getCallingUserId())) {
407 return false;
408 }
409
410 return FingerprintService.this.hasEnrolledBiometrics(userId);
411 }
412
413 @Override // Binder call
Kevin Chyn7d07c892020-02-18 18:18:17 -0800414 public long getAuthenticatorId() {
415 checkPermission(USE_BIOMETRIC_INTERNAL);
416 return FingerprintService.super.getAuthenticatorId();
Kevin Chyn037c4d52018-06-11 19:17:32 -0700417 }
418
419 @Override // Binder call
420 public void resetTimeout(byte [] token) {
421 checkPermission(RESET_FINGERPRINT_LOCKOUT);
Kevin Chyn1d6a2862019-04-02 16:20:21 -0700422
423 if (!FingerprintService.this.hasEnrolledBiometrics(mCurrentUserId)) {
424 Slog.w(TAG, "Ignoring lockout reset, no templates enrolled");
425 return;
426 }
427
Kevin Chyn037c4d52018-06-11 19:17:32 -0700428 // TODO: confirm security token when we move timeout management into the HAL layer.
429 mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
430 }
431
432 @Override
Kevin Chyn037c4d52018-06-11 19:17:32 -0700433 public boolean isClientActive() {
434 checkPermission(MANAGE_FINGERPRINT);
435 synchronized(FingerprintService.this) {
436 return (getCurrentClient() != null) || (getPendingClient() != null);
437 }
438 }
439
440 @Override
441 public void addClientActiveCallback(IFingerprintClientActiveCallback callback) {
442 checkPermission(MANAGE_FINGERPRINT);
443 mClientActiveCallbacks.add(callback);
444 }
445
446 @Override
447 public void removeClientActiveCallback(IFingerprintClientActiveCallback callback) {
448 checkPermission(MANAGE_FINGERPRINT);
449 mClientActiveCallbacks.remove(callback);
450 }
451 }
452
453 /**
454 * Receives callbacks from the ClientMonitor implementations. The results are forwarded to
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700455 * BiometricPrompt.
456 */
Kevin Chyne92cdae2018-11-21 16:35:04 -0800457 private class BiometricPromptServiceListenerImpl extends BiometricServiceListener {
Kevin Chyn23289ef2018-11-28 16:32:36 -0800458 BiometricPromptServiceListenerImpl(IBiometricServiceReceiverInternal wrapperReceiver) {
Kevin Chyn87f257a2018-11-27 16:26:07 -0800459 super(wrapperReceiver);
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700460 }
461
462 @Override
463 public void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
464 throws RemoteException {
Kevin Chyne92cdae2018-11-21 16:35:04 -0800465 if (getWrapperReceiver() != null) {
466 getWrapperReceiver().onAcquired(acquiredInfo, FingerprintManager.getAcquiredString(
Kevin Chyn8b7a0372018-09-17 15:06:05 -0700467 getContext(), acquiredInfo, vendorCode));
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700468 }
469 }
470
471 @Override
Kevin Chyn87f257a2018-11-27 16:26:07 -0800472 public void onError(long deviceId, int error, int vendorCode, int cookie)
473 throws RemoteException {
Kevin Chyne92cdae2018-11-21 16:35:04 -0800474 if (getWrapperReceiver() != null) {
Ilya Matyukhin0f9da352019-10-03 14:10:01 -0700475 getWrapperReceiver().onError(cookie, TYPE_FINGERPRINT, error, vendorCode);
Kevin Chyna24e9fd2018-08-27 12:39:17 -0700476 }
477 }
478 }
479
480 /**
481 * Receives callbacks from the ClientMonitor implementations. The results are forwarded to
Kevin Chyn037c4d52018-06-11 19:17:32 -0700482 * the FingerprintManager.
483 */
484 private class ServiceListenerImpl implements ServiceListener {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700485 private IFingerprintServiceReceiver mFingerprintServiceReceiver;
486
487 public ServiceListenerImpl(IFingerprintServiceReceiver receiver) {
488 mFingerprintServiceReceiver = receiver;
489 }
490
491 @Override
Kevin Chyna56dff72018-06-19 18:41:12 -0700492 public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining)
Kevin Chyn037c4d52018-06-11 19:17:32 -0700493 throws RemoteException {
494 if (mFingerprintServiceReceiver != null) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700495 final Fingerprint fp = (Fingerprint) identifier;
496 mFingerprintServiceReceiver.onEnrollResult(fp.getDeviceId(), fp.getBiometricId(),
497 fp.getGroupId(), remaining);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700498 }
499 }
500
501 @Override
502 public void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
503 throws RemoteException {
504 if (mFingerprintServiceReceiver != null) {
505 mFingerprintServiceReceiver.onAcquired(deviceId, acquiredInfo, vendorCode);
506 }
507 }
508
509 @Override
510 public void onAuthenticationSucceeded(long deviceId,
Kevin Chyna56dff72018-06-19 18:41:12 -0700511 BiometricAuthenticator.Identifier biometric, int userId)
Kevin Chyn037c4d52018-06-11 19:17:32 -0700512 throws RemoteException {
513 if (mFingerprintServiceReceiver != null) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700514 if (biometric == null || biometric instanceof Fingerprint) {
515 mFingerprintServiceReceiver
516 .onAuthenticationSucceeded(deviceId, (Fingerprint) biometric, userId);
517 } else {
518 Slog.e(TAG, "onAuthenticationSucceeded received non-fingerprint biometric");
519 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700520 }
521 }
522
523 @Override
524 public void onAuthenticationFailed(long deviceId) throws RemoteException {
525 if (mFingerprintServiceReceiver != null) {
526 mFingerprintServiceReceiver.onAuthenticationFailed(deviceId);
527 }
528 }
529
530 @Override
Kevin Chyn87f257a2018-11-27 16:26:07 -0800531 public void onError(long deviceId, int error, int vendorCode, int cookie)
532 throws RemoteException {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700533 if (mFingerprintServiceReceiver != null) {
534 mFingerprintServiceReceiver.onError(deviceId, error, vendorCode);
535 }
536 }
537
538 @Override
Kevin Chyna56dff72018-06-19 18:41:12 -0700539 public void onRemoved(BiometricAuthenticator.Identifier identifier, int remaining)
Kevin Chyn037c4d52018-06-11 19:17:32 -0700540 throws RemoteException {
541 if (mFingerprintServiceReceiver != null) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700542 final Fingerprint fp = (Fingerprint) identifier;
543 mFingerprintServiceReceiver.onRemoved(fp.getDeviceId(), fp.getBiometricId(),
544 fp.getGroupId(), remaining);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700545 }
546 }
547
548 @Override
Kevin Chyna56dff72018-06-19 18:41:12 -0700549 public void onEnumerated(BiometricAuthenticator.Identifier identifier, int remaining)
Kevin Chyn037c4d52018-06-11 19:17:32 -0700550 throws RemoteException {
551 if (mFingerprintServiceReceiver != null) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700552 final Fingerprint fp = (Fingerprint) identifier;
553 mFingerprintServiceReceiver.onEnumerated(fp.getDeviceId(), fp.getBiometricId(),
554 fp.getGroupId(), remaining);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700555 }
556 }
557 }
558
Kevin Chyn4cc49f72019-04-24 13:53:35 -0700559 private final FingerprintConstants mFingerprintConstants = new FingerprintConstants();
Kevin Chyn037c4d52018-06-11 19:17:32 -0700560 private final CopyOnWriteArrayList<IFingerprintClientActiveCallback> mClientActiveCallbacks =
561 new CopyOnWriteArrayList<>();
Kevin Chyn037c4d52018-06-11 19:17:32 -0700562
563 @GuardedBy("this")
564 private IBiometricsFingerprint mDaemon;
Kevin Chyna38653c2019-02-11 17:46:21 -0800565 private final SparseBooleanArray mTimedLockoutCleared;
566 private final SparseIntArray mFailedAttempts;
567 private final AlarmManager mAlarmManager;
568 private final LockoutReceiver mLockoutReceiver = new LockoutReceiver();
569 protected final ResetFailedAttemptsForUserRunnable mResetFailedAttemptsForCurrentUserRunnable =
570 new ResetFailedAttemptsForUserRunnable();
Kevin Chyn037c4d52018-06-11 19:17:32 -0700571
Kevin Chyn037c4d52018-06-11 19:17:32 -0700572 /**
573 * Receives callbacks from the HAL.
574 */
575 private IBiometricsFingerprintClientCallback mDaemonCallback =
576 new IBiometricsFingerprintClientCallback.Stub() {
577 @Override
578 public void onEnrollResult(final long deviceId, final int fingerId, final int groupId,
579 final int remaining) {
580 mHandler.post(() -> {
Kevin Chyna56dff72018-06-19 18:41:12 -0700581 final Fingerprint fingerprint =
582 new Fingerprint(getBiometricUtils().getUniqueName(getContext(), groupId),
583 groupId, fingerId, deviceId);
584 FingerprintService.super.handleEnrollResult(fingerprint, remaining);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700585 });
586 }
587
588 @Override
589 public void onAcquired(final long deviceId, final int acquiredInfo, final int vendorCode) {
Ilya Matyukhind9343702020-02-06 15:34:24 -0800590 onAcquired_2_2(deviceId, acquiredInfo, vendorCode);
591 }
592
593 @Override
594 public void onAcquired_2_2(long deviceId, int acquiredInfo, int vendorCode) {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700595 mHandler.post(() -> {
596 FingerprintService.super.handleAcquired(deviceId, acquiredInfo, vendorCode);
597 });
598 }
599
600 @Override
601 public void onAuthenticated(final long deviceId, final int fingerId, final int groupId,
602 ArrayList<Byte> token) {
603 mHandler.post(() -> {
Kevin Chynb528d692018-07-20 11:53:14 -0700604 Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
605 FingerprintService.super.handleAuthenticated(fp, token);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700606 });
607 }
608
609 @Override
610 public void onError(final long deviceId, final int error, final int vendorCode) {
611 mHandler.post(() -> {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700612 FingerprintService.super.handleError(deviceId, error, vendorCode);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700613 // TODO: this chunk of code should be common to all biometric services
614 if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) {
615 // If we get HW_UNAVAILABLE, try to connect again later...
616 Slog.w(TAG, "Got ERROR_HW_UNAVAILABLE; try reconnecting next client.");
617 synchronized (this) {
618 mDaemon = null;
619 mHalDeviceId = 0;
620 mCurrentUserId = UserHandle.USER_NULL;
Kevin Chyn09da2942018-03-09 13:13:11 -0800621 }
622 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700623 });
624 }
625
626 @Override
627 public void onRemoved(final long deviceId, final int fingerId, final int groupId,
628 final int remaining) {
629 mHandler.post(() -> {
630 ClientMonitor client = getCurrentClient();
Kevin Chyna56dff72018-06-19 18:41:12 -0700631 final Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
632 FingerprintService.super.handleRemoved(fp, remaining);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700633 });
634 }
635
636 @Override
637 public void onEnumerate(final long deviceId, final int fingerId, final int groupId,
638 final int remaining) {
639 mHandler.post(() -> {
Kevin Chyna56dff72018-06-19 18:41:12 -0700640 final Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
Kevin Chyn6737c572019-02-08 16:10:54 -0800641 FingerprintService.super.handleEnumerate(fp, remaining);
Kevin Chyn037c4d52018-06-11 19:17:32 -0700642 });
643
644 }
645 };
646
647 /**
648 * Wraps the HAL-specific code and is passed to the ClientMonitor implementations so that they
649 * can be shared between the multiple biometric services.
650 */
651 private final DaemonWrapper mDaemonWrapper = new DaemonWrapper() {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700652 @Override
Ilya Matyukhinef410e32020-02-04 13:39:48 -0800653 public int authenticate(long operationId, int groupId, NativeHandle windowId)
654 throws RemoteException {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700655 IBiometricsFingerprint daemon = getFingerprintDaemon();
656 if (daemon == null) {
657 Slog.w(TAG, "authenticate(): no fingerprint HAL!");
658 return ERROR_ESRCH;
Kevin Chyn09da2942018-03-09 13:13:11 -0800659 }
Ilya Matyukhinef410e32020-02-04 13:39:48 -0800660 android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprint daemon22 =
661 android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprint.castFrom(
662 daemon);
663 if (daemon22 != null) {
664 return daemon22.authenticate_2_2(operationId, groupId, windowId);
665 } else if (windowId == null) {
666 return daemon.authenticate(operationId, groupId);
667 } else {
668 Slog.e(TAG, "authenticate(): windowId is only supported in @2.2 HAL");
669 return ERROR_ESRCH;
670 }
Kevin Chyn037c4d52018-06-11 19:17:32 -0700671 }
672
673 @Override
674 public int cancel() throws RemoteException {
675 IBiometricsFingerprint daemon = getFingerprintDaemon();
676 if (daemon == null) {
677 Slog.w(TAG, "cancel(): no fingerprint HAL!");
678 return ERROR_ESRCH;
679 }
680 return daemon.cancel();
681 }
682
683 @Override
684 public int remove(int groupId, int biometricId) throws RemoteException {
685 IBiometricsFingerprint daemon = getFingerprintDaemon();
686 if (daemon == null) {
687 Slog.w(TAG, "remove(): no fingerprint HAL!");
688 return ERROR_ESRCH;
689 }
690 return daemon.remove(groupId, biometricId);
691 }
692
693 @Override
694 public int enumerate() throws RemoteException {
695 IBiometricsFingerprint daemon = getFingerprintDaemon();
696 if (daemon == null) {
697 Slog.w(TAG, "enumerate(): no fingerprint HAL!");
698 return ERROR_ESRCH;
699 }
700 return daemon.enumerate();
701 }
702
703 @Override
Kevin Chyn1f16c2d2018-12-07 13:06:08 -0800704 public int enroll(byte[] cryptoToken, int groupId, int timeout,
Ilya Matyukhinef410e32020-02-04 13:39:48 -0800705 ArrayList<Integer> disabledFeatures, NativeHandle windowId) throws RemoteException {
Kevin Chyn037c4d52018-06-11 19:17:32 -0700706 IBiometricsFingerprint daemon = getFingerprintDaemon();
707 if (daemon == null) {
708 Slog.w(TAG, "enroll(): no fingerprint HAL!");
709 return ERROR_ESRCH;
710 }
Ilya Matyukhinef410e32020-02-04 13:39:48 -0800711 android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprint daemon22 =
712 android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprint.castFrom(
713 daemon);
714 if (daemon22 != null) {
715 ArrayList<Byte> cryptoTokenAsList = new ArrayList<>(cryptoToken.length);
716 for (byte b : cryptoToken) {
717 cryptoTokenAsList.add(b);
718 }
719 return daemon22.enroll_2_2(cryptoTokenAsList, groupId, timeout, windowId);
720 } else if (windowId == null) {
721 return daemon.enroll(cryptoToken, groupId, timeout);
722 } else {
723 Slog.e(TAG, "enroll(): windowId is only supported in @2.2 HAL");
724 return ERROR_ESRCH;
725 }
Kevin Chyn09da2942018-03-09 13:13:11 -0800726 }
Kevin Chyna38653c2019-02-11 17:46:21 -0800727
728 @Override
729 public void resetLockout(byte[] token) throws RemoteException {
730 // TODO: confirm security token when we move timeout management into the HAL layer.
731 Slog.e(TAG, "Not supported");
732 return;
733 }
Kevin Chyn09da2942018-03-09 13:13:11 -0800734 };
735
Jim Millera75961472014-06-06 15:00:49 -0700736 public FingerprintService(Context context) {
737 super(context);
Kevin Chyna38653c2019-02-11 17:46:21 -0800738 mTimedLockoutCleared = new SparseBooleanArray();
739 mFailedAttempts = new SparseIntArray();
740 mAlarmManager = context.getSystemService(AlarmManager.class);
741 context.registerReceiver(mLockoutReceiver, new IntentFilter(getLockoutResetIntent()),
742 getLockoutBroadcastPermission(), null /* handler */);
Jim Millera75961472014-06-06 15:00:49 -0700743 }
744
Jim Millerbe675422015-05-11 20:45:25 -0700745 @Override
Kevin Chyn037c4d52018-06-11 19:17:32 -0700746 public void onStart() {
747 super.onStart();
748 publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
Felipe Lemeb68b7692019-10-09 10:43:03 -0700749 SystemServerInitThreadPool.submit(this::getFingerprintDaemon, TAG + ".onStart");
Jim Millera75961472014-06-06 15:00:49 -0700750 }
751
Kevin Chyn037c4d52018-06-11 19:17:32 -0700752 @Override
753 protected String getTag() {
754 return TAG;
755 }
756
757 @Override
Kevin Chyn6737c572019-02-08 16:10:54 -0800758 protected DaemonWrapper getDaemonWrapper() {
759 return mDaemonWrapper;
760 }
761
762 @Override
Kevin Chyna56dff72018-06-19 18:41:12 -0700763 protected BiometricUtils getBiometricUtils() {
764 return FingerprintUtils.getInstance();
765 }
766
767 @Override
Kevin Chyn4cc49f72019-04-24 13:53:35 -0700768 protected Constants getConstants() {
769 return mFingerprintConstants;
Kevin Chyn037c4d52018-06-11 19:17:32 -0700770 }
771
772 @Override
773 protected boolean hasReachedEnrollmentLimit(int userId) {
Kevin Chyna56dff72018-06-19 18:41:12 -0700774 final int limit = getContext().getResources().getInteger(
Kevin Chyn037c4d52018-06-11 19:17:32 -0700775 com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
Kevin Chyn6737c572019-02-08 16:10:54 -0800776 final int enrolled = FingerprintService.this.getEnrolledTemplates(userId).size();
Kevin Chyn037c4d52018-06-11 19:17:32 -0700777 if (enrolled >= limit) {
778 Slog.w(TAG, "Too many fingerprints registered");
779 return true;
780 }
781 return false;
782 }
783
784 @Override
Kevin Chyn9ba99912019-01-16 16:24:36 -0800785 public void serviceDied(long cookie) {
786 super.serviceDied(cookie);
787 mDaemon = null;
788 }
789
790 @Override
Kevin Chyn037c4d52018-06-11 19:17:32 -0700791 protected void updateActiveGroup(int userId, String clientPackage) {
792 IBiometricsFingerprint daemon = getFingerprintDaemon();
793
794 if (daemon != null) {
795 try {
796 userId = getUserOrWorkProfileId(clientPackage, userId);
797 if (userId != mCurrentUserId) {
798 int firstSdkInt = Build.VERSION.FIRST_SDK_INT;
799 if (firstSdkInt < Build.VERSION_CODES.BASE) {
800 Slog.e(TAG, "First SDK version " + firstSdkInt + " is invalid; must be " +
801 "at least VERSION_CODES.BASE");
802 }
803 File baseDir;
804 if (firstSdkInt <= Build.VERSION_CODES.O_MR1) {
805 baseDir = Environment.getUserSystemDirectory(userId);
806 } else {
807 baseDir = Environment.getDataVendorDeDirectory(userId);
808 }
809
810 File fpDir = new File(baseDir, FP_DATA_DIR);
811 if (!fpDir.exists()) {
812 if (!fpDir.mkdir()) {
813 Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath());
814 return;
815 }
816 // Calling mkdir() from this process will create a directory with our
817 // permissions (inherited from the containing dir). This command fixes
818 // the label.
819 if (!SELinux.restorecon(fpDir)) {
820 Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
821 return;
822 }
823 }
824
825 daemon.setActiveGroup(userId, fpDir.getAbsolutePath());
826 mCurrentUserId = userId;
827 }
828 mAuthenticatorIds.put(userId,
829 hasEnrolledBiometrics(userId) ? daemon.getAuthenticatorId() : 0L);
830 } catch (RemoteException e) {
831 Slog.e(TAG, "Failed to setActiveGroup():", e);
832 }
833 }
834 }
835
836 @Override
837 protected String getLockoutResetIntent() {
838 return ACTION_LOCKOUT_RESET;
839 }
840
841 @Override
842 protected String getLockoutBroadcastPermission() {
843 return RESET_FINGERPRINT_LOCKOUT;
844 }
845
846 @Override
847 protected long getHalDeviceId() {
848 return mHalDeviceId;
849 }
850
851 @Override
Kevin Chyn037c4d52018-06-11 19:17:32 -0700852 protected boolean hasEnrolledBiometrics(int userId) {
853 if (userId != UserHandle.getCallingUserId()) {
854 checkPermission(INTERACT_ACROSS_USERS);
855 }
Kevin Chyna56dff72018-06-19 18:41:12 -0700856 return getBiometricUtils().getBiometricsForUser(getContext(), userId).size() > 0;
Kevin Chyn037c4d52018-06-11 19:17:32 -0700857 }
858
859 @Override
860 protected String getManageBiometricPermission() {
861 return MANAGE_FINGERPRINT;
862 }
863
864 @Override
865 protected void checkUseBiometricPermission() {
866 if (getContext().checkCallingPermission(USE_FINGERPRINT)
867 != PackageManager.PERMISSION_GRANTED) {
868 checkPermission(USE_BIOMETRIC);
869 }
870 }
871
872 @Override
Kevin Chynb3c05aa2018-09-21 16:50:32 -0700873 protected boolean checkAppOps(int uid, String opPackageName) {
874 boolean appOpsOk = false;
875 if (mAppOps.noteOp(AppOpsManager.OP_USE_BIOMETRIC, uid, opPackageName)
876 == AppOpsManager.MODE_ALLOWED) {
877 appOpsOk = true;
878 } else if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
879 == AppOpsManager.MODE_ALLOWED) {
880 appOpsOk = true;
881 }
882 return appOpsOk;
Kevin Chyn037c4d52018-06-11 19:17:32 -0700883 }
884
885 @Override
Kevin Chyn6737c572019-02-08 16:10:54 -0800886 protected List<Fingerprint> getEnrolledTemplates(int userId) {
Kevin Chyn8addd4f2019-04-25 12:34:15 -0700887 if (userId != UserHandle.getCallingUserId()) {
888 checkPermission(INTERACT_ACROSS_USERS);
889 }
Kevin Chyn6737c572019-02-08 16:10:54 -0800890 return getBiometricUtils().getBiometricsForUser(getContext(), userId);
891 }
892
893 @Override
Kevin Chyn037c4d52018-06-11 19:17:32 -0700894 protected void notifyClientActiveCallbacks(boolean isActive) {
895 List<IFingerprintClientActiveCallback> callbacks = mClientActiveCallbacks;
896 for (int i = 0; i < callbacks.size(); i++) {
897 try {
898 callbacks.get(i).onClientActiveChanged(isActive);
899 } catch (RemoteException re) {
900 // If the remote is dead, stop notifying it
901 mClientActiveCallbacks.remove(callbacks.get(i));
902 }
903 }
904 }
905
Kevin Chyn7782d142019-01-18 12:51:33 -0800906 @Override
907 protected int statsModality() {
908 return BiometricsProtoEnums.MODALITY_FINGERPRINT;
909 }
910
Kevin Chyna38653c2019-02-11 17:46:21 -0800911 @Override
912 protected int getLockoutMode() {
913 final int currentUser = ActivityManager.getCurrentUser();
914 final int failedAttempts = mFailedAttempts.get(currentUser, 0);
915 if (failedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) {
916 return AuthenticationClient.LOCKOUT_PERMANENT;
917 } else if (failedAttempts > 0
918 && !mTimedLockoutCleared.get(currentUser, false)
919 && (failedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) {
920 return AuthenticationClient.LOCKOUT_TIMED;
921 }
922 return AuthenticationClient.LOCKOUT_NONE;
923 }
924
Kevin Chyn037c4d52018-06-11 19:17:32 -0700925 /** Gets the fingerprint daemon */
926 private synchronized IBiometricsFingerprint getFingerprintDaemon() {
Jim Miller40e46452016-12-16 18:38:53 -0800927 if (mDaemon == null) {
Kevin Chynedd71f92017-09-01 16:09:57 -0700928 Slog.v(TAG, "mDaemon was null, reconnect to fingerprint");
Jim Miller40e46452016-12-16 18:38:53 -0800929 try {
Yifan Hong25d5eaa2017-03-16 15:25:43 -0700930 mDaemon = IBiometricsFingerprint.getService();
Jim Miller40e46452016-12-16 18:38:53 -0800931 } catch (java.util.NoSuchElementException e) {
932 // Service doesn't exist or cannot be opened. Logged below.
933 } catch (RemoteException e) {
934 Slog.e(TAG, "Failed to get biometric interface", e);
Jim Millera75961472014-06-06 15:00:49 -0700935 }
Jim Miller40e46452016-12-16 18:38:53 -0800936 if (mDaemon == null) {
937 Slog.w(TAG, "fingerprint HIDL not available");
938 return null;
939 }
940
941 mDaemon.asBinder().linkToDeath(this, 0);
942
943 try {
944 mHalDeviceId = mDaemon.setNotify(mDaemonCallback);
945 } catch (RemoteException e) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700946 Slog.e(TAG, "Failed to open fingerprint HAL", e);
Jim Miller40e46452016-12-16 18:38:53 -0800947 mDaemon = null; // try again later!
948 }
949
950 if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
951 if (mHalDeviceId != 0) {
Charles Heda88f0e2017-02-02 18:29:13 +0000952 loadAuthenticatorIds();
Jim Miller40e46452016-12-16 18:38:53 -0800953 updateActiveGroup(ActivityManager.getCurrentUser(), null);
Kevin Chyn6737c572019-02-08 16:10:54 -0800954 doTemplateCleanupForUser(ActivityManager.getCurrentUser());
Jim Miller40e46452016-12-16 18:38:53 -0800955 } else {
956 Slog.w(TAG, "Failed to open Fingerprint HAL!");
Kevin Chyna56dff72018-06-19 18:41:12 -0700957 MetricsLogger.count(getContext(), "fingerprintd_openhal_error", 1);
Jim Miller40e46452016-12-16 18:38:53 -0800958 mDaemon = null;
959 }
Jim Millerce7eb6d2015-04-03 19:29:13 -0700960 }
Jim Miller40e46452016-12-16 18:38:53 -0800961 return mDaemon;
Jim Millerbe675422015-05-11 20:45:25 -0700962 }
963
Kevin Chyn037c4d52018-06-11 19:17:32 -0700964 private long startPreEnroll(IBinder token) {
Jim Miller40e46452016-12-16 18:38:53 -0800965 IBiometricsFingerprint daemon = getFingerprintDaemon();
Jim Millerbe675422015-05-11 20:45:25 -0700966 if (daemon == null) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700967 Slog.w(TAG, "startPreEnroll: no fingerprint HAL!");
Jim Millerbe675422015-05-11 20:45:25 -0700968 return 0;
969 }
970 try {
971 return daemon.preEnroll();
972 } catch (RemoteException e) {
973 Slog.e(TAG, "startPreEnroll failed", e);
974 }
975 return 0;
Jim Millerce7eb6d2015-04-03 19:29:13 -0700976 }
977
Kevin Chyn037c4d52018-06-11 19:17:32 -0700978 private int startPostEnroll(IBinder token) {
Jim Miller40e46452016-12-16 18:38:53 -0800979 IBiometricsFingerprint daemon = getFingerprintDaemon();
Sasha Levitskiye0943cf2015-07-08 13:22:20 -0700980 if (daemon == null) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700981 Slog.w(TAG, "startPostEnroll: no fingerprint HAL!");
Sasha Levitskiye0943cf2015-07-08 13:22:20 -0700982 return 0;
983 }
984 try {
985 return daemon.postEnroll();
986 } catch (RemoteException e) {
987 Slog.e(TAG, "startPostEnroll failed", e);
988 }
989 return 0;
990 }
991
Kevin Chyna38653c2019-02-11 17:46:21 -0800992 // Attempt counter should only be cleared when Keyguard goes away or when
993 // a biometric is successfully authenticated. Lockout should eventually be done below the HAL.
994 // See AuthenticationClient#shouldFrameworkHandleLockout().
995 private void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
996 if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
997 Slog.v(getTag(), "Reset biometric lockout, clearAttemptCounter=" + clearAttemptCounter);
998 }
999 if (clearAttemptCounter) {
1000 mFailedAttempts.put(userId, 0);
1001 }
1002 mTimedLockoutCleared.put(userId, true);
1003 // If we're asked to reset failed attempts externally (i.e. from Keyguard),
1004 // the alarm might still be pending; remove it.
1005 cancelLockoutResetForUser(userId);
1006 notifyLockoutResetMonitors();
1007 }
1008
1009
1010 private void cancelLockoutResetForUser(int userId) {
1011 mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
1012 }
1013
1014 private void scheduleLockoutResetForUser(int userId) {
1015 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1016 SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
1017 getLockoutResetIntentForUser(userId));
1018 }
1019
1020 private PendingIntent getLockoutResetIntentForUser(int userId) {
1021 return PendingIntent.getBroadcast(getContext(), userId,
1022 new Intent(getLockoutResetIntent()).putExtra(KEY_LOCKOUT_RESET_USER, userId),
1023 PendingIntent.FLAG_UPDATE_CURRENT);
1024 }
1025
Chris Wrenc510ad52015-08-14 15:43:15 -04001026 private void dumpInternal(PrintWriter pw) {
1027 JSONObject dump = new JSONObject();
1028 try {
1029 dump.put("service", "Fingerprint Manager");
1030
1031 JSONArray sets = new JSONArray();
1032 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1033 final int userId = user.getUserHandle().getIdentifier();
Kevin Chyna56dff72018-06-19 18:41:12 -07001034 final int N = getBiometricUtils().getBiometricsForUser(getContext(), userId).size();
Jim Millerbcc100a2016-07-06 14:16:49 -07001035 PerformanceStats stats = mPerformanceMap.get(userId);
1036 PerformanceStats cryptoStats = mCryptoPerformanceMap.get(userId);
Chris Wrenc510ad52015-08-14 15:43:15 -04001037 JSONObject set = new JSONObject();
1038 set.put("id", userId);
1039 set.put("count", N);
Jim Millerbcc100a2016-07-06 14:16:49 -07001040 set.put("accept", (stats != null) ? stats.accept : 0);
1041 set.put("reject", (stats != null) ? stats.reject : 0);
1042 set.put("acquire", (stats != null) ? stats.acquire : 0);
1043 set.put("lockout", (stats != null) ? stats.lockout : 0);
Kevin Chyndf9d33e2017-05-03 21:40:12 -07001044 set.put("permanentLockout", (stats != null) ? stats.permanentLockout : 0);
Jim Millerbcc100a2016-07-06 14:16:49 -07001045 // cryptoStats measures statistics about secure fingerprint transactions
1046 // (e.g. to unlock password storage, make secure purchases, etc.)
1047 set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0);
1048 set.put("rejectCrypto", (cryptoStats != null) ? cryptoStats.reject : 0);
1049 set.put("acquireCrypto", (cryptoStats != null) ? cryptoStats.acquire : 0);
1050 set.put("lockoutCrypto", (cryptoStats != null) ? cryptoStats.lockout : 0);
Kweku Adamscd7c35c2017-09-14 16:45:06 -07001051 set.put("permanentLockoutCrypto",
1052 (cryptoStats != null) ? cryptoStats.permanentLockout : 0);
Chris Wrenc510ad52015-08-14 15:43:15 -04001053 sets.put(set);
1054 }
1055
1056 dump.put("prints", sets);
1057 } catch (JSONException e) {
1058 Slog.e(TAG, "dump formatting failure", e);
1059 }
1060 pw.println(dump);
Kevin Chyn9bc1d492019-06-21 15:31:50 -07001061 pw.println("HAL deaths since last reboot: " + mHALDeathCount);
Jim Millera75961472014-06-06 15:00:49 -07001062 }
1063
Joe Onorato1754d742016-11-21 17:51:35 -08001064 private void dumpProto(FileDescriptor fd) {
1065 final ProtoOutputStream proto = new ProtoOutputStream(fd);
1066 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1067 final int userId = user.getUserHandle().getIdentifier();
1068
1069 final long userToken = proto.start(FingerprintServiceDumpProto.USERS);
1070
1071 proto.write(FingerprintUserStatsProto.USER_ID, userId);
1072 proto.write(FingerprintUserStatsProto.NUM_FINGERPRINTS,
Kevin Chyna56dff72018-06-19 18:41:12 -07001073 getBiometricUtils().getBiometricsForUser(getContext(), userId).size());
Joe Onorato1754d742016-11-21 17:51:35 -08001074
1075 // Normal fingerprint authentications (e.g. lockscreen)
1076 final PerformanceStats normal = mPerformanceMap.get(userId);
1077 if (normal != null) {
1078 final long countsToken = proto.start(FingerprintUserStatsProto.NORMAL);
Kweku Adamsfd257d62017-10-25 17:53:50 -07001079 proto.write(PerformanceStatsProto.ACCEPT, normal.accept);
1080 proto.write(PerformanceStatsProto.REJECT, normal.reject);
1081 proto.write(PerformanceStatsProto.ACQUIRE, normal.acquire);
1082 proto.write(PerformanceStatsProto.LOCKOUT, normal.lockout);
1083 proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, normal.permanentLockout);
Joe Onorato1754d742016-11-21 17:51:35 -08001084 proto.end(countsToken);
1085 }
1086
1087 // Statistics about secure fingerprint transactions (e.g. to unlock password
1088 // storage, make secure purchases, etc.)
Kevin Chyn9310f5c2017-02-21 17:22:54 -08001089 final PerformanceStats crypto = mCryptoPerformanceMap.get(userId);
Joe Onorato1754d742016-11-21 17:51:35 -08001090 if (crypto != null) {
1091 final long countsToken = proto.start(FingerprintUserStatsProto.CRYPTO);
Kweku Adamsfd257d62017-10-25 17:53:50 -07001092 proto.write(PerformanceStatsProto.ACCEPT, crypto.accept);
1093 proto.write(PerformanceStatsProto.REJECT, crypto.reject);
1094 proto.write(PerformanceStatsProto.ACQUIRE, crypto.acquire);
1095 proto.write(PerformanceStatsProto.LOCKOUT, crypto.lockout);
1096 proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, crypto.permanentLockout);
Joe Onorato1754d742016-11-21 17:51:35 -08001097 proto.end(countsToken);
1098 }
1099
1100 proto.end(userToken);
1101 }
1102 proto.flush();
Kevin Chyn89a55cb2018-03-29 14:52:59 -07001103 mPerformanceMap.clear();
1104 mCryptoPerformanceMap.clear();
Joe Onorato1754d742016-11-21 17:51:35 -08001105 }
Jim Millera75961472014-06-06 15:00:49 -07001106}