Merge "Enabled multibiometric lockout for aidl hals"

This commit is contained in:
Joshua Mccloskey
2022-11-06 18:16:24 +00:00
committed by Android (Google) Code Review
33 changed files with 755 additions and 364 deletions

View File

@@ -639,5 +639,24 @@ public class BiometricManager {
}
}
}
/**
* Notifies AuthService that keyguard has been dismissed for the given userId.
*
* @param userId
* @param hardwareAuthToken
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public void resetLockout(int userId, byte[] hardwareAuthToken) {
if (mService != null) {
try {
mService.resetLockout(userId, hardwareAuthToken);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}

View File

@@ -73,4 +73,5 @@ public abstract class BiometricStateListener extends IBiometricStateListener.Stu
*/
public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
}
}

View File

@@ -79,6 +79,9 @@ interface IAuthService {
void resetLockoutTimeBound(IBinder token, String opPackageName, int fromSensorId, int userId,
in byte[] hardwareAuthToken);
// See documentation in BiometricManager.
void resetLockout(int userId, in byte[] hardwareAuthToken);
// Provides a localized string that may be used as the label for a button that invokes
// BiometricPrompt.
CharSequence getButtonLabel(int userId, String opPackageName, int authenticators);

View File

@@ -91,6 +91,10 @@ interface IBiometricService {
void resetLockoutTimeBound(IBinder token, String opPackageName, int fromSensorId, int userId,
in byte[] hardwareAuthToken);
// See documentation in BiometricManager.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void resetLockout(int userId, in byte[] hardwareAuthToken);
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
int getCurrentStrength(int sensorId);

View File

@@ -409,6 +409,17 @@ public class AuthService extends SystemService {
}
}
@Override
public void resetLockout(int userId, byte[] hardwareAuthToken) throws RemoteException {
checkInternalPermission();
final long identity = Binder.clearCallingIdentity();
try {
mBiometricService.resetLockout(userId, hardwareAuthToken);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public CharSequence getButtonLabel(
int userId,

View File

@@ -72,6 +72,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemService;
import com.android.server.biometrics.log.BiometricContext;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -100,6 +101,7 @@ public class BiometricService extends SystemService {
private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks;
private final Random mRandom = new Random();
@NonNull private final Supplier<Long> mRequestCounter;
@NonNull private final BiometricContext mBiometricContext;
@VisibleForTesting
IStatusBarService mStatusBarService;
@@ -774,6 +776,16 @@ public class BiometricService extends SystemService {
}
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public void resetLockout(
int userId, byte[] hardwareAuthToken) {
Slog.d(TAG, "resetLockout(userId=" + userId
+ ", hat=" + (hardwareAuthToken == null ? "null " : "present") + ")");
mBiometricContext.getAuthSessionCoordinator()
.resetLockoutFor(userId, Authenticators.BIOMETRIC_STRONG, -1);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public int getCurrentStrength(int sensorId) {
@@ -984,6 +996,10 @@ public class BiometricService extends SystemService {
final AtomicLong generator = new AtomicLong(0);
return () -> generator.incrementAndGet();
}
public BiometricContext getBiometricContext(Context context) {
return BiometricContext.getInstance(context);
}
}
/**
@@ -1010,6 +1026,7 @@ public class BiometricService extends SystemService {
mSettingObserver = mInjector.getSettingObserver(context, mHandler,
mEnabledOnKeyguardCallbacks);
mRequestCounter = mInjector.getRequestGenerator();
mBiometricContext = injector.getBiometricContext(context);
try {
injector.getActivityManagerService().registerUserSwitchObserver(

View File

@@ -48,8 +48,6 @@ import java.util.List;
* the PreAuthInfo should not change any sensor state.
*/
class PreAuthInfo {
private static final String TAG = "BiometricService/PreAuthInfo";
static final int AUTHENTICATOR_OK = 1;
static final int BIOMETRIC_NO_HARDWARE = 2;
static final int BIOMETRIC_DISABLED_BY_DEVICE_POLICY = 3;
@@ -62,24 +60,7 @@ class PreAuthInfo {
static final int BIOMETRIC_LOCKOUT_TIMED = 10;
static final int BIOMETRIC_LOCKOUT_PERMANENT = 11;
static final int BIOMETRIC_SENSOR_PRIVACY_ENABLED = 12;
@IntDef({AUTHENTICATOR_OK,
BIOMETRIC_NO_HARDWARE,
BIOMETRIC_DISABLED_BY_DEVICE_POLICY,
BIOMETRIC_INSUFFICIENT_STRENGTH,
BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE,
BIOMETRIC_HARDWARE_NOT_DETECTED,
BIOMETRIC_NOT_ENROLLED,
BIOMETRIC_NOT_ENABLED_FOR_APPS,
CREDENTIAL_NOT_ENROLLED,
BIOMETRIC_LOCKOUT_TIMED,
BIOMETRIC_LOCKOUT_PERMANENT,
BIOMETRIC_SENSOR_PRIVACY_ENABLED})
@Retention(RetentionPolicy.SOURCE)
@interface AuthenticatorStatus {}
private final boolean mBiometricRequested;
private final int mBiometricStrengthRequested;
private static final String TAG = "BiometricService/PreAuthInfo";
final boolean credentialRequested;
// Sensors that can be used for this request (e.g. strong enough, enrolled, enabled).
final List<BiometricSensor> eligibleSensors;
@@ -90,6 +71,25 @@ class PreAuthInfo {
final boolean ignoreEnrollmentState;
final int userId;
final Context context;
private final boolean mBiometricRequested;
private final int mBiometricStrengthRequested;
private PreAuthInfo(boolean biometricRequested, int biometricStrengthRequested,
boolean credentialRequested, List<BiometricSensor> eligibleSensors,
List<Pair<BiometricSensor, Integer>> ineligibleSensors, boolean credentialAvailable,
boolean confirmationRequested, boolean ignoreEnrollmentState, int userId,
Context context) {
mBiometricRequested = biometricRequested;
mBiometricStrengthRequested = biometricStrengthRequested;
this.credentialRequested = credentialRequested;
this.eligibleSensors = eligibleSensors;
this.ineligibleSensors = ineligibleSensors;
this.credentialAvailable = credentialAvailable;
this.confirmationRequested = confirmationRequested;
this.ignoreEnrollmentState = ignoreEnrollmentState;
this.userId = userId;
this.context = context;
}
static PreAuthInfo create(ITrustManager trustManager,
DevicePolicyManager devicePolicyManager,
@@ -158,7 +158,8 @@ class PreAuthInfo {
*
* @return @AuthenticatorStatus
*/
private static @AuthenticatorStatus int getStatusForBiometricAuthenticator(
private static @AuthenticatorStatus
int getStatusForBiometricAuthenticator(
DevicePolicyManager devicePolicyManager,
BiometricService.SettingObserver settingObserver,
BiometricSensor sensor, int userId, String opPackageName,
@@ -200,7 +201,6 @@ class PreAuthInfo {
}
}
final @LockoutTracker.LockoutMode int lockoutMode =
sensor.impl.getLockoutModeForUser(userId);
if (lockoutMode == LockoutTracker.LOCKOUT_TIMED) {
@@ -248,8 +248,8 @@ class PreAuthInfo {
/**
* @param modality one of {@link BiometricAuthenticator#TYPE_FINGERPRINT},
* {@link BiometricAuthenticator#TYPE_IRIS} or {@link BiometricAuthenticator#TYPE_FACE}
* @return
* {@link BiometricAuthenticator#TYPE_IRIS} or
* {@link BiometricAuthenticator#TYPE_FACE}
*/
private static int mapModalityToDevicePolicyType(int modality) {
switch (modality) {
@@ -265,24 +265,6 @@ class PreAuthInfo {
}
}
private PreAuthInfo(boolean biometricRequested, int biometricStrengthRequested,
boolean credentialRequested, List<BiometricSensor> eligibleSensors,
List<Pair<BiometricSensor, Integer>> ineligibleSensors, boolean credentialAvailable,
boolean confirmationRequested, boolean ignoreEnrollmentState, int userId,
Context context) {
mBiometricRequested = biometricRequested;
mBiometricStrengthRequested = biometricStrengthRequested;
this.credentialRequested = credentialRequested;
this.eligibleSensors = eligibleSensors;
this.ineligibleSensors = ineligibleSensors;
this.credentialAvailable = credentialAvailable;
this.confirmationRequested = confirmationRequested;
this.ignoreEnrollmentState = ignoreEnrollmentState;
this.userId = userId;
this.context = context;
}
private Pair<BiometricSensor, Integer> calculateErrorByPriority() {
// If the caller requested STRONG, and the device contains both STRONG and non-STRONG
// sensors, prioritize BIOMETRIC_NOT_ENROLLED over the weak sensor's
@@ -303,6 +285,7 @@ class PreAuthInfo {
* surface, combined with the actual sensor/credential and user/system settings, calculate the
* internal {@link AuthenticatorStatus} that should be returned to the client. Note that this
* will need to be converted into the public API constant.
*
* @return Pair<Modality, Error> with error being the internal {@link AuthenticatorStatus} code
*/
private Pair<Integer, Integer> getInternalStatus() {
@@ -391,7 +374,8 @@ class PreAuthInfo {
/**
* @return public BiometricManager result for the current request.
*/
@BiometricManager.BiometricError int getCanAuthenticateResult() {
@BiometricManager.BiometricError
int getCanAuthenticateResult() {
// TODO: Convert this directly
return Utils.biometricConstantsToBiometricManager(
Utils.authenticatorStatusToBiometricConstant(
@@ -401,6 +385,7 @@ class PreAuthInfo {
/**
* For the given request, generate the appropriate reason why authentication cannot be started.
* Note that for some errors, modality is intentionally cleared.
*
* @return Pair<Modality, Error> with modality being filtered if necessary, and error
* being one of the public {@link android.hardware.biometrics.BiometricConstants} codes.
*/
@@ -443,7 +428,8 @@ class PreAuthInfo {
* @return bitmask representing the modalities that are running or could be running for the
* current session.
*/
@BiometricAuthenticator.Modality int getEligibleModalities() {
@BiometricAuthenticator.Modality
int getEligibleModalities() {
@BiometricAuthenticator.Modality int modalities = 0;
for (BiometricSensor sensor : eligibleSensors) {
modalities |= sensor.modality;
@@ -474,7 +460,7 @@ class PreAuthInfo {
+ ", StrengthRequested: " + mBiometricStrengthRequested
+ ", CredentialRequested: " + credentialRequested);
string.append(", Eligible:{");
for (BiometricSensor sensor: eligibleSensors) {
for (BiometricSensor sensor : eligibleSensors) {
string.append(sensor.id).append(" ");
}
string.append("}");
@@ -489,4 +475,20 @@ class PreAuthInfo {
string.append(", ");
return string.toString();
}
@IntDef({AUTHENTICATOR_OK,
BIOMETRIC_NO_HARDWARE,
BIOMETRIC_DISABLED_BY_DEVICE_POLICY,
BIOMETRIC_INSUFFICIENT_STRENGTH,
BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE,
BIOMETRIC_HARDWARE_NOT_DETECTED,
BIOMETRIC_NOT_ENROLLED,
BIOMETRIC_NOT_ENABLED_FOR_APPS,
CREDENTIAL_NOT_ENROLLED,
BIOMETRIC_LOCKOUT_TIMED,
BIOMETRIC_LOCKOUT_PERMANENT,
BIOMETRIC_SENSOR_PRIVACY_ENABLED})
@Retention(RetentionPolicy.SOURCE)
@interface AuthenticatorStatus {
}
}

View File

@@ -44,7 +44,7 @@ import java.util.function.Consumer;
/**
* A default provider for {@link BiometricContext}.
*/
final class BiometricContextProvider implements BiometricContext {
public final class BiometricContextProvider implements BiometricContext {
private static final String TAG = "BiometricContextProvider";
@@ -83,7 +83,8 @@ final class BiometricContextProvider implements BiometricContext {
private boolean mIsAwake = false;
@VisibleForTesting
BiometricContextProvider(@NonNull AmbientDisplayConfiguration ambientDisplayConfiguration,
public BiometricContextProvider(
@NonNull AmbientDisplayConfiguration ambientDisplayConfiguration,
@NonNull IStatusBarService service, @Nullable Handler handler,
AuthSessionCoordinator authSessionCoordinator) {
mAmbientDisplayConfiguration = ambientDisplayConfiguration;

View File

@@ -75,7 +75,10 @@ class AuthResultCoordinator {
* Adds auth success for a given strength to the current operation list.
*/
void authenticatedFor(@Authenticators.Types int strength) {
updateState(strength, (old) -> AUTHENTICATOR_UNLOCKED | old);
// Only strong unlocks matter.
if (strength == Authenticators.BIOMETRIC_STRONG) {
updateState(strength, (old) -> AUTHENTICATOR_UNLOCKED | old);
}
}
/**

View File

@@ -75,6 +75,7 @@ public class AuthSessionCoordinator implements AuthSessionListener {
mUserId = userId;
mIsAuthenticating = true;
mAuthOperations.clear();
mTimedLockouts.clear();
mAuthResultCoordinator = new AuthResultCoordinator();
mRingBuffer.addApiCall("internal : onAuthSessionStarted(" + userId + ")");
}
@@ -88,7 +89,6 @@ public class AuthSessionCoordinator implements AuthSessionListener {
*/
void endAuthSession() {
if (mIsAuthenticating) {
mAuthOperations.clear();
final long currentTime = mClock.millis();
for (Pair<Integer, Long> timedLockouts : mTimedLockouts) {
mMultiBiometricLockoutState.increaseLockoutTime(mUserId, timedLockouts.first,
@@ -109,16 +109,24 @@ public class AuthSessionCoordinator implements AuthSessionListener {
}
}
mRingBuffer.addApiCall("internal : onAuthSessionEnded(" + mUserId + ")");
mIsAuthenticating = false;
clearSession();
}
}
private void clearSession() {
mIsAuthenticating = false;
mTimedLockouts.clear();
mAuthOperations.clear();
}
/**
* @return true if a user can authenticate with a given strength.
* Returns the current lockout state for a given user/strength.
*/
public boolean getCanAuthFor(int userId, @Authenticators.Types int strength) {
return mMultiBiometricLockoutState.canUserAuthenticate(userId, strength);
@LockoutTracker.LockoutMode
public int getLockoutStateFor(int userId, @Authenticators.Types int strength) {
return mMultiBiometricLockoutState.getLockoutState(userId, strength);
}
@Override
@@ -145,19 +153,8 @@ public class AuthSessionCoordinator implements AuthSessionListener {
}
@Override
public void authenticatedFor(int userId, @Authenticators.Types int biometricStrength,
int sensorId, long requestId) {
final String authStr =
"authenticatedFor(userId=" + userId + ", strength=" + biometricStrength
+ " , sensorId=" + sensorId + ", requestId= " + requestId + ")";
mRingBuffer.addApiCall(authStr);
mAuthResultCoordinator.authenticatedFor(biometricStrength);
attemptToFinish(userId, sensorId, authStr);
}
@Override
public void lockedOutFor(int userId, @Authenticators.Types int biometricStrength,
int sensorId, long requestId) {
public void lockedOutFor(int userId, @Authenticators.Types int biometricStrength, int sensorId,
long requestId) {
final String lockedOutStr =
"lockOutFor(userId=" + userId + ", biometricStrength=" + biometricStrength
+ ", sensorId=" + sensorId + ", requestId=" + requestId + ")";
@@ -179,12 +176,16 @@ public class AuthSessionCoordinator implements AuthSessionListener {
}
@Override
public void authEndedFor(int userId, @Authenticators.Types int biometricStrength,
int sensorId, long requestId) {
public void authEndedFor(int userId, @Authenticators.Types int biometricStrength, int sensorId,
long requestId, boolean wasSuccessful) {
final String authEndedStr =
"authEndedFor(userId=" + userId + " ,biometricStrength=" + biometricStrength
+ ", sensorId=" + sensorId + ", requestId=" + requestId + ")";
+ ", sensorId=" + sensorId + ", requestId=" + requestId + ", wasSuccessful="
+ wasSuccessful + ")";
mRingBuffer.addApiCall(authEndedStr);
if (wasSuccessful) {
mAuthResultCoordinator.authenticatedFor(biometricStrength);
}
attemptToFinish(userId, sensorId, authEndedStr);
}
@@ -195,6 +196,12 @@ public class AuthSessionCoordinator implements AuthSessionListener {
"resetLockoutFor(userId=" + userId + " ,biometricStrength=" + biometricStrength
+ ", requestId=" + requestId + ")";
mRingBuffer.addApiCall(resetLockStr);
if (biometricStrength == Authenticators.BIOMETRIC_STRONG) {
clearSession();
} else {
// Lockouts cannot be reset by non-strong biometrics
return;
}
mMultiBiometricLockoutState.setAuthenticatorTo(userId, biometricStrength,
true /*canAuthenticate */);
mMultiBiometricLockoutState.clearLockoutTime(userId, biometricStrength);

View File

@@ -27,17 +27,11 @@ interface AuthSessionListener {
*/
void authStartedFor(int userId, int sensorId, long requestId);
/**
* Indicates a successful authentication occurred for a sensor of a given strength.
*/
void authenticatedFor(int userId, @Authenticators.Types int biometricStrength, int sensorId,
long requestId);
/**
* Indicates authentication ended for a sensor of a given strength.
*/
void authEndedFor(int userId, @Authenticators.Types int biometricStrength, int sensorId,
long requestId);
long requestId, boolean wasSuccessful);
/**
* Indicates a lockout occurred for a sensor of a given strength.

View File

@@ -81,9 +81,12 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
@State
protected int mState = STATE_NEW;
private long mStartTimeMs;
private boolean mAuthAttempted;
private boolean mAuthSuccess = false;
private final int mSensorStrength;
// This is used to determine if we should use the old lockout counter (HIDL) or the new lockout
// counter implementation (AIDL)
private final boolean mShouldUseLockoutTracker;
public AuthenticationClient(@NonNull Context context, @NonNull Supplier<T> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
@@ -92,7 +95,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
@NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext,
boolean isStrongBiometric, @Nullable TaskStackListener taskStackListener,
@NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication,
boolean shouldVibrate, boolean isKeyguardBypassEnabled) {
boolean shouldVibrate, boolean isKeyguardBypassEnabled, int sensorStrength) {
super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId,
shouldVibrate, biometricLogger, biometricContext);
mIsStrongBiometric = isStrongBiometric;
@@ -105,22 +108,13 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
mIsRestricted = restricted;
mAllowBackgroundAuthentication = allowBackgroundAuthentication;
mIsKeyguardBypassEnabled = isKeyguardBypassEnabled;
mShouldUseLockoutTracker = lockoutTracker != null;
mSensorStrength = sensorStrength;
}
@LockoutTracker.LockoutMode
public int handleFailedAttempt(int userId) {
@LockoutTracker.LockoutMode final int lockoutMode =
mLockoutTracker.getLockoutModeForUser(userId);
final PerformanceTracker performanceTracker =
PerformanceTracker.getInstanceForSensorId(getSensorId());
if (lockoutMode == LockoutTracker.LOCKOUT_PERMANENT) {
performanceTracker.incrementPermanentLockoutForUser(userId);
} else if (lockoutMode == LockoutTracker.LOCKOUT_TIMED) {
performanceTracker.incrementTimedLockoutForUser(userId);
}
return lockoutMode;
return LockoutTracker.LOCKOUT_NONE;
}
protected long getStartTimeMs() {
@@ -273,10 +267,12 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
cancel();
} else {
// Allow system-defined limit of number of attempts before giving up
@LockoutTracker.LockoutMode final int lockoutMode =
handleFailedAttempt(getTargetUserId());
if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
markAlreadyDone();
if (mShouldUseLockoutTracker) {
@LockoutTracker.LockoutMode final int lockoutMode =
handleFailedAttempt(getTargetUserId());
if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
markAlreadyDone();
}
}
try {
@@ -309,13 +305,6 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
@Override
public void onAcquired(int acquiredInfo, int vendorCode) {
super.onAcquired(acquiredInfo, vendorCode);
@LockoutTracker.LockoutMode final int lockoutMode =
mLockoutTracker.getLockoutModeForUser(getTargetUserId());
if (lockoutMode == LockoutTracker.LOCKOUT_NONE) {
PerformanceTracker pt = PerformanceTracker.getInstanceForSensorId(getSensorId());
pt.incrementAcquireForUser(getTargetUserId(), isCryptoOperation());
}
}
@Override
@@ -331,8 +320,14 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
@LockoutTracker.LockoutMode final int lockoutMode =
mLockoutTracker.getLockoutModeForUser(getTargetUserId());
final @LockoutTracker.LockoutMode int lockoutMode;
if (mShouldUseLockoutTracker) {
lockoutMode = mLockoutTracker.getLockoutModeForUser(getTargetUserId());
} else {
lockoutMode = getBiometricContext().getAuthSessionCoordinator()
.getLockoutStateFor(getTargetUserId(), mSensorStrength);
}
if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
Slog.v(TAG, "In lockout mode(" + lockoutMode + ") ; disallowing authentication");
int errorCode = lockoutMode == LockoutTracker.LOCKOUT_TIMED
@@ -406,6 +401,14 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
return mAuthSuccess;
}
protected int getSensorStrength() {
return mSensorStrength;
}
protected LockoutTracker getLockoutTracker() {
return mLockoutTracker;
}
protected int getShowOverlayReason() {
if (isKeyguard()) {
return BiometricOverlayConstants.REASON_AUTH_KEYGUARD;

View File

@@ -75,6 +75,9 @@ class MultiBiometricLockoutState {
// fall through
case Authenticators.BIOMETRIC_CONVENIENCE:
authMap.get(BIOMETRIC_CONVENIENCE).mPermanentlyLockedOut = !canAuth;
return;
default:
Slog.e(TAG, "increaseLockoutTime called for invalid strength : " + strength);
}
}
@@ -89,6 +92,9 @@ class MultiBiometricLockoutState {
// fall through
case Authenticators.BIOMETRIC_CONVENIENCE:
authMap.get(BIOMETRIC_CONVENIENCE).increaseLockoutTo(duration);
return;
default:
Slog.e(TAG, "increaseLockoutTime called for invalid strength : " + strength);
}
}
@@ -103,22 +109,34 @@ class MultiBiometricLockoutState {
// fall through
case Authenticators.BIOMETRIC_CONVENIENCE:
authMap.get(BIOMETRIC_CONVENIENCE).setTimedLockout(0);
return;
default:
Slog.e(TAG, "clearLockoutTime called for invalid strength : " + strength);
}
}
/**
* Indicates if a user can perform an authentication operation with a given
* {@link Authenticators.Types}
* Retrieves the lockout state for a user of a specified strength.
*
* @param userId The user.
* @param strength The strength of biometric that is requested to authenticate.
* @return If a user can authenticate with a given biometric of this strength.
*/
boolean canUserAuthenticate(int userId, @Authenticators.Types int strength) {
final boolean canAuthenticate = getAuthMapForUser(userId).get(strength).canAuthenticate();
Slog.d(TAG, "canUserAuthenticate(userId=" + userId + ", strength=" + strength + ") ="
+ canAuthenticate);
return canAuthenticate;
@LockoutTracker.LockoutMode
int getLockoutState(int userId, @Authenticators.Types int strength) {
final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId);
if (!authMap.containsKey(strength)) {
Slog.e(TAG, "Error, getLockoutState for unknown strength: " + strength
+ " returning LOCKOUT_NONE");
return LockoutTracker.LOCKOUT_NONE;
}
final AuthenticatorState state = authMap.get(strength);
if (state.mPermanentlyLockedOut) {
return LockoutTracker.LOCKOUT_PERMANENT;
} else if (state.isTimedLockout()) {
return LockoutTracker.LOCKOUT_TIMED;
} else {
return LockoutTracker.LOCKOUT_NONE;
}
}
@Override
@@ -152,7 +170,15 @@ class MultiBiometricLockoutState {
}
boolean canAuthenticate() {
return !mPermanentlyLockedOut && mClock.millis() - mTimedLockout >= 0;
return !mPermanentlyLockedOut && !isTimedLockout();
}
boolean isTimedLockout() {
return mClock.millis() - mTimedLockout < 0;
}
void setTimedLockout(long duration) {
mTimedLockout = duration;
}
/**
@@ -162,10 +188,6 @@ class MultiBiometricLockoutState {
mTimedLockout = Math.max(mTimedLockout, duration);
}
void setTimedLockout(long duration) {
mTimedLockout = duration;
}
String toString(long currentTime) {
final String duration =
mTimedLockout - currentTime > 0 ? (mTimedLockout - currentTime) + "ms" : "none";

View File

@@ -85,7 +85,7 @@ public class PerformanceTracker {
}
}
void incrementAcquireForUser(int userId, boolean isCrypto) {
public void incrementAcquireForUser(int userId, boolean isCrypto) {
createUserEntryIfNecessary(userId);
if (isCrypto) {
@@ -95,13 +95,13 @@ public class PerformanceTracker {
}
}
void incrementTimedLockoutForUser(int userId) {
public void incrementTimedLockoutForUser(int userId) {
createUserEntryIfNecessary(userId);
mAllUsersInfo.get(userId).mTimedLockout++;
}
void incrementPermanentLockoutForUser(int userId) {
public void incrementPermanentLockoutForUser(int userId) {
createUserEntryIfNecessary(userId);
mAllUsersInfo.get(userId).mPermanentLockout++;

View File

@@ -47,7 +47,7 @@ import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutConsumer;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.face.UsageStats;
import java.util.ArrayList;
@@ -63,8 +63,6 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
@NonNull
private final UsageStats mUsageStats;
@NonNull
private final LockoutCache mLockoutCache;
@NonNull
private final AuthSessionCoordinator mAuthSessionCoordinator;
@Nullable
private final NotificationManager mNotificationManager;
@@ -72,7 +70,6 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
private final int[] mBiometricPromptIgnoreListVendor;
private final int[] mKeyguardIgnoreList;
private final int[] mKeyguardIgnoreListVendor;
private final int mBiometricStrength;
@Nullable
private ICancellationSignal mCancellationSignal;
@Nullable
@@ -88,12 +85,12 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
boolean isStrongBiometric, @NonNull UsageStats usageStats,
@NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication,
boolean isKeyguardBypassEnabled, @Authenticators.Types int biometricStrength) {
boolean isKeyguardBypassEnabled, @Authenticators.Types int sensorStrength) {
this(context, lazyDaemon, token, requestId, listener, targetUserId, operationId,
restricted, owner, cookie, requireConfirmation, sensorId, logger, biometricContext,
isStrongBiometric, usageStats, lockoutCache, allowBackgroundAuthentication,
isKeyguardBypassEnabled, context.getSystemService(SensorPrivacyManager.class),
biometricStrength);
isStrongBiometric, usageStats, lockoutCache /* lockoutCache */,
allowBackgroundAuthentication, isKeyguardBypassEnabled,
context.getSystemService(SensorPrivacyManager.class), sensorStrength);
}
@VisibleForTesting
@@ -109,13 +106,11 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
@Authenticators.Types int biometricStrength) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, logger, biometricContext,
isStrongBiometric, null /* taskStackListener */, lockoutCache,
allowBackgroundAuthentication,
false /* shouldVibrate */,
isKeyguardBypassEnabled);
isStrongBiometric, null /* taskStackListener */, null /* lockoutCache */,
allowBackgroundAuthentication, false /* shouldVibrate */,
isKeyguardBypassEnabled, biometricStrength);
setRequestId(requestId);
mUsageStats = usageStats;
mLockoutCache = lockoutCache;
mNotificationManager = context.getSystemService(NotificationManager.class);
mSensorPrivacyManager = sensorPrivacyManager;
mAuthSessionCoordinator = biometricContext.getAuthSessionCoordinator();
@@ -129,14 +124,12 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
R.array.config_face_acquire_keyguard_ignorelist);
mKeyguardIgnoreListVendor = resources.getIntArray(
R.array.config_face_acquire_vendor_keyguard_ignorelist);
mBiometricStrength = biometricStrength;
}
@Override
public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
mState = STATE_STARTED;
mAuthSessionCoordinator.authStartedFor(getTargetUserId(), getSensorId(), getRequestId());
}
@NonNull
@@ -221,9 +214,6 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
0 /* error */,
0 /* vendorError */,
getTargetUserId()));
mAuthSessionCoordinator
.authenticatedFor(getTargetUserId(), mBiometricStrength, getSensorId(),
getRequestId());
}
@Override
@@ -239,8 +229,6 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
if (error == BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL) {
BiometricNotificationUtils.showReEnrollmentNotification(getContext());
}
mAuthSessionCoordinator.authEndedFor(getTargetUserId(), mBiometricStrength, getSensorId(),
getRequestId());
super.onError(error, vendorCode);
}
@@ -263,6 +251,8 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
mLastAcquire = acquireInfo;
final boolean shouldSend = shouldSendAcquiredMessage(acquireInfo, vendorCode);
onAcquiredInternal(acquireInfo, vendorCode, shouldSend);
PerformanceTracker pt = PerformanceTracker.getInstanceForSensorId(getSensorId());
pt.incrementAcquireForUser(getTargetUserId(), isCryptoOperation());
}
/**
@@ -290,35 +280,39 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
@Override
public void onLockoutTimed(long durationMillis) {
mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED);
mAuthSessionCoordinator.lockOutTimed(getTargetUserId(), getSensorStrength(), getSensorId(),
durationMillis, getRequestId());
// Lockout metrics are logged as an error code.
final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT;
getLogger().logOnError(getContext(), getOperationContext(),
error, 0 /* vendorCode */, getTargetUserId());
PerformanceTracker.getInstanceForSensorId(getSensorId())
.incrementTimedLockoutForUser(getTargetUserId());
try {
getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
mAuthSessionCoordinator.lockOutTimed(getTargetUserId(), mBiometricStrength, getSensorId(),
durationMillis, getRequestId());
}
@Override
public void onLockoutPermanent() {
mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT);
mAuthSessionCoordinator.lockedOutFor(getTargetUserId(), getSensorStrength(), getSensorId(),
getRequestId());
// Lockout metrics are logged as an error code.
final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT;
getLogger().logOnError(getContext(), getOperationContext(),
error, 0 /* vendorCode */, getTargetUserId());
PerformanceTracker.getInstanceForSensorId(getSensorId())
.incrementPermanentLockoutForUser(getTargetUserId());
try {
getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
mAuthSessionCoordinator.lockedOutFor(getTargetUserId(), mBiometricStrength, getSensorId(),
getRequestId());
}
}

View File

@@ -50,10 +50,11 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
@@ -82,20 +83,34 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
private boolean mTestHalEnabled;
@NonNull private final Context mContext;
@NonNull private final BiometricStateCallback mBiometricStateCallback;
@NonNull private final String mHalInstanceName;
@NonNull @VisibleForTesting
@NonNull
@VisibleForTesting
final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
@NonNull private final Handler mHandler;
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
@NonNull private final UsageStats mUsageStats;
@NonNull private final ActivityTaskManager mActivityTaskManager;
@NonNull private final BiometricTaskStackListener mTaskStackListener;
@NonNull
private final Context mContext;
@NonNull
private final BiometricStateCallback mBiometricStateCallback;
@NonNull
private final String mHalInstanceName;
@NonNull
private final Handler mHandler;
@NonNull
private final LockoutResetDispatcher mLockoutResetDispatcher;
@NonNull
private final UsageStats mUsageStats;
@NonNull
private final ActivityTaskManager mActivityTaskManager;
@NonNull
private final BiometricTaskStackListener mTaskStackListener;
// for requests that do not use biometric prompt
@NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
@NonNull private final BiometricContext mBiometricContext;
@Nullable private IFace mDaemon;
@NonNull
private final AtomicLong mRequestCounter = new AtomicLong(0);
@NonNull
private final BiometricContext mBiometricContext;
@NonNull
private final AuthSessionCoordinator mAuthSessionCoordinator;
@Nullable
private IFace mDaemon;
private final class BiometricTaskStackListener extends TaskStackListener {
@Override
@@ -141,6 +156,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
mActivityTaskManager = ActivityTaskManager.getInstance();
mTaskStackListener = new BiometricTaskStackListener();
mBiometricContext = biometricContext;
mAuthSessionCoordinator = mBiometricContext.getAuthSessionCoordinator();
for (SensorProps prop : props) {
final int sensorId = prop.commonProps.sensorId;
@@ -312,7 +328,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public int getLockoutModeForUser(int sensorId, int userId) {
return mSensors.get(sensorId).getLockoutCache().getLockoutModeForUser(userId);
return mBiometricContext.getAuthSessionCoordinator().getLockoutStateFor(userId,
Utils.getCurrentStrength(sensorId));
}
@Override
@@ -423,7 +440,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final int biometricStrength = Utils.getCurrentStrength(sensorId);
final FaceAuthenticationClient client = new FaceAuthenticationClient(
mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback,
userId, operationId, restricted, opPackageName, cookie,
@@ -431,8 +447,24 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, isStrongBiometric,
mUsageStats, mSensors.get(sensorId).getLockoutCache(),
allowBackgroundAuthentication, isKeyguardBypassEnabled, biometricStrength);
scheduleForSensor(sensorId, client, mBiometricStateCallback);
allowBackgroundAuthentication, isKeyguardBypassEnabled,
Utils.getCurrentStrength(sensorId)
);
scheduleForSensor(sensorId, client, new ClientMonitorCallback() {
@Override
public void onClientStarted(
BaseClientMonitor clientMonitor) {
mAuthSessionCoordinator.authStartedFor(userId, sensorId, requestId);
}
@Override
public void onClientFinished(
BaseClientMonitor clientMonitor,
boolean success) {
mAuthSessionCoordinator.authEndedFor(userId, Utils.getCurrentStrength(sensorId),
sensorId, requestId, success);
}
});
});
}

View File

@@ -89,9 +89,9 @@ public class FaceResetLockoutClient extends HalClientMonitor<AidlSession> implem
void onLockoutCleared() {
resetLocalLockoutStateToNone(getSensorId(), getTargetUserId(), mLockoutCache,
mLockoutResetDispatcher);
mCallback.onClientFinished(this, true /* success */);
getBiometricContext().getAuthSessionCoordinator()
.resetLockoutFor(getTargetUserId(), mBiometricStrength, getRequestId());
mCallback.onClientFinished(this, true /* success */);
}
public boolean interruptsPrecedingClients() {

View File

@@ -677,8 +677,9 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
opPackageName, cookie, false /* requireConfirmation */, mSensorId,
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, isStrongBiometric, mLockoutTracker,
mUsageStats, allowBackgroundAuthentication, isKeyguardBypassEnabled);
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
mUsageStats, allowBackgroundAuthentication, isKeyguardBypassEnabled,
Utils.getCurrentStrength(mSensorId));
mScheduler.scheduleClientMonitor(client);
});
}

View File

@@ -23,6 +23,7 @@ import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.face.FaceManager;
import android.os.IBinder;
@@ -39,6 +40,7 @@ import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.face.UsageStats;
import java.util.ArrayList;
@@ -70,12 +72,12 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
boolean isStrongBiometric, @NonNull LockoutTracker lockoutTracker,
@NonNull UsageStats usageStats, boolean allowBackgroundAuthentication,
boolean isKeyguardBypassEnabled) {
boolean isKeyguardBypassEnabled, @Authenticators.Types int sensorStrength) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, logger, biometricContext,
isStrongBiometric, null /* taskStackListener */,
lockoutTracker, allowBackgroundAuthentication, false /* shouldVibrate */,
isKeyguardBypassEnabled);
isKeyguardBypassEnabled, sensorStrength);
setRequestId(requestId);
mUsageStats = usageStats;
mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
@@ -153,6 +155,21 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
mCallback.onClientFinished(this, true /* success */);
}
@Override
public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
@LockoutTracker.LockoutMode final int lockoutMode =
getLockoutTracker().getLockoutModeForUser(userId);
final PerformanceTracker performanceTracker =
PerformanceTracker.getInstanceForSensorId(getSensorId());
if (lockoutMode == LockoutTracker.LOCKOUT_PERMANENT) {
performanceTracker.incrementPermanentLockoutForUser(userId);
} else if (lockoutMode == LockoutTracker.LOCKOUT_TIMED) {
performanceTracker.incrementTimedLockoutForUser(userId);
}
return lockoutMode;
}
@Override
public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) {
@@ -204,6 +221,12 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
if (acquireInfo == FaceManager.FACE_ACQUIRED_RECALIBRATE) {
BiometricNotificationUtils.showReEnrollmentNotification(getContext());
}
@LockoutTracker.LockoutMode final int lockoutMode =
getLockoutTracker().getLockoutModeForUser(getTargetUserId());
if (lockoutMode == LockoutTracker.LOCKOUT_NONE) {
PerformanceTracker pt = PerformanceTracker.getInstanceForSensorId(getSensorId());
pt.incrementAcquireForUser(getTargetUserId(), isCryptoOperation());
}
final boolean shouldSend = shouldSend(acquireInfo, vendorCode);
onAcquiredInternal(acquireInfo, vendorCode, shouldSend);

View File

@@ -56,7 +56,7 @@ import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutConsumer;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.SensorOverlays;
import com.android.server.biometrics.sensors.fingerprint.PowerPressHandler;
import com.android.server.biometrics.sensors.fingerprint.Udfps;
@@ -75,8 +75,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
private static final int MESSAGE_AUTH_SUCCESS = 2;
private static final int MESSAGE_FINGER_UP = 3;
@NonNull
private final LockoutCache mLockoutCache;
@NonNull
private final SensorOverlays mSensorOverlays;
@NonNull
private final FingerprintSensorPropertiesInternal mSensorProps;
@@ -85,7 +83,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
private final Handler mHandler;
private final int mSkipWaitForPowerAcquireMessage;
private final int mSkipWaitForPowerVendorAcquireMessage;
private final int mBiometricStrength;
private final long mFingerUpIgnoresPower = 500;
private final AuthSessionCoordinator mAuthSessionCoordinator;
@Nullable
@@ -140,12 +137,12 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
biometricContext,
isStrongBiometric,
taskStackListener,
lockoutCache,
null /* lockoutCache */,
allowBackgroundAuthentication,
false /* shouldVibrate */,
false /* isKeyguardBypassEnabled */);
false /* isKeyguardBypassEnabled */,
biometricStrength);
setRequestId(requestId);
mLockoutCache = lockoutCache;
mSensorOverlays = new SensorOverlays(udfpsOverlayController,
sidefpsController, udfpsOverlay);
mSensorProps = sensorProps;
@@ -166,7 +163,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
mSkipWaitForPowerVendorAcquireMessage =
context.getResources().getInteger(
R.integer.config_sidefpsSkipWaitForPowerVendorAcquireMessage);
mBiometricStrength = biometricStrength;
mAuthSessionCoordinator = biometricContext.getAuthSessionCoordinator();
mSideFpsLastAcquireStartTime = -1;
mClock = clock;
@@ -196,8 +192,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
} else {
mState = STATE_STARTED;
}
mAuthSessionCoordinator.authStartedFor(getTargetUserId(), getSensorId(),
getRequestId());
}
@NonNull
@@ -211,8 +205,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
protected void handleLifecycleAfterAuth(boolean authenticated) {
if (authenticated) {
mCallback.onClientFinished(this, true /* success */);
mAuthSessionCoordinator.authenticatedFor(
getTargetUserId(), mBiometricStrength, getSensorId(), getRequestId());
}
}
@@ -304,6 +296,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
});
}
}
PerformanceTracker pt = PerformanceTracker.getInstanceForSensorId(getSensorId());
pt.incrementAcquireForUser(getTargetUserId(), isCryptoOperation());
}
@@ -316,8 +310,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
}
mSensorOverlays.hide(getSensorId());
mAuthSessionCoordinator.authEndedFor(getTargetUserId(), mBiometricStrength, getSensorId(),
getRequestId());
}
@Override
@@ -455,7 +447,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
@Override
public void onLockoutTimed(long durationMillis) {
mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED);
mAuthSessionCoordinator.lockOutTimed(getTargetUserId(), getSensorStrength(), getSensorId(),
durationMillis, getRequestId());
// Lockout metrics are logged as an error code.
final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
getLogger()
@@ -466,6 +459,9 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
0 /* vendorCode */,
getTargetUserId());
PerformanceTracker.getInstanceForSensorId(getSensorId())
.incrementTimedLockoutForUser(getTargetUserId());
try {
getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
} catch (RemoteException e) {
@@ -474,13 +470,12 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
mSensorOverlays.hide(getSensorId());
mCallback.onClientFinished(this, false /* success */);
mAuthSessionCoordinator.lockOutTimed(getTargetUserId(), mBiometricStrength, getSensorId(),
durationMillis, getRequestId());
}
@Override
public void onLockoutPermanent() {
mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT);
mAuthSessionCoordinator.lockedOutFor(getTargetUserId(), getSensorStrength(), getSensorId(),
getRequestId());
// Lockout metrics are logged as an error code.
final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
getLogger()
@@ -491,6 +486,9 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
0 /* vendorCode */,
getTargetUserId());
PerformanceTracker.getInstanceForSensorId(getSensorId())
.incrementPermanentLockoutForUser(getTargetUserId());
try {
getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
} catch (RemoteException e) {
@@ -499,8 +497,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
mSensorOverlays.hide(getSensorId());
mCallback.onClientFinished(this, false /* success */);
mAuthSessionCoordinator.lockedOutFor(getTargetUserId(), mBiometricStrength, getSensorId(),
getRequestId());
}
@Override
@@ -515,8 +511,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED,
0, true);
mSensorOverlays.hide(getSensorId());
mAuthSessionCoordinator.authEndedFor(getTargetUserId(),
mBiometricStrength, getSensorId(), getRequestId());
});
}
}

