• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
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 
17 package com.android.server.fingerprint;
18 
19 import android.Manifest;
20 import android.app.ActivityManager;
21 import android.app.ActivityManager.RunningAppProcessInfo;
22 import android.app.ActivityManagerNative;
23 import android.app.AlarmManager;
24 import android.app.AppOpsManager;
25 import android.app.PendingIntent;
26 import android.app.SynchronousUserSwitchObserver;
27 import android.content.ComponentName;
28 import android.content.BroadcastReceiver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.pm.PackageManager;
33 import android.content.pm.UserInfo;
34 import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
35 import android.os.Binder;
36 import android.os.DeadObjectException;
37 import android.os.Environment;
38 import android.os.Handler;
39 import android.os.IBinder;
40 import android.os.PowerManager;
41 import android.os.RemoteException;
42 import android.os.SELinux;
43 import android.os.ServiceManager;
44 import android.os.SystemClock;
45 import android.os.UserHandle;
46 import android.os.UserManager;
47 import android.util.Slog;
48 
49 import com.android.internal.logging.MetricsLogger;
50 import com.android.server.SystemService;
51 
52 import org.json.JSONArray;
53 import org.json.JSONException;
54 import org.json.JSONObject;
55 
56 import android.hardware.fingerprint.Fingerprint;
57 import android.hardware.fingerprint.FingerprintManager;
58 import android.hardware.fingerprint.IFingerprintService;
59 import android.hardware.fingerprint.IFingerprintDaemon;
60 import android.hardware.fingerprint.IFingerprintDaemonCallback;
61 import android.hardware.fingerprint.IFingerprintServiceReceiver;
62 
63 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
64 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
65 import static android.Manifest.permission.MANAGE_FINGERPRINT;
66 import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
67 import static android.Manifest.permission.USE_FINGERPRINT;
68 
69 import java.io.File;
70 import java.io.FileDescriptor;
71 import java.io.PrintWriter;
72 import java.util.ArrayList;
73 import java.util.Arrays;
74 import java.util.Collections;
75 import java.util.HashMap;
76 import java.util.List;
77 
78 /**
79  * A service to manage multiple clients that want to access the fingerprint HAL API.
80  * The service is responsible for maintaining a list of clients and dispatching all
81  * fingerprint -related events.
82  *
83  * @hide
84  */
85 public class FingerprintService extends SystemService implements IBinder.DeathRecipient {
86     static final String TAG = "FingerprintService";
87     static final boolean DEBUG = true;
88     private static final String FP_DATA_DIR = "fpdata";
89     private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon";
90     private static final int MSG_USER_SWITCHING = 10;
91     private static final String ACTION_LOCKOUT_RESET =
92             "com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
93 
94     private class PerformanceStats {
95         int accept; // number of accepted fingerprints
96         int reject; // number of rejected fingerprints
97         int acquire; // total number of acquisitions. Should be >= accept+reject due to poor image
98                      // acquisition in some cases (too fast, too slow, dirty sensor, etc.)
99         int lockout; // total number of lockouts
100     }
101 
102     private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
103             new ArrayList<>();
104     private final AppOpsManager mAppOps;
105     private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
106     private static final int MAX_FAILED_ATTEMPTS = 5;
107     private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
108     private final String mKeyguardPackage;
109     private int mCurrentUserId = UserHandle.USER_CURRENT;
110     private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance();
111     private Context mContext;
112     private long mHalDeviceId;
113     private int mFailedAttempts;
114     private IFingerprintDaemon mDaemon;
115     private final PowerManager mPowerManager;
116     private final AlarmManager mAlarmManager;
117     private final UserManager mUserManager;
118     private ClientMonitor mCurrentClient;
119     private ClientMonitor mPendingClient;
120     private long mCurrentAuthenticatorId;
121     private PerformanceStats mPerformanceStats;
122 
123     // Normal fingerprint authentications are tracked by mPerformanceMap.
124     private HashMap<Integer, PerformanceStats> mPerformanceMap
125             = new HashMap<Integer, PerformanceStats>();
126 
127     // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
128     private HashMap<Integer, PerformanceStats> mCryptoPerformanceMap
129             = new HashMap<Integer, PerformanceStats>();
130 
131     private Handler mHandler = new Handler() {
132         @Override
133         public void handleMessage(android.os.Message msg) {
134             switch (msg.what) {
135                 case MSG_USER_SWITCHING:
136                     handleUserSwitching(msg.arg1);
137                     break;
138 
139                 default:
140                     Slog.w(TAG, "Unknown message:" + msg.what);
141             }
142         }
143     };
144 
145     private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
146         @Override
147         public void onReceive(Context context, Intent intent) {
148             if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
149                 resetFailedAttempts();
150             }
151         }
152     };
153 
154     private final Runnable mResetFailedAttemptsRunnable = new Runnable() {
155         @Override
156         public void run() {
157             resetFailedAttempts();
158         }
159     };
160 
161     private final Runnable mResetClientState = new Runnable() {
162         @Override
163         public void run() {
164             // Warning: if we get here, the driver never confirmed our call to cancel the current
165             // operation (authenticate, enroll, remove, enumerate, etc), which is
166             // really bad.  The result will be a 3-second delay in starting each new client.
167             // If you see this on a device, make certain the driver notifies with
168             // {@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} in response to cancel()
169             // once it has successfully switched to the IDLE state in the fingerprint HAL.
170             // Additionally,{@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} should only be sent
171             // in response to an actual cancel() call.
172             Slog.w(TAG, "Client "
173                     + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
174                     + " failed to respond to cancel, starting client "
175                     + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
176             mCurrentClient = null;
177             startClient(mPendingClient, false);
178         }
179     };
180 
FingerprintService(Context context)181     public FingerprintService(Context context) {
182         super(context);
183         mContext = context;
184         mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
185                 com.android.internal.R.string.config_keyguardComponent)).getPackageName();
186         mAppOps = context.getSystemService(AppOpsManager.class);
187         mPowerManager = mContext.getSystemService(PowerManager.class);
188         mAlarmManager = mContext.getSystemService(AlarmManager.class);
189         mContext.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
190                 RESET_FINGERPRINT_LOCKOUT, null /* handler */);
191         mUserManager = UserManager.get(mContext);
192     }
193 
194     @Override
binderDied()195     public void binderDied() {
196         Slog.v(TAG, "fingerprintd died");
197         mDaemon = null;
198         handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
199     }
200 
getFingerprintDaemon()201     public IFingerprintDaemon getFingerprintDaemon() {
202         if (mDaemon == null) {
203             mDaemon = IFingerprintDaemon.Stub.asInterface(ServiceManager.getService(FINGERPRINTD));
204             if (mDaemon != null) {
205                 try {
206                     mDaemon.asBinder().linkToDeath(this, 0);
207                     mDaemon.init(mDaemonCallback);
208                     mHalDeviceId = mDaemon.openHal();
209                     if (mHalDeviceId != 0) {
210                         updateActiveGroup(ActivityManager.getCurrentUser(), null);
211                     } else {
212                         Slog.w(TAG, "Failed to open Fingerprint HAL!");
213                         mDaemon = null;
214                     }
215                 } catch (RemoteException e) {
216                     Slog.e(TAG, "Failed to open fingeprintd HAL", e);
217                     mDaemon = null; // try again later!
218                 }
219             } else {
220                 Slog.w(TAG, "fingerprint service not available");
221             }
222         }
223         return mDaemon;
224     }
225 
handleEnumerate(long deviceId, int[] fingerIds, int[] groupIds)226     protected void handleEnumerate(long deviceId, int[] fingerIds, int[] groupIds) {
227         if (fingerIds.length != groupIds.length) {
228             Slog.w(TAG, "fingerIds and groupIds differ in length: f[]="
229                     + Arrays.toString(fingerIds) + ", g[]=" + Arrays.toString(groupIds));
230             return;
231         }
232         if (DEBUG) Slog.w(TAG, "Enumerate: f[]=" + fingerIds + ", g[]=" + groupIds);
233         // TODO: update fingerprint/name pairs
234     }
235 
handleError(long deviceId, int error)236     protected void handleError(long deviceId, int error) {
237         ClientMonitor client = mCurrentClient;
238         if (client != null && client.onError(error)) {
239             removeClient(client);
240         }
241         if (DEBUG) Slog.v(TAG, "handleError(client="
242                 + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
243         // This is the magic code that starts the next client when the old client finishes.
244         if (error == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
245             mHandler.removeCallbacks(mResetClientState);
246             if (mPendingClient != null) {
247                 if (DEBUG) Slog.v(TAG, "start pending client " + mPendingClient.getOwnerString());
248                 startClient(mPendingClient, false);
249                 mPendingClient = null;
250             }
251         }
252     }
253 
handleRemoved(long deviceId, int fingerId, int groupId)254     protected void handleRemoved(long deviceId, int fingerId, int groupId) {
255         ClientMonitor client = mCurrentClient;
256         if (client != null && client.onRemoved(fingerId, groupId)) {
257             removeClient(client);
258         }
259     }
260 
handleAuthenticated(long deviceId, int fingerId, int groupId)261     protected void handleAuthenticated(long deviceId, int fingerId, int groupId) {
262         ClientMonitor client = mCurrentClient;
263         if (client != null && client.onAuthenticated(fingerId, groupId)) {
264             removeClient(client);
265         }
266         if (fingerId != 0) {
267             mPerformanceStats.accept++;
268         } else {
269             mPerformanceStats.reject++;
270         }
271     }
272 
handleAcquired(long deviceId, int acquiredInfo)273     protected void handleAcquired(long deviceId, int acquiredInfo) {
274         ClientMonitor client = mCurrentClient;
275         if (client != null && client.onAcquired(acquiredInfo)) {
276             removeClient(client);
277         }
278         if (mPerformanceStats != null && !inLockoutMode()
279                 && client instanceof AuthenticationClient) {
280             // ignore enrollment acquisitions or acquisitions when we're locked out
281             mPerformanceStats.acquire++;
282         }
283     }
284 
handleEnrollResult(long deviceId, int fingerId, int groupId, int remaining)285     protected void handleEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
286         ClientMonitor client = mCurrentClient;
287         if (client != null && client.onEnrollResult(fingerId, groupId, remaining)) {
288             removeClient(client);
289         }
290     }
291 
userActivity()292     private void userActivity() {
293         long now = SystemClock.uptimeMillis();
294         mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
295     }
296 
handleUserSwitching(int userId)297     void handleUserSwitching(int userId) {
298         updateActiveGroup(userId, null);
299     }
300 
removeClient(ClientMonitor client)301     private void removeClient(ClientMonitor client) {
302         if (client != null) {
303             client.destroy();
304             if (client != mCurrentClient && mCurrentClient != null) {
305                 Slog.w(TAG, "Unexpected client: " + client.getOwnerString() + "expected: "
306                         + mCurrentClient != null ? mCurrentClient.getOwnerString() : "null");
307             }
308         }
309         if (mCurrentClient != null) {
310             if (DEBUG) Slog.v(TAG, "Done with client: " + client.getOwnerString());
311             mCurrentClient = null;
312         }
313     }
314 
inLockoutMode()315     private boolean inLockoutMode() {
316         return mFailedAttempts >= MAX_FAILED_ATTEMPTS;
317     }
318 
scheduleLockoutReset()319     private void scheduleLockoutReset() {
320         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
321                 SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS, getLockoutResetIntent());
322     }
323 
cancelLockoutReset()324     private void cancelLockoutReset() {
325         mAlarmManager.cancel(getLockoutResetIntent());
326     }
327 
getLockoutResetIntent()328     private PendingIntent getLockoutResetIntent() {
329         return PendingIntent.getBroadcast(mContext, 0,
330                 new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT);
331     }
332 
startPreEnroll(IBinder token)333     public long startPreEnroll(IBinder token) {
334         IFingerprintDaemon daemon = getFingerprintDaemon();
335         if (daemon == null) {
336             Slog.w(TAG, "startPreEnroll: no fingeprintd!");
337             return 0;
338         }
339         try {
340             return daemon.preEnroll();
341         } catch (RemoteException e) {
342             Slog.e(TAG, "startPreEnroll failed", e);
343         }
344         return 0;
345     }
346 
startPostEnroll(IBinder token)347     public int startPostEnroll(IBinder token) {
348         IFingerprintDaemon daemon = getFingerprintDaemon();
349         if (daemon == null) {
350             Slog.w(TAG, "startPostEnroll: no fingeprintd!");
351             return 0;
352         }
353         try {
354             return daemon.postEnroll();
355         } catch (RemoteException e) {
356             Slog.e(TAG, "startPostEnroll failed", e);
357         }
358         return 0;
359     }
360 
361     /**
362      * Calls fingerprintd to switch states to the new task. If there's already a current task,
363      * it calls cancel() and sets mPendingClient to begin when the current task finishes
364      * ({@link FingerprintManager#FINGERPRINT_ERROR_CANCELED}).
365      * @param newClient the new client that wants to connect
366      * @param initiatedByClient true for authenticate, remove and enroll
367      */
startClient(ClientMonitor newClient, boolean initiatedByClient)368     private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
369         ClientMonitor currentClient = mCurrentClient;
370         if (currentClient != null) {
371             if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString());
372             currentClient.stop(initiatedByClient);
373             mPendingClient = newClient;
374             mHandler.removeCallbacks(mResetClientState);
375             mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
376         } else if (newClient != null) {
377             mCurrentClient = newClient;
378             if (DEBUG) Slog.v(TAG, "starting client "
379                     + newClient.getClass().getSuperclass().getSimpleName()
380                     + "(" + newClient.getOwnerString() + ")"
381                     + ", initiatedByClient = " + initiatedByClient + ")");
382             newClient.start();
383         }
384     }
385 
startRemove(IBinder token, int fingerId, int groupId, int userId, IFingerprintServiceReceiver receiver, boolean restricted)386     void startRemove(IBinder token, int fingerId, int groupId, int userId,
387             IFingerprintServiceReceiver receiver, boolean restricted) {
388         IFingerprintDaemon daemon = getFingerprintDaemon();
389         if (daemon == null) {
390             Slog.w(TAG, "startRemove: no fingeprintd!");
391             return;
392         }
393         RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token,
394                 receiver, fingerId, groupId, userId, restricted, token.toString()) {
395             @Override
396             public void notifyUserActivity() {
397                 FingerprintService.this.userActivity();
398             }
399 
400             @Override
401             public IFingerprintDaemon getFingerprintDaemon() {
402                 return FingerprintService.this.getFingerprintDaemon();
403             }
404         };
405         startClient(client, true);
406     }
407 
getEnrolledFingerprints(int userId)408     public List<Fingerprint> getEnrolledFingerprints(int userId) {
409         return mFingerprintUtils.getFingerprintsForUser(mContext, userId);
410     }
411 
hasEnrolledFingerprints(int userId)412     public boolean hasEnrolledFingerprints(int userId) {
413         if (userId != UserHandle.getCallingUserId()) {
414             checkPermission(INTERACT_ACROSS_USERS);
415         }
416         return mFingerprintUtils.getFingerprintsForUser(mContext, userId).size() > 0;
417     }
418 
hasPermission(String permission)419     boolean hasPermission(String permission) {
420         return getContext().checkCallingOrSelfPermission(permission)
421                 == PackageManager.PERMISSION_GRANTED;
422     }
423 
checkPermission(String permission)424     void checkPermission(String permission) {
425         getContext().enforceCallingOrSelfPermission(permission,
426                 "Must have " + permission + " permission.");
427     }
428 
getEffectiveUserId(int userId)429     int getEffectiveUserId(int userId) {
430         UserManager um = UserManager.get(mContext);
431         if (um != null) {
432             final long callingIdentity = Binder.clearCallingIdentity();
433             userId = um.getCredentialOwnerProfile(userId);
434             Binder.restoreCallingIdentity(callingIdentity);
435         } else {
436             Slog.e(TAG, "Unable to acquire UserManager");
437         }
438         return userId;
439     }
440 
isCurrentUserOrProfile(int userId)441     boolean isCurrentUserOrProfile(int userId) {
442         UserManager um = UserManager.get(mContext);
443 
444         // Allow current user or profiles of the current user...
445         for (int profileId : um.getEnabledProfileIds(userId)) {
446             if (profileId == userId) {
447                 return true;
448             }
449         }
450         return false;
451     }
452 
isForegroundActivity(int uid, int pid)453     private boolean isForegroundActivity(int uid, int pid) {
454         try {
455             List<RunningAppProcessInfo> procs =
456                     ActivityManagerNative.getDefault().getRunningAppProcesses();
457             int N = procs.size();
458             for (int i = 0; i < N; i++) {
459                 RunningAppProcessInfo proc = procs.get(i);
460                 if (proc.pid == pid && proc.uid == uid
461                         && proc.importance == IMPORTANCE_FOREGROUND) {
462                     return true;
463                 }
464             }
465         } catch (RemoteException e) {
466             Slog.w(TAG, "am.getRunningAppProcesses() failed");
467         }
468         return false;
469     }
470 
471     /**
472      * @param opPackageName name of package for caller
473      * @param requireForeground only allow this call while app is in the foreground
474      * @return true if caller can use fingerprint API
475      */
canUseFingerprint(String opPackageName, boolean requireForeground, int uid, int pid)476     private boolean canUseFingerprint(String opPackageName, boolean requireForeground, int uid,
477             int pid) {
478         checkPermission(USE_FINGERPRINT);
479         if (isKeyguard(opPackageName)) {
480             return true; // Keyguard is always allowed
481         }
482         if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
483             Slog.w(TAG,"Rejecting " + opPackageName + " ; not a current user or profile");
484             return false;
485         }
486         if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
487                 != AppOpsManager.MODE_ALLOWED) {
488             Slog.w(TAG, "Rejecting " + opPackageName + " ; permission denied");
489             return false;
490         }
491         if (requireForeground && !(isForegroundActivity(uid, pid) || currentClient(opPackageName))){
492             Slog.w(TAG, "Rejecting " + opPackageName + " ; not in foreground");
493             return false;
494         }
495         return true;
496     }
497 
498     /**
499      * @param opPackageName package of the caller
500      * @return true if this is the same client currently using fingerprint
501      */
currentClient(String opPackageName)502     private boolean currentClient(String opPackageName) {
503         return mCurrentClient != null && mCurrentClient.getOwnerString().equals(opPackageName);
504     }
505 
506     /**
507      * @param clientPackage
508      * @return true if this is keyguard package
509      */
isKeyguard(String clientPackage)510     private boolean isKeyguard(String clientPackage) {
511         return mKeyguardPackage.equals(clientPackage);
512     }
513 
addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor)514     private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
515         if (!mLockoutMonitors.contains(monitor)) {
516             mLockoutMonitors.add(monitor);
517         }
518     }
519 
removeLockoutResetCallback( FingerprintServiceLockoutResetMonitor monitor)520     private void removeLockoutResetCallback(
521             FingerprintServiceLockoutResetMonitor monitor) {
522         mLockoutMonitors.remove(monitor);
523     }
524 
notifyLockoutResetMonitors()525     private void notifyLockoutResetMonitors() {
526         for (int i = 0; i < mLockoutMonitors.size(); i++) {
527             mLockoutMonitors.get(i).sendLockoutReset();
528         }
529     }
530 
startAuthentication(IBinder token, long opId, int callingUserId, int groupId, IFingerprintServiceReceiver receiver, int flags, boolean restricted, String opPackageName)531     private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId,
532                 IFingerprintServiceReceiver receiver, int flags, boolean restricted,
533                 String opPackageName) {
534         updateActiveGroup(groupId, opPackageName);
535 
536         if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")");
537 
538         AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token,
539                 receiver, mCurrentUserId, groupId, opId, restricted, opPackageName) {
540             @Override
541             public boolean handleFailedAttempt() {
542                 mFailedAttempts++;
543                 if (mFailedAttempts == MAX_FAILED_ATTEMPTS) {
544                     mPerformanceStats.lockout++;
545                 }
546                 if (inLockoutMode()) {
547                     // Failing multiple times will continue to push out the lockout time.
548                     scheduleLockoutReset();
549                     return true;
550                 }
551                 return false;
552             }
553 
554             @Override
555             public void resetFailedAttempts() {
556                 FingerprintService.this.resetFailedAttempts();
557             }
558 
559             @Override
560             public void notifyUserActivity() {
561                 FingerprintService.this.userActivity();
562             }
563 
564             @Override
565             public IFingerprintDaemon getFingerprintDaemon() {
566                 return FingerprintService.this.getFingerprintDaemon();
567             }
568         };
569 
570         if (inLockoutMode()) {
571             Slog.v(TAG, "In lockout mode; disallowing authentication");
572             // Don't bother starting the client. Just send the error message.
573             if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
574                 Slog.w(TAG, "Cannot send timeout message to client");
575             }
576             return;
577         }
578         startClient(client, true /* initiatedByClient */);
579     }
580 
startEnrollment(IBinder token, byte [] cryptoToken, int userId, IFingerprintServiceReceiver receiver, int flags, boolean restricted, String opPackageName)581     private void startEnrollment(IBinder token, byte [] cryptoToken, int userId,
582             IFingerprintServiceReceiver receiver, int flags, boolean restricted,
583             String opPackageName) {
584         updateActiveGroup(userId, opPackageName);
585 
586         final int groupId = userId; // default group for fingerprint enrollment
587 
588         EnrollClient client = new EnrollClient(getContext(), mHalDeviceId, token, receiver,
589                 userId, groupId, cryptoToken, restricted, opPackageName) {
590 
591             @Override
592             public IFingerprintDaemon getFingerprintDaemon() {
593                 return FingerprintService.this.getFingerprintDaemon();
594             }
595 
596             @Override
597             public void notifyUserActivity() {
598                 FingerprintService.this.userActivity();
599             }
600         };
601         startClient(client, true /* initiatedByClient */);
602     }
603 
resetFailedAttempts()604     protected void resetFailedAttempts() {
605         if (DEBUG && inLockoutMode()) {
606             Slog.v(TAG, "Reset fingerprint lockout");
607         }
608         mFailedAttempts = 0;
609         // If we're asked to reset failed attempts externally (i.e. from Keyguard),
610         // the alarm might still be pending; remove it.
611         cancelLockoutReset();
612         notifyLockoutResetMonitors();
613     }
614 
615     private class FingerprintServiceLockoutResetMonitor {
616 
617         private final IFingerprintServiceLockoutResetCallback mCallback;
618 
FingerprintServiceLockoutResetMonitor( IFingerprintServiceLockoutResetCallback callback)619         public FingerprintServiceLockoutResetMonitor(
620                 IFingerprintServiceLockoutResetCallback callback) {
621             mCallback = callback;
622         }
623 
sendLockoutReset()624         public void sendLockoutReset() {
625             if (mCallback != null) {
626                 try {
627                     mCallback.onLockoutReset(mHalDeviceId);
628                 } catch (DeadObjectException e) {
629                     Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
630                     mHandler.post(mRemoveCallbackRunnable);
631                 } catch (RemoteException e) {
632                     Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
633                 }
634             }
635         }
636 
637         private final Runnable mRemoveCallbackRunnable = new Runnable() {
638             @Override
639             public void run() {
640                 removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
641             }
642         };
643     }
644 
645     private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() {
646 
647         @Override
648         public void onEnrollResult(final long deviceId, final int fingerId, final int groupId,
649                 final int remaining) {
650             mHandler.post(new Runnable() {
651                 @Override
652                 public void run() {
653                     handleEnrollResult(deviceId, fingerId, groupId, remaining);
654                 }
655             });
656         }
657 
658         @Override
659         public void onAcquired(final long deviceId, final int acquiredInfo) {
660             mHandler.post(new Runnable() {
661                 @Override
662                 public void run() {
663                     handleAcquired(deviceId, acquiredInfo);
664                 }
665             });
666         }
667 
668         @Override
669         public void onAuthenticated(final long deviceId, final int fingerId, final int groupId) {
670             mHandler.post(new Runnable() {
671                 @Override
672                 public void run() {
673                     handleAuthenticated(deviceId, fingerId, groupId);
674                 }
675             });
676         }
677 
678         @Override
679         public void onError(final long deviceId, final int error) {
680             mHandler.post(new Runnable() {
681                 @Override
682                 public void run() {
683                     handleError(deviceId, error);
684                 }
685             });
686         }
687 
688         @Override
689         public void onRemoved(final long deviceId, final int fingerId, final int groupId) {
690             mHandler.post(new Runnable() {
691                 @Override
692                 public void run() {
693                     handleRemoved(deviceId, fingerId, groupId);
694                 }
695             });
696         }
697 
698         @Override
699         public void onEnumerate(final long deviceId, final int[] fingerIds, final int[] groupIds) {
700             mHandler.post(new Runnable() {
701                 @Override
702                 public void run() {
703                     handleEnumerate(deviceId, fingerIds, groupIds);
704                 }
705             });
706         }
707     };
708 
709     private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
710         @Override // Binder call
preEnroll(IBinder token)711         public long preEnroll(IBinder token) {
712             checkPermission(MANAGE_FINGERPRINT);
713             return startPreEnroll(token);
714         }
715 
716         @Override // Binder call
postEnroll(IBinder token)717         public int postEnroll(IBinder token) {
718             checkPermission(MANAGE_FINGERPRINT);
719             return startPostEnroll(token);
720         }
721 
722         @Override // Binder call
enroll(final IBinder token, final byte[] cryptoToken, final int userId, final IFingerprintServiceReceiver receiver, final int flags, final String opPackageName)723         public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
724                 final IFingerprintServiceReceiver receiver, final int flags,
725                 final String opPackageName) {
726             checkPermission(MANAGE_FINGERPRINT);
727             final int limit =  mContext.getResources().getInteger(
728                     com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
729 
730             final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size();
731             if (enrolled >= limit) {
732                 Slog.w(TAG, "Too many fingerprints registered");
733                 return;
734             }
735 
736             // Group ID is arbitrarily set to parent profile user ID. It just represents
737             // the default fingerprints for the user.
738             if (!isCurrentUserOrProfile(userId)) {
739                 return;
740             }
741 
742             final boolean restricted = isRestricted();
743             mHandler.post(new Runnable() {
744                 @Override
745                 public void run() {
746                     startEnrollment(token, cryptoToken, userId, receiver, flags,
747                             restricted, opPackageName);
748                 }
749             });
750         }
751 
isRestricted()752         private boolean isRestricted() {
753             // Only give privileged apps (like Settings) access to fingerprint info
754             final boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
755             return restricted;
756         }
757 
758         @Override // Binder call
cancelEnrollment(final IBinder token)759         public void cancelEnrollment(final IBinder token) {
760             checkPermission(MANAGE_FINGERPRINT);
761             mHandler.post(new Runnable() {
762                 @Override
763                 public void run() {
764                     ClientMonitor client = mCurrentClient;
765                     if (client instanceof EnrollClient && client.getToken() == token) {
766                         client.stop(client.getToken() == token);
767                     }
768                 }
769             });
770         }
771 
772         @Override // Binder call
authenticate(final IBinder token, final long opId, final int groupId, final IFingerprintServiceReceiver receiver, final int flags, final String opPackageName)773         public void authenticate(final IBinder token, final long opId, final int groupId,
774                 final IFingerprintServiceReceiver receiver, final int flags,
775                 final String opPackageName) {
776             final int callingUid = Binder.getCallingUid();
777             final int callingUserId = UserHandle.getCallingUserId();
778             final int pid = Binder.getCallingPid();
779             final boolean restricted = isRestricted();
780             mHandler.post(new Runnable() {
781                 @Override
782                 public void run() {
783                     if (!canUseFingerprint(opPackageName, true /* foregroundOnly */,
784                             callingUid, pid)) {
785                         if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
786                         return;
787                     }
788 
789                     MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
790 
791                     // Get performance stats object for this user.
792                     HashMap<Integer, PerformanceStats> pmap
793                             = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
794                     PerformanceStats stats = pmap.get(mCurrentUserId);
795                     if (stats == null) {
796                         stats = new PerformanceStats();
797                         pmap.put(mCurrentUserId, stats);
798                     }
799                     mPerformanceStats = stats;
800 
801                     startAuthentication(token, opId, callingUserId, groupId, receiver,
802                             flags, restricted, opPackageName);
803                 }
804             });
805         }
806 
807         @Override // Binder call
cancelAuthentication(final IBinder token, final String opPackageName)808         public void cancelAuthentication(final IBinder token, final String opPackageName) {
809             final int uid = Binder.getCallingUid();
810             final int pid = Binder.getCallingPid();
811             mHandler.post(new Runnable() {
812                 @Override
813                 public void run() {
814                     if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, uid, pid)) {
815                         if (DEBUG) Slog.v(TAG, "cancelAuthentication(): reject " + opPackageName);
816                     } else {
817                         ClientMonitor client = mCurrentClient;
818                         if (client instanceof AuthenticationClient) {
819                             if (client.getToken() == token) {
820                                 if (DEBUG) Slog.v(TAG, "stop client " + client.getOwnerString());
821                                 client.stop(client.getToken() == token);
822                             } else {
823                                 if (DEBUG) Slog.v(TAG, "can't stop client "
824                                         + client.getOwnerString() + " since tokens don't match");
825                             }
826                         } else if (client != null) {
827                             if (DEBUG) Slog.v(TAG, "can't cancel non-authenticating client "
828                                     + client.getOwnerString());
829                         }
830                     }
831                 }
832             });
833         }
834 
835         @Override // Binder call
setActiveUser(final int userId)836         public void setActiveUser(final int userId) {
837             checkPermission(MANAGE_FINGERPRINT);
838             mHandler.post(new Runnable() {
839                 @Override
840                 public void run() {
841                     updateActiveGroup(userId, null);
842                 }
843             });
844         }
845 
846         @Override // Binder call
remove(final IBinder token, final int fingerId, final int groupId, final int userId, final IFingerprintServiceReceiver receiver)847         public void remove(final IBinder token, final int fingerId, final int groupId,
848                 final int userId, final IFingerprintServiceReceiver receiver) {
849             checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
850             final boolean restricted = isRestricted();
851             mHandler.post(new Runnable() {
852                 @Override
853                 public void run() {
854                     startRemove(token, fingerId, groupId, userId, receiver, restricted);
855                 }
856             });
857 
858         }
859 
860         @Override // Binder call
isHardwareDetected(long deviceId, String opPackageName)861         public boolean isHardwareDetected(long deviceId, String opPackageName) {
862             if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
863                     Binder.getCallingUid(), Binder.getCallingPid())) {
864                 return false;
865             }
866             return mHalDeviceId != 0;
867         }
868 
869         @Override // Binder call
rename(final int fingerId, final int groupId, final String name)870         public void rename(final int fingerId, final int groupId, final String name) {
871             checkPermission(MANAGE_FINGERPRINT);
872             if (!isCurrentUserOrProfile(groupId)) {
873                 return;
874             }
875             mHandler.post(new Runnable() {
876                 @Override
877                 public void run() {
878                     mFingerprintUtils.renameFingerprintForUser(mContext, fingerId,
879                             groupId, name);
880                 }
881             });
882         }
883 
884         @Override // Binder call
getEnrolledFingerprints(int userId, String opPackageName)885         public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
886             if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
887                     Binder.getCallingUid(), Binder.getCallingPid())) {
888                 return Collections.emptyList();
889             }
890             if (!isCurrentUserOrProfile(userId)) {
891                 return Collections.emptyList();
892             }
893 
894             return FingerprintService.this.getEnrolledFingerprints(userId);
895         }
896 
897         @Override // Binder call
hasEnrolledFingerprints(int userId, String opPackageName)898         public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
899             if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
900                     Binder.getCallingUid(), Binder.getCallingPid())) {
901                 return false;
902             }
903 
904             if (!isCurrentUserOrProfile(userId)) {
905                 return false;
906             }
907             return FingerprintService.this.hasEnrolledFingerprints(userId);
908         }
909 
910         @Override // Binder call
getAuthenticatorId(String opPackageName)911         public long getAuthenticatorId(String opPackageName) {
912             // In this method, we're not checking whether the caller is permitted to use fingerprint
913             // API because current authenticator ID is leaked (in a more contrived way) via Android
914             // Keystore (android.security.keystore package): the user of that API can create a key
915             // which requires fingerprint authentication for its use, and then query the key's
916             // characteristics (hidden API) which returns, among other things, fingerprint
917             // authenticator ID which was active at key creation time.
918             //
919             // Reason: The part of Android Keystore which runs inside an app's process invokes this
920             // method in certain cases. Those cases are not always where the developer demonstrates
921             // explicit intent to use fingerprint functionality. Thus, to avoiding throwing an
922             // unexpected SecurityException this method does not check whether its caller is
923             // permitted to use fingerprint API.
924             //
925             // The permission check should be restored once Android Keystore no longer invokes this
926             // method from inside app processes.
927 
928             return FingerprintService.this.getAuthenticatorId(opPackageName);
929         }
930 
931         @Override // Binder call
dump(FileDescriptor fd, PrintWriter pw, String[] args)932         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
933             if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
934                     != PackageManager.PERMISSION_GRANTED) {
935                 pw.println("Permission Denial: can't dump Fingerprint from from pid="
936                         + Binder.getCallingPid()
937                         + ", uid=" + Binder.getCallingUid());
938                 return;
939             }
940 
941             final long ident = Binder.clearCallingIdentity();
942             try {
943                 dumpInternal(pw);
944             } finally {
945                 Binder.restoreCallingIdentity(ident);
946             }
947         }
948         @Override // Binder call
resetTimeout(byte [] token)949         public void resetTimeout(byte [] token) {
950             checkPermission(RESET_FINGERPRINT_LOCKOUT);
951             // TODO: confirm security token when we move timeout management into the HAL layer.
952             mHandler.post(mResetFailedAttemptsRunnable);
953         }
954 
955         @Override
addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback)956         public void addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback)
957                 throws RemoteException {
958             mHandler.post(new Runnable() {
959                 @Override
960                 public void run() {
961                     addLockoutResetMonitor(
962                             new FingerprintServiceLockoutResetMonitor(callback));
963                 }
964             });
965         }
966     }
967 
dumpInternal(PrintWriter pw)968     private void dumpInternal(PrintWriter pw) {
969         JSONObject dump = new JSONObject();
970         try {
971             dump.put("service", "Fingerprint Manager");
972 
973             JSONArray sets = new JSONArray();
974             for (UserInfo user : UserManager.get(getContext()).getUsers()) {
975                 final int userId = user.getUserHandle().getIdentifier();
976                 final int N = mFingerprintUtils.getFingerprintsForUser(mContext, userId).size();
977                 PerformanceStats stats = mPerformanceMap.get(userId);
978                 PerformanceStats cryptoStats = mCryptoPerformanceMap.get(userId);
979                 JSONObject set = new JSONObject();
980                 set.put("id", userId);
981                 set.put("count", N);
982                 set.put("accept", (stats != null) ? stats.accept : 0);
983                 set.put("reject", (stats != null) ? stats.reject : 0);
984                 set.put("acquire", (stats != null) ? stats.acquire : 0);
985                 set.put("lockout", (stats != null) ? stats.lockout : 0);
986                 // cryptoStats measures statistics about secure fingerprint transactions
987                 // (e.g. to unlock password storage, make secure purchases, etc.)
988                 set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0);
989                 set.put("rejectCrypto", (cryptoStats != null) ? cryptoStats.reject : 0);
990                 set.put("acquireCrypto", (cryptoStats != null) ? cryptoStats.acquire : 0);
991                 set.put("lockoutCrypto", (cryptoStats != null) ? cryptoStats.lockout : 0);
992                 sets.put(set);
993             }
994 
995             dump.put("prints", sets);
996         } catch (JSONException e) {
997             Slog.e(TAG, "dump formatting failure", e);
998         }
999         pw.println(dump);
1000     }
1001 
1002     @Override
onStart()1003     public void onStart() {
1004         publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
1005         IFingerprintDaemon daemon = getFingerprintDaemon();
1006         if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
1007         listenForUserSwitches();
1008     }
1009 
updateActiveGroup(int userId, String clientPackage)1010     private void updateActiveGroup(int userId, String clientPackage) {
1011         IFingerprintDaemon daemon = getFingerprintDaemon();
1012 
1013         if (daemon != null) {
1014             try {
1015                 userId = getUserOrWorkProfileId(clientPackage, userId);
1016                 if (userId != mCurrentUserId) {
1017                     final File systemDir = Environment.getUserSystemDirectory(userId);
1018                     final File fpDir = new File(systemDir, FP_DATA_DIR);
1019                     if (!fpDir.exists()) {
1020                         if (!fpDir.mkdir()) {
1021                             Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath());
1022                             return;
1023                         }
1024                         // Calling mkdir() from this process will create a directory with our
1025                         // permissions (inherited from the containing dir). This command fixes
1026                         // the label.
1027                         if (!SELinux.restorecon(fpDir)) {
1028                             Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
1029                             return;
1030                         }
1031                     }
1032                     daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes());
1033                     mCurrentUserId = userId;
1034                 }
1035                 mCurrentAuthenticatorId = daemon.getAuthenticatorId();
1036             } catch (RemoteException e) {
1037                 Slog.e(TAG, "Failed to setActiveGroup():", e);
1038             }
1039         }
1040     }
1041 
1042     /**
1043      * @param clientPackage the package of the caller
1044      * @return the profile id
1045      */
getUserOrWorkProfileId(String clientPackage, int userId)1046     private int getUserOrWorkProfileId(String clientPackage, int userId) {
1047         if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
1048             return userId;
1049         }
1050         return getEffectiveUserId(userId);
1051     }
1052 
1053     /**
1054      * @param userId
1055      * @return true if this is a work profile
1056      */
isWorkProfile(int userId)1057     private boolean isWorkProfile(int userId) {
1058         UserInfo info = mUserManager.getUserInfo(userId);
1059         return info != null && info.isManagedProfile();
1060     }
1061 
listenForUserSwitches()1062     private void listenForUserSwitches() {
1063         try {
1064             ActivityManagerNative.getDefault().registerUserSwitchObserver(
1065                 new SynchronousUserSwitchObserver() {
1066                     @Override
1067                     public void onUserSwitching(int newUserId) throws RemoteException {
1068                         mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
1069                                 .sendToTarget();
1070                     }
1071                     @Override
1072                     public void onUserSwitchComplete(int newUserId) throws RemoteException {
1073                         // Ignore.
1074                     }
1075                     @Override
1076                     public void onForegroundProfileSwitch(int newProfileId) {
1077                         // Ignore.
1078                     }
1079                 }, TAG);
1080         } catch (RemoteException e) {
1081             Slog.w(TAG, "Failed to listen for user switching event" ,e);
1082         }
1083     }
1084 
1085     /***
1086      * @param opPackageName the name of the calling package
1087      * @return authenticator id for the current user
1088      */
getAuthenticatorId(String opPackageName)1089     public long getAuthenticatorId(String opPackageName) {
1090         return mCurrentAuthenticatorId;
1091     }
1092 
1093 }
1094