summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/res/res/values/config.xml10
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java140
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java104
4 files changed, 205 insertions, 51 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d441b31a0996..098603e5ab5d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3534,6 +3534,16 @@
automatically dismissing. This is currently used in SideFpsEventHandler -->
<integer name="config_sideFpsToastTimeout">3000</integer>
+ <!-- This acquired message will cause the sidefpsKgPowerPress window to be skipped.
+ If this is set to BIOMETRIC_ACQUIRED_VENDOR, then the framework will skip on
+ config_sidefpsSkipWaitForPowerVendorAcquireMessage -->
+ <integer name="config_sidefpsSkipWaitForPowerAcquireMessage">6</integer>
+
+ <!-- This vendor acquired message that will cause the sidefpsKgPowerPress window to be skipped.
+ config_sidefpsSkipWaitForPowerOnFingerUp must be true and
+ config_sidefpsSkipWaitForPowerAcquireMessage must be BIOMETRIC_ACQUIRED_VENDOR == 6. -->
+ <integer name="config_sidefpsSkipWaitForPowerVendorAcquireMessage">2</integer>
+
<!-- This config is used to force VoiceInteractionService to start on certain low ram devices.
It declares the package name of VoiceInteractionService that should be started. -->
<string translatable="false" name="config_forceVoiceInteractionServicePackage"></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3ddaddd6ba40..456ec433f908 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2634,6 +2634,8 @@
<java-symbol type="integer" name="config_sidefpsKeyguardPowerPressWindow"/>
<java-symbol type="integer" name="config_sidefpsPostAuthDowntime"/>
<java-symbol type="integer" name="config_sideFpsToastTimeout"/>
+ <java-symbol type="integer" name="config_sidefpsSkipWaitForPowerAcquireMessage"/>
+ <java-symbol type="integer" name="config_sidefpsSkipWaitForPowerVendorAcquireMessage"/>
<!-- Clickable toast used during sidefps enrollment -->
<java-symbol type="layout" name="side_fps_toast" />
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index e1626f014d8b..b530c8db3c67 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskStackListener;
@@ -65,22 +67,28 @@ import java.util.function.Supplier;
class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
implements Udfps, LockoutConsumer, PowerPressHandler {
private static final String TAG = "FingerprintAuthenticationClient";
-
- @NonNull private final LockoutCache mLockoutCache;
- @NonNull private final SensorOverlays mSensorOverlays;
- @NonNull private final FingerprintSensorPropertiesInternal mSensorProps;
- @NonNull private final CallbackWithProbe<Probe> mALSProbeCallback;
-
+ private static final int MESSAGE_IGNORE_AUTH = 1;
+ 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;
+ @NonNull
+ private final CallbackWithProbe<Probe> mALSProbeCallback;
+ private final Handler mHandler;
+ private final int mSkipWaitForPowerAcquireMessage;
+ private final int mSkipWaitForPowerVendorAcquireMessage;
+ private final long mFingerUpIgnoresPower = 500;
@Nullable
private ICancellationSignal mCancellationSignal;
private boolean mIsPointerDown;
- private final Handler mHandler;
-
- private static final int MESSAGE_IGNORE_AUTH = 1;
- private static final int MESSAGE_AUTH_SUCCESS = 2;
private long mWaitForAuthKeyguard;
private long mWaitForAuthBp;
private long mIgnoreAuthFor;
+ private Runnable mAuthSuccessRunnable;
FingerprintAuthenticationClient(
@NonNull Context context,
@@ -140,6 +148,13 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
mIgnoreAuthFor =
context.getResources().getInteger(R.integer.config_sidefpsPostAuthDowntime);
+ mSkipWaitForPowerAcquireMessage =
+ context.getResources().getInteger(
+ R.integer.config_sidefpsSkipWaitForPowerAcquireMessage);
+ mSkipWaitForPowerVendorAcquireMessage =
+ context.getResources().getInteger(
+ R.integer.config_sidefpsSkipWaitForPowerVendorAcquireMessage);
+
if (mSensorProps.isAnySidefpsType()) {
if (Build.isDebuggable()) {
mWaitForAuthKeyguard = Settings.Secure.getIntForUser(context.getContentResolver(),
@@ -187,38 +202,55 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
return false;
}
- @Override
- public void onAuthenticated(
+ public void handleAuthenticate(
BiometricAuthenticator.Identifier identifier,
boolean authenticated,
ArrayList<Byte> token) {
-
- long delay = 0;
if (authenticated && mSensorProps.isAnySidefpsType()) {
- if (mHandler.hasMessages(MESSAGE_IGNORE_AUTH)) {
- Slog.i(TAG, "(sideFPS) Ignoring auth due to recent power press");
- onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, 0, true);
- return;
- }
- delay = isKeyguard() ? mWaitForAuthKeyguard : mWaitForAuthBp;
- Slog.i(TAG, "(sideFPS) Auth succeeded, sideFps waiting for power until: " + delay);
+ Slog.i(TAG, "(sideFPS): No power press detected, sending auth");
}
+ super.onAuthenticated(identifier, authenticated, token);
+ if (authenticated) {
+ mState = STATE_STOPPED;
+ mSensorOverlays.hide(getSensorId());
+ } else {
+ mState = STATE_STARTED_PAUSED_ATTEMPTED;
+ }
+ }
+
+ @Override
+ public void onAuthenticated(
+ BiometricAuthenticator.Identifier identifier,
+ boolean authenticated,
+ ArrayList<Byte> token) {
- mHandler.postDelayed(
+ mHandler.post(
() -> {
+ long delay = 0;
if (authenticated && mSensorProps.isAnySidefpsType()) {
- Slog.i(TAG, "(sideFPS): No power press detected, sending auth");
+ if (mHandler.hasMessages(MESSAGE_IGNORE_AUTH)) {
+ Slog.i(TAG, "(sideFPS) Ignoring auth due to recent power press");
+ onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, 0,
+ true);
+ return;
+ }
+ delay = isKeyguard() ? mWaitForAuthKeyguard : mWaitForAuthBp;
+ Slog.i(TAG, "(sideFPS) Auth succeeded, sideFps waiting for power for: "
+ + delay + "ms");
}
- super.onAuthenticated(identifier, authenticated, token);
- if (authenticated) {
- mState = STATE_STOPPED;
- mSensorOverlays.hide(getSensorId());
- } else {
- mState = STATE_STARTED_PAUSED_ATTEMPTED;
+
+ if (mHandler.hasMessages(MESSAGE_FINGER_UP)) {
+ Slog.i(TAG, "Finger up detected, sending auth");
+ delay = 0;
}
- },
- MESSAGE_AUTH_SUCCESS,
- delay);
+
+ mAuthSuccessRunnable =
+ () -> handleAuthenticate(identifier, authenticated, token);
+ mHandler.postDelayed(
+ mAuthSuccessRunnable,
+ MESSAGE_AUTH_SUCCESS,
+ delay);
+ });
}
@Override
@@ -227,6 +259,30 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
// for most ACQUIRED messages. See BiometricFingerprintConstants#FingerprintAcquired
mSensorOverlays.ifUdfps(controller -> controller.onAcquired(getSensorId(), acquiredInfo));
super.onAcquired(acquiredInfo, vendorCode);
+ if (mSensorProps.isAnySidefpsType()) {
+ final boolean shouldLookForVendor =
+ mSkipWaitForPowerAcquireMessage == FINGERPRINT_ACQUIRED_VENDOR;
+ final boolean acquireMessageMatch = acquiredInfo == mSkipWaitForPowerAcquireMessage;
+ final boolean vendorMessageMatch = vendorCode == mSkipWaitForPowerVendorAcquireMessage;
+ final boolean ignorePowerPress =
+ (acquireMessageMatch && !shouldLookForVendor) || (shouldLookForVendor
+ && acquireMessageMatch && vendorMessageMatch);
+
+ if (ignorePowerPress) {
+ Slog.d(TAG, "(sideFPS) onFingerUp");
+ mHandler.post(() -> {
+ if (mHandler.hasMessages(MESSAGE_AUTH_SUCCESS)) {
+ Slog.d(TAG, "(sideFPS) skipping wait for power");
+ mHandler.removeMessages(MESSAGE_AUTH_SUCCESS);
+ mHandler.post(mAuthSuccessRunnable);
+ } else {
+ mHandler.postDelayed(() -> {
+ }, MESSAGE_FINGER_UP, mFingerUpIgnoresPower);
+ }
+ });
+ }
+ }
+
}
@Override
@@ -418,14 +474,18 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
public void onPowerPressed() {
if (mSensorProps.isAnySidefpsType()) {
Slog.i(TAG, "(sideFPS): onPowerPressed");
- if (mHandler.hasMessages(MESSAGE_AUTH_SUCCESS)) {
- Slog.i(TAG, "(sideFPS): Ignoring auth in queue");
- mHandler.removeMessages(MESSAGE_AUTH_SUCCESS);
- // Do not call onError() as that will send an additional callback to coex.
- onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, 0, true);
- }
- mHandler.removeMessages(MESSAGE_IGNORE_AUTH);
- mHandler.postDelayed(() -> {}, MESSAGE_IGNORE_AUTH, mIgnoreAuthFor);
+ mHandler.post(() -> {
+ if (mHandler.hasMessages(MESSAGE_AUTH_SUCCESS)) {
+ Slog.i(TAG, "(sideFPS): Ignoring auth in queue");
+ mHandler.removeMessages(MESSAGE_AUTH_SUCCESS);
+ // Do not call onError() as that will send an additional callback to coex.
+ onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, 0, true);
+ }
+ mHandler.removeMessages(MESSAGE_IGNORE_AUTH);
+ mHandler.postDelayed(() -> {
+ }, MESSAGE_IGNORE_AUTH, mIgnoreAuthFor);
+
+ });
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index ea1e49d8748a..a149f3ee3f53 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -53,6 +53,7 @@ import android.testing.TestableContext;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.internal.R;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
@@ -88,11 +89,13 @@ public class FingerprintAuthenticationClientTest {
private static final int TOUCH_Y = 20;
private static final float TOUCH_MAJOR = 4.4f;
private static final float TOUCH_MINOR = 5.5f;
+ private static final int FINGER_UP = 111;
@Rule
public final TestableContext mContext = new TestableContext(
InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
-
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
@Mock
private ISession mHal;
@Mock
@@ -129,11 +132,7 @@ public class FingerprintAuthenticationClientTest {
private ArgumentCaptor<PointerContext> mPointerContextCaptor;
@Captor
private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
-
- private TestLooper mLooper = new TestLooper();
-
- @Rule
- public final MockitoRule mockito = MockitoJUnit.rule();
+ private final TestLooper mLooper = new TestLooper();
@Before
public void setup() {
@@ -358,16 +357,97 @@ public class FingerprintAuthenticationClientTest {
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
client.onPowerPressed();
+ mLooper.dispatchAll();
mLooper.moveTimeForward(1000);
mLooper.dispatchAll();
client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
true /* authenticated */, new ArrayList<>());
+ mLooper.dispatchAll();
mLooper.moveTimeForward(1000);
mLooper.dispatchAll();
verify(mCallback).onClientFinished(any(), eq(true));
}
+ @Test
+ public void sideFingerprintDoesntSendAuthImmediately() throws Exception {
+ when(mSensorProps.isAnySidefpsType()).thenReturn(true);
+
+ final FingerprintAuthenticationClient client = createClient(1);
+ client.start(mCallback);
+ mLooper.dispatchAll();
+ client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
+ true /* authenticated */, new ArrayList<>());
+ mLooper.dispatchAll();
+
+ verify(mCallback, never()).onClientFinished(any(), anyBoolean());
+ }
+
+ @Test
+ public void sideFingerprintSkipsWindowIfFingerUp() throws Exception {
+ when(mSensorProps.isAnySidefpsType()).thenReturn(true);
+
+ mContext.getOrCreateTestableResources().addOverride(
+ R.integer.config_sidefpsSkipWaitForPowerAcquireMessage, FINGER_UP);
+
+ final FingerprintAuthenticationClient client = createClient(1);
+ client.start(mCallback);
+ mLooper.dispatchAll();
+ client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
+ true /* authenticated */, new ArrayList<>());
+ client.onAcquired(FINGER_UP, 0);
+ mLooper.dispatchAll();
+
+ verify(mCallback).onClientFinished(any(), eq(true));
+ }
+
+ @Test
+ public void sideFingerprintSendsAuthIfFingerUp() throws Exception {
+ when(mSensorProps.isAnySidefpsType()).thenReturn(true);
+
+ mContext.getOrCreateTestableResources().addOverride(
+ R.integer.config_sidefpsSkipWaitForPowerAcquireMessage, FINGER_UP);
+
+ final FingerprintAuthenticationClient client = createClient(1);
+ client.start(mCallback);
+ mLooper.dispatchAll();
+ client.onAcquired(FINGER_UP, 0);
+ client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
+ true /* authenticated */, new ArrayList<>());
+ mLooper.dispatchAll();
+
+ verify(mCallback).onClientFinished(any(), eq(true));
+ }
+
+ @Test
+ public void sideFingerprintShortCircuitExpires() throws Exception {
+ when(mSensorProps.isAnySidefpsType()).thenReturn(true);
+
+ final int timeBeforeAuthSent = 500;
+
+ mContext.getOrCreateTestableResources().addOverride(
+ R.integer.config_sidefpsKeyguardPowerPressWindow, timeBeforeAuthSent);
+ mContext.getOrCreateTestableResources().addOverride(
+ R.integer.config_sidefpsSkipWaitForPowerAcquireMessage, FINGER_UP);
+
+ final FingerprintAuthenticationClient client = createClient(1);
+ client.start(mCallback);
+ mLooper.dispatchAll();
+ client.onAcquired(FINGER_UP, 0);
+ mLooper.dispatchAll();
+
+ mLooper.moveTimeForward(500);
+ mLooper.dispatchAll();
+ client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
+ true /* authenticated */, new ArrayList<>());
+ mLooper.dispatchAll();
+ verify(mCallback, never()).onClientFinished(any(), anyBoolean());
+
+ mLooper.moveTimeForward(500);
+ mLooper.dispatchAll();
+ verify(mCallback).onClientFinished(any(), eq(true));
+ }
+
private FingerprintAuthenticationClient createClient() throws RemoteException {
return createClient(100 /* version */, true /* allowBackgroundAuthentication */);
}
@@ -388,11 +468,13 @@ public class FingerprintAuthenticationClientTest {
final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback);
return new FingerprintAuthenticationClient(mContext, () -> aidl, mToken,
REQUEST_ID, mClientMonitorCallbackConverter, 5 /* targetUserId */, OP_ID,
- false /* restricted */, "test-owner", 4 /* cookie */, false /* requireConfirmation */,
- 9 /* sensorId */, mBiometricLogger, mBiometricContext,
- true /* isStrongBiometric */,
- null /* taskStackListener */, mLockoutCache,
- mUdfpsOverlayController, mSideFpsController, allowBackgroundAuthentication, mSensorProps,
+ false /* restricted */, "test-owner", 4 /* cookie */,
+ false /* requireConfirmation */,
+ 9 /* sensorId */, mBiometricLogger, mBiometricContext,
+ true /* isStrongBiometric */,
+ null /* taskStackListener */, mLockoutCache,
+ mUdfpsOverlayController, mSideFpsController, allowBackgroundAuthentication,
+ mSensorProps,
new Handler(mLooper.getLooper())) {
@Override
protected ActivityTaskManager getActivityTaskManager() {