View File

@@ -58,6 +58,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
@@ -94,15 +95,23 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
private boolean mTestHalEnabled;
@NonNull private final Context mContext;
@NonNull private final BiometricStateCallback mBiometricStateCallback;
@NonNull private final String mHalInstanceName;
@NonNull @VisibleForTesting
@NonNull
@VisibleForTesting
final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
@NonNull private final Handler mHandler;
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
@NonNull private final ActivityTaskManager mActivityTaskManager;
@NonNull private final BiometricTaskStackListener mTaskStackListener;
@NonNull
private final Context mContext;
@NonNull
private final BiometricStateCallback mBiometricStateCallback;
@NonNull
private final String mHalInstanceName;
@NonNull
private final Handler mHandler;
@NonNull
private final LockoutResetDispatcher mLockoutResetDispatcher;
@NonNull
private final ActivityTaskManager mActivityTaskManager;
@NonNull
private final BiometricTaskStackListener mTaskStackListener;
// for requests that do not use biometric prompt
@NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
@NonNull private final BiometricContext mBiometricContext;
@@ -110,6 +119,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
@Nullable private ISidefpsController mSidefpsController;
@Nullable private IUdfpsOverlay mUdfpsOverlay;
private AuthSessionCoordinator mAuthSessionCoordinator;
private final class BiometricTaskStackListener extends TaskStackListener {
@Override
@@ -154,6 +164,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mActivityTaskManager = ActivityTaskManager.getInstance();
mTaskStackListener = new BiometricTaskStackListener();
mBiometricContext = biometricContext;
mAuthSessionCoordinator = mBiometricContext.getAuthSessionCoordinator();
final List<SensorLocationInternal> workaroundLocations = getWorkaroundSensorProps(context);
@@ -179,11 +190,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
true /* resetLockoutRequiresHardwareAuthToken */,
!workaroundLocations.isEmpty() ? workaroundLocations :
Arrays.stream(prop.sensorLocations).map(location ->
new SensorLocationInternal(
location.display,
location.sensorLocationX,
location.sensorLocationY,
location.sensorRadius))
new SensorLocationInternal(
location.display,
location.sensorLocationX,
location.sensorLocationY,
location.sensorRadius))
.collect(Collectors.toList()));
final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
internalProp, lockoutResetDispatcher, gestureAvailabilityDispatcher,
@@ -347,7 +358,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId, opPackageName,
sensorId, createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN),
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext);
scheduleForSensor(sensorId, client);
});
@@ -445,8 +456,30 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay,
allowBackgroundAuthentication,
mSensors.get(sensorId).getSensorProperties(), mHandler,
Utils.getCurrentStrength(sensorId), SystemClock.elapsedRealtimeClock());
scheduleForSensor(sensorId, client, mBiometricStateCallback);
Utils.getCurrentStrength(sensorId),
SystemClock.elapsedRealtimeClock());
scheduleForSensor(sensorId, client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
mBiometricStateCallback.onClientStarted(clientMonitor);
mAuthSessionCoordinator.authStartedFor(userId, sensorId, requestId);
}
@Override
public void onBiometricAction(int action) {
mBiometricStateCallback.onBiometricAction(action);
}
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
mBiometricStateCallback.onClientFinished(clientMonitor, success);
mAuthSessionCoordinator.authEndedFor(userId, Utils.getCurrentStrength(sensorId),
sensorId, requestId, success);
}
});
});
}
@@ -584,7 +617,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override
public int getLockoutModeForUser(int sensorId, int userId) {
return mSensors.get(sensorId).getLockoutCache().getLockoutModeForUser(userId);
return mBiometricContext.getAuthSessionCoordinator().getLockoutStateFor(userId,
Utils.getCurrentStrength(sensorId));
}
@Override

