Implementations of biometric contraints for weak and convenience tiers
(1) 24 hours fallback
(2) 4 hours idle timeout
Bug: 141025588
Test: atest AuthServiceTest
Test: atest KeyguardUpdateMonitorTest
Test: atest BiometricsUnlockControllerTest
Test: atest KeyguardIndicationControllerTest
Test: make -j
Change-Id: I1078ce39a2ae1e4c250b6468e477b703e3016e2c
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 204f072..8ed221d 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -311,6 +311,7 @@
}
authenticator = new FingerprintAuthenticator(fingerprintService);
+ fingerprintService.initConfiguredStrength(config.mStrength);
break;
case TYPE_FACE:
@@ -322,6 +323,7 @@
}
authenticator = new FaceAuthenticator(faceService);
+ faceService.initConfiguredStrength(config.mStrength);
break;
case TYPE_IRIS:
@@ -333,6 +335,7 @@
}
authenticator = new IrisAuthenticator(irisService);
+ irisService.initConfiguredStrength(config.mStrength);
break;
default:
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 0e70994..74c70df 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -31,6 +31,7 @@
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricNativeHandle;
import android.hardware.biometrics.IBiometricService;
@@ -106,6 +107,7 @@
private PerformanceStats mPerformanceStats;
protected int mCurrentUserId = UserHandle.USER_NULL;
protected long mHalDeviceId;
+ private int mOEMStrength; // Tracks the OEM configured biometric modality strength
// Tracks if the current authentication makes use of CryptoObjects.
protected boolean mIsCrypto;
// Normal authentications are tracked by mPerformanceMap.
@@ -681,6 +683,20 @@
statsModality(), BiometricsProtoEnums.ISSUE_HAL_DEATH);
}
+ protected void initConfiguredStrengthInternal(int strength) {
+ if (DEBUG) {
+ Slog.d(getTag(), "initConfiguredStrengthInternal(" + strength + ")");
+ }
+ mOEMStrength = strength;
+ }
+
+ protected boolean isStrongBiometric() {
+ // TODO(b/141025588): need to calculate actual strength when downgrading tiers
+ final int biometricBits = mOEMStrength
+ & BiometricManager.Authenticators.BIOMETRIC_MIN_STRENGTH;
+ return biometricBits == BiometricManager.Authenticators.BIOMETRIC_STRONG;
+ }
+
protected ClientMonitor getCurrentClient() {
return mCurrentClient;
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 31c3d4d..a87a455 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -740,6 +740,12 @@
}
return 0;
}
+
+ @Override // Binder call
+ public void initConfiguredStrength(int strength) {
+ checkPermission(USE_BIOMETRIC_INTERNAL);
+ initConfiguredStrengthInternal(strength);
+ }
}
/**
@@ -809,7 +815,7 @@
if (mFaceServiceReceiver != null) {
if (biometric == null || biometric instanceof Face) {
mFaceServiceReceiver.onAuthenticationSucceeded(deviceId, (Face) biometric,
- userId);
+ userId, isStrongBiometric());
} else {
Slog.e(TAG, "onAuthenticationSucceeded received non-face biometric");
}
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 0a61988..83aa9cf 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -21,6 +21,7 @@
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
import static android.Manifest.permission.USE_BIOMETRIC;
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.Manifest.permission.USE_FINGERPRINT;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
@@ -462,6 +463,12 @@
checkPermission(MANAGE_FINGERPRINT);
mClientActiveCallbacks.remove(callback);
}
+
+ @Override // Binder call
+ public void initConfiguredStrength(int strength) {
+ checkPermission(USE_BIOMETRIC_INTERNAL);
+ initConfiguredStrengthInternal(strength);
+ }
}
/**
@@ -526,8 +533,8 @@
throws RemoteException {
if (mFingerprintServiceReceiver != null) {
if (biometric == null || biometric instanceof Fingerprint) {
- mFingerprintServiceReceiver
- .onAuthenticationSucceeded(deviceId, (Fingerprint) biometric, userId);
+ mFingerprintServiceReceiver.onAuthenticationSucceeded(deviceId,
+ (Fingerprint) biometric, userId, isStrongBiometric());
} else {
Slog.e(TAG, "onAuthenticationSucceeded received non-fingerprint biometric");
}
diff --git a/services/core/java/com/android/server/biometrics/iris/IrisService.java b/services/core/java/com/android/server/biometrics/iris/IrisService.java
index 2817315..903ae6b 100644
--- a/services/core/java/com/android/server/biometrics/iris/IrisService.java
+++ b/services/core/java/com/android/server/biometrics/iris/IrisService.java
@@ -16,9 +16,12 @@
package com.android.server.biometrics.iris;
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
+
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.iris.IIrisService;
import com.android.server.biometrics.AuthenticationClient;
import com.android.server.biometrics.BiometricServiceBase;
@@ -42,6 +45,17 @@
private static final String TAG = "IrisService";
/**
+ * Receives the incoming binder calls from IrisManager.
+ */
+ private final class IrisServiceWrapper extends IIrisService.Stub {
+ @Override // Binder call
+ public void initConfiguredStrength(int strength) {
+ checkPermission(USE_BIOMETRIC_INTERNAL);
+ initConfiguredStrengthInternal(strength);
+ }
+ }
+
+ /**
* Initializes the system service.
* <p>
* Subclasses must define a single argument constructor that accepts the context
@@ -57,6 +71,7 @@
@Override
public void onStart() {
super.onStart();
+ publishBinderService(Context.IRIS_SERVICE, new IrisServiceWrapper());
}
@Override
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 1f4048f..15dfab9 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -17,6 +17,7 @@
package com.android.server.locksettings;
import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
+import static android.Manifest.permission.MANAGE_BIOMETRIC;
import static android.Manifest.permission.READ_CONTACTS;
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -178,6 +179,7 @@
public class LockSettingsService extends ILockSettings.Stub {
private static final String TAG = "LockSettingsService";
private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
+ private static final String BIOMETRIC_PERMISSION = MANAGE_BIOMETRIC;
private static final boolean DEBUG = false;
private static final int PROFILE_KEY_IV_SIZE = 12;
@@ -1050,6 +1052,10 @@
}
}
+ private final void checkBiometricPermission() {
+ mContext.enforceCallingOrSelfPermission(BIOMETRIC_PERMISSION, "LockSettingsBiometric");
+ }
+
@Override
public boolean hasSecureLockScreen() {
return mHasSecureLockScreen;
@@ -2304,6 +2310,18 @@
}
@Override
+ public void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
+ checkBiometricPermission();
+ mStrongAuth.reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+ }
+
+ @Override
+ public void scheduleNonStrongBiometricIdleTimeout(int userId) {
+ checkBiometricPermission();
+ mStrongAuth.scheduleNonStrongBiometricIdleTimeout(userId);
+ }
+
+ @Override
public void userPresent(int userId) {
checkWritePermission(userId);
mStrongAuth.reportUnlock(userId);
@@ -3191,6 +3209,12 @@
mStorage.dump(pw);
pw.println();
pw.decreaseIndent();
+
+ pw.println("StrongAuth:");
+ pw.increaseIndent();
+ mStrongAuth.dump(pw);
+ pw.println();
+ pw.decreaseIndent();
}
/**
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
index 91cf53e..fbee6f4 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
@@ -17,6 +17,7 @@
package com.android.server.locksettings;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
import android.app.AlarmManager;
@@ -32,8 +33,10 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
/**
@@ -42,6 +45,7 @@
public class LockSettingsStrongAuth {
private static final String TAG = "LockSettings";
+ private static final boolean DEBUG = false;
private static final int MSG_REQUIRE_STRONG_AUTH = 1;
private static final int MSG_REGISTER_TRACKER = 2;
@@ -49,15 +53,40 @@
private static final int MSG_REMOVE_USER = 4;
private static final int MSG_SCHEDULE_STRONG_AUTH_TIMEOUT = 5;
private static final int MSG_NO_LONGER_REQUIRE_STRONG_AUTH = 6;
+ private static final int MSG_SCHEDULE_NON_STRONG_BIOMETRIC_TIMEOUT = 7;
+ private static final int MSG_STRONG_BIOMETRIC_UNLOCK = 8;
+ private static final int MSG_SCHEDULE_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT = 9;
private static final String STRONG_AUTH_TIMEOUT_ALARM_TAG =
"LockSettingsStrongAuth.timeoutForUser";
+ private static final String NON_STRONG_BIOMETRIC_TIMEOUT_ALARM_TAG =
+ "LockSettingsPrimaryAuth.nonStrongBiometricTimeoutForUser";
+ private static final String NON_STRONG_BIOMETRIC_IDLE_TIMEOUT_ALARM_TAG =
+ "LockSettingsPrimaryAuth.nonStrongBiometricIdleTimeoutForUser";
+
+ /**
+ * Default and maximum timeout in milliseconds after which unlocking with weak auth times out,
+ * i.e. the user has to use a strong authentication method like password, PIN or pattern.
+ */
+ public static final long DEFAULT_NON_STRONG_BIOMETRIC_TIMEOUT_MS = 24 * 60 * 60 * 1000; // 24h
+ public static final long DEFAULT_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT_MS =
+ 4 * 60 * 60 * 1000; // 4h
private final RemoteCallbackList<IStrongAuthTracker> mTrackers = new RemoteCallbackList<>();
private final SparseIntArray mStrongAuthForUser = new SparseIntArray();
+ private final SparseBooleanArray mIsNonStrongBiometricAllowedForUser = new SparseBooleanArray();
private final ArrayMap<Integer, StrongAuthTimeoutAlarmListener>
mStrongAuthTimeoutAlarmListenerForUser = new ArrayMap<>();
+ // Track non-strong biometric timeout
+ private final ArrayMap<Integer, NonStrongBiometricTimeoutAlarmListener>
+ mNonStrongBiometricTimeoutAlarmListener = new ArrayMap<>();
+ // Track non-strong biometric idle timeout
+ private final ArrayMap<Integer, NonStrongBiometricIdleTimeoutAlarmListener>
+ mNonStrongBiometricIdleTimeoutAlarmListener = new ArrayMap<>();
+
private final int mDefaultStrongAuthFlags;
+ private final boolean mDefaultIsNonStrongBiometricAllowed = true;
+
private final Context mContext;
private AlarmManager mAlarmManager;
@@ -80,6 +109,17 @@
Slog.e(TAG, "Exception while adding StrongAuthTracker.", e);
}
}
+
+ for (int i = 0; i < mIsNonStrongBiometricAllowedForUser.size(); i++) {
+ int key = mIsNonStrongBiometricAllowedForUser.keyAt(i);
+ boolean value = mIsNonStrongBiometricAllowedForUser.valueAt(i);
+ try {
+ tracker.onIsNonStrongBiometricAllowedChanged(value, key);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception while adding StrongAuthTracker: "
+ + "IsNonStrongBiometricAllowedChanged.", e);
+ }
+ }
}
private void handleRemoveStrongAuthTracker(IStrongAuthTracker tracker) {
@@ -134,6 +174,13 @@
mStrongAuthForUser.removeAt(index);
notifyStrongAuthTrackers(mDefaultStrongAuthFlags, userId);
}
+
+ index = mIsNonStrongBiometricAllowedForUser.indexOfKey(userId);
+ if (index >= 0) {
+ mIsNonStrongBiometricAllowedForUser.removeAt(index);
+ notifyStrongAuthTrackersForIsNonStrongBiometricAllowed(
+ mDefaultIsNonStrongBiometricAllowed, userId);
+ }
}
private void handleScheduleStrongAuthTimeout(int userId) {
@@ -151,6 +198,125 @@
// schedule a new alarm listener for the user
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, STRONG_AUTH_TIMEOUT_ALARM_TAG,
alarm, mHandler);
+
+ // cancel current non-strong biometric alarm listener for the user (if there was one)
+ cancelNonStrongBiometricAlarmListener(userId);
+ // cancel current non-strong biometric idle alarm listener for the user (if there was one)
+ cancelNonStrongBiometricIdleAlarmListener(userId);
+ // re-allow unlock with non-strong biometrics
+ setIsNonStrongBiometricAllowed(true, userId);
+ }
+
+ private void handleScheduleNonStrongBiometricTimeout(int userId) {
+ if (DEBUG) Slog.d(TAG, "handleScheduleNonStrongBiometricTimeout for userId=" + userId);
+ long when = SystemClock.elapsedRealtime() + DEFAULT_NON_STRONG_BIOMETRIC_TIMEOUT_MS;
+ NonStrongBiometricTimeoutAlarmListener alarm = mNonStrongBiometricTimeoutAlarmListener
+ .get(userId);
+ if (alarm != null) {
+ // Unlock with non-strong biometric will not affect the existing non-strong biometric
+ // timeout alarm
+ if (DEBUG) {
+ Slog.d(TAG, "There is an existing alarm for non-strong biometric"
+ + " fallback timeout, so do not re-schedule");
+ }
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, "Schedule a new alarm for non-strong biometric fallback timeout");
+ }
+ alarm = new NonStrongBiometricTimeoutAlarmListener(userId);
+ mNonStrongBiometricTimeoutAlarmListener.put(userId, alarm);
+ // schedule a new alarm listener for the user
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when,
+ NON_STRONG_BIOMETRIC_TIMEOUT_ALARM_TAG, alarm, mHandler);
+ }
+
+ // cancel current non-strong biometric idle alarm listener for the user (if there was one)
+ cancelNonStrongBiometricIdleAlarmListener(userId);
+ }
+
+ private void handleStrongBiometricUnlock(int userId) {
+ if (DEBUG) Slog.d(TAG, "handleStrongBiometricUnlock for userId=" + userId);
+ // cancel current non-strong biometric alarm listener for the user (if there was one)
+ cancelNonStrongBiometricAlarmListener(userId);
+ // cancel current non-strong biometric idle alarm listener for the user (if there was one)
+ cancelNonStrongBiometricIdleAlarmListener(userId);
+ // re-allow unlock with non-strong biometrics
+ setIsNonStrongBiometricAllowed(true, userId);
+ }
+
+ private void cancelNonStrongBiometricAlarmListener(int userId) {
+ if (DEBUG) Slog.d(TAG, "cancelNonStrongBiometricAlarmListener for userId=" + userId);
+ NonStrongBiometricTimeoutAlarmListener alarm = mNonStrongBiometricTimeoutAlarmListener
+ .get(userId);
+ if (alarm != null) {
+ if (DEBUG) Slog.d(TAG, "Cancel alarm for non-strong biometric fallback timeout");
+ mAlarmManager.cancel(alarm);
+ // need to remove the alarm when cancelled by primary auth or strong biometric
+ mNonStrongBiometricTimeoutAlarmListener.remove(userId);
+ }
+ }
+
+ private void cancelNonStrongBiometricIdleAlarmListener(int userId) {
+ if (DEBUG) Slog.d(TAG, "cancelNonStrongBiometricIdleAlarmListener for userId=" + userId);
+ // cancel idle alarm listener by any unlocks (i.e. primary auth, strong biometric,
+ // non-strong biometric)
+ NonStrongBiometricIdleTimeoutAlarmListener alarm =
+ mNonStrongBiometricIdleTimeoutAlarmListener.get(userId);
+ if (alarm != null) {
+ if (DEBUG) Slog.d(TAG, "Cancel alarm for non-strong biometric idle timeout");
+ mAlarmManager.cancel(alarm);
+ }
+ }
+
+ private void setIsNonStrongBiometricAllowed(boolean allowed, int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "setIsNonStrongBiometricAllowed for allowed=" + allowed
+ + ", userId=" + userId);
+ }
+ if (userId == UserHandle.USER_ALL) {
+ for (int i = 0; i < mIsNonStrongBiometricAllowedForUser.size(); i++) {
+ int key = mIsNonStrongBiometricAllowedForUser.keyAt(i);
+ setIsNonStrongBiometricAllowedOneUser(allowed, key);
+ }
+ } else {
+ setIsNonStrongBiometricAllowedOneUser(allowed, userId);
+ }
+ }
+
+ private void setIsNonStrongBiometricAllowedOneUser(boolean allowed, int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "setIsNonStrongBiometricAllowedOneUser for allowed=" + allowed
+ + ", userId=" + userId);
+ }
+ boolean oldValue = mIsNonStrongBiometricAllowedForUser.get(userId,
+ mDefaultIsNonStrongBiometricAllowed);
+ if (allowed != oldValue) {
+ if (DEBUG) {
+ Slog.d(TAG, "mIsNonStrongBiometricAllowedForUser value changed:"
+ + " oldValue=" + oldValue + ", allowed=" + allowed);
+ }
+ mIsNonStrongBiometricAllowedForUser.put(userId, allowed);
+ notifyStrongAuthTrackersForIsNonStrongBiometricAllowed(allowed, userId);
+ }
+ }
+
+ private void handleScheduleNonStrongBiometricIdleTimeout(int userId) {
+ if (DEBUG) Slog.d(TAG, "handleScheduleNonStrongBiometricIdleTimeout for userId=" + userId);
+ long when = SystemClock.elapsedRealtime() + DEFAULT_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT_MS;
+ // cancel current alarm listener for the user (if there was one)
+ NonStrongBiometricIdleTimeoutAlarmListener alarm =
+ mNonStrongBiometricIdleTimeoutAlarmListener.get(userId);
+ if (alarm != null) {
+ if (DEBUG) Slog.d(TAG, "Cancel existing alarm for non-strong biometric idle timeout");
+ mAlarmManager.cancel(alarm);
+ } else {
+ alarm = new NonStrongBiometricIdleTimeoutAlarmListener(userId);
+ mNonStrongBiometricIdleTimeoutAlarmListener.put(userId, alarm);
+ }
+ // schedule a new alarm listener for the user
+ if (DEBUG) Slog.d(TAG, "Schedule a new alarm for non-strong biometric idle timeout");
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when,
+ NON_STRONG_BIOMETRIC_IDLE_TIMEOUT_ALARM_TAG, alarm, mHandler);
}
private void notifyStrongAuthTrackers(int strongAuthReason, int userId) {
@@ -170,6 +336,29 @@
}
}
+ private void notifyStrongAuthTrackersForIsNonStrongBiometricAllowed(boolean allowed,
+ int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "notifyStrongAuthTrackersForIsNonStrongBiometricAllowed"
+ + " for allowed=" + allowed + ", userId=" + userId);
+ }
+ int i = mTrackers.beginBroadcast();
+ try {
+ while (i > 0) {
+ i--;
+ try {
+ mTrackers.getBroadcastItem(i).onIsNonStrongBiometricAllowedChanged(
+ allowed, userId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception while notifying StrongAuthTracker: "
+ + "IsNonStrongBiometricAllowedChanged.", e);
+ }
+ }
+ } finally {
+ mTrackers.finishBroadcast();
+ }
+ }
+
public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
mHandler.obtainMessage(MSG_REGISTER_TRACKER, tracker).sendToTarget();
}
@@ -207,11 +396,45 @@
requireStrongAuth(STRONG_AUTH_NOT_REQUIRED, userId);
}
+ /**
+ * Report successful unlocking with primary auth
+ */
public void reportSuccessfulStrongAuthUnlock(int userId) {
final int argNotUsed = 0;
mHandler.obtainMessage(MSG_SCHEDULE_STRONG_AUTH_TIMEOUT, userId, argNotUsed).sendToTarget();
}
+ /**
+ * Report successful unlocking with biometric
+ */
+ public void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "reportSuccessfulBiometricUnlock for isStrongBiometric="
+ + isStrongBiometric + ", userId=" + userId);
+ }
+ final int argNotUsed = 0;
+ if (isStrongBiometric) { // unlock with strong biometric
+ mHandler.obtainMessage(MSG_STRONG_BIOMETRIC_UNLOCK, userId, argNotUsed)
+ .sendToTarget();
+ } else { // unlock with non-strong biometric (i.e. weak or convenience)
+ mHandler.obtainMessage(MSG_SCHEDULE_NON_STRONG_BIOMETRIC_TIMEOUT, userId, argNotUsed)
+ .sendToTarget();
+ }
+ }
+
+ /**
+ * Schedule idle timeout for non-strong biometric (i.e. weak or convenience)
+ */
+ public void scheduleNonStrongBiometricIdleTimeout(int userId) {
+ if (DEBUG) Slog.d(TAG, "scheduleNonStrongBiometricIdleTimeout for userId=" + userId);
+ final int argNotUsed = 0;
+ mHandler.obtainMessage(MSG_SCHEDULE_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT, userId, argNotUsed)
+ .sendToTarget();
+ }
+
+ /**
+ * Alarm of fallback timeout for primary auth
+ */
private class StrongAuthTimeoutAlarmListener implements OnAlarmListener {
private final int mUserId;
@@ -226,6 +449,41 @@
}
}
+ /**
+ * Alarm of fallback timeout for non-strong biometric (i.e. weak or convenience)
+ */
+ private class NonStrongBiometricTimeoutAlarmListener implements OnAlarmListener {
+
+ private final int mUserId;
+
+ NonStrongBiometricTimeoutAlarmListener(int userId) {
+ mUserId = userId;
+ }
+
+ @Override
+ public void onAlarm() {
+ requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT, mUserId);
+ }
+ }
+
+ /**
+ * Alarm of idle timeout for non-strong biometric (i.e. weak or convenience biometric)
+ */
+ private class NonStrongBiometricIdleTimeoutAlarmListener implements OnAlarmListener {
+
+ private final int mUserId;
+
+ NonStrongBiometricIdleTimeoutAlarmListener(int userId) {
+ mUserId = userId;
+ }
+
+ @Override
+ public void onAlarm() {
+ // disallow unlock with non-strong biometrics
+ setIsNonStrongBiometricAllowed(false, mUserId);
+ }
+ }
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -248,8 +506,38 @@
case MSG_NO_LONGER_REQUIRE_STRONG_AUTH:
handleNoLongerRequireStrongAuth(msg.arg1, msg.arg2);
break;
+ case MSG_SCHEDULE_NON_STRONG_BIOMETRIC_TIMEOUT:
+ handleScheduleNonStrongBiometricTimeout(msg.arg1);
+ break;
+ case MSG_STRONG_BIOMETRIC_UNLOCK:
+ handleStrongBiometricUnlock(msg.arg1);
+ break;
+ case MSG_SCHEDULE_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT:
+ handleScheduleNonStrongBiometricIdleTimeout(msg.arg1);
+ break;
}
}
};
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("PrimaryAuthFlags state:");
+ pw.increaseIndent();
+ for (int i = 0; i < mStrongAuthForUser.size(); i++) {
+ final int key = mStrongAuthForUser.keyAt(i);
+ final int value = mStrongAuthForUser.valueAt(i);
+ pw.println("userId=" + key + ", primaryAuthFlags=" + Integer.toHexString(value));
+ }
+ pw.println();
+ pw.decreaseIndent();
+
+ pw.println("NonStrongBiometricAllowed state:");
+ pw.increaseIndent();
+ for (int i = 0; i < mIsNonStrongBiometricAllowedForUser.size(); i++) {
+ final int key = mIsNonStrongBiometricAllowedForUser.keyAt(i);
+ final boolean value = mIsNonStrongBiometricAllowedForUser.valueAt(i);
+ pw.println("userId=" + key + ", allowed=" + value);
+ }
+ pw.println();
+ pw.decreaseIndent();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index 1c8b00f..30bb38a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -111,6 +111,29 @@
any());
}
+ @Test
+ public void testRegisterAuthenticator_callsInitConfiguredStrength() throws Exception {
+
+ final String[] config = {
+ "0:2:15", // ID0:Fingerprint:Strong
+ "1:4:255", // ID1:Iris:Weak
+ "2:8:4095", // ID2:Face:Convenience
+ };
+
+ when(mInjector.getConfiguration(any())).thenReturn(config);
+
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ final int fingerprintStrength = 15;
+ final int irisStrength = 255;
+ final int faceStrength = 4095;
+
+ verify(mFingerprintService).initConfiguredStrength(eq(fingerprintStrength));
+ verify(mIrisService).initConfiguredStrength(eq(irisStrength));
+ verify(mFaceService).initConfiguredStrength(eq(faceStrength));
+ }
+
// TODO(b/141025588): Check that an exception is thrown when the userId != callingUserId
@Test