Merge "Update and cleanup FingerprintManager API to new spec" into mnc-dev

This commit is contained in:
Jim Miller
2015-06-09 01:46:15 +00:00
committed by Android (Google) Code Review
8 changed files with 155 additions and 129 deletions

View File

@@ -13942,16 +13942,8 @@ package android.hardware.display {
package android.hardware.fingerprint {
public final class Fingerprint implements android.os.Parcelable {
ctor public Fingerprint(java.lang.CharSequence, int, int, long);
method public int describeContents();
method public java.lang.CharSequence getName();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.fingerprint.Fingerprint> CREATOR;
}
public class FingerprintManager {
method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, int);
method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, int, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, android.os.Handler);
method public boolean hasEnrolledFingerprints();
method public boolean isHardwareDetected();
field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
@@ -13960,14 +13952,12 @@ package android.hardware.fingerprint {
field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
field public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000; // 0x3e8
field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
field public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000; // 0x3e8
}
public static abstract class FingerprintManager.AuthenticationCallback {
@@ -13979,11 +13969,10 @@ package android.hardware.fingerprint {
}
public static final class FingerprintManager.AuthenticationResult {
ctor public FingerprintManager.AuthenticationResult(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.hardware.fingerprint.Fingerprint);
method public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
}
public static class FingerprintManager.CryptoObject {
public static final class FingerprintManager.CryptoObject {
ctor public FingerprintManager.CryptoObject(java.security.Signature);
ctor public FingerprintManager.CryptoObject(javax.crypto.Cipher);
ctor public FingerprintManager.CryptoObject(javax.crypto.Mac);

View File

@@ -14260,16 +14260,8 @@ package android.hardware.display {
package android.hardware.fingerprint {
public final class Fingerprint implements android.os.Parcelable {
ctor public Fingerprint(java.lang.CharSequence, int, int, long);
method public int describeContents();
method public java.lang.CharSequence getName();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.fingerprint.Fingerprint> CREATOR;
}
public class FingerprintManager {
method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, int);
method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, int, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, android.os.Handler);
method public boolean hasEnrolledFingerprints();
method public boolean isHardwareDetected();
field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
@@ -14278,14 +14270,12 @@ package android.hardware.fingerprint {
field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
field public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000; // 0x3e8
field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
field public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000; // 0x3e8
}
public static abstract class FingerprintManager.AuthenticationCallback {
@@ -14297,11 +14287,10 @@ package android.hardware.fingerprint {
}
public static final class FingerprintManager.AuthenticationResult {
ctor public FingerprintManager.AuthenticationResult(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.hardware.fingerprint.Fingerprint);
method public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
}
public static class FingerprintManager.CryptoObject {
public static final class FingerprintManager.CryptoObject {
ctor public FingerprintManager.CryptoObject(java.security.Signature);
ctor public FingerprintManager.CryptoObject(javax.crypto.Cipher);
ctor public FingerprintManager.CryptoObject(javax.crypto.Mac);

View File

@@ -18,32 +18,30 @@ package android.hardware.fingerprint;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.app.ActivityManagerNative;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Binder;
import android.os.CancellationSignal;
import android.os.CancellationSignal.OnCancelListener;
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
import android.security.keystore.AndroidKeyStoreProvider;
import android.util.Log;
import android.util.Slog;
import java.security.Signature;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import static android.Manifest.permission.USE_FINGERPRINT;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
/**
* A class that coordinates access to the fingerprint hardware.
* <p>
@@ -57,9 +55,10 @@ public class FingerprintManager {
private static final boolean DEBUG = true;
private static final int MSG_ENROLL_RESULT = 100;
private static final int MSG_ACQUIRED = 101;
private static final int MSG_AUTHENTICATED = 102;
private static final int MSG_ERROR = 103;
private static final int MSG_REMOVED = 104;
private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
private static final int MSG_AUTHENTICATION_FAILED = 103;
private static final int MSG_ERROR = 104;
private static final int MSG_REMOVED = 105;
//
// Error messages from fingerprint hardware during initilization, enrollment, authentication or
@@ -112,6 +111,7 @@ public class FingerprintManager {
/**
* Hardware vendors may extend this list if there are conditions that do not fall under one of
* the above categories. Vendors are responsible for providing error strings for these errors.
* @hide
*/
public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
@@ -162,6 +162,7 @@ public class FingerprintManager {
/**
* Hardware vendors may extend this list if there are conditions that do not fall under one of
* the above categories. Vendors are responsible for providing error strings for these errors.
* @hide
*/
public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
@@ -173,6 +174,7 @@ public class FingerprintManager {
private RemovalCallback mRemovalCallback;
private CryptoObject mCryptoObject;
private Fingerprint mRemovalFingerprint;
private Handler mHandler;
private class OnEnrollCancelListener implements OnCancelListener {
@Override
@@ -198,72 +200,71 @@ public class FingerprintManager {
* A wrapper class for the crypto objects supported by FingerprintManager. Currently the
* framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
*/
public static class CryptoObject {
public static final class CryptoObject {
public CryptoObject(@NonNull Signature signature) {
mSignature = signature;
mCipher = null;
mMac = null;
mCrypto = signature;
}
public CryptoObject(@NonNull Cipher cipher) {
mCipher = cipher;
mSignature = null;
mMac = null;
mCrypto = cipher;
}
public CryptoObject(@NonNull Mac mac) {
mMac = mac;
mCipher = null;
mSignature = null;
mCrypto = mac;
}
/**
* Get {@link Signature} object.
* @return {@link Signature} object or null if this doesn't contain one.
*/
public Signature getSignature() { return mSignature; }
public Signature getSignature() {
return mCrypto instanceof Signature ? (Signature) mCrypto : null;
}
/**
* Get {@link Cipher} object.
* @return {@link Cipher} object or null if this doesn't contain one.
*/
public Cipher getCipher() { return mCipher; }
public Cipher getCipher() {
return mCrypto instanceof Cipher ? (Cipher) mCrypto : null;
}
/**
* Get {@link Mac} object.
* @return {@link Mac} object or null if this doesn't contain one.
*/
public Mac getMac() { return mMac; }
public Mac getMac() {
return mCrypto instanceof Mac ? (Mac) mCrypto : null;
}
/**
* @hide
* @return the opId associated with this object or 0 if none
*/
public long getOpId() {
if (mSignature != null) {
return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mSignature);
} else if (mCipher != null) {
return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCipher);
} else if (mMac != null) {
return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mMac);
}
return 0;
return mCrypto != null ?
AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto) : 0;
}
private final Signature mSignature;
private final Cipher mCipher;
private final Mac mMac;
private final Object mCrypto;
};
/**
* Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
* CancellationSignal, AuthenticationCallback, int)}.
* CancellationSignal, int, AuthenticationCallback, Handler)}.
*/
public static final class AuthenticationResult {
private Fingerprint mFingerprint;
private CryptoObject mCryptoObject;
/**
* Authentication result
*
* @param crypto the crypto object
* @param fingerprint the recognized fingerprint data, if allowed.
* @hide
*/
public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint) {
mCryptoObject = crypto;
mFingerprint = fingerprint;
@@ -272,7 +273,7 @@ public class FingerprintManager {
/**
* Obtain the crypto object associated with this transaction
* @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject,
* CancellationSignal, AuthenticationCallback, int)}.
* CancellationSignal, int, AuthenticationCallback, Handler)}.
*/
public CryptoObject getCryptoObject() { return mCryptoObject; }
@@ -287,28 +288,28 @@ public class FingerprintManager {
/**
* Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject,
* CancellationSignal, AuthenticationCallback, int)}. Users of {@link
* CancellationSignal, int, AuthenticationCallback, Handler)}. Users of {@link
* FingerprintManager#authenticate(CryptoObject, CancellationSignal,
* AuthenticationCallback, int) } must provide an implementation of this for listening to
* int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
* fingerprint events.
*/
public static abstract class AuthenticationCallback {
/**
* Called when an unrecoverable error has been encountered and the operation is complete.
* No further callbacks will be made on this object.
* @param errMsgId An integer identifying the error message
* @param errorCode An integer identifying the error message
* @param errString A human-readable error string that can be shown in UI
*/
public void onAuthenticationError(int errMsgId, CharSequence errString) { }
public void onAuthenticationError(int errorCode, CharSequence errString) { }
/**
* Called when a recoverable error has been encountered during authentication. The help
* string is provided to give the user guidance for what went wrong, such as
* "Sensor dirty, please clean it."
* @param helpMsgId An integer identifying the error message
* @param helpCode An integer identifying the error message
* @param helpString A human-readable string that can be shown in UI
*/
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { }
public void onAuthenticationHelp(int helpCode, CharSequence helpString) { }
/**
* Called when a fingerprint is recognized.
@@ -326,7 +327,7 @@ public class FingerprintManager {
* Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback,
* CancellationSignal, int). Users of {@link #FingerprintManager()}
* must provide an implementation of this to {@link FingerprintManager#enroll(long,
* CancellationSignal, EnrollmentCallback, int) for listening to fingerprint events.
* CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events.
*
* @hide
*/
@@ -392,31 +393,35 @@ public class FingerprintManager {
*
* @param crypto object associated with the call or null if none required.
* @param cancel an object that can be used to cancel authentication
* @param callback an object to receive authentication events
* @param flags optional flags; should be 0
* @param callback an object to receive authentication events
* @param handler an optional handler to handle callback events
*/
@RequiresPermission(USE_FINGERPRINT)
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
@NonNull AuthenticationCallback callback, int flags) {
authenticate(crypto, cancel, callback, flags, UserHandle.myUserId());
int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
authenticate(crypto, cancel, flags, callback, handler, UserHandle.myUserId());
}
/**
* Request authentication of a crypto object. This call warms up the fingerprint hardware
* and starts scanning for a fingerprint. It terminates when
* {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
* {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult) is called, at
* which point the object is no longer valid. The operation can be canceled by using the
* provided cancel object.
*
* @param crypto object associated with the call or null if none required.
* @param cancel an object that can be used to cancel authentication
* @param callback an object to receive authentication events
* @param flags optional flags; should be 0
* @param userId the userId the fingerprint belongs to
* Use the provided handler thread for events.
* @param handler
*/
private void useHandler(Handler handler) {
if (handler != null) {
mHandler = new MyHandler(handler.getLooper());
} else if (mHandler.getLooper() != mContext.getMainLooper()){
mHandler = new MyHandler(mContext.getMainLooper());
}
}
/**
* Per-user version
* @hide
*/
@RequiresPermission(USE_FINGERPRINT)
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
@NonNull AuthenticationCallback callback, int flags, int userId) {
int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an authentication callback");
}
@@ -431,6 +436,7 @@ public class FingerprintManager {
}
if (mService != null) try {
useHandler(handler);
mAuthenticationCallback = callback;
mCryptoObject = crypto;
long sessionId = crypto != null ? crypto.getOpId() : 0;
@@ -458,12 +464,13 @@ public class FingerprintManager {
* @param token a unique token provided by a recent creation or verification of device
* credentials (e.g. pin, pattern or password).
* @param cancel an object that can be used to cancel enrollment
* @param callback an object to receive enrollment events
* @param flags optional flags
* @param callback an object to receive enrollment events
* @hide
*/
public void enroll(byte [] token, CancellationSignal cancel, EnrollmentCallback callback,
int flags) {
@RequiresPermission(MANAGE_FINGERPRINT)
public void enroll(byte [] token, CancellationSignal cancel, int flags,
EnrollmentCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an enrollment callback");
}
@@ -496,6 +503,7 @@ public class FingerprintManager {
* existing device credentials (e.g. pin/pattern/password).
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public long preEnroll() {
long result = 0;
if (mService != null) try {
@@ -514,6 +522,7 @@ public class FingerprintManager {
*
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void remove(Fingerprint fp, RemovalCallback callback) {
if (mService != null) try {
mRemovalCallback = callback;
@@ -535,6 +544,7 @@ public class FingerprintManager {
*
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void rename(int fpId, String newName) {
// Renames the given fpId
if (mService != null) {
@@ -554,6 +564,7 @@ public class FingerprintManager {
*
* @hide
*/
@RequiresPermission(USE_FINGERPRINT)
public List<Fingerprint> getEnrolledFingerprints(int userId) {
if (mService != null) try {
return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
@@ -569,6 +580,7 @@ public class FingerprintManager {
*
* @hide
*/
@RequiresPermission(USE_FINGERPRINT)
public List<Fingerprint> getEnrolledFingerprints() {
return getEnrolledFingerprints(UserHandle.myUserId());
}
@@ -578,6 +590,7 @@ public class FingerprintManager {
*
* @return true if at least one fingerprint is enrolled, false otherwise
*/
@RequiresPermission(USE_FINGERPRINT)
public boolean hasEnrolledFingerprints() {
if (mService != null) try {
return mService.hasEnrolledFingerprints(UserHandle.myUserId(),
@@ -593,6 +606,7 @@ public class FingerprintManager {
*
* @return true if hardware is present and functional, false otherwise.
*/
@RequiresPermission(USE_FINGERPRINT)
public boolean isHardwareDetected() {
if (mService != null) {
try {
@@ -626,13 +640,15 @@ public class FingerprintManager {
return 0;
}
private Handler mHandler;
private class MyHandler extends Handler {
private MyHandler(Context context) {
super(context.getMainLooper());
}
private MyHandler(Looper looper) {
super(looper);
}
public void handleMessage(android.os.Message msg) {
switch(msg.what) {
case MSG_ENROLL_RESULT:
@@ -641,8 +657,11 @@ public class FingerprintManager {
case MSG_ACQUIRED:
sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
break;
case MSG_AUTHENTICATED:
sendAuthenticatedResult((Fingerprint) msg.obj);
case MSG_AUTHENTICATION_SUCCEEDED:
sendAuthenticatedSucceeded((Fingerprint) msg.obj);
break;
case MSG_AUTHENTICATION_FAILED:
sendAuthenticatedFailed();
break;
case MSG_ERROR:
sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
@@ -684,15 +703,16 @@ public class FingerprintManager {
}
}
private void sendAuthenticatedResult(Fingerprint fp) {
private void sendAuthenticatedSucceeded(Fingerprint fp) {
if (mAuthenticationCallback != null) {
if (fp.getFingerId() == 0) {
// Fingerprint template valid but doesn't match one in database
mAuthenticationCallback.onAuthenticationFailed();
} else {
final AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp);
mAuthenticationCallback.onAuthenticationSucceeded(result);
}
final AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp);
mAuthenticationCallback.onAuthenticationSucceeded(result);
}
}
private void sendAuthenticatedFailed() {
if (mAuthenticationCallback != null) {
mAuthenticationCallback.onAuthenticationFailed();
}
}
@@ -809,24 +829,33 @@ public class FingerprintManager {
private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
@Override // binder call
public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
}
@Override // binder call
public void onAcquired(long deviceId, int acquireInfo) {
mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
}
public void onAuthenticated(long deviceId, int fingerId, int groupId) {
mHandler.obtainMessage(MSG_AUTHENTICATED,
new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
@Override // binder call
public void onAuthenticationSucceeded(long deviceId, Fingerprint fp) {
mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, fp).sendToTarget();
}
@Override // binder call
public void onAuthenticationFailed(long deviceId) {
mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();;
}
@Override // binder call
public void onError(long deviceId, int error) {
mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
}
@Override // binder call
public void onRemoved(long deviceId, int fingerId, int groupId) {
mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
}

View File

@@ -15,6 +15,7 @@
*/
package android.hardware.fingerprint;
import android.hardware.fingerprint.Fingerprint;
import android.os.Bundle;
import android.os.UserHandle;
@@ -25,7 +26,8 @@ import android.os.UserHandle;
oneway interface IFingerprintServiceReceiver {
void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
void onAcquired(long deviceId, int acquiredInfo);
void onAuthenticated(long deviceId, int fingerId, int groupId);
void onAuthenticationSucceeded(long deviceId, in Fingerprint fp);
void onAuthenticationFailed(long deviceId);
void onError(long deviceId, int error);
void onRemoved(long deviceId, int fingerId, int groupId);
}

View File

@@ -197,7 +197,7 @@ of the two modes:
reset (e.g. by a Device Admin).</li>
<li>User authentication is required for every use of the key. In this mode, a specific operation
involving a specific key is authorized by the user. Currently, the only means of such
authorization is fingerprint authentication: {@link android.hardware.fingerprint.FingerprintManager#authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, int) FingerprintManager.authenticate}.
authorization is fingerprint authentication: {@link android.hardware.fingerprint.FingerprintManager#authenticate(CryptoObject, CancellationSignal, int, AuthenticationCallback, Handler) FingerprintManager.authenticate}.
Such keys can only be generated or imported if at least one fingerprint is enrolled (see {@link android.hardware.fingerprint.FingerprintManager#hasEnrolledFingerprints() FingerprintManager.hasEnrolledFingerprints}).
These keys become permanently invalidated once all fingerprints are unenrolled.</li>
</ul>

View File

@@ -796,7 +796,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
mFingerprintCancelSignal.cancel();
}
mFingerprintCancelSignal = new CancellationSignal();
mFpm.authenticate(null, mFingerprintCancelSignal, mAuthenticationCallback, 0, userId);
mFpm.authenticate(null, mFingerprintCancelSignal, 0, mAuthenticationCallback, null, userId);
setFingerprintRunningDetectionRunning(true);
}
}

View File

@@ -22,6 +22,7 @@ import android.app.AppOpsManager;
import android.app.IUserSwitchObserver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
@@ -73,13 +74,6 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
private ClientMonitor mRemoveClient = null;
private final AppOpsManager mAppOps;
// Message types. Used internally to dispatch messages to the correct callback.
// Must agree with the list in fingerprint.h
private static final int FINGERPRINT_ERROR = -1;
private static final int FINGERPRINT_ACQUIRED = 1;
private static final int FINGERPRINT_TEMPLATE_ENROLLING = 3;
private static final int FINGERPRINT_TEMPLATE_REMOVED = 4;
private static final int FINGERPRINT_AUTHENTICATED = 5;
private static final long MS_PER_SEC = 1000;
private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
private static final int MAX_FAILED_ATTEMPTS = 5;
@@ -207,7 +201,6 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
if (mEnrollClient != null) {
if (mEnrollClient.sendEnrollResult(fingerId, groupId, remaining)) {
if (remaining == 0) {
ContentResolver res = mContext.getContentResolver();
addTemplateForUser(mEnrollClient, fingerId);
removeClient(mEnrollClient);
}
@@ -262,14 +255,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
void startEnrollment(IBinder token, byte[] cryptoToken, int groupId,
IFingerprintServiceReceiver receiver, int flags) {
IFingerprintServiceReceiver receiver, int flags, boolean restricted) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "enroll: no fingeprintd!");
return;
}
stopPendingOperations();
mEnrollClient = new ClientMonitor(token, receiver, groupId);
mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted);
final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
try {
final int result = daemon.enroll(cryptoToken, groupId, timeout);
@@ -328,14 +321,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
void startAuthentication(IBinder token, long opId, int groupId,
IFingerprintServiceReceiver receiver, int flags) {
IFingerprintServiceReceiver receiver, int flags, boolean restricted) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "startAuthentication: no fingeprintd!");
return;
}
stopPendingOperations();
mAuthClient = new ClientMonitor(token, receiver, groupId);
mAuthClient = new ClientMonitor(token, receiver, groupId, restricted);
if (inLockoutMode()) {
Slog.v(TAG, "In lockout mode; disallowing authentication");
if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
@@ -344,7 +337,6 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
mAuthClient = null;
return;
}
final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
try {
final int result = daemon.authenticate(opId, groupId);
if (result != 0) {
@@ -378,13 +370,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
void startRemove(IBinder token, int fingerId, int userId,
IFingerprintServiceReceiver receiver) {
IFingerprintServiceReceiver receiver, boolean restricted) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "startRemove: no fingeprintd!");
return;
}
mRemoveClient = new ClientMonitor(token, receiver, userId);
mRemoveClient = new ClientMonitor(token, receiver, userId, restricted);
// The fingerprint template ids will be removed when we get confirmation from the HAL
try {
final int result = daemon.remove(fingerId, userId);
@@ -404,6 +397,11 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
return mFingerprintUtils.getFingerprintsForUser(mContext, groupId).size() > 0;
}
boolean hasPermission(String permission) {
return getContext().checkCallingOrSelfPermission(permission)
== PackageManager.PERMISSION_GRANTED;
}
void checkPermission(String permission) {
getContext().enforceCallingOrSelfPermission(permission,
"Must have " + permission + " permission.");
@@ -420,11 +418,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
IBinder token;
IFingerprintServiceReceiver receiver;
int userId;
boolean restricted; // True if client does not have MANAGE_FINGERPRINT permission
public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId) {
public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId,
boolean restricted) {
this.token = token;
this.receiver = receiver;
this.userId = userId;
this.restricted = restricted;
try {
token.linkToDeath(this, 0);
} catch (RemoteException e) {
@@ -498,7 +499,13 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
boolean result = false;
if (receiver != null) {
try {
receiver.onAuthenticated(mHalDeviceId, fpId, groupId);
if (fpId == 0) {
receiver.onAuthenticationFailed(mHalDeviceId);
} else {
Fingerprint fp = !restricted ?
new Fingerprint("" /* TODO */, groupId, fpId, mHalDeviceId) : null;
receiver.onAuthenticationSucceeded(mHalDeviceId, fp);
}
} catch (RemoteException e) {
Slog.w(TAG, "Failed to notify Authenticated:", e);
result = true; // client failed
@@ -592,14 +599,22 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
final IFingerprintServiceReceiver receiver, final int flags) {
checkPermission(MANAGE_FINGERPRINT);
final byte [] cryptoClone = Arrays.copyOf(cryptoToken, cryptoToken.length);
final boolean restricted = isRestricted();
mHandler.post(new Runnable() {
@Override
public void run() {
startEnrollment(token, cryptoClone, groupId, receiver, flags);
startEnrollment(token, cryptoClone, groupId, receiver, flags, restricted);
}
});
}
private boolean isRestricted() {
// Only give privileged apps (like Settings) access to fingerprint info
final boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
return restricted;
}
@Override // Binder call
public void cancelEnrollment(final IBinder token) {
checkPermission(MANAGE_FINGERPRINT);
@@ -614,14 +629,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
@Override // Binder call
public void authenticate(final IBinder token, final long opId, final int groupId,
final IFingerprintServiceReceiver receiver, final int flags, String opPackageName) {
checkPermission(USE_FINGERPRINT);
if (!canUseFingerprint(opPackageName)) {
return;
}
final boolean restricted = isRestricted();
mHandler.post(new Runnable() {
@Override
public void run() {
startAuthentication(token, opId, groupId, receiver, flags);
startAuthentication(token, opId, groupId, receiver, flags, restricted);
}
});
}
@@ -643,10 +659,11 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
public void remove(final IBinder token, final int fingerId, final int groupId,
final IFingerprintServiceReceiver receiver) {
checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
final boolean restricted = isRestricted();
mHandler.post(new Runnable() {
@Override
public void run() {
startRemove(token, fingerId, groupId, receiver);
startRemove(token, fingerId, groupId, receiver, restricted);
}
});

View File

@@ -57,7 +57,7 @@ class FingerprintsUserState {
private final File mFile;
@GuardedBy("this")
private final ArrayList<Fingerprint> mFingerprints = new ArrayList<>();
private final ArrayList<Fingerprint> mFingerprints = new ArrayList<Fingerprint>();
private final Context mCtx;
public FingerprintsUserState(Context ctx, int userId) {
@@ -127,7 +127,7 @@ class FingerprintsUserState {
}
private ArrayList<Fingerprint> getCopy(ArrayList<Fingerprint> array) {
ArrayList<Fingerprint> result = new ArrayList<>(array.size());
ArrayList<Fingerprint> result = new ArrayList<Fingerprint>(array.size());
for (int i = 0; i < array.size(); i++) {
Fingerprint fp = array.get(i);
result.add(new Fingerprint(fp.getName(), fp.getGroupId(), fp.getFingerId(),