View File

@@ -93,9 +93,9 @@ class FingerprintResetLockoutClient extends HalClientMonitor<AidlSession> implem
void onLockoutCleared() {
resetLocalLockoutStateToNone(getSensorId(), getTargetUserId(), mLockoutCache,
mLockoutResetDispatcher);
mCallback.onClientFinished(this, true /* success */);
getBiometricContext().getAuthSessionCoordinator()
.resetLockoutFor(getTargetUserId(), mBiometricStrength, getRequestId());
mCallback.onClientFinished(this, true /* success */);
}
/**

View File

@@ -667,7 +667,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mBiometricContext, isStrongBiometric,
mTaskStackListener, mLockoutTracker,
mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay,
allowBackgroundAuthentication, mSensorProperties);
allowBackgroundAuthentication, mSensorProperties,
Utils.getCurrentStrength(mSensorId));
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
});
}

View File

@@ -23,6 +23,7 @@ import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.ISidefpsController;
@@ -42,6 +43,7 @@ import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.SensorOverlays;
import com.android.server.biometrics.sensors.fingerprint.Udfps;
import com.android.server.biometrics.sensors.fingerprint.UdfpsHelper;
@@ -79,12 +81,13 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
@Nullable ISidefpsController sidefpsController,
@Nullable IUdfpsOverlay udfpsOverlay,
boolean allowBackgroundAuthentication,
@NonNull FingerprintSensorPropertiesInternal sensorProps) {
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@Authenticators.Types int sensorStrength) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, logger, biometricContext,
isStrongBiometric, taskStackListener, lockoutTracker,
allowBackgroundAuthentication, false /* shouldVibrate */,
false /* isKeyguardBypassEnabled */);
isStrongBiometric, taskStackListener, lockoutTracker, allowBackgroundAuthentication,
false /* shouldVibrate */, false /* isKeyguardBypassEnabled */,
sensorStrength);
setRequestId(requestId);
mLockoutFrameworkImpl = lockoutTracker;
mSensorOverlays = new SensorOverlays(udfpsOverlayController,
@@ -166,6 +169,18 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
}
}
@Override
public void onAcquired(int acquiredInfo, int vendorCode) {
super.onAcquired(acquiredInfo, vendorCode);
@LockoutTracker.LockoutMode final int lockoutMode =
getLockoutTracker().getLockoutModeForUser(getTargetUserId());
if (lockoutMode == LockoutTracker.LOCKOUT_NONE) {
PerformanceTracker pt = PerformanceTracker.getInstanceForSensorId(getSensorId());
pt.incrementAcquireForUser(getTargetUserId(), isCryptoOperation());
}
}
@Override
public boolean wasUserDetected() {
// TODO: Update if it needs to be used for fingerprint, i.e. success/reject, error_timeout
@@ -175,7 +190,17 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
@Override
public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
mLockoutFrameworkImpl.addFailedAttemptForUser(userId);
return super.handleFailedAttempt(userId);
@LockoutTracker.LockoutMode final int lockoutMode =
getLockoutTracker().getLockoutModeForUser(userId);
final PerformanceTracker performanceTracker =
PerformanceTracker.getInstanceForSensorId(getSensorId());
if (lockoutMode == LockoutTracker.LOCKOUT_PERMANENT) {
performanceTracker.incrementPermanentLockoutForUser(userId);
} else if (lockoutMode == LockoutTracker.LOCKOUT_TIMED) {
performanceTracker.incrementTimedLockoutForUser(userId);
}
return lockoutMode;
}
@Override

