blob: b5f94b1ce384a12bd5b5a41d0917185e1d4525ce [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;
Andreas Huber7fe20532018-01-22 11:26:44 -080048import android.os.Build;
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +010049import android.os.Bundle;
Jorim Jaggi3a464782015-08-28 16:59:13 -070050import android.os.DeadObjectException;
Sasha Levitskiy80db9ba2015-05-08 14:31:48 -070051import android.os.Environment;
Jim Millera75961472014-06-06 15:00:49 -070052import android.os.Handler;
53import android.os.IBinder;
Jim Miller40e46452016-12-16 18:38:53 -080054import android.os.IHwBinder;
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +010055import android.os.IRemoteCallback;
Jim Millerdca15d22015-06-16 20:55:13 -070056import android.os.PowerManager;
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +010057import android.os.PowerManager.WakeLock;
Jim Millera75961472014-06-06 15:00:49 -070058import android.os.RemoteException;
Jim Miller16ef71f2015-05-21 17:02:21 -070059import android.os.SELinux;
Kevin Chynaae4a152018-01-18 11:48:09 -080060import android.os.ServiceManager;
Jim Millerdca15d22015-06-16 20:55:13 -070061import android.os.SystemClock;
Andreas Huber7fe20532018-01-22 11:26:44 -080062import android.os.SystemProperties;
Jim Miller599ef0e2015-06-15 20:39:44 -070063import android.os.UserHandle;
Jim Millercb7d9e92015-06-16 15:05:48 -070064import android.os.UserManager;
Charles He959ac8e2017-03-27 21:16:20 +010065import android.security.KeyStore;
Jim Millera75961472014-06-06 15:00:49 -070066import android.util.Slog;
Kevin Chyn5457cba2017-08-30 15:28:28 -070067import android.util.SparseBooleanArray;
68import android.util.SparseIntArray;
Joe Onorato1754d742016-11-21 17:51:35 -080069import android.util.proto.ProtoOutputStream;
Jim Millera75961472014-06-06 15:00:49 -070070
Fyodor Kupolov449e7082016-10-31 15:06:12 -070071import com.android.internal.annotations.GuardedBy;
Chris Wrenc510ad52015-08-14 15:43:15 -040072import com.android.internal.logging.MetricsLogger;
Kevin Chynaae4a152018-01-18 11:48:09 -080073import com.android.internal.statusbar.IStatusBarService;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060074import com.android.internal.util.DumpUtils;
Fyodor Kupolove29a5a12016-12-16 16:14:17 -080075import com.android.server.SystemServerInitThreadPool;
Jim Millera75961472014-06-06 15:00:49 -070076import com.android.server.SystemService;
77
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 Millerbcc100a2016-07-06 14:16:49 -070087import java.util.HashMap;
Jim Miller9f0753f2015-03-23 23:59:22 -070088import java.util.List;
Charles Heda88f0e2017-02-02 18:29:13 +000089import java.util.Map;
Phil Weaver27fcd9c2017-01-20 15:57:24 -080090import java.util.concurrent.CopyOnWriteArrayList;
Jim Millera75961472014-06-06 15:00:49 -070091
92/**
93 * A service to manage multiple clients that want to access the fingerprint HAL API.
94 * The service is responsible for maintaining a list of clients and dispatching all
Kevin Chynedd71f92017-09-01 16:09:57 -070095 * fingerprint-related events.
Jim Millera75961472014-06-06 15:00:49 -070096 *
97 * @hide
98 */
Jim Miller40e46452016-12-16 18:38:53 -080099public class FingerprintService extends SystemService implements IHwBinder.DeathRecipient {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700100 static final String TAG = "FingerprintService";
101 static final boolean DEBUG = true;
Kevin Chynedd71f92017-09-01 16:09:57 -0700102 private static final boolean CLEANUP_UNUSED_FP = true;
Jim Millerbe675422015-05-11 20:45:25 -0700103 private static final String FP_DATA_DIR = "fpdata";
Jim Millerbe675422015-05-11 20:45:25 -0700104 private static final int MSG_USER_SWITCHING = 10;
Jorim Jaggi5e354222015-09-04 14:17:58 -0700105 private static final String ACTION_LOCKOUT_RESET =
106 "com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
Kevin Chyn5457cba2017-08-30 15:28:28 -0700107 private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
Jim Millerbe675422015-05-11 20:45:25 -0700108
Jim Millerbcc100a2016-07-06 14:16:49 -0700109 private class PerformanceStats {
110 int accept; // number of accepted fingerprints
111 int reject; // number of rejected fingerprints
112 int acquire; // total number of acquisitions. Should be >= accept+reject due to poor image
113 // acquisition in some cases (too fast, too slow, dirty sensor, etc.)
114 int lockout; // total number of lockouts
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700115 int permanentLockout; // total number of permanent lockouts
Jim Millerbcc100a2016-07-06 14:16:49 -0700116 }
117
Jorim Jaggi3a464782015-08-28 16:59:13 -0700118 private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
119 new ArrayList<>();
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800120 private final CopyOnWriteArrayList<IFingerprintClientActiveCallback> mClientActiveCallbacks =
121 new CopyOnWriteArrayList<>();
Charles Heda88f0e2017-02-02 18:29:13 +0000122 private final Map<Integer, Long> mAuthenticatorIds =
123 Collections.synchronizedMap(new HashMap<>());
Svetoslav4af76a52015-04-29 15:29:46 -0700124 private final AppOpsManager mAppOps;
Jim Milleraf281ca2015-04-20 19:04:21 -0700125 private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700126 private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5;
127 private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;
128
Jim Miller3d5e3962016-06-08 01:52:50 +0000129 private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
Jim Miller975f1452015-08-31 18:18:22 -0700130 private final String mKeyguardPackage;
Charles He959ac8e2017-03-27 21:16:20 +0100131 private int mCurrentUserId = UserHandle.USER_NULL;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700132 private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance();
133 private Context mContext;
134 private long mHalDeviceId;
Kevin Chyn5457cba2017-08-30 15:28:28 -0700135 private SparseBooleanArray mTimedLockoutCleared;
136 private SparseIntArray mFailedAttempts;
Fyodor Kupolov449e7082016-10-31 15:06:12 -0700137 @GuardedBy("this")
Jim Miller40e46452016-12-16 18:38:53 -0800138 private IBiometricsFingerprint mDaemon;
Kevin Chynaae4a152018-01-18 11:48:09 -0800139 private IStatusBarService mStatusBarService;
Jim Millercb2ce6f2016-04-13 20:28:18 -0700140 private final PowerManager mPowerManager;
141 private final AlarmManager mAlarmManager;
142 private final UserManager mUserManager;
143 private ClientMonitor mCurrentClient;
144 private ClientMonitor mPendingClient;
Jim Millerbcc100a2016-07-06 14:16:49 -0700145 private PerformanceStats mPerformanceStats;
146
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700147 private IBinder mToken = new Binder(); // used for internal FingerprintService enumeration
Kevin Chynedd71f92017-09-01 16:09:57 -0700148 private ArrayList<UserFingerprint> mUnknownFingerprints = new ArrayList<>(); // hw fingerprints
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700149
150 private class UserFingerprint {
151 Fingerprint f;
152 int userId;
153 public UserFingerprint(Fingerprint f, int userId) {
154 this.f = f;
155 this.userId = userId;
156 }
157 }
158
Jim Millerbcc100a2016-07-06 14:16:49 -0700159 // Normal fingerprint authentications are tracked by mPerformanceMap.
Jim Miller40e46452016-12-16 18:38:53 -0800160 private HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
Jim Millerbcc100a2016-07-06 14:16:49 -0700161
162 // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
Jim Miller40e46452016-12-16 18:38:53 -0800163 private HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
Jim Millerce7eb6d2015-04-03 19:29:13 -0700164
Jim Millercb2ce6f2016-04-13 20:28:18 -0700165 private Handler mHandler = new Handler() {
Jim Miller80a776e2015-07-15 18:57:14 -0700166 @Override
Jim Millera75961472014-06-06 15:00:49 -0700167 public void handleMessage(android.os.Message msg) {
168 switch (msg.what) {
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -0700169 case MSG_USER_SWITCHING:
170 handleUserSwitching(msg.arg1);
171 break;
172
Jim Millera75961472014-06-06 15:00:49 -0700173 default:
174 Slog.w(TAG, "Unknown message:" + msg.what);
175 }
176 }
177 };
Jim Millerbe675422015-05-11 20:45:25 -0700178
Jorim Jaggi5e354222015-09-04 14:17:58 -0700179 private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
180 @Override
181 public void onReceive(Context context, Intent intent) {
182 if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700183 final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
184 resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
Jorim Jaggi5e354222015-09-04 14:17:58 -0700185 }
186 }
187 };
188
Kevin Chyn5457cba2017-08-30 15:28:28 -0700189 private final Runnable mResetFailedAttemptsForCurrentUserRunnable = new Runnable() {
Jim Millerfe6439f2015-04-11 18:07:57 -0700190 @Override
191 public void run() {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700192 resetFailedAttemptsForUser(true /* clearAttemptCounter */,
193 ActivityManager.getCurrentUser());
Jim Millerfe6439f2015-04-11 18:07:57 -0700194 }
195 };
Jim Millera75961472014-06-06 15:00:49 -0700196
Jim Millercb2ce6f2016-04-13 20:28:18 -0700197 private final Runnable mResetClientState = new Runnable() {
198 @Override
199 public void run() {
200 // Warning: if we get here, the driver never confirmed our call to cancel the current
201 // operation (authenticate, enroll, remove, enumerate, etc), which is
202 // really bad. The result will be a 3-second delay in starting each new client.
203 // If you see this on a device, make certain the driver notifies with
204 // {@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} in response to cancel()
205 // once it has successfully switched to the IDLE state in the fingerprint HAL.
206 // Additionally,{@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} should only be sent
207 // in response to an actual cancel() call.
208 Slog.w(TAG, "Client "
209 + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
210 + " failed to respond to cancel, starting client "
211 + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700212
Jim Millercb2ce6f2016-04-13 20:28:18 -0700213 mCurrentClient = null;
214 startClient(mPendingClient, false);
215 }
216 };
217
Jim Millera75961472014-06-06 15:00:49 -0700218 public FingerprintService(Context context) {
219 super(context);
220 mContext = context;
Jim Miller975f1452015-08-31 18:18:22 -0700221 mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
222 com.android.internal.R.string.config_keyguardComponent)).getPackageName();
Svetoslav4af76a52015-04-29 15:29:46 -0700223 mAppOps = context.getSystemService(AppOpsManager.class);
Jorim Jaggi5e354222015-09-04 14:17:58 -0700224 mPowerManager = mContext.getSystemService(PowerManager.class);
225 mAlarmManager = mContext.getSystemService(AlarmManager.class);
226 mContext.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
227 RESET_FINGERPRINT_LOCKOUT, null /* handler */);
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000228 mUserManager = UserManager.get(mContext);
Kevin Chyn5457cba2017-08-30 15:28:28 -0700229 mTimedLockoutCleared = new SparseBooleanArray();
230 mFailedAttempts = new SparseIntArray();
Kevin Chynaae4a152018-01-18 11:48:09 -0800231 mStatusBarService = IStatusBarService.Stub.asInterface(
232 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
Jim Millera75961472014-06-06 15:00:49 -0700233 }
234
Jim Millerbe675422015-05-11 20:45:25 -0700235 @Override
Jim Miller40e46452016-12-16 18:38:53 -0800236 public void serviceDied(long cookie) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700237 Slog.v(TAG, "fingerprint HAL died");
Jim Millerc57c8d92016-09-30 17:17:59 -0700238 MetricsLogger.count(mContext, "fingerprintd_died", 1);
Jim Miller40e46452016-12-16 18:38:53 -0800239 handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
240 0 /*vendorCode */);
Jim Millera75961472014-06-06 15:00:49 -0700241 }
242
Jim Miller40e46452016-12-16 18:38:53 -0800243 public synchronized IBiometricsFingerprint getFingerprintDaemon() {
244 if (mDaemon == null) {
Kevin Chynedd71f92017-09-01 16:09:57 -0700245 Slog.v(TAG, "mDaemon was null, reconnect to fingerprint");
Jim Miller40e46452016-12-16 18:38:53 -0800246 try {
Yifan Hong25d5eaa2017-03-16 15:25:43 -0700247 mDaemon = IBiometricsFingerprint.getService();
Jim Miller40e46452016-12-16 18:38:53 -0800248 } catch (java.util.NoSuchElementException e) {
249 // Service doesn't exist or cannot be opened. Logged below.
250 } catch (RemoteException e) {
251 Slog.e(TAG, "Failed to get biometric interface", e);
Jim Millera75961472014-06-06 15:00:49 -0700252 }
Jim Miller40e46452016-12-16 18:38:53 -0800253 if (mDaemon == null) {
254 Slog.w(TAG, "fingerprint HIDL not available");
255 return null;
256 }
257
258 mDaemon.asBinder().linkToDeath(this, 0);
259
260 try {
261 mHalDeviceId = mDaemon.setNotify(mDaemonCallback);
262 } catch (RemoteException e) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700263 Slog.e(TAG, "Failed to open fingerprint HAL", e);
Jim Miller40e46452016-12-16 18:38:53 -0800264 mDaemon = null; // try again later!
265 }
266
267 if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
268 if (mHalDeviceId != 0) {
Charles Heda88f0e2017-02-02 18:29:13 +0000269 loadAuthenticatorIds();
Jim Miller40e46452016-12-16 18:38:53 -0800270 updateActiveGroup(ActivityManager.getCurrentUser(), null);
Kevin Chynedd71f92017-09-01 16:09:57 -0700271 doFingerprintCleanupForUser(ActivityManager.getCurrentUser());
Jim Miller40e46452016-12-16 18:38:53 -0800272 } else {
273 Slog.w(TAG, "Failed to open Fingerprint HAL!");
274 MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);
275 mDaemon = null;
276 }
Jim Millerce7eb6d2015-04-03 19:29:13 -0700277 }
Jim Miller40e46452016-12-16 18:38:53 -0800278 return mDaemon;
Jim Millerbe675422015-05-11 20:45:25 -0700279 }
280
Charles Heda88f0e2017-02-02 18:29:13 +0000281 /** Populates existing authenticator ids. To be used only during the start of the service. */
282 private void loadAuthenticatorIds() {
283 // This operation can be expensive, so keep track of the elapsed time. Might need to move to
284 // background if it takes too long.
285 long t = System.currentTimeMillis();
Charles Heda88f0e2017-02-02 18:29:13 +0000286 mAuthenticatorIds.clear();
287 for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) {
288 int userId = getUserOrWorkProfileId(null, user.id);
289 if (!mAuthenticatorIds.containsKey(userId)) {
290 updateActiveGroup(userId, null);
291 }
292 }
293
294 t = System.currentTimeMillis() - t;
295 if (t > 1000) {
296 Slog.w(TAG, "loadAuthenticatorIds() taking too long: " + t + "ms");
297 }
298 }
299
Kevin Chynedd71f92017-09-01 16:09:57 -0700300 /**
301 * This method should be called upon connection to the daemon, and when user switches.
302 * @param userId
303 */
304 private void doFingerprintCleanupForUser(int userId) {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700305 if (CLEANUP_UNUSED_FP) {
Kevin Chynedd71f92017-09-01 16:09:57 -0700306 enumerateUser(userId);
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700307 }
308 }
309
Kevin Chynedd71f92017-09-01 16:09:57 -0700310 private void clearEnumerateState() {
311 if (DEBUG) Slog.v(TAG, "clearEnumerateState()");
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700312 mUnknownFingerprints.clear();
313 }
314
Kevin Chynedd71f92017-09-01 16:09:57 -0700315 private void enumerateUser(int userId) {
316 if (DEBUG) Slog.v(TAG, "Enumerating user(" + userId + ")");
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700317 boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
Kevin Chynedd71f92017-09-01 16:09:57 -0700318 startEnumerate(mToken, userId, null, restricted, true /* internal */);
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700319 }
320
321 // Remove unknown fingerprints from hardware
322 private void cleanupUnknownFingerprints() {
323 if (!mUnknownFingerprints.isEmpty()) {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700324 UserFingerprint uf = mUnknownFingerprints.get(0);
325 mUnknownFingerprints.remove(uf);
326 boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700327 startRemove(mToken, uf.f.getFingerId(), uf.f.getGroupId(), uf.userId, null,
328 restricted, true /* internal */);
329 } else {
Kevin Chynedd71f92017-09-01 16:09:57 -0700330 clearEnumerateState();
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700331 }
332 }
333
Jim Miller40e46452016-12-16 18:38:53 -0800334 protected void handleEnumerate(long deviceId, int fingerId, int groupId, int remaining) {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700335 ClientMonitor client = mCurrentClient;
336
337 if ( !(client instanceof InternalRemovalClient) && !(client instanceof EnumerateClient) ) {
338 return;
339 }
340 client.onEnumerationResult(fingerId, groupId, remaining);
341
342 // All fingerprints in hardware for this user were enumerated
343 if (remaining == 0) {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700344 if (client instanceof InternalEnumerateClient) {
Kevin Chynedd71f92017-09-01 16:09:57 -0700345 List<Fingerprint> unknownFingerprints =
346 ((InternalEnumerateClient) client).getUnknownFingerprints();
347
348 if (!unknownFingerprints.isEmpty()) {
349 Slog.w(TAG, "Adding " + unknownFingerprints.size() +
350 " fingerprints for deletion");
351 }
352 for (Fingerprint f : unknownFingerprints) {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700353 mUnknownFingerprints.add(new UserFingerprint(f, client.getTargetUserId()));
354 }
Kevin Chynedd71f92017-09-01 16:09:57 -0700355 removeClient(client);
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700356 cleanupUnknownFingerprints();
Kevin Chynedd71f92017-09-01 16:09:57 -0700357 } else {
358 removeClient(client);
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700359 }
360 }
Jim Millerbe675422015-05-11 20:45:25 -0700361 }
362
Jim Miller40e46452016-12-16 18:38:53 -0800363 protected void handleError(long deviceId, int error, int vendorCode) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700364 ClientMonitor client = mCurrentClient;
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700365 if (client instanceof InternalRemovalClient || client instanceof InternalEnumerateClient) {
Kevin Chynedd71f92017-09-01 16:09:57 -0700366 clearEnumerateState();
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700367 }
Jim Miller40e46452016-12-16 18:38:53 -0800368 if (client != null && client.onError(error, vendorCode)) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700369 removeClient(client);
Jim Millerbe675422015-05-11 20:45:25 -0700370 }
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700371
Jim Millercb2ce6f2016-04-13 20:28:18 -0700372 if (DEBUG) Slog.v(TAG, "handleError(client="
Jim Millerc1e61b82016-04-18 13:00:40 -0700373 + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
Jim Millercb2ce6f2016-04-13 20:28:18 -0700374 // This is the magic code that starts the next client when the old client finishes.
375 if (error == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
376 mHandler.removeCallbacks(mResetClientState);
377 if (mPendingClient != null) {
378 if (DEBUG) Slog.v(TAG, "start pending client " + mPendingClient.getOwnerString());
379 startClient(mPendingClient, false);
380 mPendingClient = null;
381 }
Jim Miller8eddd332017-03-22 16:40:10 -0700382 } else if (error == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) {
383 // If we get HW_UNAVAILABLE, try to connect again later...
384 Slog.w(TAG, "Got ERROR_HW_UNAVAILABLE; try reconnecting next client.");
385 synchronized (this) {
386 mDaemon = null;
387 mHalDeviceId = 0;
Charles He959ac8e2017-03-27 21:16:20 +0100388 mCurrentUserId = UserHandle.USER_NULL;
Jim Miller8eddd332017-03-22 16:40:10 -0700389 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700390 }
391 }
392
Jim Miller40e46452016-12-16 18:38:53 -0800393 protected void handleRemoved(long deviceId, int fingerId, int groupId, int remaining) {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700394 if (DEBUG) Slog.w(TAG, "Removed: fid=" + fingerId
395 + ", gid=" + groupId
396 + ", dev=" + deviceId
397 + ", rem=" + remaining);
398
Jim Millercb2ce6f2016-04-13 20:28:18 -0700399 ClientMonitor client = mCurrentClient;
Jim Miller40e46452016-12-16 18:38:53 -0800400 if (client != null && client.onRemoved(fingerId, groupId, remaining)) {
Jim Miller07dbd632016-04-05 18:22:30 -0700401 removeClient(client);
Charles He29b3a8a2017-05-04 16:02:38 +0100402 // When the last fingerprint of a group is removed, update the authenticator id
403 if (!hasEnrolledFingerprints(groupId)) {
404 updateActiveGroup(groupId, null);
405 }
Jim Millerbe675422015-05-11 20:45:25 -0700406 }
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700407 if (client instanceof InternalRemovalClient && !mUnknownFingerprints.isEmpty()) {
408 cleanupUnknownFingerprints();
409 } else if (client instanceof InternalRemovalClient){
Kevin Chynedd71f92017-09-01 16:09:57 -0700410 clearEnumerateState();
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700411 }
Jim Millerbe675422015-05-11 20:45:25 -0700412 }
413
Jim Millera8eaeeb2017-01-24 14:47:04 -0800414 protected void handleAuthenticated(long deviceId, int fingerId, int groupId,
415 ArrayList<Byte> token) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700416 ClientMonitor client = mCurrentClient;
Jim Millera8eaeeb2017-01-24 14:47:04 -0800417 if (fingerId != 0) {
418 // Ugh...
419 final byte[] byteToken = new byte[token.size()];
420 for (int i = 0; i < token.size(); i++) {
421 byteToken[i] = token.get(i);
422 }
423 // Send to Keystore
424 KeyStore.getInstance().addAuthToken(byteToken);
425 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700426 if (client != null && client.onAuthenticated(fingerId, groupId)) {
427 removeClient(client);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700428 }
Jim Millerbcc100a2016-07-06 14:16:49 -0700429 if (fingerId != 0) {
430 mPerformanceStats.accept++;
431 } else {
432 mPerformanceStats.reject++;
433 }
Jim Millerbe675422015-05-11 20:45:25 -0700434 }
435
Jim Miller40e46452016-12-16 18:38:53 -0800436 protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700437 ClientMonitor client = mCurrentClient;
Jim Miller40e46452016-12-16 18:38:53 -0800438 if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700439 removeClient(client);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700440 }
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700441 if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
Jim Millerbcc100a2016-07-06 14:16:49 -0700442 && client instanceof AuthenticationClient) {
443 // ignore enrollment acquisitions or acquisitions when we're locked out
444 mPerformanceStats.acquire++;
445 }
Jim Millerdca15d22015-06-16 20:55:13 -0700446 }
Jim Millerbe675422015-05-11 20:45:25 -0700447
Jim Miller8b3c25a2015-08-28 17:29:49 -0700448 protected void handleEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700449 ClientMonitor client = mCurrentClient;
450 if (client != null && client.onEnrollResult(fingerId, groupId, remaining)) {
451 removeClient(client);
Charles He29b3a8a2017-05-04 16:02:38 +0100452 // When enrollment finishes, update this group's authenticator id, as the HAL has
453 // already generated a new authenticator id when the new fingerprint is enrolled.
454 updateActiveGroup(groupId, null);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700455 }
Jim Millerce7eb6d2015-04-03 19:29:13 -0700456 }
457
Jim Miller8b3c25a2015-08-28 17:29:49 -0700458 private void userActivity() {
459 long now = SystemClock.uptimeMillis();
460 mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
461 }
462
463 void handleUserSwitching(int userId) {
Kevin Chynedd71f92017-09-01 16:09:57 -0700464 if (mCurrentClient instanceof InternalRemovalClient
465 || mCurrentClient instanceof InternalEnumerateClient) {
466 Slog.w(TAG, "User switched while performing cleanup");
467 removeClient(mCurrentClient);
468 clearEnumerateState();
469 }
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000470 updateActiveGroup(userId, null);
Kevin Chynedd71f92017-09-01 16:09:57 -0700471 doFingerprintCleanupForUser(userId);
Jim Miller8b3c25a2015-08-28 17:29:49 -0700472 }
473
Jim Millerbe675422015-05-11 20:45:25 -0700474 private void removeClient(ClientMonitor client) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700475 if (client != null) {
476 client.destroy();
477 if (client != mCurrentClient && mCurrentClient != null) {
478 Slog.w(TAG, "Unexpected client: " + client.getOwnerString() + "expected: "
479 + mCurrentClient != null ? mCurrentClient.getOwnerString() : "null");
480 }
481 }
482 if (mCurrentClient != null) {
483 if (DEBUG) Slog.v(TAG, "Done with client: " + client.getOwnerString());
484 mCurrentClient = null;
Jim Millerfe6439f2015-04-11 18:07:57 -0700485 }
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800486 if (mPendingClient == null) {
487 notifyClientActiveCallbacks(false);
488 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700489 }
490
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700491 private int getLockoutMode() {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700492 final int currentUser = ActivityManager.getCurrentUser();
493 final int failedAttempts = mFailedAttempts.get(currentUser, 0);
494 if (failedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) {
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700495 return AuthenticationClient.LOCKOUT_PERMANENT;
Kevin Chyn5457cba2017-08-30 15:28:28 -0700496 } else if (failedAttempts > 0 &&
497 mTimedLockoutCleared.get(currentUser, false) == false
498 && (failedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) {
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700499 return AuthenticationClient.LOCKOUT_TIMED;
500 }
501 return AuthenticationClient.LOCKOUT_NONE;
Jim Millerfe6439f2015-04-11 18:07:57 -0700502 }
503
Kevin Chyn5457cba2017-08-30 15:28:28 -0700504 private void scheduleLockoutResetForUser(int userId) {
505 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
506 SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
507 getLockoutResetIntentForUser(userId));
Jorim Jaggi5e354222015-09-04 14:17:58 -0700508 }
509
Kevin Chyn5457cba2017-08-30 15:28:28 -0700510 private void cancelLockoutResetForUser(int userId) {
511 mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
Jorim Jaggi5e354222015-09-04 14:17:58 -0700512 }
513
Kevin Chyn5457cba2017-08-30 15:28:28 -0700514 private PendingIntent getLockoutResetIntentForUser(int userId) {
515 return PendingIntent.getBroadcast(mContext, userId,
516 new Intent(ACTION_LOCKOUT_RESET).putExtra(KEY_LOCKOUT_RESET_USER, userId),
517 PendingIntent.FLAG_UPDATE_CURRENT);
Jorim Jaggi5e354222015-09-04 14:17:58 -0700518 }
519
Jim Millerce7eb6d2015-04-03 19:29:13 -0700520 public long startPreEnroll(IBinder token) {
Jim Miller40e46452016-12-16 18:38:53 -0800521 IBiometricsFingerprint daemon = getFingerprintDaemon();
Jim Millerbe675422015-05-11 20:45:25 -0700522 if (daemon == null) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700523 Slog.w(TAG, "startPreEnroll: no fingerprint HAL!");
Jim Millerbe675422015-05-11 20:45:25 -0700524 return 0;
525 }
526 try {
527 return daemon.preEnroll();
528 } catch (RemoteException e) {
529 Slog.e(TAG, "startPreEnroll failed", e);
530 }
531 return 0;
Jim Millerce7eb6d2015-04-03 19:29:13 -0700532 }
533
Sasha Levitskiye0943cf2015-07-08 13:22:20 -0700534 public int startPostEnroll(IBinder token) {
Jim Miller40e46452016-12-16 18:38:53 -0800535 IBiometricsFingerprint daemon = getFingerprintDaemon();
Sasha Levitskiye0943cf2015-07-08 13:22:20 -0700536 if (daemon == null) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700537 Slog.w(TAG, "startPostEnroll: no fingerprint HAL!");
Sasha Levitskiye0943cf2015-07-08 13:22:20 -0700538 return 0;
539 }
540 try {
541 return daemon.postEnroll();
542 } catch (RemoteException e) {
543 Slog.e(TAG, "startPostEnroll failed", e);
544 }
545 return 0;
546 }
547
Jim Miller80a776e2015-07-15 18:57:14 -0700548 /**
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700549 * Calls fingerprint HAL to switch states to the new task. If there's already a current task,
Jim Millercb2ce6f2016-04-13 20:28:18 -0700550 * it calls cancel() and sets mPendingClient to begin when the current task finishes
551 * ({@link FingerprintManager#FINGERPRINT_ERROR_CANCELED}).
552 * @param newClient the new client that wants to connect
553 * @param initiatedByClient true for authenticate, remove and enroll
Jim Miller80a776e2015-07-15 18:57:14 -0700554 */
Jim Millercb2ce6f2016-04-13 20:28:18 -0700555 private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
556 ClientMonitor currentClient = mCurrentClient;
557 if (currentClient != null) {
558 if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString());
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700559 if (currentClient instanceof InternalEnumerateClient ||
560 currentClient instanceof InternalRemovalClient) {
561 // This condition means we're currently running internal diagnostics to
562 // remove extra fingerprints in the hardware and/or the software
563 // TODO: design an escape hatch in case client never finishes
Kevin Chynedd71f92017-09-01 16:09:57 -0700564 if (newClient != null) {
565 Slog.w(TAG, "Internal cleanup in progress but trying to start client "
566 + newClient.getClass().getSuperclass().getSimpleName()
567 + "(" + newClient.getOwnerString() + ")"
568 + ", initiatedByClient = " + initiatedByClient);
569 }
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700570 }
571 else {
572 currentClient.stop(initiatedByClient);
573 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700574 mPendingClient = newClient;
575 mHandler.removeCallbacks(mResetClientState);
576 mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
577 } else if (newClient != null) {
578 mCurrentClient = newClient;
579 if (DEBUG) Slog.v(TAG, "starting client "
580 + newClient.getClass().getSuperclass().getSimpleName()
581 + "(" + newClient.getOwnerString() + ")"
Kevin Chynedd71f92017-09-01 16:09:57 -0700582 + ", initiatedByClient = " + initiatedByClient);
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800583 notifyClientActiveCallbacks(true);
584
Jim Millercb2ce6f2016-04-13 20:28:18 -0700585 newClient.start();
Jim Millera75961472014-06-06 15:00:49 -0700586 }
587 }
588
Jim Miller8f2aca02016-04-20 13:34:11 -0700589 void startRemove(IBinder token, int fingerId, int groupId, int userId,
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700590 IFingerprintServiceReceiver receiver, boolean restricted, boolean internal) {
Jim Miller40e46452016-12-16 18:38:53 -0800591 IBiometricsFingerprint daemon = getFingerprintDaemon();
Jim Millerbe675422015-05-11 20:45:25 -0700592 if (daemon == null) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700593 Slog.w(TAG, "startRemove: no fingerprint HAL!");
Jim Millerbe675422015-05-11 20:45:25 -0700594 return;
595 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700596
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700597 if (internal) {
598 Context context = getContext();
599 InternalRemovalClient client = new InternalRemovalClient(context, mHalDeviceId,
600 token, receiver, fingerId, groupId, userId, restricted,
601 context.getOpPackageName()) {
602 @Override
603 public void notifyUserActivity() {
604
605 }
606 @Override
607 public IBiometricsFingerprint getFingerprintDaemon() {
608 return FingerprintService.this.getFingerprintDaemon();
609 }
610 };
611 startClient(client, true);
612 }
613 else {
614 RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token,
615 receiver, fingerId, groupId, userId, restricted, token.toString()) {
616 @Override
617 public void notifyUserActivity() {
618 FingerprintService.this.userActivity();
619 }
620
621 @Override
622 public IBiometricsFingerprint getFingerprintDaemon() {
623 return FingerprintService.this.getFingerprintDaemon();
624 }
625 };
626 startClient(client, true);
627 }
Jim Miller40e46452016-12-16 18:38:53 -0800628 }
629
630 void startEnumerate(IBinder token, int userId,
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700631 IFingerprintServiceReceiver receiver, boolean restricted, boolean internal) {
Jim Miller40e46452016-12-16 18:38:53 -0800632 IBiometricsFingerprint daemon = getFingerprintDaemon();
633 if (daemon == null) {
Kevin Chyn80e40cc2017-03-14 12:31:17 -0700634 Slog.w(TAG, "startEnumerate: no fingerprint HAL!");
Jim Miller40e46452016-12-16 18:38:53 -0800635 return;
636 }
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700637 if (internal) {
638 List<Fingerprint> enrolledList = getEnrolledFingerprints(userId);
639 Context context = getContext();
640 InternalEnumerateClient client = new InternalEnumerateClient(context, mHalDeviceId,
641 token, receiver, userId, userId, restricted, context.getOpPackageName(),
642 enrolledList) {
643 @Override
644 public void notifyUserActivity() {
Jim Miller40e46452016-12-16 18:38:53 -0800645
Kevin Chynd1f1a0b2017-04-03 13:37:48 -0700646 }
647
648 @Override
649 public IBiometricsFingerprint getFingerprintDaemon() {
650 return FingerprintService.this.getFingerprintDaemon();
651 }
652 };
653 startClient(client, true);
654 }
655 else {
656 EnumerateClient client = new EnumerateClient(getContext(), mHalDeviceId, token,
657 receiver, userId, userId, restricted, token.toString()) {
658 @Override
659 public void notifyUserActivity() {
660 FingerprintService.this.userActivity();
661 }
662
663 @Override
664 public IBiometricsFingerprint getFingerprintDaemon() {
665 return FingerprintService.this.getFingerprintDaemon();
666 }
667 };
668 startClient(client, true);
669 }
Jim Millera75961472014-06-06 15:00:49 -0700670 }
671
Jim Miller599ef0e2015-06-15 20:39:44 -0700672 public List<Fingerprint> getEnrolledFingerprints(int userId) {
673 return mFingerprintUtils.getFingerprintsForUser(mContext, userId);
Jim Miller9f0753f2015-03-23 23:59:22 -0700674 }
675
Jim Miller599ef0e2015-06-15 20:39:44 -0700676 public boolean hasEnrolledFingerprints(int userId) {
Jim Miller1fd298b2016-02-25 16:42:28 -0800677 if (userId != UserHandle.getCallingUserId()) {
Clara Bayarri33fd3cf2016-02-19 16:54:49 +0000678 checkPermission(INTERACT_ACROSS_USERS);
679 }
Jim Miller599ef0e2015-06-15 20:39:44 -0700680 return mFingerprintUtils.getFingerprintsForUser(mContext, userId).size() > 0;
Jorim Jaggi2aad7ee2015-04-14 15:25:06 -0700681 }
682
Jim Millerf501b582015-06-03 16:36:31 -0700683 boolean hasPermission(String permission) {
684 return getContext().checkCallingOrSelfPermission(permission)
685 == PackageManager.PERMISSION_GRANTED;
686 }
687
Jim Millerba67aee2015-02-20 16:21:26 -0800688 void checkPermission(String permission) {
Jim Miller9f0753f2015-03-23 23:59:22 -0700689 getContext().enforceCallingOrSelfPermission(permission,
690 "Must have " + permission + " permission.");
Jim Millera75961472014-06-06 15:00:49 -0700691 }
692
Andres Morales494d6e92015-08-06 15:01:41 -0700693 int getEffectiveUserId(int userId) {
694 UserManager um = UserManager.get(mContext);
695 if (um != null) {
696 final long callingIdentity = Binder.clearCallingIdentity();
697 userId = um.getCredentialOwnerProfile(userId);
698 Binder.restoreCallingIdentity(callingIdentity);
699 } else {
700 Slog.e(TAG, "Unable to acquire UserManager");
701 }
702 return userId;
703 }
704
Jim Millercb7d9e92015-06-16 15:05:48 -0700705 boolean isCurrentUserOrProfile(int userId) {
706 UserManager um = UserManager.get(mContext);
Charles Heda88f0e2017-02-02 18:29:13 +0000707 if (um == null) {
708 Slog.e(TAG, "Unable to acquire UserManager");
709 return false;
Jim Millercb7d9e92015-06-16 15:05:48 -0700710 }
Charles Heda88f0e2017-02-02 18:29:13 +0000711
712 final long token = Binder.clearCallingIdentity();
713 try {
714 // Allow current user or profiles of the current user...
Charles He959ac8e2017-03-27 21:16:20 +0100715 for (int profileId : um.getEnabledProfileIds(ActivityManager.getCurrentUser())) {
Charles Heda88f0e2017-02-02 18:29:13 +0000716 if (profileId == userId) {
717 return true;
718 }
719 }
Charles Heda88f0e2017-02-02 18:29:13 +0000720 } finally {
721 Binder.restoreCallingIdentity(token);
722 }
Charles He959ac8e2017-03-27 21:16:20 +0100723
724 return false;
Jim Millercb7d9e92015-06-16 15:05:48 -0700725 }
726
Jim Miller975f1452015-08-31 18:18:22 -0700727 private boolean isForegroundActivity(int uid, int pid) {
728 try {
729 List<RunningAppProcessInfo> procs =
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800730 ActivityManager.getService().getRunningAppProcesses();
Jim Miller975f1452015-08-31 18:18:22 -0700731 int N = procs.size();
732 for (int i = 0; i < N; i++) {
733 RunningAppProcessInfo proc = procs.get(i);
734 if (proc.pid == pid && proc.uid == uid
735 && proc.importance == IMPORTANCE_FOREGROUND) {
736 return true;
737 }
738 }
739 } catch (RemoteException e) {
740 Slog.w(TAG, "am.getRunningAppProcesses() failed");
741 }
742 return false;
743 }
744
745 /**
746 * @param opPackageName name of package for caller
Jim Miller37979c92016-08-05 18:54:58 -0700747 * @param requireForeground only allow this call while app is in the foreground
Jim Miller975f1452015-08-31 18:18:22 -0700748 * @return true if caller can use fingerprint API
749 */
Jim Miller37979c92016-08-05 18:54:58 -0700750 private boolean canUseFingerprint(String opPackageName, boolean requireForeground, int uid,
Kevin Chynf4023b52017-04-07 16:29:19 -0700751 int pid, int userId) {
Svetoslav4af76a52015-04-29 15:29:46 -0700752 checkPermission(USE_FINGERPRINT);
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000753 if (isKeyguard(opPackageName)) {
Jim Miller975f1452015-08-31 18:18:22 -0700754 return true; // Keyguard is always allowed
755 }
Kevin Chynf4023b52017-04-07 16:29:19 -0700756 if (!isCurrentUserOrProfile(userId)) {
Jim Miller975f1452015-08-31 18:18:22 -0700757 Slog.w(TAG,"Rejecting " + opPackageName + " ; not a current user or profile");
758 return false;
759 }
760 if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
761 != AppOpsManager.MODE_ALLOWED) {
Jim Miller1adb4a72015-09-14 18:58:08 -0700762 Slog.w(TAG, "Rejecting " + opPackageName + " ; permission denied");
Jim Miller975f1452015-08-31 18:18:22 -0700763 return false;
764 }
Jim Miller37979c92016-08-05 18:54:58 -0700765 if (requireForeground && !(isForegroundActivity(uid, pid) || currentClient(opPackageName))){
Jim Miller1adb4a72015-09-14 18:58:08 -0700766 Slog.w(TAG, "Rejecting " + opPackageName + " ; not in foreground");
Jim Miller975f1452015-08-31 18:18:22 -0700767 return false;
768 }
769 return true;
Svetoslav4af76a52015-04-29 15:29:46 -0700770 }
771
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000772 /**
Jim Miller37979c92016-08-05 18:54:58 -0700773 * @param opPackageName package of the caller
774 * @return true if this is the same client currently using fingerprint
775 */
776 private boolean currentClient(String opPackageName) {
777 return mCurrentClient != null && mCurrentClient.getOwnerString().equals(opPackageName);
778 }
779
780 /**
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000781 * @param clientPackage
782 * @return true if this is keyguard package
783 */
784 private boolean isKeyguard(String clientPackage) {
785 return mKeyguardPackage.equals(clientPackage);
786 }
787
Jorim Jaggi3a464782015-08-28 16:59:13 -0700788 private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
789 if (!mLockoutMonitors.contains(monitor)) {
790 mLockoutMonitors.add(monitor);
791 }
792 }
793
794 private void removeLockoutResetCallback(
795 FingerprintServiceLockoutResetMonitor monitor) {
796 mLockoutMonitors.remove(monitor);
797 }
798
799 private void notifyLockoutResetMonitors() {
800 for (int i = 0; i < mLockoutMonitors.size(); i++) {
801 mLockoutMonitors.get(i).sendLockoutReset();
802 }
803 }
804
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800805 private void notifyClientActiveCallbacks(boolean isActive) {
806 List<IFingerprintClientActiveCallback> callbacks = mClientActiveCallbacks;
807 for (int i = 0; i < callbacks.size(); i++) {
808 try {
809 callbacks.get(i).onClientActiveChanged(isActive);
810 } catch (RemoteException re) {
811 // If the remote is dead, stop notifying it
812 mClientActiveCallbacks.remove(callbacks.get(i));
Charles He959ac8e2017-03-27 21:16:20 +0100813 }
Phil Weaver27fcd9c2017-01-20 15:57:24 -0800814 }
815 }
816
Tony Makff715ac2016-04-19 20:44:12 +0100817 private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId,
Jim Millercb2ce6f2016-04-13 20:28:18 -0700818 IFingerprintServiceReceiver receiver, int flags, boolean restricted,
Kevin Chynaae4a152018-01-18 11:48:09 -0800819 String opPackageName, Bundle bundle, IFingerprintDialogReceiver dialogReceiver) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700820 updateActiveGroup(groupId, opPackageName);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700821
Jim Millercb2ce6f2016-04-13 20:28:18 -0700822 if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")");
Jim Millerfe6439f2015-04-11 18:07:57 -0700823
Jim Millercb2ce6f2016-04-13 20:28:18 -0700824 AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token,
Kevin Chynaae4a152018-01-18 11:48:09 -0800825 receiver, mCurrentUserId, groupId, opId, restricted, opPackageName, bundle,
826 dialogReceiver, mStatusBarService) {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700827 @Override
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700828 public int handleFailedAttempt() {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700829 final int currentUser = ActivityManager.getCurrentUser();
830 mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
831 mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700832 final int lockoutMode = getLockoutMode();
833 if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
834 mPerformanceStats.permanentLockout++;
835 } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
Jim Millerbcc100a2016-07-06 14:16:49 -0700836 mPerformanceStats.lockout++;
837 }
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700838
839 // Failing multiple times will continue to push out the lockout time
840 if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700841 scheduleLockoutResetForUser(currentUser);
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700842 return lockoutMode;
Jim Miller16ef71f2015-05-21 17:02:21 -0700843 }
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700844 return AuthenticationClient.LOCKOUT_NONE;
Jim Millerfe6439f2015-04-11 18:07:57 -0700845 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700846
Jim Millercb2ce6f2016-04-13 20:28:18 -0700847 @Override
848 public void resetFailedAttempts() {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700849 FingerprintService.this.resetFailedAttemptsForUser(true /* clearAttemptCounter */,
850 ActivityManager.getCurrentUser());
Jim Millercb2ce6f2016-04-13 20:28:18 -0700851 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700852
Jim Millercb2ce6f2016-04-13 20:28:18 -0700853 @Override
854 public void notifyUserActivity() {
855 FingerprintService.this.userActivity();
Jim Millerfe6439f2015-04-11 18:07:57 -0700856 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700857
Jim Millercb2ce6f2016-04-13 20:28:18 -0700858 @Override
Jim Miller40e46452016-12-16 18:38:53 -0800859 public IBiometricsFingerprint getFingerprintDaemon() {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700860 return FingerprintService.this.getFingerprintDaemon();
Jim Millerfe6439f2015-04-11 18:07:57 -0700861 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700862 };
Jim Millerfe6439f2015-04-11 18:07:57 -0700863
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700864 int lockoutMode = getLockoutMode();
865 if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
866 Slog.v(TAG, "In lockout mode(" + lockoutMode +
867 ") ; disallowing authentication");
868 int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
869 FingerprintManager.FINGERPRINT_ERROR_LOCKOUT :
870 FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
871 if (!client.onError(errorCode, 0 /* vendorCode */)) {
872 Slog.w(TAG, "Cannot send permanent lockout message to client");
Jim Millerfe6439f2015-04-11 18:07:57 -0700873 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700874 return;
Jim Millerfe6439f2015-04-11 18:07:57 -0700875 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700876 startClient(client, true /* initiatedByClient */);
877 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700878
Jim Millerc12eca82016-04-28 15:12:53 -0700879 private void startEnrollment(IBinder token, byte [] cryptoToken, int userId,
Jim Millercb2ce6f2016-04-13 20:28:18 -0700880 IFingerprintServiceReceiver receiver, int flags, boolean restricted,
881 String opPackageName) {
Jim Millerc12eca82016-04-28 15:12:53 -0700882 updateActiveGroup(userId, opPackageName);
883
884 final int groupId = userId; // default group for fingerprint enrollment
Jim Millerfe6439f2015-04-11 18:07:57 -0700885
Jim Millercb2ce6f2016-04-13 20:28:18 -0700886 EnrollClient client = new EnrollClient(getContext(), mHalDeviceId, token, receiver,
Jim Millerc12eca82016-04-28 15:12:53 -0700887 userId, groupId, cryptoToken, restricted, opPackageName) {
Jim Millerfe6439f2015-04-11 18:07:57 -0700888
Jim Millercb2ce6f2016-04-13 20:28:18 -0700889 @Override
Jim Miller40e46452016-12-16 18:38:53 -0800890 public IBiometricsFingerprint getFingerprintDaemon() {
Jim Millercb2ce6f2016-04-13 20:28:18 -0700891 return FingerprintService.this.getFingerprintDaemon();
Jim Millerfe6439f2015-04-11 18:07:57 -0700892 }
Jim Millercb2ce6f2016-04-13 20:28:18 -0700893
894 @Override
895 public void notifyUserActivity() {
896 FingerprintService.this.userActivity();
897 }
898 };
899 startClient(client, true /* initiatedByClient */);
900 }
901
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700902 // attempt counter should only be cleared when Keyguard goes away or when
903 // a fingerprint is successfully authenticated
Kevin Chyn5457cba2017-08-30 15:28:28 -0700904 protected void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700905 if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
906 Slog.v(TAG, "Reset fingerprint lockout, clearAttemptCounter=" + clearAttemptCounter);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700907 }
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700908 if (clearAttemptCounter) {
Kevin Chyn5457cba2017-08-30 15:28:28 -0700909 mFailedAttempts.put(userId, 0);
Kevin Chyndf9d33e2017-05-03 21:40:12 -0700910 }
Kevin Chyn5457cba2017-08-30 15:28:28 -0700911 mTimedLockoutCleared.put(userId, true);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700912 // If we're asked to reset failed attempts externally (i.e. from Keyguard),
913 // the alarm might still be pending; remove it.
Kevin Chyn5457cba2017-08-30 15:28:28 -0700914 cancelLockoutResetForUser(userId);
Jim Millercb2ce6f2016-04-13 20:28:18 -0700915 notifyLockoutResetMonitors();
Jim Millerce7eb6d2015-04-03 19:29:13 -0700916 }
917
Jorim Jaggi3a464782015-08-28 16:59:13 -0700918 private class FingerprintServiceLockoutResetMonitor {
919
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +0100920 private static final long WAKELOCK_TIMEOUT_MS = 2000;
Jorim Jaggi3a464782015-08-28 16:59:13 -0700921 private final IFingerprintServiceLockoutResetCallback mCallback;
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +0100922 private final WakeLock mWakeLock;
Jorim Jaggi3a464782015-08-28 16:59:13 -0700923
924 public FingerprintServiceLockoutResetMonitor(
925 IFingerprintServiceLockoutResetCallback callback) {
926 mCallback = callback;
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +0100927 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
928 "lockout reset callback");
Jorim Jaggi3a464782015-08-28 16:59:13 -0700929 }
930
931 public void sendLockoutReset() {
932 if (mCallback != null) {
933 try {
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +0100934 mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
935 mCallback.onLockoutReset(mHalDeviceId, new IRemoteCallback.Stub() {
936
937 @Override
938 public void sendResult(Bundle data) throws RemoteException {
Kevin Chync3101182017-08-08 16:03:45 -0700939 if (mWakeLock.isHeld()) {
940 mWakeLock.release();
941 }
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +0100942 }
943 });
Jorim Jaggi3a464782015-08-28 16:59:13 -0700944 } catch (DeadObjectException e) {
945 Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
946 mHandler.post(mRemoveCallbackRunnable);
947 } catch (RemoteException e) {
948 Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
949 }
950 }
951 }
952
953 private final Runnable mRemoveCallbackRunnable = new Runnable() {
954 @Override
955 public void run() {
Jorim Jaggi57e2f4d2016-11-24 14:38:18 +0100956 if (mWakeLock.isHeld()) {
957 mWakeLock.release();
958 }
Jorim Jaggi3a464782015-08-28 16:59:13 -0700959 removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
960 }
961 };
962 }
963
Jim Miller40e46452016-12-16 18:38:53 -0800964 private IBiometricsFingerprintClientCallback mDaemonCallback =
965 new IBiometricsFingerprintClientCallback.Stub() {
Jim Millerbe675422015-05-11 20:45:25 -0700966
Jim Miller9f0753f2015-03-23 23:59:22 -0700967 @Override
Jim Miller8b3c25a2015-08-28 17:29:49 -0700968 public void onEnrollResult(final long deviceId, final int fingerId, final int groupId,
969 final int remaining) {
970 mHandler.post(new Runnable() {
971 @Override
972 public void run() {
973 handleEnrollResult(deviceId, fingerId, groupId, remaining);
974 }
975 });
Jim Millerbe675422015-05-11 20:45:25 -0700976 }
977
978 @Override
Jim Miller40e46452016-12-16 18:38:53 -0800979 public void onAcquired(final long deviceId, final int acquiredInfo, final int vendorCode) {
Jim Miller8b3c25a2015-08-28 17:29:49 -0700980 mHandler.post(new Runnable() {
981 @Override
982 public void run() {
Jim Miller40e46452016-12-16 18:38:53 -0800983 handleAcquired(deviceId, acquiredInfo, vendorCode);
Jim Miller8b3c25a2015-08-28 17:29:49 -0700984 }
985 });
Jim Millerbe675422015-05-11 20:45:25 -0700986 }
987
988 @Override
Jim Millera8eaeeb2017-01-24 14:47:04 -0800989 public void onAuthenticated(final long deviceId, final int fingerId, final int groupId,
990 ArrayList<Byte> token) {
Jim Miller8b3c25a2015-08-28 17:29:49 -0700991 mHandler.post(new Runnable() {
992 @Override
993 public void run() {
Jim Millera8eaeeb2017-01-24 14:47:04 -0800994 handleAuthenticated(deviceId, fingerId, groupId, token);
Jim Miller8b3c25a2015-08-28 17:29:49 -0700995 }
996 });
Jim Millerbe675422015-05-11 20:45:25 -0700997 }
998
999 @Override
Jim Miller40e46452016-12-16 18:38:53 -08001000 public void onError(final long deviceId, final int error, final int vendorCode) {
Jim Miller8b3c25a2015-08-28 17:29:49 -07001001 mHandler.post(new Runnable() {
1002 @Override
1003 public void run() {
Jim Miller40e46452016-12-16 18:38:53 -08001004 handleError(deviceId, error, vendorCode);
Jim Miller8b3c25a2015-08-28 17:29:49 -07001005 }
1006 });
Jim Millerbe675422015-05-11 20:45:25 -07001007 }
1008
1009 @Override
Jim Miller40e46452016-12-16 18:38:53 -08001010 public void onRemoved(final long deviceId, final int fingerId, final int groupId, final int remaining) {
Jim Miller8b3c25a2015-08-28 17:29:49 -07001011 mHandler.post(new Runnable() {
1012 @Override
1013 public void run() {
Jim Miller40e46452016-12-16 18:38:53 -08001014 handleRemoved(deviceId, fingerId, groupId, remaining);
Jim Miller8b3c25a2015-08-28 17:29:49 -07001015 }
1016 });
Jim Millerbe675422015-05-11 20:45:25 -07001017 }
1018
1019 @Override
Jim Miller40e46452016-12-16 18:38:53 -08001020 public void onEnumerate(final long deviceId, final int fingerId, final int groupId,
1021 final int remaining) {
Jim Miller8b3c25a2015-08-28 17:29:49 -07001022 mHandler.post(new Runnable() {
1023 @Override
1024 public void run() {
Jim Miller40e46452016-12-16 18:38:53 -08001025 handleEnumerate(deviceId, fingerId, groupId, remaining);
Jim Miller8b3c25a2015-08-28 17:29:49 -07001026 }
1027 });
Jim Millerbe675422015-05-11 20:45:25 -07001028 }
Jim Millerbe675422015-05-11 20:45:25 -07001029 };
1030
1031 private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
1032 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -07001033 public long preEnroll(IBinder token) {
Jim Millerba67aee2015-02-20 16:21:26 -08001034 checkPermission(MANAGE_FINGERPRINT);
Jim Millerce7eb6d2015-04-03 19:29:13 -07001035 return startPreEnroll(token);
Jim Millera75961472014-06-06 15:00:49 -07001036 }
1037
Jim Millerbe675422015-05-11 20:45:25 -07001038 @Override // Binder call
Sasha Levitskiye0943cf2015-07-08 13:22:20 -07001039 public int postEnroll(IBinder token) {
1040 checkPermission(MANAGE_FINGERPRINT);
1041 return startPostEnroll(token);
1042 }
1043
1044 @Override // Binder call
Jim Millerc12eca82016-04-28 15:12:53 -07001045 public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
Jim Millercb2ce6f2016-04-13 20:28:18 -07001046 final IFingerprintServiceReceiver receiver, final int flags,
1047 final String opPackageName) {
Jim Millerce7eb6d2015-04-03 19:29:13 -07001048 checkPermission(MANAGE_FINGERPRINT);
Kevin Chynaae4a152018-01-18 11:48:09 -08001049 final int limit = mContext.getResources().getInteger(
Jim Miller599ef0e2015-06-15 20:39:44 -07001050 com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
Jim Millerc12eca82016-04-28 15:12:53 -07001051
1052 final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size();
Jim Miller599ef0e2015-06-15 20:39:44 -07001053 if (enrolled >= limit) {
1054 Slog.w(TAG, "Too many fingerprints registered");
1055 return;
1056 }
Jim Millerf501b582015-06-03 16:36:31 -07001057
Andres Morales494d6e92015-08-06 15:01:41 -07001058 // Group ID is arbitrarily set to parent profile user ID. It just represents
1059 // the default fingerprints for the user.
Jim Millerc12eca82016-04-28 15:12:53 -07001060 if (!isCurrentUserOrProfile(userId)) {
Clara Bayarri35fd93812016-02-29 17:49:18 -08001061 return;
1062 }
Andres Morales494d6e92015-08-06 15:01:41 -07001063
Jim Millerf501b582015-06-03 16:36:31 -07001064 final boolean restricted = isRestricted();
Jim Millerce7eb6d2015-04-03 19:29:13 -07001065 mHandler.post(new Runnable() {
1066 @Override
1067 public void run() {
Jim Millerc12eca82016-04-28 15:12:53 -07001068 startEnrollment(token, cryptoToken, userId, receiver, flags,
Jim Millercb2ce6f2016-04-13 20:28:18 -07001069 restricted, opPackageName);
Jim Millerce7eb6d2015-04-03 19:29:13 -07001070 }
1071 });
1072 }
1073
Jim Millerf501b582015-06-03 16:36:31 -07001074 private boolean isRestricted() {
1075 // Only give privileged apps (like Settings) access to fingerprint info
1076 final boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
1077 return restricted;
1078 }
1079
Jim Millerbe675422015-05-11 20:45:25 -07001080 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -07001081 public void cancelEnrollment(final IBinder token) {
1082 checkPermission(MANAGE_FINGERPRINT);
1083 mHandler.post(new Runnable() {
1084 @Override
1085 public void run() {
Jim Millercb2ce6f2016-04-13 20:28:18 -07001086 ClientMonitor client = mCurrentClient;
1087 if (client instanceof EnrollClient && client.getToken() == token) {
1088 client.stop(client.getToken() == token);
1089 }
Jim Millerce7eb6d2015-04-03 19:29:13 -07001090 }
1091 });
1092 }
1093
Jim Millerbe675422015-05-11 20:45:25 -07001094 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -07001095 public void authenticate(final IBinder token, final long opId, final int groupId,
Jim Millerdca15d22015-06-16 20:55:13 -07001096 final IFingerprintServiceReceiver receiver, final int flags,
Kevin Chynaae4a152018-01-18 11:48:09 -08001097 final String opPackageName, final Bundle bundle,
1098 final IFingerprintDialogReceiver dialogReceiver) {
Tony Makff715ac2016-04-19 20:44:12 +01001099 final int callingUid = Binder.getCallingUid();
Kevin Chyn33fdf112017-08-09 11:45:21 -07001100 final int callingPid = Binder.getCallingPid();
Tony Makff715ac2016-04-19 20:44:12 +01001101 final int callingUserId = UserHandle.getCallingUserId();
Jim Millerf501b582015-06-03 16:36:31 -07001102 final boolean restricted = isRestricted();
Kevin Chyn33fdf112017-08-09 11:45:21 -07001103
1104 if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
1105 callingUserId)) {
1106 if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
1107 return;
1108 }
1109
Jim Millerce7eb6d2015-04-03 19:29:13 -07001110 mHandler.post(new Runnable() {
1111 @Override
1112 public void run() {
Jim Millerbcc100a2016-07-06 14:16:49 -07001113 MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
1114
1115 // Get performance stats object for this user.
1116 HashMap<Integer, PerformanceStats> pmap
1117 = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
1118 PerformanceStats stats = pmap.get(mCurrentUserId);
1119 if (stats == null) {
1120 stats = new PerformanceStats();
1121 pmap.put(mCurrentUserId, stats);
1122 }
1123 mPerformanceStats = stats;
1124
Tony Makff715ac2016-04-19 20:44:12 +01001125 startAuthentication(token, opId, callingUserId, groupId, receiver,
Kevin Chynaae4a152018-01-18 11:48:09 -08001126 flags, restricted, opPackageName, bundle, dialogReceiver);
Jim Millerce7eb6d2015-04-03 19:29:13 -07001127 }
1128 });
1129 }
1130
Jim Millerbe675422015-05-11 20:45:25 -07001131 @Override // Binder call
Jim Millercb2ce6f2016-04-13 20:28:18 -07001132 public void cancelAuthentication(final IBinder token, final String opPackageName) {
Kevin Chyn33fdf112017-08-09 11:45:21 -07001133 final int callingUid = Binder.getCallingUid();
1134 final int callingPid = Binder.getCallingPid();
Kevin Chynf4023b52017-04-07 16:29:19 -07001135 final int callingUserId = UserHandle.getCallingUserId();
Kevin Chyn33fdf112017-08-09 11:45:21 -07001136
1137 if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
1138 callingUserId)) {
1139 if (DEBUG) Slog.v(TAG, "cancelAuthentication(): reject " + opPackageName);
1140 return;
1141 }
1142
Jim Millerce7eb6d2015-04-03 19:29:13 -07001143 mHandler.post(new Runnable() {
1144 @Override
1145 public void run() {
Kevin Chyn33fdf112017-08-09 11:45:21 -07001146 ClientMonitor client = mCurrentClient;
1147 if (client instanceof AuthenticationClient) {
1148 if (client.getToken() == token) {
1149 if (DEBUG) Slog.v(TAG, "stop client " + client.getOwnerString());
1150 client.stop(client.getToken() == token);
1151 } else {
1152 if (DEBUG) Slog.v(TAG, "can't stop client "
1153 + client.getOwnerString() + " since tokens don't match");
Jim Millercb2ce6f2016-04-13 20:28:18 -07001154 }
Kevin Chyn33fdf112017-08-09 11:45:21 -07001155 } else if (client != null) {
1156 if (DEBUG) Slog.v(TAG, "can't cancel non-authenticating client "
1157 + client.getOwnerString());
Jim Millercb2ce6f2016-04-13 20:28:18 -07001158 }
Jim Millerce7eb6d2015-04-03 19:29:13 -07001159 }
1160 });
Jim Millerba67aee2015-02-20 16:21:26 -08001161 }
Jim Miller99d60192015-03-11 17:41:58 -07001162
Jim Millerbe675422015-05-11 20:45:25 -07001163 @Override // Binder call
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001164 public void setActiveUser(final int userId) {
1165 checkPermission(MANAGE_FINGERPRINT);
1166 mHandler.post(new Runnable() {
1167 @Override
1168 public void run() {
1169 updateActiveGroup(userId, null);
1170 }
1171 });
1172 }
1173
1174 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -07001175 public void remove(final IBinder token, final int fingerId, final int groupId,
Jim Miller8f2aca02016-04-20 13:34:11 -07001176 final int userId, final IFingerprintServiceReceiver receiver) {
Jim Miller9f0753f2015-03-23 23:59:22 -07001177 checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
Jim Millerf501b582015-06-03 16:36:31 -07001178 final boolean restricted = isRestricted();
Jim Millerce7eb6d2015-04-03 19:29:13 -07001179 mHandler.post(new Runnable() {
1180 @Override
1181 public void run() {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -07001182 startRemove(token, fingerId, groupId, userId, receiver,
1183 restricted, false /* internal */);
Jim Millerce7eb6d2015-04-03 19:29:13 -07001184 }
1185 });
Jim Miller9f0753f2015-03-23 23:59:22 -07001186 }
1187
Kevin Chynd1f1a0b2017-04-03 13:37:48 -07001188 @Override // Binder call
Jim Miller40e46452016-12-16 18:38:53 -08001189 public void enumerate(final IBinder token, final int userId,
1190 final IFingerprintServiceReceiver receiver) {
1191 checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
1192 final boolean restricted = isRestricted();
1193 mHandler.post(new Runnable() {
1194 @Override
1195 public void run() {
Kevin Chynd1f1a0b2017-04-03 13:37:48 -07001196 startEnumerate(token, userId, receiver, restricted, false /* internal */);
Jim Miller40e46452016-12-16 18:38:53 -08001197 }
1198 });
Jim Miller40e46452016-12-16 18:38:53 -08001199 }
1200
Jim Millerbe675422015-05-11 20:45:25 -07001201 @Override // Binder call
Svetoslav4af76a52015-04-29 15:29:46 -07001202 public boolean isHardwareDetected(long deviceId, String opPackageName) {
Jim Millercb2ce6f2016-04-13 20:28:18 -07001203 if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
Kevin Chynf4023b52017-04-07 16:29:19 -07001204 Binder.getCallingUid(), Binder.getCallingPid(),
1205 UserHandle.getCallingUserId())) {
Svetoslav4af76a52015-04-29 15:29:46 -07001206 return false;
1207 }
Charles He959ac8e2017-03-27 21:16:20 +01001208
1209 final long token = Binder.clearCallingIdentity();
1210 try {
1211 IBiometricsFingerprint daemon = getFingerprintDaemon();
1212 return daemon != null && mHalDeviceId != 0;
1213 } finally {
1214 Binder.restoreCallingIdentity(token);
1215 }
Jim Miller9f0753f2015-03-23 23:59:22 -07001216 }
1217
Jim Millerbe675422015-05-11 20:45:25 -07001218 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -07001219 public void rename(final int fingerId, final int groupId, final String name) {
Jim Miller99d60192015-03-11 17:41:58 -07001220 checkPermission(MANAGE_FINGERPRINT);
Clara Bayarri35fd93812016-02-29 17:49:18 -08001221 if (!isCurrentUserOrProfile(groupId)) {
1222 return;
1223 }
Jim Millerce7eb6d2015-04-03 19:29:13 -07001224 mHandler.post(new Runnable() {
1225 @Override
1226 public void run() {
Andres Morales494d6e92015-08-06 15:01:41 -07001227 mFingerprintUtils.renameFingerprintForUser(mContext, fingerId,
Clara Bayarri35fd93812016-02-29 17:49:18 -08001228 groupId, name);
Jim Millerce7eb6d2015-04-03 19:29:13 -07001229 }
1230 });
Jim Miller99d60192015-03-11 17:41:58 -07001231 }
Jim Miller9f0753f2015-03-23 23:59:22 -07001232
Jim Millerbe675422015-05-11 20:45:25 -07001233 @Override // Binder call
Jim Miller599ef0e2015-06-15 20:39:44 -07001234 public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
Jim Millercb2ce6f2016-04-13 20:28:18 -07001235 if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
Kevin Chynf4023b52017-04-07 16:29:19 -07001236 Binder.getCallingUid(), Binder.getCallingPid(),
1237 UserHandle.getCallingUserId())) {
Svetoslav4af76a52015-04-29 15:29:46 -07001238 return Collections.emptyList();
1239 }
Andres Morales494d6e92015-08-06 15:01:41 -07001240
Clara Bayarri35fd93812016-02-29 17:49:18 -08001241 return FingerprintService.this.getEnrolledFingerprints(userId);
Jim Miller9f0753f2015-03-23 23:59:22 -07001242 }
Jorim Jaggi2aad7ee2015-04-14 15:25:06 -07001243
Jim Millerbe675422015-05-11 20:45:25 -07001244 @Override // Binder call
Andres Morales494d6e92015-08-06 15:01:41 -07001245 public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
Jim Millercb2ce6f2016-04-13 20:28:18 -07001246 if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
Kevin Chynf4023b52017-04-07 16:29:19 -07001247 Binder.getCallingUid(), Binder.getCallingPid(),
1248 UserHandle.getCallingUserId())) {
Svetoslav4af76a52015-04-29 15:29:46 -07001249 return false;
1250 }
Andres Morales494d6e92015-08-06 15:01:41 -07001251
Clara Bayarri35fd93812016-02-29 17:49:18 -08001252 return FingerprintService.this.hasEnrolledFingerprints(userId);
Jorim Jaggi2aad7ee2015-04-14 15:25:06 -07001253 }
Andres Morales4d41a202015-04-16 14:12:38 -07001254
Jim Millerbe675422015-05-11 20:45:25 -07001255 @Override // Binder call
Svetoslav4af76a52015-04-29 15:29:46 -07001256 public long getAuthenticatorId(String opPackageName) {
Alex Klyubina99b8b52015-06-11 13:27:34 -07001257 // In this method, we're not checking whether the caller is permitted to use fingerprint
1258 // API because current authenticator ID is leaked (in a more contrived way) via Android
1259 // Keystore (android.security.keystore package): the user of that API can create a key
1260 // which requires fingerprint authentication for its use, and then query the key's
1261 // characteristics (hidden API) which returns, among other things, fingerprint
1262 // authenticator ID which was active at key creation time.
1263 //
1264 // Reason: The part of Android Keystore which runs inside an app's process invokes this
1265 // method in certain cases. Those cases are not always where the developer demonstrates
1266 // explicit intent to use fingerprint functionality. Thus, to avoiding throwing an
1267 // unexpected SecurityException this method does not check whether its caller is
1268 // permitted to use fingerprint API.
1269 //
1270 // The permission check should be restored once Android Keystore no longer invokes this
1271 // method from inside app processes.
1272
Jim Millercb2ce6f2016-04-13 20:28:18 -07001273 return FingerprintService.this.getAuthenticatorId(opPackageName);
Andres Morales4d41a202015-04-16 14:12:38 -07001274 }
Chris Wrenc510ad52015-08-14 15:43:15 -04001275
1276 @Override // Binder call
1277 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001278 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Chris Wrenc510ad52015-08-14 15:43:15 -04001279
1280 final long ident = Binder.clearCallingIdentity();
1281 try {
Joe Onorato1754d742016-11-21 17:51:35 -08001282 if (args.length > 0 && "--proto".equals(args[0])) {
1283 dumpProto(fd);
1284 } else {
1285 dumpInternal(pw);
1286 }
Chris Wrenc510ad52015-08-14 15:43:15 -04001287 } finally {
1288 Binder.restoreCallingIdentity(ident);
1289 }
1290 }
Charles He959ac8e2017-03-27 21:16:20 +01001291
Jim Millere0507bb2015-08-12 20:30:34 -07001292 @Override // Binder call
1293 public void resetTimeout(byte [] token) {
1294 checkPermission(RESET_FINGERPRINT_LOCKOUT);
1295 // TODO: confirm security token when we move timeout management into the HAL layer.
Kevin Chyn5457cba2017-08-30 15:28:28 -07001296 mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
Jorim Jaggi3a464782015-08-28 16:59:13 -07001297 }
1298
1299 @Override
1300 public void addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback)
1301 throws RemoteException {
1302 mHandler.post(new Runnable() {
1303 @Override
1304 public void run() {
1305 addLockoutResetMonitor(
1306 new FingerprintServiceLockoutResetMonitor(callback));
1307 }
1308 });
Jim Millere0507bb2015-08-12 20:30:34 -07001309 }
Phil Weaver27fcd9c2017-01-20 15:57:24 -08001310
1311 @Override
1312 public boolean isClientActive() {
1313 checkPermission(MANAGE_FINGERPRINT);
1314 synchronized(FingerprintService.this) {
1315 return (mCurrentClient != null) || (mPendingClient != null);
1316 }
1317 }
1318
1319 @Override
1320 public void addClientActiveCallback(IFingerprintClientActiveCallback callback) {
1321 checkPermission(MANAGE_FINGERPRINT);
1322 mClientActiveCallbacks.add(callback);
1323 }
1324
1325 @Override
1326 public void removeClientActiveCallback(IFingerprintClientActiveCallback callback) {
1327 checkPermission(MANAGE_FINGERPRINT);
1328 mClientActiveCallbacks.remove(callback);
1329 }
Chris Wrenc510ad52015-08-14 15:43:15 -04001330 }
1331
1332 private void dumpInternal(PrintWriter pw) {
1333 JSONObject dump = new JSONObject();
1334 try {
1335 dump.put("service", "Fingerprint Manager");
1336
1337 JSONArray sets = new JSONArray();
1338 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1339 final int userId = user.getUserHandle().getIdentifier();
1340 final int N = mFingerprintUtils.getFingerprintsForUser(mContext, userId).size();
Jim Millerbcc100a2016-07-06 14:16:49 -07001341 PerformanceStats stats = mPerformanceMap.get(userId);
1342 PerformanceStats cryptoStats = mCryptoPerformanceMap.get(userId);
Chris Wrenc510ad52015-08-14 15:43:15 -04001343 JSONObject set = new JSONObject();
1344 set.put("id", userId);
1345 set.put("count", N);
Jim Millerbcc100a2016-07-06 14:16:49 -07001346 set.put("accept", (stats != null) ? stats.accept : 0);
1347 set.put("reject", (stats != null) ? stats.reject : 0);
1348 set.put("acquire", (stats != null) ? stats.acquire : 0);
1349 set.put("lockout", (stats != null) ? stats.lockout : 0);
Kevin Chyndf9d33e2017-05-03 21:40:12 -07001350 set.put("permanentLockout", (stats != null) ? stats.permanentLockout : 0);
Jim Millerbcc100a2016-07-06 14:16:49 -07001351 // cryptoStats measures statistics about secure fingerprint transactions
1352 // (e.g. to unlock password storage, make secure purchases, etc.)
1353 set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0);
1354 set.put("rejectCrypto", (cryptoStats != null) ? cryptoStats.reject : 0);
1355 set.put("acquireCrypto", (cryptoStats != null) ? cryptoStats.acquire : 0);
1356 set.put("lockoutCrypto", (cryptoStats != null) ? cryptoStats.lockout : 0);
Kweku Adamscd7c35c2017-09-14 16:45:06 -07001357 set.put("permanentLockoutCrypto",
1358 (cryptoStats != null) ? cryptoStats.permanentLockout : 0);
Chris Wrenc510ad52015-08-14 15:43:15 -04001359 sets.put(set);
1360 }
1361
1362 dump.put("prints", sets);
1363 } catch (JSONException e) {
1364 Slog.e(TAG, "dump formatting failure", e);
1365 }
1366 pw.println(dump);
Jim Millera75961472014-06-06 15:00:49 -07001367 }
1368
Joe Onorato1754d742016-11-21 17:51:35 -08001369 private void dumpProto(FileDescriptor fd) {
1370 final ProtoOutputStream proto = new ProtoOutputStream(fd);
1371 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1372 final int userId = user.getUserHandle().getIdentifier();
1373
1374 final long userToken = proto.start(FingerprintServiceDumpProto.USERS);
1375
1376 proto.write(FingerprintUserStatsProto.USER_ID, userId);
1377 proto.write(FingerprintUserStatsProto.NUM_FINGERPRINTS,
1378 mFingerprintUtils.getFingerprintsForUser(mContext, userId).size());
1379
1380 // Normal fingerprint authentications (e.g. lockscreen)
1381 final PerformanceStats normal = mPerformanceMap.get(userId);
1382 if (normal != null) {
1383 final long countsToken = proto.start(FingerprintUserStatsProto.NORMAL);
Kweku Adamsfd257d62017-10-25 17:53:50 -07001384 proto.write(PerformanceStatsProto.ACCEPT, normal.accept);
1385 proto.write(PerformanceStatsProto.REJECT, normal.reject);
1386 proto.write(PerformanceStatsProto.ACQUIRE, normal.acquire);
1387 proto.write(PerformanceStatsProto.LOCKOUT, normal.lockout);
1388 proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, normal.permanentLockout);
Joe Onorato1754d742016-11-21 17:51:35 -08001389 proto.end(countsToken);
1390 }
1391
1392 // Statistics about secure fingerprint transactions (e.g. to unlock password
1393 // storage, make secure purchases, etc.)
Kevin Chyn9310f5c2017-02-21 17:22:54 -08001394 final PerformanceStats crypto = mCryptoPerformanceMap.get(userId);
Joe Onorato1754d742016-11-21 17:51:35 -08001395 if (crypto != null) {
1396 final long countsToken = proto.start(FingerprintUserStatsProto.CRYPTO);
Kweku Adamsfd257d62017-10-25 17:53:50 -07001397 proto.write(PerformanceStatsProto.ACCEPT, crypto.accept);
1398 proto.write(PerformanceStatsProto.REJECT, crypto.reject);
1399 proto.write(PerformanceStatsProto.ACQUIRE, crypto.acquire);
1400 proto.write(PerformanceStatsProto.LOCKOUT, crypto.lockout);
1401 proto.write(PerformanceStatsProto.PERMANENT_LOCKOUT, crypto.permanentLockout);
Joe Onorato1754d742016-11-21 17:51:35 -08001402 proto.end(countsToken);
1403 }
1404
1405 proto.end(userToken);
1406 }
1407 proto.flush();
1408 }
1409
Jim Millera75961472014-06-06 15:00:49 -07001410 @Override
1411 public void onStart() {
Jim Miller9f0753f2015-03-23 23:59:22 -07001412 publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
Fyodor Kupolove29a5a12016-12-16 16:14:17 -08001413 SystemServerInitThreadPool.get().submit(this::getFingerprintDaemon, TAG + ".onStart");
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -07001414 listenForUserSwitches();
Jim Millera75961472014-06-06 15:00:49 -07001415 }
1416
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001417 private void updateActiveGroup(int userId, String clientPackage) {
Jim Miller40e46452016-12-16 18:38:53 -08001418 IBiometricsFingerprint daemon = getFingerprintDaemon();
Jim Millerbcc100a2016-07-06 14:16:49 -07001419
Jim Millerbe675422015-05-11 20:45:25 -07001420 if (daemon != null) {
1421 try {
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001422 userId = getUserOrWorkProfileId(clientPackage, userId);
1423 if (userId != mCurrentUserId) {
Andreas Huber7fe20532018-01-22 11:26:44 -08001424 File baseDir;
1425 if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1
1426 && !SystemProperties.getBoolean(
1427 "ro.treble.supports_vendor_data", false)) {
1428 // TODO(b/72405644) remove the override when possible.
1429 baseDir = Environment.getUserSystemDirectory(userId);
1430 } else {
1431 baseDir = Environment.getDataVendorDeDirectory(userId);
1432 }
1433
1434 File fpDir = new File(baseDir, FP_DATA_DIR);
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001435 if (!fpDir.exists()) {
1436 if (!fpDir.mkdir()) {
1437 Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath());
1438 return;
1439 }
1440 // Calling mkdir() from this process will create a directory with our
1441 // permissions (inherited from the containing dir). This command fixes
1442 // the label.
1443 if (!SELinux.restorecon(fpDir)) {
1444 Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
1445 return;
1446 }
Jim Millerbe675422015-05-11 20:45:25 -07001447 }
Andreas Huber7fe20532018-01-22 11:26:44 -08001448
Jim Miller40e46452016-12-16 18:38:53 -08001449 daemon.setActiveGroup(userId, fpDir.getAbsolutePath());
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001450 mCurrentUserId = userId;
Jim Millerbe675422015-05-11 20:45:25 -07001451 }
Charles He29b3a8a2017-05-04 16:02:38 +01001452 mAuthenticatorIds.put(userId,
1453 hasEnrolledFingerprints(userId) ? daemon.getAuthenticatorId() : 0L);
Jim Millerbe675422015-05-11 20:45:25 -07001454 } catch (RemoteException e) {
1455 Slog.e(TAG, "Failed to setActiveGroup():", e);
1456 }
Jim Millerdbe780f2015-05-18 13:55:00 -07001457 }
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -07001458 }
1459
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001460 /**
1461 * @param clientPackage the package of the caller
1462 * @return the profile id
1463 */
1464 private int getUserOrWorkProfileId(String clientPackage, int userId) {
1465 if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
1466 return userId;
1467 }
1468 return getEffectiveUserId(userId);
1469 }
1470
1471 /**
1472 * @param userId
1473 * @return true if this is a work profile
1474 */
1475 private boolean isWorkProfile(int userId) {
Charles Heda88f0e2017-02-02 18:29:13 +00001476 UserInfo userInfo = null;
1477 final long token = Binder.clearCallingIdentity();
1478 try {
1479 userInfo = mUserManager.getUserInfo(userId);
1480 } finally {
1481 Binder.restoreCallingIdentity(token);
1482 }
1483 return userInfo != null && userInfo.isManagedProfile();
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001484 }
1485
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -07001486 private void listenForUserSwitches() {
1487 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001488 ActivityManager.getService().registerUserSwitchObserver(
Fyodor Kupolov6005b3f2015-11-23 17:41:50 -08001489 new SynchronousUserSwitchObserver() {
Jim Millerbe675422015-05-11 20:45:25 -07001490 @Override
Fyodor Kupolov6005b3f2015-11-23 17:41:50 -08001491 public void onUserSwitching(int newUserId) throws RemoteException {
Jim Millerbe675422015-05-11 20:45:25 -07001492 mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
1493 .sendToTarget();
1494 }
Fyodor Kupolov0b77ef92016-06-20 17:16:52 -07001495 }, TAG);
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -07001496 } catch (RemoteException e) {
1497 Slog.w(TAG, "Failed to listen for user switching event" ,e);
1498 }
1499 }
Jim Millerbe675422015-05-11 20:45:25 -07001500
Jim Millerd0063102016-06-28 16:43:57 -07001501 /***
1502 * @param opPackageName the name of the calling package
Charles Heda88f0e2017-02-02 18:29:13 +00001503 * @return authenticator id for the calling user
Jim Millerd0063102016-06-28 16:43:57 -07001504 */
Jim Millercb2ce6f2016-04-13 20:28:18 -07001505 public long getAuthenticatorId(String opPackageName) {
Charles Heda88f0e2017-02-02 18:29:13 +00001506 final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
Charles He29b3a8a2017-05-04 16:02:38 +01001507 return mAuthenticatorIds.getOrDefault(userId, 0L);
Jim Millerbe675422015-05-11 20:45:25 -07001508 }
Jim Millera75961472014-06-06 15:00:49 -07001509}