diff options
31 files changed, 1153 insertions, 473 deletions
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java index 3b56dde69704..987d790601b4 100644 --- a/core/java/android/hardware/biometrics/BiometricManager.java +++ b/core/java/android/hardware/biometrics/BiometricManager.java @@ -208,7 +208,17 @@ public class BiometricManager { @NonNull @RequiresPermission(TEST_BIOMETRIC) public List<SensorProperties> getSensorProperties() { - return new ArrayList<>(); // TODO(169459906) + try { + final List<SensorPropertiesInternal> internalProperties = + mService.getSensorProperties(mContext.getOpPackageName()); + final List<SensorProperties> properties = new ArrayList<>(); + for (SensorPropertiesInternal internalProp : internalProperties) { + properties.add(SensorProperties.from(internalProp)); + } + return properties; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -219,7 +229,12 @@ public class BiometricManager { @NonNull @RequiresPermission(TEST_BIOMETRIC) public BiometricTestSession createTestSession(int sensorId) { - return null; // TODO(169459906) + try { + return new BiometricTestSession(mContext, + mService.createTestSession(sensorId, mContext.getOpPackageName())); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl index b44327678ad4..8e7f5ce8a85d 100644 --- a/core/java/android/hardware/biometrics/IAuthService.aidl +++ b/core/java/android/hardware/biometrics/IAuthService.aidl @@ -18,7 +18,9 @@ package android.hardware.biometrics; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricServiceReceiver; +import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.PromptInfo; +import android.hardware.biometrics.SensorPropertiesInternal; /** * Communication channel from BiometricPrompt and BiometricManager to AuthService. The @@ -28,6 +30,12 @@ import android.hardware.biometrics.PromptInfo; * @hide */ interface IAuthService { + // Creates a test session with the specified sensorId + ITestSession createTestSession(int sensorId, String opPackageName); + + // Retrieve static sensor properties for all biometric sensors + List<SensorPropertiesInternal> getSensorProperties(String opPackageName); + // Retrieve the package where BIometricOrompt's UI is implemented String getUiPackage(); diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl index 5e6fe6885f9d..cb43943f4864 100644 --- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl +++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl @@ -18,6 +18,8 @@ package android.hardware.biometrics; import android.hardware.biometrics.IBiometricSensorReceiver; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; +import android.hardware.biometrics.ITestSession; +import android.hardware.biometrics.SensorPropertiesInternal; import android.hardware.face.IFaceServiceReceiver; import android.hardware.face.Face; @@ -28,6 +30,15 @@ import android.hardware.face.Face; */ interface IBiometricAuthenticator { + // Creates a test session + ITestSession createTestSession(String opPackageName); + + // Retrieve static sensor properties + SensorPropertiesInternal getSensorProperties(String opPackageName); + + // Requests a proto dump of the service. See biometrics.proto + byte[] dumpSensorServiceStateProto(); + // This method prepares the service to start authenticating, but doesn't start authentication. // This is protected by the MANAGE_BIOMETRIC signature permission. This method should only be // called from BiometricService. The additional uid, pid, userId arguments should be determined @@ -35,14 +46,13 @@ interface IBiometricAuthenticator { // startPreparedClient(). void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, int callingUid, int callingPid, int callingUserId); + int cookie); // Starts authentication with the previously prepared client. void startPreparedClient(int cookie); // Cancels authentication. - void cancelAuthenticationFromService(IBinder token, String opPackageName, - int callingUid, int callingPid, int callingUserId); + void cancelAuthenticationFromService(IBinder token, String opPackageName); // Determine if HAL is loaded and ready boolean isHardwareDetected(String opPackageName); diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl index 005ed324da77..6f7bcb68cc8d 100644 --- a/core/java/android/hardware/biometrics/IBiometricService.aidl +++ b/core/java/android/hardware/biometrics/IBiometricService.aidl @@ -19,22 +19,28 @@ package android.hardware.biometrics; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.IBiometricAuthenticator; +import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.PromptInfo; +import android.hardware.biometrics.SensorPropertiesInternal; /** * Communication channel from AuthService to BiometricService. * @hide */ interface IBiometricService { + // Creates a test session with the specified sensorId + ITestSession createTestSession(int sensorId, String opPackageName); + + // Retrieve static sensor properties for all biometric sensors + List<SensorPropertiesInternal> getSensorProperties(String opPackageName); + // Requests authentication. The service choose the appropriate biometric to use, and show // the corresponding BiometricDialog. void authenticate(IBinder token, long operationId, int userId, - IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo, - int callingUid, int callingPid, int callingUserId); + IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo); // Cancel authentication for the given session. - void cancelAuthentication(IBinder token, String opPackageName, int callingUid, int callingPid, - int callingUserId); + void cancelAuthentication(IBinder token, String opPackageName); // Checks if biometrics can be used. int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators); diff --git a/core/java/android/hardware/biometrics/SensorProperties.java b/core/java/android/hardware/biometrics/SensorProperties.java index 5b1b5e612c73..360f138815c0 100644 --- a/core/java/android/hardware/biometrics/SensorProperties.java +++ b/core/java/android/hardware/biometrics/SensorProperties.java @@ -81,4 +81,12 @@ public class SensorProperties { public int getSensorStrength() { return mSensorStrength; } + + /** + * Constructs a {@link SensorProperties} from the internal parcelable representation. + * @hide + */ + public static SensorProperties from(SensorPropertiesInternal internalProp) { + return new SensorProperties(internalProp.sensorId, internalProp.sensorStrength); + } } diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index 27cdda7b0723..c5c51e4661c5 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -17,6 +17,7 @@ package android.hardware.face; import android.hardware.biometrics.IBiometricSensorReceiver; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; +import android.hardware.biometrics.ITestSession; import android.hardware.face.IFaceServiceReceiver; import android.hardware.face.Face; import android.hardware.face.FaceSensorPropertiesInternal; @@ -28,9 +29,19 @@ import android.view.Surface; * @hide */ interface IFaceService { + + // Creates a test session with the specified sensorId + ITestSession createTestSession(int sensorId, String opPackageName); + + // Requests a proto dump of the service to the specified fd + byte[] dumpSensorServiceStateProto(); + // Retrieve static sensor properties for all face sensors List<FaceSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName); + // Retrieve static sensor properties for the specified sensor + FaceSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName); + // Authenticate the given sessionId with a face void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver, String opPackageName); @@ -46,7 +57,7 @@ interface IFaceService { // startPreparedClient(). void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, int callingUid, int callingPid, int callingUserId); + int cookie); // Starts authentication with the previously prepared client. void startPreparedClient(int sensorId, int cookie); @@ -58,8 +69,7 @@ interface IFaceService { void cancelFaceDetect(IBinder token, String opPackageName); // Same as above, with extra arguments. - void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, - int callingUid, int callingPid, int callingUserId); + void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName); // Start face enrollment void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver, diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 2128d67f80ae..9248b08f260d 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -34,9 +34,15 @@ interface IFingerprintService { // Creates a test session with the specified sensorId ITestSession createTestSession(int sensorId, String opPackageName); + // Requests a proto dump of the service to the specified fd + byte[] dumpSensorServiceStateProto(); + // Retrieve static sensor properties for all fingerprint sensors List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName); + // Retrieve static sensor properties for the specified sensor + FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName); + // Authenticate the given sessionId with a fingerprint. This is protected by // USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes // through FingerprintManager now. @@ -54,8 +60,7 @@ interface IFingerprintService { // by BiometricService. To start authentication after the clients are ready, use // startPreparedClient(). void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId, - IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie, - int callingUid, int callingPid, int callingUserId); + IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie); // Starts authentication with the previously prepared client. void startPreparedClient(int sensorId, int cookie); @@ -68,8 +73,7 @@ interface IFingerprintService { // Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes // an additional uid, pid, userid. - void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, - int callingUid, int callingPid, int callingUserId); + void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName); // Start fingerprint enrollment void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver, diff --git a/core/proto/android/server/biometrics.proto b/core/proto/android/server/biometrics.proto new file mode 100644 index 000000000000..632c1e5d419e --- /dev/null +++ b/core/proto/android/server/biometrics.proto @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; +package com.android.server.biometrics; + +import "frameworks/base/core/proto/android/privacy.proto"; + +option java_multiple_files = true; +option java_outer_classname = "BiometricsProto"; + +// Overall state of BiometricService (and not <Biometric>Service), including any +// <Biomteric>Service(s), for example FingerprintService or FaceService. +message BiometricServiceStateProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + enum AuthSessionState { + /** + * Authentication either just called and we have not transitioned to the CALLED state, or + * authentication terminated (success or error). + */ + STATE_AUTH_IDLE = 0; + + /** + * Authentication was called and we are waiting for the <Biometric>Services to return their + * cookies before starting the hardware and showing the BiometricPrompt. + */ + STATE_AUTH_CALLED = 1; + + /** + * Authentication started, BiometricPrompt is showing and the hardware is authenticating. + */ + STATE_AUTH_STARTED = 2; + + /** + * Same as {@link #STATE_AUTH_STARTED}, except the BiometricPrompt UI is done animating in. + */ + STATE_AUTH_STARTED_UI_SHOWING = 3; + + /** + * Authentication is paused, waiting for the user to press "try again" button. Only + * passive modalities such as Face or Iris should have this state. Note that for passive + * modalities, the HAL enters the idle state after onAuthenticated(false) which differs from + * fingerprint. + */ + STATE_AUTH_PAUSED = 4; + + /** + * Paused, but "try again" was pressed. Sensors have new cookies and we're now waiting for + * all cookies to be returned. + */ + STATE_AUTH_PAUSED_RESUMING = 5; + + /** + * Authentication is successful, but we're waiting for the user to press "confirm" button. + */ + STATE_AUTH_PENDING_CONFIRM = 6; + + /** + * Biometric authenticated, waiting for SysUI to finish animation + */ + STATE_AUTHENTICATED_PENDING_SYSUI = 7; + + /** + * Biometric error, waiting for SysUI to finish animation + */ + STATE_ERROR_PENDING_SYSUI = 8; + + /** + * Device credential in AuthController is showing + */ + STATE_SHOWING_DEVICE_CREDENTIAL = 9; + + /** + * The client binder died, and sensors were authenticating at the time. Cancel has been + * requested and we're waiting for the HAL(s) to send ERROR_CANCELED. + */ + STATE_CLIENT_DIED_CANCELLING = 10; + } + + repeated SensorServiceStateProto sensor_service_states = 1; + + optional AuthSessionState auth_session_state = 2; +} + +// Overall state for an instance of a <Biometric>Service, for example FingerprintService or +// FaceService. Note that a single service may provide multiple sensors. +message SensorServiceStateProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + repeated SensorStateProto sensor_states = 1; +} + +// State of a single sensor. +message SensorStateProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + // Unique sensorId + optional int32 sensor_id = 1; + + // State of the sensor's scheduler. True if currently handling an operation, false if idle. + optional bool is_busy = 2; + + // User states for this sensor. + repeated UserStateProto user_states = 3; +} + +// State of a specific user for a specific sensor. +message UserStateProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + // Android user ID + optional int32 user_id = 1; + + // Number of fingerprints enrolled + optional int32 num_enrolled = 2; +}
\ No newline at end of file diff --git a/core/proto/android/server/fingerprint.proto b/core/proto/android/server/fingerprint.proto index a49a1adcc619..e6b2df5d12ec 100644 --- a/core/proto/android/server/fingerprint.proto +++ b/core/proto/android/server/fingerprint.proto @@ -65,37 +65,4 @@ message PerformanceStatsProto { // Total number of permanent lockouts. optional int32 permanent_lockout = 5; -} - -// Internal FingerprintService states. The above messages (FingerprintServiceDumpProto, etc) -// are used for legacy metrics and should not be modified. -message FingerprintServiceStateProto { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - repeated SensorStateProto sensor_states = 1; -} - -// State of a single sensor. -message SensorStateProto { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - // Unique sensorId - optional int32 sensor_id = 1; - - // State of the sensor's scheduler. True if currently handling an operation, false if idle. - optional bool is_busy = 2; - - // User states for this sensor. - repeated UserStateProto user_states = 3; -} - -// State of a specific user for a specific sensor. -message UserStateProto { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - // Android user ID - optional int32 user_id = 1; - - // Number of fingerprints enrolled - optional int32 num_enrolled = 2; }
\ No newline at end of file diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java index 27b39c69758f..cf8bfbc547f8 100644 --- a/services/core/java/com/android/server/biometrics/AuthService.java +++ b/services/core/java/com/android/server/biometrics/AuthService.java @@ -29,6 +29,7 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRIN import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS; import static android.hardware.biometrics.BiometricManager.Authenticators; +import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; @@ -37,7 +38,9 @@ import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricService; import android.hardware.biometrics.IBiometricServiceReceiver; +import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.PromptInfo; +import android.hardware.biometrics.SensorPropertiesInternal; import android.hardware.face.IFaceService; import android.hardware.fingerprint.IFingerprintService; import android.hardware.iris.IIrisService; @@ -55,6 +58,8 @@ import com.android.server.biometrics.sensors.face.FaceAuthenticator; import com.android.server.biometrics.sensors.fingerprint.FingerprintAuthenticator; import com.android.server.biometrics.sensors.iris.IrisAuthenticator; +import java.util.List; + /** * System service that provides an interface for authenticating with biometrics and * PIN/pattern/password to BiometricPrompt and lock screen. @@ -138,6 +143,34 @@ public class AuthService extends SystemService { private final class AuthServiceImpl extends IAuthService.Stub { @Override + public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) + throws RemoteException { + Utils.checkPermission(getContext(), TEST_BIOMETRIC); + + final long identity = Binder.clearCallingIdentity(); + try { + return mInjector.getBiometricService().createTestSession(sensorId, opPackageName); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public List<SensorPropertiesInternal> getSensorProperties(String opPackageName) + throws RemoteException { + Utils.checkPermission(getContext(), TEST_BIOMETRIC); + + final long identity = Binder.clearCallingIdentity(); + try { + // Get the result from BiometricService, since it is the source of truth for all + // biometric sensors. + return mInjector.getBiometricService().getSensorProperties(opPackageName); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override public String getUiPackage() { Utils.checkPermission(getContext(), TEST_BIOMETRIC); @@ -185,8 +218,7 @@ public class AuthService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { mBiometricService.authenticate( - token, sessionId, userId, receiver, opPackageName, promptInfo, callingUid, - callingPid, callingUserId); + token, sessionId, userId, receiver, opPackageName, promptInfo); } finally { Binder.restoreCallingIdentity(identity); } @@ -202,13 +234,9 @@ public class AuthService extends SystemService { return; } - final int callingUid = Binder.getCallingUid(); - final int callingPid = Binder.getCallingPid(); - final int callingUserId = UserHandle.getCallingUserId(); final long identity = Binder.clearCallingIdentity(); try { - mBiometricService.cancelAuthentication(token, opPackageName, callingUid, - callingPid, callingUserId); + mBiometricService.cancelAuthentication(token, opPackageName); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java index 637a8963402e..efc025dd7b0c 100644 --- a/services/core/java/com/android/server/biometrics/AuthSession.java +++ b/services/core/java/com/android/server/biometrics/AuthSession.java @@ -20,6 +20,8 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE; +import static com.android.server.biometrics.BiometricServiceStateProto.*; + import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -48,7 +50,6 @@ import com.android.internal.util.FrameworkStatsLog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -61,60 +62,11 @@ public final class AuthSession implements IBinder.DeathRecipient { private static final String TAG = "BiometricService/AuthSession"; private static final boolean DEBUG = false; - /** - * Authentication either just called and we have not transitioned to the CALLED state, or - * authentication terminated (success or error). - */ - static final int STATE_AUTH_IDLE = 0; - /** - * Authentication was called and we are waiting for the <Biometric>Services to return their - * cookies before starting the hardware and showing the BiometricPrompt. - */ - static final int STATE_AUTH_CALLED = 1; - /** - * Authentication started, BiometricPrompt is showing and the hardware is authenticating. At - * this point, the BiometricPrompt UI has been requested, but is not necessarily done animating - * in yet. - */ - static final int STATE_AUTH_STARTED = 2; - /** - * Same as {@link #STATE_AUTH_STARTED}, except the BiometricPrompt UI is done animating in. - */ - static final int STATE_AUTH_STARTED_UI_SHOWING = 3; - /** - * Authentication is paused, waiting for the user to press "try again" button. Only - * passive modalities such as Face or Iris should have this state. Note that for passive - * modalities, the HAL enters the idle state after onAuthenticated(false) which differs from - * fingerprint. - */ - static final int STATE_AUTH_PAUSED = 4; - /** - * Paused, but "try again" was pressed. Sensors have new cookies and we're now waiting for all - * cookies to be returned. - */ - static final int STATE_AUTH_PAUSED_RESUMING = 5; - /** - * Authentication is successful, but we're waiting for the user to press "confirm" button. - */ - static final int STATE_AUTH_PENDING_CONFIRM = 6; - /** - * Biometric authenticated, waiting for SysUI to finish animation - */ - static final int STATE_AUTHENTICATED_PENDING_SYSUI = 7; - /** - * Biometric error, waiting for SysUI to finish animation - */ - static final int STATE_ERROR_PENDING_SYSUI = 8; - /** - * Device credential in AuthController is showing - */ - static final int STATE_SHOWING_DEVICE_CREDENTIAL = 9; - /** - * The client binder died, and sensors were authenticating at the time. Cancel has been - * requested and we're waiting for the HAL(s) to send ERROR_CANCELED. - */ - static final int STATE_CLIENT_DIED_CANCELLING = 10; + + /* + * Defined in biometrics.proto + */ @IntDef({ STATE_AUTH_IDLE, STATE_AUTH_CALLED, @@ -157,9 +109,6 @@ public final class AuthSession implements IBinder.DeathRecipient { // Original receiver from BiometricPrompt. private final IBiometricServiceReceiver mClientReceiver; private final String mOpPackageName; - private final int mCallingUid; - private final int mCallingPid; - private final int mCallingUserId; private final boolean mDebugEnabled; private final List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties; @@ -191,9 +140,6 @@ public final class AuthSession implements IBinder.DeathRecipient { @NonNull IBiometricServiceReceiver clientReceiver, @NonNull String opPackageName, @NonNull PromptInfo promptInfo, - int callingUid, - int callingPid, - int callingUserId, boolean debugEnabled, @NonNull List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties) { mContext = context; @@ -210,9 +156,6 @@ public final class AuthSession implements IBinder.DeathRecipient { mClientReceiver = clientReceiver; mOpPackageName = opPackageName; mPromptInfo = promptInfo; - mCallingUid = callingUid; - mCallingPid = callingPid; - mCallingUserId = callingUserId; mDebugEnabled = debugEnabled; mFingerprintSensorProperties = fingerprintSensorProperties; @@ -254,8 +197,7 @@ public final class AuthSession implements IBinder.DeathRecipient { final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1; final boolean requireConfirmation = isConfirmationRequired(sensor); sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId, - mUserId, mSensorReceiver, mOpPackageName, cookie, mCallingUid, mCallingPid, - mCallingUserId); + mUserId, mSensorReceiver, mOpPackageName, cookie); } } @@ -264,7 +206,7 @@ public final class AuthSession implements IBinder.DeathRecipient { // Only device credential should be shown. In this case, we don't need to wait, // since LockSettingsService/Gatekeeper is always ready to check for credential. // SystemUI invokes that path. - mState = AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL; + mState = STATE_SHOWING_DEVICE_CREDENTIAL; mStatusBarService.showAuthenticationDialog( mPromptInfo, @@ -278,7 +220,7 @@ public final class AuthSession implements IBinder.DeathRecipient { } else if (!mPreAuthInfo.eligibleSensors.isEmpty()) { // Some combination of biometric or biometric|credential is requested setSensorsToStateWaitingForCookie(); - mState = AuthSession.STATE_AUTH_CALLED; + mState = STATE_AUTH_CALLED; } else { // No authenticators requested. This should never happen - an exception should have // been thrown earlier in the pipeline. @@ -386,8 +328,7 @@ public final class AuthSession implements IBinder.DeathRecipient { // sending the final error callback to the application. for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { try { - sensor.goToStateCancelling(mToken, mOpPackageName, mCallingUid, mCallingPid, - mCallingUserId); + sensor.goToStateCancelling(mToken, mOpPackageName); } catch (RemoteException e) { Slog.e(TAG, "Unable to cancel authentication"); } @@ -429,7 +370,7 @@ public final class AuthSession implements IBinder.DeathRecipient { authenticators = Utils.removeBiometricBits(authenticators); mPromptInfo.setAuthenticators(authenticators); - mState = AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL; + mState = STATE_SHOWING_DEVICE_CREDENTIAL; mStatusBarService.showAuthenticationDialog( mPromptInfo, @@ -453,7 +394,7 @@ public final class AuthSession implements IBinder.DeathRecipient { || error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT; if (isAllowDeviceCredential() && errorLockout) { // SystemUI handles transition from biometric to device credential. - mState = AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL; + mState = STATE_SHOWING_DEVICE_CREDENTIAL; mStatusBarService.onBiometricError(modality, error, vendorCode); } else if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) { mStatusBarService.hideAuthenticationDialog(); @@ -463,7 +404,7 @@ public final class AuthSession implements IBinder.DeathRecipient { mClientReceiver.onError(modality, error, vendorCode); return true; } else { - mState = AuthSession.STATE_ERROR_PENDING_SYSUI; + mState = STATE_ERROR_PENDING_SYSUI; mStatusBarService.onBiometricError(modality, error, vendorCode); } break; @@ -582,7 +523,7 @@ public final class AuthSession implements IBinder.DeathRecipient { if (hasPausableBiometric()) { // Pause authentication. onBiometricAuthenticated(false) causes the // dialog to show a "try again" button for passive modalities. - mState = AuthSession.STATE_AUTH_PAUSED; + mState = STATE_AUTH_PAUSED; } mClientReceiver.onAuthenticationFailed(); diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java index 09d058383e78..17ec11233c4e 100644 --- a/services/core/java/com/android/server/biometrics/BiometricSensor.java +++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java @@ -16,6 +16,8 @@ package com.android.server.biometrics; +import static android.hardware.biometrics.BiometricManager.Authenticators; + import android.annotation.IntDef; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricManager; @@ -61,11 +63,11 @@ public abstract class BiometricSensor { @interface SensorState {} public final int id; - public final int oemStrength; // strength as configured by the OEM + public final @Authenticators.Types int oemStrength; // strength as configured by the OEM public final int modality; public final IBiometricAuthenticator impl; - private int mUpdatedStrength; // strength updated by BiometricStrengthController + private @Authenticators.Types int mUpdatedStrength; // updated by BiometricStrengthController private @SensorState int mSensorState; private @BiometricConstants.Errors int mError; @@ -82,7 +84,7 @@ public abstract class BiometricSensor { */ abstract boolean confirmationSupported(); - BiometricSensor(int id, int modality, int strength, + BiometricSensor(int id, int modality, @Authenticators.Types int strength, IBiometricAuthenticator impl) { this.id = id; this.modality = modality; @@ -101,12 +103,11 @@ public abstract class BiometricSensor { void goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, int callingUid, int callingPid, int callingUserId) + int cookie) throws RemoteException { mCookie = cookie; impl.prepareForAuthentication(requireConfirmation, token, - sessionId, userId, sensorReceiver, opPackageName, mCookie, - callingUid, callingPid, callingUserId); + sessionId, userId, sensorReceiver, opPackageName, mCookie); mSensorState = STATE_WAITING_FOR_COOKIE; } @@ -122,10 +123,8 @@ public abstract class BiometricSensor { mSensorState = STATE_AUTHENTICATING; } - void goToStateCancelling(IBinder token, String opPackageName, int callingUid, - int callingPid, int callingUserId) throws RemoteException { - impl.cancelAuthenticationFromService(token, opPackageName, callingUid, callingPid, - callingUserId); + void goToStateCancelling(IBinder token, String opPackageName) throws RemoteException { + impl.cancelAuthenticationFromService(token, opPackageName); mSensorState = STATE_CANCELING; } @@ -143,7 +142,7 @@ public abstract class BiometricSensor { * strength. * @return a bitfield, see {@link BiometricManager.Authenticators} */ - int getCurrentStrength() { + @Authenticators.Types int getCurrentStrength() { return oemStrength | mUpdatedStrength; } @@ -160,7 +159,7 @@ public abstract class BiometricSensor { * is checked. * @param newStrength */ - void updateStrength(int newStrength) { + void updateStrength(@Authenticators.Types int newStrength) { String log = "updateStrength: Before(" + toString() + ")"; mUpdatedStrength = newStrength; log += " After(" + toString() + ")"; diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index 196582a6c0d6..a471664b19b7 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -19,6 +19,9 @@ package com.android.server.biometrics; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; import static android.hardware.biometrics.BiometricManager.Authenticators; +import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_IDLE; + +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.IActivityManager; @@ -38,7 +41,9 @@ import android.hardware.biometrics.IBiometricSensorReceiver; import android.hardware.biometrics.IBiometricService; import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.IBiometricSysuiReceiver; +import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.PromptInfo; +import android.hardware.biometrics.SensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.net.Uri; @@ -56,6 +61,7 @@ import android.security.KeyStore; import android.text.TextUtils; import android.util.Pair; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; @@ -185,10 +191,7 @@ public class BiometricService extends SystemService { args.argi1 /* userid */, (IBiometricServiceReceiver) args.arg3 /* receiver */, (String) args.arg4 /* opPackageName */, - (PromptInfo) args.arg5 /* promptInfo */, - args.argi2 /* callingUid */, - args.argi3 /* callingPid */, - args.argi4 /* callingUserId */); + (PromptInfo) args.arg5 /* promptInfo */); args.recycle(); break; } @@ -476,6 +479,34 @@ public class BiometricService extends SystemService { */ private final class BiometricServiceWrapper extends IBiometricService.Stub { @Override // Binder call + public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) + throws RemoteException { + checkInternalPermission(); + + for (BiometricSensor sensor : mSensors) { + if (sensor.id == sensorId) { + return sensor.impl.createTestSession(opPackageName); + } + } + + Slog.e(TAG, "Unknown sensor for createTestSession: " + sensorId); + return null; + } + + @Override // Binder call + public List<SensorPropertiesInternal> getSensorProperties(String opPackageName) + throws RemoteException { + checkInternalPermission(); + + final List<SensorPropertiesInternal> sensors = new ArrayList<>(); + for (BiometricSensor sensor : mSensors) { + sensors.add(sensor.impl.getSensorProperties(opPackageName)); + } + + return sensors; + } + + @Override // Binder call public void onReadyForAuthentication(int cookie) { checkInternalPermission(); @@ -486,8 +517,7 @@ public class BiometricService extends SystemService { @Override // Binder call public void authenticate(IBinder token, long operationId, int userId, - IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo, - int callingUid, int callingPid, int callingUserId) { + IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) { checkInternalPermission(); if (token == null || receiver == null || opPackageName == null || promptInfo == null) { @@ -516,16 +546,12 @@ public class BiometricService extends SystemService { args.arg3 = receiver; args.arg4 = opPackageName; args.arg5 = promptInfo; - args.argi2 = callingUid; - args.argi3 = callingPid; - args.argi4 = callingUserId; mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget(); } @Override // Binder call - public void cancelAuthentication(IBinder token, String opPackageName, - int callingUid, int callingPid, int callingUserId) { + public void cancelAuthentication(IBinder token, String opPackageName) { checkInternalPermission(); mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION).sendToTarget(); @@ -577,7 +603,7 @@ public class BiometricService extends SystemService { } @Override - public void registerAuthenticator(int id, int modality, int strength, + public void registerAuthenticator(int id, int modality, @Authenticators.Types int strength, IBiometricAuthenticator authenticator) { checkInternalPermission(); @@ -677,14 +703,28 @@ public class BiometricService extends SystemService { } @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) { return; } final long ident = Binder.clearCallingIdentity(); try { - dumpInternal(pw); + if (args.length > 0 && "--proto".equals(args[0])) { + final ProtoOutputStream proto = new ProtoOutputStream(fd); + proto.write(BiometricServiceStateProto.AUTH_SESSION_STATE, + mCurrentAuthSession != null ? mCurrentAuthSession.getState() + : STATE_AUTH_IDLE); + for (BiometricSensor sensor : mSensors) { + byte[] serviceState = sensor.impl.dumpSensorServiceStateProto(); + proto.write(BiometricServiceStateProto.SENSOR_SERVICE_STATES, serviceState); + } + proto.flush(); + } else { + dumpInternal(pw); + } + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); } finally { Binder.restoreCallingIdentity(ident); } @@ -992,8 +1032,7 @@ public class BiometricService extends SystemService { } private void handleAuthenticate(IBinder token, long operationId, int userId, - IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo, - int callingUid, int callingPid, int callingUserId) { + IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) { mHandler.post(() -> { try { @@ -1017,7 +1056,7 @@ public class BiometricService extends SystemService { } authenticateInternal(token, operationId, userId, receiver, opPackageName, - promptInfo, callingUid, callingPid, callingUserId, preAuthInfo); + promptInfo, preAuthInfo); } else { receiver.onError(preAuthStatus.first /* modality */, preAuthStatus.second /* errorCode */, @@ -1040,7 +1079,7 @@ public class BiometricService extends SystemService { */ private void authenticateInternal(IBinder token, long operationId, int userId, IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo, - int callingUid, int callingPid, int callingUserId, PreAuthInfo preAuthInfo) { + PreAuthInfo preAuthInfo) { Slog.d(TAG, "Creating authSession with authRequest: " + preAuthInfo); // No need to dismiss dialog / send error yet if we're continuing authentication, e.g. @@ -1057,8 +1096,7 @@ public class BiometricService extends SystemService { final boolean debugEnabled = mInjector.isDebugEnabled(getContext(), userId); mCurrentAuthSession = new AuthSession(getContext(), mStatusBarService, mSysuiReceiver, mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, token, operationId, userId, - mBiometricSensorReceiver, receiver, opPackageName, promptInfo, callingUid, - callingPid, callingUserId, debugEnabled, + mBiometricSensorReceiver, receiver, opPackageName, promptInfo, debugEnabled, mInjector.getFingerprintSensorProperties(getContext())); try { mCurrentAuthSession.goToInitialState(); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java index b3e6cad0e666..62c9295adda5 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java @@ -16,8 +16,11 @@ package com.android.server.biometrics.sensors.face; +import android.annotation.NonNull; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.IBiometricSensorReceiver; +import android.hardware.biometrics.ITestSession; +import android.hardware.biometrics.SensorPropertiesInternal; import android.hardware.face.IFaceService; import android.os.IBinder; import android.os.RemoteException; @@ -32,20 +35,34 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub { private final IFaceService mFaceService; private final int mSensorId; - public FaceAuthenticator(IFaceService faceService, int sensorId) - throws RemoteException { + public FaceAuthenticator(IFaceService faceService, int sensorId) throws RemoteException { mFaceService = faceService; mSensorId = sensorId; } @Override + public ITestSession createTestSession(@NonNull String opPackageName) throws RemoteException { + return mFaceService.createTestSession(mSensorId, opPackageName); + } + + @Override + public SensorPropertiesInternal getSensorProperties(@NonNull String opPackageName) + throws RemoteException { + return mFaceService.getSensorProperties(mSensorId, opPackageName); + } + + @Override + public byte[] dumpSensorServiceStateProto() throws RemoteException { + return mFaceService.dumpSensorServiceStateProto(); + } + + @Override public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, - String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId) + String opPackageName, int cookie) throws RemoteException { mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId, - userId, sensorReceiver, opPackageName, cookie, callingUid, callingPid, - callingUserId); + userId, sensorReceiver, opPackageName, cookie); } @Override @@ -54,10 +71,9 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub { } @Override - public void cancelAuthenticationFromService(IBinder token, String opPackageName, int callingUid, - int callingPid, int callingUserId) throws RemoteException { - mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName, callingUid, - callingPid, callingUserId); + public void cancelAuthenticationFromService(IBinder token, String opPackageName) + throws RemoteException { + mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java index 1e0764a275c5..4906aacd06c0 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java @@ -29,6 +29,7 @@ import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.IBiometricSensorReceiver; import android.hardware.biometrics.IBiometricService; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; +import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.face.IFace; import android.hardware.biometrics.face.SensorProps; import android.hardware.face.Face; @@ -38,8 +39,8 @@ import android.hardware.face.IFaceServiceReceiver; import android.os.Binder; import android.os.Handler; import android.os.IBinder; -import android.os.Process; import android.os.NativeHandle; +import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -140,6 +141,34 @@ public class FaceService extends SystemService implements BiometricServiceCallba * Receives the incoming binder calls from FaceManager. */ private final class FaceServiceWrapper extends IFaceService.Stub { + @Override + public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) { + Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); + + final ServiceProvider provider = getProviderForSensor(sensorId); + + if (provider == null) { + Slog.w(TAG, "Null provider for createTestSession, sensorId: " + sensorId); + return null; + } + + return provider.createTestSession(sensorId, opPackageName); + } + + @Override + public byte[] dumpSensorServiceStateProto() { + Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); + + final ProtoOutputStream proto = new ProtoOutputStream(); + for (ServiceProvider provider : mServiceProviders) { + for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) { + provider.dumpProtoState(props.sensorId, proto); + } + } + proto.flush(); + return proto.getBytes(); + } + @Override // Binder call public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal( String opPackageName) { @@ -154,6 +183,21 @@ public class FaceService extends SystemService implements BiometricServiceCallba } @Override // Binder call + public FaceSensorPropertiesInternal getSensorProperties(int sensorId, + @NonNull String opPackageName) { + Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); + + final ServiceProvider provider = getProviderForSensor(sensorId); + if (provider == null) { + Slog.w(TAG, "No matching sensor for getSensorProperties, sensorId: " + sensorId + + ", caller: " + opPackageName); + return null; + } + + return provider.getSensorProperties(sensorId); + } + + @Override // Binder call public void generateChallenge(IBinder token, int sensorId, int userId, IFaceServiceReceiver receiver, String opPackageName) { Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); @@ -270,8 +314,7 @@ public class FaceService extends SystemService implements BiometricServiceCallba @Override // Binder call public void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId, int userId, - IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie, - int callingUid, int callingPid, int callingUserId) { + IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); final ServiceProvider provider = getProviderForSensor(sensorId); @@ -326,7 +369,7 @@ public class FaceService extends SystemService implements BiometricServiceCallba @Override // Binder call public void cancelAuthenticationFromService(int sensorId, final IBinder token, - final String opPackageName, int callingUid, int callingPid, int callingUserId) { + final String opPackageName) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); final ServiceProvider provider = getProviderForSensor(sensorId); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java index e3fb750a1e14..d1578fa7bbf3 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java @@ -18,7 +18,9 @@ package com.android.server.biometrics.sensors.face; import android.annotation.NonNull; import android.annotation.Nullable; +import android.hardware.biometrics.ITestSession; import android.hardware.face.Face; +import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceServiceReceiver; import android.os.IBinder; @@ -61,6 +63,9 @@ public interface ServiceProvider { List<FaceSensorPropertiesInternal> getSensorProperties(); @NonNull + FaceSensorPropertiesInternal getSensorProperties(int sensorId); + + @NonNull List<Face> getEnrolledFaces(int sensorId, int userId); @LockoutTracker.LockoutMode @@ -110,4 +115,7 @@ public interface ServiceProvider { void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd); void dumpInternal(int sensorId, @NonNull PrintWriter pw); + + @NonNull + ITestSession createTestSession(int sensorId, @NonNull String opPackageName); } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java index 590579adbe1a..01c16fd1f4a6 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java @@ -24,6 +24,7 @@ import android.app.IActivityTaskManager; import android.app.TaskStackListener; import android.content.Context; import android.content.pm.UserInfo; +import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.face.IFace; import android.hardware.biometrics.face.SensorProps; import android.hardware.face.Face; @@ -254,6 +255,12 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { @NonNull @Override + public FaceSensorPropertiesInternal getSensorProperties(int sensorId) { + return mSensors.get(sensorId).getSensorProperties(); + } + + @NonNull + @Override public List<Face> getEnrolledFaces(int sensorId, int userId) { return FaceUtils.getInstance(sensorId).getBiometricsForUser(mContext, userId); } @@ -566,6 +573,12 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { mUsageStats.print(pw); } + @NonNull + @Override + public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) { + return null; // TODO + } + @Override public void binderDied() { Slog.e(getTag(), "HAL died"); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java new file mode 100644 index 000000000000..4c983fb5fa6c --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.biometrics.sensors.face.hidl; + +import static android.Manifest.permission.TEST_BIOMETRIC; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.ITestSession; +import android.hardware.face.Face; +import android.hardware.face.IFaceServiceReceiver; +import android.os.Binder; +import android.util.Slog; + +import com.android.server.biometrics.Utils; +import com.android.server.biometrics.sensors.face.FaceUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +public class BiometricTestSessionImpl extends ITestSession.Stub { + private static final String TAG = "BiometricTestSessionImpl"; + + @NonNull private final Context mContext; + private final int mSensorId; + @NonNull private final Face10 mFace10; + @NonNull private final Face10.HalResultController mHalResultController; + @NonNull private final Set<Integer> mEnrollmentIds; + @NonNull private final Random mRandom; + + private final IFaceServiceReceiver mReceiver = new IFaceServiceReceiver.Stub() { + @Override + public void onEnrollResult(Face face, int remaining) { + + } + + @Override + public void onAcquired(int acquiredInfo, int vendorCode) { + + } + + @Override + public void onAuthenticationSucceeded(Face face, int userId, boolean isStrongBiometric) { + + } + + @Override + public void onFaceDetected(int sensorId, int userId, boolean isStrongBiometric) { + + } + + @Override + public void onAuthenticationFailed() { + + } + + @Override + public void onError(int error, int vendorCode) { + + } + + @Override + public void onRemoved(Face face, int remaining) { + + } + + @Override + public void onFeatureSet(boolean success, int feature) { + + } + + @Override + public void onFeatureGet(boolean success, int feature, boolean value) { + + } + + @Override + public void onChallengeGenerated(int sensorId, long challenge) { + + } + + @Override + public void onChallengeInterrupted(int sensorId) { + + } + + @Override + public void onChallengeInterruptFinished(int sensorId) { + + } + }; + + BiometricTestSessionImpl(@NonNull Context context, int sensorId, @NonNull Face10 face10, + @NonNull Face10.HalResultController halResultController) { + mContext = context; + mSensorId = sensorId; + mFace10 = face10; + mHalResultController = halResultController; + mEnrollmentIds = new HashSet<>(); + mRandom = new Random(); + } + + @Override + public void setTestHalEnabled(boolean enabled) { + Utils.checkPermission(mContext, TEST_BIOMETRIC); + + mFace10.setTestHalEnabled(enabled); + } + + @Override + public void startEnroll(int userId) { + Utils.checkPermission(mContext, TEST_BIOMETRIC); + + mFace10.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver, + mContext.getOpPackageName(), new int[0] /* disabledFeatures */, + null /* surfaceHandle */); + } + + @Override + public void finishEnroll(int userId) { + Utils.checkPermission(mContext, TEST_BIOMETRIC); + + int nextRandomId = mRandom.nextInt(); + while (mEnrollmentIds.contains(nextRandomId)) { + nextRandomId = mRandom.nextInt(); + } + + mEnrollmentIds.add(nextRandomId); + mHalResultController.onEnrollResult(0 /* deviceId */, + nextRandomId /* faceId */, userId, 0); + } + + @Override + public void acceptAuthentication(int userId) { + Utils.checkPermission(mContext, TEST_BIOMETRIC); + + // Fake authentication with any of the existing fingers + List<Face> faces = FaceUtils.getInstance().getBiometricsForUser(mContext, userId); + if (faces.isEmpty()) { + Slog.w(TAG, "No faces, returning"); + return; + } + final int fid = faces.get(0).getBiometricId(); + final ArrayList<Byte> hat = new ArrayList<>(Collections.nCopies(69, (byte) 0)); + mHalResultController.onAuthenticated(0 /* deviceId */, fid, userId, hat); + } + + @Override + public void rejectAuthentication(int userId) { + Utils.checkPermission(mContext, TEST_BIOMETRIC); + + mHalResultController.onAuthenticated(0 /* deviceId */, 0 /* faceId */, userId, null); + } + + @Override + public void notifyAcquired(int userId, int acquireInfo) { + Utils.checkPermission(mContext, TEST_BIOMETRIC); + + mHalResultController.onAcquired(0 /* deviceId */, userId, acquireInfo, 0 /* vendorCode */); + } + + @Override + public void notifyError(int userId, int errorCode) { + Utils.checkPermission(mContext, TEST_BIOMETRIC); + + mHalResultController.onError(0 /* deviceId */, userId, errorCode, 0 /* vendorCode */); + } + + @Override + public void cleanupInternalState(int userId) { + Utils.checkPermission(mContext, TEST_BIOMETRIC); + + mFace10.scheduleInternalCleanup(mSensorId, userId); + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java index 7b70bd8a8730..27ca33de415d 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java @@ -28,6 +28,7 @@ import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricFaceConstants; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.face.V1_0.IBiometricsFace; import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback; import android.hardware.face.Face; @@ -51,6 +52,9 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; +import com.android.server.biometrics.SensorServiceStateProto; +import com.android.server.biometrics.SensorStateProto; +import com.android.server.biometrics.UserStateProto; import com.android.server.biometrics.Utils; import com.android.server.biometrics.sensors.AcquisitionClient; import com.android.server.biometrics.sensors.AuthenticationConsumer; @@ -67,6 +71,7 @@ import com.android.server.biometrics.sensors.face.FaceUtils; import com.android.server.biometrics.sensors.face.LockoutHalImpl; import com.android.server.biometrics.sensors.face.ServiceProvider; import com.android.server.biometrics.sensors.face.UsageStats; +import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils; import org.json.JSONArray; import org.json.JSONException; @@ -93,6 +98,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { static final String NOTIFICATION_TAG = "FaceService"; static final int NOTIFICATION_ID = 1; + private boolean mTestHalEnabled; + @NonNull private final FaceSensorPropertiesInternal mSensorProperties; @NonNull private final Context mContext; @NonNull private final BiometricScheduler mScheduler; @@ -104,6 +111,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { @NonNull private final NotificationManager mNotificationManager; @NonNull private final Map<Integer, Long> mAuthenticatorIds; @Nullable private IBiometricsFace mDaemon; + @NonNull private final HalResultController mHalResultController; // If a challenge is generated, keep track of its owner. Since IBiometricsFace@1.0 only // supports a single in-flight challenge, we must notify the interrupted owner that its // challenge is no longer valid. The interrupted owner will be notified when the interrupter @@ -122,174 +130,207 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { } }; - private final IBiometricsFaceClientCallback mDaemonCallback = - new IBiometricsFaceClientCallback.Stub() { - @Override - public void onEnrollResult(long deviceId, int faceId, int userId, int remaining) { - mHandler.post(() -> { - final CharSequence name = FaceUtils.getInstance() - .getUniqueName(mContext, userId); - final Face face = new Face(name, faceId, deviceId); - - final ClientMonitor<?> client = mScheduler.getCurrentClient(); - if (!(client instanceof FaceEnrollClient)) { - Slog.e(TAG, "onEnrollResult for non-enroll client: " - + Utils.getClientName(client)); - return; - } + public static class HalResultController extends IBiometricsFaceClientCallback.Stub { + /** + * Interface to sends results to the HalResultController's owner. + */ + public interface Callback { + /** + * Invoked when the HAL sends ERROR_HW_UNAVAILABLE. + */ + void onHardwareUnavailable(); + } - final FaceEnrollClient enrollClient = (FaceEnrollClient) client; - enrollClient.onEnrollResult(face, remaining); - }); - } + private final int mSensorId; + @NonNull private final Context mContext; + @NonNull private final Handler mHandler; + @NonNull private final BiometricScheduler mScheduler; + @Nullable private Callback mCallback; + @NonNull private final LockoutHalImpl mLockoutTracker; + @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher; + + HalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler, + @NonNull BiometricScheduler scheduler, @NonNull LockoutHalImpl lockoutTracker, + @NonNull LockoutResetDispatcher lockoutResetDispatcher) { + mSensorId = sensorId; + mContext = context; + mHandler = handler; + mScheduler = scheduler; + mLockoutTracker = lockoutTracker; + mLockoutResetDispatcher = lockoutResetDispatcher; + } - @Override - public void onAuthenticated(long deviceId, int faceId, int userId, - ArrayList<Byte> token) { - mHandler.post(() -> { - final ClientMonitor<?> client = mScheduler.getCurrentClient(); - if (!(client instanceof AuthenticationConsumer)) { - Slog.e(TAG, "onAuthenticated for non-authentication consumer: " - + Utils.getClientName(client)); - return; - } + public void setCallback(@Nullable Callback callback) { + mCallback = callback; + } - final AuthenticationConsumer authenticationConsumer = - (AuthenticationConsumer) client; - final boolean authenticated = faceId != 0; - final Face face = new Face("", faceId, deviceId); - authenticationConsumer.onAuthenticated(face, authenticated, token); - }); + @Override + public void onEnrollResult(long deviceId, int faceId, int userId, int remaining) { + mHandler.post(() -> { + final CharSequence name = FaceUtils.getInstance() + .getUniqueName(mContext, userId); + final Face face = new Face(name, faceId, deviceId); + + final ClientMonitor<?> client = mScheduler.getCurrentClient(); + if (!(client instanceof FaceEnrollClient)) { + Slog.e(TAG, "onEnrollResult for non-enroll client: " + + Utils.getClientName(client)); + return; } - @Override - public void onAcquired(long deviceId, int userId, int acquiredInfo, - int vendorCode) { - mHandler.post(() -> { - final ClientMonitor<?> client = mScheduler.getCurrentClient(); - if (!(client instanceof AcquisitionClient)) { - Slog.e(TAG, "onAcquired for non-acquire client: " - + Utils.getClientName(client)); - return; - } + final FaceEnrollClient enrollClient = (FaceEnrollClient) client; + enrollClient.onEnrollResult(face, remaining); + }); + } - final AcquisitionClient<?> acquisitionClient = - (AcquisitionClient<?>) client; - acquisitionClient.onAcquired(acquiredInfo, vendorCode); - }); + @Override + public void onAuthenticated(long deviceId, int faceId, int userId, + ArrayList<Byte> token) { + mHandler.post(() -> { + final ClientMonitor<?> client = mScheduler.getCurrentClient(); + if (!(client instanceof AuthenticationConsumer)) { + Slog.e(TAG, "onAuthenticated for non-authentication consumer: " + + Utils.getClientName(client)); + return; } - @Override - public void onError(long deviceId, int userId, int error, int vendorCode) { - mHandler.post(() -> { - final ClientMonitor<?> client = mScheduler.getCurrentClient(); - Slog.d(TAG, "handleError" - + ", client: " + (client != null ? client.getOwnerString() : null) - + ", error: " + error - + ", vendorCode: " + vendorCode); - if (!(client instanceof Interruptable)) { - Slog.e(TAG, "onError for non-error consumer: " + Utils.getClientName( - client)); - return; - } + final AuthenticationConsumer authenticationConsumer = + (AuthenticationConsumer) client; + final boolean authenticated = faceId != 0; + final Face face = new Face("", faceId, deviceId); + authenticationConsumer.onAuthenticated(face, authenticated, token); + }); + } + + @Override + public void onAcquired(long deviceId, int userId, int acquiredInfo, + int vendorCode) { + mHandler.post(() -> { + final ClientMonitor<?> client = mScheduler.getCurrentClient(); + if (!(client instanceof AcquisitionClient)) { + Slog.e(TAG, "onAcquired for non-acquire client: " + + Utils.getClientName(client)); + return; + } - final Interruptable interruptable = (Interruptable) client; - interruptable.onError(error, vendorCode); + final AcquisitionClient<?> acquisitionClient = + (AcquisitionClient<?>) client; + acquisitionClient.onAcquired(acquiredInfo, vendorCode); + }); + } - if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) { - Slog.e(TAG, "Got ERROR_HW_UNAVAILABLE"); - mDaemon = null; - mCurrentUserId = UserHandle.USER_NULL; - } - }); + @Override + public void onError(long deviceId, int userId, int error, int vendorCode) { + mHandler.post(() -> { + final ClientMonitor<?> client = mScheduler.getCurrentClient(); + Slog.d(TAG, "handleError" + + ", client: " + (client != null ? client.getOwnerString() : null) + + ", error: " + error + + ", vendorCode: " + vendorCode); + if (!(client instanceof Interruptable)) { + Slog.e(TAG, "onError for non-error consumer: " + Utils.getClientName( + client)); + return; } - @Override - public void onRemoved(long deviceId, ArrayList<Integer> removed, int userId) { - mHandler.post(() -> { - final ClientMonitor<?> client = mScheduler.getCurrentClient(); - if (!(client instanceof RemovalConsumer)) { - Slog.e(TAG, "onRemoved for non-removal consumer: " - + Utils.getClientName(client)); - return; - } + final Interruptable interruptable = (Interruptable) client; + interruptable.onError(error, vendorCode); - final RemovalConsumer removalConsumer = (RemovalConsumer) client; - - if (!removed.isEmpty()) { - // Convert to old fingerprint-like behavior, where remove() receives - // one removal - // at a time. This way, remove can share some more common code. - for (int i = 0; i < removed.size(); i++) { - final int id = removed.get(i); - final Face face = new Face("", id, deviceId); - final int remaining = removed.size() - i - 1; - Slog.d(TAG, "Removed, faceId: " + id + ", remaining: " + remaining); - removalConsumer.onRemoved(face, remaining); - } - } else { - removalConsumer.onRemoved(null, 0 /* remaining */); - } + if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) { + Slog.e(TAG, "Got ERROR_HW_UNAVAILABLE"); + if (mCallback != null) { + mCallback.onHardwareUnavailable(); + } + } + }); + } - Settings.Secure.putIntForUser(mContext.getContentResolver(), - Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT); - }); + @Override + public void onRemoved(long deviceId, ArrayList<Integer> removed, int userId) { + mHandler.post(() -> { + final ClientMonitor<?> client = mScheduler.getCurrentClient(); + if (!(client instanceof RemovalConsumer)) { + Slog.e(TAG, "onRemoved for non-removal consumer: " + + Utils.getClientName(client)); + return; } - @Override - public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId) { - mHandler.post(() -> { - final ClientMonitor<?> client = mScheduler.getCurrentClient(); - if (!(client instanceof EnumerateConsumer)) { - Slog.e(TAG, "onEnumerate for non-enumerate consumer: " - + Utils.getClientName(client)); - return; - } + final RemovalConsumer removalConsumer = (RemovalConsumer) client; + + if (!removed.isEmpty()) { + // Convert to old fingerprint-like behavior, where remove() receives + // one removal + // at a time. This way, remove can share some more common code. + for (int i = 0; i < removed.size(); i++) { + final int id = removed.get(i); + final Face face = new Face("", id, deviceId); + final int remaining = removed.size() - i - 1; + Slog.d(TAG, "Removed, faceId: " + id + ", remaining: " + remaining); + removalConsumer.onRemoved(face, remaining); + } + } else { + removalConsumer.onRemoved(null, 0 /* remaining */); + } - final EnumerateConsumer enumerateConsumer = (EnumerateConsumer) client; + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT); + }); + } - if (!faceIds.isEmpty()) { - // Convert to old fingerprint-like behavior, where enumerate() - // receives one - // template at a time. This way, enumerate can share some more common - // code. - for (int i = 0; i < faceIds.size(); i++) { - final Face face = new Face("", faceIds.get(i), deviceId); - enumerateConsumer.onEnumerationResult(face, faceIds.size() - i - 1); - } - } else { - // For face, the HIDL contract is to receive an empty list when there - // are no - // templates enrolled. Send a null identifier since we don't consume - // them - // anywhere, and send remaining == 0 so this code can be shared with - // Fingerprint@2.1 - enumerateConsumer.onEnumerationResult(null /* identifier */, 0); - } - }); + @Override + public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId) { + mHandler.post(() -> { + final ClientMonitor<?> client = mScheduler.getCurrentClient(); + if (!(client instanceof EnumerateConsumer)) { + Slog.e(TAG, "onEnumerate for non-enumerate consumer: " + + Utils.getClientName(client)); + return; } - @Override - public void onLockoutChanged(long duration) { - mHandler.post(() -> { - Slog.d(TAG, "onLockoutChanged: " + duration); - final @LockoutTracker.LockoutMode int lockoutMode; - if (duration == 0) { - lockoutMode = LockoutTracker.LOCKOUT_NONE; - } else if (duration == -1 || duration == Long.MAX_VALUE) { - lockoutMode = LockoutTracker.LOCKOUT_PERMANENT; - } else { - lockoutMode = LockoutTracker.LOCKOUT_TIMED; - } + final EnumerateConsumer enumerateConsumer = (EnumerateConsumer) client; - mLockoutTracker.setCurrentUserLockoutMode(lockoutMode); + if (!faceIds.isEmpty()) { + // Convert to old fingerprint-like behavior, where enumerate() + // receives one + // template at a time. This way, enumerate can share some more common + // code. + for (int i = 0; i < faceIds.size(); i++) { + final Face face = new Face("", faceIds.get(i), deviceId); + enumerateConsumer.onEnumerationResult(face, faceIds.size() - i - 1); + } + } else { + // For face, the HIDL contract is to receive an empty list when there + // are no + // templates enrolled. Send a null identifier since we don't consume + // them + // anywhere, and send remaining == 0 so this code can be shared with + // Fingerprint@2.1 + enumerateConsumer.onEnumerationResult(null /* identifier */, 0); + } + }); + } - if (duration == 0) { - mLockoutResetDispatcher.notifyLockoutResetCallbacks(mSensorId); - } - }); + @Override + public void onLockoutChanged(long duration) { + mHandler.post(() -> { + Slog.d(TAG, "onLockoutChanged: " + duration); + final @LockoutTracker.LockoutMode int lockoutMode; + if (duration == 0) { + lockoutMode = LockoutTracker.LOCKOUT_NONE; + } else if (duration == -1 || duration == Long.MAX_VALUE) { + lockoutMode = LockoutTracker.LOCKOUT_PERMANENT; + } else { + lockoutMode = LockoutTracker.LOCKOUT_TIMED; + } + + mLockoutTracker.setCurrentUserLockoutMode(lockoutMode); + + if (duration == 0) { + mLockoutResetDispatcher.notifyLockoutResetCallbacks(mSensorId); } - }; + }); + } + } @VisibleForTesting public Face10(@NonNull Context context, int sensorId, @@ -309,6 +350,12 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { mNotificationManager = mContext.getSystemService(NotificationManager.class); mLockoutTracker = new LockoutHalImpl(); mLockoutResetDispatcher = lockoutResetDispatcher; + mHalResultController = new HalResultController(sensorId, context, mHandler, mScheduler, + mLockoutTracker, lockoutResetDispatcher); + mHalResultController.setCallback(() -> { + mDaemon = null; + mCurrentUserId = UserHandle.USER_NULL; + }); try { ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG); @@ -351,6 +398,12 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { } private synchronized IBiometricsFace getDaemon() { + if (mTestHalEnabled) { + final TestHal testHal = new TestHal(); + testHal.setCallback(mHalResultController); + return testHal; + } + if (mDaemon != null) { return mDaemon; } @@ -378,7 +431,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { // successfully set. long halId = 0; try { - halId = mDaemon.setCallback(mDaemonCallback).value; + halId = mDaemon.setCallback(mHalResultController).value; } catch (RemoteException e) { Slog.e(TAG, "Failed to set callback for face HAL", e); mDaemon = null; @@ -413,6 +466,12 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { return properties; } + @NonNull + @Override + public FaceSensorPropertiesInternal getSensorProperties(int sensorId) { + return mSensorProperties; + } + @Override @NonNull public List<Face> getEnrolledFaces(int sensorId, int userId) { @@ -712,6 +771,22 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { @Override public void dumpProtoState(int sensorId, ProtoOutputStream proto) { + final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES); + + proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId); + proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null); + + for (UserInfo user : UserManager.get(mContext).getUsers()) { + final int userId = user.getUserHandle().getIdentifier(); + + final long userToken = proto.start(SensorStateProto.USER_STATES); + proto.write(UserStateProto.USER_ID, userId); + proto.write(UserStateProto.NUM_ENROLLED, FaceUtils.getInstance() + .getBiometricsForUser(mContext, userId).size()); + proto.end(userToken); + } + + proto.end(sensorToken); } @Override @@ -844,4 +919,14 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { } } } + + void setTestHalEnabled(boolean enabled) { + mTestHalEnabled = enabled; + } + + @NonNull + @Override + public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) { + return new BiometricTestSessionImpl(mContext, mSensorId, this, mHalResultController); + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/TestHal.java new file mode 100644 index 000000000000..bab1114dc70d --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/TestHal.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.biometrics.sensors.face.hidl; + +import android.annotation.Nullable; +import android.hardware.biometrics.face.V1_0.FaceError; +import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback; +import android.hardware.biometrics.face.V1_0.OptionalBool; +import android.hardware.biometrics.face.V1_0.OptionalUint64; +import android.hardware.biometrics.face.V1_0.Status; +import android.hardware.biometrics.face.V1_1.IBiometricsFace; +import android.os.NativeHandle; +import android.os.RemoteException; + +import java.util.ArrayList; + +public class TestHal extends IBiometricsFace.Stub { + @Nullable + private IBiometricsFaceClientCallback mCallback; + + @Override + public OptionalUint64 setCallback(IBiometricsFaceClientCallback clientCallback) { + mCallback = clientCallback; + final OptionalUint64 result = new OptionalUint64(); + result.status = Status.OK; + return new OptionalUint64(); + } + + @Override + public int setActiveUser(int userId, String storePath) { + return 0; + } + + @Override + public OptionalUint64 generateChallenge(int challengeTimeoutSec) { + final OptionalUint64 result = new OptionalUint64(); + result.status = Status.OK; + result.value = 0; + return result; + } + + @Override + public int enroll(ArrayList<Byte> hat, int timeoutSec, ArrayList<Integer> disabledFeatures) { + return 0; + } + + @Override + public int revokeChallenge() { + return 0; + } + + @Override + public int setFeature(int feature, boolean enabled, ArrayList<Byte> hat, int faceId) { + return 0; + } + + @Override + public OptionalBool getFeature(int feature, int faceId) { + final OptionalBool result = new OptionalBool(); + result.status = Status.OK; + result.value = true; + return result; + } + + @Override + public OptionalUint64 getAuthenticatorId() { + final OptionalUint64 result = new OptionalUint64(); + result.status = Status.OK; + result.value = 0; + return result; + } + + @Override + public int cancel() throws RemoteException { + if (mCallback != null) { + mCallback.onError(0 /* deviceId */, 0 /* userId */, FaceError.CANCELED, + 0 /* vendorCode */); + } + return 0; + } + + @Override + public int enumerate() { + return 0; + } + + @Override + public int remove(int faceId) { + return 0; + } + + @Override + public int authenticate(long operationId) { + return 0; + } + + @Override + public int userActivity() { + return 0; + } + + @Override + public int resetLockout(ArrayList<Byte> hat) { + return 0; + } + + @Override + public int enrollRemotely(ArrayList<Byte> hat, int timeoutSec, + ArrayList<Integer> disabledFeatures) { + return 0; + } + + @Override + public int enroll_1_1(ArrayList<Byte> hat, int timeoutSec, ArrayList<Integer> disabledFeatures, + NativeHandle nativeHandle) { + return 0; + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java index 9f9d9cca2158..1616457e09a9 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java @@ -16,8 +16,11 @@ package com.android.server.biometrics.sensors.fingerprint; +import android.annotation.NonNull; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.IBiometricSensorReceiver; +import android.hardware.biometrics.ITestSession; +import android.hardware.biometrics.SensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintService; import android.os.IBinder; import android.os.RemoteException; @@ -39,12 +42,28 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub } @Override + public ITestSession createTestSession(@NonNull String opPackageName) throws RemoteException { + return mFingerprintService.createTestSession(mSensorId, opPackageName); + } + + @Override + public SensorPropertiesInternal getSensorProperties(@NonNull String opPackageName) + throws RemoteException { + return mFingerprintService.getSensorProperties(mSensorId, opPackageName); + } + + @Override + public byte[] dumpSensorServiceStateProto() throws RemoteException { + return mFingerprintService.dumpSensorServiceStateProto(); + } + + @Override public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, - String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId) + String opPackageName, int cookie) throws RemoteException { mFingerprintService.prepareForAuthentication(mSensorId, token, operationId, userId, - sensorReceiver, opPackageName, cookie, callingUid, callingPid, callingUserId); + sensorReceiver, opPackageName, cookie); } @Override @@ -53,10 +72,9 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub } @Override - public void cancelAuthenticationFromService(IBinder token, String opPackageName, int callingUid, - int callingPid, int callingUserId) throws RemoteException { - mFingerprintService.cancelAuthenticationFromService(mSensorId, token, opPackageName, - callingUid, callingPid, callingUserId); + public void cancelAuthenticationFromService(IBinder token, String opPackageName) + throws RemoteException { + mFingerprintService.cancelAuthenticationFromService(mSensorId, token, opPackageName); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index b84d0958e426..af0935fa799a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -100,21 +100,37 @@ public class FingerprintService extends SystemService implements BiometricServic */ private final class FingerprintServiceWrapper extends IFingerprintService.Stub { @Override - public ITestSession createTestSession(int sensorId, String opPackageName) { + public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) { Utils.checkPermission(getContext(), TEST_BIOMETRIC); + final ServiceProvider provider = getProviderForSensor(sensorId); + + if (provider == null) { + Slog.w(TAG, "Null provider for createTestSession, sensorId: " + sensorId); + return null; + } + + return provider.createTestSession(sensorId, opPackageName); + } + + @Override + public byte[] dumpSensorServiceStateProto() { + Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); + + final ProtoOutputStream proto = new ProtoOutputStream(); for (ServiceProvider provider : mServiceProviders) { - if (provider.containsSensor(sensorId)) { - return provider.createTestSession(sensorId, opPackageName); + for (FingerprintSensorPropertiesInternal props + : provider.getSensorProperties()) { + provider.dumpProtoState(props.sensorId, proto); } } - - return null; + proto.flush(); + return proto.getBytes(); } @Override // Binder call public List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal( - String opPackageName) { + @NonNull String opPackageName) { if (getContext().checkCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL) != PackageManager.PERMISSION_GRANTED) { Utils.checkPermission(getContext(), TEST_BIOMETRIC); @@ -128,6 +144,20 @@ public class FingerprintService extends SystemService implements BiometricServic return properties; } + @Override + public FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, + @NonNull String opPackageName) { + Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); + + final ServiceProvider provider = getProviderForSensor(sensorId); + if (provider == null) { + Slog.w(TAG, "No matching sensor for getSensorProperties, sensorId: " + sensorId + + ", caller: " + opPackageName); + return null; + } + return provider.getSensorProperties(sensorId); + } + @Override // Binder call public void generateChallenge(IBinder token, int sensorId, int userId, IFingerprintServiceReceiver receiver, String opPackageName) { @@ -262,7 +292,7 @@ public class FingerprintService extends SystemService implements BiometricServic @Override // Binder call public void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, int callingUid, int callingPid, int callingUserId) { + int cookie) { Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); final ServiceProvider provider = getProviderForSensor(sensorId); @@ -334,7 +364,7 @@ public class FingerprintService extends SystemService implements BiometricServic @Override // Binder call public void cancelAuthenticationFromService(final int sensorId, final IBinder token, - final String opPackageName, int callingUid, int callingPid, int callingUserId) { + final String opPackageName) { Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); final ServiceProvider provider = getProviderForSensor(sensorId); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java index c13a6569b16a..6e36cd24b2e7 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java @@ -64,6 +64,9 @@ public interface ServiceProvider { @NonNull List<FingerprintSensorPropertiesInternal> getSensorProperties(); + @NonNull + FingerprintSensorPropertiesInternal getSensorProperties(int sensorId); + void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken); void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token, diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java index 0ebfe9381d15..5f3be488c12c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java @@ -226,6 +226,12 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi return props; } + @NonNull + @Override + public FingerprintSensorPropertiesInternal getSensorProperties(int sensorId) { + return mSensors.get(sensorId).getSensorProperties(); + } + private void scheduleLoadAuthenticatorIds(int sensorId) { for (UserInfo user : UserManager.get(mContext).getAliveUsers()) { scheduleLoadAuthenticatorIdsForUser(sensorId, user.id); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java index 2e78912703f2..380608f1b0a9 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java @@ -39,10 +39,10 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.util.FrameworkStatsLog; import com.android.server.biometrics.HardwareAuthTokenUtils; +import com.android.server.biometrics.SensorServiceStateProto; +import com.android.server.biometrics.SensorStateProto; +import com.android.server.biometrics.UserStateProto; import com.android.server.biometrics.Utils; -import com.android.server.biometrics.fingerprint.FingerprintServiceStateProto; -import com.android.server.biometrics.fingerprint.SensorStateProto; -import com.android.server.biometrics.fingerprint.UserStateProto; import com.android.server.biometrics.sensors.AcquisitionClient; import com.android.server.biometrics.sensors.AuthenticationConsumer; import com.android.server.biometrics.sensors.BiometricScheduler; @@ -491,7 +491,7 @@ class Sensor implements IBinder.DeathRecipient { } void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) { - final long sensorToken = proto.start(FingerprintServiceStateProto.SENSOR_STATES); + final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES); proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId); proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java index 8c766d682bf7..9924d4710436 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java @@ -49,13 +49,13 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.util.FrameworkStatsLog; +import com.android.server.biometrics.SensorServiceStateProto; +import com.android.server.biometrics.SensorStateProto; +import com.android.server.biometrics.UserStateProto; import com.android.server.biometrics.Utils; import com.android.server.biometrics.fingerprint.FingerprintServiceDumpProto; -import com.android.server.biometrics.fingerprint.FingerprintServiceStateProto; import com.android.server.biometrics.fingerprint.FingerprintUserStatsProto; import com.android.server.biometrics.fingerprint.PerformanceStatsProto; -import com.android.server.biometrics.fingerprint.SensorStateProto; -import com.android.server.biometrics.fingerprint.UserStateProto; import com.android.server.biometrics.sensors.AcquisitionClient; import com.android.server.biometrics.sensors.AuthenticationClient; import com.android.server.biometrics.sensors.AuthenticationConsumer; @@ -397,7 +397,9 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider private synchronized IBiometricsFingerprint getDaemon() { if (mTestHalEnabled) { - return new TestHal(); + final TestHal testHal = new TestHal(); + testHal.setNotify(mHalResultController); + return testHal; } if (mDaemon != null) { @@ -504,6 +506,12 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider return properties; } + @NonNull + @Override + public FingerprintSensorPropertiesInternal getSensorProperties(int sensorId) { + return mSensorProperties; + } + @Override public void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken) { // Fingerprint2.1 keeps track of lockout in the framework. Let's just do it on the handler @@ -701,7 +709,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider @Override public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) { - final long sensorToken = proto.start(FingerprintServiceStateProto.SENSOR_STATES); + final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES); proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId); proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/TestHal.java index 86c0875af48c..b7aec0ed2731 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/TestHal.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/TestHal.java @@ -16,6 +16,8 @@ package com.android.server.biometrics.sensors.fingerprint.hidl; +import android.annotation.Nullable; +import android.hardware.biometrics.fingerprint.V2_1.FingerprintError; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback; import android.hardware.biometrics.fingerprint.V2_3.IBiometricsFingerprint; import android.os.RemoteException; @@ -24,6 +26,9 @@ import android.os.RemoteException; * Test HAL that provides only provides no-ops. */ public class TestHal extends IBiometricsFingerprint.Stub { + @Nullable + private IBiometricsFingerprintClientCallback mCallback; + @Override public boolean isUdfps(int sensorId) { return false; @@ -41,6 +46,7 @@ public class TestHal extends IBiometricsFingerprint.Stub { @Override public long setNotify(IBiometricsFingerprintClientCallback clientCallback) { + mCallback = clientCallback; return 0; } @@ -65,7 +71,10 @@ public class TestHal extends IBiometricsFingerprint.Stub { } @Override - public int cancel() { + public int cancel() throws RemoteException { + if (mCallback != null) { + mCallback.onError(0, FingerprintError.ERROR_CANCELED, 0 /* vendorCode */); + } return 0; } diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java index b756d8e87fd6..6f437a7c31d2 100644 --- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java @@ -16,8 +16,11 @@ package com.android.server.biometrics.sensors.iris; +import android.annotation.NonNull; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.IBiometricSensorReceiver; +import android.hardware.biometrics.ITestSession; +import android.hardware.biometrics.SensorPropertiesInternal; import android.hardware.iris.IIrisService; import android.os.IBinder; import android.os.RemoteException; @@ -36,10 +39,25 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub { } @Override + public ITestSession createTestSession(@NonNull String opPackageName) throws RemoteException { + return null; + } + + @Override + public SensorPropertiesInternal getSensorProperties(@NonNull String opPackageName) + throws RemoteException { + return null; + } + + @Override + public byte[] dumpSensorServiceStateProto() throws RemoteException { + return null; + } + + @Override public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long sessionId, int userId, IBiometricSensorReceiver sensorReceiver, - String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId) - throws RemoteException { + String opPackageName, int cookie) throws RemoteException { } @Override @@ -47,8 +65,8 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub { } @Override - public void cancelAuthenticationFromService(IBinder token, String opPackageName, int callingUid, - int callingPid, int callingUserId) throws RemoteException { + public void cancelAuthenticationFromService(IBinder token, String opPackageName) + throws RemoteException { } @Override 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 e011c797777e..e4be448f6b18 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java @@ -47,7 +47,6 @@ import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; -import org.mockito.AdditionalMatchers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -170,10 +169,7 @@ public class AuthServiceTest { eq(userId), eq(mReceiver), eq(TEST_OP_PACKAGE_NAME), - eq(promptInfo), - eq(Binder.getCallingUid()), - eq(Binder.getCallingPid()), - eq(UserHandle.getCallingUserId())); + eq(promptInfo)); } @Test @@ -202,10 +198,7 @@ public class AuthServiceTest { eq(userId), eq(mReceiver), eq(TEST_OP_PACKAGE_NAME), - eq(promptInfo), - eq(Binder.getCallingUid()), - eq(Binder.getCallingPid()), - eq(UserHandle.getCallingUserId())); + eq(promptInfo)); } @Test 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 6b000f39aba2..8d890b9cd606 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java @@ -19,6 +19,8 @@ package com.android.server.biometrics; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; +import static com.android.server.biometrics.BiometricServiceStateProto.*; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -29,7 +31,6 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; 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; @@ -108,10 +109,7 @@ public class AuthSessionTest { false /* checkDevicePolicyManager */, Authenticators.BIOMETRIC_STRONG, 0 /* operationId */, - 0 /* userId */, - 0 /* callingUid */, - 0 /* callingPid */, - 0 /* callingUserId */); + 0 /* userId */); for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState()); @@ -126,18 +124,12 @@ public class AuthSessionTest { final boolean requireConfirmation = true; 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 */, Authenticators.BIOMETRIC_STRONG, operationId, - userId, - callingUid, - callingPid, - callingUserId); + userId); assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size()); for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { @@ -156,10 +148,7 @@ public class AuthSessionTest { eq(userId), eq(mSensorReceiver), eq(TEST_PACKAGE), - eq(sensor.getCookie()), - eq(callingUid), - eq(callingPid), - eq(callingUserId)); + eq(sensor.getCookie())); } final int cookie1 = session.mPreAuthInfo.eligibleSensors.get(0).getCookie(); @@ -200,10 +189,7 @@ public class AuthSessionTest { false /* checkDevicePolicyManager */, Authenticators.BIOMETRIC_STRONG, operationId, - userId, - callingUid, - callingPid, - callingUserId); + userId); assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size()); for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { @@ -225,13 +211,13 @@ public class AuthSessionTest { assertTrue(session.allCookiesReceived()); // UDFPS does not start even if all cookies are received - assertEquals(AuthSession.STATE_AUTH_STARTED, session.getState()); + assertEquals(STATE_AUTH_STARTED, session.getState()); verify(mStatusBarService).showAuthenticationDialog(any(), any(), any(), anyBoolean(), anyBoolean(), anyInt(), any(), anyLong()); // Notify AuthSession that the UI is shown. Then, UDFPS sensor should be started. session.onDialogAnimatedIn(); - assertEquals(AuthSession.STATE_AUTH_STARTED_UI_SHOWING, session.getState()); + assertEquals(STATE_AUTH_STARTED_UI_SHOWING, session.getState()); assertEquals(BiometricSensor.STATE_AUTHENTICATING, session.mPreAuthInfo.eligibleSensors.get(0).getSensorState()); @@ -251,9 +237,7 @@ public class AuthSessionTest { private AuthSession createAuthSession(List<BiometricSensor> sensors, boolean checkDevicePolicyManager, @Authenticators.Types int authenticators, - long operationId, int userId, - int callingUid, int callingPid, int callingUserId) - throws RemoteException { + long operationId, int userId) throws RemoteException { final PromptInfo promptInfo = createPromptInfo(authenticators); @@ -261,8 +245,8 @@ public class AuthSessionTest { checkDevicePolicyManager); return new AuthSession(mContext, mStatusBarService, mSysuiReceiver, mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, mToken, operationId, userId, - mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo, callingUid, - callingPid, callingUserId, false /* debugEnabled */, mFingerprintSensorProps); + mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo, + false /* debugEnabled */, mFingerprintSensorProps); } private PromptInfo createPromptInfo(@Authenticators.Types int authenticators) { @@ -299,7 +283,7 @@ public class AuthSessionTest { } private void setupFace(int id, boolean confirmationAlwaysRequired) throws RemoteException { - IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class); + IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class); when(faceAuthenticator.isHardwareDetected(any())).thenReturn(true); when(faceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true); mSensors.add(new BiometricSensor(id, diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java index 435c7008ca59..0c95e05342c8 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -18,6 +18,8 @@ package com.android.server.biometrics; import static android.hardware.biometrics.BiometricManager.Authenticators; +import static com.android.server.biometrics.BiometricServiceStateProto.*; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -174,8 +176,7 @@ public class BiometricServiceTest { 0 /* vendorCode */); waitForIdle(); - assertEquals(AuthSession.STATE_AUTH_PAUSED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_PAUSED, mBiometricService.mCurrentAuthSession.getState()); mBiometricService.mCurrentAuthSession.binderDied(); waitForIdle(); @@ -195,22 +196,18 @@ public class BiometricServiceTest { verify(mReceiver1.asBinder()).linkToDeath(eq(mBiometricService.mCurrentAuthSession), anyInt()); - assertEquals(AuthSession.STATE_AUTH_STARTED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); mBiometricService.mCurrentAuthSession.binderDied(); waitForIdle(); assertNotNull(mBiometricService.mCurrentAuthSession); verify(mBiometricService.mStatusBarService, never()).hideAuthenticationDialog(); - assertEquals(AuthSession.STATE_CLIENT_DIED_CANCELLING, + assertEquals(STATE_CLIENT_DIED_CANCELLING, mBiometricService.mCurrentAuthSession.getState()); verify(mBiometricService.mCurrentAuthSession.mPreAuthInfo.eligibleSensors.get(0).impl) .cancelAuthenticationFromService(any(), - any(), - anyInt(), - anyInt(), - anyInt()); + any()); // Simulate ERROR_CANCELED received from HAL mBiometricService.mBiometricSensorReceiver.onError( @@ -256,7 +253,7 @@ public class BiometricServiceTest { waitForIdle(); assertNotNull(mBiometricService.mCurrentAuthSession); - assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL, + assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL, mBiometricService.mCurrentAuthSession.getState()); // StatusBar showBiometricDialog invoked verify(mBiometricService.mStatusBarService).showAuthenticationDialog( @@ -406,7 +403,7 @@ public class BiometricServiceTest { HAT); waitForIdle(); // Confirmation is required - assertEquals(AuthSession.STATE_AUTH_PENDING_CONFIRM, + assertEquals(STATE_AUTH_PENDING_CONFIRM, mBiometricService.mCurrentAuthSession.getState()); // Enrolled, not disabled in settings, user doesn't require confirmation in settings @@ -422,7 +419,7 @@ public class BiometricServiceTest { HAT); waitForIdle(); // Confirmation not required, waiting for dialog to dismiss - assertEquals(AuthSession.STATE_AUTHENTICATED_PENDING_SYSUI, + assertEquals(STATE_AUTHENTICATED_PENDING_SYSUI, mBiometricService.mCurrentAuthSession.getState()); } @@ -447,8 +444,7 @@ public class BiometricServiceTest { waitForIdle(); // Creates a pending auth session with the correct initial states - assertEquals(AuthSession.STATE_AUTH_CALLED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_CALLED, mBiometricService.mCurrentAuthSession.getState()); // Invokes <Modality>Service#prepareForAuthentication ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class); @@ -460,16 +456,12 @@ public class BiometricServiceTest { anyInt() /* userId */, any(IBiometricSensorReceiver.class), anyString() /* opPackageName */, - cookieCaptor.capture() /* cookie */, - anyInt() /* callingUid */, - anyInt() /* callingPid */, - anyInt() /* callingUserId */); + cookieCaptor.capture() /* cookie */); // onReadyForAuthentication, mCurrentAuthSession state OK mBiometricService.mImpl.onReadyForAuthentication(cookieCaptor.getValue()); waitForIdle(); - assertEquals(AuthSession.STATE_AUTH_STARTED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); // startPreparedClient invoked verify(mBiometricService.mSensors.get(0).impl) @@ -493,7 +485,7 @@ public class BiometricServiceTest { HAT); waitForIdle(); // Waiting for SystemUI to send dismissed callback - assertEquals(AuthSession.STATE_AUTHENTICATED_PENDING_SYSUI, + assertEquals(STATE_AUTHENTICATED_PENDING_SYSUI, mBiometricService.mCurrentAuthSession.getState()); // Notify SystemUI hardware authenticated verify(mBiometricService.mStatusBarService).onBiometricAuthenticated(); @@ -526,7 +518,7 @@ public class BiometricServiceTest { Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK); waitForIdle(); - assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL, + assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL, mBiometricService.mCurrentAuthSession.getState()); assertEquals(Authenticators.DEVICE_CREDENTIAL, mBiometricService.mCurrentAuthSession.mPromptInfo.getAuthenticators()); @@ -566,8 +558,7 @@ public class BiometricServiceTest { HAT); waitForIdle(); // Waiting for SystemUI to send confirmation callback - assertEquals(AuthSession.STATE_AUTH_PENDING_CONFIRM, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_PENDING_CONFIRM, mBiometricService.mCurrentAuthSession.getState()); verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class)); // SystemUI sends confirm, HAT is sent to keystore and client is notified. @@ -615,8 +606,7 @@ public class BiometricServiceTest { eq(BiometricConstants.BIOMETRIC_PAUSED_REJECTED), eq(0 /* vendorCode */)); verify(mReceiver1).onAuthenticationFailed(); - assertEquals(AuthSession.STATE_AUTH_PAUSED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_PAUSED, mBiometricService.mCurrentAuthSession.getState()); } @Test @@ -634,8 +624,7 @@ public class BiometricServiceTest { eq(BiometricConstants.BIOMETRIC_PAUSED_REJECTED), eq(0 /* vendorCode */)); verify(mReceiver1).onAuthenticationFailed(); - assertEquals(AuthSession.STATE_AUTH_STARTED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); } @Test @@ -670,8 +659,7 @@ public class BiometricServiceTest { 0 /* vendorCode */); waitForIdle(); - assertEquals(AuthSession.STATE_AUTH_PAUSED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_PAUSED, mBiometricService.mCurrentAuthSession.getState()); verify(mBiometricService.mStatusBarService).onBiometricError( eq(BiometricAuthenticator.TYPE_FACE), eq(BiometricConstants.BIOMETRIC_ERROR_TIMEOUT), @@ -680,8 +668,7 @@ public class BiometricServiceTest { verify(mReceiver1, never()).onAuthenticationFailed(); // No auth session. Pressing try again will create one. - assertEquals(AuthSession.STATE_AUTH_PAUSED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_PAUSED, mBiometricService.mCurrentAuthSession.getState()); // Pressing "Try again" on SystemUI mBiometricService.mSysuiReceiver.onTryAgainPressed(); @@ -689,8 +676,7 @@ public class BiometricServiceTest { verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt()); // AuthSession is now resuming - assertEquals(AuthSession.STATE_AUTH_PAUSED_RESUMING, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_PAUSED_RESUMING, mBiometricService.mCurrentAuthSession.getState()); // Test resuming when hardware becomes ready. SystemUI should not be requested to // show another dialog since it's already showing. @@ -755,8 +741,7 @@ public class BiometricServiceTest { waitForIdle(); // Sends error to SystemUI and does not notify client yet - assertEquals(AuthSession.STATE_ERROR_PENDING_SYSUI, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_ERROR_PENDING_SYSUI, mBiometricService.mCurrentAuthSession.getState()); verify(mBiometricService.mStatusBarService).onBiometricError( eq(BiometricAuthenticator.TYPE_FINGERPRINT), eq(BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_PROCESS), @@ -783,8 +768,7 @@ public class BiometricServiceTest { Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK); waitForIdle(); - assertEquals(AuthSession.STATE_AUTH_CALLED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_CALLED, mBiometricService.mCurrentAuthSession.getState()); mBiometricService.mBiometricSensorReceiver.onError( SENSOR_ID_FINGERPRINT, getCookieForPendingSession(mBiometricService.mCurrentAuthSession), @@ -794,7 +778,7 @@ public class BiometricServiceTest { // We should be showing device credential now assertNotNull(mBiometricService.mCurrentAuthSession); - assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL, + assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL, mBiometricService.mCurrentAuthSession.getState()); assertEquals(Authenticators.DEVICE_CREDENTIAL, mBiometricService.mCurrentAuthSession.mPromptInfo.getAuthenticators()); @@ -873,7 +857,7 @@ public class BiometricServiceTest { verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt()); assertNotNull(mBiometricService.mCurrentAuthSession); - assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL, + assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL, mBiometricService.mCurrentAuthSession.getState()); assertEquals(Authenticators.DEVICE_CREDENTIAL, mBiometricService.mCurrentAuthSession.mPromptInfo.getAuthenticators()); @@ -950,7 +934,7 @@ public class BiometricServiceTest { mBiometricService.mSysuiReceiver.onDeviceCredentialPressed(); waitForIdle(); - assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL, + assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL, mBiometricService.mCurrentAuthSession.getState()); verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt()); @@ -961,7 +945,7 @@ public class BiometricServiceTest { 0 /* vendorCode */); waitForIdle(); - assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL, + assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL, mBiometricService.mCurrentAuthSession.getState()); verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt()); } @@ -973,8 +957,7 @@ public class BiometricServiceTest { false /* requireConfirmation */, Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK); - assertEquals(AuthSession.STATE_AUTH_STARTED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); mBiometricService.mBiometricSensorReceiver.onError( SENSOR_ID_FINGERPRINT, @@ -983,7 +966,7 @@ public class BiometricServiceTest { 0 /* vendorCode */); waitForIdle(); - assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL, + assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL, mBiometricService.mCurrentAuthSession.getState()); verify(mBiometricService.mStatusBarService).onBiometricError( eq(BiometricAuthenticator.TYPE_FINGERPRINT), @@ -997,8 +980,7 @@ public class BiometricServiceTest { invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, null /* authenticators */); - assertEquals(AuthSession.STATE_AUTH_STARTED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); mBiometricService.mBiometricSensorReceiver.onError( SENSOR_ID_FINGERPRINT, @@ -1007,7 +989,7 @@ public class BiometricServiceTest { 0 /* vendorCode */); waitForIdle(); - assertEquals(AuthSession.STATE_ERROR_PENDING_SYSUI, + assertEquals(STATE_ERROR_PENDING_SYSUI, mBiometricService.mCurrentAuthSession.getState()); verify(mBiometricService.mStatusBarService).onBiometricError( eq(BiometricAuthenticator.TYPE_FINGERPRINT), @@ -1031,10 +1013,7 @@ public class BiometricServiceTest { eq(0 /* vendorCode */)); verify(mBiometricService.mSensors.get(0).impl).cancelAuthenticationFromService( any(), - any(), - anyInt(), - anyInt(), - anyInt()); + any()); assertNull(mBiometricService.mCurrentAuthSession); } @@ -1056,10 +1035,7 @@ public class BiometricServiceTest { verify(mBiometricService.mSensors.get(0).impl, never()).cancelAuthenticationFromService( any(), - any(), - anyInt(), - anyInt(), - anyInt()); + any()); } @Test @@ -1081,10 +1057,7 @@ public class BiometricServiceTest { verify(mBiometricService.mSensors.get(0).impl, never()).cancelAuthenticationFromService( any(), - any(), - anyInt(), - anyInt(), - anyInt()); + any()); } @Test @@ -1104,10 +1077,7 @@ public class BiometricServiceTest { verify(mBiometricService.mSensors.get(0).impl, never()).cancelAuthenticationFromService( any(), - any(), - anyInt(), - anyInt(), - anyInt()); + any()); verify(mReceiver1).onError( eq(BiometricAuthenticator.TYPE_FACE), eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED), @@ -1134,8 +1104,7 @@ public class BiometricServiceTest { // string is retrieved for now, but it's also very unlikely to break anyway. verify(mBiometricService.mStatusBarService) .onBiometricHelp(anyString()); - assertEquals(AuthSession.STATE_AUTH_STARTED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); } @Test @@ -1145,7 +1114,7 @@ public class BiometricServiceTest { false /* requireConfirmation */, null /* authenticators */); mBiometricService.mImpl.cancelAuthentication(mBiometricService.mCurrentAuthSession.mToken, - TEST_PACKAGE_NAME, 0 /* callingUId */, 0 /* callingPid */, 0 /* callingUserId */); + TEST_PACKAGE_NAME); waitForIdle(); // Pretend that the HAL has responded to cancel with ERROR_CANCELED @@ -1491,12 +1460,10 @@ public class BiometricServiceTest { invokeAuthenticateForWorkApp(mBiometricService.mImpl, mReceiver1, Authenticators.BIOMETRIC_STRONG); waitForIdle(); - assertEquals(AuthSession.STATE_AUTH_CALLED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_CALLED, mBiometricService.mCurrentAuthSession.getState()); startPendingAuthSession(mBiometricService); waitForIdle(); - assertEquals(AuthSession.STATE_AUTH_STARTED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); } @Test @@ -1508,8 +1475,7 @@ public class BiometricServiceTest { invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, Authenticators.BIOMETRIC_STRONG); waitForIdle(); - assertEquals(AuthSession.STATE_AUTH_STARTED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); } @Test @@ -1522,12 +1488,10 @@ public class BiometricServiceTest { invokeAuthenticateForWorkApp(mBiometricService.mImpl, mReceiver1, Authenticators.BIOMETRIC_STRONG); waitForIdle(); - assertEquals(AuthSession.STATE_AUTH_CALLED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_CALLED, mBiometricService.mCurrentAuthSession.getState()); startPendingAuthSession(mBiometricService); waitForIdle(); - assertEquals(AuthSession.STATE_AUTH_STARTED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); } @Test @@ -1549,7 +1513,7 @@ public class BiometricServiceTest { Authenticators.BIOMETRIC_STRONG | Authenticators.DEVICE_CREDENTIAL); waitForIdle(); assertNotNull(mBiometricService.mCurrentAuthSession); - assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL, + assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL, mBiometricService.mCurrentAuthSession.getState()); verify(mReceiver2, never()).onError(anyInt(), anyInt(), anyInt()); } @@ -1647,8 +1611,7 @@ public class BiometricServiceTest { waitForIdle(); assertNotNull(mBiometricService.mCurrentAuthSession); - assertEquals(AuthSession.STATE_AUTH_STARTED, - mBiometricService.mCurrentAuthSession.getState()); + assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); } private static void startPendingAuthSession(BiometricService service) throws Exception { @@ -1674,10 +1637,7 @@ public class BiometricServiceTest { receiver, TEST_PACKAGE_NAME /* packageName */, createTestPromptInfo(requireConfirmation, authenticators, - false /* checkDevicePolicy */), - 0 /* callingUid */, - 0 /* callingPid */, - 0 /* callingUserId */); + false /* checkDevicePolicy */)); } private static void invokeAuthenticateForWorkApp(IBiometricService.Stub service, @@ -1689,10 +1649,7 @@ public class BiometricServiceTest { receiver, TEST_PACKAGE_NAME /* packageName */, createTestPromptInfo(false /* requireConfirmation */, authenticators, - true /* checkDevicePolicy */), - 0 /* callingUid */, - 0 /* callingPid */, - 0 /* callingUserId */); + true /* checkDevicePolicy */)); } private static PromptInfo createTestPromptInfo( |