blob: e9d684a6154e4102ef99ed2b254d2a4ca770418f [file] [log] [blame]
Jim Millera75961472014-06-06 15:00:49 -07001/**
2 * 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
Chris Wrenc510ad52015-08-14 15:43:15 -040019import android.Manifest;
Sasha Levitskiy80db9ba2015-05-08 14:31:48 -070020import android.app.ActivityManager;
Jim Miller975f1452015-08-31 18:18:22 -070021import android.app.ActivityManager.RunningAppProcessInfo;
Clara Bayarrid1f722d2016-01-07 14:17:39 +000022import android.app.trust.TrustManager;
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -070023import android.app.ActivityManagerNative;
Jorim Jaggi5e354222015-09-04 14:17:58 -070024import android.app.AlarmManager;
Svetoslav4af76a52015-04-29 15:29:46 -070025import android.app.AppOpsManager;
Jorim Jaggi5e354222015-09-04 14:17:58 -070026import android.app.PendingIntent;
Fyodor Kupolov6005b3f2015-11-23 17:41:50 -080027import android.app.SynchronousUserSwitchObserver;
Jim Miller975f1452015-08-31 18:18:22 -070028import android.content.ComponentName;
Jorim Jaggi5e354222015-09-04 14:17:58 -070029import android.content.BroadcastReceiver;
Jim Millera75961472014-06-06 15:00:49 -070030import android.content.Context;
Jorim Jaggi5e354222015-09-04 14:17:58 -070031import android.content.Intent;
32import android.content.IntentFilter;
Jim Millerf501b582015-06-03 16:36:31 -070033import android.content.pm.PackageManager;
Jim Millercb7d9e92015-06-16 15:05:48 -070034import android.content.pm.UserInfo;
Jorim Jaggi3a464782015-08-28 16:59:13 -070035import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
Svetoslav4af76a52015-04-29 15:29:46 -070036import android.os.Binder;
Jorim Jaggi3a464782015-08-28 16:59:13 -070037import android.os.DeadObjectException;
Sasha Levitskiy80db9ba2015-05-08 14:31:48 -070038import android.os.Environment;
Jim Millera75961472014-06-06 15:00:49 -070039import android.os.Handler;
40import android.os.IBinder;
Jim Millerdca15d22015-06-16 20:55:13 -070041import android.os.PowerManager;
Jim Millera75961472014-06-06 15:00:49 -070042import android.os.RemoteException;
Jim Miller16ef71f2015-05-21 17:02:21 -070043import android.os.SELinux;
Jim Millerbe675422015-05-11 20:45:25 -070044import android.os.ServiceManager;
Jim Millerdca15d22015-06-16 20:55:13 -070045import android.os.SystemClock;
Jim Miller599ef0e2015-06-15 20:39:44 -070046import android.os.UserHandle;
Jim Millercb7d9e92015-06-16 15:05:48 -070047import android.os.UserManager;
Jim Millera75961472014-06-06 15:00:49 -070048import android.util.Slog;
49
Chris Wrenc510ad52015-08-14 15:43:15 -040050import com.android.internal.logging.MetricsLogger;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050051import com.android.internal.logging.MetricsProto.MetricsEvent;
Jim Millera75961472014-06-06 15:00:49 -070052import com.android.server.SystemService;
53
Chris Wrenc510ad52015-08-14 15:43:15 -040054import org.json.JSONArray;
55import org.json.JSONException;
56import org.json.JSONObject;
57
Jim Millerebbf2052015-03-31 17:24:34 -070058import android.hardware.fingerprint.Fingerprint;
59import android.hardware.fingerprint.FingerprintManager;
60import android.hardware.fingerprint.IFingerprintService;
Jim Millerbe675422015-05-11 20:45:25 -070061import android.hardware.fingerprint.IFingerprintDaemon;
62import android.hardware.fingerprint.IFingerprintDaemonCallback;
Jim Millerebbf2052015-03-31 17:24:34 -070063import android.hardware.fingerprint.IFingerprintServiceReceiver;
Jim Miller9f0753f2015-03-23 23:59:22 -070064
Clara Bayarri33fd3cf2016-02-19 16:54:49 +000065import static android.Manifest.permission.INTERACT_ACROSS_USERS;
Jim Miller975f1452015-08-31 18:18:22 -070066import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
Jim Millerba67aee2015-02-20 16:21:26 -080067import static android.Manifest.permission.MANAGE_FINGERPRINT;
Jim Millere0507bb2015-08-12 20:30:34 -070068import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
Jim Millerba67aee2015-02-20 16:21:26 -080069import static android.Manifest.permission.USE_FINGERPRINT;
Jim Millera75961472014-06-06 15:00:49 -070070
Sasha Levitskiy80db9ba2015-05-08 14:31:48 -070071import java.io.File;
Chris Wrenc510ad52015-08-14 15:43:15 -040072import java.io.FileDescriptor;
73import java.io.PrintWriter;
Jorim Jaggi3a464782015-08-28 16:59:13 -070074import java.util.ArrayList;
Jim Millerfe6439f2015-04-11 18:07:57 -070075import java.util.Arrays;
Svetoslav4af76a52015-04-29 15:29:46 -070076import java.util.Collections;
Jim Miller9f0753f2015-03-23 23:59:22 -070077import java.util.List;
Jim Miller16ef71f2015-05-21 17:02:21 -070078import java.util.NoSuchElementException;
Jim Millera75961472014-06-06 15:00:49 -070079
80/**
81 * A service to manage multiple clients that want to access the fingerprint HAL API.
82 * The service is responsible for maintaining a list of clients and dispatching all
83 * fingerprint -related events.
84 *
85 * @hide
86 */
Jim Millerbe675422015-05-11 20:45:25 -070087public class FingerprintService extends SystemService implements IBinder.DeathRecipient {
Jim Millerce7eb6d2015-04-03 19:29:13 -070088 private static final String TAG = "FingerprintService";
Jim Millera75961472014-06-06 15:00:49 -070089 private static final boolean DEBUG = true;
Jim Millerbe675422015-05-11 20:45:25 -070090 private static final String FP_DATA_DIR = "fpdata";
91 private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon";
92 private static final int MSG_USER_SWITCHING = 10;
93 private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
Jorim Jaggi5e354222015-09-04 14:17:58 -070094 private static final String ACTION_LOCKOUT_RESET =
95 "com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
Jim Millerbe675422015-05-11 20:45:25 -070096
Jim Millerfe6439f2015-04-11 18:07:57 -070097 private ClientMonitor mAuthClient = null;
98 private ClientMonitor mEnrollClient = null;
99 private ClientMonitor mRemoveClient = null;
Jorim Jaggi3a464782015-08-28 16:59:13 -0700100 private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
101 new ArrayList<>();
Svetoslav4af76a52015-04-29 15:29:46 -0700102 private final AppOpsManager mAppOps;
103
Jim Milleraf281ca2015-04-20 19:04:21 -0700104 private static final long MS_PER_SEC = 1000;
105 private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
106 private static final int MAX_FAILED_ATTEMPTS = 5;
Jim Millerdca15d22015-06-16 20:55:13 -0700107 private static final int FINGERPRINT_ACQUIRED_GOOD = 0;
Jim Miller975f1452015-08-31 18:18:22 -0700108 private final String mKeyguardPackage;
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000109 private int mCurrentUserId = UserHandle.USER_CURRENT;
Jim Millerce7eb6d2015-04-03 19:29:13 -0700110
Jim Millera75961472014-06-06 15:00:49 -0700111 Handler mHandler = new Handler() {
Jim Miller80a776e2015-07-15 18:57:14 -0700112 @Override
Jim Millera75961472014-06-06 15:00:49 -0700113 public void handleMessage(android.os.Message msg) {
114 switch (msg.what) {
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -0700115 case MSG_USER_SWITCHING:
116 handleUserSwitching(msg.arg1);
117 break;
118
Jim Millera75961472014-06-06 15:00:49 -0700119 default:
120 Slog.w(TAG, "Unknown message:" + msg.what);
121 }
122 }
123 };
Jim Millerbe675422015-05-11 20:45:25 -0700124
Jorim Jaggiee77ceb2015-05-12 15:00:12 -0700125 private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance();
Jim Millerbe675422015-05-11 20:45:25 -0700126 private Context mContext;
127 private long mHalDeviceId;
128 private int mFailedAttempts;
129 private IFingerprintDaemon mDaemon;
Jorim Jaggi5e354222015-09-04 14:17:58 -0700130 private final PowerManager mPowerManager;
131 private final AlarmManager mAlarmManager;
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000132 private final UserManager mUserManager;
Jim Millerbe675422015-05-11 20:45:25 -0700133
Jorim Jaggi5e354222015-09-04 14:17:58 -0700134 private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
135 @Override
136 public void onReceive(Context context, Intent intent) {
137 if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
138 resetFailedAttempts();
139 }
140 }
141 };
142
143 private final Runnable mResetFailedAttemptsRunnable = new Runnable() {
Jim Millerfe6439f2015-04-11 18:07:57 -0700144 @Override
145 public void run() {
146 resetFailedAttempts();
147 }
148 };
Jim Millera75961472014-06-06 15:00:49 -0700149
Jim Millera75961472014-06-06 15:00:49 -0700150 public FingerprintService(Context context) {
151 super(context);
152 mContext = context;
Jim Miller975f1452015-08-31 18:18:22 -0700153 mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
154 com.android.internal.R.string.config_keyguardComponent)).getPackageName();
Svetoslav4af76a52015-04-29 15:29:46 -0700155 mAppOps = context.getSystemService(AppOpsManager.class);
Jorim Jaggi5e354222015-09-04 14:17:58 -0700156 mPowerManager = mContext.getSystemService(PowerManager.class);
157 mAlarmManager = mContext.getSystemService(AlarmManager.class);
158 mContext.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
159 RESET_FINGERPRINT_LOCKOUT, null /* handler */);
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000160 mUserManager = UserManager.get(mContext);
Jim Millera75961472014-06-06 15:00:49 -0700161 }
162
Jim Millerbe675422015-05-11 20:45:25 -0700163 @Override
164 public void binderDied() {
165 Slog.v(TAG, "fingerprintd died");
166 mDaemon = null;
Jim Miller8b3c25a2015-08-28 17:29:49 -0700167 handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
Jim Millera75961472014-06-06 15:00:49 -0700168 }
169
Jim Millerbe675422015-05-11 20:45:25 -0700170 public IFingerprintDaemon getFingerprintDaemon() {
171 if (mDaemon == null) {
172 mDaemon = IFingerprintDaemon.Stub.asInterface(ServiceManager.getService(FINGERPRINTD));
Jim Miller091f0e52015-07-21 16:58:46 -0700173 if (mDaemon != null) {
Jim Millerbe675422015-05-11 20:45:25 -0700174 try {
175 mDaemon.asBinder().linkToDeath(this, 0);
Jim Miller091f0e52015-07-21 16:58:46 -0700176 mDaemon.init(mDaemonCallback);
177 mHalDeviceId = mDaemon.openHal();
178 if (mHalDeviceId != 0) {
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000179 updateActiveGroup(ActivityManager.getCurrentUser(), null);
Jim Miller091f0e52015-07-21 16:58:46 -0700180 } else {
181 Slog.w(TAG, "Failed to open Fingerprint HAL!");
182 mDaemon = null;
183 }
184 } catch (RemoteException e) {
185 Slog.e(TAG, "Failed to open fingeprintd HAL", e);
186 mDaemon = null; // try again later!
Jim Millerbe675422015-05-11 20:45:25 -0700187 }
Jim Miller091f0e52015-07-21 16:58:46 -0700188 } else {
189 Slog.w(TAG, "fingerprint service not available");
Jim Millera75961472014-06-06 15:00:49 -0700190 }
Jim Millerce7eb6d2015-04-03 19:29:13 -0700191 }
Jim Millerbe675422015-05-11 20:45:25 -0700192 return mDaemon;
193 }
194
Jim Miller8b3c25a2015-08-28 17:29:49 -0700195 protected void handleEnumerate(long deviceId, int[] fingerIds, int[] groupIds) {
Jim Millerbe675422015-05-11 20:45:25 -0700196 if (fingerIds.length != groupIds.length) {
197 Slog.w(TAG, "fingerIds and groupIds differ in length: f[]="
Andreas Gampee6748ce2015-12-11 18:00:38 -0800198 + Arrays.toString(fingerIds) + ", g[]=" + Arrays.toString(groupIds));
Jim Millerbe675422015-05-11 20:45:25 -0700199 return;
200 }
201 if (DEBUG) Slog.w(TAG, "Enumerate: f[]=" + fingerIds + ", g[]=" + groupIds);
202 // TODO: update fingerprint/name pairs
203 }
204
Jim Miller8b3c25a2015-08-28 17:29:49 -0700205 protected void handleRemoved(long deviceId, int fingerId, int groupId) {
Jim Millerbe675422015-05-11 20:45:25 -0700206 final ClientMonitor client = mRemoveClient;
207 if (fingerId != 0) {
Jim Millerbe675422015-05-11 20:45:25 -0700208 removeTemplateForUser(mRemoveClient, fingerId);
209 }
210 if (client != null && client.sendRemoved(fingerId, groupId)) {
211 removeClient(mRemoveClient);
212 }
213 }
214
Jim Miller8b3c25a2015-08-28 17:29:49 -0700215 protected void handleError(long deviceId, int error) {
Jim Millerbe675422015-05-11 20:45:25 -0700216 if (mEnrollClient != null) {
217 final IBinder token = mEnrollClient.token;
218 if (mEnrollClient.sendError(error)) {
219 stopEnrollment(token, false);
220 }
221 } else if (mAuthClient != null) {
222 final IBinder token = mAuthClient.token;
223 if (mAuthClient.sendError(error)) {
224 stopAuthentication(token, false);
225 }
226 } else if (mRemoveClient != null) {
227 if (mRemoveClient.sendError(error)) removeClient(mRemoveClient);
228 }
229 }
230
Jim Miller8b3c25a2015-08-28 17:29:49 -0700231 protected void handleAuthenticated(long deviceId, int fingerId, int groupId) {
Jim Millerce7eb6d2015-04-03 19:29:13 -0700232 if (mAuthClient != null) {
Jim Millerfe6439f2015-04-11 18:07:57 -0700233 final IBinder token = mAuthClient.token;
Jim Millerbe675422015-05-11 20:45:25 -0700234 if (mAuthClient.sendAuthenticated(fingerId, groupId)) {
Jim Miller13041372015-04-16 14:48:55 -0700235 stopAuthentication(token, false);
236 removeClient(mAuthClient);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700237 }
238 }
Jim Millerbe675422015-05-11 20:45:25 -0700239 }
240
Jim Miller8b3c25a2015-08-28 17:29:49 -0700241 protected void handleAcquired(long deviceId, int acquiredInfo) {
Jim Millerbe675422015-05-11 20:45:25 -0700242 if (mEnrollClient != null) {
243 if (mEnrollClient.sendAcquired(acquiredInfo)) {
244 removeClient(mEnrollClient);
245 }
246 } else if (mAuthClient != null) {
247 if (mAuthClient.sendAcquired(acquiredInfo)) {
248 removeClient(mAuthClient);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700249 }
250 }
Jim Millerdca15d22015-06-16 20:55:13 -0700251 }
Jim Millerbe675422015-05-11 20:45:25 -0700252
Jim Miller8b3c25a2015-08-28 17:29:49 -0700253 protected void handleEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
Jim Millerbe675422015-05-11 20:45:25 -0700254 if (mEnrollClient != null) {
255 if (mEnrollClient.sendEnrollResult(fingerId, groupId, remaining)) {
Jim Miller13041372015-04-16 14:48:55 -0700256 if (remaining == 0) {
Jim Millerbe675422015-05-11 20:45:25 -0700257 addTemplateForUser(mEnrollClient, fingerId);
258 removeClient(mEnrollClient);
Jim Millera75961472014-06-06 15:00:49 -0700259 }
Jim Millerbe675422015-05-11 20:45:25 -0700260 }
Jim Millerce7eb6d2015-04-03 19:29:13 -0700261 }
Jim Millerce7eb6d2015-04-03 19:29:13 -0700262 }
263
Jim Miller8b3c25a2015-08-28 17:29:49 -0700264 private void userActivity() {
265 long now = SystemClock.uptimeMillis();
266 mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
267 }
268
269 void handleUserSwitching(int userId) {
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000270 updateActiveGroup(userId, null);
Jim Miller8b3c25a2015-08-28 17:29:49 -0700271 }
272
Jim Millerbe675422015-05-11 20:45:25 -0700273 private void removeClient(ClientMonitor client) {
274 if (client == null) return;
275 client.destroy();
276 if (client == mAuthClient) {
Jim Millerfe6439f2015-04-11 18:07:57 -0700277 mAuthClient = null;
Jim Millerbe675422015-05-11 20:45:25 -0700278 } else if (client == mEnrollClient) {
Jim Millerfe6439f2015-04-11 18:07:57 -0700279 mEnrollClient = null;
Jim Millerbe675422015-05-11 20:45:25 -0700280 } else if (client == mRemoveClient) {
Jim Millerfe6439f2015-04-11 18:07:57 -0700281 mRemoveClient = null;
282 }
283 }
284
285 private boolean inLockoutMode() {
Jim Miller73633dd2015-09-02 15:35:33 -0700286 return mFailedAttempts >= MAX_FAILED_ATTEMPTS;
Jim Millerfe6439f2015-04-11 18:07:57 -0700287 }
288
Jorim Jaggi5e354222015-09-04 14:17:58 -0700289 private void scheduleLockoutReset() {
290 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
291 SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS, getLockoutResetIntent());
292 }
293
294 private void cancelLockoutReset() {
295 mAlarmManager.cancel(getLockoutResetIntent());
296 }
297
298 private PendingIntent getLockoutResetIntent() {
299 return PendingIntent.getBroadcast(mContext, 0,
300 new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT);
301 }
302
Jim Millerfe6439f2015-04-11 18:07:57 -0700303 private void resetFailedAttempts() {
Jim Miller13041372015-04-16 14:48:55 -0700304 if (DEBUG && inLockoutMode()) {
305 Slog.v(TAG, "Reset fingerprint lockout");
306 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700307 mFailedAttempts = 0;
Jorim Jaggi5e354222015-09-04 14:17:58 -0700308 // If we're asked to reset failed attempts externally (i.e. from Keyguard), the alarm might
309 // still be pending; remove it.
310 cancelLockoutReset();
Jorim Jaggi3a464782015-08-28 16:59:13 -0700311 notifyLockoutResetMonitors();
Jim Millerfe6439f2015-04-11 18:07:57 -0700312 }
313
314 private boolean handleFailedAttempt(ClientMonitor clientMonitor) {
315 mFailedAttempts++;
Jim Miller73633dd2015-09-02 15:35:33 -0700316 if (inLockoutMode()) {
Jim Millerfe6439f2015-04-11 18:07:57 -0700317 // Failing multiple times will continue to push out the lockout time.
Jorim Jaggi5e354222015-09-04 14:17:58 -0700318 scheduleLockoutReset();
Jim Millerfe6439f2015-04-11 18:07:57 -0700319 if (clientMonitor != null
320 && !clientMonitor.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
321 Slog.w(TAG, "Cannot send lockout message to client");
322 }
323 return true;
324 }
325 return false;
326 }
327
Jorim Jaggiee77ceb2015-05-12 15:00:12 -0700328 private void removeTemplateForUser(ClientMonitor clientMonitor, int fingerId) {
329 mFingerprintUtils.removeFingerprintIdForUser(mContext, fingerId, clientMonitor.userId);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700330 }
331
Jorim Jaggiee77ceb2015-05-12 15:00:12 -0700332 private void addTemplateForUser(ClientMonitor clientMonitor, int fingerId) {
333 mFingerprintUtils.addFingerprintForUser(mContext, fingerId, clientMonitor.userId);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700334 }
335
Jim Millerfe6439f2015-04-11 18:07:57 -0700336 void startEnrollment(IBinder token, byte[] cryptoToken, int groupId,
Jim Millerf501b582015-06-03 16:36:31 -0700337 IFingerprintServiceReceiver receiver, int flags, boolean restricted) {
Jim Millerbe675422015-05-11 20:45:25 -0700338 IFingerprintDaemon daemon = getFingerprintDaemon();
339 if (daemon == null) {
340 Slog.w(TAG, "enroll: no fingeprintd!");
341 return;
342 }
Jim Miller80a776e2015-07-15 18:57:14 -0700343 stopPendingOperations(true);
Jim Miller1adb4a72015-09-14 18:58:08 -0700344 mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted, token.toString());
Jim Millerce7eb6d2015-04-03 19:29:13 -0700345 final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
Jim Millerbe675422015-05-11 20:45:25 -0700346 try {
347 final int result = daemon.enroll(cryptoToken, groupId, timeout);
348 if (result != 0) {
349 Slog.w(TAG, "startEnroll failed, result=" + result);
Jim Miller8b3c25a2015-08-28 17:29:49 -0700350 handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
Jim Millerbe675422015-05-11 20:45:25 -0700351 }
352 } catch (RemoteException e) {
353 Slog.e(TAG, "startEnroll failed", e);
Jim Millera75961472014-06-06 15:00:49 -0700354 }
355 }
356
Jim Millerce7eb6d2015-04-03 19:29:13 -0700357 public long startPreEnroll(IBinder token) {
Jim Millerbe675422015-05-11 20:45:25 -0700358 IFingerprintDaemon daemon = getFingerprintDaemon();
359 if (daemon == null) {
360 Slog.w(TAG, "startPreEnroll: no fingeprintd!");
361 return 0;
362 }
363 try {
364 return daemon.preEnroll();
365 } catch (RemoteException e) {
366 Slog.e(TAG, "startPreEnroll failed", e);
367 }
368 return 0;
Jim Millerce7eb6d2015-04-03 19:29:13 -0700369 }
370
Sasha Levitskiye0943cf2015-07-08 13:22:20 -0700371 public int startPostEnroll(IBinder token) {
372 IFingerprintDaemon daemon = getFingerprintDaemon();
373 if (daemon == null) {
374 Slog.w(TAG, "startPostEnroll: no fingeprintd!");
375 return 0;
376 }
377 try {
378 return daemon.postEnroll();
379 } catch (RemoteException e) {
380 Slog.e(TAG, "startPostEnroll failed", e);
381 }
382 return 0;
383 }
384
Jim Miller80a776e2015-07-15 18:57:14 -0700385 private void stopPendingOperations(boolean initiatedByClient) {
Jim Millerce7eb6d2015-04-03 19:29:13 -0700386 if (mEnrollClient != null) {
Jim Miller80a776e2015-07-15 18:57:14 -0700387 stopEnrollment(mEnrollClient.token, initiatedByClient);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700388 }
389 if (mAuthClient != null) {
Jim Miller80a776e2015-07-15 18:57:14 -0700390 stopAuthentication(mAuthClient.token, initiatedByClient);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700391 }
392 // mRemoveClient is allowed to continue
393 }
394
Jim Miller80a776e2015-07-15 18:57:14 -0700395 /**
396 * Stop enrollment in progress and inform client if they initiated it.
397 *
398 * @param token token for client
399 * @param initiatedByClient if this call is the result of client action (e.g. calling cancel)
400 */
401 void stopEnrollment(IBinder token, boolean initiatedByClient) {
Jim Millerbe675422015-05-11 20:45:25 -0700402 IFingerprintDaemon daemon = getFingerprintDaemon();
403 if (daemon == null) {
404 Slog.w(TAG, "stopEnrollment: no fingeprintd!");
405 return;
406 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700407 final ClientMonitor client = mEnrollClient;
408 if (client == null || client.token != token) return;
Jim Miller80a776e2015-07-15 18:57:14 -0700409 if (initiatedByClient) {
410 try {
411 int result = daemon.cancelEnrollment();
412 if (result != 0) {
413 Slog.w(TAG, "startEnrollCancel failed, result = " + result);
414 }
415 } catch (RemoteException e) {
416 Slog.e(TAG, "stopEnrollment failed", e);
Jim Millerbe675422015-05-11 20:45:25 -0700417 }
Jim Miller13041372015-04-16 14:48:55 -0700418 client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
419 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700420 removeClient(mEnrollClient);
Jim Miller9f0753f2015-03-23 23:59:22 -0700421 }
422
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000423 void startAuthentication(IBinder token, long opId, int realUserId, int groupId,
Jim Miller1adb4a72015-09-14 18:58:08 -0700424 IFingerprintServiceReceiver receiver, int flags, boolean restricted,
425 String opPackageName) {
Jim Millerbe675422015-05-11 20:45:25 -0700426 IFingerprintDaemon daemon = getFingerprintDaemon();
427 if (daemon == null) {
428 Slog.w(TAG, "startAuthentication: no fingeprintd!");
429 return;
430 }
Jim Miller80a776e2015-07-15 18:57:14 -0700431 stopPendingOperations(true);
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000432 updateActiveGroup(groupId, opPackageName);
Jim Miller1adb4a72015-09-14 18:58:08 -0700433 mAuthClient = new ClientMonitor(token, receiver, groupId, restricted, opPackageName);
Jim Millerfe6439f2015-04-11 18:07:57 -0700434 if (inLockoutMode()) {
435 Slog.v(TAG, "In lockout mode; disallowing authentication");
436 if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
437 Slog.w(TAG, "Cannot send timeout message to client");
438 }
439 mAuthClient = null;
440 return;
441 }
Jim Millerbe675422015-05-11 20:45:25 -0700442 try {
443 final int result = daemon.authenticate(opId, groupId);
444 if (result != 0) {
445 Slog.w(TAG, "startAuthentication failed, result=" + result);
Jim Miller8b3c25a2015-08-28 17:29:49 -0700446 handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
Jim Millerbe675422015-05-11 20:45:25 -0700447 }
448 } catch (RemoteException e) {
449 Slog.e(TAG, "startAuthentication failed", e);
Jim Millera75961472014-06-06 15:00:49 -0700450 }
451 }
452
Jim Miller80a776e2015-07-15 18:57:14 -0700453 /**
454 * Stop authentication in progress and inform client if they initiated it.
455 *
456 * @param token token for client
457 * @param initiatedByClient if this call is the result of client action (e.g. calling cancel)
458 */
459 void stopAuthentication(IBinder token, boolean initiatedByClient) {
Jim Millerbe675422015-05-11 20:45:25 -0700460 IFingerprintDaemon daemon = getFingerprintDaemon();
461 if (daemon == null) {
462 Slog.w(TAG, "stopAuthentication: no fingeprintd!");
463 return;
464 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700465 final ClientMonitor client = mAuthClient;
466 if (client == null || client.token != token) return;
Jim Miller80a776e2015-07-15 18:57:14 -0700467 if (initiatedByClient) {
468 try {
469 int result = daemon.cancelAuthentication();
470 if (result != 0) {
471 Slog.w(TAG, "stopAuthentication failed, result=" + result);
472 }
473 } catch (RemoteException e) {
474 Slog.e(TAG, "stopAuthentication failed", e);
Jim Millerbe675422015-05-11 20:45:25 -0700475 }
Jim Miller13041372015-04-16 14:48:55 -0700476 client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
477 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700478 removeClient(mAuthClient);
Jim Millera75961472014-06-06 15:00:49 -0700479 }
480
Jim Millerce7eb6d2015-04-03 19:29:13 -0700481 void startRemove(IBinder token, int fingerId, int userId,
Jim Millerf501b582015-06-03 16:36:31 -0700482 IFingerprintServiceReceiver receiver, boolean restricted) {
Jim Millerbe675422015-05-11 20:45:25 -0700483 IFingerprintDaemon daemon = getFingerprintDaemon();
484 if (daemon == null) {
485 Slog.w(TAG, "startRemove: no fingeprintd!");
486 return;
487 }
Jim Millerf501b582015-06-03 16:36:31 -0700488
Jim Miller827afda2015-08-21 18:45:15 -0700489 stopPendingOperations(true);
Jim Miller1adb4a72015-09-14 18:58:08 -0700490 mRemoveClient = new ClientMonitor(token, receiver, userId, restricted, token.toString());
Jim Millerce7eb6d2015-04-03 19:29:13 -0700491 // The fingerprint template ids will be removed when we get confirmation from the HAL
Jim Millerbe675422015-05-11 20:45:25 -0700492 try {
493 final int result = daemon.remove(fingerId, userId);
494 if (result != 0) {
495 Slog.w(TAG, "startRemove with id = " + fingerId + " failed, result=" + result);
Jim Miller8b3c25a2015-08-28 17:29:49 -0700496 handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
Jim Millerbe675422015-05-11 20:45:25 -0700497 }
498 } catch (RemoteException e) {
499 Slog.e(TAG, "startRemove failed", e);
Jim Millera75961472014-06-06 15:00:49 -0700500 }
501 }
502
Jim Miller599ef0e2015-06-15 20:39:44 -0700503 public List<Fingerprint> getEnrolledFingerprints(int userId) {
504 return mFingerprintUtils.getFingerprintsForUser(mContext, userId);
Jim Miller9f0753f2015-03-23 23:59:22 -0700505 }
506
Jim Miller599ef0e2015-06-15 20:39:44 -0700507 public boolean hasEnrolledFingerprints(int userId) {
Clara Bayarri33fd3cf2016-02-19 16:54:49 +0000508 if (userId != Binder.getCallingUid()) {
509 checkPermission(INTERACT_ACROSS_USERS);
510 }
Jim Miller599ef0e2015-06-15 20:39:44 -0700511 return mFingerprintUtils.getFingerprintsForUser(mContext, userId).size() > 0;
Jorim Jaggi2aad7ee2015-04-14 15:25:06 -0700512 }
513
Jim Millerf501b582015-06-03 16:36:31 -0700514 boolean hasPermission(String permission) {
515 return getContext().checkCallingOrSelfPermission(permission)
516 == PackageManager.PERMISSION_GRANTED;
517 }
518
Jim Millerba67aee2015-02-20 16:21:26 -0800519 void checkPermission(String permission) {
Jim Miller9f0753f2015-03-23 23:59:22 -0700520 getContext().enforceCallingOrSelfPermission(permission,
521 "Must have " + permission + " permission.");
Jim Millera75961472014-06-06 15:00:49 -0700522 }
523
Andres Morales494d6e92015-08-06 15:01:41 -0700524 int getEffectiveUserId(int userId) {
525 UserManager um = UserManager.get(mContext);
526 if (um != null) {
527 final long callingIdentity = Binder.clearCallingIdentity();
528 userId = um.getCredentialOwnerProfile(userId);
529 Binder.restoreCallingIdentity(callingIdentity);
530 } else {
531 Slog.e(TAG, "Unable to acquire UserManager");
532 }
533 return userId;
534 }
535
Jim Millercb7d9e92015-06-16 15:05:48 -0700536 boolean isCurrentUserOrProfile(int userId) {
537 UserManager um = UserManager.get(mContext);
538
539 // Allow current user or profiles of the current user...
540 List<UserInfo> profiles = um.getEnabledProfiles(userId);
541 final int n = profiles.size();
542 for (int i = 0; i < n; i++) {
543 if (profiles.get(i).id == userId) {
544 return true;
545 }
546 }
547 return false;
548 }
549
Jim Miller975f1452015-08-31 18:18:22 -0700550 private boolean isForegroundActivity(int uid, int pid) {
551 try {
552 List<RunningAppProcessInfo> procs =
553 ActivityManagerNative.getDefault().getRunningAppProcesses();
554 int N = procs.size();
555 for (int i = 0; i < N; i++) {
556 RunningAppProcessInfo proc = procs.get(i);
557 if (proc.pid == pid && proc.uid == uid
558 && proc.importance == IMPORTANCE_FOREGROUND) {
559 return true;
560 }
561 }
562 } catch (RemoteException e) {
563 Slog.w(TAG, "am.getRunningAppProcesses() failed");
564 }
565 return false;
566 }
567
568 /**
569 * @param opPackageName name of package for caller
570 * @param foregroundOnly only allow this call while app is in the foreground
571 * @return true if caller can use fingerprint API
572 */
573 private boolean canUseFingerprint(String opPackageName, boolean foregroundOnly) {
Svetoslav4af76a52015-04-29 15:29:46 -0700574 checkPermission(USE_FINGERPRINT);
Jim Miller975f1452015-08-31 18:18:22 -0700575 final int uid = Binder.getCallingUid();
576 final int pid = Binder.getCallingPid();
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000577 if (isKeyguard(opPackageName)) {
Jim Miller975f1452015-08-31 18:18:22 -0700578 return true; // Keyguard is always allowed
579 }
580 if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
581 Slog.w(TAG,"Rejecting " + opPackageName + " ; not a current user or profile");
582 return false;
583 }
584 if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
585 != AppOpsManager.MODE_ALLOWED) {
Jim Miller1adb4a72015-09-14 18:58:08 -0700586 Slog.w(TAG, "Rejecting " + opPackageName + " ; permission denied");
Jim Miller975f1452015-08-31 18:18:22 -0700587 return false;
588 }
589 if (foregroundOnly && !isForegroundActivity(uid, pid)) {
Jim Miller1adb4a72015-09-14 18:58:08 -0700590 Slog.w(TAG, "Rejecting " + opPackageName + " ; not in foreground");
Jim Miller975f1452015-08-31 18:18:22 -0700591 return false;
592 }
593 return true;
Svetoslav4af76a52015-04-29 15:29:46 -0700594 }
595
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000596 /**
597 * @param clientPackage
598 * @return true if this is keyguard package
599 */
600 private boolean isKeyguard(String clientPackage) {
601 return mKeyguardPackage.equals(clientPackage);
602 }
603
Jorim Jaggi3a464782015-08-28 16:59:13 -0700604 private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
605 if (!mLockoutMonitors.contains(monitor)) {
606 mLockoutMonitors.add(monitor);
607 }
608 }
609
610 private void removeLockoutResetCallback(
611 FingerprintServiceLockoutResetMonitor monitor) {
612 mLockoutMonitors.remove(monitor);
613 }
614
615 private void notifyLockoutResetMonitors() {
616 for (int i = 0; i < mLockoutMonitors.size(); i++) {
617 mLockoutMonitors.get(i).sendLockoutReset();
618 }
619 }
620
Jim Millerfe6439f2015-04-11 18:07:57 -0700621 private class ClientMonitor implements IBinder.DeathRecipient {
Jim Millerce7eb6d2015-04-03 19:29:13 -0700622 IBinder token;
Jim Millerb21e1b22015-04-24 16:59:11 -0700623 IFingerprintServiceReceiver receiver;
Jim Millerfe6439f2015-04-11 18:07:57 -0700624 int userId;
Jim Millerf501b582015-06-03 16:36:31 -0700625 boolean restricted; // True if client does not have MANAGE_FINGERPRINT permission
Jim Miller1adb4a72015-09-14 18:58:08 -0700626 String owner;
Jim Millerce7eb6d2015-04-03 19:29:13 -0700627
Jim Millerf501b582015-06-03 16:36:31 -0700628 public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId,
Jim Miller1adb4a72015-09-14 18:58:08 -0700629 boolean restricted, String owner) {
Jim Millerce7eb6d2015-04-03 19:29:13 -0700630 this.token = token;
Jim Millerb21e1b22015-04-24 16:59:11 -0700631 this.receiver = receiver;
Jim Millerfe6439f2015-04-11 18:07:57 -0700632 this.userId = userId;
Jim Millerf501b582015-06-03 16:36:31 -0700633 this.restricted = restricted;
Jim Miller1adb4a72015-09-14 18:58:08 -0700634 this.owner = owner; // name of the client that owns this - for debugging
Jim Millerfe6439f2015-04-11 18:07:57 -0700635 try {
636 token.linkToDeath(this, 0);
637 } catch (RemoteException e) {
638 Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
639 }
640 }
641
642 public void destroy() {
643 if (token != null) {
Jim Miller16ef71f2015-05-21 17:02:21 -0700644 try {
645 token.unlinkToDeath(this, 0);
646 } catch (NoSuchElementException e) {
647 // TODO: remove when duplicate call bug is found
648 Slog.e(TAG, "destroy(): " + this + ":", new Exception("here"));
649 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700650 token = null;
651 }
652 receiver = null;
653 }
654
Jim Miller80a776e2015-07-15 18:57:14 -0700655 @Override
Jim Millerfe6439f2015-04-11 18:07:57 -0700656 public void binderDied() {
657 token = null;
658 removeClient(this);
Jim Millerb21e1b22015-04-24 16:59:11 -0700659 receiver = null;
Jim Millerfe6439f2015-04-11 18:07:57 -0700660 }
661
Jim Miller80a776e2015-07-15 18:57:14 -0700662 @Override
Jim Millerfe6439f2015-04-11 18:07:57 -0700663 protected void finalize() throws Throwable {
664 try {
665 if (token != null) {
666 if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token);
667 removeClient(this);
668 }
669 } finally {
670 super.finalize();
671 }
672 }
673
Jim Miller13041372015-04-16 14:48:55 -0700674 /*
675 * @return true if we're done.
676 */
Jim Millerfe6439f2015-04-11 18:07:57 -0700677 private boolean sendRemoved(int fingerId, int groupId) {
Jim Millerb21e1b22015-04-24 16:59:11 -0700678 if (receiver == null) return true; // client not listening
Jim Miller13041372015-04-16 14:48:55 -0700679 try {
Jim Millerb21e1b22015-04-24 16:59:11 -0700680 receiver.onRemoved(mHalDeviceId, fingerId, groupId);
Jim Miller13041372015-04-16 14:48:55 -0700681 return fingerId == 0;
682 } catch (RemoteException e) {
683 Slog.w(TAG, "Failed to notify Removed:", e);
Jim Millerfe6439f2015-04-11 18:07:57 -0700684 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700685 return false;
686 }
687
Jim Miller13041372015-04-16 14:48:55 -0700688 /*
689 * @return true if we're done.
690 */
Jim Millerfe6439f2015-04-11 18:07:57 -0700691 private boolean sendEnrollResult(int fpId, int groupId, int remaining) {
Jim Millerb21e1b22015-04-24 16:59:11 -0700692 if (receiver == null) return true; // client not listening
Jim Milleraf281ca2015-04-20 19:04:21 -0700693 FingerprintUtils.vibrateFingerprintSuccess(getContext());
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500694 MetricsLogger.action(mContext, MetricsEvent.ACTION_FINGERPRINT_ENROLL);
Jim Miller13041372015-04-16 14:48:55 -0700695 try {
Jim Millerb21e1b22015-04-24 16:59:11 -0700696 receiver.onEnrollResult(mHalDeviceId, fpId, groupId, remaining);
Jim Miller13041372015-04-16 14:48:55 -0700697 return remaining == 0;
698 } catch (RemoteException e) {
699 Slog.w(TAG, "Failed to notify EnrollResult:", e);
700 return true;
Jim Millerfe6439f2015-04-11 18:07:57 -0700701 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700702 }
703
Jim Miller13041372015-04-16 14:48:55 -0700704 /*
705 * @return true if we're done.
706 */
Jim Millerfe6439f2015-04-11 18:07:57 -0700707 private boolean sendAuthenticated(int fpId, int groupId) {
Jim Miller13041372015-04-16 14:48:55 -0700708 boolean result = false;
Jim Millerdca15d22015-06-16 20:55:13 -0700709 boolean authenticated = fpId != 0;
Jim Millerb21e1b22015-04-24 16:59:11 -0700710 if (receiver != null) {
Jim Millerfe6439f2015-04-11 18:07:57 -0700711 try {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500712 MetricsLogger.action(mContext, MetricsEvent.ACTION_FINGERPRINT_AUTH,
Chris Wrenc510ad52015-08-14 15:43:15 -0400713 authenticated);
Jim Millerdca15d22015-06-16 20:55:13 -0700714 if (!authenticated) {
Jim Millerf501b582015-06-03 16:36:31 -0700715 receiver.onAuthenticationFailed(mHalDeviceId);
716 } else {
Jim Miller1adb4a72015-09-14 18:58:08 -0700717 if (DEBUG) {
718 Slog.v(TAG, "onAuthenticated(owner=" + mAuthClient.owner
719 + ", id=" + fpId + ", gp=" + groupId + ")");
720 }
Jim Millerf501b582015-06-03 16:36:31 -0700721 Fingerprint fp = !restricted ?
722 new Fingerprint("" /* TODO */, groupId, fpId, mHalDeviceId) : null;
723 receiver.onAuthenticationSucceeded(mHalDeviceId, fp);
724 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700725 } catch (RemoteException e) {
Jim Miller13041372015-04-16 14:48:55 -0700726 Slog.w(TAG, "Failed to notify Authenticated:", e);
727 result = true; // client failed
Jim Millerfe6439f2015-04-11 18:07:57 -0700728 }
Jim Miller13041372015-04-16 14:48:55 -0700729 } else {
730 result = true; // client not listening
Vineeta Srivastava99b88202015-07-08 13:37:09 -0700731 }
732 if (fpId == 0) {
Jorim Jaggi055eafd2015-08-12 18:06:22 -0700733 if (receiver != null) {
734 FingerprintUtils.vibrateFingerprintError(getContext());
735 }
Jim Miller13041372015-04-16 14:48:55 -0700736 result |= handleFailedAttempt(this);
737 } else {
Jorim Jaggi055eafd2015-08-12 18:06:22 -0700738 if (receiver != null) {
739 FingerprintUtils.vibrateFingerprintSuccess(getContext());
740 }
Jim Miller13041372015-04-16 14:48:55 -0700741 result |= true; // we have a valid fingerprint
Jorim Jaggi5e354222015-09-04 14:17:58 -0700742 resetFailedAttempts();
Jim Miller13041372015-04-16 14:48:55 -0700743 }
744 return result;
Jim Millerfe6439f2015-04-11 18:07:57 -0700745 }
746
Jim Miller13041372015-04-16 14:48:55 -0700747 /*
748 * @return true if we're done.
749 */
Jim Millerfe6439f2015-04-11 18:07:57 -0700750 private boolean sendAcquired(int acquiredInfo) {
Jim Millerb21e1b22015-04-24 16:59:11 -0700751 if (receiver == null) return true; // client not listening
Jim Miller13041372015-04-16 14:48:55 -0700752 try {
Jim Millerb21e1b22015-04-24 16:59:11 -0700753 receiver.onAcquired(mHalDeviceId, acquiredInfo);
Jim Miller13041372015-04-16 14:48:55 -0700754 return false; // acquisition continues...
755 } catch (RemoteException e) {
756 Slog.w(TAG, "Failed to invoke sendAcquired:", e);
757 return true; // client failed
Jim Millerfe6439f2015-04-11 18:07:57 -0700758 }
Jim Millerdca15d22015-06-16 20:55:13 -0700759 finally {
760 // Good scans will keep the device awake
761 if (acquiredInfo == FINGERPRINT_ACQUIRED_GOOD) {
762 userActivity();
763 }
764 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700765 }
766
Jim Miller13041372015-04-16 14:48:55 -0700767 /*
768 * @return true if we're done.
769 */
Jim Millerfe6439f2015-04-11 18:07:57 -0700770 private boolean sendError(int error) {
Jim Millerb21e1b22015-04-24 16:59:11 -0700771 if (receiver != null) {
Jim Millerfe6439f2015-04-11 18:07:57 -0700772 try {
Jim Millerb21e1b22015-04-24 16:59:11 -0700773 receiver.onError(mHalDeviceId, error);
Jim Millerfe6439f2015-04-11 18:07:57 -0700774 } catch (RemoteException e) {
Jim Miller13041372015-04-16 14:48:55 -0700775 Slog.w(TAG, "Failed to invoke sendError:", e);
Jim Millerfe6439f2015-04-11 18:07:57 -0700776 }
777 }
Jim Miller13041372015-04-16 14:48:55 -0700778 return true; // errors always terminate progress
Jim Millerce7eb6d2015-04-03 19:29:13 -0700779 }
780 }
781
Jorim Jaggi3a464782015-08-28 16:59:13 -0700782 private class FingerprintServiceLockoutResetMonitor {
783
784 private final IFingerprintServiceLockoutResetCallback mCallback;
785
786 public FingerprintServiceLockoutResetMonitor(
787 IFingerprintServiceLockoutResetCallback callback) {
788 mCallback = callback;
789 }
790
791 public void sendLockoutReset() {
792 if (mCallback != null) {
793 try {
794 mCallback.onLockoutReset(mHalDeviceId);
795 } catch (DeadObjectException e) {
796 Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
797 mHandler.post(mRemoveCallbackRunnable);
798 } catch (RemoteException e) {
799 Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
800 }
801 }
802 }
803
804 private final Runnable mRemoveCallbackRunnable = new Runnable() {
805 @Override
806 public void run() {
807 removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
808 }
809 };
810 }
811
Jim Millerbe675422015-05-11 20:45:25 -0700812 private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() {
813
Jim Miller9f0753f2015-03-23 23:59:22 -0700814 @Override
Jim Miller8b3c25a2015-08-28 17:29:49 -0700815 public void onEnrollResult(final long deviceId, final int fingerId, final int groupId,
816 final int remaining) {
817 mHandler.post(new Runnable() {
818 @Override
819 public void run() {
820 handleEnrollResult(deviceId, fingerId, groupId, remaining);
821 }
822 });
Jim Millerbe675422015-05-11 20:45:25 -0700823 }
824
825 @Override
Jim Miller8b3c25a2015-08-28 17:29:49 -0700826 public void onAcquired(final long deviceId, final int acquiredInfo) {
827 mHandler.post(new Runnable() {
828 @Override
829 public void run() {
830 handleAcquired(deviceId, acquiredInfo);
831 }
832 });
Jim Millerbe675422015-05-11 20:45:25 -0700833 }
834
835 @Override
Jim Miller8b3c25a2015-08-28 17:29:49 -0700836 public void onAuthenticated(final long deviceId, final int fingerId, final int groupId) {
837 mHandler.post(new Runnable() {
838 @Override
839 public void run() {
840 handleAuthenticated(deviceId, fingerId, groupId);
841 }
842 });
Jim Millerbe675422015-05-11 20:45:25 -0700843 }
844
845 @Override
Jim Miller8b3c25a2015-08-28 17:29:49 -0700846 public void onError(final long deviceId, final int error) {
847 mHandler.post(new Runnable() {
848 @Override
849 public void run() {
850 handleError(deviceId, error);
851 }
852 });
Jim Millerbe675422015-05-11 20:45:25 -0700853 }
854
855 @Override
Jim Miller8b3c25a2015-08-28 17:29:49 -0700856 public void onRemoved(final long deviceId, final int fingerId, final int groupId) {
857 mHandler.post(new Runnable() {
858 @Override
859 public void run() {
860 handleRemoved(deviceId, fingerId, groupId);
861 }
862 });
Jim Millerbe675422015-05-11 20:45:25 -0700863 }
864
865 @Override
Jim Miller8b3c25a2015-08-28 17:29:49 -0700866 public void onEnumerate(final long deviceId, final int[] fingerIds, final int[] groupIds) {
867 mHandler.post(new Runnable() {
868 @Override
869 public void run() {
870 handleEnumerate(deviceId, fingerIds, groupIds);
871 }
872 });
Jim Millerbe675422015-05-11 20:45:25 -0700873 }
Jim Millerbe675422015-05-11 20:45:25 -0700874 };
875
876 private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
Jim Millerdca15d22015-06-16 20:55:13 -0700877 private static final String KEYGUARD_PACKAGE = "com.android.systemui";
878
Jim Millerbe675422015-05-11 20:45:25 -0700879 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -0700880 public long preEnroll(IBinder token) {
Jim Millerba67aee2015-02-20 16:21:26 -0800881 checkPermission(MANAGE_FINGERPRINT);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700882 return startPreEnroll(token);
Jim Millera75961472014-06-06 15:00:49 -0700883 }
884
Jim Millerbe675422015-05-11 20:45:25 -0700885 @Override // Binder call
Sasha Levitskiye0943cf2015-07-08 13:22:20 -0700886 public int postEnroll(IBinder token) {
887 checkPermission(MANAGE_FINGERPRINT);
888 return startPostEnroll(token);
889 }
890
891 @Override // Binder call
Jim Millerfe6439f2015-04-11 18:07:57 -0700892 public void enroll(final IBinder token, final byte[] cryptoToken, final int groupId,
Jim Millerce7eb6d2015-04-03 19:29:13 -0700893 final IFingerprintServiceReceiver receiver, final int flags) {
894 checkPermission(MANAGE_FINGERPRINT);
Jim Miller599ef0e2015-06-15 20:39:44 -0700895 final int limit = mContext.getResources().getInteger(
896 com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
897 final int callingUid = Binder.getCallingUid();
898 final int userId = UserHandle.getUserId(callingUid);
899 final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size();
900 if (enrolled >= limit) {
901 Slog.w(TAG, "Too many fingerprints registered");
902 return;
903 }
Jim Millerfe6439f2015-04-11 18:07:57 -0700904 final byte [] cryptoClone = Arrays.copyOf(cryptoToken, cryptoToken.length);
Jim Millerf501b582015-06-03 16:36:31 -0700905
Andres Morales494d6e92015-08-06 15:01:41 -0700906 // Group ID is arbitrarily set to parent profile user ID. It just represents
907 // the default fingerprints for the user.
908 final int effectiveGroupId = getEffectiveUserId(groupId);
909
Jim Millerf501b582015-06-03 16:36:31 -0700910 final boolean restricted = isRestricted();
Jim Millerce7eb6d2015-04-03 19:29:13 -0700911 mHandler.post(new Runnable() {
912 @Override
913 public void run() {
Andres Morales494d6e92015-08-06 15:01:41 -0700914 startEnrollment(token, cryptoClone, effectiveGroupId, receiver, flags, restricted);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700915 }
916 });
917 }
918
Jim Millerf501b582015-06-03 16:36:31 -0700919 private boolean isRestricted() {
920 // Only give privileged apps (like Settings) access to fingerprint info
921 final boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
922 return restricted;
923 }
924
Jim Millerbe675422015-05-11 20:45:25 -0700925 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -0700926 public void cancelEnrollment(final IBinder token) {
927 checkPermission(MANAGE_FINGERPRINT);
928 mHandler.post(new Runnable() {
929 @Override
930 public void run() {
Jim Miller13041372015-04-16 14:48:55 -0700931 stopEnrollment(token, true);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700932 }
933 });
934 }
935
Jim Millerbe675422015-05-11 20:45:25 -0700936 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -0700937 public void authenticate(final IBinder token, final long opId, final int groupId,
Jim Millerdca15d22015-06-16 20:55:13 -0700938 final IFingerprintServiceReceiver receiver, final int flags,
939 final String opPackageName) {
Jim Miller975f1452015-08-31 18:18:22 -0700940 if (!canUseFingerprint(opPackageName, true /* foregroundOnly */)) {
Jim Miller1adb4a72015-09-14 18:58:08 -0700941 if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
Svetoslav4af76a52015-04-29 15:29:46 -0700942 return;
943 }
Andres Morales494d6e92015-08-06 15:01:41 -0700944
945 // Group ID is arbitrarily set to parent profile user ID. It just represents
946 // the default fingerprints for the user.
947 final int effectiveGroupId = getEffectiveUserId(groupId);
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000948 final int realUserId = Binder.getCallingUid();
Andres Morales494d6e92015-08-06 15:01:41 -0700949
Jim Millerf501b582015-06-03 16:36:31 -0700950 final boolean restricted = isRestricted();
Jim Millerce7eb6d2015-04-03 19:29:13 -0700951 mHandler.post(new Runnable() {
952 @Override
953 public void run() {
Chris Wren95212312015-08-24 16:19:03 -0400954 MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000955 startAuthentication(token, opId, realUserId, effectiveGroupId, receiver,
956 flags, restricted, opPackageName);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700957 }
958 });
959 }
960
Jim Millerbe675422015-05-11 20:45:25 -0700961 @Override // Binder call
Svetoslav4af76a52015-04-29 15:29:46 -0700962 public void cancelAuthentication(final IBinder token, String opPackageName) {
Jim Miller975f1452015-08-31 18:18:22 -0700963 if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
Svetoslav4af76a52015-04-29 15:29:46 -0700964 return;
965 }
Jim Millerce7eb6d2015-04-03 19:29:13 -0700966 mHandler.post(new Runnable() {
967 @Override
968 public void run() {
Jim Miller13041372015-04-16 14:48:55 -0700969 stopAuthentication(token, true);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700970 }
971 });
Jim Millerba67aee2015-02-20 16:21:26 -0800972 }
Jim Miller99d60192015-03-11 17:41:58 -0700973
Jim Millerbe675422015-05-11 20:45:25 -0700974 @Override // Binder call
Clara Bayarrid1f722d2016-01-07 14:17:39 +0000975 public void setActiveUser(final int userId) {
976 checkPermission(MANAGE_FINGERPRINT);
977 mHandler.post(new Runnable() {
978 @Override
979 public void run() {
980 updateActiveGroup(userId, null);
981 }
982 });
983 }
984
985 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -0700986 public void remove(final IBinder token, final int fingerId, final int groupId,
987 final IFingerprintServiceReceiver receiver) {
Jim Miller9f0753f2015-03-23 23:59:22 -0700988 checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
Jim Millerf501b582015-06-03 16:36:31 -0700989 final boolean restricted = isRestricted();
Andres Morales494d6e92015-08-06 15:01:41 -0700990
991 // Group ID is arbitrarily set to parent profile user ID. It just represents
992 // the default fingerprints for the user.
993 final int effectiveGroupId = getEffectiveUserId(groupId);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700994 mHandler.post(new Runnable() {
995 @Override
996 public void run() {
Andres Morales494d6e92015-08-06 15:01:41 -0700997 startRemove(token, fingerId, effectiveGroupId, receiver, restricted);
Jim Millerce7eb6d2015-04-03 19:29:13 -0700998 }
999 });
Jim Miller9f0753f2015-03-23 23:59:22 -07001000
Jim Miller9f0753f2015-03-23 23:59:22 -07001001 }
1002
Jim Millerbe675422015-05-11 20:45:25 -07001003 @Override // Binder call
Svetoslav4af76a52015-04-29 15:29:46 -07001004 public boolean isHardwareDetected(long deviceId, String opPackageName) {
Jim Miller975f1452015-08-31 18:18:22 -07001005 if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
Svetoslav4af76a52015-04-29 15:29:46 -07001006 return false;
1007 }
Jim Millerbe675422015-05-11 20:45:25 -07001008 return mHalDeviceId != 0;
Jim Miller9f0753f2015-03-23 23:59:22 -07001009 }
1010
Jim Millerbe675422015-05-11 20:45:25 -07001011 @Override // Binder call
Jim Millerce7eb6d2015-04-03 19:29:13 -07001012 public void rename(final int fingerId, final int groupId, final String name) {
Jim Miller99d60192015-03-11 17:41:58 -07001013 checkPermission(MANAGE_FINGERPRINT);
Andres Morales494d6e92015-08-06 15:01:41 -07001014
1015 // Group ID is arbitrarily set to parent profile user ID. It just represents
1016 // the default fingerprints for the user.
1017 final int effectiveGroupId = getEffectiveUserId(groupId);
Jim Millerce7eb6d2015-04-03 19:29:13 -07001018 mHandler.post(new Runnable() {
1019 @Override
1020 public void run() {
Andres Morales494d6e92015-08-06 15:01:41 -07001021 mFingerprintUtils.renameFingerprintForUser(mContext, fingerId,
1022 effectiveGroupId, name);
Jim Millerce7eb6d2015-04-03 19:29:13 -07001023 }
1024 });
Jim Miller99d60192015-03-11 17:41:58 -07001025 }
Jim Miller9f0753f2015-03-23 23:59:22 -07001026
Jim Millerbe675422015-05-11 20:45:25 -07001027 @Override // Binder call
Jim Miller599ef0e2015-06-15 20:39:44 -07001028 public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
Jim Miller975f1452015-08-31 18:18:22 -07001029 if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
Svetoslav4af76a52015-04-29 15:29:46 -07001030 return Collections.emptyList();
1031 }
Andres Morales494d6e92015-08-06 15:01:41 -07001032 int effectiveUserId = getEffectiveUserId(userId);
1033
1034 return FingerprintService.this.getEnrolledFingerprints(effectiveUserId);
Jim Miller9f0753f2015-03-23 23:59:22 -07001035 }
Jorim Jaggi2aad7ee2015-04-14 15:25:06 -07001036
Jim Millerbe675422015-05-11 20:45:25 -07001037 @Override // Binder call
Andres Morales494d6e92015-08-06 15:01:41 -07001038 public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
Jim Miller975f1452015-08-31 18:18:22 -07001039 if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
Svetoslav4af76a52015-04-29 15:29:46 -07001040 return false;
1041 }
Andres Morales494d6e92015-08-06 15:01:41 -07001042
1043 int effectiveUserId = getEffectiveUserId(userId);
1044 return FingerprintService.this.hasEnrolledFingerprints(effectiveUserId);
Jorim Jaggi2aad7ee2015-04-14 15:25:06 -07001045 }
Andres Morales4d41a202015-04-16 14:12:38 -07001046
Jim Millerbe675422015-05-11 20:45:25 -07001047 @Override // Binder call
Svetoslav4af76a52015-04-29 15:29:46 -07001048 public long getAuthenticatorId(String opPackageName) {
Alex Klyubina99b8b52015-06-11 13:27:34 -07001049 // In this method, we're not checking whether the caller is permitted to use fingerprint
1050 // API because current authenticator ID is leaked (in a more contrived way) via Android
1051 // Keystore (android.security.keystore package): the user of that API can create a key
1052 // which requires fingerprint authentication for its use, and then query the key's
1053 // characteristics (hidden API) which returns, among other things, fingerprint
1054 // authenticator ID which was active at key creation time.
1055 //
1056 // Reason: The part of Android Keystore which runs inside an app's process invokes this
1057 // method in certain cases. Those cases are not always where the developer demonstrates
1058 // explicit intent to use fingerprint functionality. Thus, to avoiding throwing an
1059 // unexpected SecurityException this method does not check whether its caller is
1060 // permitted to use fingerprint API.
1061 //
1062 // The permission check should be restored once Android Keystore no longer invokes this
1063 // method from inside app processes.
1064
Jim Millerbe675422015-05-11 20:45:25 -07001065 return FingerprintService.this.getAuthenticatorId();
Andres Morales4d41a202015-04-16 14:12:38 -07001066 }
Chris Wrenc510ad52015-08-14 15:43:15 -04001067
1068 @Override // Binder call
1069 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1070 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
1071 != PackageManager.PERMISSION_GRANTED) {
1072 pw.println("Permission Denial: can't dump Fingerprint from from pid="
1073 + Binder.getCallingPid()
1074 + ", uid=" + Binder.getCallingUid());
1075 return;
1076 }
1077
1078 final long ident = Binder.clearCallingIdentity();
1079 try {
1080 dumpInternal(pw);
1081 } finally {
1082 Binder.restoreCallingIdentity(ident);
1083 }
1084 }
Jim Millere0507bb2015-08-12 20:30:34 -07001085 @Override // Binder call
1086 public void resetTimeout(byte [] token) {
1087 checkPermission(RESET_FINGERPRINT_LOCKOUT);
1088 // TODO: confirm security token when we move timeout management into the HAL layer.
Jorim Jaggi5e354222015-09-04 14:17:58 -07001089 mHandler.post(mResetFailedAttemptsRunnable);
Jorim Jaggi3a464782015-08-28 16:59:13 -07001090 }
1091
1092 @Override
1093 public void addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback)
1094 throws RemoteException {
1095 mHandler.post(new Runnable() {
1096 @Override
1097 public void run() {
1098 addLockoutResetMonitor(
1099 new FingerprintServiceLockoutResetMonitor(callback));
1100 }
1101 });
Jim Millere0507bb2015-08-12 20:30:34 -07001102 }
Chris Wrenc510ad52015-08-14 15:43:15 -04001103 }
1104
1105 private void dumpInternal(PrintWriter pw) {
1106 JSONObject dump = new JSONObject();
1107 try {
1108 dump.put("service", "Fingerprint Manager");
1109
1110 JSONArray sets = new JSONArray();
1111 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1112 final int userId = user.getUserHandle().getIdentifier();
1113 final int N = mFingerprintUtils.getFingerprintsForUser(mContext, userId).size();
1114 JSONObject set = new JSONObject();
1115 set.put("id", userId);
1116 set.put("count", N);
1117 sets.put(set);
1118 }
1119
1120 dump.put("prints", sets);
1121 } catch (JSONException e) {
1122 Slog.e(TAG, "dump formatting failure", e);
1123 }
1124 pw.println(dump);
Jim Millera75961472014-06-06 15:00:49 -07001125 }
1126
1127 @Override
1128 public void onStart() {
Jim Miller9f0753f2015-03-23 23:59:22 -07001129 publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
Jim Millerbe675422015-05-11 20:45:25 -07001130 IFingerprintDaemon daemon = getFingerprintDaemon();
Jim Miller9f0753f2015-03-23 23:59:22 -07001131 if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -07001132 listenForUserSwitches();
Jim Millera75961472014-06-06 15:00:49 -07001133 }
1134
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001135 private void updateActiveGroup(int userId, String clientPackage) {
Jim Millerbe675422015-05-11 20:45:25 -07001136 IFingerprintDaemon daemon = getFingerprintDaemon();
1137 if (daemon != null) {
1138 try {
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001139 userId = getUserOrWorkProfileId(clientPackage, userId);
1140 if (userId != mCurrentUserId) {
1141 final File systemDir = Environment.getUserSystemDirectory(userId);
1142 final File fpDir = new File(systemDir, FP_DATA_DIR);
1143 if (!fpDir.exists()) {
1144 if (!fpDir.mkdir()) {
1145 Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath());
1146 return;
1147 }
1148 // Calling mkdir() from this process will create a directory with our
1149 // permissions (inherited from the containing dir). This command fixes
1150 // the label.
1151 if (!SELinux.restorecon(fpDir)) {
1152 Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
1153 return;
1154 }
Jim Millerbe675422015-05-11 20:45:25 -07001155 }
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001156 daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes());
1157 mCurrentUserId = userId;
Jim Millerbe675422015-05-11 20:45:25 -07001158 }
Jim Millerbe675422015-05-11 20:45:25 -07001159 } catch (RemoteException e) {
1160 Slog.e(TAG, "Failed to setActiveGroup():", e);
1161 }
Jim Millerdbe780f2015-05-18 13:55:00 -07001162 }
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -07001163 }
1164
Clara Bayarrid1f722d2016-01-07 14:17:39 +00001165 /**
1166 * @param clientPackage the package of the caller
1167 * @return the profile id
1168 */
1169 private int getUserOrWorkProfileId(String clientPackage, int userId) {
1170 if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
1171 return userId;
1172 }
1173 return getEffectiveUserId(userId);
1174 }
1175
1176 /**
1177 * @param userId
1178 * @return true if this is a work profile
1179 */
1180 private boolean isWorkProfile(int userId) {
1181 UserInfo info = mUserManager.getUserInfo(userId);
1182 return info != null && info.isManagedProfile();
1183 }
1184
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -07001185 private void listenForUserSwitches() {
1186 try {
1187 ActivityManagerNative.getDefault().registerUserSwitchObserver(
Fyodor Kupolov6005b3f2015-11-23 17:41:50 -08001188 new SynchronousUserSwitchObserver() {
Jim Millerbe675422015-05-11 20:45:25 -07001189 @Override
Fyodor Kupolov6005b3f2015-11-23 17:41:50 -08001190 public void onUserSwitching(int newUserId) throws RemoteException {
Jim Millerbe675422015-05-11 20:45:25 -07001191 mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
1192 .sendToTarget();
1193 }
1194 @Override
1195 public void onUserSwitchComplete(int newUserId) throws RemoteException {
1196 // Ignore.
1197 }
1198 @Override
1199 public void onForegroundProfileSwitch(int newProfileId) {
1200 // Ignore.
1201 }
1202 });
Jorim Jaggiaa4d32a2015-05-13 16:30:04 -07001203 } catch (RemoteException e) {
1204 Slog.w(TAG, "Failed to listen for user switching event" ,e);
1205 }
1206 }
Jim Millerbe675422015-05-11 20:45:25 -07001207
1208 public long getAuthenticatorId() {
1209 IFingerprintDaemon daemon = getFingerprintDaemon();
1210 if (daemon != null) {
1211 try {
1212 return daemon.getAuthenticatorId();
1213 } catch (RemoteException e) {
1214 Slog.e(TAG, "getAuthenticatorId failed", e);
1215 }
1216 }
1217 return 0;
1218 }
1219
Jim Millera75961472014-06-06 15:00:49 -07001220}