View File

@@ -19,6 +19,7 @@ package com.android.server.locksettings;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricManager;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager;
@@ -48,11 +49,13 @@ public class BiometricDeferredQueue {
@NonNull private final Handler mHandler;
@Nullable private FingerprintManager mFingerprintManager;
@Nullable private FaceManager mFaceManager;
@Nullable private BiometricManager mBiometricManager;
// Entries added by LockSettingsService once a user's synthetic password is known. At this point
// things are still keyed by userId.
@NonNull private final ArrayList<UserAuthInfo> mPendingResetLockoutsForFingerprint;
@NonNull private final ArrayList<UserAuthInfo> mPendingResetLockoutsForFace;
@NonNull private final ArrayList<UserAuthInfo> mPendingResetLockouts;
/**
* Authentication info for a successful user unlock via Synthetic Password. This can be used to
@@ -125,7 +128,6 @@ public class BiometricDeferredQueue {
}
@Nullable private FaceResetLockoutTask mFaceResetLockoutTask;
private final FaceResetLockoutTask.FinishCallback mFaceFinishCallback = () -> {
mFaceResetLockoutTask = null;
};
@@ -135,12 +137,14 @@ public class BiometricDeferredQueue {
mHandler = handler;
mPendingResetLockoutsForFingerprint = new ArrayList<>();
mPendingResetLockoutsForFace = new ArrayList<>();
mPendingResetLockouts = new ArrayList<>();
}
public void systemReady(@Nullable FingerprintManager fingerprintManager,
@Nullable FaceManager faceManager) {
@Nullable FaceManager faceManager, @Nullable BiometricManager biometricManager) {
mFingerprintManager = fingerprintManager;
mFaceManager = faceManager;
mBiometricManager = biometricManager;
}
/**
@@ -151,7 +155,7 @@ public class BiometricDeferredQueue {
* Note that this should only ever be invoked for successful authentications, otherwise it will
* consume a Gatekeeper authentication attempt and potentially wipe the user/device.
*
* @param userId The user that the operation will apply for.
* @param userId The user that the operation will apply for.
* @param gatekeeperPassword The Gatekeeper Password
*/
void addPendingLockoutResetForUser(int userId, @NonNull byte[] gatekeeperPassword) {
@@ -167,6 +171,12 @@ public class BiometricDeferredQueue {
mPendingResetLockoutsForFingerprint.add(new UserAuthInfo(userId,
gatekeeperPassword));
}
if (mBiometricManager != null) {
Slog.d(TAG, "Fingerprint addPendingLockoutResetForUser: " + userId);
mPendingResetLockouts.add(new UserAuthInfo(userId,
gatekeeperPassword));
}
});
}
@@ -184,6 +194,14 @@ public class BiometricDeferredQueue {
new ArrayList<>(mPendingResetLockoutsForFingerprint));
mPendingResetLockoutsForFingerprint.clear();
}
if (!mPendingResetLockouts.isEmpty()) {
Slog.d(TAG, "Processing pending resetLockouts(Generic)");
processPendingLockoutsGeneric(
new ArrayList<>(mPendingResetLockouts));
mPendingResetLockouts.clear();
}
});
}
@@ -257,6 +275,17 @@ public class BiometricDeferredQueue {
}
}
private void processPendingLockoutsGeneric(List<UserAuthInfo> pendingResetLockouts) {
for (UserAuthInfo user : pendingResetLockouts) {
Slog.d(TAG, "Resetting biometric lockout for user: " + user.userId);
final byte[] hat = requestHatFromGatekeeperPassword(mSpManager, user,
0 /* challenge */);
if (hat != null) {
mBiometricManager.resetLockout(user.userId, hat);
}
}
}
@Nullable
private static byte[] requestHatFromGatekeeperPassword(
@NonNull SyntheticPasswordManager spManager,

View File

@@ -70,6 +70,7 @@ import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.database.sqlite.SQLiteDatabase;
import android.hardware.authsecret.V1_0.IAuthSecret;
import android.hardware.biometrics.BiometricManager;
import android.hardware.face.Face;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.Fingerprint;
@@ -552,6 +553,10 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
public BiometricManager getBiometricManager() {
return (BiometricManager) mContext.getSystemService(Context.BIOMETRIC_SERVICE);
}
public int settingsGlobalGetInt(ContentResolver contentResolver, String keyName,
int defaultValue) {
return Settings.Global.getInt(contentResolver, keyName, defaultValue);
@@ -837,7 +842,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// TODO: maybe skip this for split system user mode.
mStorage.prefetchUser(UserHandle.USER_SYSTEM);
mBiometricDeferredQueue.systemReady(mInjector.getFingerprintManager(),
mInjector.getFaceManager());
mInjector.getFaceManager(), mInjector.getBiometricManager());
}
private void loadEscrowData() {

View File

@@ -64,6 +64,7 @@ import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Binder;
import android.os.IBinder;
@@ -75,7 +76,10 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.internal.statusbar.ISessionListener;
import com.android.internal.statusbar.IStatusBarService;
import com.android.server.biometrics.log.BiometricContextProvider;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.LockoutTracker;
import org.junit.Before;
@@ -129,6 +133,16 @@ public class BiometricServiceTest {
ITrustManager mTrustManager;
@Mock
DevicePolicyManager mDevicePolicyManager;
@Mock
private IStatusBarService mStatusBarService;
@Mock
private ISessionListener mSessionListener;
@Mock
private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
@Mock
private AuthSessionCoordinator mAuthSessionCoordinator;
BiometricContextProvider mBiometricContextProvider;
@Before
public void setUp() {
@@ -160,6 +174,11 @@ public class BiometricServiceTest {
when(mResources.getString(R.string.biometric_error_user_canceled))
.thenReturn(ERROR_USER_CANCELED);
when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
mBiometricContextProvider = new BiometricContextProvider(mAmbientDisplayConfiguration,
mStatusBarService, null /* handler */, mAuthSessionCoordinator);
when(mInjector.getBiometricContext(any())).thenReturn(mBiometricContextProvider);
final String[] config = {
"0:2:15", // ID0:Fingerprint:Strong
"1:8:15", // ID1:Face:Strong

View File

@@ -61,11 +61,11 @@ public class AuthResultCoordinatorTest {
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
AUTHENTICATOR_DEFAULT);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
AUTHENTICATOR_UNLOCKED);
AUTHENTICATOR_DEFAULT);
}
@Test
public void testLockout() {
public void testConvenientLockout() {
mAuthResultCoordinator.lockedOutFor(
BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE);
@@ -80,7 +80,7 @@ public class AuthResultCoordinatorTest {
}
@Test
public void testConvenientLockout() {
public void testConvenientUnlock() {
mAuthResultCoordinator.authenticatedFor(
BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE);
@@ -91,11 +91,26 @@ public class AuthResultCoordinatorTest {
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
AUTHENTICATOR_DEFAULT);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
AUTHENTICATOR_UNLOCKED);
AUTHENTICATOR_DEFAULT);
}
@Test
public void testWeakLockout() {
mAuthResultCoordinator.lockedOutFor(
BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE);
Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
AUTHENTICATOR_DEFAULT);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
AUTHENTICATOR_DEFAULT);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
AUTHENTICATOR_LOCKED);
}
@Test
public void testWeakUnlock() {
mAuthResultCoordinator.authenticatedFor(
BiometricManager.Authenticators.BIOMETRIC_WEAK);
@@ -104,13 +119,29 @@ public class AuthResultCoordinatorTest {
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
AUTHENTICATOR_DEFAULT);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
AUTHENTICATOR_UNLOCKED);
AUTHENTICATOR_DEFAULT);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
AUTHENTICATOR_UNLOCKED);
AUTHENTICATOR_DEFAULT);
}
@Test
public void testStrongLockout() {
mAuthResultCoordinator.lockedOutFor(
BiometricManager.Authenticators.BIOMETRIC_STRONG);
Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
AUTHENTICATOR_LOCKED);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
AUTHENTICATOR_LOCKED);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
AUTHENTICATOR_LOCKED);
}
@Test
public void testStrongUnlock() {
mAuthResultCoordinator.authenticatedFor(
BiometricManager.Authenticators.BIOMETRIC_STRONG);
@@ -136,9 +167,9 @@ public class AuthResultCoordinatorTest {
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
AUTHENTICATOR_DEFAULT);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
AUTHENTICATOR_UNLOCKED | AUTHENTICATOR_LOCKED);
AUTHENTICATOR_LOCKED);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
AUTHENTICATOR_UNLOCKED | AUTHENTICATOR_LOCKED);
AUTHENTICATOR_LOCKED);
}

