diff options
11 files changed, 323 insertions, 6 deletions
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContext.java b/services/core/java/com/android/server/biometrics/log/BiometricContext.java index 3dcea19b6077..337745c43e80 100644 --- a/services/core/java/com/android/server/biometrics/log/BiometricContext.java +++ b/services/core/java/com/android/server/biometrics/log/BiometricContext.java @@ -84,10 +84,30 @@ public interface BiometricContext { * * @param context context that will be modified when changed * @param consumer callback when the context is modified + * + * @deprecated instead use {@link BiometricContext#subscribe(OperationContextExt, Consumer, + * Consumer, AuthenticateOptions)} + * TODO (b/294161627): Delete this API once Flags.DE_HIDL is removed. */ + @Deprecated void subscribe(@NonNull OperationContextExt context, @NonNull Consumer<OperationContext> consumer); + /** + * Subscribe to context changes and start the HAL operation. + * + * Note that this method only notifies for properties that are visible to the HAL. + * + * @param context context that will be modified when changed + * @param startHalConsumer callback to start HAL operation after subscription is done + * @param updateContextConsumer callback when the context is modified + * @param options authentication options for updating the context + */ + void subscribe(@NonNull OperationContextExt context, + @NonNull Consumer<OperationContext> startHalConsumer, + @NonNull Consumer<OperationContext> updateContextConsumer, + @Nullable AuthenticateOptions options); + /** Unsubscribe from context changes. */ void unsubscribe(@NonNull OperationContextExt context); diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java index 95a047faef07..ddcd4292b7b5 100644 --- a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java +++ b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java @@ -225,6 +225,19 @@ public final class BiometricContextProvider implements BiometricContext { } @Override + public void subscribe(@NonNull OperationContextExt context, + @NonNull Consumer<OperationContext> startHalConsumer, + @NonNull Consumer<OperationContext> updateContextConsumer, + @Nullable AuthenticateOptions options) { + mSubscribers.put(updateContext(context, context.isCrypto()), updateContextConsumer); + if (options != null) { + startHalConsumer.accept(context.toAidlContext(options)); + } else { + startHalConsumer.accept(context.toAidlContext()); + } + } + + @Override public void unsubscribe(@NonNull OperationContextExt context) { mSubscribers.remove(context); } diff --git a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java index b4e0dff615f5..9c86cecd6331 100644 --- a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java +++ b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java @@ -87,6 +87,24 @@ public class OperationContextExt { * @return the underlying AIDL context */ @NonNull + public OperationContext toAidlContext(@NonNull AuthenticateOptions options) { + if (options instanceof FaceAuthenticateOptions) { + return toAidlContext((FaceAuthenticateOptions) options); + } + if (options instanceof FingerprintAuthenticateOptions) { + return toAidlContext((FingerprintAuthenticateOptions) options); + } + throw new IllegalStateException("Authenticate options are invalid."); + } + + /** + * Gets the subset of the context that can be shared with the HAL and updates + * it with the given options. + * + * @param options authenticate options + * @return the underlying AIDL context + */ + @NonNull public OperationContext toAidlContext(@NonNull FaceAuthenticateOptions options) { mAidlContext.authenticateReason = AuthenticateReason .faceAuthenticateReason(getAuthReason(options)); diff --git a/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java index 03658ce21fc2..139b745daef2 100644 --- a/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java +++ b/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.content.Context; import android.os.IBinder; +import com.android.server.biometrics.Flags; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; import com.android.server.biometrics.log.OperationContextExt; @@ -91,6 +92,9 @@ public abstract class HalClientMonitor<T> extends BaseClientMonitor { } protected OperationContextExt getOperationContext() { + if (Flags.deHidl()) { + return mOperationContext; + } return getBiometricContext().updateContext(mOperationContext, isCryptoOperation()); } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java index 470dc4b7172c..22e399c6747b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java @@ -37,6 +37,7 @@ import android.util.Slog; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.biometrics.Flags; import com.android.server.biometrics.Utils; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; @@ -153,7 +154,11 @@ public class FaceAuthenticationClient 0 /* vendorCode */); mCallback.onClientFinished(this, false /* success */); } else { - mCancellationSignal = doAuthenticate(); + if (Flags.deHidl()) { + startAuthenticate(); + } else { + mCancellationSignal = doAuthenticate(); + } } } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting auth", e); @@ -182,6 +187,33 @@ public class FaceAuthenticationClient } } + private void startAuthenticate() throws RemoteException { + final AidlSession session = getFreshDaemon(); + + if (session.hasContextMethods()) { + final OperationContextExt opContext = getOperationContext(); + getBiometricContext().subscribe(opContext, ctx -> { + try { + mCancellationSignal = session.getSession().authenticateWithContext( + mOperationId, ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when requesting auth", e); + onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, + 0 /* vendorCode */); + mCallback.onClientFinished(this, false /* success */); + } + }, ctx -> { + try { + session.getSession().onContextChanged(ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify context changed", e); + } + }, getOptions()); + } else { + mCancellationSignal = session.getSession().authenticate(mOperationId); + } + } + @Override protected void stopHalOperation() { unsubscribeBiometricContext(); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java index a529fb9779a7..5ddddda4e201 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java @@ -29,6 +29,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.biometrics.BiometricsProto; +import com.android.server.biometrics.Flags; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; import com.android.server.biometrics.log.OperationContextExt; @@ -111,7 +112,11 @@ public class FaceDetectClient extends AcquisitionClient<AidlSession> implements } try { - mCancellationSignal = doDetectInteraction(); + if (Flags.deHidl()) { + startDetect(); + } else { + mCancellationSignal = doDetectInteraction(); + } } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting face detect", e); mCallback.onClientFinished(this, false /* success */); @@ -138,6 +143,30 @@ public class FaceDetectClient extends AcquisitionClient<AidlSession> implements } } + private void startDetect() throws RemoteException { + final AidlSession session = getFreshDaemon(); + + if (session.hasContextMethods()) { + final OperationContextExt opContext = getOperationContext(); + getBiometricContext().subscribe(opContext, ctx -> { + try { + mCancellationSignal = session.getSession().detectInteractionWithContext(ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when requesting face detect", e); + mCallback.onClientFinished(this, false /* success */); + } + }, ctx -> { + try { + session.getSession().onContextChanged(ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify context changed", e); + } + }, mOptions); + } else { + mCancellationSignal = session.getSession().detectInteraction(); + } + } + @Override public void onInteractionDetected() { vibrateSuccess(); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java index 0af6e40434ef..f5c452992674 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java @@ -36,6 +36,7 @@ import android.util.Slog; import android.view.Surface; import com.android.internal.R; +import com.android.server.biometrics.Flags; import com.android.server.biometrics.HardwareAuthTokenUtils; import com.android.server.biometrics.Utils; import com.android.server.biometrics.log.BiometricContext; @@ -187,7 +188,11 @@ public class FaceEnrollClient extends EnrollClient<AidlSession> { features[i] = featureList.get(i); } - mCancellationSignal = doEnroll(features); + if (Flags.deHidl()) { + startEnroll(features); + } else { + mCancellationSignal = doEnroll(features); + } } catch (RemoteException | IllegalArgumentException e) { Slog.e(TAG, "Exception when requesting enroll", e); onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */); @@ -231,6 +236,48 @@ public class FaceEnrollClient extends EnrollClient<AidlSession> { } } + private void startEnroll(byte[] features) throws RemoteException { + final AidlSession session = getFreshDaemon(); + final HardwareAuthToken hat = + HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken); + + if (session.hasContextMethods()) { + final OperationContextExt opContext = getOperationContext(); + getBiometricContext().subscribe(opContext, ctx -> { + try { + if (session.supportsFaceEnrollOptions()) { + FaceEnrollOptions options = new FaceEnrollOptions(); + options.hardwareAuthToken = hat; + options.enrollmentType = EnrollmentType.DEFAULT; + options.features = features; + options.nativeHandlePreview = null; + options.context = ctx; + options.surfacePreview = mPreviewSurface; + mCancellationSignal = session.getSession().enrollWithOptions(options); + } else { + mCancellationSignal = session.getSession().enrollWithContext( + hat, EnrollmentType.DEFAULT, features, mHwPreviewHandle, ctx); + } + } catch (RemoteException e) { + Slog.e(TAG, "Exception when requesting enroll", e); + onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, + 0 /* vendorCode */); + mCallback.onClientFinished(this, false /* success */); + } + }, ctx -> { + try { + session.getSession().onContextChanged(ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify context changed", e); + } + }, null /* options */); + } else { + mCancellationSignal = session.getSession().enroll(hat, EnrollmentType.DEFAULT, features, + mHwPreviewHandle); + } + } + + @Override protected void stopHalOperation() { unsubscribeBiometricContext(); 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 29c5a3de3a80..2755ab50debb 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 @@ -43,6 +43,7 @@ import android.provider.Settings; import android.util.Slog; import com.android.internal.R; +import com.android.server.biometrics.Flags; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; import com.android.server.biometrics.log.CallbackWithProbe; @@ -296,7 +297,11 @@ public class FingerprintAuthenticationClient } try { - mCancellationSignal = doAuthenticate(); + if (Flags.deHidl()) { + startAuthentication(); + } else { + mCancellationSignal = doAuthenticate(); + } } catch (RemoteException e) { Slog.e(TAG, "Remote exception", e); onError( @@ -346,6 +351,51 @@ public class FingerprintAuthenticationClient return cancel; } + private void startAuthentication() { + final AidlSession session = getFreshDaemon(); + final OperationContextExt opContext = getOperationContext(); + + getBiometricContext().subscribe(opContext, ctx -> { + try { + if (session.hasContextMethods()) { + mCancellationSignal = session.getSession().authenticateWithContext(mOperationId, + ctx); + } else { + mCancellationSignal = session.getSession().authenticate(mOperationId); + } + + if (getBiometricContext().isAwake()) { + mALSProbeCallback.getProbe().enable(); + } + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + onError( + BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE, + 0 /* vendorCode */); + mSensorOverlays.hide(getSensorId()); + if (sidefpsControllerRefactor()) { + mAuthenticationStateListeners.onAuthenticationStopped(); + } + mCallback.onClientFinished(this, false /* success */); + } + }, ctx -> { + if (session.hasContextMethods()) { + try { + session.getSession().onContextChanged(ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify context changed", e); + } + } + + final boolean isAwake = getBiometricContext().isAwake(); + if (isAwake) { + mALSProbeCallback.getProbe().enable(); + } else { + mALSProbeCallback.getProbe().disable(); + } + }, getOptions()); + } + @Override protected void stopHalOperation() { mSensorOverlays.hide(getSensorId()); 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 e58e5ae117b5..e9a1c23c148e 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 @@ -30,6 +30,7 @@ import android.os.RemoteException; import android.util.Slog; import com.android.server.biometrics.BiometricsProto; +import com.android.server.biometrics.Flags; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; import com.android.server.biometrics.log.OperationContextExt; @@ -104,7 +105,11 @@ public class FingerprintDetectClient extends AcquisitionClient<AidlSession> this); try { - mCancellationSignal = doDetectInteraction(); + if (Flags.deHidl()) { + startDetectInteraction(); + } else { + mCancellationSignal = doDetectInteraction(); + } } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting finger detect", e); mSensorOverlays.hide(getSensorId()); @@ -132,6 +137,32 @@ public class FingerprintDetectClient extends AcquisitionClient<AidlSession> } } + private void startDetectInteraction() throws RemoteException { + final AidlSession session = getFreshDaemon(); + + if (session.hasContextMethods()) { + final OperationContextExt opContext = getOperationContext(); + getBiometricContext().subscribe(opContext, ctx -> { + try { + mCancellationSignal = session.getSession().detectInteractionWithContext( + ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to start detect interaction", e); + mSensorOverlays.hide(getSensorId()); + mCallback.onClientFinished(this, false /* success */); + } + }, ctx -> { + try { + session.getSession().onContextChanged(ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify context changed", e); + } + }, mOptions); + } else { + mCancellationSignal = session.getSession().detectInteraction(); + } + } + @Override public void onInteractionDetected() { vibrateSuccess(); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java index c0761ed8f32b..9d0c67b8f911 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java @@ -38,6 +38,7 @@ import android.os.RemoteException; import android.util.Slog; import android.view.accessibility.AccessibilityManager; +import com.android.server.biometrics.Flags; import com.android.server.biometrics.HardwareAuthTokenUtils; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; @@ -199,7 +200,11 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement BiometricNotificationUtils.cancelBadCalibrationNotification(getContext()); try { - mCancellationSignal = doEnroll(); + if (Flags.deHidl()) { + startEnroll(); + } else { + mCancellationSignal = doEnroll(); + } } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting enroll", e); onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_UNABLE_TO_PROCESS, @@ -230,6 +235,35 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement } } + private void startEnroll() throws RemoteException { + final AidlSession session = getFreshDaemon(); + final HardwareAuthToken hat = + HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken); + + if (session.hasContextMethods()) { + final OperationContextExt opContext = getOperationContext(); + getBiometricContext().subscribe(opContext, ctx -> { + try { + mCancellationSignal = session.getSession().enrollWithContext( + hat, ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when requesting enroll", e); + onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_UNABLE_TO_PROCESS, + 0 /* vendorCode */); + mCallback.onClientFinished(this, false /* success */); + } + }, ctx -> { + try { + session.getSession().onContextChanged(ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify context changed", e); + } + }, null /* options */); + } else { + mCancellationSignal = session.getSession().enroll(hat); + } + } + @Override protected void stopHalOperation() { mSensorOverlays.hide(getSensorId()); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java index 1b9e6fb6e247..1c35f08a9ffe 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java @@ -20,6 +20,7 @@ import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.mock; @@ -33,11 +34,15 @@ import android.content.Intent; import android.hardware.biometrics.AuthenticateOptions; import android.hardware.biometrics.IBiometricContextListener; import android.hardware.biometrics.IBiometricContextListener.FoldState; +import android.hardware.biometrics.common.DisplayState; import android.hardware.biometrics.common.OperationContext; import android.hardware.biometrics.common.OperationReason; import android.hardware.display.DisplayManagerGlobal; +import android.hardware.fingerprint.FingerprintAuthenticateOptions; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.testing.TestableContext; import android.view.Display; import android.view.DisplayInfo; @@ -72,6 +77,9 @@ public class BiometricContextProviderTest { @Rule public TestableContext mContext = new TestableContext( InstrumentationRegistry.getInstrumentation().getContext()); + @Rule + public final CheckFlagsRule mCheckFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule(); @Mock private IStatusBarService mStatusBarService; @@ -386,6 +394,37 @@ public class BiometricContextProviderTest { } } + @Test + public void testSubscribe_thenStartHal() throws RemoteException { + Consumer<OperationContext> updateConsumer = mock(Consumer.class); + Consumer<OperationContext> startHalConsumer = mock(Consumer.class); + AuthenticateOptions options = new FingerprintAuthenticateOptions.Builder().build(); + OperationContextExt context = mProvider.updateContext(mOpContext, false /* crypto */); + + assertThat(context.getDisplayState()).isEqualTo(DisplayState.UNKNOWN); + assertThat(context.getFoldState()).isEqualTo(IBiometricContextListener.FoldState.UNKNOWN); + + mListener.onDisplayStateChanged(DisplayState.LOCKSCREEN); + mListener.onFoldChanged(FoldState.FULLY_CLOSED); + mProvider.subscribe(context, startHalConsumer, updateConsumer, options); + + assertThat(context.getDisplayState()).isEqualTo(DisplayState.LOCKSCREEN); + assertThat(context.getFoldState()).isEqualTo(FoldState.FULLY_CLOSED); + verify(updateConsumer, never()).accept(context.toAidlContext()); + verify(startHalConsumer).accept(context.toAidlContext(options)); + } + + @Test + public void testSubscribe_withInvalidOptions() { + Consumer<OperationContext> updateConsumer = mock(Consumer.class); + Consumer<OperationContext> startHalConsumer = mock(Consumer.class); + AuthenticateOptions options = mock(AuthenticateOptions.class); + OperationContextExt context = mProvider.updateContext(mOpContext, false /* crypto */); + + assertThrows(IllegalStateException.class, () -> mProvider.subscribe( + context, startHalConsumer, updateConsumer, options)); + } + private static byte reason(int type) { if (type == StatusBarManager.SESSION_BIOMETRIC_PROMPT) { return OperationReason.BIOMETRIC_PROMPT; |