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