View File

@@ -53,22 +53,28 @@ public class AuthSessionCoordinatorTest {
}
@Test
public void testUserUnlocked() {
public void testUserUnlockedWithWeak() {
mCoordinator.authStartedFor(PRIMARY_USER, 1 /* sensorId */, 0 /* requestId */);
mCoordinator.lockedOutFor(PRIMARY_USER, BIOMETRIC_STRONG, 1 /* sensorId */,
0 /* requestId */);
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
mCoordinator.authStartedFor(PRIMARY_USER, 1 /* sensorId */, 0 /* requestId */);
mCoordinator.authenticatedFor(PRIMARY_USER, BIOMETRIC_WEAK, 1 /* sensorId */,
0 /* requestId */);
mCoordinator.authEndedFor(PRIMARY_USER, BIOMETRIC_WEAK, 1 /* sensorId */,
0 /* requestId */, true /* wasSuccessful */);
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
}
@Test
@@ -77,38 +83,79 @@ public class AuthSessionCoordinatorTest {
mCoordinator.authStartedFor(PRIMARY_USER, 2 /* sensorId */, 0 /* requestId */);
mCoordinator.lockedOutFor(PRIMARY_USER, BIOMETRIC_STRONG, 1 /* sensorId */,
0 /* requestId */);
mCoordinator.authenticatedFor(PRIMARY_USER, BIOMETRIC_WEAK, 2 /* sensorId */,
0 /* requestId */);
mCoordinator.authEndedFor(PRIMARY_USER, BIOMETRIC_WEAK, 2 /* sensorId */,
0 /* requestId */, false /* wasSuccessful */);
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
mCoordinator.authStartedFor(PRIMARY_USER, 1 /* sensorId */, 0 /* requestId */);
mCoordinator.authenticatedFor(PRIMARY_USER, BIOMETRIC_WEAK, 1 /* sensorId */,
0 /* requestId */);
mCoordinator.authEndedFor(PRIMARY_USER, BIOMETRIC_WEAK, 1 /* sensorId */,
0 /* requestId */, false /* wasSuccessful */);
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
}
@Test
public void testWeakAndConvenientCannotResetLockout() {
mCoordinator.authStartedFor(PRIMARY_USER, 1 /* sensorId */, 0 /* requestId */);
mCoordinator.lockedOutFor(PRIMARY_USER, BIOMETRIC_STRONG, 1 /* sensorId */,
0 /* requestId */);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
mCoordinator.resetLockoutFor(PRIMARY_USER, BIOMETRIC_WEAK, 0 /* requestId */);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
mCoordinator.resetLockoutFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE, 0 /* requestId */);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
}
@Test
public void testUserCanAuthDuringLockoutOfSameSession() {
mCoordinator.resetLockoutFor(PRIMARY_USER, BIOMETRIC_STRONG, 0 /* requestId */);
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
mCoordinator.authStartedFor(PRIMARY_USER, 1 /* sensorId */, 0 /* requestId */);
mCoordinator.authStartedFor(PRIMARY_USER, 2 /* sensorId */, 0 /* requestId */);
mCoordinator.lockedOutFor(PRIMARY_USER, BIOMETRIC_WEAK, 2 /* sensorId */,
0 /* requestId */);
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
}
@Test
@@ -123,25 +170,39 @@ public class AuthSessionCoordinatorTest {
mCoordinator.resetLockoutFor(PRIMARY_USER, BIOMETRIC_STRONG, 0 /* requestId */);
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mCoordinator.getCanAuthFor(SECONDARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
assertThat(mCoordinator.getCanAuthFor(SECONDARY_USER, BIOMETRIC_WEAK)).isFalse();
assertThat(mCoordinator.getCanAuthFor(SECONDARY_USER, BIOMETRIC_STRONG)).isFalse();
assertThat(
mCoordinator.getLockoutStateFor(SECONDARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(SECONDARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(SECONDARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
mCoordinator.authStartedFor(PRIMARY_USER, 1 /* sensorId */, 0 /* requestId */);
mCoordinator.authStartedFor(PRIMARY_USER, 2 /* sensorId */, 0 /* requestId */);
mCoordinator.lockedOutFor(PRIMARY_USER, BIOMETRIC_WEAK, 2 /* sensorId */,
0 /* requestId */);
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mCoordinator.getCanAuthFor(SECONDARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
assertThat(mCoordinator.getCanAuthFor(SECONDARY_USER, BIOMETRIC_WEAK)).isFalse();
assertThat(mCoordinator.getCanAuthFor(SECONDARY_USER, BIOMETRIC_STRONG)).isFalse();
assertThat(
mCoordinator.getLockoutStateFor(SECONDARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(SECONDARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mCoordinator.getLockoutStateFor(SECONDARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
}
}

View File

@@ -17,6 +17,7 @@
package com.android.server.biometrics.sensors;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_SUCCESS;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -78,17 +79,24 @@ public class BiometricSchedulerTest {
private static final int TEST_SENSOR_ID = 1;
private static final int LOG_NUM_RECENT_OPERATIONS = 2;
@Rule
public final TestableContext mContext =
new TestableContext(InstrumentationRegistry.getContext(), null);
public final TestableContext mContext = new TestableContext(
InstrumentationRegistry.getContext(), null);
private BiometricScheduler mScheduler;
private IBinder mToken;
@Mock
private IBiometricService mBiometricService;
@Mock
private BiometricContext mBiometricContext;
@Mock
private AuthSessionCoordinator mAuthSessionCoordinator;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mToken = new Binder();
when(mAuthSessionCoordinator.getLockoutStateFor(anyInt(), anyInt())).thenReturn(
BIOMETRIC_SUCCESS);
when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator);
mScheduler = new BiometricScheduler(TAG, new Handler(TestableLooper.get(this).getLooper()),
BiometricScheduler.SENSOR_TYPE_UNKNOWN, null /* gestureAvailabilityTracker */,
mBiometricService, LOG_NUM_RECENT_OPERATIONS);
@@ -98,10 +106,10 @@ public class BiometricSchedulerTest {
public void testClientDuplicateFinish_ignoredBySchedulerAndDoesNotCrash() {
final Supplier<Object> nonNullDaemon = () -> mock(Object.class);
final HalClientMonitor<Object> client1 =
new TestHalClientMonitor(mContext, mToken, nonNullDaemon);
final HalClientMonitor<Object> client2 =
new TestHalClientMonitor(mContext, mToken, nonNullDaemon);
final HalClientMonitor<Object> client1 = new TestHalClientMonitor(mContext, mToken,
nonNullDaemon);
final HalClientMonitor<Object> client2 = new TestHalClientMonitor(mContext, mToken,
nonNullDaemon);
mScheduler.scheduleClientMonitor(client1);
mScheduler.scheduleClientMonitor(client2);
@@ -112,10 +120,9 @@ public class BiometricSchedulerTest {
@Test
public void testRemovesPendingOperations_whenNullHal_andNotBiometricPrompt() {
// Even if second client has a non-null daemon, it needs to be canceled.
final TestHalClientMonitor client1 = new TestHalClientMonitor(
mContext, mToken, () -> null);
final TestHalClientMonitor client2 = new TestHalClientMonitor(
mContext, mToken, () -> mock(Object.class));
final TestHalClientMonitor client1 = new TestHalClientMonitor(mContext, mToken, () -> null);
final TestHalClientMonitor client2 = new TestHalClientMonitor(mContext, mToken,
() -> mock(Object.class));
final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class);
final ClientMonitorCallback callback2 = mock(ClientMonitorCallback.class);
@@ -150,10 +157,10 @@ public class BiometricSchedulerTest {
final ClientMonitorCallbackConverter listener1 = mock(ClientMonitorCallbackConverter.class);
final TestAuthenticationClient client1 =
new TestAuthenticationClient(mContext, () -> null, mToken, listener1);
final TestHalClientMonitor client2 =
new TestHalClientMonitor(mContext, mToken, () -> daemon2);
final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext, () -> null,
mToken, listener1, mBiometricContext);
final TestHalClientMonitor client2 = new TestHalClientMonitor(mContext, mToken,
() -> daemon2);
final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class);
final ClientMonitorCallback callback2 = mock(ClientMonitorCallback.class);
@@ -188,15 +195,15 @@ public class BiometricSchedulerTest {
@Test
public void testCancelNotInvoked_whenOperationWaitingForCookie() {
final Supplier<Object> lazyDaemon1 = () -> mock(Object.class);
final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext,
lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class));
final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext, lazyDaemon1,
mToken, mock(ClientMonitorCallbackConverter.class), mBiometricContext);
final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class);
// Schedule a BiometricPrompt authentication request
mScheduler.scheduleClientMonitor(client1, callback1);
assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart(
mock(ClientMonitorCallback.class)));
assertNotEquals(0,
mScheduler.mCurrentOperation.isReadyToStart(mock(ClientMonitorCallback.class)));
assertEquals(client1, mScheduler.mCurrentOperation.getClientMonitor());
assertEquals(0, mScheduler.mPendingOperations.size());
@@ -304,7 +311,7 @@ public class BiometricSchedulerTest {
final TestHalClientMonitor client1 = new TestHalClientMonitor(mContext, mToken, lazyDaemon);
final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class);
final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext, lazyDaemon,
mToken, callback);
mToken, callback, mBiometricContext);
// Add a non-cancellable client, then add the auth client
mScheduler.scheduleClientMonitor(client1);
@@ -367,7 +374,8 @@ public class BiometricSchedulerTest {
final Supplier<Object> lazyDaemon = () -> mock(Object.class);
final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class);
testCancelsWhenRequestId(requestId, cancelRequestId, started,
new TestAuthenticationClient(mContext, lazyDaemon, mToken, callback));
new TestAuthenticationClient(mContext, lazyDaemon, mToken, callback,
mBiometricContext));
}
@Test
@@ -448,11 +456,11 @@ public class BiometricSchedulerTest {
final long requestId2 = 20;
final Supplier<Object> lazyDaemon = () -> mock(Object.class);
final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class);
final TestAuthenticationClient client1 = new TestAuthenticationClient(
mContext, lazyDaemon, mToken, callback);
final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext, lazyDaemon,
mToken, callback, mBiometricContext);
client1.setRequestId(requestId1);
final TestAuthenticationClient client2 = new TestAuthenticationClient(
mContext, lazyDaemon, mToken, callback);
final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext, lazyDaemon,
mToken, callback, mBiometricContext);
client2.setRequestId(requestId2);
mScheduler.scheduleClientMonitor(client1);
@@ -506,8 +514,8 @@ public class BiometricSchedulerTest {
@Test
public void testClientDestroyed_afterFinish() {
final Supplier<Object> nonNullDaemon = () -> mock(Object.class);
final TestHalClientMonitor client =
new TestHalClientMonitor(mContext, mToken, nonNullDaemon);
final TestHalClientMonitor client = new TestHalClientMonitor(mContext, mToken,
nonNullDaemon);
mScheduler.scheduleClientMonitor(client);
client.mCallback.onClientFinished(client, true /* success */);
waitForIdle();
@@ -520,7 +528,8 @@ public class BiometricSchedulerTest {
final TestableLooper looper = TestableLooper.get(this);
final Supplier<Object> lazyDaemon1 = () -> mock(Object.class);
final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext,
lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class), 0 /* cookie */);
lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class), 0 /* cookie */,
mBiometricContext);
final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class);
mScheduler.scheduleClientMonitor(client1, callback1);
@@ -555,7 +564,8 @@ public class BiometricSchedulerTest {
final TestableLooper looper = TestableLooper.get(this);
final Supplier<Object> lazyDaemon1 = () -> mock(Object.class);
final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext,
lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class), 0 /* cookie */);
lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class), 0 /* cookie */,
mBiometricContext);
final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class);
mScheduler.scheduleClientMonitor(client1, callback1);
@@ -589,7 +599,8 @@ public class BiometricSchedulerTest {
//Run additional auth client
final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext,
lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class), 0 /* cookie */);
lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class), 0 /* cookie */,
mBiometricContext);
final ClientMonitorCallback callback2 = mock(ClientMonitorCallback.class);
mScheduler.scheduleClientMonitor(client2, callback2);
@@ -626,7 +637,8 @@ public class BiometricSchedulerTest {
final TestableLooper looper = TestableLooper.get(this);
final Supplier<Object> lazyDaemon1 = () -> mock(Object.class);
final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext,
lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class), 0 /* cookie */);
lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class), 0 /* cookie */,
mBiometricContext);
final ClientMonitorCallback callback1 = mock(ClientMonitorCallback.class);
mScheduler.scheduleClientMonitor(client1, callback1);
@@ -679,19 +691,22 @@ public class BiometricSchedulerTest {
TestAuthenticationClient(@NonNull Context context,
@NonNull Supplier<Object> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener) {
this(context, lazyDaemon, token, listener, 1 /* cookie */);
@NonNull ClientMonitorCallbackConverter listener,
BiometricContext biometricContext) {
this(context, lazyDaemon, token, listener, 1 /* cookie */, biometricContext);
}
TestAuthenticationClient(@NonNull Context context,
@NonNull Supplier<Object> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int cookie) {
@NonNull ClientMonitorCallbackConverter listener, int cookie,
@NonNull BiometricContext biometricContext) {
super(context, lazyDaemon, token, listener, 0 /* targetUserId */, 0 /* operationId */,
false /* restricted */, TAG, cookie, false /* requireConfirmation */,
TEST_SENSOR_ID, mock(BiometricLogger.class), mock(BiometricContext.class),
TEST_SENSOR_ID, mock(BiometricLogger.class), biometricContext,
true /* isStrongBiometric */, null /* taskStackListener */,
mock(LockoutTracker.class), false /* isKeyguard */,
true /* shouldVibrate */, false /* isKeyguardBypassEnabled */);
null /* lockoutTracker */, false /* isKeyguard */,
true /* shouldVibrate */, false /* isKeyguardBypassEnabled */,
0 /* sensorStrength */);
}
@Override
@@ -742,14 +757,12 @@ public class BiometricSchedulerTest {
boolean mStoppedHal = false;
int mNumCancels = 0;
TestEnrollClient(@NonNull Context context,
@NonNull Supplier<Object> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener) {
TestEnrollClient(@NonNull Context context, @NonNull Supplier<Object> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener) {
super(context, lazyDaemon, token, listener, 0 /* userId */, new byte[69],
"test" /* owner */, mock(BiometricUtils.class),
5 /* timeoutSec */, TEST_SENSOR_ID,
true /* shouldVibrate */,
mock(BiometricLogger.class), mock(BiometricContext.class));
"test" /* owner */, mock(BiometricUtils.class), 5 /* timeoutSec */,
TEST_SENSOR_ID, true /* shouldVibrate */, mock(BiometricLogger.class),
mock(BiometricContext.class));
}
@Override
@@ -787,9 +800,9 @@ public class BiometricSchedulerTest {
TestHalClientMonitor(@NonNull Context context, @NonNull IBinder token,
@NonNull Supplier<Object> lazyDaemon, int cookie, int protoEnum) {
super(context, lazyDaemon, token /* token */, null /* listener */, 0 /* userId */,
TAG, cookie, TEST_SENSOR_ID,
mock(BiometricLogger.class), mock(BiometricContext.class));
super(context, lazyDaemon, token /* token */, null /* listener */, 0 /* userId */, TAG,
cookie, TEST_SENSOR_ID, mock(BiometricLogger.class),
mock(BiometricContext.class));
mProtoEnum = protoEnum;
}

View File

@@ -50,16 +50,22 @@ public class MultiBiometricLockoutStateTest {
private static void unlockAllBiometrics(MultiBiometricLockoutState lockoutState, int userId) {
lockoutState.setAuthenticatorTo(userId, BIOMETRIC_STRONG, true /* canAuthenticate */);
assertThat(lockoutState.canUserAuthenticate(userId, BIOMETRIC_STRONG)).isTrue();
assertThat(lockoutState.canUserAuthenticate(userId, BIOMETRIC_WEAK)).isTrue();
assertThat(lockoutState.canUserAuthenticate(userId, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
}
private static void lockoutAllBiometrics(MultiBiometricLockoutState lockoutState, int userId) {
lockoutState.setAuthenticatorTo(userId, BIOMETRIC_STRONG, false /* canAuthenticate */);
assertThat(lockoutState.canUserAuthenticate(userId, BIOMETRIC_STRONG)).isFalse();
assertThat(lockoutState.canUserAuthenticate(userId, BIOMETRIC_WEAK)).isFalse();
assertThat(lockoutState.canUserAuthenticate(userId, BIOMETRIC_CONVENIENCE)).isFalse();
assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
}
private void unlockAllBiometrics() {
@@ -79,9 +85,12 @@ public class MultiBiometricLockoutStateTest {
@Test
public void testInitialStateLockedOut() {
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
}
@Test
@@ -89,20 +98,26 @@ public class MultiBiometricLockoutStateTest {
unlockAllBiometrics();
mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_CONVENIENCE,
false /* canAuthenticate */);
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(
mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
}
@Test
public void testWeakLockout() {
unlockAllBiometrics();
mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_WEAK, false /* canAuthenticate */);
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(
mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
}
@Test
@@ -110,10 +125,13 @@ public class MultiBiometricLockoutStateTest {
lockoutAllBiometrics();
mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_STRONG,
false /* canAuthenticate */);
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(
mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
}
@Test
@@ -121,18 +139,24 @@ public class MultiBiometricLockoutStateTest {
lockoutAllBiometrics();
mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_CONVENIENCE,
true /* canAuthenticate */);
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
}
@Test
public void testWeakUnlock() {
lockoutAllBiometrics();
mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_WEAK, true /* canAuthenticate */);
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
}
@Test
@@ -140,9 +164,12 @@ public class MultiBiometricLockoutStateTest {
lockoutAllBiometrics();
mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_STRONG,
true /* canAuthenticate */);
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
}
@Test
@@ -154,45 +181,66 @@ public class MultiBiometricLockoutStateTest {
lockoutAllBiometrics(lockoutState, userTwo);
lockoutState.setAuthenticatorTo(userOne, BIOMETRIC_WEAK, true /* canAuthenticate */);
assertThat(lockoutState.canUserAuthenticate(userOne, BIOMETRIC_STRONG)).isFalse();
assertThat(lockoutState.canUserAuthenticate(userOne, BIOMETRIC_WEAK)).isTrue();
assertThat(lockoutState.canUserAuthenticate(userOne, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(lockoutState.getLockoutState(userOne, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(lockoutState.getLockoutState(userOne, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(lockoutState.getLockoutState(userOne, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(lockoutState.canUserAuthenticate(userTwo, BIOMETRIC_STRONG)).isFalse();
assertThat(lockoutState.canUserAuthenticate(userTwo, BIOMETRIC_WEAK)).isFalse();
assertThat(lockoutState.canUserAuthenticate(userTwo, BIOMETRIC_CONVENIENCE)).isFalse();
assertThat(lockoutState.getLockoutState(userTwo, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(lockoutState.getLockoutState(userTwo, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(lockoutState.getLockoutState(userTwo, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
}
@Test
public void testTimedLockout() {
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
mLockoutState.increaseLockoutTime(PRIMARY_USER, BIOMETRIC_STRONG,
System.currentTimeMillis() + 1);
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_TIMED);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_TIMED);
assertThat(
mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_TIMED);
}
@Test
public void testTimedLockoutAfterDuration() {
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
when(mClock.millis()).thenReturn(0L);
mLockoutState.increaseLockoutTime(PRIMARY_USER, BIOMETRIC_STRONG, 1);
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_TIMED);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_TIMED);
assertThat(
mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_TIMED);
when(mClock.millis()).thenReturn(2L);
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
}
}

View File

@@ -47,7 +47,6 @@ import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.face.UsageStats;
import org.junit.Before;
@@ -85,8 +84,6 @@ public class FaceAuthenticationClientTest {
@Mock
private BiometricContext mBiometricContext;
@Mock
private LockoutCache mLockoutCache;
@Mock
private UsageStats mUsageStats;
@Mock
private ClientMonitorCallback mCallback;
@@ -161,7 +158,7 @@ public class FaceAuthenticationClientTest {
false /* restricted */, "test-owner", 4 /* cookie */,
false /* requireConfirmation */, 9 /* sensorId */,
mBiometricLogger, mBiometricContext, true /* isStrongBiometric */,
mUsageStats, mLockoutCache, false /* allowBackgroundAuthentication */,
mUsageStats, null /* mLockoutCache */, false /* allowBackgroundAuthentication */,
false /* isKeyguardBypassEnabled */, null /* sensorPrivacyManager */,
0 /* biometricStrength */) {
@Override

View File

@@ -63,7 +63,6 @@ import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutCache;
import org.junit.Before;
import org.junit.Rule;
@@ -114,8 +113,6 @@ public class FingerprintAuthenticationClientTest {
@Mock
private BiometricManager mBiometricManager;
@Mock
private LockoutCache mLockoutCache;
@Mock
private IUdfpsOverlayController mUdfpsOverlayController;
@Mock
private ISidefpsController mSideFpsController;
@@ -658,7 +655,7 @@ public class FingerprintAuthenticationClientTest {
false /* requireConfirmation */,
9 /* sensorId */, mBiometricLogger, mBiometricContext,
true /* isStrongBiometric */,
null /* taskStackListener */, mLockoutCache,
null /* taskStackListener */, null /* lockoutCache */,
mUdfpsOverlayController, mSideFpsController, null, allowBackgroundAuthentication,
mSensorProps,
new Handler(mLooper.getLooper()), 0 /* biometricStrength */, mClock) {