Merge "Rewrite FingerprintService to use HIDL 2.1"

This commit is contained in:
TreeHugger Robot
2017-01-17 20:16:49 +00:00
committed by Android (Google) Code Review
14 changed files with 306 additions and 232 deletions

View File

@@ -178,8 +178,6 @@ LOCAL_SRC_FILES += \
core/java/android/hardware/display/IDisplayManager.aidl \
core/java/android/hardware/display/IDisplayManagerCallback.aidl \
core/java/android/hardware/display/IVirtualDisplayCallback.aidl \
core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl \
core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl \
core/java/android/hardware/fingerprint/IFingerprintService.aidl \
core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl \
core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \

View File

@@ -62,6 +62,7 @@ public class FingerprintManager {
private static final int MSG_AUTHENTICATION_FAILED = 103;
private static final int MSG_ERROR = 104;
private static final int MSG_REMOVED = 105;
private static final int MSG_ENUMERATED = 106;
//
// Error messages from fingerprint hardware during initilization, enrollment, authentication or
@@ -116,6 +117,10 @@ public class FingerprintManager {
* the above categories. Vendors are responsible for providing error strings for these errors.
* @hide
*/
public static final int FINGERPRINT_ERROR_VENDOR = 8;
/**
* @hide
*/
public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
//
@@ -167,6 +172,10 @@ public class FingerprintManager {
* the above categories. Vendors are responsible for providing error strings for these errors.
* @hide
*/
public static final int FINGERPRINT_ACQUIRED_VENDOR = 6;
/**
* @hide
*/
public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
private IFingerprintService mService;
@@ -175,6 +184,7 @@ public class FingerprintManager {
private AuthenticationCallback mAuthenticationCallback;
private EnrollmentCallback mEnrollmentCallback;
private RemovalCallback mRemovalCallback;
private EnumerateCallback mEnumerateCallback;
private CryptoObject mCryptoObject;
private Fingerprint mRemovalFingerprint;
private Handler mHandler;
@@ -402,6 +412,29 @@ public class FingerprintManager {
public void onRemovalSucceeded(Fingerprint fingerprint) { }
};
/**
* Callback structure provided to {@link FingerprintManager#enumerate(int). Users of
* {@link #FingerprintManager()} may optionally provide an implementation of this to
* {@link FingerprintManager#enumerate(int, int, EnumerateCallback)} for listening to
* fingerprint template removal events.
*
* @hide
*/
public static abstract class EnumerateCallback {
/**
* Called when the given fingerprint can't be removed.
* @param errMsgId An associated error message id
* @param errString An error message indicating why the fingerprint id can't be removed
*/
public void onEnumerateError(int errMsgId, CharSequence errString) { }
/**
* Called when a given fingerprint is successfully removed.
* @param fingerprint the fingerprint template that was removed.
*/
public void onEnumerate(Fingerprint fingerprint) { }
};
/**
* @hide
*/
@@ -484,7 +517,7 @@ public class FingerprintManager {
// Though this may not be a hardware issue, it will cause apps to give up or try
// again later.
callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
}
}
}
@@ -534,7 +567,7 @@ public class FingerprintManager {
// Though this may not be a hardware issue, it will cause apps to give up or try
// again later.
callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
}
}
}
@@ -604,7 +637,29 @@ public class FingerprintManager {
Log.w(TAG, "Remote exception in remove: ", e);
if (callback != null) {
callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
}
}
}
/**
* Enumerate all fingerprint templates stored in hardware and/or protected storage.
* @param userId the user who this fingerprint belongs to
* @param callback an optional callback to verify that fingerprint templates have been
* successfully removed. May be null of no callback is required.
*
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void enumerate(int userId, @NonNull EnumerateCallback callback) {
if (mService != null) try {
mEnumerateCallback = callback;
mService.enumerate(mToken, userId, mServiceReceiver);
} catch (RemoteException e) {
Log.w(TAG, "Remote exception in enumerate: ", e);
if (callback != null) {
callback.onEnumerateError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
}
}
}
@@ -800,7 +855,8 @@ public class FingerprintManager {
sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
break;
case MSG_ACQUIRED:
sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */,
msg.arg2 /* vendorCode */);
break;
case MSG_AUTHENTICATION_SUCCEEDED:
sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */);
@@ -809,11 +865,15 @@ public class FingerprintManager {
sendAuthenticatedFailed();
break;
case MSG_ERROR:
sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */,
msg.arg2 /* vendorCode */);
break;
case MSG_REMOVED:
sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
msg.arg2 /* groupId */);
case MSG_ENUMERATED:
sendEnumeratedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
msg.arg2 /* groupId */);
}
}
@@ -834,14 +894,28 @@ public class FingerprintManager {
}
}
private void sendErrorResult(long deviceId, int errMsgId) {
private void sendEnumeratedResult(long deviceId, int fingerId, int groupId) {
if (mEnumerateCallback != null) {
mEnumerateCallback.onEnumerate(new Fingerprint(null, groupId, fingerId, deviceId));
}
}
private void sendErrorResult(long deviceId, int errMsgId, int vendorCode) {
// emulate HAL 2.1 behavior and send real errMsgId
final int clientErrMsgId = errMsgId == FINGERPRINT_ERROR_VENDOR
? (vendorCode + FINGERPRINT_ERROR_VENDOR_BASE) : errMsgId;
if (mEnrollmentCallback != null) {
mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId));
mEnrollmentCallback.onEnrollmentError(clientErrMsgId,
getErrorString(errMsgId, vendorCode));
} else if (mAuthenticationCallback != null) {
mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId));
mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
getErrorString(errMsgId, vendorCode));
} else if (mRemovalCallback != null) {
mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId,
getErrorString(errMsgId));
mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId,
getErrorString(errMsgId, vendorCode));
} else if (mEnumerateCallback != null) {
mEnumerateCallback.onEnumerateError(clientErrMsgId,
getErrorString(errMsgId, vendorCode));
}
}
@@ -865,18 +939,21 @@ public class FingerprintManager {
}
}
private void sendAcquiredResult(long deviceId, int acquireInfo) {
private void sendAcquiredResult(long deviceId, int acquireInfo, int vendorCode) {
if (mAuthenticationCallback != null) {
mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
}
final String msg = getAcquiredString(acquireInfo);
final String msg = getAcquiredString(acquireInfo, vendorCode);
if (msg == null) {
return;
}
// emulate HAL 2.1 behavior and send real acquiredInfo
final int clientInfo = acquireInfo == FINGERPRINT_ACQUIRED_VENDOR
? (vendorCode + FINGERPRINT_ACQUIRED_VENDOR_BASE) : acquireInfo;
if (mEnrollmentCallback != null) {
mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg);
mEnrollmentCallback.onEnrollmentHelp(clientInfo, msg);
} else if (mAuthenticationCallback != null) {
mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg);
mAuthenticationCallback.onAuthenticationHelp(clientInfo, msg);
}
}
};
@@ -917,7 +994,7 @@ public class FingerprintManager {
}
}
private String getErrorString(int errMsg) {
private String getErrorString(int errMsg, int vendorCode) {
switch (errMsg) {
case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
return mContext.getString(
@@ -934,20 +1011,19 @@ public class FingerprintManager {
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;
case FINGERPRINT_ERROR_VENDOR: {
String[] msgArray = mContext.getResources().getStringArray(
com.android.internal.R.array.fingerprint_error_vendor);
if (msgNumber < msgArray.length) {
return msgArray[msgNumber];
if (vendorCode < msgArray.length) {
return msgArray[vendorCode];
}
}
return null;
}
Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
return null;
}
private String getAcquiredString(int acquireInfo) {
private String getAcquiredString(int acquireInfo, int vendorCode) {
switch (acquireInfo) {
case FINGERPRINT_ACQUIRED_GOOD:
return null;
@@ -966,17 +1042,16 @@ public class FingerprintManager {
case FINGERPRINT_ACQUIRED_TOO_FAST:
return mContext.getString(
com.android.internal.R.string.fingerprint_acquired_too_fast);
default:
if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE;
case FINGERPRINT_ACQUIRED_VENDOR: {
String[] msgArray = mContext.getResources().getStringArray(
com.android.internal.R.array.fingerprint_acquired_vendor);
if (msgNumber < msgArray.length) {
return msgArray[msgNumber];
if (vendorCode < msgArray.length) {
return msgArray[vendorCode];
}
}
return null;
}
Slog.w(TAG, "Invalid acquired message: " + acquireInfo + ", " + vendorCode);
return null;
}
private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
@@ -988,8 +1063,8 @@ public class FingerprintManager {
}
@Override // binder call
public void onAcquired(long deviceId, int acquireInfo) {
mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
public void onAcquired(long deviceId, int acquireInfo, int vendorCode) {
mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode, deviceId).sendToTarget();
}
@Override // binder call
@@ -1003,14 +1078,21 @@ public class FingerprintManager {
}
@Override // binder call
public void onError(long deviceId, int error) {
mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
public void onError(long deviceId, int error, int vendorCode) {
mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
}
@Override // binder call
public void onRemoved(long deviceId, int fingerId, int groupId) {
public void onRemoved(long deviceId, int fingerId, int groupId, int remaining) {
// TODO: propagate remaining
mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
}
@Override // binder call
public void onEnumerated(long deviceId, int fingerId, int groupId, int remaining) {
// TODO: propagate remaining
mHandler.obtainMessage(MSG_ENUMERATED, fingerId, groupId, deviceId).sendToTarget();
}
};
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.fingerprint;
import android.hardware.fingerprint.IFingerprintDaemonCallback;
/**
* Communication channel from FingerprintService to FingerprintDaemon (fingerprintd)
* @hide
*/
interface IFingerprintDaemon {
int authenticate(long sessionId, int groupId);
int cancelAuthentication();
int enroll(in byte [] token, int groupId, int timeout);
int cancelEnrollment();
long preEnroll();
int remove(int fingerId, int groupId);
long getAuthenticatorId();
int setActiveGroup(int groupId, in byte[] path);
long openHal();
int closeHal();
void init(IFingerprintDaemonCallback callback);
int postEnroll();
int enumerate();
int cancelEnumeration();
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.fingerprint;
/**
* Communication channel from the fingerprintd back to FingerprintService.
* @hide
*/
interface IFingerprintDaemonCallback {
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 onError(long deviceId, int error);
void onRemoved(long deviceId, int fingerId, int groupId);
void onEnumerate(long deviceId, in int [] fingerIds, in int [] groupIds);
}

View File

@@ -79,4 +79,7 @@ interface IFingerprintService {
// Explicitly set the active user (for enrolling work profile)
void setActiveUser(int uid);
// Enumerate all fingerprints
void enumerate(IBinder token, int userId, IFingerprintServiceReceiver receiver);
}

View File

@@ -25,9 +25,10 @@ import android.os.UserHandle;
*/
oneway interface IFingerprintServiceReceiver {
void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
void onAcquired(long deviceId, int acquiredInfo);
void onAcquired(long deviceId, int acquiredInfo, int vendorCode);
void onAuthenticationSucceeded(long deviceId, in Fingerprint fp, int userId);
void onAuthenticationFailed(long deviceId);
void onError(long deviceId, int error);
void onRemoved(long deviceId, int fingerId, int groupId);
void onError(long deviceId, int error, int vendorCode);
void onRemoved(long deviceId, int fingerId, int groupId, int remaining);
void onEnumerated(long deviceId, int fingerId, int groupId, int remaining);
}

View File

@@ -36,7 +36,9 @@ services := \
voiceinteraction
# The convention is to name each service module 'services.$(module_name)'
LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services))
LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services)) \
android.hidl.base@1.0-java \
android.hardware.biometrics.fingerprint@2.1-java
ifeq ($(EMMA_INSTRUMENT_FRAMEWORK),true)
LOCAL_EMMA_INSTRUMENT := true

View File

@@ -24,7 +24,9 @@ LOCAL_JAVA_LIBRARIES := \
android.hardware.power@1.0-java \
android.hardware.tv.cec@1.0-java
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update2
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update2 \
android.hidl.base@1.0-java \
android.hardware.biometrics.fingerprint@2.1-java \
ifneq ($(INCREMENTAL_BUILDS),)
LOCAL_PROGUARD_ENABLED := disabled

View File

@@ -16,17 +16,16 @@
package com.android.server.fingerprint;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import android.content.Context;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintDaemon;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.os.IBinder;
import android.os.RemoteException;
import android.system.ErrnoException;
import android.util.Slog;
/**
@@ -85,7 +84,7 @@ public abstract class AuthenticationClient extends ClientMonitor {
try {
Slog.w(TAG, "Forcing lockout (fp driver code should do this!)");
receiver.onError(getHalDeviceId(),
FingerprintManager.FINGERPRINT_ERROR_LOCKOUT);
FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, 0 /* vendorCode */);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to notify lockout:", e);
}
@@ -106,7 +105,7 @@ public abstract class AuthenticationClient extends ClientMonitor {
*/
@Override
public int start() {
IFingerprintDaemon daemon = getFingerprintDaemon();
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "start authentication: no fingeprintd!");
return ERROR_ESRCH;
@@ -116,7 +115,7 @@ public abstract class AuthenticationClient extends ClientMonitor {
if (result != 0) {
Slog.w(TAG, "startAuthentication failed, result=" + result);
MetricsLogger.histogram(getContext(), "fingeprintd_auth_start_error", result);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
return result;
}
if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is authenticating...");
@@ -129,13 +128,13 @@ public abstract class AuthenticationClient extends ClientMonitor {
@Override
public int stop(boolean initiatedByClient) {
IFingerprintDaemon daemon = getFingerprintDaemon();
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "stopAuthentication: no fingeprintd!");
return ERROR_ESRCH;
}
try {
final int result = daemon.cancelAuthentication();
final int result = daemon.cancel();
if (result != 0) {
Slog.w(TAG, "stopAuthentication failed, result=" + result);
return result;
@@ -149,19 +148,19 @@ public abstract class AuthenticationClient extends ClientMonitor {
}
@Override
public boolean onEnrollResult(int fingerId, int groupId, int rem) {
public boolean onEnrollResult(int fingerId, int groupId, int remaining) {
if (DEBUG) Slog.w(TAG, "onEnrollResult() called for authenticate!");
return true; // Invalid for Authenticate
}
@Override
public boolean onRemoved(int fingerId, int groupId) {
public boolean onRemoved(int fingerId, int groupId, int remaining) {
if (DEBUG) Slog.w(TAG, "onRemoved() called for authenticate!");
return true; // Invalid for Authenticate
}
@Override
public boolean onEnumerationResult(int fingerId, int groupId) {
public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for authenticate!");
return true; // Invalid for Authenticate
}

View File

@@ -18,8 +18,8 @@ package com.android.server.fingerprint;
import android.Manifest;
import android.content.Context;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintDaemon;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.os.IBinder;
import android.os.RemoteException;
@@ -94,7 +94,7 @@ public abstract class ClientMonitor implements IBinder.DeathRecipient {
/**
* Gets the fingerprint daemon from the cached state in the container class.
*/
public abstract IFingerprintDaemon getFingerprintDaemon();
public abstract IBiometricsFingerprint getFingerprintDaemon();
// Event callbacks from driver. Inappropriate calls is flagged/logged by the
// respective client (e.g. enrolling shouldn't get authenticate events).
@@ -102,8 +102,8 @@ public abstract class ClientMonitor implements IBinder.DeathRecipient {
// to the next client (e.g. authentication accepts or rejects a fingerprint).
public abstract boolean onEnrollResult(int fingerId, int groupId, int rem);
public abstract boolean onAuthenticated(int fingerId, int groupId);
public abstract boolean onRemoved(int fingerId, int groupId);
public abstract boolean onEnumerationResult(int fingerId, int groupId);
public abstract boolean onRemoved(int fingerId, int groupId, int remaining);
public abstract boolean onEnumerationResult(int fingerId, int groupId, int remaining);
/**
* Called when we get notification from fingerprintd that an image has been acquired.
@@ -111,11 +111,11 @@ public abstract class ClientMonitor implements IBinder.DeathRecipient {
* @param acquiredInfo info about the current image acquisition
* @return true if client should be removed
*/
public boolean onAcquired(int acquiredInfo) {
public boolean onAcquired(int acquiredInfo, int vendorCode) {
if (mReceiver == null)
return true; // client not connected
try {
mReceiver.onAcquired(getHalDeviceId(), acquiredInfo);
mReceiver.onAcquired(getHalDeviceId(), acquiredInfo, vendorCode);
return false; // acquisition continues...
} catch (RemoteException e) {
Slog.w(TAG, "Failed to invoke sendAcquired:", e);
@@ -134,10 +134,10 @@ public abstract class ClientMonitor implements IBinder.DeathRecipient {
* @param error
* @return true if client should be removed
*/
public boolean onError(int error) {
public boolean onError(int error, int vendorCode) {
if (mReceiver != null) {
try {
mReceiver.onError(getHalDeviceId(), error);
mReceiver.onError(getHalDeviceId(), error, vendorCode);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to invoke sendError:", e);
}
@@ -162,7 +162,7 @@ public abstract class ClientMonitor implements IBinder.DeathRecipient {
public void binderDied() {
mToken = null;
mReceiver = null;
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
}
@Override
@@ -170,7 +170,7 @@ public abstract class ClientMonitor implements IBinder.DeathRecipient {
try {
if (mToken != null) {
if (DEBUG) Slog.w(TAG, "removing leaked reference: " + mToken);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
}
} finally {
super.finalize();

View File

@@ -17,8 +17,8 @@
package com.android.server.fingerprint;
import android.content.Context;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintDaemon;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.os.IBinder;
import android.os.RemoteException;
@@ -78,7 +78,7 @@ public abstract class EnrollClient extends ClientMonitor {
@Override
public int start() {
IFingerprintDaemon daemon = getFingerprintDaemon();
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "enroll: no fingeprintd!");
return ERROR_ESRCH;
@@ -89,7 +89,7 @@ public abstract class EnrollClient extends ClientMonitor {
if (result != 0) {
Slog.w(TAG, "startEnroll failed, result=" + result);
MetricsLogger.histogram(getContext(), "fingerprintd_enroll_start_error", result);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
return result;
}
} catch (RemoteException e) {
@@ -100,13 +100,13 @@ public abstract class EnrollClient extends ClientMonitor {
@Override
public int stop(boolean initiatedByClient) {
IFingerprintDaemon daemon = getFingerprintDaemon();
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "stopEnrollment: no fingeprintd!");
return ERROR_ESRCH;
}
try {
final int result = daemon.cancelEnrollment();
final int result = daemon.cancel();
if (result != 0) {
Slog.w(TAG, "startEnrollCancel failed, result = " + result);
return result;
@@ -115,19 +115,19 @@ public abstract class EnrollClient extends ClientMonitor {
Slog.e(TAG, "stopEnrollment failed", e);
}
if (initiatedByClient) {
onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, 0 /* vendorCode */);
}
return 0;
}
@Override
public boolean onRemoved(int fingerId, int groupId) {
public boolean onRemoved(int fingerId, int groupId, int remaining) {
if (DEBUG) Slog.w(TAG, "onRemoved() called for enroll!");
return true; // Invalid for EnrollClient
}
@Override
public boolean onEnumerationResult(int fingerId, int groupId) {
public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for enroll!");
return true; // Invalid for EnrollClient
}

View File

@@ -17,8 +17,8 @@
package com.android.server.fingerprint;
import android.content.Context;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintDaemon;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.os.IBinder;
import android.os.RemoteException;
@@ -30,14 +30,14 @@ import com.android.internal.logging.MetricsLogger;
*/
public abstract class EnumerateClient extends ClientMonitor {
public EnumerateClient(Context context, long halDeviceId, IBinder token,
IFingerprintServiceReceiver receiver, int userId, int groupId,
boolean restricted, String owner) {
IFingerprintServiceReceiver receiver, int groupId, int userId,
boolean restricted, String owner) {
super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
}
@Override
public int start() {
IFingerprintDaemon daemon = getFingerprintDaemon();
IBiometricsFingerprint daemon = getFingerprintDaemon();
// The fingerprint template ids will be removed when we get confirmation from the HAL
try {
final int result = daemon.enumerate();
@@ -45,50 +45,69 @@ public abstract class EnumerateClient extends ClientMonitor {
Slog.w(TAG, "start enumerate for user " + getTargetUserId()
+ " failed, result=" + result);
MetricsLogger.histogram(getContext(), "fingerprintd_enum_start_error", result);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
return result;
}
} catch (RemoteException e) {
Slog.e(TAG, "startRemove failed", e);
Slog.e(TAG, "startEnumeration failed", e);
}
return 0;
}
@Override
public int stop(boolean initiatedByClient) {
IFingerprintDaemon daemon = getFingerprintDaemon();
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "stopAuthentication: no fingeprintd!");
return ERROR_ESRCH;
}
try {
final int result = daemon.cancelEnumeration();
final int result = daemon.cancel();
if (result != 0) {
Slog.w(TAG, "stop enumeration failed, result=" + result);
return result;
}
} catch (RemoteException e) {
Slog.e(TAG, "stop enumeration failed", e);
Slog.e(TAG, "stopEnumeration failed", e);
return ERROR_ESRCH;
}
// We don't actually stop enumerate, but inform the client that the cancel operation
// succeeded so we can start the next operation.
if (initiatedByClient) {
onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, 0 /* vendorCode */);
}
return 0; // success
}
@Override
public boolean onEnumerationResult(int fingerId, int groupId) {
public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
IFingerprintServiceReceiver receiver = getReceiver();
if (receiver == null)
return true; // client not listening
try {
receiver.onRemoved(getHalDeviceId(), fingerId, groupId);
receiver.onEnumerated(getHalDeviceId(), fingerId, groupId, remaining);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to notify enumerated:", e);
}
return fingerId == 0; // done when id hits 0
}
@Override
public boolean onAuthenticated(int fingerId, int groupId) {
if (DEBUG) Slog.w(TAG, "onAuthenticated() called for enumerate!");
return true; // Invalid for Enumerate.
}
@Override
public boolean onEnrollResult(int fingerId, int groupId, int rem) {
if (DEBUG) Slog.w(TAG, "onEnrollResult() called for enumerate!");
return true; // Invalid for Remove
}
@Override
public boolean onRemoved(int fingerId, int groupId, int remaining) {
if (DEBUG) Slog.w(TAG, "onRemoved() called for enumerate!");
return true; // Invalid for Authenticate
}
}

View File

@@ -37,12 +37,12 @@ import android.os.DeadObjectException;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.IHwBinder;
import android.os.IRemoteCallback;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
import android.os.SELinux;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -61,11 +61,12 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.fingerprint.IFingerprintDaemon;
import android.hardware.fingerprint.IFingerprintDaemonCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
@@ -78,7 +79,6 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -90,11 +90,11 @@ import java.util.List;
*
* @hide
*/
public class FingerprintService extends SystemService implements IBinder.DeathRecipient {
public class FingerprintService extends SystemService implements IHwBinder.DeathRecipient {
static final String TAG = "FingerprintService";
static final boolean DEBUG = true;
private static final String FP_DATA_DIR = "fpdata";
private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon";
private static final String FINGERPRINT_HIDL = "fingerprint_hal";
private static final int MSG_USER_SWITCHING = 10;
private static final String ACTION_LOCKOUT_RESET =
"com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
@@ -120,7 +120,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
private long mHalDeviceId;
private int mFailedAttempts;
@GuardedBy("this")
private IFingerprintDaemon mDaemon;
private IBiometricsFingerprint mDaemon;
private final PowerManager mPowerManager;
private final AlarmManager mAlarmManager;
private final UserManager mUserManager;
@@ -130,12 +130,10 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
private PerformanceStats mPerformanceStats;
// Normal fingerprint authentications are tracked by mPerformanceMap.
private HashMap<Integer, PerformanceStats> mPerformanceMap
= new HashMap<Integer, PerformanceStats>();
private HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
// Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
private HashMap<Integer, PerformanceStats> mCryptoPerformanceMap
= new HashMap<Integer, PerformanceStats>();
private HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
private Handler mHandler = new Handler() {
@Override
@@ -201,59 +199,61 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
@Override
public void binderDied() {
public void serviceDied(long cookie) {
Slog.v(TAG, "fingerprintd died");
MetricsLogger.count(mContext, "fingerprintd_died", 1);
synchronized (this) {
mDaemon = null;
}
mCurrentUserId = UserHandle.USER_CURRENT;
handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /*vendorCode */);
}
public IFingerprintDaemon getFingerprintDaemon() {
synchronized (this) {
if (mDaemon == null) {
mDaemon = IFingerprintDaemon.Stub
.asInterface(ServiceManager.getService(FINGERPRINTD));
if (mDaemon != null) {
try {
mDaemon.asBinder().linkToDeath(this, 0);
mDaemon.init(mDaemonCallback);
mHalDeviceId = mDaemon.openHal();
if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
if (mHalDeviceId != 0) {
updateActiveGroup(ActivityManager.getCurrentUser(), null);
} else {
Slog.w(TAG, "Failed to open Fingerprint HAL!");
MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);
mDaemon = null;
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to open fingeprintd HAL", e);
mDaemon = null; // try again later!
}
} else {
Slog.w(TAG, "fingerprint service not available");
}
public synchronized IBiometricsFingerprint getFingerprintDaemon() {
if (mDaemon == null) {
try {
mDaemon = IBiometricsFingerprint.getService(FINGERPRINT_HIDL);
} catch (java.util.NoSuchElementException e) {
// Service doesn't exist or cannot be opened. Logged below.
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get biometric interface", e);
}
if (mDaemon == null) {
Slog.w(TAG, "fingerprint HIDL not available");
return null;
}
mDaemon.asBinder().linkToDeath(this, 0);
try {
mHalDeviceId = mDaemon.setNotify(mDaemonCallback);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to open fingeprintd HAL", e);
mDaemon = null; // try again later!
}
if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
if (mHalDeviceId != 0) {
updateActiveGroup(ActivityManager.getCurrentUser(), null);
} else {
Slog.w(TAG, "Failed to open Fingerprint HAL!");
MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);
mDaemon = null;
}
return mDaemon;
}
return mDaemon;
}
protected void handleEnumerate(long deviceId, int[] fingerIds, int[] groupIds) {
if (fingerIds.length != groupIds.length) {
Slog.w(TAG, "fingerIds and groupIds differ in length: f[]="
+ Arrays.toString(fingerIds) + ", g[]=" + Arrays.toString(groupIds));
return;
}
if (DEBUG) Slog.w(TAG, "Enumerate: f[]=" + fingerIds + ", g[]=" + groupIds);
// TODO: update fingerprint/name pairs
protected void handleEnumerate(long deviceId, int fingerId, int groupId, int remaining) {
if (DEBUG) Slog.w(TAG, "Enumerate: fid=" + fingerId + ", gid="
+ groupId + "rem=" + remaining);
// TODO: coordinate names with framework
}
protected void handleError(long deviceId, int error) {
protected void handleError(long deviceId, int error, int vendorCode) {
ClientMonitor client = mCurrentClient;
if (client != null && client.onError(error)) {
if (client != null && client.onError(error, vendorCode)) {
removeClient(client);
}
if (DEBUG) Slog.v(TAG, "handleError(client="
@@ -269,9 +269,9 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
}
protected void handleRemoved(long deviceId, int fingerId, int groupId) {
protected void handleRemoved(long deviceId, int fingerId, int groupId, int remaining) {
ClientMonitor client = mCurrentClient;
if (client != null && client.onRemoved(fingerId, groupId)) {
if (client != null && client.onRemoved(fingerId, groupId, remaining)) {
removeClient(client);
}
}
@@ -288,9 +288,9 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
}
protected void handleAcquired(long deviceId, int acquiredInfo) {
protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
ClientMonitor client = mCurrentClient;
if (client != null && client.onAcquired(acquiredInfo)) {
if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
removeClient(client);
}
if (mPerformanceStats != null && !inLockoutMode()
@@ -349,7 +349,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
public long startPreEnroll(IBinder token) {
IFingerprintDaemon daemon = getFingerprintDaemon();
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "startPreEnroll: no fingeprintd!");
return 0;
@@ -363,7 +363,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
public int startPostEnroll(IBinder token) {
IFingerprintDaemon daemon = getFingerprintDaemon();
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "startPostEnroll: no fingeprintd!");
return 0;
@@ -403,7 +403,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
void startRemove(IBinder token, int fingerId, int groupId, int userId,
IFingerprintServiceReceiver receiver, boolean restricted) {
IFingerprintDaemon daemon = getFingerprintDaemon();
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "startRemove: no fingeprintd!");
return;
@@ -416,7 +416,29 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
@Override
public IFingerprintDaemon getFingerprintDaemon() {
public IBiometricsFingerprint getFingerprintDaemon() {
return FingerprintService.this.getFingerprintDaemon();
}
};
startClient(client, true);
}
void startEnumerate(IBinder token, int userId,
IFingerprintServiceReceiver receiver, boolean restricted) {
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "startEnumerate: no fingeprintd!");
return;
}
EnumerateClient client = new EnumerateClient(getContext(), mHalDeviceId, token,
receiver, userId, userId, restricted, token.toString()) {
@Override
public void notifyUserActivity() {
FingerprintService.this.userActivity();
}
@Override
public IBiometricsFingerprint getFingerprintDaemon() {
return FingerprintService.this.getFingerprintDaemon();
}
};
@@ -580,7 +602,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
@Override
public IFingerprintDaemon getFingerprintDaemon() {
public IBiometricsFingerprint getFingerprintDaemon() {
return FingerprintService.this.getFingerprintDaemon();
}
};
@@ -588,7 +610,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
if (inLockoutMode()) {
Slog.v(TAG, "In lockout mode; disallowing authentication");
// Don't bother starting the client. Just send the error message.
if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, 0 /* vendorCode */)) {
Slog.w(TAG, "Cannot send timeout message to client");
}
return;
@@ -607,7 +629,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
userId, groupId, cryptoToken, restricted, opPackageName) {
@Override
public IFingerprintDaemon getFingerprintDaemon() {
public IBiometricsFingerprint getFingerprintDaemon() {
return FingerprintService.this.getFingerprintDaemon();
}
@@ -674,7 +696,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
};
}
private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() {
private IBiometricsFingerprintClientCallback mDaemonCallback =
new IBiometricsFingerprintClientCallback.Stub() {
@Override
public void onEnrollResult(final long deviceId, final int fingerId, final int groupId,
@@ -688,11 +711,11 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
@Override
public void onAcquired(final long deviceId, final int acquiredInfo) {
public void onAcquired(final long deviceId, final int acquiredInfo, final int vendorCode) {
mHandler.post(new Runnable() {
@Override
public void run() {
handleAcquired(deviceId, acquiredInfo);
handleAcquired(deviceId, acquiredInfo, vendorCode);
}
});
}
@@ -708,31 +731,32 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
@Override
public void onError(final long deviceId, final int error) {
public void onError(final long deviceId, final int error, final int vendorCode) {
mHandler.post(new Runnable() {
@Override
public void run() {
handleError(deviceId, error);
handleError(deviceId, error, vendorCode);
}
});
}
@Override
public void onRemoved(final long deviceId, final int fingerId, final int groupId) {
public void onRemoved(final long deviceId, final int fingerId, final int groupId, final int remaining) {
mHandler.post(new Runnable() {
@Override
public void run() {
handleRemoved(deviceId, fingerId, groupId);
handleRemoved(deviceId, fingerId, groupId, remaining);
}
});
}
@Override
public void onEnumerate(final long deviceId, final int[] fingerIds, final int[] groupIds) {
public void onEnumerate(final long deviceId, final int fingerId, final int groupId,
final int remaining) {
mHandler.post(new Runnable() {
@Override
public void run() {
handleEnumerate(deviceId, fingerIds, groupIds);
handleEnumerate(deviceId, fingerId, groupId, remaining);
}
});
}
@@ -889,6 +913,19 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
public void enumerate(final IBinder token, final int userId,
final IFingerprintServiceReceiver receiver) {
checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
final boolean restricted = isRestricted();
mHandler.post(new Runnable() {
@Override
public void run() {
startEnumerate(token, userId, receiver, restricted);
}
});
}
@Override // Binder call
public boolean isHardwareDetected(long deviceId, String opPackageName) {
if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
@@ -1082,7 +1119,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
private void updateActiveGroup(int userId, String clientPackage) {
IFingerprintDaemon daemon = getFingerprintDaemon();
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon != null) {
try {
@@ -1103,7 +1140,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
return;
}
}
daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes());
daemon.setActiveGroup(userId, fpDir.getAbsolutePath());
mCurrentUserId = userId;
}
mCurrentAuthenticatorId = daemon.getAuthenticatorId();
@@ -1155,5 +1192,4 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
public long getAuthenticatorId(String opPackageName) {
return mCurrentAuthenticatorId;
}
}

View File

@@ -17,8 +17,8 @@
package com.android.server.fingerprint;
import android.content.Context;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintDaemon;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.os.IBinder;
import android.os.RemoteException;
@@ -41,14 +41,14 @@ public abstract class RemovalClient extends ClientMonitor {
@Override
public int start() {
IFingerprintDaemon daemon = getFingerprintDaemon();
IBiometricsFingerprint daemon = getFingerprintDaemon();
// The fingerprint template ids will be removed when we get confirmation from the HAL
try {
final int result = daemon.remove(mFingerId, getGroupId());
final int result = daemon.remove(getGroupId(), mFingerId);
if (result != 0) {
Slog.w(TAG, "startRemove with id = " + mFingerId + " failed, result=" + result);
MetricsLogger.histogram(getContext(), "fingerprintd_remove_start_error", result);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
return result;
}
} catch (RemoteException e) {
@@ -62,7 +62,7 @@ public abstract class RemovalClient extends ClientMonitor {
// We don't actually stop remove, but inform the client that the cancel operation succeeded
// so we can start the next operation.
if (initiatedByClient) {
onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, 0 /* vendorCode */);
}
return 0;
}
@@ -70,11 +70,12 @@ public abstract class RemovalClient extends ClientMonitor {
/*
* @return true if we're done.
*/
private boolean sendRemoved(int fingerId, int groupId) {
private boolean sendRemoved(int fingerId, int groupId, int remaining) {
IFingerprintServiceReceiver receiver = getReceiver();
try {
if (receiver != null) {
receiver.onRemoved(getHalDeviceId(), fingerId, groupId);
// TODO: plumb remaining
receiver.onRemoved(getHalDeviceId(), fingerId, groupId, remaining);
}
} catch (RemoteException e) {
Slog.w(TAG, "Failed to notify Removed:", e);
@@ -83,12 +84,12 @@ public abstract class RemovalClient extends ClientMonitor {
}
@Override
public boolean onRemoved(int fingerId, int groupId) {
public boolean onRemoved(int fingerId, int groupId, int remaining) {
if (fingerId != 0) {
FingerprintUtils.getInstance().removeFingerprintIdForUser(getContext(), fingerId,
getTargetUserId());
}
return sendRemoved(fingerId, getGroupId());
return sendRemoved(fingerId, getGroupId(), remaining);
}
@Override
@@ -104,9 +105,9 @@ public abstract class RemovalClient extends ClientMonitor {
}
@Override
public boolean onEnumerationResult(int fingerId, int groupId) {
public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for remove!");
return false; // Invalid for Remove.
return true; // Invalid for Remove.
}