Merge "9/n: Add BiometricScheduler proto dump"
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<FaceSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
|
||||
|
||||
@@ -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<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<T> extends AcquisitionClient<T>
|
||||
mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_AUTHENTICATE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() + "}";
|
||||
}
|
||||
|
||||
@@ -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<CrashState> mCrashStates;
|
||||
|
||||
private int mTotalOperationsHandled;
|
||||
private final int mRecentOperationsLimit;
|
||||
@NonNull private final List<Integer> 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.
|
||||
|
||||
@@ -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<T> extends AcquisitionClient<T> {
|
||||
false /* enrollSuccessful */);
|
||||
super.onError(error, vendorCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_ENROLL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<T> extends HalClientMonitor<T> {
|
||||
|
||||
private static final String TAG = "GenerateChallengeClient";
|
||||
@@ -50,4 +52,9 @@ public abstract class GenerateChallengeClient<T> extends HalClientMonitor<T> {
|
||||
|
||||
startHalOperation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_GENERATE_CHALLENGE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<S extends BiometricAuthenticator.Ide
|
||||
}
|
||||
((EnumerateConsumer) mCurrentTask).onEnumerationResult(identifier, remaining);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_INTERNAL_CLEANUP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -123,4 +124,9 @@ public abstract class InternalEnumerateClient<T> extends HalClientMonitor<T>
|
||||
public List<BiometricAuthenticator.Identifier> getUnknownHALTemplates() {
|
||||
return mUnknownHALTemplates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_ENUMERATE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<S extends BiometricAuthenticator.Identi
|
||||
public void unableToStart() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_INVALIDATE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import android.hardware.biometrics.BiometricManager;
|
||||
import android.hardware.biometrics.BiometricsProtoEnums;
|
||||
import android.hardware.biometrics.IInvalidationCallback;
|
||||
|
||||
import com.android.server.biometrics.BiometricsProto;
|
||||
|
||||
/**
|
||||
* ClientMonitor subclass responsible for coordination of authenticatorId invalidation of other
|
||||
* sensors. See {@link InvalidationClient} for the ClientMonitor subclass responsible for initiating
|
||||
@@ -89,4 +91,9 @@ public class InvalidationRequesterClient<S extends BiometricAuthenticator.Identi
|
||||
mBiometricManager.invalidateAuthenticatorIds(getTargetUserId(), getSensorId(),
|
||||
mInvalidationCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_INVALIDATION_REQUESTER;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.biometrics.BiometricsProto;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -90,4 +92,9 @@ public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier,
|
||||
mCallback.onClientFinished(this, true /* success */);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_REMOVE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricsProtoEnums;
|
||||
import android.os.IBinder;
|
||||
|
||||
import com.android.server.biometrics.BiometricsProto;
|
||||
|
||||
public abstract class RevokeChallengeClient<T> extends HalClientMonitor<T> {
|
||||
|
||||
public RevokeChallengeClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
|
||||
@@ -42,4 +44,9 @@ public abstract class RevokeChallengeClient<T> extends HalClientMonitor<T> {
|
||||
startHalOperation();
|
||||
mCallback.onClientFinished(this, true /* success */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_REVOKE_CHALLENGE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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<ISession> {
|
||||
mAuthenticatorIds.put(getTargetUserId(), authenticatorId);
|
||||
mCallback.onClientFinished(this, true /* success */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_GET_AUTHENTICATOR_ID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ISession> {
|
||||
mLockoutResetDispatcher.notifyLockoutResetCallbacks(getSensorId());
|
||||
mCallback.onClientFinished(this, true /* success */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_RESET_LOCKOUT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<IBiometricsFace> {
|
||||
boolean getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_GET_FEATURE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<IBiometricsFace> {
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_RESET_LOCKOUT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<IBiometricsFace> {
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_SET_FEATURE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<IBiometricsFace
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_UPDATE_ACTIVE_USER;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +53,8 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] dumpSensorServiceStateProto() throws RemoteException {
|
||||
return mFingerprintService.dumpSensorServiceStateProto(mSensorId);
|
||||
public byte[] dumpSensorServiceStateProto(boolean clearSchedulerBuffer) throws RemoteException {
|
||||
return mFingerprintService.dumpSensorServiceStateProto(mSensorId, clearSchedulerBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -116,13 +116,13 @@ public class FingerprintService extends SystemService implements BiometricServic
|
||||
}
|
||||
|
||||
@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();
|
||||
@@ -419,7 +419,7 @@ public class FingerprintService extends SystemService implements BiometricServic
|
||||
for (ServiceProvider provider : mServiceProviders) {
|
||||
for (FingerprintSensorPropertiesInternal props
|
||||
: provider.getSensorProperties()) {
|
||||
provider.dumpProtoState(props.sensorId, proto);
|
||||
provider.dumpProtoState(props.sensorId, proto, false);
|
||||
}
|
||||
}
|
||||
proto.flush();
|
||||
|
||||
@@ -128,7 +128,8 @@ public interface ServiceProvider {
|
||||
|
||||
void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller);
|
||||
|
||||
void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto);
|
||||
void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
|
||||
boolean clearSchedulerBuffer);
|
||||
|
||||
void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd);
|
||||
|
||||
|
||||
@@ -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.AcquisitionClient;
|
||||
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
|
||||
import com.android.server.biometrics.sensors.fingerprint.UdfpsHelper;
|
||||
@@ -91,4 +92,9 @@ class FingerprintDetectClient extends AcquisitionClient<ISession> {
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_DETECT_INTERACTION;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ISession> {
|
||||
mAuthenticatorIds.put(getTargetUserId(), authenticatorId);
|
||||
mCallback.onClientFinished(this, true /* success */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_GET_AUTHENTICATOR_ID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ISession> {
|
||||
mLockoutResetDispatcher.notifyLockoutResetCallbacks(getSensorId());
|
||||
mCallback.onClientFinished(this, true /* success */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_RESET_LOCKOUT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<IBiometricsFingerprint>
|
||||
Slog.e(TAG, "Remote exception when sending onDetected", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_DETECT_INTERACTION;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<IBiometr
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_UPDATE_ACTIVE_USER;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] dumpSensorServiceStateProto() throws RemoteException {
|
||||
public byte[] dumpSensorServiceStateProto(boolean clearSchedulerBuffer) throws RemoteException {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,11 +34,14 @@ import android.hardware.biometrics.IBiometricService;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.server.biometrics.nano.BiometricSchedulerProto;
|
||||
import com.android.server.biometrics.nano.BiometricsProto;
|
||||
import com.android.server.biometrics.sensors.BiometricScheduler.Operation;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -52,6 +55,7 @@ public class BiometricSchedulerTest {
|
||||
|
||||
private static final String TAG = "BiometricSchedulerTest";
|
||||
private static final int TEST_SENSOR_ID = 1;
|
||||
private static final int LOG_NUM_RECENT_OPERATIONS = 2;
|
||||
|
||||
private BiometricScheduler mScheduler;
|
||||
private IBinder mToken;
|
||||
@@ -66,7 +70,7 @@ public class BiometricSchedulerTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mToken = new Binder();
|
||||
mScheduler = new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */,
|
||||
mBiometricService);
|
||||
mBiometricService, LOG_NUM_RECENT_OPERATIONS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -186,6 +190,88 @@ public class BiometricSchedulerTest {
|
||||
assertNull(mScheduler.mCurrentOperation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProtoDump_singleCurrentOperation() throws Exception {
|
||||
// Nothing so far
|
||||
BiometricSchedulerProto bsp = getDump(true /* clearSchedulerBuffer */);
|
||||
assertEquals(BiometricsProto.CM_NONE, bsp.currentOperation);
|
||||
assertEquals(0, bsp.totalOperations);
|
||||
assertEquals(0, bsp.recentOperations.length);
|
||||
|
||||
// Pretend the scheduler is busy enrolling, and check the proto dump again.
|
||||
final TestClientMonitor2 client = new TestClientMonitor2(mContext, mToken,
|
||||
() -> 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<Object> {
|
||||
|
||||
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<Object> lazyDaemon, int protoEnum) {
|
||||
super(context, token, lazyDaemon);
|
||||
mProtoEnum = protoEnum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return mProtoEnum;
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestClientMonitor extends HalClientMonitor<Object> {
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user