FingerprintService.java revision ff715ac551fcb09640acdf28278384ca2d5f85c0
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 callingUserId, 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, callingUserId, groupId, fingerId, restricted, token.toString()) {
368            @Override
369            public void notifyUserActivity() {
370                FingerprintService.this.userActivity();
371            }
372
373            @Override
374            public IFingerprintDaemon getFingerprintDaemon() {
375                return FingerprintService.this.getFingerprintDaemon();
376            }
377        };
378        startClient(client, true);
379    }
380
381    public List<Fingerprint> getEnrolledFingerprints(int userId) {
382        return mFingerprintUtils.getFingerprintsForUser(mContext, userId);
383    }
384
385    public boolean hasEnrolledFingerprints(int userId) {
386        if (userId != UserHandle.getCallingUserId()) {
387            checkPermission(INTERACT_ACROSS_USERS);
388        }
389        return mFingerprintUtils.getFingerprintsForUser(mContext, userId).size() > 0;
390    }
391
392    boolean hasPermission(String permission) {
393        return getContext().checkCallingOrSelfPermission(permission)
394                == PackageManager.PERMISSION_GRANTED;
395    }
396
397    void checkPermission(String permission) {
398        getContext().enforceCallingOrSelfPermission(permission,
399                "Must have " + permission + " permission.");
400    }
401
402    int getEffectiveUserId(int userId) {
403        UserManager um = UserManager.get(mContext);
404        if (um != null) {
405            final long callingIdentity = Binder.clearCallingIdentity();
406            userId = um.getCredentialOwnerProfile(userId);
407            Binder.restoreCallingIdentity(callingIdentity);
408        } else {
409            Slog.e(TAG, "Unable to acquire UserManager");
410        }
411        return userId;
412    }
413
414    boolean isCurrentUserOrProfile(int userId) {
415        UserManager um = UserManager.get(mContext);
416
417        // Allow current user or profiles of the current user...
418        for (int profileId : um.getEnabledProfileIds(userId)) {
419            if (profileId == userId) {
420                return true;
421            }
422        }
423        return false;
424    }
425
426    private boolean isForegroundActivity(int uid, int pid) {
427        try {
428            List<RunningAppProcessInfo> procs =
429                    ActivityManagerNative.getDefault().getRunningAppProcesses();
430            int N = procs.size();
431            for (int i = 0; i < N; i++) {
432                RunningAppProcessInfo proc = procs.get(i);
433                if (proc.pid == pid && proc.uid == uid
434                        && proc.importance == IMPORTANCE_FOREGROUND) {
435                    return true;
436                }
437            }
438        } catch (RemoteException e) {
439            Slog.w(TAG, "am.getRunningAppProcesses() failed");
440        }
441        return false;
442    }
443
444    /**
445     * @param opPackageName name of package for caller
446     * @param foregroundOnly only allow this call while app is in the foreground
447     * @return true if caller can use fingerprint API
448     */
449    private boolean canUseFingerprint(String opPackageName, boolean foregroundOnly, int uid,
450            int pid) {
451        checkPermission(USE_FINGERPRINT);
452        if (isKeyguard(opPackageName)) {
453            return true; // Keyguard is always allowed
454        }
455        if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
456            Slog.w(TAG,"Rejecting " + opPackageName + " ; not a current user or profile");
457            return false;
458        }
459        if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
460                != AppOpsManager.MODE_ALLOWED) {
461            Slog.w(TAG, "Rejecting " + opPackageName + " ; permission denied");
462            return false;
463        }
464        if (foregroundOnly && !isForegroundActivity(uid, pid)) {
465            Slog.w(TAG, "Rejecting " + opPackageName + " ; not in foreground");
466            return false;
467        }
468        return true;
469    }
470
471    /**
472     * @param clientPackage
473     * @return true if this is keyguard package
474     */
475    private boolean isKeyguard(String clientPackage) {
476        return mKeyguardPackage.equals(clientPackage);
477    }
478
479    private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
480        if (!mLockoutMonitors.contains(monitor)) {
481            mLockoutMonitors.add(monitor);
482        }
483    }
484
485    private void removeLockoutResetCallback(
486            FingerprintServiceLockoutResetMonitor monitor) {
487        mLockoutMonitors.remove(monitor);
488    }
489
490    private void notifyLockoutResetMonitors() {
491        for (int i = 0; i < mLockoutMonitors.size(); i++) {
492            mLockoutMonitors.get(i).sendLockoutReset();
493        }
494    }
495
496    private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId,
497                IFingerprintServiceReceiver receiver, int flags, boolean restricted,
498                String opPackageName) {
499        updateActiveGroup(groupId, opPackageName);
500
501        if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")");
502
503        AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token,
504                receiver, callingUserId, groupId, opId, restricted, opPackageName) {
505            @Override
506            public boolean handleFailedAttempt() {
507                mFailedAttempts++;
508                if (inLockoutMode()) {
509                    // Failing multiple times will continue to push out the lockout time.
510                    scheduleLockoutReset();
511                    return true;
512                }
513                return false;
514            }
515
516            @Override
517            public void resetFailedAttempts() {
518                FingerprintService.this.resetFailedAttempts();
519            }
520
521            @Override
522            public void notifyUserActivity() {
523                FingerprintService.this.userActivity();
524            }
525
526            @Override
527            public IFingerprintDaemon getFingerprintDaemon() {
528                return FingerprintService.this.getFingerprintDaemon();
529            }
530        };
531
532        if (inLockoutMode()) {
533            Slog.v(TAG, "In lockout mode; disallowing authentication");
534            // Don't bother starting the client. Just send the error message.
535            if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
536                Slog.w(TAG, "Cannot send timeout message to client");
537            }
538            return;
539        }
540        startClient(client, true /* initiatedByClient */);
541    }
542
543    private void startEnrollment(IBinder token, byte [] cryptoToken, int callingUserId, int groupId,
544            IFingerprintServiceReceiver receiver, int flags, boolean restricted,
545            String opPackageName) {
546        updateActiveGroup(groupId, opPackageName);
547
548        EnrollClient client = new EnrollClient(getContext(), mHalDeviceId, token, receiver,
549                callingUserId, groupId, cryptoToken, restricted, opPackageName) {
550
551            @Override
552            public IFingerprintDaemon getFingerprintDaemon() {
553                return FingerprintService.this.getFingerprintDaemon();
554            }
555
556            @Override
557            public void notifyUserActivity() {
558                FingerprintService.this.userActivity();
559            }
560        };
561        startClient(client, true /* initiatedByClient */);
562    }
563
564    protected void resetFailedAttempts() {
565        if (DEBUG && inLockoutMode()) {
566            Slog.v(TAG, "Reset fingerprint lockout");
567        }
568        mFailedAttempts = 0;
569        // If we're asked to reset failed attempts externally (i.e. from Keyguard),
570        // the alarm might still be pending; remove it.
571        cancelLockoutReset();
572        notifyLockoutResetMonitors();
573    }
574
575    private class FingerprintServiceLockoutResetMonitor {
576
577        private final IFingerprintServiceLockoutResetCallback mCallback;
578
579        public FingerprintServiceLockoutResetMonitor(
580                IFingerprintServiceLockoutResetCallback callback) {
581            mCallback = callback;
582        }
583
584        public void sendLockoutReset() {
585            if (mCallback != null) {
586                try {
587                    mCallback.onLockoutReset(mHalDeviceId);
588                } catch (DeadObjectException e) {
589                    Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
590                    mHandler.post(mRemoveCallbackRunnable);
591                } catch (RemoteException e) {
592                    Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
593                }
594            }
595        }
596
597        private final Runnable mRemoveCallbackRunnable = new Runnable() {
598            @Override
599            public void run() {
600                removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
601            }
602        };
603    }
604
605    private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() {
606
607        @Override
608        public void onEnrollResult(final long deviceId, final int fingerId, final int groupId,
609                final int remaining) {
610            mHandler.post(new Runnable() {
611                @Override
612                public void run() {
613                    handleEnrollResult(deviceId, fingerId, groupId, remaining);
614                }
615            });
616        }
617
618        @Override
619        public void onAcquired(final long deviceId, final int acquiredInfo) {
620            mHandler.post(new Runnable() {
621                @Override
622                public void run() {
623                    handleAcquired(deviceId, acquiredInfo);
624                }
625            });
626        }
627
628        @Override
629        public void onAuthenticated(final long deviceId, final int fingerId, final int groupId) {
630            mHandler.post(new Runnable() {
631                @Override
632                public void run() {
633                    handleAuthenticated(deviceId, fingerId, groupId);
634                }
635            });
636        }
637
638        @Override
639        public void onError(final long deviceId, final int error) {
640            mHandler.post(new Runnable() {
641                @Override
642                public void run() {
643                    handleError(deviceId, error);
644                }
645            });
646        }
647
648        @Override
649        public void onRemoved(final long deviceId, final int fingerId, final int groupId) {
650            mHandler.post(new Runnable() {
651                @Override
652                public void run() {
653                    handleRemoved(deviceId, fingerId, groupId);
654                }
655            });
656        }
657
658        @Override
659        public void onEnumerate(final long deviceId, final int[] fingerIds, final int[] groupIds) {
660            mHandler.post(new Runnable() {
661                @Override
662                public void run() {
663                    handleEnumerate(deviceId, fingerIds, groupIds);
664                }
665            });
666        }
667    };
668
669    private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
670        @Override // Binder call
671        public long preEnroll(IBinder token) {
672            checkPermission(MANAGE_FINGERPRINT);
673            return startPreEnroll(token);
674        }
675
676        @Override // Binder call
677        public int postEnroll(IBinder token) {
678            checkPermission(MANAGE_FINGERPRINT);
679            return startPostEnroll(token);
680        }
681
682        @Override // Binder call
683        public void enroll(final IBinder token, final byte[] cryptoToken, final int groupId,
684                final IFingerprintServiceReceiver receiver, final int flags,
685                final String opPackageName) {
686            checkPermission(MANAGE_FINGERPRINT);
687            final int limit =  mContext.getResources().getInteger(
688                    com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
689            final int callingUserId = UserHandle.getCallingUserId();
690            final int enrolled = FingerprintService.this.
691                    getEnrolledFingerprints(callingUserId).size();
692            if (enrolled >= limit) {
693                Slog.w(TAG, "Too many fingerprints registered");
694                return;
695            }
696
697            // Group ID is arbitrarily set to parent profile user ID. It just represents
698            // the default fingerprints for the user.
699            if (!isCurrentUserOrProfile(groupId)) {
700                return;
701            }
702
703            final boolean restricted = isRestricted();
704            mHandler.post(new Runnable() {
705                @Override
706                public void run() {
707                    startEnrollment(token, cryptoToken, callingUserId, groupId, receiver, flags,
708                            restricted, opPackageName);
709                }
710            });
711        }
712
713        private boolean isRestricted() {
714            // Only give privileged apps (like Settings) access to fingerprint info
715            final boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
716            return restricted;
717        }
718
719        @Override // Binder call
720        public void cancelEnrollment(final IBinder token) {
721            checkPermission(MANAGE_FINGERPRINT);
722            mHandler.post(new Runnable() {
723                @Override
724                public void run() {
725                    ClientMonitor client = mCurrentClient;
726                    if (client instanceof EnrollClient && client.getToken() == token) {
727                        client.stop(client.getToken() == token);
728                    }
729                }
730            });
731        }
732
733        @Override // Binder call
734        public void authenticate(final IBinder token, final long opId, final int groupId,
735                final IFingerprintServiceReceiver receiver, final int flags,
736                final String opPackageName) {
737            final int callingUid = Binder.getCallingUid();
738            final int callingUserId = UserHandle.getCallingUserId();
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                            callingUid, pid)) {
747                        if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
748                        return;
749                    }
750                    startAuthentication(token, opId, callingUserId, 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 callingUserId = UserHandle.getCallingUserId();
801            mHandler.post(new Runnable() {
802                @Override
803                public void run() {
804                    startRemove(token, fingerId, callingUserId, 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