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 android.hardware.fingerprint;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.RequiresPermission;
22 import android.annotation.SystemService;
23 import android.app.ActivityManager;
24 import android.content.Context;
25 import android.os.Binder;
26 import android.os.CancellationSignal;
27 import android.os.CancellationSignal.OnCancelListener;
28 import android.os.Handler;
29 import android.os.IBinder;
30 import android.os.IRemoteCallback;
31 import android.os.Looper;
32 import android.os.PowerManager;
33 import android.os.RemoteException;
34 import android.os.UserHandle;
35 import android.security.keystore.AndroidKeyStoreProvider;
36 import android.util.Log;
37 import android.util.Slog;
38 
39 import java.security.Signature;
40 import java.util.List;
41 
42 import javax.crypto.Cipher;
43 import javax.crypto.Mac;
44 
45 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
46 import static android.Manifest.permission.MANAGE_FINGERPRINT;
47 import static android.Manifest.permission.USE_FINGERPRINT;
48 
49 /**
50  * A class that coordinates access to the fingerprint hardware.
51  */
52 @SystemService(Context.FINGERPRINT_SERVICE)
53 public class FingerprintManager {
54     private static final String TAG = "FingerprintManager";
55     private static final boolean DEBUG = true;
56     private static final int MSG_ENROLL_RESULT = 100;
57     private static final int MSG_ACQUIRED = 101;
58     private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
59     private static final int MSG_AUTHENTICATION_FAILED = 103;
60     private static final int MSG_ERROR = 104;
61     private static final int MSG_REMOVED = 105;
62     private static final int MSG_ENUMERATED = 106;
63 
64     //
65     // Error messages from fingerprint hardware during initilization, enrollment, authentication or
66     // removal. Must agree with the list in fingerprint.h
67     //
68 
69     /**
70      * The hardware is unavailable. Try again later.
71      */
72     public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
73 
74     /**
75      * Error state returned when the sensor was unable to process the current image.
76      */
77     public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2;
78 
79     /**
80      * Error state returned when the current request has been running too long. This is intended to
81      * prevent programs from waiting for the fingerprint sensor indefinitely. The timeout is
82      * platform and sensor-specific, but is generally on the order of 30 seconds.
83      */
84     public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
85 
86     /**
87      * Error state returned for operations like enrollment; the operation cannot be completed
88      * because there's not enough storage remaining to complete the operation.
89      */
90     public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
91 
92     /**
93      * The operation was canceled because the fingerprint sensor is unavailable. For example,
94      * this may happen when the user is switched, the device is locked or another pending operation
95      * prevents or disables it.
96      */
97     public static final int FINGERPRINT_ERROR_CANCELED = 5;
98 
99     /**
100      * The {@link FingerprintManager#remove} call failed. Typically this will happen when the
101      * provided fingerprint id was incorrect.
102      *
103      * @hide
104      */
105     public static final int FINGERPRINT_ERROR_UNABLE_TO_REMOVE = 6;
106 
107    /**
108      * The operation was canceled because the API is locked out due to too many attempts.
109      */
110     public static final int FINGERPRINT_ERROR_LOCKOUT = 7;
111 
112     /**
113      * Hardware vendors may extend this list if there are conditions that do not fall under one of
114      * the above categories. Vendors are responsible for providing error strings for these errors.
115      * @hide
116      */
117     public static final int FINGERPRINT_ERROR_VENDOR = 8;
118 
119     /**
120      * The operation was canceled because FINGERPRINT_ERROR_LOCKOUT occurred too many times.
121      * Fingerprint authentication is disabled until the user unlocks with strong authentication
122      * (PIN/Pattern/Password)
123      * @hide
124      */
125     public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9;
126 
127     /**
128      * @hide
129      */
130     public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
131 
132     //
133     // Image acquisition messages. Must agree with those in fingerprint.h
134     //
135 
136     /**
137      * The image acquired was good.
138      */
139     public static final int FINGERPRINT_ACQUIRED_GOOD = 0;
140 
141     /**
142      * Only a partial fingerprint image was detected. During enrollment, the user should be
143      * informed on what needs to happen to resolve this problem, e.g. "press firmly on sensor."
144      */
145     public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1;
146 
147     /**
148      * The fingerprint image was too noisy to process due to a detected condition (i.e. dry skin) or
149      * a possibly dirty sensor (See {@link #FINGERPRINT_ACQUIRED_IMAGER_DIRTY}).
150      */
151     public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2;
152 
153     /**
154      * The fingerprint image was too noisy due to suspected or detected dirt on the sensor.
155      * For example, it's reasonable return this after multiple
156      * {@link #FINGERPRINT_ACQUIRED_INSUFFICIENT} or actual detection of dirt on the sensor
157      * (stuck pixels, swaths, etc.). The user is expected to take action to clean the sensor
158      * when this is returned.
159      */
160     public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3;
161 
162     /**
163      * The fingerprint image was unreadable due to lack of motion. This is most appropriate for
164      * linear array sensors that require a swipe motion.
165      */
166     public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4;
167 
168     /**
169      * The fingerprint image was incomplete due to quick motion. While mostly appropriate for
170      * linear array sensors,  this could also happen if the finger was moved during acquisition.
171      * The user should be asked to move the finger slower (linear) or leave the finger on the sensor
172      * longer.
173      */
174     public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5;
175 
176     /**
177      * Hardware vendors may extend this list if there are conditions that do not fall under one of
178      * the above categories. Vendors are responsible for providing error strings for these errors.
179      * @hide
180      */
181     public static final int FINGERPRINT_ACQUIRED_VENDOR = 6;
182     /**
183      * @hide
184      */
185     public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
186 
187     private IFingerprintService mService;
188     private Context mContext;
189     private IBinder mToken = new Binder();
190     private AuthenticationCallback mAuthenticationCallback;
191     private EnrollmentCallback mEnrollmentCallback;
192     private RemovalCallback mRemovalCallback;
193     private EnumerateCallback mEnumerateCallback;
194     private CryptoObject mCryptoObject;
195     private Fingerprint mRemovalFingerprint;
196     private Handler mHandler;
197 
198     private class OnEnrollCancelListener implements OnCancelListener {
199         @Override
onCancel()200         public void onCancel() {
201             cancelEnrollment();
202         }
203     }
204 
205     private class OnAuthenticationCancelListener implements OnCancelListener {
206         private CryptoObject mCrypto;
207 
OnAuthenticationCancelListener(CryptoObject crypto)208         public OnAuthenticationCancelListener(CryptoObject crypto) {
209             mCrypto = crypto;
210         }
211 
212         @Override
onCancel()213         public void onCancel() {
214             cancelAuthentication(mCrypto);
215         }
216     }
217 
218     /**
219      * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
220      * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
221      */
222     public static final class CryptoObject {
223 
CryptoObject(@onNull Signature signature)224         public CryptoObject(@NonNull Signature signature) {
225             mCrypto = signature;
226         }
227 
CryptoObject(@onNull Cipher cipher)228         public CryptoObject(@NonNull Cipher cipher) {
229             mCrypto = cipher;
230         }
231 
CryptoObject(@onNull Mac mac)232         public CryptoObject(@NonNull Mac mac) {
233             mCrypto = mac;
234         }
235 
236         /**
237          * Get {@link Signature} object.
238          * @return {@link Signature} object or null if this doesn't contain one.
239          */
getSignature()240         public Signature getSignature() {
241             return mCrypto instanceof Signature ? (Signature) mCrypto : null;
242         }
243 
244         /**
245          * Get {@link Cipher} object.
246          * @return {@link Cipher} object or null if this doesn't contain one.
247          */
getCipher()248         public Cipher getCipher() {
249             return mCrypto instanceof Cipher ? (Cipher) mCrypto : null;
250         }
251 
252         /**
253          * Get {@link Mac} object.
254          * @return {@link Mac} object or null if this doesn't contain one.
255          */
getMac()256         public Mac getMac() {
257             return mCrypto instanceof Mac ? (Mac) mCrypto : null;
258         }
259 
260         /**
261          * @hide
262          * @return the opId associated with this object or 0 if none
263          */
getOpId()264         public long getOpId() {
265             return mCrypto != null ?
266                     AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto) : 0;
267         }
268 
269         private final Object mCrypto;
270     };
271 
272     /**
273      * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
274      *     CancellationSignal, int, AuthenticationCallback, Handler)}.
275      */
276     public static class AuthenticationResult {
277         private Fingerprint mFingerprint;
278         private CryptoObject mCryptoObject;
279         private int mUserId;
280 
281         /**
282          * Authentication result
283          *
284          * @param crypto the crypto object
285          * @param fingerprint the recognized fingerprint data, if allowed.
286          * @hide
287          */
AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint, int userId)288         public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint, int userId) {
289             mCryptoObject = crypto;
290             mFingerprint = fingerprint;
291             mUserId = userId;
292         }
293 
294         /**
295          * Obtain the crypto object associated with this transaction
296          * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject,
297          *     CancellationSignal, int, AuthenticationCallback, Handler)}.
298          */
getCryptoObject()299         public CryptoObject getCryptoObject() { return mCryptoObject; }
300 
301         /**
302          * Obtain the Fingerprint associated with this operation. Applications are strongly
303          * discouraged from associating specific fingers with specific applications or operations.
304          *
305          * @hide
306          */
getFingerprint()307         public Fingerprint getFingerprint() { return mFingerprint; }
308 
309         /**
310          * Obtain the userId for which this fingerprint was authenticated.
311          * @hide
312          */
getUserId()313         public int getUserId() { return mUserId; }
314     };
315 
316     /**
317      * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject,
318      * CancellationSignal, int, AuthenticationCallback, Handler)}. Users of {@link
319      * FingerprintManager#authenticate(CryptoObject, CancellationSignal,
320      * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
321      * fingerprint events.
322      */
323     public static abstract class AuthenticationCallback {
324         /**
325          * Called when an unrecoverable error has been encountered and the operation is complete.
326          * No further callbacks will be made on this object.
327          * @param errorCode An integer identifying the error message
328          * @param errString A human-readable error string that can be shown in UI
329          */
onAuthenticationError(int errorCode, CharSequence errString)330         public void onAuthenticationError(int errorCode, CharSequence errString) { }
331 
332         /**
333          * Called when a recoverable error has been encountered during authentication. The help
334          * string is provided to give the user guidance for what went wrong, such as
335          * "Sensor dirty, please clean it."
336          * @param helpCode An integer identifying the error message
337          * @param helpString A human-readable string that can be shown in UI
338          */
onAuthenticationHelp(int helpCode, CharSequence helpString)339         public void onAuthenticationHelp(int helpCode, CharSequence helpString) { }
340 
341         /**
342          * Called when a fingerprint is recognized.
343          * @param result An object containing authentication-related data
344          */
onAuthenticationSucceeded(AuthenticationResult result)345         public void onAuthenticationSucceeded(AuthenticationResult result) { }
346 
347         /**
348          * Called when a fingerprint is valid but not recognized.
349          */
onAuthenticationFailed()350         public void onAuthenticationFailed() { }
351 
352         /**
353          * Called when a fingerprint image has been acquired, but wasn't processed yet.
354          *
355          * @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants
356          * @hide
357          */
onAuthenticationAcquired(int acquireInfo)358         public void onAuthenticationAcquired(int acquireInfo) {}
359     };
360 
361     /**
362      * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback,
363      * CancellationSignal, int). Users of {@link #FingerprintManager()}
364      * must provide an implementation of this to {@link FingerprintManager#enroll(long,
365      * CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events.
366      *
367      * @hide
368      */
369     public static abstract class EnrollmentCallback {
370         /**
371          * Called when an unrecoverable error has been encountered and the operation is complete.
372          * No further callbacks will be made on this object.
373          * @param errMsgId An integer identifying the error message
374          * @param errString A human-readable error string that can be shown in UI
375          */
onEnrollmentError(int errMsgId, CharSequence errString)376         public void onEnrollmentError(int errMsgId, CharSequence errString) { }
377 
378         /**
379          * Called when a recoverable error has been encountered during enrollment. The help
380          * string is provided to give the user guidance for what went wrong, such as
381          * "Sensor dirty, please clean it" or what they need to do next, such as
382          * "Touch sensor again."
383          * @param helpMsgId An integer identifying the error message
384          * @param helpString A human-readable string that can be shown in UI
385          */
onEnrollmentHelp(int helpMsgId, CharSequence helpString)386         public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { }
387 
388         /**
389          * Called as each enrollment step progresses. Enrollment is considered complete when
390          * remaining reaches 0. This function will not be called if enrollment fails. See
391          * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)}
392          * @param remaining The number of remaining steps
393          */
onEnrollmentProgress(int remaining)394         public void onEnrollmentProgress(int remaining) { }
395     };
396 
397     /**
398      * Callback structure provided to {@link #remove}. Users of {@link FingerprintManager} may
399      * optionally provide an implementation of this to
400      * {@link #remove(Fingerprint, int, RemovalCallback)} for listening to fingerprint template
401      * removal events.
402      *
403      * @hide
404      */
405     public static abstract class RemovalCallback {
406         /**
407          * Called when the given fingerprint can't be removed.
408          * @param fp The fingerprint that the call attempted to remove
409          * @param errMsgId An associated error message id
410          * @param errString An error message indicating why the fingerprint id can't be removed
411          */
onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString)412         public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) { }
413 
414         /**
415          * Called when a given fingerprint is successfully removed.
416          * @param fp The fingerprint template that was removed.
417          * @param remaining The number of fingerprints yet to be removed in this operation. If
418          *         {@link #remove} is called on one fingerprint, this should be 0. If
419          *         {@link #remove} is called on a group, this should be the number of remaining
420          *         fingerprints in the group, and 0 after the last fingerprint is removed.
421          */
onRemovalSucceeded(Fingerprint fp, int remaining)422         public void onRemovalSucceeded(Fingerprint fp, int remaining) { }
423     };
424 
425     /**
426      * Callback structure provided to {@link FingerprintManager#enumerate(int). Users of
427      * {@link #FingerprintManager()} may optionally provide an implementation of this to
428      * {@link FingerprintManager#enumerate(int, int, EnumerateCallback)} for listening to
429      * fingerprint template removal events.
430      *
431      * @hide
432      */
433     public static abstract class EnumerateCallback {
434         /**
435          * Called when the given fingerprint can't be removed.
436          * @param errMsgId An associated error message id
437          * @param errString An error message indicating why the fingerprint id can't be removed
438          */
onEnumerateError(int errMsgId, CharSequence errString)439         public void onEnumerateError(int errMsgId, CharSequence errString) { }
440 
441         /**
442          * Called when a given fingerprint is successfully removed.
443          * @param fingerprint the fingerprint template that was removed.
444          */
onEnumerate(Fingerprint fingerprint)445         public void onEnumerate(Fingerprint fingerprint) { }
446     };
447 
448     /**
449      * @hide
450      */
451     public static abstract class LockoutResetCallback {
452 
453         /**
454          * Called when lockout period expired and clients are allowed to listen for fingerprint
455          * again.
456          */
onLockoutReset()457         public void onLockoutReset() { }
458     };
459 
460     /**
461      * Request authentication of a crypto object. This call warms up the fingerprint hardware
462      * and starts scanning for a fingerprint. It terminates when
463      * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
464      * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
465      * which point the object is no longer valid. The operation can be canceled by using the
466      * provided cancel object.
467      *
468      * @param crypto object associated with the call or null if none required.
469      * @param cancel an object that can be used to cancel authentication
470      * @param flags optional flags; should be 0
471      * @param callback an object to receive authentication events
472      * @param handler an optional handler to handle callback events
473      *
474      * @throws IllegalArgumentException if the crypto operation is not supported or is not backed
475      *         by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
476      *         facility</a>.
477      * @throws IllegalStateException if the crypto primitive is not initialized.
478      */
479     @RequiresPermission(USE_FINGERPRINT)
authenticate(@ullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler)480     public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
481             int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
482         authenticate(crypto, cancel, flags, callback, handler, UserHandle.myUserId());
483     }
484 
485     /**
486      * Use the provided handler thread for events.
487      * @param handler
488      */
useHandler(Handler handler)489     private void useHandler(Handler handler) {
490         if (handler != null) {
491             mHandler = new MyHandler(handler.getLooper());
492         } else if (mHandler.getLooper() != mContext.getMainLooper()){
493             mHandler = new MyHandler(mContext.getMainLooper());
494         }
495     }
496 
497     /**
498      * Per-user version
499      * @hide
500      */
501     @RequiresPermission(USE_FINGERPRINT)
authenticate(@ullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId)502     public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
503             int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
504         if (callback == null) {
505             throw new IllegalArgumentException("Must supply an authentication callback");
506         }
507 
508         if (cancel != null) {
509             if (cancel.isCanceled()) {
510                 Log.w(TAG, "authentication already canceled");
511                 return;
512             } else {
513                 cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
514             }
515         }
516 
517         if (mService != null) try {
518             useHandler(handler);
519             mAuthenticationCallback = callback;
520             mCryptoObject = crypto;
521             long sessionId = crypto != null ? crypto.getOpId() : 0;
522             mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
523                     mContext.getOpPackageName());
524         } catch (RemoteException e) {
525             Log.w(TAG, "Remote exception while authenticating: ", e);
526             if (callback != null) {
527                 // Though this may not be a hardware issue, it will cause apps to give up or try
528                 // again later.
529                 callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
530                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
531             }
532         }
533     }
534 
535     /**
536      * Request fingerprint enrollment. This call warms up the fingerprint hardware
537      * and starts scanning for fingerprints. Progress will be indicated by callbacks to the
538      * {@link EnrollmentCallback} object. It terminates when
539      * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
540      * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
541      * which point the object is no longer valid. The operation can be canceled by using the
542      * provided cancel object.
543      * @param token a unique token provided by a recent creation or verification of device
544      * credentials (e.g. pin, pattern or password).
545      * @param cancel an object that can be used to cancel enrollment
546      * @param flags optional flags
547      * @param userId the user to whom this fingerprint will belong to
548      * @param callback an object to receive enrollment events
549      * @hide
550      */
551     @RequiresPermission(MANAGE_FINGERPRINT)
enroll(byte [] token, CancellationSignal cancel, int flags, int userId, EnrollmentCallback callback)552     public void enroll(byte [] token, CancellationSignal cancel, int flags,
553             int userId, EnrollmentCallback callback) {
554         if (userId == UserHandle.USER_CURRENT) {
555             userId = getCurrentUserId();
556         }
557         if (callback == null) {
558             throw new IllegalArgumentException("Must supply an enrollment callback");
559         }
560 
561         if (cancel != null) {
562             if (cancel.isCanceled()) {
563                 Log.w(TAG, "enrollment already canceled");
564                 return;
565             } else {
566                 cancel.setOnCancelListener(new OnEnrollCancelListener());
567             }
568         }
569 
570         if (mService != null) try {
571             mEnrollmentCallback = callback;
572             mService.enroll(mToken, token, userId, mServiceReceiver, flags,
573                     mContext.getOpPackageName());
574         } catch (RemoteException e) {
575             Log.w(TAG, "Remote exception in enroll: ", e);
576             if (callback != null) {
577                 // Though this may not be a hardware issue, it will cause apps to give up or try
578                 // again later.
579                 callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
580                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
581             }
582         }
583     }
584 
585     /**
586      * Requests a pre-enrollment auth token to tie enrollment to the confirmation of
587      * existing device credentials (e.g. pin/pattern/password).
588      * @hide
589      */
590     @RequiresPermission(MANAGE_FINGERPRINT)
preEnroll()591     public long preEnroll() {
592         long result = 0;
593         if (mService != null) try {
594             result = mService.preEnroll(mToken);
595         } catch (RemoteException e) {
596             throw e.rethrowFromSystemServer();
597         }
598         return result;
599     }
600 
601     /**
602      * Finishes enrollment and cancels the current auth token.
603      * @hide
604      */
605     @RequiresPermission(MANAGE_FINGERPRINT)
postEnroll()606     public int postEnroll() {
607         int result = 0;
608         if (mService != null) try {
609             result = mService.postEnroll(mToken);
610         } catch (RemoteException e) {
611             throw e.rethrowFromSystemServer();
612         }
613         return result;
614     }
615 
616     /**
617      * Sets the active user. This is meant to be used to select the current profile for enrollment
618      * to allow separate enrolled fingers for a work profile
619      * @param userId
620      * @hide
621      */
622     @RequiresPermission(MANAGE_FINGERPRINT)
setActiveUser(int userId)623     public void setActiveUser(int userId) {
624         if (mService != null) try {
625             mService.setActiveUser(userId);
626         } catch (RemoteException e) {
627             throw e.rethrowFromSystemServer();
628         }
629     }
630 
631     /**
632      * Remove given fingerprint template from fingerprint hardware and/or protected storage.
633      * @param fp the fingerprint item to remove
634      * @param userId the user who this fingerprint belongs to
635      * @param callback an optional callback to verify that fingerprint templates have been
636      * successfully removed. May be null of no callback is required.
637      *
638      * @hide
639      */
640     @RequiresPermission(MANAGE_FINGERPRINT)
remove(Fingerprint fp, int userId, RemovalCallback callback)641     public void remove(Fingerprint fp, int userId, RemovalCallback callback) {
642         if (mService != null) try {
643             mRemovalCallback = callback;
644             mRemovalFingerprint = fp;
645             mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver);
646         } catch (RemoteException e) {
647             Log.w(TAG, "Remote exception in remove: ", e);
648             if (callback != null) {
649                 callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
650                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
651             }
652         }
653     }
654 
655     /**
656      * Enumerate all fingerprint templates stored in hardware and/or protected storage.
657      * @param userId the user who this fingerprint belongs to
658      * @param callback an optional callback to verify that fingerprint templates have been
659      * successfully removed. May be null of no callback is required.
660      *
661      * @hide
662      */
663     @RequiresPermission(MANAGE_FINGERPRINT)
enumerate(int userId, @NonNull EnumerateCallback callback)664     public void enumerate(int userId, @NonNull EnumerateCallback callback) {
665         if (mService != null) try {
666             mEnumerateCallback = callback;
667             mService.enumerate(mToken, userId, mServiceReceiver);
668         } catch (RemoteException e) {
669             Log.w(TAG, "Remote exception in enumerate: ", e);
670             if (callback != null) {
671                 callback.onEnumerateError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
672                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
673             }
674         }
675     }
676 
677     /**
678      * Renames the given fingerprint template
679      * @param fpId the fingerprint id
680      * @param userId the user who this fingerprint belongs to
681      * @param newName the new name
682      *
683      * @hide
684      */
685     @RequiresPermission(MANAGE_FINGERPRINT)
rename(int fpId, int userId, String newName)686     public void rename(int fpId, int userId, String newName) {
687         // Renames the given fpId
688         if (mService != null) {
689             try {
690                 mService.rename(fpId, userId, newName);
691             } catch (RemoteException e) {
692                 throw e.rethrowFromSystemServer();
693             }
694         } else {
695             Log.w(TAG, "rename(): Service not connected!");
696         }
697     }
698 
699     /**
700      * Obtain the list of enrolled fingerprints templates.
701      * @return list of current fingerprint items
702      *
703      * @hide
704      */
705     @RequiresPermission(USE_FINGERPRINT)
getEnrolledFingerprints(int userId)706     public List<Fingerprint> getEnrolledFingerprints(int userId) {
707         if (mService != null) try {
708             return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
709         } catch (RemoteException e) {
710             throw e.rethrowFromSystemServer();
711         }
712         return null;
713     }
714 
715     /**
716      * Obtain the list of enrolled fingerprints templates.
717      * @return list of current fingerprint items
718      *
719      * @hide
720      */
721     @RequiresPermission(USE_FINGERPRINT)
getEnrolledFingerprints()722     public List<Fingerprint> getEnrolledFingerprints() {
723         return getEnrolledFingerprints(UserHandle.myUserId());
724     }
725 
726     /**
727      * Determine if there is at least one fingerprint enrolled.
728      *
729      * @return true if at least one fingerprint is enrolled, false otherwise
730      */
731     @RequiresPermission(USE_FINGERPRINT)
hasEnrolledFingerprints()732     public boolean hasEnrolledFingerprints() {
733         if (mService != null) try {
734             return mService.hasEnrolledFingerprints(
735                     UserHandle.myUserId(), mContext.getOpPackageName());
736         } catch (RemoteException e) {
737             throw e.rethrowFromSystemServer();
738         }
739         return false;
740     }
741 
742     /**
743      * @hide
744      */
745     @RequiresPermission(allOf = {
746             USE_FINGERPRINT,
747             INTERACT_ACROSS_USERS})
hasEnrolledFingerprints(int userId)748     public boolean hasEnrolledFingerprints(int userId) {
749         if (mService != null) try {
750             return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName());
751         } catch (RemoteException e) {
752             throw e.rethrowFromSystemServer();
753         }
754         return false;
755     }
756 
757     /**
758      * Determine if fingerprint hardware is present and functional.
759      *
760      * @return true if hardware is present and functional, false otherwise.
761      */
762     @RequiresPermission(USE_FINGERPRINT)
isHardwareDetected()763     public boolean isHardwareDetected() {
764         if (mService != null) {
765             try {
766                 long deviceId = 0; /* TODO: plumb hardware id to FPMS */
767                 return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
768             } catch (RemoteException e) {
769                 throw e.rethrowFromSystemServer();
770             }
771         } else {
772             Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
773         }
774         return false;
775     }
776 
777     /**
778      * Retrieves the authenticator token for binding keys to the lifecycle
779      * of the calling user's fingerprints. Used only by internal clients.
780      *
781      * @hide
782      */
getAuthenticatorId()783     public long getAuthenticatorId() {
784         if (mService != null) {
785             try {
786                 return mService.getAuthenticatorId(mContext.getOpPackageName());
787             } catch (RemoteException e) {
788                 throw e.rethrowFromSystemServer();
789             }
790         } else {
791             Log.w(TAG, "getAuthenticatorId(): Service not connected!");
792         }
793         return 0;
794     }
795 
796     /**
797      * Reset the lockout timer when asked to do so by keyguard.
798      *
799      * @param token an opaque token returned by password confirmation.
800      *
801      * @hide
802      */
resetTimeout(byte[] token)803     public void resetTimeout(byte[] token) {
804         if (mService != null) {
805             try {
806                 mService.resetTimeout(token);
807             } catch (RemoteException e) {
808                 throw e.rethrowFromSystemServer();
809             }
810         } else {
811             Log.w(TAG, "resetTimeout(): Service not connected!");
812         }
813     }
814 
815     /**
816      * @hide
817      */
addLockoutResetCallback(final LockoutResetCallback callback)818     public void addLockoutResetCallback(final LockoutResetCallback callback) {
819         if (mService != null) {
820             try {
821                 final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
822                 mService.addLockoutResetCallback(
823                         new IFingerprintServiceLockoutResetCallback.Stub() {
824 
825                     @Override
826                     public void onLockoutReset(long deviceId, IRemoteCallback serverCallback)
827                             throws RemoteException {
828                         try {
829                             final PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
830                                     PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback");
831                             wakeLock.acquire();
832                             mHandler.post(() -> {
833                                 try {
834                                     callback.onLockoutReset();
835                                 } finally {
836                                     wakeLock.release();
837                                 }
838                             });
839                         } finally {
840                             serverCallback.sendResult(null /* data */);
841                         }
842                     }
843                 });
844             } catch (RemoteException e) {
845                 throw e.rethrowFromSystemServer();
846             }
847         } else {
848             Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
849         }
850     }
851 
852     private class MyHandler extends Handler {
MyHandler(Context context)853         private MyHandler(Context context) {
854             super(context.getMainLooper());
855         }
856 
MyHandler(Looper looper)857         private MyHandler(Looper looper) {
858             super(looper);
859         }
860 
861         @Override
handleMessage(android.os.Message msg)862         public void handleMessage(android.os.Message msg) {
863             switch(msg.what) {
864                 case MSG_ENROLL_RESULT:
865                     sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
866                     break;
867                 case MSG_ACQUIRED:
868                     sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */,
869                             msg.arg2 /* vendorCode */);
870                     break;
871                 case MSG_AUTHENTICATION_SUCCEEDED:
872                     sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */);
873                     break;
874                 case MSG_AUTHENTICATION_FAILED:
875                     sendAuthenticatedFailed();
876                     break;
877                 case MSG_ERROR:
878                     sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */,
879                             msg.arg2 /* vendorCode */);
880                     break;
881                 case MSG_REMOVED:
882                     sendRemovedResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
883                     break;
884                 case MSG_ENUMERATED:
885                     sendEnumeratedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
886                             msg.arg2 /* groupId */);
887                     break;
888             }
889         }
890 
sendRemovedResult(Fingerprint fingerprint, int remaining)891         private void sendRemovedResult(Fingerprint fingerprint, int remaining) {
892             if (mRemovalCallback == null) {
893                 return;
894             }
895             if (fingerprint == null) {
896                 Log.e(TAG, "Received MSG_REMOVED, but fingerprint is null");
897                 return;
898             }
899 
900             int fingerId = fingerprint.getFingerId();
901             int reqFingerId = mRemovalFingerprint.getFingerId();
902             if (reqFingerId != 0 && fingerId != 0 && fingerId != reqFingerId) {
903                 Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
904                 return;
905             }
906             int groupId = fingerprint.getGroupId();
907             int reqGroupId = mRemovalFingerprint.getGroupId();
908             if (groupId != reqGroupId) {
909                 Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
910                 return;
911             }
912 
913             mRemovalCallback.onRemovalSucceeded(fingerprint, remaining);
914         }
915 
sendEnumeratedResult(long deviceId, int fingerId, int groupId)916         private void sendEnumeratedResult(long deviceId, int fingerId, int groupId) {
917             if (mEnumerateCallback != null) {
918                 mEnumerateCallback.onEnumerate(new Fingerprint(null, groupId, fingerId, deviceId));
919             }
920         }
921 
sendErrorResult(long deviceId, int errMsgId, int vendorCode)922         private void sendErrorResult(long deviceId, int errMsgId, int vendorCode) {
923             // emulate HAL 2.1 behavior and send real errMsgId
924             final int clientErrMsgId = errMsgId == FINGERPRINT_ERROR_VENDOR
925                     ? (vendorCode + FINGERPRINT_ERROR_VENDOR_BASE) : errMsgId;
926             if (mEnrollmentCallback != null) {
927                 mEnrollmentCallback.onEnrollmentError(clientErrMsgId,
928                         getErrorString(errMsgId, vendorCode));
929             } else if (mAuthenticationCallback != null) {
930                 mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
931                         getErrorString(errMsgId, vendorCode));
932             } else if (mRemovalCallback != null) {
933                 mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId,
934                         getErrorString(errMsgId, vendorCode));
935             } else if (mEnumerateCallback != null) {
936                 mEnumerateCallback.onEnumerateError(clientErrMsgId,
937                         getErrorString(errMsgId, vendorCode));
938             }
939         }
940 
sendEnrollResult(Fingerprint fp, int remaining)941         private void sendEnrollResult(Fingerprint fp, int remaining) {
942             if (mEnrollmentCallback != null) {
943                 mEnrollmentCallback.onEnrollmentProgress(remaining);
944             }
945         }
946 
sendAuthenticatedSucceeded(Fingerprint fp, int userId)947         private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
948             if (mAuthenticationCallback != null) {
949                 final AuthenticationResult result =
950                         new AuthenticationResult(mCryptoObject, fp, userId);
951                 mAuthenticationCallback.onAuthenticationSucceeded(result);
952             }
953         }
954 
sendAuthenticatedFailed()955         private void sendAuthenticatedFailed() {
956             if (mAuthenticationCallback != null) {
957                 mAuthenticationCallback.onAuthenticationFailed();
958             }
959         }
960 
sendAcquiredResult(long deviceId, int acquireInfo, int vendorCode)961         private void sendAcquiredResult(long deviceId, int acquireInfo, int vendorCode) {
962             if (mAuthenticationCallback != null) {
963                 mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
964             }
965             final String msg = getAcquiredString(acquireInfo, vendorCode);
966             if (msg == null) {
967                 return;
968             }
969             // emulate HAL 2.1 behavior and send real acquiredInfo
970             final int clientInfo = acquireInfo == FINGERPRINT_ACQUIRED_VENDOR
971                     ? (vendorCode + FINGERPRINT_ACQUIRED_VENDOR_BASE) : acquireInfo;
972             if (mEnrollmentCallback != null) {
973                 mEnrollmentCallback.onEnrollmentHelp(clientInfo, msg);
974             } else if (mAuthenticationCallback != null) {
975                 mAuthenticationCallback.onAuthenticationHelp(clientInfo, msg);
976             }
977         }
978     };
979 
980     /**
981      * @hide
982      */
FingerprintManager(Context context, IFingerprintService service)983     public FingerprintManager(Context context, IFingerprintService service) {
984         mContext = context;
985         mService = service;
986         if (mService == null) {
987             Slog.v(TAG, "FingerprintManagerService was null");
988         }
989         mHandler = new MyHandler(context);
990     }
991 
getCurrentUserId()992     private int getCurrentUserId() {
993         try {
994             return ActivityManager.getService().getCurrentUser().id;
995         } catch (RemoteException e) {
996             throw e.rethrowFromSystemServer();
997         }
998     }
999 
cancelEnrollment()1000     private void cancelEnrollment() {
1001         if (mService != null) try {
1002             mService.cancelEnrollment(mToken);
1003         } catch (RemoteException e) {
1004             throw e.rethrowFromSystemServer();
1005         }
1006     }
1007 
cancelAuthentication(CryptoObject cryptoObject)1008     private void cancelAuthentication(CryptoObject cryptoObject) {
1009         if (mService != null) try {
1010             mService.cancelAuthentication(mToken, mContext.getOpPackageName());
1011         } catch (RemoteException e) {
1012             throw e.rethrowFromSystemServer();
1013         }
1014     }
1015 
getErrorString(int errMsg, int vendorCode)1016     private String getErrorString(int errMsg, int vendorCode) {
1017         switch (errMsg) {
1018             case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
1019                 return mContext.getString(
1020                     com.android.internal.R.string.fingerprint_error_unable_to_process);
1021             case FINGERPRINT_ERROR_HW_UNAVAILABLE:
1022                 return mContext.getString(
1023                     com.android.internal.R.string.fingerprint_error_hw_not_available);
1024             case FINGERPRINT_ERROR_NO_SPACE:
1025                 return mContext.getString(
1026                     com.android.internal.R.string.fingerprint_error_no_space);
1027             case FINGERPRINT_ERROR_TIMEOUT:
1028                 return mContext.getString(com.android.internal.R.string.fingerprint_error_timeout);
1029             case FINGERPRINT_ERROR_CANCELED:
1030                 return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
1031             case FINGERPRINT_ERROR_LOCKOUT:
1032                 return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
1033             case FINGERPRINT_ERROR_LOCKOUT_PERMANENT:
1034                 return mContext.getString(
1035                         com.android.internal.R.string.fingerprint_error_lockout_permanent);
1036             case FINGERPRINT_ERROR_VENDOR: {
1037                     String[] msgArray = mContext.getResources().getStringArray(
1038                             com.android.internal.R.array.fingerprint_error_vendor);
1039                     if (vendorCode < msgArray.length) {
1040                         return msgArray[vendorCode];
1041                     }
1042                 }
1043         }
1044         Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
1045         return null;
1046     }
1047 
getAcquiredString(int acquireInfo, int vendorCode)1048     private String getAcquiredString(int acquireInfo, int vendorCode) {
1049         switch (acquireInfo) {
1050             case FINGERPRINT_ACQUIRED_GOOD:
1051                 return null;
1052             case FINGERPRINT_ACQUIRED_PARTIAL:
1053                 return mContext.getString(
1054                     com.android.internal.R.string.fingerprint_acquired_partial);
1055             case FINGERPRINT_ACQUIRED_INSUFFICIENT:
1056                 return mContext.getString(
1057                     com.android.internal.R.string.fingerprint_acquired_insufficient);
1058             case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
1059                 return mContext.getString(
1060                     com.android.internal.R.string.fingerprint_acquired_imager_dirty);
1061             case FINGERPRINT_ACQUIRED_TOO_SLOW:
1062                 return mContext.getString(
1063                     com.android.internal.R.string.fingerprint_acquired_too_slow);
1064             case FINGERPRINT_ACQUIRED_TOO_FAST:
1065                 return mContext.getString(
1066                     com.android.internal.R.string.fingerprint_acquired_too_fast);
1067             case FINGERPRINT_ACQUIRED_VENDOR: {
1068                     String[] msgArray = mContext.getResources().getStringArray(
1069                             com.android.internal.R.array.fingerprint_acquired_vendor);
1070                     if (vendorCode < msgArray.length) {
1071                         return msgArray[vendorCode];
1072                     }
1073                 }
1074         }
1075         Slog.w(TAG, "Invalid acquired message: " + acquireInfo + ", " + vendorCode);
1076         return null;
1077     }
1078 
1079     private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
1080 
1081         @Override // binder call
1082         public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
1083             mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
1084                     new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
1085         }
1086 
1087         @Override // binder call
1088         public void onAcquired(long deviceId, int acquireInfo, int vendorCode) {
1089             mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode, deviceId).sendToTarget();
1090         }
1091 
1092         @Override // binder call
1093         public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) {
1094             mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
1095         }
1096 
1097         @Override // binder call
1098         public void onAuthenticationFailed(long deviceId) {
1099             mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();
1100         }
1101 
1102         @Override // binder call
1103         public void onError(long deviceId, int error, int vendorCode) {
1104             mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
1105         }
1106 
1107         @Override // binder call
1108         public void onRemoved(long deviceId, int fingerId, int groupId, int remaining) {
1109             mHandler.obtainMessage(MSG_REMOVED, remaining, 0,
1110                     new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
1111         }
1112 
1113         @Override // binder call
1114         public void onEnumerated(long deviceId, int fingerId, int groupId, int remaining) {
1115             // TODO: propagate remaining
1116             mHandler.obtainMessage(MSG_ENUMERATED, fingerId, groupId, deviceId).sendToTarget();
1117         }
1118     };
1119 
1120 }
1121