blob: 3e1958d9edfca7eb39c1a1530d22ff994184c62b [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
17package com.android.server.fingerprint;
18
Charles He959ac8e2017-03-27 21:16:20 +010019import static android.Manifest.permission.INTERACT_ACROSS_USERS;
20import static android.Manifest.permission.MANAGE_FINGERPRINT;
21import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
22import static android.Manifest.permission.USE_FINGERPRINT;
Charles He29b3a8a2017-05-04 16:02:38 +010023import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
Charles He959ac8e2017-03-27 21:16:20 +010024
Sasha Levitskiy80db9ba2015-05-08 14:31:48 -070025import android.app.ActivityManager;
Jim Miller975f1452015-08-31 18:18:22 -070026import android.app.ActivityManager.RunningAppProcessInfo;
Jorim Jaggi5e354222015-09-04 14:17:58 -070027import android.app.AlarmManager;
Svetoslav4af76a52015-04-29 15:29:46 -070028import android.app.AppOpsManager;
Jorim Jaggi5e354222015-09-04 14:17:58 -070029import android.app.PendingIntent;
Fyodor Kupolov6005b3f2015-11-23 17:41:50 -080030import android.app.SynchronousUserSwitchObserver;
Jorim Jaggi5e354222015-09-04 14:17:58 -070031import android.content.BroadcastReceiver;
Charles He29b3a8a2017-05-04 16:02:38 +010032import android.content.ComponentName;
Jim Millera75961472014-06-06 15:00:49 -070033import android.content.Context;
Jorim Jaggi5e354222015-09-04 14:17:58 -070034import 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;
Charles He959ac8e2017-03-27 21:16:20 +010038import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
39import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
40import android.hardware.fingerprint.Fingerprint;
41import android.hardware.fingerprint.FingerprintManager;
Phil Weaver27fcd9c2017-01-20 15:57:24 -080042import android.hardware.fingerprint.IFingerprintClientActiveCallback;
Kevin Chynaae4a152018-01-18 11:48:09 -080043import android.hardware.fingerprint.IFingerprintDialogReceiver;
Charles He959ac8e2017-03-27 21:16:20 +010044import android.hardware.fingerprint.IFingerprintService;
Jorim Jaggi3a464782015-08-28 16:59:13 -070045import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
Charles He959ac8e2017-03-27 21:16:20 +010046import android.hardware.fingerprint.IFingerprintServiceReceiver;
Svetoslav4af76a52015-04-29 15:29:46 -070047import android.os.Binder;
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +010048import android.os.Bundle;
Jorim Jaggi3a464782015-08-28 16:59:13 -070049import android.os.DeadObjectException;
Sasha Levitskiy80db9ba2015-05-08 14:31:48 -070050import android.os.Environment;
Jim Millera75961472014-06-06 15:00:49 -070051import android.os.Handler;
52import android.os.IBinder;
Jim Miller40e46452016-12-16 18:38:53 -080053import android.os.IHwBinder;
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +010054import android.os.IRemoteCallback;
Jim Millerdca15d22015-06-16 20:55:13 -070055import android.os.PowerManager;
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +010056import android.os.PowerManager.WakeLock;
Jim Millera75961472014-06-06 15:00:49 -070057import android.os.RemoteException;
Jim Miller16ef71f2015-05-21 17:02:21 -070058import android.os.SELinux;
Kevin Chynaae4a152018-01-18 11:48:09 -080059import android.os.ServiceManager;
Jim Millerdca15d22015-06-16 20:55:13 -070060import android.os.SystemClock;
Jim Miller599ef0e2015-06-15 20:39:44 -070061import android.os.UserHandle;
Jim Millercb7d9e92015-06-16 15:05:48 -070062import android.os.UserManager;
Charles He959ac8e2017-03-27 21:16:20 +010063import android.security.KeyStore;
Jim Millera75961472014-06-06 15:00:49 -070064import android.util.Slog;
Kevin Chyn5457cba2017-08-30 15:28:28 -070065import android.util.SparseBooleanArray;
66import android.util.SparseIntArray;
Joe Onorato1754d742016-11-21 17:51:35 -080067import android.util.proto.ProtoOutputStream;
Jim Millera75961472014-06-06 15:00:49 -070068
Fyodor Kupolov449e7082016-10-31 15:06:12 -070069import com.android.internal.annotations.GuardedBy;
Chris Wrenc510ad52015-08-14 15:43:15 -040070import com.android.internal.logging.MetricsLogger;
Kevin Chynaae4a152018-01-18 11:48:09 -080071import com.android.internal.statusbar.IStatusBarService;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060072import com.android.internal.util.DumpUtils;
Fyodor Kupolove29a5a12016-12-16 16:14:17 -080073import com.android.server.SystemServerInitThreadPool;
Jim Millera75961472014-06-06 15:00:49 -070074import com.android.server.SystemService;
75
Chris Wrenc510ad52015-08-14 15:43:15 -040076import org.json.JSONArray;
77import org.json.JSONException;
78import org.json.JSONObject;
79
Sasha Levitskiy80db9ba2015-05-08 14:31:48 -070080import java.io.File;
Chris Wrenc510ad52015-08-14 15:43:15 -040081import java.io.FileDescriptor;
82import java.io.PrintWriter;
Jorim Jaggi3a464782015-08-28 16:59:13 -070083import java.util.ArrayList;
Svetoslav4af76a52015-04-29 15:29:46 -070084import java.util.Collections;
Jim Millerbcc100a2016-07-06 14:16:49 -070085import java.util.HashMap;
Jim Miller9f0753f2015-03-23 23:59:22 -070086import java.util.List;
Charles Heda88f0e2017-02-02 18:29:13 +000087import java.util.Map;
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 */
Jim Miller40e46452016-12-16 18:38:53 -080097public class FingerprintService extends SystemService implements IHwBinder.DeathRecipient {
Jim Millercb2ce6f2016-04-13 20:28:18 -070098 static final String TAG = "FingerprintService";
99 static final boolean DEBUG = true;
Kevin Chynedd71f92017-09-01 16:09:57 -0700100 private static final boolean CLEANUP_UNUSED_FP = true;
Jim Millerbe675422015-05-11 20:45:25 -0700101 private static final String FP_DATA_DIR = "fpdata";
Jim Millerbe675422015-05-11 20:45:25 -0700102 private static final int MSG_USER_SWITCHING = 10;
Jorim Jaggi5e354222015-09-04 14:17:58 -0700103 private static final String ACTION_LOCKOUT_RESET =
104 "com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
Kevin Chyn5457cba2017-08-30 15:28:28 -0700105 private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
Jim Millerbe675422015-05-11 20:45:25 -0700106
Jim Millerbcc100a2016-07-06 14:16:49 -0700107 private class PerformanceStats {
108 int accept; // number of accepted fingerprints
109 int reject; // number of rejected fingerprints
110 int acquire; // total number of acquisitions. Should be >= accept+reject due to poor image
111 // acquisition in some cases (too fast, too slow, dirty sensor, etc.)
112 int lockout; // total number of lockouts
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700113 int permanentLockout; // total number of permanent lockouts
Jim Millerbcc100a2016-07-06 14:16:49 -0700114 }
115
Jorim Jaggi3a464782015-08-28 16:59:13 -0700116 private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
117 new ArrayList<>();
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800118 private final CopyOnWriteArrayList<IFingerprintClientActiveCallback> mClientActiveCallbacks =
119 new CopyOnWriteArrayList<>();
Charles Heda88f0e2017-02-02 18:29:13 +0000120 private final Map<Integer, Long> mAuthenticatorIds =
121 Collections.synchronizedMap(new HashMap<>());
Svetoslav4af76a52015-04-29 15:29:46 -0700122 private final AppOpsManager mAppOps;
Jim Milleraf281ca2015-04-20 19:04:21 -0700123 private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700124 private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5;
125 private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;
126
Jim Miller3d5e3962016-06-08 01:52:50 +0000127 private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
Jim Miller975f1452015-08-31 18:18:22 -0700128 private final String mKeyguardPackage;
Charles He959ac8e2017-03-27 21:16:20 +0100129 private int mCurrentUserId = UserHandle.USER_NULL;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700130 private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance();
131 private Context mContext;
132 private long mHalDeviceId;
Kevin Chyn5457cba2017-08-30 15:28:28 -0700133 private SparseBooleanArray mTimedLockoutCleared;
134 private SparseIntArray mFailedAttempts;
Fyodor Kupolov449e7082016-10-31 15:06:12 -0700135 @GuardedBy("this")
Jim Miller40e46452016-12-16 18:38:53 -0800136 private IBiometricsFingerprint mDaemon;
Kevin Chynaae4a152018-01-18 11:48:09 -0800137 private IStatusBarService mStatusBarService;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700138 private final PowerManager mPowerManager;
139 private final AlarmManager mAlarmManager;
140 private final UserManager mUserManager;
141 private ClientMonitor mCurrentClient;
142 private ClientMonitor mPendingClient;
Jim Millerbcc100a2016-07-06 14:16:49 -0700143 private PerformanceStats mPerformanceStats;
144
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700145 private IBinder mToken = new Binder(); // used for internal FingerprintService enumeration
Kevin Chynedd71f92017-09-01 16:09:57 -0700146 private ArrayList<UserFingerprint> mUnknownFingerprints = new ArrayList<>(); // hw fingerprints
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700147
148 private class UserFingerprint {
149 Fingerprint f;
150 int userId;
151 public UserFingerprint(Fingerprint f, int userId) {
152 this.f = f;
153 this.userId = userId;
154 }
155 }
156
Jim Millerbcc100a2016-07-06 14:16:49 -0700157 // Normal fingerprint authentications are tracked by mPerformanceMap.
Jim Miller40e46452016-12-16 18:38:53 -0800158 private HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
Jim Millerbcc100a2016-07-06 14:16:49 -0700159
160 // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
Jim Miller40e46452016-12-16 18:38:53 -0800161 private HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
Jim Millerce7eb6d2015-04-03 19:29:13 -0700162
Jim Millercb2ce6f2016-04-13 20:28:18 -0700163 private Handler mHandler = new Handler() {
Jim Miller80a776e2015-07-15 18:57:14 -0700164 @Override
Jim Millera75961472014-06-06 15:00:49 -0700165 public void handleMessage(android.os.Message msg) {
166 switch (msg.what) {
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -0700167 case MSG_USER_SWITCHING:
168 handleUserSwitching(msg.arg1);
169 break;
170
Jim Millera75961472014-06-06 15:00:49 -0700171 default:
172 Slog.w(TAG, "Unknown message:" + msg.what);
173 }
174 }
175 };
Jim Millerbe675422015-05-11 20:45:25 -0700176
Jorim Jaggi5e354222015-09-04 14:17:58 -0700177 private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
178 @Override
179 public void onReceive(Context context, Intent intent) {
180 if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700181 final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
182 resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
Jorim Jaggi5e354222015-09-04 14:17:58 -0700183 }
184 }
185 };
186
Kevin Chyn5457cba2017-08-30 15:28:28 -0700187 private final Runnable mResetFailedAttemptsForCurrentUserRunnable = new Runnable() {
Jim Millerfe6439f2015-04-11 18:07:57 -0700188 @Override
189 public void run() {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700190 resetFailedAttemptsForUser(true /* clearAttemptCounter */,
191 ActivityManager.getCurrentUser());
Jim Millerfe6439f2015-04-11 18:07:57 -0700192 }
193 };
Jim Millera75961472014-06-06 15:00:49 -0700194
Jim Millercb2ce6f2016-04-13 20:28:18 -0700195 private final Runnable mResetClientState = new Runnable() {
196 @Override
197 public void run() {
198 // Warning: if we get here, the driver never confirmed our call to cancel the current
199 // operation (authenticate, enroll, remove, enumerate, etc), which is
200 // really bad. The result will be a 3-second delay in starting each new client.
201 // If you see this on a device, make certain the driver notifies with
202 // {@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} in response to cancel()
203 // once it has successfully switched to the IDLE state in the fingerprint HAL.
204 // Additionally,{@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} should only be sent
205 // in response to an actual cancel() call.
206 Slog.w(TAG, "Client "
207 + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
208 + " failed to respond to cancel, starting client "
209 + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700210
Jim Millercb2ce6f2016-04-13 20:28:18 -0700211 mCurrentClient = null;
212 startClient(mPendingClient, false);
213 }
214 };
215
Jim Millera75961472014-06-06 15:00:49 -0700216 public FingerprintService(Context context) {
217 super(context);
218 mContext = context;
Jim Miller975f1452015-08-31 18:18:22 -0700219 mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
220 com.android.internal.R.string.config_keyguardComponent)).getPackageName();
Svetoslav4af76a52015-04-29 15:29:46 -0700221 mAppOps = context.getSystemService(AppOpsManager.class);
Jorim Jaggi5e354222015-09-04 14:17:58 -0700222 mPowerManager = mContext.getSystemService(PowerManager.class);
223 mAlarmManager = mContext.getSystemService(AlarmManager.class);
224 mContext.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
225 RESET_FINGERPRINT_LOCKOUT, null /* handler */);
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000226 mUserManager = UserManager.get(mContext);
Kevin Chyn5457cba2017-08-30 15:28:28 -0700227 mTimedLockoutCleared = new SparseBooleanArray();
228 mFailedAttempts = new SparseIntArray();
Kevin Chynaae4a152018-01-18 11:48:09 -0800229 mStatusBarService = IStatusBarService.Stub.asInterface(
230 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
Jim Millera75961472014-06-06 15:00:49 -0700231 }
232
Jim Millerbe675422015-05-11 20:45:25 -0700233 @Override
Jim Miller40e46452016-12-16 18:38:53 -0800234 public void serviceDied(long cookie) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700235 Slog.v(TAG, "fingerprint HAL died");
Jim Millerc57c8d92016-09-30 17:17:59 -0700236 MetricsLogger.count(mContext, "fingerprintd_died", 1);
Jim Miller40e46452016-12-16 18:38:53 -0800237 handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
238 0 /*vendorCode */);
Jim Millera75961472014-06-06 15:00:49 -0700239 }
240
Jim Miller40e46452016-12-16 18:38:53 -0800241 public synchronized IBiometricsFingerprint getFingerprintDaemon() {
242 if (mDaemon == null) {
Kevin Chynedd71f92017-09-01 16:09:57 -0700243 Slog.v(TAG, "mDaemon was null, reconnect to fingerprint");
Jim Miller40e46452016-12-16 18:38:53 -0800244 try {
Yifan Hong25d5eaa2017-03-16 15:25:43 -0700245 mDaemon = IBiometricsFingerprint.getService();
Jim Miller40e46452016-12-16 18:38:53 -0800246 } catch (java.util.NoSuchElementException e) {
247 // Service doesn't exist or cannot be opened. Logged below.
248 } catch (RemoteException e) {
249 Slog.e(TAG, "Failed to get biometric interface", e);
Jim Millera75961472014-06-06 15:00:49 -0700250 }
Jim Miller40e46452016-12-16 18:38:53 -0800251 if (mDaemon == null) {
252 Slog.w(TAG, "fingerprint HIDL not available");
253 return null;
254 }
255
256 mDaemon.asBinder().linkToDeath(this, 0);
257
258 try {
259 mHalDeviceId = mDaemon.setNotify(mDaemonCallback);
260 } catch (RemoteException e) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700261 Slog.e(TAG, "Failed to open fingerprint HAL", e);
Jim Miller40e46452016-12-16 18:38:53 -0800262 mDaemon = null; // try again later!
263 }
264
265 if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
266 if (mHalDeviceId != 0) {
Charles Heda88f0e2017-02-02 18:29:13 +0000267 loadAuthenticatorIds();
Jim Miller40e46452016-12-16 18:38:53 -0800268 updateActiveGroup(ActivityManager.getCurrentUser(), null);
Kevin Chynedd71f92017-09-01 16:09:57 -0700269 doFingerprintCleanupForUser(ActivityManager.getCurrentUser());
Jim Miller40e46452016-12-16 18:38:53 -0800270 } else {
271 Slog.w(TAG, "Failed to open Fingerprint HAL!");
272 MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);
273 mDaemon = null;
274 }
Jim Millerce7eb6d2015-04-03 19:29:13 -0700275 }
Jim Miller40e46452016-12-16 18:38:53 -0800276 return mDaemon;
Jim Millerbe675422015-05-11 20:45:25 -0700277 }
278
Charles Heda88f0e2017-02-02 18:29:13 +0000279 /** Populates existing authenticator ids. To be used only during the start of the service. */
280 private void loadAuthenticatorIds() {
281 // This operation can be expensive, so keep track of the elapsed time. Might need to move to
282 // background if it takes too long.
283 long t = System.currentTimeMillis();
Charles Heda88f0e2017-02-02 18:29:13 +0000284 mAuthenticatorIds.clear();
285 for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) {
286 int userId = getUserOrWorkProfileId(null, user.id);
287 if (!mAuthenticatorIds.containsKey(userId)) {
288 updateActiveGroup(userId, null);
289 }
290 }
291
292 t = System.currentTimeMillis() - t;
293 if (t > 1000) {
294 Slog.w(TAG, "loadAuthenticatorIds() taking too long: " + t + "ms");
295 }
296 }
297
Kevin Chynedd71f92017-09-01 16:09:57 -0700298 /**
299 * This method should be called upon connection to the daemon, and when user switches.
300 * @param userId
301 */
302 private void doFingerprintCleanupForUser(int userId) {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700303 if (CLEANUP_UNUSED_FP) {
Kevin Chynedd71f92017-09-01 16:09:57 -0700304 enumerateUser(userId);
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700305 }
306 }
307
Kevin Chynedd71f92017-09-01 16:09:57 -0700308 private void clearEnumerateState() {
309 if (DEBUG) Slog.v(TAG, "clearEnumerateState()");
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700310 mUnknownFingerprints.clear();
311 }
312
Kevin Chynedd71f92017-09-01 16:09:57 -0700313 private void enumerateUser(int userId) {
314 if (DEBUG) Slog.v(TAG, "Enumerating user(" + userId + ")");
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700315 boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
Kevin Chynedd71f92017-09-01 16:09:57 -0700316 startEnumerate(mToken, userId, null, restricted, true /* internal */);
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700317 }
318
319 // Remove unknown fingerprints from hardware
320 private void cleanupUnknownFingerprints() {
321 if (!mUnknownFingerprints.isEmpty()) {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700322 UserFingerprint uf = mUnknownFingerprints.get(0);
323 mUnknownFingerprints.remove(uf);
324 boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700325 startRemove(mToken, uf.f.getFingerId(), uf.f.getGroupId(), uf.userId, null,
326 restricted, true /* internal */);
327 } else {
Kevin Chynedd71f92017-09-01 16:09:57 -0700328 clearEnumerateState();
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700329 }
330 }
331
Jim Miller40e46452016-12-16 18:38:53 -0800332 protected void handleEnumerate(long deviceId, int fingerId, int groupId, int remaining) {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700333 ClientMonitor client = mCurrentClient;
334
335 if ( !(client instanceof InternalRemovalClient) && !(client instanceof EnumerateClient) ) {
336 return;
337 }
338 client.onEnumerationResult(fingerId, groupId, remaining);
339
340 // All fingerprints in hardware for this user were enumerated
341 if (remaining == 0) {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700342 if (client instanceof InternalEnumerateClient) {
Kevin Chynedd71f92017-09-01 16:09:57 -0700343 List<Fingerprint> unknownFingerprints =
344 ((InternalEnumerateClient) client).getUnknownFingerprints();
345
346 if (!unknownFingerprints.isEmpty()) {
347 Slog.w(TAG, "Adding " + unknownFingerprints.size() +
348 " fingerprints for deletion");
349 }
350 for (Fingerprint f : unknownFingerprints) {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700351 mUnknownFingerprints.add(new UserFingerprint(f, client.getTargetUserId()));
352 }
Kevin Chynedd71f92017-09-01 16:09:57 -0700353 removeClient(client);
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700354 cleanupUnknownFingerprints();
Kevin Chynedd71f92017-09-01 16:09:57 -0700355 } else {
356 removeClient(client);
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700357 }
358 }
Jim Millerbe675422015-05-11 20:45:25 -0700359 }
360
Jim Miller40e46452016-12-16 18:38:53 -0800361 protected void handleError(long deviceId, int error, int vendorCode) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700362 ClientMonitor client = mCurrentClient;
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700363 if (client instanceof InternalRemovalClient || client instanceof InternalEnumerateClient) {
Kevin Chynedd71f92017-09-01 16:09:57 -0700364 clearEnumerateState();
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700365 }
Jim Miller40e46452016-12-16 18:38:53 -0800366 if (client != null && client.onError(error, vendorCode)) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700367 removeClient(client);
Jim Millerbe675422015-05-11 20:45:25 -0700368 }
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700369
Jim Millercb2ce6f2016-04-13 20:28:18 -0700370 if (DEBUG) Slog.v(TAG, "handleError(client="
Jim Millerc1e61b82016-04-18 13:00:40 -0700371 + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
Jim Millercb2ce6f2016-04-13 20:28:18 -0700372 // This is the magic code that starts the next client when the old client finishes.
373 if (error == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
374 mHandler.removeCallbacks(mResetClientState);
375 if (mPendingClient != null) {
376 if (DEBUG) Slog.v(TAG, "start pending client " + mPendingClient.getOwnerString());
377 startClient(mPendingClient, false);
378 mPendingClient = null;
379 }
Jim Miller8eddd332017-03-22 16:40:10 -0700380 } else if (error == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) {
381 // If we get HW_UNAVAILABLE, try to connect again later...
382 Slog.w(TAG, "Got ERROR_HW_UNAVAILABLE; try reconnecting next client.");
383 synchronized (this) {
384 mDaemon = null;
385 mHalDeviceId = 0;
Charles He959ac8e2017-03-27 21:16:20 +0100386 mCurrentUserId = UserHandle.USER_NULL;
Jim Miller8eddd332017-03-22 16:40:10 -0700387 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700388 }
389 }
390
Jim Miller40e46452016-12-16 18:38:53 -0800391 protected void handleRemoved(long deviceId, int fingerId, int groupId, int remaining) {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700392 if (DEBUG) Slog.w(TAG, "Removed: fid=" + fingerId
393 + ", gid=" + groupId
394 + ", dev=" + deviceId
395 + ", rem=" + remaining);
396
Jim Millercb2ce6f2016-04-13 20:28:18 -0700397 ClientMonitor client = mCurrentClient;
Jim Miller40e46452016-12-16 18:38:53 -0800398 if (client != null && client.onRemoved(fingerId, groupId, remaining)) {
Jim Miller07dbd632016-04-05 18:22:30 -0700399 removeClient(client);
Charles He29b3a8a2017-05-04 16:02:38 +0100400 // When the last fingerprint of a group is removed, update the authenticator id
401 if (!hasEnrolledFingerprints(groupId)) {
402 updateActiveGroup(groupId, null);
403 }
Jim Millerbe675422015-05-11 20:45:25 -0700404 }
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700405 if (client instanceof InternalRemovalClient && !mUnknownFingerprints.isEmpty()) {
406 cleanupUnknownFingerprints();
407 } else if (client instanceof InternalRemovalClient){
Kevin Chynedd71f92017-09-01 16:09:57 -0700408 clearEnumerateState();
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700409 }
Jim Millerbe675422015-05-11 20:45:25 -0700410 }
411
Jim Millera8eaeeb2017-01-24 14:47:04 -0800412 protected void handleAuthenticated(long deviceId, int fingerId, int groupId,
413 ArrayList<Byte> token) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700414 ClientMonitor client = mCurrentClient;
Jim Millera8eaeeb2017-01-24 14:47:04 -0800415 if (fingerId != 0) {
416 // Ugh...
417 final byte[] byteToken = new byte[token.size()];
418 for (int i = 0; i < token.size(); i++) {
419 byteToken[i] = token.get(i);
420 }
421 // Send to Keystore
422 KeyStore.getInstance().addAuthToken(byteToken);
423 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700424 if (client != null && client.onAuthenticated(fingerId, groupId)) {
425 removeClient(client);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700426 }
Jim Millerbcc100a2016-07-06 14:16:49 -0700427 if (fingerId != 0) {
428 mPerformanceStats.accept++;
429 } else {
430 mPerformanceStats.reject++;
431 }
Jim Millerbe675422015-05-11 20:45:25 -0700432 }
433
Jim Miller40e46452016-12-16 18:38:53 -0800434 protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700435 ClientMonitor client = mCurrentClient;
Jim Miller40e46452016-12-16 18:38:53 -0800436 if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700437 removeClient(client);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700438 }
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700439 if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
Jim Millerbcc100a2016-07-06 14:16:49 -0700440 && client instanceof AuthenticationClient) {
441 // ignore enrollment acquisitions or acquisitions when we're locked out
442 mPerformanceStats.acquire++;
443 }
Jim Millerdca15d22015-06-16 20:55:13 -0700444 }
Jim Millerbe675422015-05-11 20:45:25 -0700445
Jim Miller8b3c25a2015-08-28 17:29:49 -0700446 protected void handleEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700447 ClientMonitor client = mCurrentClient;
448 if (client != null && client.onEnrollResult(fingerId, groupId, remaining)) {
449 removeClient(client);
Charles He29b3a8a2017-05-04 16:02:38 +0100450 // When enrollment finishes, update this group's authenticator id, as the HAL has
451 // already generated a new authenticator id when the new fingerprint is enrolled.
452 updateActiveGroup(groupId, null);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700453 }
Jim Millerce7eb6d2015-04-03 19:29:13 -0700454 }
455
Jim Miller8b3c25a2015-08-28 17:29:49 -0700456 private void userActivity() {
457 long now = SystemClock.uptimeMillis();
458 mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
459 }
460
461 void handleUserSwitching(int userId) {
Kevin Chynedd71f92017-09-01 16:09:57 -0700462 if (mCurrentClient instanceof InternalRemovalClient
463 || mCurrentClient instanceof InternalEnumerateClient) {
464 Slog.w(TAG, "User switched while performing cleanup");
465 removeClient(mCurrentClient);
466 clearEnumerateState();
467 }
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000468 updateActiveGroup(userId, null);
Kevin Chynedd71f92017-09-01 16:09:57 -0700469 doFingerprintCleanupForUser(userId);
Jim Miller8b3c25a2015-08-28 17:29:49 -0700470 }
471
Jim Millerbe675422015-05-11 20:45:25 -0700472 private void removeClient(ClientMonitor client) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700473 if (client != null) {
474 client.destroy();
475 if (client != mCurrentClient && mCurrentClient != null) {
476 Slog.w(TAG, "Unexpected client: " + client.getOwnerString() + "expected: "
477 + mCurrentClient != null ? mCurrentClient.getOwnerString() : "null");
478 }
479 }
480 if (mCurrentClient != null) {
481 if (DEBUG) Slog.v(TAG, "Done with client: " + client.getOwnerString());
482 mCurrentClient = null;
Jim Millerfe6439f2015-04-11 18:07:57 -0700483 }
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800484 if (mPendingClient == null) {
485 notifyClientActiveCallbacks(false);
486 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700487 }
488
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700489 private int getLockoutMode() {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700490 final int currentUser = ActivityManager.getCurrentUser();
491 final int failedAttempts = mFailedAttempts.get(currentUser, 0);
492 if (failedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) {
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700493 return AuthenticationClient.LOCKOUT_PERMANENT;
Kevin Chyn5457cba2017-08-30 15:28:28 -0700494 } else if (failedAttempts > 0 &&
495 mTimedLockoutCleared.get(currentUser, false) == false
496 && (failedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) {
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700497 return AuthenticationClient.LOCKOUT_TIMED;
498 }
499 return AuthenticationClient.LOCKOUT_NONE;
Jim Millerfe6439f2015-04-11 18:07:57 -0700500 }
501
Kevin Chyn5457cba2017-08-30 15:28:28 -0700502 private void scheduleLockoutResetForUser(int userId) {
503 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
504 SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
505 getLockoutResetIntentForUser(userId));
Jorim Jaggi5e354222015-09-04 14:17:58 -0700506 }
507
Kevin Chyn5457cba2017-08-30 15:28:28 -0700508 private void cancelLockoutResetForUser(int userId) {
509 mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
Jorim Jaggi5e354222015-09-04 14:17:58 -0700510 }
511
Kevin Chyn5457cba2017-08-30 15:28:28 -0700512 private PendingIntent getLockoutResetIntentForUser(int userId) {
513 return PendingIntent.getBroadcast(mContext, userId,
514 new Intent(ACTION_LOCKOUT_RESET).putExtra(KEY_LOCKOUT_RESET_USER, userId),
515 PendingIntent.FLAG_UPDATE_CURRENT);
Jorim Jaggi5e354222015-09-04 14:17:58 -0700516 }
517
Jim Millerce7eb6d2015-04-03 19:29:13 -0700518 public long startPreEnroll(IBinder token) {
Jim Miller40e46452016-12-16 18:38:53 -0800519 IBiometricsFingerprint daemon = getFingerprintDaemon();
Jim Millerbe675422015-05-11 20:45:25 -0700520 if (daemon == null) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700521 Slog.w(TAG, "startPreEnroll: no fingerprint HAL!");
Jim Millerbe675422015-05-11 20:45:25 -0700522 return 0;
523 }
524 try {
525 return daemon.preEnroll();
526 } catch (RemoteException e) {
527 Slog.e(TAG, "startPreEnroll failed", e);
528 }
529 return 0;
Jim Millerce7eb6d2015-04-03 19:29:13 -0700530 }
531
Sasha Levitskiye0943cf2015-07-08 13:22:20 -0700532 public int startPostEnroll(IBinder token) {
Jim Miller40e46452016-12-16 18:38:53 -0800533 IBiometricsFingerprint daemon = getFingerprintDaemon();
Sasha Levitskiye0943cf2015-07-08 13:22:20 -0700534 if (daemon == null) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700535 Slog.w(TAG, "startPostEnroll: no fingerprint HAL!");
Sasha Levitskiye0943cf2015-07-08 13:22:20 -0700536 return 0;
537 }
538 try {
539 return daemon.postEnroll();
540 } catch (RemoteException e) {
541 Slog.e(TAG, "startPostEnroll failed", e);
542 }
543 return 0;
544 }
545
Jim Miller80a776e2015-07-15 18:57:14 -0700546 /**
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700547 * Calls fingerprint HAL to switch states to the new task. If there's already a current task,
Jim Millercb2ce6f2016-04-13 20:28:18 -0700548 * it calls cancel() and sets mPendingClient to begin when the current task finishes
549 * ({@link FingerprintManager#FINGERPRINT_ERROR_CANCELED}).
550 * @param newClient the new client that wants to connect
551 * @param initiatedByClient true for authenticate, remove and enroll
Jim Miller80a776e2015-07-15 18:57:14 -0700552 */
Jim Millercb2ce6f2016-04-13 20:28:18 -0700553 private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
554 ClientMonitor currentClient = mCurrentClient;
555 if (currentClient != null) {
556 if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString());
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700557 if (currentClient instanceof InternalEnumerateClient ||
558 currentClient instanceof InternalRemovalClient) {
559 // This condition means we're currently running internal diagnostics to
560 // remove extra fingerprints in the hardware and/or the software
561 // TODO: design an escape hatch in case client never finishes
Kevin Chynedd71f92017-09-01 16:09:57 -0700562 if (newClient != null) {
563 Slog.w(TAG, "Internal cleanup in progress but trying to start client "
564 + newClient.getClass().getSuperclass().getSimpleName()
565 + "(" + newClient.getOwnerString() + ")"
566 + ", initiatedByClient = " + initiatedByClient);
567 }
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700568 }
569 else {
570 currentClient.stop(initiatedByClient);
571 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700572 mPendingClient = newClient;
573 mHandler.removeCallbacks(mResetClientState);
574 mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
575 } else if (newClient != null) {
576 mCurrentClient = newClient;
577 if (DEBUG) Slog.v(TAG, "starting client "
578 + newClient.getClass().getSuperclass().getSimpleName()
579 + "(" + newClient.getOwnerString() + ")"
Kevin Chynedd71f92017-09-01 16:09:57 -0700580 + ", initiatedByClient = " + initiatedByClient);
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800581 notifyClientActiveCallbacks(true);
582
Jim Millercb2ce6f2016-04-13 20:28:18 -0700583 newClient.start();
Jim Millera75961472014-06-06 15:00:49 -0700584 }
585 }
586
Jim Miller8f2aca02016-04-20 13:34:11 -0700587 void startRemove(IBinder token, int fingerId, int groupId, int userId,
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700588 IFingerprintServiceReceiver receiver, boolean restricted, boolean internal) {
Jim Miller40e46452016-12-16 18:38:53 -0800589 IBiometricsFingerprint daemon = getFingerprintDaemon();
Jim Millerbe675422015-05-11 20:45:25 -0700590 if (daemon == null) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700591 Slog.w(TAG, "startRemove: no fingerprint HAL!");
Jim Millerbe675422015-05-11 20:45:25 -0700592 return;
593 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700594
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700595 if (internal) {
596 Context context = getContext();
597 InternalRemovalClient client = new InternalRemovalClient(context, mHalDeviceId,
598 token, receiver, fingerId, groupId, userId, restricted,
599 context.getOpPackageName()) {
600 @Override
601 public void notifyUserActivity() {
602
603 }
604 @Override
605 public IBiometricsFingerprint getFingerprintDaemon() {
606 return FingerprintService.this.getFingerprintDaemon();
607 }
608 };
609 startClient(client, true);
610 }
611 else {
612 RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token,
613 receiver, fingerId, groupId, userId, restricted, token.toString()) {
614 @Override
615 public void notifyUserActivity() {
616 FingerprintService.this.userActivity();
617 }
618
619 @Override
620 public IBiometricsFingerprint getFingerprintDaemon() {
621 return FingerprintService.this.getFingerprintDaemon();
622 }
623 };
624 startClient(client, true);
625 }
Jim Miller40e46452016-12-16 18:38:53 -0800626 }
627
628 void startEnumerate(IBinder token, int userId,
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700629 IFingerprintServiceReceiver receiver, boolean restricted, boolean internal) {
Jim Miller40e46452016-12-16 18:38:53 -0800630 IBiometricsFingerprint daemon = getFingerprintDaemon();
631 if (daemon == null) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700632 Slog.w(TAG, "startEnumerate: no fingerprint HAL!");
Jim Miller40e46452016-12-16 18:38:53 -0800633 return;
634 }
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700635 if (internal) {
636 List<Fingerprint> enrolledList = getEnrolledFingerprints(userId);
637 Context context = getContext();
638 InternalEnumerateClient client = new InternalEnumerateClient(context, mHalDeviceId,
639 token, receiver, userId, userId, restricted, context.getOpPackageName(),
640 enrolledList) {
641 @Override
642 public void notifyUserActivity() {
Jim Miller40e46452016-12-16 18:38:53 -0800643
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700644 }
645
646 @Override
647 public IBiometricsFingerprint getFingerprintDaemon() {
648 return FingerprintService.this.getFingerprintDaemon();
649 }
650 };
651 startClient(client, true);
652 }
653 else {
654 EnumerateClient client = new EnumerateClient(getContext(), mHalDeviceId, token,
655 receiver, userId, userId, restricted, token.toString()) {
656 @Override
657 public void notifyUserActivity() {
658 FingerprintService.this.userActivity();
659 }
660
661 @Override
662 public IBiometricsFingerprint getFingerprintDaemon() {
663 return FingerprintService.this.getFingerprintDaemon();
664 }
665 };
666 startClient(client, true);
667 }
Jim Millera75961472014-06-06 15:00:49 -0700668 }
669
Jim Miller599ef0e2015-06-15 20:39:44 -0700670 public List<Fingerprint> getEnrolledFingerprints(int userId) {
671 return mFingerprintUtils.getFingerprintsForUser(mContext, userId);
Jim Miller9f0753f2015-03-23 23:59:22 -0700672 }
673
Jim Miller599ef0e2015-06-15 20:39:44 -0700674 public boolean hasEnrolledFingerprints(int userId) {
Jim Miller1fd298b2016-02-25 16:42:28 -0800675 if (userId != UserHandle.getCallingUserId()) {
Clara Bayarri33fd3cf2016-02-19 16:54:49 +0000676 checkPermission(INTERACT_ACROSS_USERS);
677 }
Jim Miller599ef0e2015-06-15 20:39:44 -0700678 return mFingerprintUtils.getFingerprintsForUser(mContext, userId).size() > 0;
Jorim Jaggi2aad7ee2015-04-14 15:25:06 -0700679 }
680
Jim Millerf501b582015-06-03 16:36:31 -0700681 boolean hasPermission(String permission) {
682 return getContext().checkCallingOrSelfPermission(permission)
683 == PackageManager.PERMISSION_GRANTED;
684 }
685
Jim Millerba67aee2015-02-20 16:21:26 -0800686 void checkPermission(String permission) {
Jim Miller9f0753f2015-03-23 23:59:22 -0700687 getContext().enforceCallingOrSelfPermission(permission,
688 "Must have " + permission + " permission.");
Jim Millera75961472014-06-06 15:00:49 -0700689 }
690
Andres Morales494d6e92015-08-06 15:01:41 -0700691 int getEffectiveUserId(int userId) {
692 UserManager um = UserManager.get(mContext);
693 if (um != null) {
694 final long callingIdentity = Binder.clearCallingIdentity();
695 userId = um.getCredentialOwnerProfile(userId);
696 Binder.restoreCallingIdentity(callingIdentity);
697 } else {
698 Slog.e(TAG, "Unable to acquire UserManager");
699 }
700 return userId;
701 }
702
Jim Millercb7d9e92015-06-16 15:05:48 -0700703 boolean isCurrentUserOrProfile(int userId) {
704 UserManager um = UserManager.get(mContext);
Charles Heda88f0e2017-02-02 18:29:13 +0000705 if (um == null) {
706 Slog.e(TAG, "Unable to acquire UserManager");
707 return false;
Jim Millercb7d9e92015-06-16 15:05:48 -0700708 }
Charles Heda88f0e2017-02-02 18:29:13 +0000709
710 final long token = Binder.clearCallingIdentity();
711 try {
712 // Allow current user or profiles of the current user...
Charles He959ac8e2017-03-27 21:16:20 +0100713 for (int profileId : um.getEnabledProfileIds(ActivityManager.getCurrentUser())) {
Charles Heda88f0e2017-02-02 18:29:13 +0000714 if (profileId == userId) {
715 return true;
716 }
717 }
Charles Heda88f0e2017-02-02 18:29:13 +0000718 } finally {
719 Binder.restoreCallingIdentity(token);
720 }
Charles He959ac8e2017-03-27 21:16:20 +0100721
722 return false;
Jim Millercb7d9e92015-06-16 15:05:48 -0700723 }
724
Jim Miller975f1452015-08-31 18:18:22 -0700725 private boolean isForegroundActivity(int uid, int pid) {
726 try {
727 List<RunningAppProcessInfo> procs =
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800728 ActivityManager.getService().getRunningAppProcesses();
Jim Miller975f1452015-08-31 18:18:22 -0700729 int N = procs.size();
730 for (int i = 0; i < N; i++) {
731 RunningAppProcessInfo proc = procs.get(i);
732 if (proc.pid == pid && proc.uid == uid
733 && proc.importance == IMPORTANCE_FOREGROUND) {
734 return true;
735 }
736 }
737 } catch (RemoteException e) {
738 Slog.w(TAG, "am.getRunningAppProcesses() failed");
739 }
740 return false;
741 }
742
743 /**
744 * @param opPackageName name of package for caller
Jim Miller37979c92016-08-05 18:54:58 -0700745 * @param requireForeground only allow this call while app is in the foreground
Jim Miller975f1452015-08-31 18:18:22 -0700746 * @return true if caller can use fingerprint API
747 */
Jim Miller37979c92016-08-05 18:54:58 -0700748 private boolean canUseFingerprint(String opPackageName, boolean requireForeground, int uid,
Kevin Chynf4023b52017-04-07 16:29:19 -0700749 int pid, int userId) {
Svetoslav4af76a52015-04-29 15:29:46 -0700750 checkPermission(USE_FINGERPRINT);
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000751 if (isKeyguard(opPackageName)) {
Jim Miller975f1452015-08-31 18:18:22 -0700752 return true; // Keyguard is always allowed
753 }
Kevin Chynf4023b52017-04-07 16:29:19 -0700754 if (!isCurrentUserOrProfile(userId)) {
Jim Miller975f1452015-08-31 18:18:22 -0700755 Slog.w(TAG,"Rejecting " + opPackageName + " ; not a current user or profile");
756 return false;
757 }
758 if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
759 != AppOpsManager.MODE_ALLOWED) {
Jim Miller1adb4a72015-09-14 18:58:08 -0700760 Slog.w(TAG, "Rejecting " + opPackageName + " ; permission denied");
Jim Miller975f1452015-08-31 18:18:22 -0700761 return false;
762 }
Jim Miller37979c92016-08-05 18:54:58 -0700763 if (requireForeground && !(isForegroundActivity(uid, pid) || currentClient(opPackageName))){
Jim Miller1adb4a72015-09-14 18:58:08 -0700764 Slog.w(TAG, "Rejecting " + opPackageName + " ; not in foreground");
Jim Miller975f1452015-08-31 18:18:22 -0700765 return false;
766 }
767 return true;
Svetoslav4af76a52015-04-29 15:29:46 -0700768 }
769
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000770 /**
Jim Miller37979c92016-08-05 18:54:58 -0700771 * @param opPackageName package of the caller
772 * @return true if this is the same client currently using fingerprint
773 */
774 private boolean currentClient(String opPackageName) {
775 return mCurrentClient != null && mCurrentClient.getOwnerString().equals(opPackageName);
776 }
777
778 /**
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000779 * @param clientPackage
780 * @return true if this is keyguard package
781 */
782 private boolean isKeyguard(String clientPackage) {
783 return mKeyguardPackage.equals(clientPackage);
784 }
785
Jorim Jaggi3a464782015-08-28 16:59:13 -0700786 private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
787 if (!mLockoutMonitors.contains(monitor)) {
788 mLockoutMonitors.add(monitor);
789 }
790 }
791
792 private void removeLockoutResetCallback(
793 FingerprintServiceLockoutResetMonitor monitor) {
794 mLockoutMonitors.remove(monitor);
795 }
796
797 private void notifyLockoutResetMonitors() {
798 for (int i = 0; i < mLockoutMonitors.size(); i++) {
799 mLockoutMonitors.get(i).sendLockoutReset();
800 }
801 }
802
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800803 private void notifyClientActiveCallbacks(boolean isActive) {
804 List<IFingerprintClientActiveCallback> callbacks = mClientActiveCallbacks;
805 for (int i = 0; i < callbacks.size(); i++) {
806 try {
807 callbacks.get(i).onClientActiveChanged(isActive);
808 } catch (RemoteException re) {
809 // If the remote is dead, stop notifying it
810 mClientActiveCallbacks.remove(callbacks.get(i));
Charles He959ac8e2017-03-27 21:16:20 +0100811 }
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800812 }
813 }
814
Tony Makff715ac2016-04-19 20:44:12 +0100815 private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId,
Jim Millercb2ce6f2016-04-13 20:28:18 -0700816 IFingerprintServiceReceiver receiver, int flags, boolean restricted,
Kevin Chynaae4a152018-01-18 11:48:09 -0800817 String opPackageName, Bundle bundle, IFingerprintDialogReceiver dialogReceiver) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700818 updateActiveGroup(groupId, opPackageName);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700819
Jim Millercb2ce6f2016-04-13 20:28:18 -0700820 if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")");
Jim Millerfe6439f2015-04-11 18:07:57 -0700821
Jim Millercb2ce6f2016-04-13 20:28:18 -0700822 AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token,
Kevin Chynaae4a152018-01-18 11:48:09 -0800823 receiver, mCurrentUserId, groupId, opId, restricted, opPackageName, bundle,
824 dialogReceiver, mStatusBarService) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700825 @Override
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700826 public int handleFailedAttempt() {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700827 final int currentUser = ActivityManager.getCurrentUser();
828 mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
829 mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700830 final int lockoutMode = getLockoutMode();
831 if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
832 mPerformanceStats.permanentLockout++;
833 } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
Jim Millerbcc100a2016-07-06 14:16:49 -0700834 mPerformanceStats.lockout++;
835 }
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700836
837 // Failing multiple times will continue to push out the lockout time
838 if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700839 scheduleLockoutResetForUser(currentUser);
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700840 return lockoutMode;
Jim Miller16ef71f2015-05-21 17:02:21 -0700841 }
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700842 return AuthenticationClient.LOCKOUT_NONE;
Jim Millerfe6439f2015-04-11 18:07:57 -0700843 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700844
Jim Millercb2ce6f2016-04-13 20:28:18 -0700845 @Override
846 public void resetFailedAttempts() {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700847 FingerprintService.this.resetFailedAttemptsForUser(true /* clearAttemptCounter */,
848 ActivityManager.getCurrentUser());
Jim Millercb2ce6f2016-04-13 20:28:18 -0700849 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700850
Jim Millercb2ce6f2016-04-13 20:28:18 -0700851 @Override
852 public void notifyUserActivity() {
853 FingerprintService.this.userActivity();
Jim Millerfe6439f2015-04-11 18:07:57 -0700854 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700855
Jim Millercb2ce6f2016-04-13 20:28:18 -0700856 @Override
Jim Miller40e46452016-12-16 18:38:53 -0800857 public IBiometricsFingerprint getFingerprintDaemon() {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700858 return FingerprintService.this.getFingerprintDaemon();
Jim Millerfe6439f2015-04-11 18:07:57 -0700859 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700860 };
Jim Millerfe6439f2015-04-11 18:07:57 -0700861
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700862 int lockoutMode = getLockoutMode();
863 if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
864 Slog.v(TAG, "In lockout mode(" + lockoutMode +
865 ") ; disallowing authentication");
866 int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
867 FingerprintManager.FINGERPRINT_ERROR_LOCKOUT :
868 FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
869 if (!client.onError(errorCode, 0 /* vendorCode */)) {
870 Slog.w(TAG, "Cannot send permanent lockout message to client");
Jim Millerfe6439f2015-04-11 18:07:57 -0700871 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700872 return;
Jim Millerfe6439f2015-04-11 18:07:57 -0700873 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700874 startClient(client, true /* initiatedByClient */);
875 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700876
Jim Millerc12eca82016-04-28 15:12:53 -0700877 private void startEnrollment(IBinder token, byte [] cryptoToken, int userId,
Jim Millercb2ce6f2016-04-13 20:28:18 -0700878 IFingerprintServiceReceiver receiver, int flags, boolean restricted,
879 String opPackageName) {
Jim Millerc12eca82016-04-28 15:12:53 -0700880 updateActiveGroup(userId, opPackageName);
881
882 final int groupId = userId; // default group for fingerprint enrollment
Jim Millerfe6439f2015-04-11 18:07:57 -0700883
Jim Millercb2ce6f2016-04-13 20:28:18 -0700884 EnrollClient client = new EnrollClient(getContext(), mHalDeviceId, token, receiver,
Jim Millerc12eca82016-04-28 15:12:53 -0700885 userId, groupId, cryptoToken, restricted, opPackageName) {
Jim Millerfe6439f2015-04-11 18:07:57 -0700886
Jim Millercb2ce6f2016-04-13 20:28:18 -0700887 @Override
Jim Miller40e46452016-12-16 18:38:53 -0800888 public IBiometricsFingerprint getFingerprintDaemon() {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700889 return FingerprintService.this.getFingerprintDaemon();
Jim Millerfe6439f2015-04-11 18:07:57 -0700890 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700891
892 @Override
893 public void notifyUserActivity() {
894 FingerprintService.this.userActivity();
895 }
896 };
897 startClient(client, true /* initiatedByClient */);
898 }
899
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700900 // attempt counter should only be cleared when Keyguard goes away or when
901 // a fingerprint is successfully authenticated
Kevin Chyn5457cba2017-08-30 15:28:28 -0700902 protected void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700903 if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
904 Slog.v(TAG, "Reset fingerprint lockout, clearAttemptCounter=" + clearAttemptCounter);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700905 }
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700906 if (clearAttemptCounter) {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700907 mFailedAttempts.put(userId, 0);
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700908 }
Kevin Chyn5457cba2017-08-30 15:28:28 -0700909 mTimedLockoutCleared.put(userId, true);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700910 // If we're asked to reset failed attempts externally (i.e. from Keyguard),
911 // the alarm might still be pending; remove it.
Kevin Chyn5457cba2017-08-30 15:28:28 -0700912 cancelLockoutResetForUser(userId);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700913 notifyLockoutResetMonitors();
Jim Millerce7eb6d2015-04-03 19:29:13 -0700914 }
915
Jorim Jaggi3a464782015-08-28 16:59:13 -0700916 private class FingerprintServiceLockoutResetMonitor {
917
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +0100918 private static final long WAKELOCK_TIMEOUT_MS = 2000;
Jorim Jaggi3a464782015-08-28 16:59:13 -0700919 private final IFingerprintServiceLockoutResetCallback mCallback;
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +0100920 private final WakeLock mWakeLock;
Jorim Jaggi3a464782015-08-28 16:59:13 -0700921
922 public FingerprintServiceLockoutResetMonitor(
923 IFingerprintServiceLockoutResetCallback callback) {
924 mCallback = callback;
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +0100925 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
926 "lockout reset callback");
Jorim Jaggi3a464782015-08-28 16:59:13 -0700927 }
928
929 public void sendLockoutReset() {
930 if (mCallback != null) {
931 try {
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +0100932 mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
933 mCallback.onLockoutReset(mHalDeviceId, new IRemoteCallback.Stub() {
934
935 @Override
936 public void sendResult(Bundle data) throws RemoteException {
Kevin Chync3101182017-08-08 16:03:45 -0700937 if (mWakeLock.isHeld()) {
938 mWakeLock.release();
939 }
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +0100940 }
941 });
Jorim Jaggi3a464782015-08-28 16:59:13 -0700942 } catch (DeadObjectException e) {
943 Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
944 mHandler.post(mRemoveCallbackRunnable);
945 } catch (RemoteException e) {
946 Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
947 }
948 }
949 }
950
951 private final Runnable mRemoveCallbackRunnable = new Runnable() {
952 @Override
953 public void run() {
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +0100954 if (mWakeLock.isHeld()) {
955 mWakeLock.release();
956 }
Jorim Jaggi3a464782015-08-28 16:59:13 -0700957 removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
958 }
959 };
960 }
961
Jim Miller40e46452016-12-16 18:38:53 -0800962 private IBiometricsFingerprintClientCallback mDaemonCallback =
963 new IBiometricsFingerprintClientCallback.Stub() {
Jim Millerbe675422015-05-11 20:45:25 -0700964
Jim Miller9f0753f2015-03-23 23:59:22 -0700965 @Override
Jim Miller8b3c25a2015-08-28 17:29:49 -0700966 public void onEnrollResult(final long deviceId, final int fingerId, final int groupId,
967 final int remaining) {
968 mHandler.post(new Runnable() {
969 @Override
970 public void run() {
971 handleEnrollResult(deviceId, fingerId, groupId, remaining);
972 }
973 });
Jim Millerbe675422015-05-11 20:45:25 -0700974 }
975
976 @Override
Jim Miller40e46452016-12-16 18:38:53 -0800977 public void onAcquired(final long deviceId, final int acquiredInfo, final int vendorCode) {
Jim Miller8b3c25a2015-08-28 17:29:49 -0700978 mHandler.post(new Runnable() {
979 @Override
980 public void run() {
Jim Miller40e46452016-12-16 18:38:53 -0800981 handleAcquired(deviceId, acquiredInfo, vendorCode);
Jim Miller8b3c25a2015-08-28 17:29:49 -0700982 }
983 });
Jim Millerbe675422015-05-11 20:45:25 -0700984 }
985
986 @Override
Jim Millera8eaeeb2017-01-24 14:47:04 -0800987 public void onAuthenticated(final long deviceId, final int fingerId, final int groupId,
988 ArrayList<Byte> token) {
Jim Miller8b3c25a2015-08-28 17:29:49 -0700989 mHandler.post(new Runnable() {
990 @Override
991 public void run() {
Jim Millera8eaeeb2017-01-24 14:47:04 -0800992 handleAuthenticated(deviceId, fingerId, groupId, token);
Jim Miller8b3c25a2015-08-28 17:29:49 -0700993 }
994 });
Jim Millerbe675422015-05-11 20:45:25 -0700995 }
996
997 @Override
Jim Miller40e46452016-12-16 18:38:53 -0800998 public void onError(final long deviceId, final int error, final int vendorCode) {
Jim Miller8b3c25a2015-08-28 17:29:49 -0700999 mHandler.post(new Runnable() {
1000 @Override
1001 public void run() {
Jim Miller40e46452016-12-16 18:38:53 -08001002 handleError(deviceId, error, vendorCode);
Jim Miller8b3c25a2015-08-28 17:29:49 -07001003 }
1004 });
Jim Millerbe675422015-05-11 20:45:25 -07001005 }
1006
1007 @Override
Jim Miller40e46452016-12-16 18:38:53 -08001008 public void onRemoved(final long deviceId, final int fingerId, final int groupId, final int remaining) {
Jim Miller8b3c25a2015-08-28 17:29:49 -07001009 mHandler.post(new Runnable() {
1010 @Override
1011 public void run() {
Jim Miller40e46452016-12-16 18:38:53 -08001012 handleRemoved(deviceId, fingerId, groupId, remaining);
Jim Miller8b3c25a2015-08-28 17:29:49 -07001013 }
1014 });
Jim Millerbe675422015-05-11 20:45:25 -07001015 }
1016
1017 @Override
Jim Miller40e46452016-12-16 18:38:53 -08001018 public void onEnumerate(final long deviceId, final int fingerId, final int groupId,
1019 final int remaining) {
Jim Miller8b3c25a2015-08-28 17:29:49 -07001020 mHandler.post(new Runnable() {
1021 @Override
1022 public void run() {
Jim Miller40e46452016-12-16 18:38:53 -08001023 handleEnumerate(deviceId, fingerId, groupId, remaining);
Jim Miller8b3c25a2015-08-28 17:29:49 -07001024 }
1025 });
Jim Millerbe675422015-05-11 20:45:25 -07001026 }
Jim Millerbe675422015-05-11 20:45:25 -07001027 };
1028
1029 private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
1030 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -07001031 public long preEnroll(IBinder token) {
Jim Millerba67aee2015-02-20 16:21:26 -08001032 checkPermission(MANAGE_FINGERPRINT);
Jim Millerce7eb6d2015-04-03 19:29:13 -07001033 return startPreEnroll(token);
Jim Millera75961472014-06-06 15:00:49 -07001034 }
1035
Jim Millerbe675422015-05-11 20:45:25 -07001036 @Override // Binder call
Sasha Levitskiye0943cf2015-07-08 13:22:20 -07001037 public int postEnroll(IBinder token) {
1038 checkPermission(MANAGE_FINGERPRINT);
1039 return startPostEnroll(token);
1040 }
1041
1042 @Override // Binder call
Jim Millerc12eca82016-04-28 15:12:53 -07001043 public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
Jim Millercb2ce6f2016-04-13 20:28:18 -07001044 final IFingerprintServiceReceiver receiver, final int flags,
1045 final String opPackageName) {
Jim Millerce7eb6d2015-04-03 19:29:13 -07001046 checkPermission(MANAGE_FINGERPRINT);
Kevin Chynaae4a152018-01-18 11:48:09 -08001047 final int limit = mContext.getResources().getInteger(
Jim Miller599ef0e2015-06-15 20:39:44 -07001048 com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
Jim Millerc12eca82016-04-28 15:12:53 -07001049
1050 final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size();
Jim Miller599ef0e2015-06-15 20:39:44 -07001051 if (enrolled >= limit) {
1052 Slog.w(TAG, "Too many fingerprints registered");
1053 return;
1054 }
Jim Millerf501b582015-06-03 16:36:31 -07001055
Andres Morales494d6e92015-08-06 15:01:41 -07001056 // Group ID is arbitrarily set to parent profile user ID. It just represents
1057 // the default fingerprints for the user.
Jim Millerc12eca82016-04-28 15:12:53 -07001058 if (!isCurrentUserOrProfile(userId)) {
Clara Bayarri35fd93812016-02-29 17:49:18 -08001059 return;
1060 }
Andres Morales494d6e92015-08-06 15:01:41 -07001061
Jim Millerf501b582015-06-03 16:36:31 -07001062 final boolean restricted = isRestricted();
Jim Millerce7eb6d2015-04-03 19:29:13 -07001063 mHandler.post(new Runnable() {
1064 @Override
1065 public void run() {
Jim Millerc12eca82016-04-28 15:12:53 -07001066 startEnrollment(token, cryptoToken, userId, receiver, flags,
Jim Millercb2ce6f2016-04-13 20:28:18 -07001067 restricted, opPackageName);
Jim Millerce7eb6d2015-04-03 19:29:13 -07001068 }
1069 });
1070 }
1071
Jim Millerf501b582015-06-03 16:36:31 -07001072 private boolean isRestricted() {
1073 // Only give privileged apps (like Settings) access to fingerprint info
1074 final boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
1075 return restricted;
1076 }
1077
Jim Millerbe675422015-05-11 20:45:25 -07001078 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -07001079 public void cancelEnrollment(final IBinder token) {
1080 checkPermission(MANAGE_FINGERPRINT);
1081 mHandler.post(new Runnable() {
1082 @Override
1083 public void run() {
Jim Millercb2ce6f2016-04-13 20:28:18 -07001084 ClientMonitor client = mCurrentClient;
1085 if (client instanceof EnrollClient && client.getToken() == token) {
1086 client.stop(client.getToken() == token);
1087 }
Jim Millerce7eb6d2015-04-03 19:29:13 -07001088 }
1089 });
1090 }
1091
Jim Millerbe675422015-05-11 20:45:25 -07001092 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -07001093 public void authenticate(final IBinder token, final long opId, final int groupId,
Jim Millerdca15d22015-06-16 20:55:13 -07001094 final IFingerprintServiceReceiver receiver, final int flags,
Kevin Chynaae4a152018-01-18 11:48:09 -08001095 final String opPackageName, final Bundle bundle,
1096 final IFingerprintDialogReceiver dialogReceiver) {
Tony Makff715ac2016-04-19 20:44:12 +01001097 final int callingUid = Binder.getCallingUid();
Kevin Chyn33fdf112017-08-09 11:45:21 -07001098 final int callingPid = Binder.getCallingPid();
Tony Makff715ac2016-04-19 20:44:12 +01001099 final int callingUserId = UserHandle.getCallingUserId();
Jim Millerf501b582015-06-03 16:36:31 -07001100 final boolean restricted = isRestricted();
Kevin Chyn33fdf112017-08-09 11:45:21 -07001101
1102 if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
1103 callingUserId)) {
1104 if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
1105 return;
1106 }
1107
Jim Millerce7eb6d2015-04-03 19:29:13 -07001108 mHandler.post(new Runnable() {
1109 @Override
1110 public void run() {
Jim Millerbcc100a2016-07-06 14:16:49 -07001111 MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
1112
1113 // Get performance stats object for this user.
1114 HashMap<Integer, PerformanceStats> pmap
1115 = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
1116 PerformanceStats stats = pmap.get(mCurrentUserId);
1117 if (stats == null) {
1118 stats = new PerformanceStats();
1119 pmap.put(mCurrentUserId, stats);
1120 }
1121 mPerformanceStats = stats;
1122
Tony Makff715ac2016-04-19 20:44:12 +01001123 startAuthentication(token, opId, callingUserId, groupId, receiver,
Kevin Chynaae4a152018-01-18 11:48:09 -08001124 flags, restricted, opPackageName, bundle, dialogReceiver);
Jim Millerce7eb6d2015-04-03 19:29:13 -07001125 }
1126 });
1127 }
1128
Jim Millerbe675422015-05-11 20:45:25 -07001129 @Override // Binder call
Jim Millercb2ce6f2016-04-13 20:28:18 -07001130 public void cancelAuthentication(final IBinder token, final String opPackageName) {
Kevin Chyn33fdf112017-08-09 11:45:21 -07001131 final int callingUid = Binder.getCallingUid();
1132 final int callingPid = Binder.getCallingPid();
Kevin Chynf4023b52017-04-07 16:29:19 -07001133 final int callingUserId = UserHandle.getCallingUserId();
Kevin Chyn33fdf112017-08-09 11:45:21 -07001134
1135 if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
1136 callingUserId)) {
1137 if (DEBUG) Slog.v(TAG, "cancelAuthentication(): reject " + opPackageName);
1138 return;
1139 }
1140
Jim Millerce7eb6d2015-04-03 19:29:13 -07001141 mHandler.post(new Runnable() {
1142 @Override
1143 public void run() {
Kevin Chyn33fdf112017-08-09 11:45:21 -07001144 ClientMonitor client = mCurrentClient;
1145 if (client instanceof AuthenticationClient) {
1146 if (client.getToken() == token) {
1147 if (DEBUG) Slog.v(TAG, "stop client " + client.getOwnerString());
1148 client.stop(client.getToken() == token);
1149 } else {
1150 if (DEBUG) Slog.v(TAG, "can't stop client "
1151 + client.getOwnerString() + " since tokens don't match");
Jim Millercb2ce6f2016-04-13 20:28:18 -07001152 }
Kevin Chyn33fdf112017-08-09 11:45:21 -07001153 } else if (client != null) {
1154 if (DEBUG) Slog.v(TAG, "can't cancel non-authenticating client "
1155 + client.getOwnerString());
Jim Millercb2ce6f2016-04-13 20:28:18 -07001156 }
Jim Millerce7eb6d2015-04-03 19:29:13 -07001157 }
1158 });
Jim Millerba67aee2015-02-20 16:21:26 -08001159 }
Jim Miller99d60192015-03-11 17:41:58 -07001160
Jim Millerbe675422015-05-11 20:45:25 -07001161 @Override // Binder call
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001162 public void setActiveUser(final int userId) {
1163 checkPermission(MANAGE_FINGERPRINT);
1164 mHandler.post(new Runnable() {
1165 @Override
1166 public void run() {
1167 updateActiveGroup(userId, null);
1168 }
1169 });
1170 }
1171
1172 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -07001173 public void remove(final IBinder token, final int fingerId, final int groupId,
Jim Miller8f2aca02016-04-20 13:34:11 -07001174 final int userId, final IFingerprintServiceReceiver receiver) {
Jim Miller9f0753f2015-03-23 23:59:22 -07001175 checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
Jim Millerf501b582015-06-03 16:36:31 -07001176 final boolean restricted = isRestricted();
Jim Millerce7eb6d2015-04-03 19:29:13 -07001177 mHandler.post(new Runnable() {
1178 @Override
1179 public void run() {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -07001180 startRemove(token, fingerId, groupId, userId, receiver,
1181 restricted, false /* internal */);
Jim Millerce7eb6d2015-04-03 19:29:13 -07001182 }
1183 });
Jim Miller9f0753f2015-03-23 23:59:22 -07001184 }
1185
Kevin Chynd1f1a0b2017-04-03 13:37:48 -07001186 @Override // Binder call
Jim Miller40e46452016-12-16 18:38:53 -08001187 public void enumerate(final IBinder token, final int userId,
1188 final IFingerprintServiceReceiver receiver) {
1189 checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
1190 final boolean restricted = isRestricted();
1191 mHandler.post(new Runnable() {
1192 @Override
1193 public void run() {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -07001194 startEnumerate(token, userId, receiver, restricted, false /* internal */);
Jim Miller40e46452016-12-16 18:38:53 -08001195 }
1196 });
Jim Miller40e46452016-12-16 18:38:53 -08001197 }
1198
Jim Millerbe675422015-05-11 20:45:25 -07001199 @Override // Binder call
Svetoslav4af76a52015-04-29 15:29:46 -07001200 public boolean isHardwareDetected(long deviceId, String opPackageName) {
Jim Millercb2ce6f2016-04-13 20:28:18 -07001201 if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
Kevin Chynf4023b52017-04-07 16:29:19 -07001202 Binder.getCallingUid(), Binder.getCallingPid(),
1203 UserHandle.getCallingUserId())) {
Svetoslav4af76a52015-04-29 15:29:46 -07001204 return false;
1205 }
Charles He959ac8e2017-03-27 21:16:20 +01001206
1207 final long token = Binder.clearCallingIdentity();
1208 try {
1209 IBiometricsFingerprint daemon = getFingerprintDaemon();
1210 return daemon != null && mHalDeviceId != 0;
1211 } finally {
1212 Binder.restoreCallingIdentity(token);
1213 }
Jim Miller9f0753f2015-03-23 23:59:22 -07001214 }
1215
Jim Millerbe675422015-05-11 20:45:25 -07001216 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -07001217 public void rename(final int fingerId, final int groupId, final String name) {
Jim Miller99d60192015-03-11 17:41:58 -07001218 checkPermission(MANAGE_FINGERPRINT);
Clara Bayarri35fd93812016-02-29 17:49:18 -08001219 if (!isCurrentUserOrProfile(groupId)) {
1220 return;
1221 }
Jim Millerce7eb6d2015-04-03 19:29:13 -07001222 mHandler.post(new Runnable() {
1223 @Override
1224 public void run() {
Andres Morales494d6e92015-08-06 15:01:41 -07001225 mFingerprintUtils.renameFingerprintForUser(mContext, fingerId,
Clara Bayarri35fd93812016-02-29 17:49:18 -08001226 groupId, name);
Jim Millerce7eb6d2015-04-03 19:29:13 -07001227 }
1228 });
Jim Miller99d60192015-03-11 17:41:58 -07001229 }
Jim Miller9f0753f2015-03-23 23:59:22 -07001230
Jim Millerbe675422015-05-11 20:45:25 -07001231 @Override // Binder call
Jim Miller599ef0e2015-06-15 20:39:44 -07001232 public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
Jim Millercb2ce6f2016-04-13 20:28:18 -07001233 if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
Kevin Chynf4023b52017-04-07 16:29:19 -07001234 Binder.getCallingUid(), Binder.getCallingPid(),
1235 UserHandle.getCallingUserId())) {
Svetoslav4af76a52015-04-29 15:29:46 -07001236 return Collections.emptyList();
1237 }
Andres Morales494d6e92015-08-06 15:01:41 -07001238
Clara Bayarri35fd93812016-02-29 17:49:18 -08001239 return FingerprintService.this.getEnrolledFingerprints(userId);
Jim Miller9f0753f2015-03-23 23:59:22 -07001240 }
Jorim Jaggi2aad7ee2015-04-14 15:25:06 -07001241
Jim Millerbe675422015-05-11 20:45:25 -07001242 @Override // Binder call
Andres Morales494d6e92015-08-06 15:01:41 -07001243 public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
Jim Millercb2ce6f2016-04-13 20:28:18 -07001244 if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
Kevin Chynf4023b52017-04-07 16:29:19 -07001245 Binder.getCallingUid(), Binder.getCallingPid(),
1246 UserHandle.getCallingUserId())) {
Svetoslav4af76a52015-04-29 15:29:46 -07001247 return false;
1248 }
Andres Morales494d6e92015-08-06 15:01:41 -07001249
Clara Bayarri35fd93812016-02-29 17:49:18 -08001250 return FingerprintService.this.hasEnrolledFingerprints(userId);
Jorim Jaggi2aad7ee2015-04-14 15:25:06 -07001251 }
Andres Morales4d41a202015-04-16 14:12:38 -07001252
Jim Millerbe675422015-05-11 20:45:25 -07001253 @Override // Binder call
Svetoslav4af76a52015-04-29 15:29:46 -07001254 public long getAuthenticatorId(String opPackageName) {
Alex Klyubina99b8b52015-06-11 13:27:34 -07001255 // In this method, we're not checking whether the caller is permitted to use fingerprint
1256 // API because current authenticator ID is leaked (in a more contrived way) via Android
1257 // Keystore (android.security.keystore package): the user of that API can create a key
1258 // which requires fingerprint authentication for its use, and then query the key's
1259 // characteristics (hidden API) which returns, among other things, fingerprint
1260 // authenticator ID which was active at key creation time.
1261 //
1262 // Reason: The part of Android Keystore which runs inside an app's process invokes this
1263 // method in certain cases. Those cases are not always where the developer demonstrates
1264 // explicit intent to use fingerprint functionality. Thus, to avoiding throwing an
1265 // unexpected SecurityException this method does not check whether its caller is
1266 // permitted to use fingerprint API.
1267 //
1268 // The permission check should be restored once Android Keystore no longer invokes this
1269 // method from inside app processes.
1270
Jim Millercb2ce6f2016-04-13 20:28:18 -07001271 return FingerprintService.this.getAuthenticatorId(opPackageName);
Andres Morales4d41a202015-04-16 14:12:38 -07001272 }
Chris Wrenc510ad52015-08-14 15:43:15 -04001273
1274 @Override // Binder call
1275 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001276 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Chris Wrenc510ad52015-08-14 15:43:15 -04001277
1278 final long ident = Binder.clearCallingIdentity();
1279 try {
Joe Onorato1754d742016-11-21 17:51:35 -08001280 if (args.length > 0 && "--proto".equals(args[0])) {
1281 dumpProto(fd);
1282 } else {
1283 dumpInternal(pw);
1284 }
Chris Wrenc510ad52015-08-14 15:43:15 -04001285 } finally {
1286 Binder.restoreCallingIdentity(ident);
1287 }
1288 }
Charles He959ac8e2017-03-27 21:16:20 +01001289
Jim Millere0507bb2015-08-12 20:30:34 -07001290 @Override // Binder call
1291 public void resetTimeout(byte [] token) {
1292 checkPermission(RESET_FINGERPRINT_LOCKOUT);
1293 // TODO: confirm security token when we move timeout management into the HAL layer.
Kevin Chyn5457cba2017-08-30 15:28:28 -07001294 mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
Jorim Jaggi3a464782015-08-28 16:59:13 -07001295 }
1296
1297 @Override
1298 public void addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback)
1299 throws RemoteException {
1300 mHandler.post(new Runnable() {
1301 @Override
1302 public void run() {
1303 addLockoutResetMonitor(
1304 new FingerprintServiceLockoutResetMonitor(callback));
1305 }
1306 });
Jim Millere0507bb2015-08-12 20:30:34 -07001307 }
Phil Weaver27fcd9c2017-01-20 15:57:24 -08001308
1309 @Override
1310 public boolean isClientActive() {
1311 checkPermission(MANAGE_FINGERPRINT);
1312 synchronized(FingerprintService.this) {
1313 return (mCurrentClient != null) || (mPendingClient != null);
1314 }
1315 }
1316
1317 @Override
1318 public void addClientActiveCallback(IFingerprintClientActiveCallback callback) {
1319 checkPermission(MANAGE_FINGERPRINT);
1320 mClientActiveCallbacks.add(callback);
1321 }
1322
1323 @Override
1324 public void removeClientActiveCallback(IFingerprintClientActiveCallback callback) {
1325 checkPermission(MANAGE_FINGERPRINT);
1326 mClientActiveCallbacks.remove(callback);
1327 }
Chris Wrenc510ad52015-08-14 15:43:15 -04001328 }
1329
1330 private void dumpInternal(PrintWriter pw) {
1331 JSONObject dump = new JSONObject();
1332 try {
1333 dump.put("service", "Fingerprint Manager");
1334
1335 JSONArray sets = new JSONArray();
1336 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1337 final int userId = user.getUserHandle().getIdentifier();
1338 final int N = mFingerprintUtils.getFingerprintsForUser(mContext, userId).size();
Jim Millerbcc100a2016-07-06 14:16:49 -07001339 PerformanceStats stats = mPerformanceMap.get(userId);
1340 PerformanceStats cryptoStats = mCryptoPerformanceMap.get(userId);
Chris Wrenc510ad52015-08-14 15:43:15 -04001341 JSONObject set = new JSONObject();
1342 set.put("id", userId);
1343 set.put("count", N);
Jim Millerbcc100a2016-07-06 14:16:49 -07001344 set.put("accept", (stats != null) ? stats.accept : 0);
1345 set.put("reject", (stats != null) ? stats.reject : 0);
1346 set.put("acquire", (stats != null) ? stats.acquire : 0);
1347 set.put("lockout", (stats != null) ? stats.lockout : 0);
Kevin Chyndf9d33e2017-05-03 21:40:12 -07001348 set.put("permanentLockout", (stats != null) ? stats.permanentLockout : 0);
Jim Millerbcc100a2016-07-06 14:16:49 -07001349 // cryptoStats measures statistics about secure fingerprint transactions
1350 // (e.g. to unlock password storage, make secure purchases, etc.)
1351 set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0);
1352 set.put("rejectCrypto", (cryptoStats != null) ? cryptoStats.reject : 0);
1353 set.put("acquireCrypto", (cryptoStats != null) ? cryptoStats.acquire : 0);
1354 set.put("lockoutCrypto", (cryptoStats != null) ? cryptoStats.lockout : 0);
Kweku Adamscd7c35c2017-09-14 16:45:06 -07001355 set.put("permanentLockoutCrypto",
1356 (cryptoStats != null) ? cryptoStats.permanentLockout : 0);
Chris Wrenc510ad52015-08-14 15:43:15 -04001357 sets.put(set);
1358 }
1359
1360 dump.put("prints", sets);
1361 } catch (JSONException e) {
1362 Slog.e(TAG, "dump formatting failure", e);
1363 }
1364 pw.println(dump);
Jim Millera75961472014-06-06 15:00:49 -07001365 }
1366
Joe Onorato1754d742016-11-21 17:51:35 -08001367 private void dumpProto(FileDescriptor fd) {
1368 final ProtoOutputStream proto = new ProtoOutputStream(fd);
1369 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1370 final int userId = user.getUserHandle().getIdentifier();
1371
1372 final long userToken = proto.start(FingerprintServiceDumpProto.USERS);
1373
1374 proto.write(FingerprintUserStatsProto.USER_ID, userId);
1375 proto.write(FingerprintUserStatsProto.NUM_FINGERPRINTS,
1376 mFingerprintUtils.getFingerprintsForUser(mContext, userId).size());
1377
1378 // Normal fingerprint authentications (e.g. lockscreen)
1379 final PerformanceStats normal = mPerformanceMap.get(userId);
1380 if (normal != null) {
1381 final long countsToken = proto.start(FingerprintUserStatsProto.NORMAL);
Kweku Adamsfd257d62017-10-25 17:53:50 -07001382 proto.write(PerformanceStatsProto.ACCEPT, normal.accept);
1383 proto.write(PerformanceStatsProto.REJECT, normal.reject);
1384 proto.write(PerformanceStatsProto.ACQUIRE, normal.acquire);
1385 proto.write(PerformanceStatsProto.LOCKOUT, normal.lockout);
1386 proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, normal.permanentLockout);
Joe Onorato1754d742016-11-21 17:51:35 -08001387 proto.end(countsToken);
1388 }
1389
1390 // Statistics about secure fingerprint transactions (e.g. to unlock password
1391 // storage, make secure purchases, etc.)
Kevin Chyn9310f5c2017-02-21 17:22:54 -08001392 final PerformanceStats crypto = mCryptoPerformanceMap.get(userId);
Joe Onorato1754d742016-11-21 17:51:35 -08001393 if (crypto != null) {
1394 final long countsToken = proto.start(FingerprintUserStatsProto.CRYPTO);
Kweku Adamsfd257d62017-10-25 17:53:50 -07001395 proto.write(PerformanceStatsProto.ACCEPT, crypto.accept);
1396 proto.write(PerformanceStatsProto.REJECT, crypto.reject);
1397 proto.write(PerformanceStatsProto.ACQUIRE, crypto.acquire);
1398 proto.write(PerformanceStatsProto.LOCKOUT, crypto.lockout);
1399 proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, crypto.permanentLockout);
Joe Onorato1754d742016-11-21 17:51:35 -08001400 proto.end(countsToken);
1401 }
1402
1403 proto.end(userToken);
1404 }
1405 proto.flush();
1406 }
1407
Jim Millera75961472014-06-06 15:00:49 -07001408 @Override
1409 public void onStart() {
Jim Miller9f0753f2015-03-23 23:59:22 -07001410 publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
Fyodor Kupolove29a5a12016-12-16 16:14:17 -08001411 SystemServerInitThreadPool.get().submit(this::getFingerprintDaemon, TAG + ".onStart");
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -07001412 listenForUserSwitches();
Jim Millera75961472014-06-06 15:00:49 -07001413 }
1414
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001415 private void updateActiveGroup(int userId, String clientPackage) {
Jim Miller40e46452016-12-16 18:38:53 -08001416 IBiometricsFingerprint daemon = getFingerprintDaemon();
Jim Millerbcc100a2016-07-06 14:16:49 -07001417
Jim Millerbe675422015-05-11 20:45:25 -07001418 if (daemon != null) {
1419 try {
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001420 userId = getUserOrWorkProfileId(clientPackage, userId);
1421 if (userId != mCurrentUserId) {
1422 final File systemDir = Environment.getUserSystemDirectory(userId);
1423 final File fpDir = new File(systemDir, FP_DATA_DIR);
1424 if (!fpDir.exists()) {
1425 if (!fpDir.mkdir()) {
1426 Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath());
1427 return;
1428 }
1429 // Calling mkdir() from this process will create a directory with our
1430 // permissions (inherited from the containing dir). This command fixes
1431 // the label.
1432 if (!SELinux.restorecon(fpDir)) {
1433 Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
1434 return;
1435 }
Jim Millerbe675422015-05-11 20:45:25 -07001436 }
Jim Miller40e46452016-12-16 18:38:53 -08001437 daemon.setActiveGroup(userId, fpDir.getAbsolutePath());
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001438 mCurrentUserId = userId;
Jim Millerbe675422015-05-11 20:45:25 -07001439 }
Charles He29b3a8a2017-05-04 16:02:38 +01001440 mAuthenticatorIds.put(userId,
1441 hasEnrolledFingerprints(userId) ? daemon.getAuthenticatorId() : 0L);
Jim Millerbe675422015-05-11 20:45:25 -07001442 } catch (RemoteException e) {
1443 Slog.e(TAG, "Failed to setActiveGroup():", e);
1444 }
Jim Millerdbe780f2015-05-18 13:55:00 -07001445 }
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -07001446 }
1447
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001448 /**
1449 * @param clientPackage the package of the caller
1450 * @return the profile id
1451 */
1452 private int getUserOrWorkProfileId(String clientPackage, int userId) {
1453 if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
1454 return userId;
1455 }
1456 return getEffectiveUserId(userId);
1457 }
1458
1459 /**
1460 * @param userId
1461 * @return true if this is a work profile
1462 */
1463 private boolean isWorkProfile(int userId) {
Charles Heda88f0e2017-02-02 18:29:13 +00001464 UserInfo userInfo = null;
1465 final long token = Binder.clearCallingIdentity();
1466 try {
1467 userInfo = mUserManager.getUserInfo(userId);
1468 } finally {
1469 Binder.restoreCallingIdentity(token);
1470 }
1471 return userInfo != null && userInfo.isManagedProfile();
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001472 }
1473
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -07001474 private void listenForUserSwitches() {
1475 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001476 ActivityManager.getService().registerUserSwitchObserver(
Fyodor Kupolov6005b3f2015-11-23 17:41:50 -08001477 new SynchronousUserSwitchObserver() {
Jim Millerbe675422015-05-11 20:45:25 -07001478 @Override
Fyodor Kupolov6005b3f2015-11-23 17:41:50 -08001479 public void onUserSwitching(int newUserId) throws RemoteException {
Jim Millerbe675422015-05-11 20:45:25 -07001480 mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
1481 .sendToTarget();
1482 }
Fyodor Kupolov0b77ef92016-06-20 17:16:52 -07001483 }, TAG);
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -07001484 } catch (RemoteException e) {
1485 Slog.w(TAG, "Failed to listen for user switching event" ,e);
1486 }
1487 }
Jim Millerbe675422015-05-11 20:45:25 -07001488
Jim Millerd0063102016-06-28 16:43:57 -07001489 /***
1490 * @param opPackageName the name of the calling package
Charles Heda88f0e2017-02-02 18:29:13 +00001491 * @return authenticator id for the calling user
Jim Millerd0063102016-06-28 16:43:57 -07001492 */
Jim Millercb2ce6f2016-04-13 20:28:18 -07001493 public long getAuthenticatorId(String opPackageName) {
Charles Heda88f0e2017-02-02 18:29:13 +00001494 final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
Charles He29b3a8a2017-05-04 16:02:38 +01001495 return mAuthenticatorIds.getOrDefault(userId, 0L);
Jim Millerbe675422015-05-11 20:45:25 -07001496 }
Jim Millera75961472014-06-06 15:00:49 -07001497}