Merge "4/n: Add RevokeChallenge and ResetLockout for IFingerprint"
This commit is contained in:
@@ -636,13 +636,24 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes enrollment and cancels the current auth token.
|
||||
* Revokes the current challenge.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(MANAGE_FINGERPRINT)
|
||||
public void revokeChallenge() {
|
||||
// On HALs with only single in-flight challenge such as IBiometricsFingerprint@2.1,
|
||||
// this parameter is ignored.
|
||||
revokeChallenge(0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes the specified challenge.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(MANAGE_FINGERPRINT)
|
||||
public void revokeChallenge(long challenge) {
|
||||
if (mService != null) try {
|
||||
mService.revokeChallenge(mToken, mContext.getOpPackageName());
|
||||
mService.revokeChallenge(mToken, mContext.getOpPackageName(), challenge);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ interface IFingerprintService {
|
||||
void generateChallenge(IBinder token, int sensorId, IFingerprintServiceReceiver receiver, String opPackageName);
|
||||
|
||||
// Finish an enrollment sequence and invalidate the authentication token
|
||||
void revokeChallenge(IBinder token, String opPackageName);
|
||||
void revokeChallenge(IBinder token, String opPackageName, long challenge);
|
||||
|
||||
// Determine if a user has at least one enrolled fingerprint
|
||||
boolean hasEnrolledFingerprints(int userId, String opPackageName);
|
||||
|
||||
@@ -187,7 +187,7 @@ public class FingerprintService extends SystemService {
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void revokeChallenge(IBinder token, String opPackageName) {
|
||||
public void revokeChallenge(IBinder token, String opPackageName, long challenge) {
|
||||
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
|
||||
|
||||
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
|
||||
@@ -196,7 +196,8 @@ public class FingerprintService extends SystemService {
|
||||
return;
|
||||
}
|
||||
|
||||
provider.second.scheduleRevokeChallenge(provider.first, token, opPackageName);
|
||||
provider.second.scheduleRevokeChallenge(provider.first, token, opPackageName,
|
||||
challenge);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
|
||||
@@ -68,7 +68,7 @@ public interface ServiceProvider {
|
||||
@NonNull IFingerprintServiceReceiver receiver, String opPackageName);
|
||||
|
||||
void scheduleRevokeChallenge(int sensorId, @NonNull IBinder token,
|
||||
@NonNull String opPackageName);
|
||||
@NonNull String opPackageName, long challenge);
|
||||
|
||||
void scheduleEnroll(int sensorId, @NonNull IBinder token, byte[] hardwareAuthToken, int userId,
|
||||
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
|
||||
|
||||
@@ -34,7 +34,7 @@ public class FingerprintGenerateChallengeClient extends GenerateChallengeClient<
|
||||
private static final String TAG = "FingerprintGenerateChallengeClient";
|
||||
private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
|
||||
|
||||
private IGenerateChallengeCallback mGenerateChallengeCallback =
|
||||
private final IGenerateChallengeCallback mGenerateChallengeCallback =
|
||||
new IGenerateChallengeCallback.Stub() {
|
||||
@Override
|
||||
public void onChallengeGenerated(int sensorId, int userId, long challenge) {
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.hardware.biometrics.BiometricsProtoEnums;
|
||||
import android.hardware.biometrics.fingerprint.IFingerprint;
|
||||
import android.hardware.biometrics.fingerprint.SensorProps;
|
||||
import android.hardware.fingerprint.Fingerprint;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.hardware.fingerprint.IFingerprintServiceReceiver;
|
||||
import android.hardware.fingerprint.IUdfpsOverlayController;
|
||||
@@ -58,6 +59,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
@NonNull private final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
|
||||
@NonNull private final ClientMonitor.LazyDaemon<IFingerprint> mLazyDaemon;
|
||||
@NonNull private final Handler mHandler;
|
||||
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
|
||||
|
||||
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
|
||||
|
||||
@@ -69,6 +71,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
mSensors = new SparseArray<>();
|
||||
mLazyDaemon = this::getHalInstance;
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
mLockoutResetDispatcher = lockoutResetDispatcher;
|
||||
|
||||
for (SensorProps prop : props) {
|
||||
final int sensorId = prop.commonProps.sensorId;
|
||||
@@ -157,7 +160,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
@NonNull
|
||||
@Override
|
||||
public List<FingerprintSensorPropertiesInternal> getSensorProperties() {
|
||||
List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
|
||||
final List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
|
||||
for (int i = 0; i < mSensors.size(); i++) {
|
||||
props.add(mSensors.valueAt(i).getSensorProperties());
|
||||
}
|
||||
@@ -166,7 +169,27 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
|
||||
@Override
|
||||
public void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken) {
|
||||
mHandler.post(() -> {
|
||||
final IFingerprint daemon = getHalInstance();
|
||||
if (daemon == null) {
|
||||
Slog.e(getTag(), "Null daemon during resetLockout, sensorId: " + sensorId);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
|
||||
scheduleCreateSessionWithoutHandler(daemon, sensorId, userId);
|
||||
}
|
||||
|
||||
final FingerprintResetLockoutClient client = new FingerprintResetLockoutClient(
|
||||
mContext, mSensors.get(sensorId).getLazySession(), userId,
|
||||
mContext.getOpPackageName(), sensorId, hardwareAuthToken,
|
||||
mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher);
|
||||
scheduleForSensor(sensorId, client);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(getTag(), "Remote exception when scheduling resetLockout", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -176,14 +199,19 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
final FingerprintGenerateChallengeClient client =
|
||||
new FingerprintGenerateChallengeClient(mContext, mLazyDaemon, token,
|
||||
new ClientMonitorCallbackConverter(receiver), opPackageName, sensorId);
|
||||
mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scheduleRevokeChallenge(int sensorId, @NonNull IBinder token,
|
||||
@NonNull String opPackageName) {
|
||||
|
||||
@NonNull String opPackageName, long challenge) {
|
||||
mHandler.post(() -> {
|
||||
final FingerprintRevokeChallengeClient client =
|
||||
new FingerprintRevokeChallengeClient(mContext, mLazyDaemon, token,
|
||||
opPackageName, sensorId, challenge);
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -194,6 +222,13 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
final IFingerprint daemon = getHalInstance();
|
||||
if (daemon == null) {
|
||||
Slog.e(getTag(), "Null daemon during enroll, sensorId: " + sensorId);
|
||||
|
||||
try {
|
||||
receiver.onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
|
||||
0 /* vendorCode */);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(getTag(), "Unable to send HW_UNAVAILABLE", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 com.android.server.biometrics.sensors.fingerprint.aidl;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricsProtoEnums;
|
||||
import android.hardware.biometrics.fingerprint.IFingerprint;
|
||||
import android.hardware.biometrics.fingerprint.ISession;
|
||||
import android.hardware.keymaster.HardwareAuthToken;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.biometrics.HardwareAuthTokenUtils;
|
||||
import com.android.server.biometrics.sensors.ClientMonitor;
|
||||
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
|
||||
import com.android.server.biometrics.sensors.LockoutTracker;
|
||||
|
||||
/**
|
||||
* Fingerprint-specific resetLockout client for the {@link IFingerprint} AIDL HAL interface.
|
||||
* Updates the framework's lockout cache and notifies clients such as Keyguard when lockout is
|
||||
* cleared.
|
||||
*/
|
||||
public class FingerprintResetLockoutClient extends ClientMonitor<ISession> {
|
||||
|
||||
private static final String TAG = "FingerprintResetLockoutClient";
|
||||
|
||||
private final HardwareAuthToken mHardwareAuthToken;
|
||||
private final LockoutCache mLockoutCache;
|
||||
private final LockoutResetDispatcher mLockoutResetDispatcher;
|
||||
|
||||
public FingerprintResetLockoutClient(@NonNull Context context,
|
||||
@NonNull LazyDaemon<ISession> lazyDaemon, int userId, String owner, int sensorId,
|
||||
@NonNull byte[] hardwareAuthToken, @NonNull LockoutCache lockoutTracker,
|
||||
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
|
||||
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
|
||||
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
|
||||
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
|
||||
mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
|
||||
mLockoutCache = lockoutTracker;
|
||||
mLockoutResetDispatcher = lockoutResetDispatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unableToStart() {
|
||||
// Nothing to do here
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startHalOperation() {
|
||||
try {
|
||||
getFreshDaemon().resetLockout(mSequentialId, mHardwareAuthToken);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to reset lockout", e);
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
}
|
||||
}
|
||||
|
||||
void onLockoutCleared() {
|
||||
mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_NONE);
|
||||
mLockoutResetDispatcher.notifyLockoutResetCallbacks(getSensorId());
|
||||
mCallback.onClientFinished(this, true /* success */);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 com.android.server.biometrics.sensors.fingerprint.aidl;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.fingerprint.IFingerprint;
|
||||
import android.hardware.biometrics.fingerprint.IRevokeChallengeCallback;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.biometrics.sensors.RevokeChallengeClient;
|
||||
|
||||
/**
|
||||
* Fingerprint-specific revokeChallenge client for the {@link IFingerprint} AIDL HAL interface.
|
||||
*/
|
||||
public class FingerprintRevokeChallengeClient extends RevokeChallengeClient<IFingerprint> {
|
||||
|
||||
private static final String TAG = "FingerpirntRevokeChallengeClient";
|
||||
|
||||
private final long mChallenge;
|
||||
|
||||
private final IRevokeChallengeCallback mRevokeChallengeCallback =
|
||||
new IRevokeChallengeCallback.Stub() {
|
||||
@Override
|
||||
public void onChallengeRevoked(int sensorId, int userId, long challenge) {
|
||||
final boolean success = challenge == mChallenge;
|
||||
mCallback.onClientFinished(FingerprintRevokeChallengeClient.this, success);
|
||||
}
|
||||
};
|
||||
|
||||
public FingerprintRevokeChallengeClient(
|
||||
@NonNull Context context,
|
||||
@NonNull LazyDaemon<IFingerprint> lazyDaemon,
|
||||
@NonNull IBinder token,
|
||||
@NonNull String owner, int sensorId, long challenge) {
|
||||
super(context, lazyDaemon, token, owner, sensorId);
|
||||
mChallenge = challenge;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startHalOperation() {
|
||||
try {
|
||||
getFreshDaemon().revokeChallenge(getSensorId(), getTargetUserId(), mChallenge,
|
||||
mRevokeChallengeCallback);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to revokeChallenge", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 com.android.server.biometrics.sensors.fingerprint.aidl;
|
||||
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.android.server.biometrics.sensors.LockoutTracker;
|
||||
|
||||
/**
|
||||
* For a single sensor, caches lockout states for all users.
|
||||
*/
|
||||
public class LockoutCache implements LockoutTracker {
|
||||
|
||||
// Map of userId to LockoutMode
|
||||
private final SparseIntArray mUserLockoutStates;
|
||||
|
||||
LockoutCache() {
|
||||
mUserLockoutStates = new SparseIntArray();
|
||||
}
|
||||
|
||||
public void setLockoutModeForUser(int userId, @LockoutMode int mode) {
|
||||
synchronized (this) {
|
||||
mUserLockoutStates.put(userId, mode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLockoutModeForUser(int userId) {
|
||||
synchronized (this) {
|
||||
return mUserLockoutStates.get(userId, LOCKOUT_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ class Sensor {
|
||||
@NonNull private final Handler mHandler;
|
||||
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
|
||||
@NonNull private final BiometricScheduler mScheduler;
|
||||
@NonNull private final LockoutCache mLockoutCache;
|
||||
|
||||
@Nullable private Session mCurrentSession; // TODO: Death recipient
|
||||
@NonNull private final ClientMonitor.LazyDaemon<ISession> mLazySession;
|
||||
@@ -82,6 +83,7 @@ class Sensor {
|
||||
mHandler = handler;
|
||||
mSensorProperties = sensorProperties;
|
||||
mScheduler = new BiometricScheduler(tag, gestureAvailabilityDispatcher);
|
||||
mLockoutCache = new LockoutCache();
|
||||
mLazySession = () -> mCurrentSession != null ? mCurrentSession.mSession : null;
|
||||
}
|
||||
|
||||
@@ -217,7 +219,18 @@ class Sensor {
|
||||
|
||||
@Override
|
||||
public void onLockoutCleared() {
|
||||
mHandler.post(() -> {
|
||||
final ClientMonitor<?> client = mScheduler.getCurrentClient();
|
||||
if (!(client instanceof FingerprintResetLockoutClient)) {
|
||||
Slog.e(mTag, "onLockoutCleared for non-resetLockout client: "
|
||||
+ Utils.getClientName(client));
|
||||
return;
|
||||
}
|
||||
|
||||
final FingerprintResetLockoutClient resetLockoutClient =
|
||||
(FingerprintResetLockoutClient) client;
|
||||
resetLockoutClient.onLockoutCleared();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -253,4 +266,8 @@ class Sensor {
|
||||
@NonNull BiometricScheduler getScheduler() {
|
||||
return mScheduler;
|
||||
}
|
||||
|
||||
@NonNull LockoutCache getLockoutCache() {
|
||||
return mLockoutCache;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,7 +518,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
|
||||
@Override
|
||||
public void scheduleRevokeChallenge(int sensorId, @NonNull IBinder token,
|
||||
@NonNull String opPackageName) {
|
||||
@NonNull String opPackageName, long challenge) {
|
||||
mHandler.post(() -> {
|
||||
final FingerprintRevokeChallengeClient client = new FingerprintRevokeChallengeClient(
|
||||
mContext, mLazyDaemon, token, opPackageName, mSensorProperties.sensorId);
|
||||
|
||||
Reference in New Issue
Block a user