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