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