Merge "Several fixes to Fingerprint code after large merge - route fingerprint enrollment auth token - replace "processed" event with "authenticated" - fix type-o in strings.xml"
This commit is contained in:
@ -13774,6 +13774,7 @@ package android.hardware.fingerprint {
|
||||
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
|
||||
|
@ -14070,6 +14070,7 @@ package android.hardware.fingerprint {
|
||||
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
|
||||
|
@ -56,7 +56,7 @@ 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_PROCESSED = 102;
|
||||
private static final int MSG_AUTHENTICATED = 102;
|
||||
private static final int MSG_ERROR = 103;
|
||||
private static final int MSG_REMOVED = 104;
|
||||
|
||||
@ -103,6 +103,11 @@ public class FingerprintManager {
|
||||
*/
|
||||
public static final int FINGERPRINT_ERROR_UNABLE_TO_REMOVE = 6;
|
||||
|
||||
/**
|
||||
* The operation was canceled because the API is locked out due to too many attempts.
|
||||
*/
|
||||
public static final int FINGERPRINT_ERROR_LOCKOUT = 7;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -169,15 +174,9 @@ public class FingerprintManager {
|
||||
private Fingerprint mRemovalFingerprint;
|
||||
|
||||
private class OnEnrollCancelListener implements OnCancelListener {
|
||||
private long mChallenge;
|
||||
|
||||
public OnEnrollCancelListener(long challenge) {
|
||||
mChallenge = challenge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
cancelEnrollment(mChallenge);
|
||||
cancelEnrollment();
|
||||
}
|
||||
}
|
||||
|
||||
@ -437,14 +436,14 @@ public class FingerprintManager {
|
||||
* {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
|
||||
* which point the object is no longer valid. The operation can be canceled by using the
|
||||
* provided cancel object.
|
||||
* @param challenge a unique id provided by a recent verification of device credentials
|
||||
* (e.g. pin, pattern or password).
|
||||
* @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
|
||||
* @hide
|
||||
*/
|
||||
public void enroll(long challenge, CancellationSignal cancel, EnrollmentCallback callback,
|
||||
public void enroll(byte [] token, CancellationSignal cancel, EnrollmentCallback callback,
|
||||
int flags) {
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("Must supply an enrollment callback");
|
||||
@ -455,13 +454,13 @@ public class FingerprintManager {
|
||||
Log.w(TAG, "enrollment already canceled");
|
||||
return;
|
||||
} else {
|
||||
cancel.setOnCancelListener(new OnEnrollCancelListener(challenge));
|
||||
cancel.setOnCancelListener(new OnEnrollCancelListener());
|
||||
}
|
||||
}
|
||||
|
||||
if (mService != null) try {
|
||||
mEnrollmentCallback = callback;
|
||||
mService.enroll(mToken, challenge, getCurrentUserId(), mServiceReceiver, flags);
|
||||
mService.enroll(mToken, token, getCurrentUserId(), mServiceReceiver, flags);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Remote exception in enroll: ", e);
|
||||
if (callback != null) {
|
||||
@ -574,8 +573,8 @@ public class FingerprintManager {
|
||||
case MSG_ACQUIRED:
|
||||
sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
|
||||
break;
|
||||
case MSG_PROCESSED:
|
||||
sendProcessedResult((Fingerprint) msg.obj);
|
||||
case MSG_AUTHENTICATED:
|
||||
sendAuthenticatedResult((Fingerprint) msg.obj);
|
||||
break;
|
||||
case MSG_ERROR:
|
||||
sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
|
||||
@ -617,7 +616,7 @@ public class FingerprintManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void sendProcessedResult(Fingerprint fp) {
|
||||
private void sendAuthenticatedResult(Fingerprint fp) {
|
||||
if (mAuthenticationCallback != null) {
|
||||
if (fp.getFingerId() == 0 && fp.getGroupId() == 0) {
|
||||
// Fingerprint template valid but doesn't match one in database
|
||||
@ -667,7 +666,7 @@ public class FingerprintManager {
|
||||
mRemovalCallback = null;
|
||||
}
|
||||
|
||||
private void cancelEnrollment(long challenge) {
|
||||
private void cancelEnrollment() {
|
||||
if (mService != null) try {
|
||||
mService.cancelEnrollment(mToken);
|
||||
} catch (RemoteException e) {
|
||||
@ -695,8 +694,11 @@ public class FingerprintManager {
|
||||
return mContext.getString(
|
||||
com.android.internal.R.string.fingerprint_error_no_space);
|
||||
case FINGERPRINT_ERROR_TIMEOUT:
|
||||
return mContext.getString(
|
||||
com.android.internal.R.string.fingerprint_error_timeout);
|
||||
return mContext.getString(com.android.internal.R.string.fingerprint_error_timeout);
|
||||
case FINGERPRINT_ERROR_CANCELED:
|
||||
return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
|
||||
case FINGERPRINT_ERROR_LOCKOUT:
|
||||
return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
|
||||
default:
|
||||
if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) {
|
||||
int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE;
|
||||
@ -753,8 +755,8 @@ public class FingerprintManager {
|
||||
mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
|
||||
}
|
||||
|
||||
public void onProcessed(long deviceId, int fingerId, int groupId) {
|
||||
mHandler.obtainMessage(MSG_PROCESSED,
|
||||
public void onAuthenticated(long deviceId, int fingerId, int groupId) {
|
||||
mHandler.obtainMessage(MSG_AUTHENTICATED,
|
||||
new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ interface IFingerprintService {
|
||||
void cancelAuthentication(IBinder token);
|
||||
|
||||
// Start fingerprint enrollment
|
||||
void enroll(IBinder token, long challenge, int groupId, IFingerprintServiceReceiver receiver,
|
||||
void enroll(IBinder token, in byte [] cryptoToken, int groupId, IFingerprintServiceReceiver receiver,
|
||||
int flags);
|
||||
|
||||
// Cancel enrollment in progress
|
||||
|
@ -25,7 +25,7 @@ import android.os.UserHandle;
|
||||
oneway interface IFingerprintServiceReceiver {
|
||||
void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
|
||||
void onAcquired(long deviceId, int acquiredInfo);
|
||||
void onProcessed(long deviceId, int fingerId, int groupId);
|
||||
void onAuthenticated(long deviceId, int fingerId, int groupId);
|
||||
void onError(long deviceId, int error);
|
||||
void onRemoved(long deviceId, int fingerId, int groupId);
|
||||
}
|
||||
|
@ -1242,23 +1242,26 @@
|
||||
<!-- Message shown during fingerprint acquisision when the fingerprint sensor needs cleaning -->
|
||||
<string name="fingerprint_acquired_imager_dirty">Fingerprint sensor is dirty. Please clean and try again.</string>
|
||||
<!-- Message shown during fingerprint acquisision when the user removes their finger from the sensor too quickly -->
|
||||
<string name="fingerprint_acquired_too_fast">Finger moved to fast. Please try again.</string>
|
||||
<string name="fingerprint_acquired_too_fast">Finger moved too fast. Please try again.</string>
|
||||
<!-- Message shown during fingerprint acquisision when the user moves their finger too slowly -->
|
||||
<string name="fingerprint_acquired_too_slow">Finger moved to slow. Please try again.</string>
|
||||
<!-- Array containing custom messages shown during fingerprint acquisision from vendor. Vendor is expected to add and translate these strings -->
|
||||
<string-array name="fingerprint_acquired_vendor">
|
||||
</string-array>
|
||||
|
||||
<!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
|
||||
<string name="fingerprint_error_unable_to_process">Unable to process. Try again.</string>
|
||||
<!-- Error message shown when the fingerprint hardware can't be accessed -->
|
||||
<string name="fingerprint_error_hw_not_available">Hardware not available.</string>
|
||||
<string name="fingerprint_error_hw_not_available">Fingerprint hardware not available.</string>
|
||||
<!-- Error message shown when the fingerprint hardware has run out of room for storing fingerprints -->
|
||||
<string name="fingerprint_error_no_space">Fingerprint can\'t be stored. Please remove an existing fingerprint.</string>
|
||||
<!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
|
||||
<string name="fingerprint_error_timeout">Fingerprint time out reached. Try again.</string>
|
||||
<!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
|
||||
<string name="fingerprint_error_vendor">Fingerprint time out reached. Try again.</string>
|
||||
<!-- Generic error message shown when the fingerprint operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user-->
|
||||
<string name="fingerprint_error_canceled">Fingerprint operation canceled.</string>
|
||||
<!-- Generic error message shown when the fingerprint operation fails because too many attempts have been made. -->
|
||||
<string name="fingerprint_error_lockout">Too many attempts. Try again later.</string>
|
||||
<!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
|
||||
<string name="fingerprint_error_unable_to_process">Try again.</string>
|
||||
|
||||
<!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings -->
|
||||
<string-array name="fingerprint_error_vendor">
|
||||
</string-array>
|
||||
|
@ -2091,6 +2091,8 @@
|
||||
<java-symbol type="string" name="fingerprint_acquired_too_slow" />
|
||||
<java-symbol type="string" name="fingerprint_acquired_too_fast" />
|
||||
<java-symbol type="array" name="fingerprint_acquired_vendor" />
|
||||
<java-symbol type="string" name="fingerprint_error_canceled" />
|
||||
<java-symbol type="string" name="fingerprint_error_lockout" />
|
||||
|
||||
<!-- From various Material changes -->
|
||||
<java-symbol type="attr" name="titleTextAppearance" />
|
||||
|
@ -28,6 +28,7 @@ import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.InsetDrawable;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
@ -625,6 +626,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
|
||||
public void onFingerprintError(int msgId, String errString) {
|
||||
// TODO: Go to bouncer if this is "too many attempts" (lockout) error.
|
||||
Log.i(TAG, "FP Error: " + errString);
|
||||
updateLockIcon();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -39,6 +39,7 @@ import static android.Manifest.permission.USE_FINGERPRINT;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -51,9 +52,9 @@ import java.util.List;
|
||||
public class FingerprintService extends SystemService {
|
||||
private static final String TAG = "FingerprintService";
|
||||
private static final boolean DEBUG = true;
|
||||
private ClientData mAuthClient = null;
|
||||
private ClientData mEnrollClient = null;
|
||||
private ClientData mRemoveClient = null;
|
||||
private ClientMonitor mAuthClient = null;
|
||||
private ClientMonitor mEnrollClient = null;
|
||||
private ClientMonitor mRemoveClient = null;
|
||||
|
||||
private static final int MSG_NOTIFY = 10;
|
||||
|
||||
@ -63,7 +64,6 @@ public class FingerprintService extends SystemService {
|
||||
// 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_PROCESSED = 2;
|
||||
private static final int FINGERPRINT_TEMPLATE_ENROLLING = 3;
|
||||
private static final int FINGERPRINT_TEMPLATE_REMOVED = 4;
|
||||
private static final int FINGERPRINT_AUTHENTICATED = 5;
|
||||
@ -83,80 +83,21 @@ public class FingerprintService extends SystemService {
|
||||
};
|
||||
private Context mContext;
|
||||
private int mHalDeviceId;
|
||||
private int mFailedAttempts;
|
||||
private final Runnable mLockoutReset = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
resetFailedAttempts();
|
||||
}
|
||||
};
|
||||
|
||||
private static final int STATE_IDLE = 0;
|
||||
private static final int STATE_AUTHENTICATING = 1;
|
||||
private static final int STATE_ENROLLING = 2;
|
||||
private static final int STATE_REMOVING = 3;
|
||||
private static final long MS_PER_SEC = 1000;
|
||||
|
||||
private class ClientData {
|
||||
IBinder token;
|
||||
IFingerprintServiceReceiver receiver;
|
||||
int userId;
|
||||
long opId;
|
||||
private TokenWatcher tokenWatcher;
|
||||
public ClientData(IBinder token, long opId, IFingerprintServiceReceiver receiver,
|
||||
int userId) {
|
||||
this.token = token;
|
||||
this.opId = opId;
|
||||
this.receiver = receiver;
|
||||
this.userId = userId;
|
||||
tokenWatcher = new TokenWatcher(token);
|
||||
try {
|
||||
token.linkToDeath(tokenWatcher, 0);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
IBinder getToken() {
|
||||
return tokenWatcher.getToken();
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
token.unlinkToDeath(tokenWatcher, 0);
|
||||
tokenWatcher.token = null;
|
||||
}
|
||||
}
|
||||
|
||||
private class TokenWatcher implements IBinder.DeathRecipient {
|
||||
WeakReference<IBinder> token;
|
||||
|
||||
TokenWatcher(IBinder token) {
|
||||
this.token = new WeakReference<IBinder>(token);
|
||||
}
|
||||
|
||||
IBinder getToken() {
|
||||
return token.get();
|
||||
}
|
||||
|
||||
public void binderDied() {
|
||||
if (mAuthClient != null & mAuthClient.token == token)
|
||||
mAuthClient = null;
|
||||
if (mEnrollClient != null && mEnrollClient.token == token)
|
||||
mEnrollClient = null;
|
||||
this.token = null;
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
if (token != null) {
|
||||
if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token);
|
||||
if (mAuthClient != null && mAuthClient.token == token) {
|
||||
mAuthClient.destroy();
|
||||
mAuthClient = null;
|
||||
}
|
||||
if (mEnrollClient != null && mEnrollClient.token == token) {
|
||||
mAuthClient.destroy();
|
||||
mEnrollClient = null;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
|
||||
private static final int MAX_FAILED_ATTEMPTS = 5;
|
||||
|
||||
public FingerprintService(Context context) {
|
||||
super(context);
|
||||
@ -166,11 +107,11 @@ public class FingerprintService extends SystemService {
|
||||
|
||||
// TODO: Move these into separate process
|
||||
// JNI methods to communicate from FingerprintService to HAL
|
||||
static native int nativeEnroll(long challenge, int groupId, int timeout);
|
||||
static native int nativeEnroll(byte [] token, int groupId, int timeout);
|
||||
static native long nativePreEnroll();
|
||||
static native int nativeStopEnrollment();
|
||||
static native int nativeAuthenticate(long sessionId, int groupId);
|
||||
static native int nativeStopAuthentication(long sessionId);
|
||||
static native int nativeStopAuthentication();
|
||||
static native int nativeRemove(int fingerId, int groupId);
|
||||
static native int nativeOpenHal();
|
||||
static native int nativeCloseHal();
|
||||
@ -201,82 +142,62 @@ public class FingerprintService extends SystemService {
|
||||
Slog.v(TAG, "handleNotify(type=" + type + ", arg1=" + arg1 + ", arg2=" + arg2 + ")"
|
||||
+ ", mAuthClients = " + mAuthClient + ", mEnrollClient = " + mEnrollClient);
|
||||
if (mEnrollClient != null) {
|
||||
try {
|
||||
final IBinder token = mEnrollClient.token;
|
||||
if (doNotify(mEnrollClient, type, arg1, arg2, arg3)) {
|
||||
stopEnrollment(token);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "can't send message to mEnrollClient. Did it die?", e);
|
||||
mEnrollClient.destroy();
|
||||
mEnrollClient = null;
|
||||
final IBinder token = mEnrollClient.token;
|
||||
if (doNotify(mEnrollClient, type, arg1, arg2, arg3)) {
|
||||
stopEnrollment(token);
|
||||
}
|
||||
}
|
||||
if (mAuthClient != null) {
|
||||
try {
|
||||
final IBinder token = mAuthClient.getToken();
|
||||
if (doNotify(mAuthClient, type, arg1, arg2, arg3)) {
|
||||
stopAuthentication(token);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "can't send message to mAuthClient. Did it die?", e);
|
||||
mAuthClient.destroy();
|
||||
mAuthClient = null;
|
||||
final IBinder token = mAuthClient.token;
|
||||
if (doNotify(mAuthClient, type, arg1, arg2, arg3)) {
|
||||
stopAuthentication(token);
|
||||
}
|
||||
}
|
||||
if (mRemoveClient != null) {
|
||||
try {
|
||||
if (doNotify(mRemoveClient, type, arg1, arg2, arg3)) {
|
||||
mRemoveClient.destroy();
|
||||
mRemoveClient = null;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "can't send message to mRemoveClient. Did it die?", e);
|
||||
mRemoveClient.destroy();
|
||||
mRemoveClient = null;
|
||||
if (doNotify(mRemoveClient, type, arg1, arg2, arg3)) {
|
||||
removeClient(mRemoveClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the operation is done, i.e. authentication completed
|
||||
boolean doNotify(ClientData clientData, int type, int arg1, int arg2, int arg3)
|
||||
throws RemoteException {
|
||||
if (clientData.receiver == null) {
|
||||
if (DEBUG) Slog.v(TAG, "receiver not registered!!");
|
||||
return false;
|
||||
}
|
||||
boolean doNotify(ClientMonitor clientMonitor, int type, int arg1, int arg2, int arg3) {
|
||||
ContentResolver contentResolver = mContext.getContentResolver();
|
||||
boolean operationCompleted = false;
|
||||
switch (type) {
|
||||
case FINGERPRINT_ERROR:
|
||||
clientData.receiver.onError(mHalDeviceId, arg1 /* error */);
|
||||
if (arg1 == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
|
||||
if (mEnrollClient != null) {
|
||||
mEnrollClient.destroy();
|
||||
mEnrollClient = null;
|
||||
}
|
||||
if (mAuthClient != null) {
|
||||
mAuthClient.destroy();
|
||||
mAuthClient = null;
|
||||
}
|
||||
{
|
||||
final int error = arg1;
|
||||
clientMonitor.sendError(error);
|
||||
removeClient(clientMonitor);
|
||||
operationCompleted = true; // any error means the operation is done
|
||||
}
|
||||
operationCompleted = true; // any error means the operation is done
|
||||
break;
|
||||
case FINGERPRINT_ACQUIRED:
|
||||
clientData.receiver.onAcquired(mHalDeviceId, arg1 /* acquireInfo */);
|
||||
clientMonitor.sendAcquired(arg1 /* acquireInfo */);
|
||||
break;
|
||||
case FINGERPRINT_PROCESSED:
|
||||
clientData.receiver.onProcessed(mHalDeviceId, arg1 /* fpId */, arg2 /* gpId */);
|
||||
operationCompleted = true; // we either got a positive or negative match
|
||||
case FINGERPRINT_AUTHENTICATED:
|
||||
{
|
||||
final int fpId = arg1;
|
||||
final int groupId = arg2;
|
||||
clientMonitor.sendAuthenticated(fpId, groupId);
|
||||
if (fpId == 0) {
|
||||
if (clientMonitor == mAuthClient) {
|
||||
operationCompleted = handleFailedAttempt(clientMonitor);
|
||||
}
|
||||
} else {
|
||||
mLockoutReset.run(); // a valid fingerprint resets lockout
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FINGERPRINT_TEMPLATE_ENROLLING:
|
||||
{
|
||||
final int fpId = arg1;
|
||||
final int groupId = arg2;
|
||||
final int remaining = arg3;
|
||||
clientData.receiver.onEnrollResult(mHalDeviceId, fpId, groupId, remaining);
|
||||
clientMonitor.sendEnrollResult(fpId, groupId, remaining);
|
||||
if (remaining == 0) {
|
||||
addTemplateForUser(clientData, contentResolver, fpId);
|
||||
addTemplateForUser(clientMonitor, contentResolver, fpId);
|
||||
operationCompleted = true; // enroll completed
|
||||
}
|
||||
}
|
||||
@ -285,11 +206,11 @@ public class FingerprintService extends SystemService {
|
||||
{
|
||||
final int fingerId = arg1;
|
||||
final int groupId = arg2;
|
||||
removeTemplateForUser(clientData, contentResolver, fingerId);
|
||||
removeTemplateForUser(clientMonitor, contentResolver, fingerId);
|
||||
if (fingerId == 0) {
|
||||
operationCompleted = true; // remove completed
|
||||
} else {
|
||||
clientData.receiver.onRemoved(mHalDeviceId, fingerId, groupId);
|
||||
clientMonitor.sendRemoved(fingerId, groupId);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -297,24 +218,60 @@ public class FingerprintService extends SystemService {
|
||||
return operationCompleted;
|
||||
}
|
||||
|
||||
private void removeTemplateForUser(ClientData clientData, ContentResolver contentResolver,
|
||||
private void removeClient(ClientMonitor clientMonitor) {
|
||||
if (clientMonitor == null) return;
|
||||
clientMonitor.destroy();
|
||||
if (clientMonitor == mAuthClient) {
|
||||
mAuthClient = null;
|
||||
} else if (clientMonitor == mEnrollClient) {
|
||||
mEnrollClient = null;
|
||||
} else if (clientMonitor == mRemoveClient) {
|
||||
mRemoveClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean inLockoutMode() {
|
||||
return mFailedAttempts > MAX_FAILED_ATTEMPTS;
|
||||
}
|
||||
|
||||
private void resetFailedAttempts() {
|
||||
if (DEBUG) Slog.v(TAG, "Reset fingerprint lockout");
|
||||
mFailedAttempts = 0;
|
||||
}
|
||||
|
||||
private boolean handleFailedAttempt(ClientMonitor clientMonitor) {
|
||||
mFailedAttempts++;
|
||||
if (mFailedAttempts > MAX_FAILED_ATTEMPTS) {
|
||||
// Failing multiple times will continue to push out the lockout time.
|
||||
mHandler.removeCallbacks(mLockoutReset);
|
||||
mHandler.postDelayed(mLockoutReset, FAIL_LOCKOUT_TIMEOUT_MS);
|
||||
if (clientMonitor != null
|
||||
&& !clientMonitor.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
|
||||
Slog.w(TAG, "Cannot send lockout message to client");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void removeTemplateForUser(ClientMonitor clientMonitor, ContentResolver contentResolver,
|
||||
final int fingerId) {
|
||||
FingerprintUtils.removeFingerprintIdForUser(fingerId, contentResolver,
|
||||
clientData.userId);
|
||||
clientMonitor.userId);
|
||||
}
|
||||
|
||||
private void addTemplateForUser(ClientData clientData, ContentResolver contentResolver,
|
||||
private void addTemplateForUser(ClientMonitor clientMonitor, ContentResolver contentResolver,
|
||||
final int fingerId) {
|
||||
FingerprintUtils.addFingerprintIdForUser(contentResolver, fingerId,
|
||||
clientData.userId);
|
||||
clientMonitor.userId);
|
||||
}
|
||||
|
||||
void startEnrollment(IBinder token, long opId,
|
||||
int groupId, IFingerprintServiceReceiver receiver, int flags) {
|
||||
void startEnrollment(IBinder token, byte[] cryptoToken, int groupId,
|
||||
IFingerprintServiceReceiver receiver, int flags) {
|
||||
stopPendingOperations();
|
||||
mEnrollClient = new ClientData(token, opId, receiver, groupId);
|
||||
mEnrollClient = new ClientMonitor(token, receiver, groupId);
|
||||
final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
|
||||
final int result = nativeEnroll(opId, groupId, timeout);
|
||||
final int result = nativeEnroll(cryptoToken, groupId, timeout);
|
||||
if (result != 0) {
|
||||
Slog.w(TAG, "startEnroll failed, result=" + result);
|
||||
}
|
||||
@ -335,8 +292,11 @@ public class FingerprintService extends SystemService {
|
||||
}
|
||||
|
||||
void stopEnrollment(IBinder token) {
|
||||
if (mEnrollClient == null || mEnrollClient.token != token) return;
|
||||
final ClientMonitor client = mEnrollClient;
|
||||
if (client == null || client.token != token) return;
|
||||
int result = nativeStopEnrollment();
|
||||
client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
|
||||
removeClient(mEnrollClient);
|
||||
if (result != 0) {
|
||||
Slog.w(TAG, "startEnrollCancel failed, result=" + result);
|
||||
}
|
||||
@ -345,7 +305,15 @@ public class FingerprintService extends SystemService {
|
||||
void startAuthentication(IBinder token, long opId, int groupId,
|
||||
IFingerprintServiceReceiver receiver, int flags) {
|
||||
stopPendingOperations();
|
||||
mAuthClient = new ClientData(token, opId, receiver, groupId);
|
||||
mAuthClient = new ClientMonitor(token, receiver, groupId);
|
||||
if (inLockoutMode()) {
|
||||
Slog.v(TAG, "In lockout mode; disallowing authentication");
|
||||
if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
|
||||
Slog.w(TAG, "Cannot send timeout message to client");
|
||||
}
|
||||
mAuthClient = null;
|
||||
return;
|
||||
}
|
||||
final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
|
||||
final int result = nativeAuthenticate(opId, groupId);
|
||||
if (result != 0) {
|
||||
@ -354,8 +322,11 @@ public class FingerprintService extends SystemService {
|
||||
}
|
||||
|
||||
void stopAuthentication(IBinder token) {
|
||||
if (mAuthClient == null || mAuthClient.token != token) return;
|
||||
int result = nativeStopAuthentication(mAuthClient.opId);
|
||||
final ClientMonitor client = mAuthClient;
|
||||
if (client == null || client.token != token) return;
|
||||
int result = nativeStopAuthentication();
|
||||
client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
|
||||
removeClient(mAuthClient);
|
||||
if (result != 0) {
|
||||
Slog.w(TAG, "stopAuthentication failed, result=" + result);
|
||||
}
|
||||
@ -363,7 +334,7 @@ public class FingerprintService extends SystemService {
|
||||
|
||||
void startRemove(IBinder token, int fingerId, int userId,
|
||||
IFingerprintServiceReceiver receiver) {
|
||||
mRemoveClient = new ClientData(token, 0, receiver, userId);
|
||||
mRemoveClient = new ClientMonitor(token, receiver, userId);
|
||||
// The fingerprint template ids will be removed when we get confirmation from the HAL
|
||||
final int result = nativeRemove(fingerId, userId);
|
||||
if (result != 0) {
|
||||
@ -392,17 +363,114 @@ public class FingerprintService extends SystemService {
|
||||
"Must have " + permission + " permission.");
|
||||
}
|
||||
|
||||
private static final class Message {
|
||||
private class ClientMonitor implements IBinder.DeathRecipient {
|
||||
IBinder token;
|
||||
long opId;
|
||||
int groupId;
|
||||
int flags;
|
||||
WeakReference<IFingerprintServiceReceiver> receiver;
|
||||
int userId;
|
||||
|
||||
public Message(IBinder token, long challenge, int groupId, int flags) {
|
||||
public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId) {
|
||||
this.token = token;
|
||||
this.opId = challenge;
|
||||
this.groupId = groupId;
|
||||
this.flags = flags;
|
||||
this.receiver = new WeakReference<IFingerprintServiceReceiver>(receiver);
|
||||
this.userId = userId;
|
||||
try {
|
||||
token.linkToDeath(this, 0);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (token != null) {
|
||||
token.unlinkToDeath(this, 0);
|
||||
token = null;
|
||||
}
|
||||
receiver = null;
|
||||
}
|
||||
|
||||
public void binderDied() {
|
||||
token = null;
|
||||
removeClient(this);
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
if (token != null) {
|
||||
if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token);
|
||||
removeClient(this);
|
||||
}
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean sendRemoved(int fingerId, int groupId) {
|
||||
IFingerprintServiceReceiver rx = receiver.get();
|
||||
if (rx != null) {
|
||||
try {
|
||||
rx.onRemoved(mHalDeviceId, fingerId, groupId);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
if (DEBUG) Slog.v(TAG, "Failed to invoke sendRemoved:", e);
|
||||
}
|
||||
}
|
||||
removeClient(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean sendEnrollResult(int fpId, int groupId, int remaining) {
|
||||
IFingerprintServiceReceiver rx = receiver.get();
|
||||
if (rx != null) {
|
||||
try {
|
||||
rx.onEnrollResult(mHalDeviceId, fpId, groupId, remaining);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
if (DEBUG) Slog.v(TAG, "Failed to invoke sendEnrollResult:", e);
|
||||
}
|
||||
}
|
||||
removeClient(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean sendAuthenticated(int fpId, int groupId) {
|
||||
IFingerprintServiceReceiver rx = receiver.get();
|
||||
if (rx != null) {
|
||||
try {
|
||||
rx.onAuthenticated(mHalDeviceId, fpId, groupId);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
if (DEBUG) Slog.v(TAG, "Failed to invoke sendProcessed:", e);
|
||||
}
|
||||
}
|
||||
removeClient(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean sendAcquired(int acquiredInfo) {
|
||||
IFingerprintServiceReceiver rx = receiver.get();
|
||||
if (rx != null) {
|
||||
try {
|
||||
rx.onAcquired(mHalDeviceId, acquiredInfo);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
if (DEBUG) Slog.v(TAG, "Failed to invoke sendAcquired:", e);
|
||||
}
|
||||
}
|
||||
removeClient(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean sendError(int error) {
|
||||
IFingerprintServiceReceiver rx = receiver.get();
|
||||
if (rx != null) {
|
||||
try {
|
||||
rx.onError(mHalDeviceId, error);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
if (DEBUG) Slog.v(TAG, "Failed to invoke sendError:", e);
|
||||
}
|
||||
}
|
||||
removeClient(this);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -415,13 +483,14 @@ public class FingerprintService extends SystemService {
|
||||
|
||||
@Override
|
||||
// Binder call
|
||||
public void enroll(final IBinder token, final long opid, final int groupId,
|
||||
public void enroll(final IBinder token, final byte[] cryptoToken, final int groupId,
|
||||
final IFingerprintServiceReceiver receiver, final int flags) {
|
||||
checkPermission(MANAGE_FINGERPRINT);
|
||||
final byte [] cryptoClone = Arrays.copyOf(cryptoToken, cryptoToken.length);
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startEnrollment(token, opid, groupId, receiver, flags);
|
||||
startEnrollment(token, cryptoClone, groupId, receiver, flags);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -128,11 +128,16 @@ static void nativeInit(JNIEnv *env, jobject clazz, jobject mQueue, jobject callb
|
||||
gLooper = android_os_MessageQueue_getMessageQueue(env, mQueue)->getLooper();
|
||||
}
|
||||
|
||||
static jint nativeEnroll(JNIEnv* env, jobject clazz, jint groupId, jint timeout) {
|
||||
hw_auth_token_t *hat = NULL; // This is here as a placeholder,
|
||||
// please figure out your favorite way to send the hat struct through JNI
|
||||
static jint nativeEnroll(JNIEnv* env, jobject clazz, jbyteArray token, jint groupId, jint timeout) {
|
||||
ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll(gid=%d, timeout=%d)\n", groupId, timeout);
|
||||
int ret = gContext.device->enroll(gContext.device, hat, groupId, timeout);
|
||||
const int tokenSize = env->GetArrayLength(token);
|
||||
jbyte* tokenData = env->GetByteArrayElements(token, 0);
|
||||
if (tokenSize != sizeof(hw_auth_token_t)) {
|
||||
ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll() : invalid token size %d\n", tokenSize);
|
||||
return -1;
|
||||
}
|
||||
int ret = gContext.device->enroll(gContext.device, (hw_auth_token_t*) tokenData, groupId, timeout);
|
||||
env->ReleaseByteArrayElements(token, tokenData, 0);
|
||||
return reinterpret_cast<jint>(ret);
|
||||
}
|
||||
|
||||
@ -154,7 +159,7 @@ static jint nativeAuthenticate(JNIEnv* env, jobject clazz, jlong sessionId, jint
|
||||
return reinterpret_cast<jint>(ret);
|
||||
}
|
||||
|
||||
static jint nativeStopAuthentication(JNIEnv* env, jobject clazz, jlong sessionId) {
|
||||
static jint nativeStopAuthentication(JNIEnv* env, jobject clazz) {
|
||||
ALOG(LOG_VERBOSE, LOG_TAG, "nativeStopAuthentication()\n");
|
||||
int ret = gContext.device->cancel(gContext.device);
|
||||
return reinterpret_cast<jint>(ret);
|
||||
@ -227,8 +232,8 @@ static jint nativeCloseHal(JNIEnv* env, jobject clazz) {
|
||||
// TODO: clean up void methods
|
||||
static const JNINativeMethod g_methods[] = {
|
||||
{ "nativeAuthenticate", "(JI)I", (void*)nativeAuthenticate },
|
||||
{ "nativeStopAuthentication", "(J)I", (void*)nativeStopAuthentication },
|
||||
{ "nativeEnroll", "(JII)I", (void*)nativeEnroll },
|
||||
{ "nativeStopAuthentication", "()I", (void*)nativeStopAuthentication },
|
||||
{ "nativeEnroll", "([BII)I", (void*)nativeEnroll },
|
||||
{ "nativePreEnroll", "()J", (void*)nativePreEnroll },
|
||||
{ "nativeStopEnrollment", "()I", (void*)nativeStopEnrollment },
|
||||
{ "nativeRemove", "(II)I", (void*)nativeRemove },
|
||||
|
Reference in New Issue
Block a user