summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kevin Chyn <kchyn@google.com> 2021-02-10 09:40:21 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-02-10 09:40:21 +0000
commit8ce6b9fbd9084b0d837391462a136b127c61de9c (patch)
tree68338a7157927ec6b24dc418f43acc2b8cfc993d
parentd438be4ba8d97233f04b15ca36b5027c853d4a16 (diff)
parent0c1be610a22585dfd191268c3d749d088db49108 (diff)
Merge changes I96fe9587,Ie51b121b into sc-dev
* changes: Request cancelAllSensors when STATE_AUTH_CALLED Add BaseClientMonitor#interruptsPrecedingClients
-rw-r--r--services/core/java/com/android/server/biometrics/AuthSession.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java26
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/EnrollClient.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java37
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java37
9 files changed, 108 insertions, 25 deletions
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index 14292d9c5f8d..c9560437799e 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -686,7 +686,8 @@ public final class AuthSession implements IBinder.DeathRecipient {
* @return true if this AuthSession is finished, e.g. should be set to null
*/
boolean onCancelAuthSession(boolean force) {
- final boolean authStarted = mState == STATE_AUTH_STARTED
+ final boolean authStarted = mState == STATE_AUTH_CALLED
+ || mState == STATE_AUTH_STARTED
|| mState == STATE_AUTH_STARTED_UI_SHOWING;
if (authStarted && !force) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 0536e78e58f6..b31a54b8b15e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -311,4 +311,9 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
public int getProtoEnum() {
return BiometricsProto.CM_AUTHENTICATE;
}
+
+ @Override
+ public boolean interruptsPrecedingClients() {
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index 8fa3bbbf615a..81ce2d535237 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -82,12 +82,18 @@ public abstract class BaseClientMonitor extends LoggableMonitor
@NonNull protected Callback mCallback;
/**
- * Returns a ClientMonitorEnum constant defined in biometrics.proto
- * @return
+ * @return A ClientMonitorEnum constant defined in biometrics.proto
*/
public abstract int getProtoEnum();
/**
+ * @return True if the ClientMonitor should cancel any current and pending interruptable clients
+ */
+ public boolean interruptsPrecedingClients() {
+ return false;
+ }
+
+ /**
* @param context system_server context
* @param token a unique token for the client
* @param listener recipient of related events (e.g. authentication)
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index c5237ab8c8e7..20c25c35535a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -475,14 +475,17 @@ public class BiometricScheduler {
*/
public void scheduleClientMonitor(@NonNull BaseClientMonitor clientMonitor,
@Nullable BaseClientMonitor.Callback clientCallback) {
- // Mark any interruptable pending clients as canceling. Once they reach the head of the
- // queue, the scheduler will send ERROR_CANCELED and skip the operation.
- for (Operation operation : mPendingOperations) {
- if (operation.mClientMonitor instanceof Interruptable
- && operation.mState != Operation.STATE_WAITING_IN_QUEUE_CANCELING) {
- Slog.d(getTag(), "New client incoming, marking pending client as canceling: "
- + operation.mClientMonitor);
- operation.mState = Operation.STATE_WAITING_IN_QUEUE_CANCELING;
+ // If the incoming operation should interrupt preceding clients, mark any interruptable
+ // pending clients as canceling. Once they reach the head of the queue, the scheduler will
+ // send ERROR_CANCELED and skip the operation.
+ if (clientMonitor.interruptsPrecedingClients()) {
+ for (Operation operation : mPendingOperations) {
+ if (operation.mClientMonitor instanceof Interruptable
+ && operation.mState != Operation.STATE_WAITING_IN_QUEUE_CANCELING) {
+ Slog.d(getTag(), "New client incoming, marking pending client as canceling: "
+ + operation.mClientMonitor);
+ operation.mState = Operation.STATE_WAITING_IN_QUEUE_CANCELING;
+ }
}
}
@@ -490,8 +493,11 @@ public class BiometricScheduler {
Slog.d(getTag(), "[Added] " + clientMonitor
+ ", new queue size: " + mPendingOperations.size());
- // If the current operation is cancellable, start the cancellation process.
- if (mCurrentOperation != null && mCurrentOperation.mClientMonitor instanceof Interruptable
+ // If the new operation should interrupt preceding clients, and if the current operation is
+ // cancellable, start the cancellation process.
+ if (clientMonitor.interruptsPrecedingClients()
+ && mCurrentOperation != null
+ && mCurrentOperation.mClientMonitor instanceof Interruptable
&& mCurrentOperation.mState == Operation.STATE_STARTED) {
Slog.d(getTag(), "[Cancelling Interruptable]: " + mCurrentOperation);
cancelInternal(mCurrentOperation);
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
index 8d81016dab59..e1320d8e1a4f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
@@ -113,4 +113,9 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> {
public int getProtoEnum() {
return BiometricsProto.CM_ENROLL;
}
+
+ @Override
+ public boolean interruptsPrecedingClients() {
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index 9611192fa13e..bcd1b8bc9976 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -98,4 +98,9 @@ class FingerprintDetectClient extends AcquisitionClient<ISession> {
public int getProtoEnum() {
return BiometricsProto.CM_DETECT_INTERACTION;
}
+
+ @Override
+ public boolean interruptsPrecedingClients() {
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 7989dca3e06f..8acb284667c7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -130,4 +130,9 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
public int getProtoEnum() {
return BiometricsProto.CM_DETECT_INTERACTION;
}
+
+ @Override
+ public boolean interruptsPrecedingClients() {
+ return true;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index 8d890b9cd606..7a4b901bdc5e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -103,7 +103,8 @@ public class AuthSessionTest {
@Test
public void testNewAuthSession_eligibleSensorsSetToStateUnknown() throws RemoteException {
setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_REAR);
- setupFace(1 /* id */, false /* confirmationAlwaysRequired */);
+ setupFace(1 /* id */, false /* confirmationAlwaysRequired */,
+ mock(IBiometricAuthenticator.class));
final AuthSession session = createAuthSession(mSensors,
false /* checkDevicePolicyManager */,
@@ -118,7 +119,8 @@ public class AuthSessionTest {
@Test
public void testStartNewAuthSession() throws RemoteException {
- setupFace(0 /* id */, false /* confirmationAlwaysRequired */);
+ setupFace(0 /* id */, false /* confirmationAlwaysRequired */,
+ mock(IBiometricAuthenticator.class));
setupFingerprint(1 /* id */, FingerprintSensorProperties.TYPE_REAR);
final boolean requireConfirmation = true;
@@ -181,9 +183,6 @@ public class AuthSessionTest {
final long operationId = 123;
final int userId = 10;
- final int callingUid = 100;
- final int callingPid = 1000;
- final int callingUserId = 10000;
final AuthSession session = createAuthSession(mSensors,
false /* checkDevicePolicyManager */,
@@ -220,7 +219,25 @@ public class AuthSessionTest {
assertEquals(STATE_AUTH_STARTED_UI_SHOWING, session.getState());
assertEquals(BiometricSensor.STATE_AUTHENTICATING,
session.mPreAuthInfo.eligibleSensors.get(0).getSensorState());
+ }
+
+ @Test
+ public void testCancelAuthentication_whenStateAuthCalled_invokesCancel()
+ throws RemoteException {
+ final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class);
+
+ setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator);
+ final AuthSession session = createAuthSession(mSensors,
+ false /* checkDevicePolicyManager */,
+ Authenticators.BIOMETRIC_STRONG,
+ 0 /* operationId */,
+ 0 /* userId */);
+
+ session.goToInitialState();
+ assertEquals(STATE_AUTH_CALLED, session.getState());
+ session.onCancelAuthSession(false /* force */);
+ verify(faceAuthenticator).cancelAuthenticationFromService(eq(mToken), eq(TEST_PACKAGE));
}
private PreAuthInfo createPreAuthInfo(List<BiometricSensor> sensors, int userId,
@@ -282,14 +299,14 @@ public class AuthSessionTest {
false /* resetLockoutRequiresHardwareAuthToken */));
}
- private void setupFace(int id, boolean confirmationAlwaysRequired) throws RemoteException {
- IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class);
- when(faceAuthenticator.isHardwareDetected(any())).thenReturn(true);
- when(faceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
+ private void setupFace(int id, boolean confirmationAlwaysRequired,
+ IBiometricAuthenticator authenticator) throws RemoteException {
+ when(authenticator.isHardwareDetected(any())).thenReturn(true);
+ when(authenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
mSensors.add(new BiometricSensor(id,
TYPE_FACE /* modality */,
Authenticators.BIOMETRIC_STRONG /* strength */,
- faceAuthenticator) {
+ authenticator) {
@Override
boolean confirmationAlwaysRequired(int userId) {
return confirmationAlwaysRequired;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 2d457260b8fe..7dd073499c73 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -27,6 +27,8 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
import android.content.Context;
import android.hardware.biometrics.BiometricConstants;
@@ -159,8 +161,8 @@ public class BiometricSchedulerTest {
// Client 1 cleans up properly
verify(listener1).onError(eq(TEST_SENSOR_ID), anyInt(),
- eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED), eq(0));
- verify(callback1).onClientFinished(eq(client1), eq(true) /* success */);
+ eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE), eq(0));
+ verify(callback1).onClientFinished(eq(client1), eq(false) /* success */);
verify(callback1, never()).onClientStarted(any());
// Client 2 was able to start
@@ -310,6 +312,37 @@ public class BiometricSchedulerTest {
assertNull(mScheduler.getCurrentClient());
}
+ @Test
+ public void testInterruptPrecedingClients_whenExpected() {
+ final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class,
+ withSettings().extraInterfaces(Interruptable.class));
+
+ final BaseClientMonitor interrupter = mock(BaseClientMonitor.class);
+ when(interrupter.interruptsPrecedingClients()).thenReturn(true);
+
+ mScheduler.scheduleClientMonitor(interruptableMonitor);
+ mScheduler.scheduleClientMonitor(interrupter);
+ waitForIdle();
+
+ verify((Interruptable) interruptableMonitor).cancel();
+ mScheduler.getInternalCallback().onClientFinished(interruptableMonitor, true /* success */);
+ }
+
+ @Test
+ public void testDoesNotInterruptPrecedingClients_whenNotExpected() {
+ final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class,
+ withSettings().extraInterfaces(Interruptable.class));
+
+ final BaseClientMonitor interrupter = mock(BaseClientMonitor.class);
+ when(interrupter.interruptsPrecedingClients()).thenReturn(false);
+
+ mScheduler.scheduleClientMonitor(interruptableMonitor);
+ mScheduler.scheduleClientMonitor(interrupter);
+ waitForIdle();
+
+ verify((Interruptable) interruptableMonitor, never()).cancel();
+ }
+
private BiometricSchedulerProto getDump(boolean clearSchedulerBuffer) throws Exception {
return BiometricSchedulerProto.parseFrom(mScheduler.dumpProtoState(clearSchedulerBuffer));
}