diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl index fcdf61e99471c..c854ac9847d8c 100644 --- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl +++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl @@ -38,7 +38,7 @@ interface IBiometricAuthenticator { SensorPropertiesInternal getSensorProperties(String opPackageName); // Requests a proto dump of the sensor. See biometrics.proto - byte[] dumpSensorServiceStateProto(); + byte[] dumpSensorServiceStateProto(boolean clearSchedulerBuffer); // 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 diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index 3b19f12a41bac..1b188e87e90fa 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -35,7 +35,7 @@ interface IFaceService { ITestSession createTestSession(int sensorId, String opPackageName); // Requests a proto dump of the specified sensor - byte[] dumpSensorServiceStateProto(int sensorId); + byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer); // Retrieve static sensor properties for all face sensors List getSensorPropertiesInternal(String opPackageName); diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 74c5b5864e877..3657a83039ad4 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -36,7 +36,7 @@ interface IFingerprintService { ITestSession createTestSession(int sensorId, String opPackageName); // Requests a proto dump of the specified sensor - byte[] dumpSensorServiceStateProto(int sensorId); + byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer); // Retrieve static sensor properties for all fingerprint sensors List getSensorPropertiesInternal(String opPackageName); diff --git a/core/proto/android/server/biometrics.proto b/core/proto/android/server/biometrics.proto index 14b5c52acce4c..900235ea65fb9 100644 --- a/core/proto/android/server/biometrics.proto +++ b/core/proto/android/server/biometrics.proto @@ -120,8 +120,8 @@ message SensorStateProto { optional Modality modality = 2; - // State of the sensor's scheduler. True if currently handling an operation, false if idle. - optional bool is_busy = 3; + // State of the sensor's scheduler. + optional BiometricSchedulerProto scheduler = 3; // User states for this sensor. repeated UserStateProto user_states = 4; @@ -136,4 +136,39 @@ message UserStateProto { // Number of fingerprints enrolled optional int32 num_enrolled = 2; +} + +// BiometricScheduler dump +message BiometricSchedulerProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + // Operation currently being handled by the BiometricScheduler + optional ClientMonitorEnum current_operation = 1; + + // Total number of operations that have been handled, not including the current one if one + // exists. Kept in FIFO order (most recent at the end of the array) + optional int32 total_operations = 2; + + // A list of recent past operations in the order which they were handled + repeated ClientMonitorEnum recent_operations = 3; +} + +// BaseClientMonitor subtypes +enum ClientMonitorEnum { + CM_NONE = 0; + CM_UPDATE_ACTIVE_USER = 1; + CM_ENROLL = 2; + CM_AUTHENTICATE = 3; + CM_REMOVE = 4; + CM_GET_AUTHENTICATOR_ID = 5; + CM_ENUMERATE = 6; + CM_INTERNAL_CLEANUP = 7; + CM_SET_FEATURE = 8; + CM_GET_FEATURE = 9; + CM_GENERATE_CHALLENGE = 10; + CM_REVOKE_CHALLENGE = 11; + CM_RESET_LOCKOUT = 12; + CM_DETECT_INTERACTION = 13; + CM_INVALIDATION_REQUESTER = 14; + CM_INVALIDATE = 15; } \ No newline at end of file diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java index 52152ab78992d..14292d9c5f8de 100644 --- a/services/core/java/com/android/server/biometrics/AuthSession.java +++ b/services/core/java/com/android/server/biometrics/AuthSession.java @@ -37,7 +37,6 @@ import android.hardware.biometrics.IBiometricSysuiReceiver; import android.hardware.biometrics.PromptInfo; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; -import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.IBinder; import android.os.RemoteException; @@ -62,8 +61,6 @@ public final class AuthSession implements IBinder.DeathRecipient { private static final String TAG = "BiometricService/AuthSession"; private static final boolean DEBUG = false; - - /* * Defined in biometrics.proto */ diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index 3387049d69f38..614c5f1b65bfb 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -815,12 +815,16 @@ public class BiometricService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { if (args.length > 0 && "--proto".equals(args[0])) { + final boolean clearSchedulerBuffer = args.length > 1 + && "--clear-scheduler-buffer".equals(args[1]); + Slog.d(TAG, "ClearSchedulerBuffer: " + clearSchedulerBuffer); 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(); + byte[] serviceState = sensor.impl + .dumpSensorServiceStateProto(clearSchedulerBuffer); proto.write(BiometricServiceStateProto.SENSOR_SERVICE_STATES, serviceState); } proto.flush(); diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java index 5663495db037c..3f6ae6439aa4c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java @@ -33,6 +33,7 @@ import android.security.KeyStore; import android.util.EventLog; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.Utils; import java.util.ArrayList; @@ -298,4 +299,9 @@ public abstract class AuthenticationClient extends AcquisitionClient mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); } } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_AUTHENTICATE; + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java index f3c37efd4b612..8fa3bbbf615ae 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java +++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java @@ -24,6 +24,8 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; + import java.util.NoSuchElementException; /** @@ -79,6 +81,12 @@ public abstract class BaseClientMonitor extends LoggableMonitor @NonNull protected Callback mCallback; + /** + * Returns a ClientMonitorEnum constant defined in biometrics.proto + * @return + */ + public abstract int getProtoEnum(); + /** * @param context system_server context * @param token a unique token for the client @@ -195,10 +203,16 @@ public abstract class BaseClientMonitor extends LoggableMonitor return mSensorId; } + @VisibleForTesting + public Callback getCallback() { + return mCallback; + } + @Override public String toString() { return "{[" + mSequentialId + "] " + this.getClass().getSimpleName() + + ", " + getProtoEnum() + ", " + getOwnerString() + ", " + getCookie() + "}"; } diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java index aa7faf51b1b66..c86bfcb4a88ea 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java @@ -28,8 +28,11 @@ import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.biometrics.BiometricSchedulerProto; +import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; import java.io.PrintWriter; @@ -51,6 +54,8 @@ import java.util.Locale; public class BiometricScheduler { private static final String BASE_TAG = "BiometricScheduler"; + // Number of recent operations to keep in our logs for dumpsys + private static final int LOG_NUM_RECENT_OPERATIONS = 50; /** * Contains all the necessary information for a HAL operation. @@ -200,6 +205,10 @@ public class BiometricScheduler { @VisibleForTesting @Nullable Operation mCurrentOperation; @NonNull private final ArrayDeque mCrashStates; + private int mTotalOperationsHandled; + private final int mRecentOperationsLimit; + @NonNull private final List mRecentOperations; + // Internal callback, notified when an operation is complete. Notifies the requester // that the operation is complete, before performing internal scheduler work (such as // starting the next client). @@ -240,7 +249,12 @@ public class BiometricScheduler { mCurrentOperation.mClientMonitor.getSensorId(), false /* active */); } + if (mRecentOperations.size() >= mRecentOperationsLimit) { + mRecentOperations.remove(0); + } + mRecentOperations.add(mCurrentOperation.mClientMonitor.getProtoEnum()); mCurrentOperation = null; + mTotalOperationsHandled++; startNextOperationIfIdle(); }); } @@ -249,13 +263,15 @@ public class BiometricScheduler { @VisibleForTesting BiometricScheduler(@NonNull String tag, @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher, - @NonNull IBiometricService biometricService) { + @NonNull IBiometricService biometricService, int recentOperationsLimit) { mBiometricTag = tag; mInternalCallback = new InternalCallback(); mGestureAvailabilityDispatcher = gestureAvailabilityDispatcher; mPendingOperations = new ArrayDeque<>(); mBiometricService = biometricService; mCrashStates = new ArrayDeque<>(); + mRecentOperationsLimit = recentOperationsLimit; + mRecentOperations = new ArrayList<>(); } /** @@ -267,7 +283,7 @@ public class BiometricScheduler { public BiometricScheduler(@NonNull String tag, @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { this(tag, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface( - ServiceManager.getService(Context.BIOMETRIC_SERVICE))); + ServiceManager.getService(Context.BIOMETRIC_SERVICE)), LOG_NUM_RECENT_OPERATIONS); } /** @@ -602,6 +618,24 @@ public class BiometricScheduler { } } + public byte[] dumpProtoState(boolean clearSchedulerBuffer) { + final ProtoOutputStream proto = new ProtoOutputStream(); + proto.write(BiometricSchedulerProto.CURRENT_OPERATION, mCurrentOperation != null + ? mCurrentOperation.mClientMonitor.getProtoEnum() : BiometricsProto.CM_NONE); + proto.write(BiometricSchedulerProto.TOTAL_OPERATIONS, mTotalOperationsHandled); + Slog.d(getTag(), "Total operations: " + mTotalOperationsHandled); + for (int i = 0; i < mRecentOperations.size(); i++) { + Slog.d(getTag(), "Operation: " + mRecentOperations.get(i)); + proto.write(BiometricSchedulerProto.RECENT_OPERATIONS, mRecentOperations.get(i)); + } + proto.flush(); + + if (clearSchedulerBuffer) { + mRecentOperations.clear(); + } + return proto.getBytes(); + } + /** * Clears the scheduler of anything work-related. This should be used for example when the * HAL dies. diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java index 8bf9680d60cd1..8d81016dab596 100644 --- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java @@ -24,6 +24,8 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; + import java.util.Arrays; /** @@ -106,4 +108,9 @@ public abstract class EnrollClient extends AcquisitionClient { false /* enrollSuccessful */); super.onError(error, vendorCode); } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_ENROLL; + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java index 6a622c339d0ba..741946e147cde 100644 --- a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java @@ -23,6 +23,8 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; + public abstract class GenerateChallengeClient extends HalClientMonitor { private static final String TAG = "GenerateChallengeClient"; @@ -50,4 +52,9 @@ public abstract class GenerateChallengeClient extends HalClientMonitor { startHalOperation(); } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_GENERATE_CHALLENGE; + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java index 8529e810f9a18..ce24e5efdc072 100644 --- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java @@ -24,6 +24,7 @@ import android.os.IBinder; import android.util.Slog; import com.android.internal.util.FrameworkStatsLog; +import com.android.server.biometrics.BiometricsProto; import java.util.ArrayList; import java.util.List; @@ -166,4 +167,9 @@ public abstract class InternalCleanupClient extends HalClientMonitor public List getUnknownHALTemplates() { return mUnknownHALTemplates; } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_ENUMERATE; + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java b/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java index 630e5eaae377a..cede4a7252467 100644 --- a/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java @@ -24,6 +24,8 @@ import android.hardware.biometrics.IInvalidationCallback; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; + import java.util.Map; /** @@ -70,4 +72,9 @@ public abstract class InvalidationClient extends HalClientMonitor { public RevokeChallengeClient(@NonNull Context context, @NonNull LazyDaemon lazyDaemon, @@ -42,4 +44,9 @@ public abstract class RevokeChallengeClient extends HalClientMonitor { startHalOperation(); mCallback.onClientFinished(this, true /* success */); } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_REVOKE_CHALLENGE; + } } 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 54ab2e5646768..f37cf18a13207 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 @@ -52,8 +52,8 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub { } @Override - public byte[] dumpSensorServiceStateProto() throws RemoteException { - return mFaceService.dumpSensorServiceStateProto(mSensorId); + public byte[] dumpSensorServiceStateProto(boolean clearSchedulerBuffer) throws RemoteException { + return mFaceService.dumpSensorServiceStateProto(mSensorId, clearSchedulerBuffer); } @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 f055d559cc83d..1a63dded4298f 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 @@ -147,13 +147,13 @@ public class FaceService extends SystemService implements BiometricServiceCallba } @Override - public byte[] dumpSensorServiceStateProto(int sensorId) { + public byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); final ProtoOutputStream proto = new ProtoOutputStream(); final ServiceProvider provider = getProviderForSensor(sensorId); if (provider != null) { - provider.dumpProtoState(sensorId, proto); + provider.dumpProtoState(sensorId, proto, clearSchedulerBuffer); } proto.flush(); return proto.getBytes(); @@ -405,7 +405,7 @@ public class FaceService extends SystemService implements BiometricServiceCallba final ProtoOutputStream proto = new ProtoOutputStream(fd); for (ServiceProvider provider : mServiceProviders) { for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) { - provider.dumpProtoState(props.sensorId, proto); + provider.dumpProtoState(props.sensorId, proto, false); } } proto.flush(); 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 51b427d772a11..32428ac131142 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 @@ -121,7 +121,8 @@ public interface ServiceProvider { void scheduleInternalCleanup(int sensorId, int userId); - void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto); + void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, + boolean clearSchedulerBuffer); void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java index 5fb194c75d77c..773647b4bf20b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java @@ -23,6 +23,7 @@ import android.hardware.biometrics.face.ISession; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.sensors.HalClientMonitor; import java.util.Map; @@ -65,4 +66,9 @@ class FaceGetAuthenticatorIdClient extends HalClientMonitor { mAuthenticatorIds.put(getTargetUserId(), authenticatorId); mCallback.onClientFinished(this, true /* success */); } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_GET_AUTHENTICATOR_ID; + } } 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 810489b1c740b..20318e3f836a9 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 @@ -571,9 +571,10 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { } @Override - public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) { + public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, + boolean clearSchedulerBuffer) { if (mSensors.contains(sensorId)) { - mSensors.get(sensorId).dumpProtoState(sensorId, proto); + mSensors.get(sensorId).dumpProtoState(sensorId, proto, clearSchedulerBuffer); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java index f355158d57278..71bac577a4a03 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java @@ -25,6 +25,7 @@ import android.hardware.keymaster.HardwareAuthToken; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.HardwareAuthTokenUtils; import com.android.server.biometrics.sensors.HalClientMonitor; import com.android.server.biometrics.sensors.LockoutCache; @@ -81,4 +82,9 @@ public class FaceResetLockoutClient extends HalClientMonitor { mLockoutResetDispatcher.notifyLockoutResetCallbacks(getSensorId()); mCallback.onClientFinished(this, true /* success */); } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_RESET_LOCKOUT; + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java index b28713e613992..9b00ba63d8460 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java @@ -486,12 +486,13 @@ public class Sensor implements IBinder.DeathRecipient { mTestHalEnabled = enabled; } - void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) { + void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, + boolean clearSchedulerBuffer) { final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES); proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId); proto.write(SensorStateProto.MODALITY, SensorStateProto.FACE); - proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null); + proto.write(SensorStateProto.SCHEDULER, mScheduler.dumpProtoState(clearSchedulerBuffer)); for (UserInfo user : UserManager.get(mContext).getUsers()) { final int userId = user.getUserHandle().getIdentifier(); 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 5e7ddeb64fb4c..7010d9669b8d3 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 @@ -767,12 +767,13 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { } @Override - public void dumpProtoState(int sensorId, ProtoOutputStream proto) { + public void dumpProtoState(int sensorId, ProtoOutputStream proto, + boolean clearSchedulerBuffer) { final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES); proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId); proto.write(SensorStateProto.MODALITY, SensorStateProto.FACE); - proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null); + proto.write(SensorStateProto.SCHEDULER, mScheduler.dumpProtoState(clearSchedulerBuffer)); for (UserInfo user : UserManager.get(mContext).getUsers()) { final int userId = user.getUserHandle().getIdentifier(); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java index 442303b037fb8..722a3b843e12b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java @@ -27,6 +27,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.HalClientMonitor; @@ -88,4 +89,9 @@ public class FaceGetFeatureClient extends HalClientMonitor { boolean getValue() { return mValue; } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_GET_FEATURE; + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java index e0548e073a98a..14a46481ddc62 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java @@ -23,6 +23,7 @@ import android.hardware.biometrics.face.V1_0.IBiometricsFace; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.sensors.HalClientMonitor; import java.util.ArrayList; @@ -71,4 +72,9 @@ public class FaceResetLockoutClient extends HalClientMonitor { mCallback.onClientFinished(this, false /* success */); } } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_RESET_LOCKOUT; + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java index 43560434f1478..6290e001f65b3 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java @@ -25,6 +25,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.HalClientMonitor; @@ -88,4 +89,9 @@ public class FaceSetFeatureClient extends HalClientMonitor { mCallback.onClientFinished(this, false /* success */); } } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_SET_FEATURE; + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java index 0e72f941b4d24..70e20339ce987 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java @@ -24,6 +24,7 @@ import android.os.Environment; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.sensors.HalClientMonitor; import java.io.File; @@ -91,4 +92,9 @@ public class FaceUpdateActiveUserClient extends HalClientMonitor { mCallback.onClientFinished(this, false /* success */); } } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_DETECT_INTERACTION; + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java index 02d4ac3dd98e3..ce1a31899a0ca 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java @@ -23,6 +23,7 @@ import android.hardware.biometrics.fingerprint.ISession; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.sensors.HalClientMonitor; import java.util.Map; @@ -65,4 +66,9 @@ class FingerprintGetAuthenticatorIdClient extends HalClientMonitor { mAuthenticatorIds.put(getTargetUserId(), authenticatorId); mCallback.onClientFinished(this, true /* success */); } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_GET_AUTHENTICATOR_ID; + } } 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 8a666f9acb7fc..727184f183c14 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 @@ -627,9 +627,10 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi } @Override - public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) { + public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, + boolean clearSchedulerBuffer) { if (mSensors.contains(sensorId)) { - mSensors.get(sensorId).dumpProtoState(sensorId, proto); + mSensors.get(sensorId).dumpProtoState(sensorId, proto, clearSchedulerBuffer); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java index cd84cdfda5e5d..ddcfcad59203a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java @@ -25,6 +25,7 @@ import android.hardware.keymaster.HardwareAuthToken; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.HardwareAuthTokenUtils; import com.android.server.biometrics.sensors.HalClientMonitor; import com.android.server.biometrics.sensors.LockoutCache; @@ -76,4 +77,9 @@ class FingerprintResetLockoutClient extends HalClientMonitor { mLockoutResetDispatcher.notifyLockoutResetCallbacks(getSensorId()); mCallback.onClientFinished(this, true /* success */); } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_RESET_LOCKOUT; + } } 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 911f6b48af415..f0e7e1cf5d254 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 @@ -481,12 +481,13 @@ class Sensor implements IBinder.DeathRecipient { mTestHalEnabled = enabled; } - void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) { + void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, + boolean clearSchedulerBuffer) { final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES); proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId); proto.write(SensorStateProto.MODALITY, SensorStateProto.FINGERPRINT); - proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null); + proto.write(SensorStateProto.SCHEDULER, mScheduler.dumpProtoState(clearSchedulerBuffer)); for (UserInfo user : UserManager.get(mContext).getUsers()) { final int userId = user.getUserHandle().getIdentifier(); 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 6cc8687b34265..acc575fb19731 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 @@ -714,12 +714,13 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider } @Override - public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) { + public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, + boolean clearSchedulerBuffer) { final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES); proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId); proto.write(SensorStateProto.MODALITY, SensorStateProto.FINGERPRINT); - proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null); + proto.write(SensorStateProto.SCHEDULER, mScheduler.dumpProtoState(clearSchedulerBuffer)); for (UserInfo user : UserManager.get(mContext).getUsers()) { final int userId = user.getUserHandle().getIdentifier(); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java index 55995ea5b89df..6318139f3aaed 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java @@ -28,6 +28,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.sensors.AcquisitionClient; import com.android.server.biometrics.sensors.AuthenticationConsumer; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; @@ -123,4 +124,9 @@ class FingerprintDetectClient extends AcquisitionClient Slog.e(TAG, "Remote exception when sending onDetected", e); } } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_DETECT_INTERACTION; + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java index f6ec4d9435434..11ffbb27128ac 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java @@ -26,6 +26,7 @@ import android.os.RemoteException; import android.os.SELinux; import android.util.Slog; +import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.sensors.HalClientMonitor; import java.io.File; @@ -121,4 +122,9 @@ public class FingerprintUpdateActiveUserClient extends HalClientMonitor mock(Object.class), BiometricsProto.CM_ENROLL); + mScheduler.scheduleClientMonitor(client); + waitForIdle(); + bsp = getDump(true /* clearSchedulerBuffer */); + assertEquals(BiometricsProto.CM_ENROLL, bsp.currentOperation); + // No operations have completed yet + assertEquals(0, bsp.totalOperations); + assertEquals(0, bsp.recentOperations.length); + // Finish this operation, so the next scheduled one can start + client.getCallback().onClientFinished(client, true); + } + + @Test + public void testProtoDump_fifo() throws Exception { + // Add the first operation + final TestClientMonitor2 client = new TestClientMonitor2(mContext, mToken, + () -> mock(Object.class), BiometricsProto.CM_ENROLL); + mScheduler.scheduleClientMonitor(client); + waitForIdle(); + BiometricSchedulerProto bsp = getDump(false /* clearSchedulerBuffer */); + assertEquals(BiometricsProto.CM_ENROLL, bsp.currentOperation); + // No operations have completed yet + assertEquals(0, bsp.totalOperations); + assertEquals(0, bsp.recentOperations.length); + // Finish this operation, so the next scheduled one can start + client.getCallback().onClientFinished(client, true); + + // Add another operation + final TestClientMonitor2 client2 = new TestClientMonitor2(mContext, mToken, + () -> mock(Object.class), BiometricsProto.CM_REMOVE); + mScheduler.scheduleClientMonitor(client2); + waitForIdle(); + bsp = getDump(false /* clearSchedulerBuffer */); + assertEquals(BiometricsProto.CM_REMOVE, bsp.currentOperation); + assertEquals(1, bsp.totalOperations); // Enroll finished + assertEquals(1, bsp.recentOperations.length); + assertEquals(BiometricsProto.CM_ENROLL, bsp.recentOperations[0]); + client2.getCallback().onClientFinished(client2, true); + + // And another operation + final TestClientMonitor2 client3 = new TestClientMonitor2(mContext, mToken, + () -> mock(Object.class), BiometricsProto.CM_AUTHENTICATE); + mScheduler.scheduleClientMonitor(client3); + waitForIdle(); + bsp = getDump(false /* clearSchedulerBuffer */); + assertEquals(BiometricsProto.CM_AUTHENTICATE, bsp.currentOperation); + assertEquals(2, bsp.totalOperations); + assertEquals(2, bsp.recentOperations.length); + assertEquals(BiometricsProto.CM_ENROLL, bsp.recentOperations[0]); + assertEquals(BiometricsProto.CM_REMOVE, bsp.recentOperations[1]); + + // Finish the last operation, and check that the first operation is removed from the FIFO. + // The test initializes the scheduler with "LOG_NUM_RECENT_OPERATIONS = 2" :) + client3.getCallback().onClientFinished(client3, true); + waitForIdle(); + bsp = getDump(true /* clearSchedulerBuffer */); + assertEquals(3, bsp.totalOperations); + assertEquals(2, bsp.recentOperations.length); + assertEquals(BiometricsProto.CM_REMOVE, bsp.recentOperations[0]); + assertEquals(BiometricsProto.CM_AUTHENTICATE, bsp.recentOperations[1]); + // Nothing is currently running anymore + assertEquals(BiometricsProto.CM_NONE, bsp.currentOperation); + + // RecentOperations queue is cleared (by the previous dump) + bsp = getDump(true /* clearSchedulerBuffer */); + assertEquals(0, bsp.recentOperations.length); + } + + private BiometricSchedulerProto getDump(boolean clearSchedulerBuffer) throws Exception { + return BiometricSchedulerProto.parseFrom(mScheduler.dumpProtoState(clearSchedulerBuffer)); + } + private static class BiometricPromptClientMonitor extends AuthenticationClient { public BiometricPromptClientMonitor(@NonNull Context context, @NonNull IBinder token, @@ -207,6 +293,21 @@ public class BiometricSchedulerTest { } } + private static class TestClientMonitor2 extends TestClientMonitor { + private final int mProtoEnum; + + public TestClientMonitor2(@NonNull Context context, @NonNull IBinder token, + @NonNull LazyDaemon lazyDaemon, int protoEnum) { + super(context, token, lazyDaemon); + mProtoEnum = protoEnum; + } + + @Override + public int getProtoEnum() { + return mProtoEnum; + } + } + private static class TestClientMonitor extends HalClientMonitor { private boolean mUnableToStart; private boolean mStarted; @@ -229,6 +330,13 @@ public class BiometricSchedulerTest { mUnableToStart = true; } + @Override + public int getProtoEnum() { + // Anything other than CM_NONE, which is used to represent "idle". Tests that need + // real proto enums should use TestClientMonitor2 + return BiometricsProto.CM_UPDATE_ACTIVE_USER; + } + @Override public void start(@NonNull Callback callback) { super.start(callback);