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.app.ActivityManager;
20 import android.app.ActivityManagerNative;
21 import android.app.AppOpsManager;
22 import android.app.IUserSwitchObserver;
23 import android.content.ContentResolver;
24 import android.content.Context;
25 import android.content.pm.PackageManager;
26 import android.content.pm.UserInfo;
27 import android.os.Binder;
28 import android.os.Environment;
29 import android.os.Handler;
30 import android.os.IBinder;
31 import android.os.IRemoteCallback;
32 import android.os.Looper;
33 import android.os.MessageQueue;
34 import android.os.PowerManager;
35 import android.os.RemoteException;
36 import android.os.SELinux;
37 import android.os.ServiceManager;
38 import android.os.SystemClock;
39 import android.os.UserHandle;
40 import android.os.UserManager;
41 import android.util.Slog;
42 
43 import com.android.server.SystemService;
44 
45 import android.hardware.fingerprint.Fingerprint;
46 import android.hardware.fingerprint.FingerprintManager;
47 import android.hardware.fingerprint.IFingerprintService;
48 import android.hardware.fingerprint.IFingerprintDaemon;
49 import android.hardware.fingerprint.IFingerprintDaemonCallback;
50 import android.hardware.fingerprint.IFingerprintServiceReceiver;
51 
52 import static android.Manifest.permission.MANAGE_FINGERPRINT;
53 import static android.Manifest.permission.USE_FINGERPRINT;
54 
55 import java.io.File;
56 import java.util.ArrayList;
57 import java.util.Arrays;
58 import java.util.Collections;
59 import java.util.List;
60 import java.util.NoSuchElementException;
61 
62 /**
63  * A service to manage multiple clients that want to access the fingerprint HAL API.
64  * The service is responsible for maintaining a list of clients and dispatching all
65  * fingerprint -related events.
66  *
67  * @hide
68  */
69 public class FingerprintService extends SystemService implements IBinder.DeathRecipient {
70     private static final String TAG = "FingerprintService";
71     private static final boolean DEBUG = true;
72     private static final String FP_DATA_DIR = "fpdata";
73     private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon";
74     private static final int MSG_USER_SWITCHING = 10;
75     private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
76 
77     private ClientMonitor mAuthClient = null;
78     private ClientMonitor mEnrollClient = null;
79     private ClientMonitor mRemoveClient = null;
80     private final AppOpsManager mAppOps;
81 
82     private static final long MS_PER_SEC = 1000;
83     private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
84     private static final int MAX_FAILED_ATTEMPTS = 5;
85     private static final int FINGERPRINT_ACQUIRED_GOOD = 0;
86 
87     Handler mHandler = new Handler() {
88         @Override
89         public void handleMessage(android.os.Message msg) {
90             switch (msg.what) {
91                 case MSG_USER_SWITCHING:
92                     handleUserSwitching(msg.arg1);
93                     break;
94 
95                 default:
96                     Slog.w(TAG, "Unknown message:" + msg.what);
97             }
98         }
99     };
100 
101     private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance();
102     private Context mContext;
103     private long mHalDeviceId;
104     private int mFailedAttempts;
105     private IFingerprintDaemon mDaemon;
106     private PowerManager mPowerManager;
107 
108     private final Runnable mLockoutReset = new Runnable() {
109         @Override
110         public void run() {
111             resetFailedAttempts();
112         }
113     };
114 
FingerprintService(Context context)115     public FingerprintService(Context context) {
116         super(context);
117         mContext = context;
118         mAppOps = context.getSystemService(AppOpsManager.class);
119         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
120     }
121 
122     @Override
binderDied()123     public void binderDied() {
124         Slog.v(TAG, "fingerprintd died");
125         mDaemon = null;
126         dispatchError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
127     }
128 
getFingerprintDaemon()129     public IFingerprintDaemon getFingerprintDaemon() {
130         if (mDaemon == null) {
131             mDaemon = IFingerprintDaemon.Stub.asInterface(ServiceManager.getService(FINGERPRINTD));
132             if (mDaemon != null) {
133                 try {
134                     mDaemon.asBinder().linkToDeath(this, 0);
135                     mDaemon.init(mDaemonCallback);
136                     mHalDeviceId = mDaemon.openHal();
137                     if (mHalDeviceId != 0) {
138                         updateActiveGroup(ActivityManager.getCurrentUser());
139                     } else {
140                         Slog.w(TAG, "Failed to open Fingerprint HAL!");
141                         mDaemon = null;
142                     }
143                 } catch (RemoteException e) {
144                     Slog.e(TAG, "Failed to open fingeprintd HAL", e);
145                     mDaemon = null; // try again later!
146                 }
147             } else {
148                 Slog.w(TAG, "fingerprint service not available");
149             }
150         }
151         return mDaemon;
152     }
153 
dispatchEnumerate(long deviceId, int[] fingerIds, int[] groupIds)154     protected void dispatchEnumerate(long deviceId, int[] fingerIds, int[] groupIds) {
155         if (fingerIds.length != groupIds.length) {
156             Slog.w(TAG, "fingerIds and groupIds differ in length: f[]="
157                     + fingerIds + ", g[]=" + groupIds);
158             return;
159         }
160         if (DEBUG) Slog.w(TAG, "Enumerate: f[]=" + fingerIds + ", g[]=" + groupIds);
161         // TODO: update fingerprint/name pairs
162     }
163 
dispatchRemoved(long deviceId, int fingerId, int groupId)164     protected void dispatchRemoved(long deviceId, int fingerId, int groupId) {
165         final ClientMonitor client = mRemoveClient;
166         if (fingerId != 0) {
167             removeTemplateForUser(mRemoveClient, fingerId);
168         }
169         if (client != null && client.sendRemoved(fingerId, groupId)) {
170             removeClient(mRemoveClient);
171         }
172     }
173 
dispatchError(long deviceId, int error)174     protected void dispatchError(long deviceId, int error) {
175         if (mEnrollClient != null) {
176             final IBinder token = mEnrollClient.token;
177             if (mEnrollClient.sendError(error)) {
178                 stopEnrollment(token, false);
179             }
180         } else if (mAuthClient != null) {
181             final IBinder token = mAuthClient.token;
182             if (mAuthClient.sendError(error)) {
183                 stopAuthentication(token, false);
184             }
185         } else if (mRemoveClient != null) {
186             if (mRemoveClient.sendError(error)) removeClient(mRemoveClient);
187         }
188     }
189 
dispatchAuthenticated(long deviceId, int fingerId, int groupId)190     protected void dispatchAuthenticated(long deviceId, int fingerId, int groupId) {
191         if (mAuthClient != null) {
192             final IBinder token = mAuthClient.token;
193             if (mAuthClient.sendAuthenticated(fingerId, groupId)) {
194                 stopAuthentication(token, false);
195                 removeClient(mAuthClient);
196             }
197         }
198     }
199 
dispatchAcquired(long deviceId, int acquiredInfo)200     protected void dispatchAcquired(long deviceId, int acquiredInfo) {
201         if (mEnrollClient != null) {
202             if (mEnrollClient.sendAcquired(acquiredInfo)) {
203                 removeClient(mEnrollClient);
204             }
205         } else if (mAuthClient != null) {
206             if (mAuthClient.sendAcquired(acquiredInfo)) {
207                 removeClient(mAuthClient);
208             }
209         }
210     }
211 
userActivity()212     private void userActivity() {
213         long now = SystemClock.uptimeMillis();
214         mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
215     }
216 
handleUserSwitching(int userId)217     void handleUserSwitching(int userId) {
218         updateActiveGroup(userId);
219     }
220 
dispatchEnrollResult(long deviceId, int fingerId, int groupId, int remaining)221     protected void dispatchEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
222         if (mEnrollClient != null) {
223             if (mEnrollClient.sendEnrollResult(fingerId, groupId, remaining)) {
224                 if (remaining == 0) {
225                     addTemplateForUser(mEnrollClient, fingerId);
226                     removeClient(mEnrollClient);
227                 }
228             }
229         }
230     }
231 
removeClient(ClientMonitor client)232     private void removeClient(ClientMonitor client) {
233         if (client == null) return;
234         client.destroy();
235         if (client == mAuthClient) {
236             mAuthClient = null;
237         } else if (client == mEnrollClient) {
238             mEnrollClient = null;
239         } else if (client == mRemoveClient) {
240             mRemoveClient = null;
241         }
242     }
243 
inLockoutMode()244     private boolean inLockoutMode() {
245         return mFailedAttempts > MAX_FAILED_ATTEMPTS;
246     }
247 
resetFailedAttempts()248     private void resetFailedAttempts() {
249         if (DEBUG && inLockoutMode()) {
250             Slog.v(TAG, "Reset fingerprint lockout");
251         }
252         mFailedAttempts = 0;
253     }
254 
handleFailedAttempt(ClientMonitor clientMonitor)255     private boolean handleFailedAttempt(ClientMonitor clientMonitor) {
256         mFailedAttempts++;
257         if (mFailedAttempts > MAX_FAILED_ATTEMPTS) {
258             // Failing multiple times will continue to push out the lockout time.
259             mHandler.removeCallbacks(mLockoutReset);
260             mHandler.postDelayed(mLockoutReset, FAIL_LOCKOUT_TIMEOUT_MS);
261             if (clientMonitor != null
262                     && !clientMonitor.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
263                 Slog.w(TAG, "Cannot send lockout message to client");
264             }
265             return true;
266         }
267         return false;
268     }
269 
removeTemplateForUser(ClientMonitor clientMonitor, int fingerId)270     private void removeTemplateForUser(ClientMonitor clientMonitor, int fingerId) {
271         mFingerprintUtils.removeFingerprintIdForUser(mContext, fingerId, clientMonitor.userId);
272     }
273 
addTemplateForUser(ClientMonitor clientMonitor, int fingerId)274     private void addTemplateForUser(ClientMonitor clientMonitor, int fingerId) {
275         mFingerprintUtils.addFingerprintForUser(mContext, fingerId, clientMonitor.userId);
276     }
277 
startEnrollment(IBinder token, byte[] cryptoToken, int groupId, IFingerprintServiceReceiver receiver, int flags, boolean restricted)278     void startEnrollment(IBinder token, byte[] cryptoToken, int groupId,
279             IFingerprintServiceReceiver receiver, int flags, boolean restricted) {
280         IFingerprintDaemon daemon = getFingerprintDaemon();
281         if (daemon == null) {
282             Slog.w(TAG, "enroll: no fingeprintd!");
283             return;
284         }
285         stopPendingOperations(true);
286         mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted);
287         final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
288         try {
289             final int result = daemon.enroll(cryptoToken, groupId, timeout);
290             if (result != 0) {
291                 Slog.w(TAG, "startEnroll failed, result=" + result);
292             }
293         } catch (RemoteException e) {
294             Slog.e(TAG, "startEnroll failed", e);
295         }
296     }
297 
startPreEnroll(IBinder token)298     public long startPreEnroll(IBinder token) {
299         IFingerprintDaemon daemon = getFingerprintDaemon();
300         if (daemon == null) {
301             Slog.w(TAG, "startPreEnroll: no fingeprintd!");
302             return 0;
303         }
304         try {
305             return daemon.preEnroll();
306         } catch (RemoteException e) {
307             Slog.e(TAG, "startPreEnroll failed", e);
308         }
309         return 0;
310     }
311 
startPostEnroll(IBinder token)312     public int startPostEnroll(IBinder token) {
313         IFingerprintDaemon daemon = getFingerprintDaemon();
314         if (daemon == null) {
315             Slog.w(TAG, "startPostEnroll: no fingeprintd!");
316             return 0;
317         }
318         try {
319             return daemon.postEnroll();
320         } catch (RemoteException e) {
321             Slog.e(TAG, "startPostEnroll failed", e);
322         }
323         return 0;
324     }
325 
stopPendingOperations(boolean initiatedByClient)326     private void stopPendingOperations(boolean initiatedByClient) {
327         if (mEnrollClient != null) {
328             stopEnrollment(mEnrollClient.token, initiatedByClient);
329         }
330         if (mAuthClient != null) {
331             stopAuthentication(mAuthClient.token, initiatedByClient);
332         }
333         // mRemoveClient is allowed to continue
334     }
335 
336     /**
337      * Stop enrollment in progress and inform client if they initiated it.
338      *
339      * @param token token for client
340      * @param initiatedByClient if this call is the result of client action (e.g. calling cancel)
341      */
stopEnrollment(IBinder token, boolean initiatedByClient)342     void stopEnrollment(IBinder token, boolean initiatedByClient) {
343         IFingerprintDaemon daemon = getFingerprintDaemon();
344         if (daemon == null) {
345             Slog.w(TAG, "stopEnrollment: no fingeprintd!");
346             return;
347         }
348         final ClientMonitor client = mEnrollClient;
349         if (client == null || client.token != token) return;
350         if (initiatedByClient) {
351             try {
352                 int result = daemon.cancelEnrollment();
353                 if (result != 0) {
354                     Slog.w(TAG, "startEnrollCancel failed, result = " + result);
355                 }
356             } catch (RemoteException e) {
357                 Slog.e(TAG, "stopEnrollment failed", e);
358             }
359             client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
360         }
361         removeClient(mEnrollClient);
362     }
363 
startAuthentication(IBinder token, long opId, int groupId, IFingerprintServiceReceiver receiver, int flags, boolean restricted)364     void startAuthentication(IBinder token, long opId, int groupId,
365             IFingerprintServiceReceiver receiver, int flags, boolean restricted) {
366         IFingerprintDaemon daemon = getFingerprintDaemon();
367         if (daemon == null) {
368             Slog.w(TAG, "startAuthentication: no fingeprintd!");
369             return;
370         }
371         stopPendingOperations(true);
372         mAuthClient = new ClientMonitor(token, receiver, groupId, restricted);
373         if (inLockoutMode()) {
374             Slog.v(TAG, "In lockout mode; disallowing authentication");
375             if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
376                 Slog.w(TAG, "Cannot send timeout message to client");
377             }
378             mAuthClient = null;
379             return;
380         }
381         try {
382             final int result = daemon.authenticate(opId, groupId);
383             if (result != 0) {
384                 Slog.w(TAG, "startAuthentication failed, result=" + result);
385             }
386         } catch (RemoteException e) {
387             Slog.e(TAG, "startAuthentication failed", e);
388         }
389     }
390 
391     /**
392      * Stop authentication in progress and inform client if they initiated it.
393      *
394      * @param token token for client
395      * @param initiatedByClient if this call is the result of client action (e.g. calling cancel)
396      */
stopAuthentication(IBinder token, boolean initiatedByClient)397     void stopAuthentication(IBinder token, boolean initiatedByClient) {
398         IFingerprintDaemon daemon = getFingerprintDaemon();
399         if (daemon == null) {
400             Slog.w(TAG, "stopAuthentication: no fingeprintd!");
401             return;
402         }
403         final ClientMonitor client = mAuthClient;
404         if (client == null || client.token != token) return;
405         if (initiatedByClient) {
406             try {
407                 int result = daemon.cancelAuthentication();
408                 if (result != 0) {
409                     Slog.w(TAG, "stopAuthentication failed, result=" + result);
410                 }
411             } catch (RemoteException e) {
412                 Slog.e(TAG, "stopAuthentication failed", e);
413             }
414             client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
415         }
416         removeClient(mAuthClient);
417     }
418 
startRemove(IBinder token, int fingerId, int userId, IFingerprintServiceReceiver receiver, boolean restricted)419     void startRemove(IBinder token, int fingerId, int userId,
420             IFingerprintServiceReceiver receiver, boolean restricted) {
421         IFingerprintDaemon daemon = getFingerprintDaemon();
422         if (daemon == null) {
423             Slog.w(TAG, "startRemove: no fingeprintd!");
424             return;
425         }
426 
427         mRemoveClient = new ClientMonitor(token, receiver, userId, restricted);
428         // The fingerprint template ids will be removed when we get confirmation from the HAL
429         try {
430             final int result = daemon.remove(fingerId, userId);
431             if (result != 0) {
432                 Slog.w(TAG, "startRemove with id = " + fingerId + " failed, result=" + result);
433             }
434         } catch (RemoteException e) {
435             Slog.e(TAG, "startRemove failed", e);
436         }
437     }
438 
getEnrolledFingerprints(int userId)439     public List<Fingerprint> getEnrolledFingerprints(int userId) {
440         return mFingerprintUtils.getFingerprintsForUser(mContext, userId);
441     }
442 
hasEnrolledFingerprints(int userId)443     public boolean hasEnrolledFingerprints(int userId) {
444         return mFingerprintUtils.getFingerprintsForUser(mContext, userId).size() > 0;
445     }
446 
hasPermission(String permission)447     boolean hasPermission(String permission) {
448         return getContext().checkCallingOrSelfPermission(permission)
449                 == PackageManager.PERMISSION_GRANTED;
450     }
451 
checkPermission(String permission)452     void checkPermission(String permission) {
453         getContext().enforceCallingOrSelfPermission(permission,
454                 "Must have " + permission + " permission.");
455     }
456 
getEffectiveUserId(int userId)457     int getEffectiveUserId(int userId) {
458         UserManager um = UserManager.get(mContext);
459         if (um != null) {
460             final long callingIdentity = Binder.clearCallingIdentity();
461             userId = um.getCredentialOwnerProfile(userId);
462             Binder.restoreCallingIdentity(callingIdentity);
463         } else {
464             Slog.e(TAG, "Unable to acquire UserManager");
465         }
466         return userId;
467     }
468 
isCurrentUserOrProfile(int userId)469     boolean isCurrentUserOrProfile(int userId) {
470         UserManager um = UserManager.get(mContext);
471 
472         // Allow current user or profiles of the current user...
473         List<UserInfo> profiles = um.getEnabledProfiles(userId);
474         final int n = profiles.size();
475         for (int i = 0; i < n; i++) {
476             if (profiles.get(i).id == userId) {
477                 return true;
478             }
479         }
480         return false;
481     }
482 
canUseFingerprint(String opPackageName)483     private boolean canUseFingerprint(String opPackageName) {
484         checkPermission(USE_FINGERPRINT);
485         return mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, Binder.getCallingUid(),
486                 opPackageName) == AppOpsManager.MODE_ALLOWED;
487     }
488 
489     private class ClientMonitor implements IBinder.DeathRecipient {
490         IBinder token;
491         IFingerprintServiceReceiver receiver;
492         int userId;
493         boolean restricted; // True if client does not have MANAGE_FINGERPRINT permission
494 
ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId, boolean restricted)495         public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId,
496                 boolean restricted) {
497             this.token = token;
498             this.receiver = receiver;
499             this.userId = userId;
500             this.restricted = restricted;
501             try {
502                 token.linkToDeath(this, 0);
503             } catch (RemoteException e) {
504                 Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
505             }
506         }
507 
destroy()508         public void destroy() {
509             if (token != null) {
510                 try {
511                     token.unlinkToDeath(this, 0);
512                 } catch (NoSuchElementException e) {
513                     // TODO: remove when duplicate call bug is found
514                     Slog.e(TAG, "destroy(): " + this + ":", new Exception("here"));
515                 }
516                 token = null;
517             }
518             receiver = null;
519         }
520 
521         @Override
binderDied()522         public void binderDied() {
523             token = null;
524             removeClient(this);
525             receiver = null;
526         }
527 
528         @Override
finalize()529         protected void finalize() throws Throwable {
530             try {
531                 if (token != null) {
532                     if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token);
533                     removeClient(this);
534                 }
535             } finally {
536                 super.finalize();
537             }
538         }
539 
540         /*
541          * @return true if we're done.
542          */
sendRemoved(int fingerId, int groupId)543         private boolean sendRemoved(int fingerId, int groupId) {
544             if (receiver == null) return true; // client not listening
545             try {
546                 receiver.onRemoved(mHalDeviceId, fingerId, groupId);
547                 return fingerId == 0;
548             } catch (RemoteException e) {
549                 Slog.w(TAG, "Failed to notify Removed:", e);
550             }
551             return false;
552         }
553 
554         /*
555          * @return true if we're done.
556          */
sendEnrollResult(int fpId, int groupId, int remaining)557         private boolean sendEnrollResult(int fpId, int groupId, int remaining) {
558             if (receiver == null) return true; // client not listening
559             FingerprintUtils.vibrateFingerprintSuccess(getContext());
560             try {
561                 receiver.onEnrollResult(mHalDeviceId, fpId, groupId, remaining);
562                 return remaining == 0;
563             } catch (RemoteException e) {
564                 Slog.w(TAG, "Failed to notify EnrollResult:", e);
565                 return true;
566             }
567         }
568 
569         /*
570          * @return true if we're done.
571          */
sendAuthenticated(int fpId, int groupId)572         private boolean sendAuthenticated(int fpId, int groupId) {
573             boolean result = false;
574             boolean authenticated = fpId != 0;
575             if (receiver != null) {
576                 try {
577                     if (!authenticated) {
578                         receiver.onAuthenticationFailed(mHalDeviceId);
579                     } else {
580                         Fingerprint fp = !restricted ?
581                                 new Fingerprint("" /* TODO */, groupId, fpId, mHalDeviceId) : null;
582                         receiver.onAuthenticationSucceeded(mHalDeviceId, fp);
583                     }
584                 } catch (RemoteException e) {
585                     Slog.w(TAG, "Failed to notify Authenticated:", e);
586                     result = true; // client failed
587                 }
588             } else {
589                 result = true; // client not listening
590 	    }
591 	    if (fpId == 0) {
592                 FingerprintUtils.vibrateFingerprintError(getContext());
593                 result |= handleFailedAttempt(this);
594             } else {
595                 FingerprintUtils.vibrateFingerprintSuccess(getContext());
596                 result |= true; // we have a valid fingerprint
597                 mLockoutReset.run();
598             }
599             return result;
600         }
601 
602         /*
603          * @return true if we're done.
604          */
sendAcquired(int acquiredInfo)605         private boolean sendAcquired(int acquiredInfo) {
606             if (receiver == null) return true; // client not listening
607             try {
608                 receiver.onAcquired(mHalDeviceId, acquiredInfo);
609                 return false; // acquisition continues...
610             } catch (RemoteException e) {
611                 Slog.w(TAG, "Failed to invoke sendAcquired:", e);
612                 return true; // client failed
613             }
614             finally {
615                 // Good scans will keep the device awake
616                 if (acquiredInfo == FINGERPRINT_ACQUIRED_GOOD) {
617                     userActivity();
618                 }
619             }
620         }
621 
622         /*
623          * @return true if we're done.
624          */
sendError(int error)625         private boolean sendError(int error) {
626             if (receiver != null) {
627                 try {
628                     receiver.onError(mHalDeviceId, error);
629                 } catch (RemoteException e) {
630                     Slog.w(TAG, "Failed to invoke sendError:", e);
631                 }
632             }
633             return true; // errors always terminate progress
634         }
635     }
636 
637     private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() {
638 
639         @Override
640         public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
641             dispatchEnrollResult(deviceId, fingerId, groupId, remaining);
642         }
643 
644         @Override
645         public void onAcquired(long deviceId, int acquiredInfo) {
646             dispatchAcquired(deviceId, acquiredInfo);
647         }
648 
649         @Override
650         public void onAuthenticated(long deviceId, int fingerId, int groupId) {
651             dispatchAuthenticated(deviceId, fingerId, groupId);
652         }
653 
654         @Override
655         public void onError(long deviceId, int error) {
656             dispatchError(deviceId, error);
657         }
658 
659         @Override
660         public void onRemoved(long deviceId, int fingerId, int groupId) {
661             dispatchRemoved(deviceId, fingerId, groupId);
662         }
663 
664         @Override
665         public void onEnumerate(long deviceId, int[] fingerIds, int[] groupIds) {
666             dispatchEnumerate(deviceId, fingerIds, groupIds);
667         }
668 
669     };
670 
671     private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
672         private static final String KEYGUARD_PACKAGE = "com.android.systemui";
673 
674         @Override // Binder call
preEnroll(IBinder token)675         public long preEnroll(IBinder token) {
676             checkPermission(MANAGE_FINGERPRINT);
677             return startPreEnroll(token);
678         }
679 
680         @Override // Binder call
postEnroll(IBinder token)681         public int postEnroll(IBinder token) {
682             checkPermission(MANAGE_FINGERPRINT);
683             return startPostEnroll(token);
684         }
685 
686         @Override // Binder call
enroll(final IBinder token, final byte[] cryptoToken, final int groupId, final IFingerprintServiceReceiver receiver, final int flags)687         public void enroll(final IBinder token, final byte[] cryptoToken, final int groupId,
688                 final IFingerprintServiceReceiver receiver, final int flags) {
689             checkPermission(MANAGE_FINGERPRINT);
690             final int limit =  mContext.getResources().getInteger(
691                     com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
692             final int callingUid = Binder.getCallingUid();
693             final int userId = UserHandle.getUserId(callingUid);
694             final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size();
695             if (enrolled >= limit) {
696                 Slog.w(TAG, "Too many fingerprints registered");
697                 return;
698             }
699             final byte [] cryptoClone = Arrays.copyOf(cryptoToken, cryptoToken.length);
700 
701             // Group ID is arbitrarily set to parent profile user ID. It just represents
702             // the default fingerprints for the user.
703             final int effectiveGroupId = getEffectiveUserId(groupId);
704 
705             final boolean restricted = isRestricted();
706             mHandler.post(new Runnable() {
707                 @Override
708                 public void run() {
709                     startEnrollment(token, cryptoClone, effectiveGroupId, receiver, flags, restricted);
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                     stopEnrollment(token, true);
727                 }
728             });
729         }
730 
731         @Override // Binder call
authenticate(final IBinder token, final long opId, final int groupId, final IFingerprintServiceReceiver receiver, final int flags, final String opPackageName)732         public void authenticate(final IBinder token, final long opId, final int groupId,
733                 final IFingerprintServiceReceiver receiver, final int flags,
734                 final String opPackageName) {
735             if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
736                 Slog.w(TAG, "Can't authenticate non-current user");
737                 return;
738             }
739             if (!canUseFingerprint(opPackageName)) {
740                 Slog.w(TAG, "Calling not granted permission to use fingerprint");
741                 return;
742             }
743 
744             // Group ID is arbitrarily set to parent profile user ID. It just represents
745             // the default fingerprints for the user.
746             final int effectiveGroupId = getEffectiveUserId(groupId);
747 
748             final boolean restricted = isRestricted();
749             mHandler.post(new Runnable() {
750                 @Override
751                 public void run() {
752                     startAuthentication(token, opId, effectiveGroupId, receiver, flags, restricted);
753                 }
754             });
755         }
756 
757         @Override // Binder call
cancelAuthentication(final IBinder token, String opPackageName)758         public void cancelAuthentication(final IBinder token, String opPackageName) {
759             if (!canUseFingerprint(opPackageName)) {
760                 return;
761             }
762             mHandler.post(new Runnable() {
763                 @Override
764                 public void run() {
765                     stopAuthentication(token, true);
766                 }
767             });
768         }
769 
770         @Override // Binder call
remove(final IBinder token, final int fingerId, final int groupId, final IFingerprintServiceReceiver receiver)771         public void remove(final IBinder token, final int fingerId, final int groupId,
772                 final IFingerprintServiceReceiver receiver) {
773             checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
774             final boolean restricted = isRestricted();
775 
776             // Group ID is arbitrarily set to parent profile user ID. It just represents
777             // the default fingerprints for the user.
778             final int effectiveGroupId = getEffectiveUserId(groupId);
779             mHandler.post(new Runnable() {
780                 @Override
781                 public void run() {
782                     startRemove(token, fingerId, effectiveGroupId, receiver, restricted);
783                 }
784             });
785 
786         }
787 
788         @Override // Binder call
isHardwareDetected(long deviceId, String opPackageName)789         public boolean isHardwareDetected(long deviceId, String opPackageName) {
790             if (!canUseFingerprint(opPackageName)) {
791                 return false;
792             }
793             return mHalDeviceId != 0;
794         }
795 
796         @Override // Binder call
rename(final int fingerId, final int groupId, final String name)797         public void rename(final int fingerId, final int groupId, final String name) {
798             checkPermission(MANAGE_FINGERPRINT);
799 
800             // Group ID is arbitrarily set to parent profile user ID. It just represents
801             // the default fingerprints for the user.
802             final int effectiveGroupId = getEffectiveUserId(groupId);
803             mHandler.post(new Runnable() {
804                 @Override
805                 public void run() {
806                     mFingerprintUtils.renameFingerprintForUser(mContext, fingerId,
807                             effectiveGroupId, name);
808                 }
809             });
810         }
811 
812         @Override // Binder call
getEnrolledFingerprints(int userId, String opPackageName)813         public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
814             if (!canUseFingerprint(opPackageName)) {
815                 return Collections.emptyList();
816             }
817             int effectiveUserId = getEffectiveUserId(userId);
818 
819             return FingerprintService.this.getEnrolledFingerprints(effectiveUserId);
820         }
821 
822         @Override // Binder call
hasEnrolledFingerprints(int userId, String opPackageName)823         public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
824             if (!canUseFingerprint(opPackageName)) {
825                 return false;
826             }
827 
828             int effectiveUserId  = getEffectiveUserId(userId);
829             return FingerprintService.this.hasEnrolledFingerprints(effectiveUserId);
830         }
831 
832         @Override // Binder call
getAuthenticatorId(String opPackageName)833         public long getAuthenticatorId(String opPackageName) {
834             // In this method, we're not checking whether the caller is permitted to use fingerprint
835             // API because current authenticator ID is leaked (in a more contrived way) via Android
836             // Keystore (android.security.keystore package): the user of that API can create a key
837             // which requires fingerprint authentication for its use, and then query the key's
838             // characteristics (hidden API) which returns, among other things, fingerprint
839             // authenticator ID which was active at key creation time.
840             //
841             // Reason: The part of Android Keystore which runs inside an app's process invokes this
842             // method in certain cases. Those cases are not always where the developer demonstrates
843             // explicit intent to use fingerprint functionality. Thus, to avoiding throwing an
844             // unexpected SecurityException this method does not check whether its caller is
845             // permitted to use fingerprint API.
846             //
847             // The permission check should be restored once Android Keystore no longer invokes this
848             // method from inside app processes.
849 
850             return FingerprintService.this.getAuthenticatorId();
851         }
852     }
853 
854     @Override
onStart()855     public void onStart() {
856         publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
857         IFingerprintDaemon daemon = getFingerprintDaemon();
858         if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
859         listenForUserSwitches();
860     }
861 
updateActiveGroup(int userId)862     private void updateActiveGroup(int userId) {
863         IFingerprintDaemon daemon = getFingerprintDaemon();
864         if (daemon != null) {
865             try {
866                 userId = getEffectiveUserId(userId);
867                 final File systemDir = Environment.getUserSystemDirectory(userId);
868                 final File fpDir = new File(systemDir, FP_DATA_DIR);
869                 if (!fpDir.exists()) {
870                     if (!fpDir.mkdir()) {
871                         Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath());
872                         return;
873                     }
874                     // Calling mkdir() from this process will create a directory with our
875                     // permissions (inherited from the containing dir). This command fixes
876                     // the label.
877                     if (!SELinux.restorecon(fpDir)) {
878                         Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
879                         return;
880                     }
881                 }
882                 daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes());
883             } catch (RemoteException e) {
884                 Slog.e(TAG, "Failed to setActiveGroup():", e);
885             }
886         }
887     }
888 
listenForUserSwitches()889     private void listenForUserSwitches() {
890         try {
891             ActivityManagerNative.getDefault().registerUserSwitchObserver(
892                 new IUserSwitchObserver.Stub() {
893                     @Override
894                     public void onUserSwitching(int newUserId, IRemoteCallback reply) {
895                         mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
896                                 .sendToTarget();
897                     }
898                     @Override
899                     public void onUserSwitchComplete(int newUserId) throws RemoteException {
900                         // Ignore.
901                     }
902                     @Override
903                     public void onForegroundProfileSwitch(int newProfileId) {
904                         // Ignore.
905                     }
906                 });
907         } catch (RemoteException e) {
908             Slog.w(TAG, "Failed to listen for user switching event" ,e);
909         }
910     }
911 
getAuthenticatorId()912     public long getAuthenticatorId() {
913         IFingerprintDaemon daemon = getFingerprintDaemon();
914         if (daemon != null) {
915             try {
916                 return daemon.getAuthenticatorId();
917             } catch (RemoteException e) {
918                 Slog.e(TAG, "getAuthenticatorId failed", e);
919             }
920         }
921         return 0;
922     }
923 
924 }
925