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:
Jim Miller
2015-04-15 05:25:23 +00:00
committed by Android (Google) Code Review
10 changed files with 270 additions and 185 deletions

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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);
}

View File

@ -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>

View File

@ -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" />

View File

@ -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();
}
};

View File

@ -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);
}
});
}

View File

@ -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 },