Home | History | Annotate | Download | only in fingerprint
      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 
    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
    195     public void binderDied() {
    196         Slog.v(TAG, "fingerprintd died");
    197         mDaemon = null;
    198         handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
    199     }
    200 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    292     private void userActivity() {
    293         long now = SystemClock.uptimeMillis();
    294         mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
    295     }
    296 
    297     void handleUserSwitching(int userId) {
    298         updateActiveGroup(userId, null);
    299     }
    300 
    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 
    315     private boolean inLockoutMode() {
    316         return mFailedAttempts >= MAX_FAILED_ATTEMPTS;
    317     }
    318 
    319     private void scheduleLockoutReset() {
    320         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    321                 SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS, getLockoutResetIntent());
    322     }
    323 
    324     private void cancelLockoutReset() {
    325         mAlarmManager.cancel(getLockoutResetIntent());
    326     }
    327 
    328     private PendingIntent getLockoutResetIntent() {
    329         return PendingIntent.getBroadcast(mContext, 0,
    330                 new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT);
    331     }
    332 
    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 
    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      */
    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 
    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 
    408     public List<Fingerprint> getEnrolledFingerprints(int userId) {
    409         return mFingerprintUtils.getFingerprintsForUser(mContext, userId);
    410     }
    411 
    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 
    419     boolean hasPermission(String permission) {
    420         return getContext().checkCallingOrSelfPermission(permission)
    421                 == PackageManager.PERMISSION_GRANTED;
    422     }
    423 
    424     void checkPermission(String permission) {
    425         getContext().enforceCallingOrSelfPermission(permission,
    426                 "Must have " + permission + " permission.");
    427     }
    428 
    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 
    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 
    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      */
    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      */
    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      */
    510     private boolean isKeyguard(String clientPackage) {
    511         return mKeyguardPackage.equals(clientPackage);
    512     }
    513 
    514     private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
    515         if (!mLockoutMonitors.contains(monitor)) {
    516             mLockoutMonitors.add(monitor);
    517         }
    518     }
    519 
    520     private void removeLockoutResetCallback(
    521             FingerprintServiceLockoutResetMonitor monitor) {
    522         mLockoutMonitors.remove(monitor);
    523     }
    524 
    525     private void notifyLockoutResetMonitors() {
    526         for (int i = 0; i < mLockoutMonitors.size(); i++) {
    527             mLockoutMonitors.get(i).sendLockoutReset();
    528         }
    529     }
    530 
    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 
    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 
    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 
    619         public FingerprintServiceLockoutResetMonitor(
    620                 IFingerprintServiceLockoutResetCallback callback) {
    621             mCallback = callback;
    622         }
    623 
    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
    711         public long preEnroll(IBinder token) {
    712             checkPermission(MANAGE_FINGERPRINT);
    713             return startPreEnroll(token);
    714         }
    715 
    716         @Override // Binder call
    717         public int postEnroll(IBinder token) {
    718             checkPermission(MANAGE_FINGERPRINT);
    719             return startPostEnroll(token);
    720         }
    721 
    722         @Override // Binder call
    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 
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    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
   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 
   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      */
   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      */
   1057     private boolean isWorkProfile(int userId) {
   1058         UserInfo info = mUserManager.getUserInfo(userId);
   1059         return info != null && info.isManagedProfile();
   1060     }
   1061 
   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      */
   1089     public long getAuthenticatorId(String opPackageName) {
   1090         return mCurrentAuthenticatorId;
   1091     }
   1092 
   1093 }
   1094