Loading services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java 0 → 100644 +126 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2022 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.log; import android.hardware.biometrics.BiometricsProtoEnums; import android.util.Slog; import com.android.internal.util.FrameworkStatsLog; /** * Wrapper for {@link FrameworkStatsLog} to isolate the testable parts. */ public class BiometricFrameworkStatsLogger { private static final String TAG = "BiometricFrameworkStatsLogger"; private static final BiometricFrameworkStatsLogger sInstance = new BiometricFrameworkStatsLogger(); private BiometricFrameworkStatsLogger() {} public static BiometricFrameworkStatsLogger getInstance() { return sInstance; } /** {@see FrameworkStatsLog.BIOMETRIC_ACQUIRED}. */ public void acquired( int statsModality, int statsAction, int statsClient, boolean isDebug, int acquiredInfo, int vendorCode, boolean isCrypto, int targetUserId) { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ACQUIRED, statsModality, targetUserId, isCrypto, statsAction, statsClient, acquiredInfo, vendorCode, isDebug, -1 /* sensorId */); } /** {@see FrameworkStatsLog.BIOMETRIC_AUTHENTICATED}. */ public void authenticate( int statsModality, int statsAction, int statsClient, boolean isDebug, long latency, boolean authenticated, int authState, boolean requireConfirmation, boolean isCrypto, int targetUserId, boolean isBiometricPrompt, float ambientLightLux) { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_AUTHENTICATED, statsModality, targetUserId, isCrypto, statsClient, requireConfirmation, authState, sanitizeLatency(latency), isDebug, -1 /* sensorId */, ambientLightLux); } /** {@see FrameworkStatsLog.BIOMETRIC_ENROLLED}. */ public void enroll(int statsModality, int statsAction, int statsClient, int targetUserId, long latency, boolean enrollSuccessful, float ambientLightLux) { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ENROLLED, statsModality, targetUserId, sanitizeLatency(latency), enrollSuccessful, -1, /* sensorId */ ambientLightLux); } /** {@see FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED}. */ public void error( int statsModality, int statsAction, int statsClient, boolean isDebug, long latency, int error, int vendorCode, boolean isCrypto, int targetUserId) { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED, statsModality, targetUserId, isCrypto, statsAction, statsClient, error, vendorCode, isDebug, sanitizeLatency(latency), -1 /* sensorId */); } /** {@see FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED}. */ public void reportUnknownTemplateEnrolledHal(int statsModality) { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality, BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL, -1 /* sensorId */); } /** {@see FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED}. */ public void reportUnknownTemplateEnrolledFramework(int statsModality) { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality, BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK, -1 /* sensorId */); } private long sanitizeLatency(long latency) { if (latency < 0) { Slog.w(TAG, "found a negative latency : " + latency); return -1; } return latency; } } services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java→services/core/java/com/android/server/biometrics/log/BiometricLogger.java +68 −118 Original line number Original line Diff line number Diff line /* /* * Copyright (C) 2020 The Android Open Source Project * Copyright (C) 2022 The Android Open Source Project * * * Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License. Loading @@ -14,7 +14,7 @@ * limitations under the License. * limitations under the License. */ */ package com.android.server.biometrics.sensors; package com.android.server.biometrics.log; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; Loading @@ -29,71 +29,28 @@ import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager; import android.util.Slog; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.FrameworkStatsLog; import com.android.server.biometrics.Utils; import com.android.server.biometrics.Utils; /** /** * Abstract class that adds logging functionality to the ClientMonitor classes. * Logger for all reported Biometric framework events. */ */ public abstract class LoggableMonitor { public class BiometricLogger { public static final String TAG = "Biometrics/LoggableMonitor"; public static final String TAG = "BiometricLogger"; public static final boolean DEBUG = false; public static final boolean DEBUG = false; final int mStatsModality; private final int mStatsModality; private final int mStatsAction; private final int mStatsAction; private final int mStatsClient; private final int mStatsClient; private final BiometricFrameworkStatsLogger mSink; @NonNull private final SensorManager mSensorManager; @NonNull private final SensorManager mSensorManager; private long mFirstAcquireTimeMs; private long mFirstAcquireTimeMs; private boolean mLightSensorEnabled = false; private boolean mLightSensorEnabled = false; private boolean mShouldLogMetrics = true; private boolean mShouldLogMetrics = true; /** * Probe for loggable attributes that can be continuously monitored, such as ambient light. * * Disable probes when the sensors are in states that are not interesting for monitoring * purposes to save power. */ protected interface Probe { /** Ensure the probe is actively sampling for new data. */ void enable(); /** Stop sampling data. */ void disable(); } /** * Client monitor callback that exposes a probe. * * Disables the probe when the operation completes. */ protected static class CallbackWithProbe<T extends Probe> implements BaseClientMonitor.Callback { private final boolean mStartWithClient; private final T mProbe; public CallbackWithProbe(@NonNull T probe, boolean startWithClient) { mProbe = probe; mStartWithClient = startWithClient; } @Override public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { if (mStartWithClient) { mProbe.enable(); } } @Override public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) { mProbe.disable(); } @NonNull public T getProbe() { return mProbe; } } private class ALSProbe implements Probe { private class ALSProbe implements Probe { @Override @Override public void enable() { public void enable() { Loading Loading @@ -128,26 +85,30 @@ public abstract class LoggableMonitor { * @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants. * @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants. * @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants. * @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants. */ */ public LoggableMonitor(@NonNull Context context, int statsModality, int statsAction, public BiometricLogger( int statsClient) { @NonNull Context context, int statsModality, int statsAction, int statsClient) { this(statsModality, statsAction, statsClient, BiometricFrameworkStatsLogger.getInstance(), context.getSystemService(SensorManager.class)); } @VisibleForTesting BiometricLogger( int statsModality, int statsAction, int statsClient, BiometricFrameworkStatsLogger logSink, SensorManager sensorManager) { mStatsModality = statsModality; mStatsModality = statsModality; mStatsAction = statsAction; mStatsAction = statsAction; mStatsClient = statsClient; mStatsClient = statsClient; mSensorManager = context.getSystemService(SensorManager.class); mSink = logSink; mSensorManager = sensorManager; } } /** /** Disable logging metrics and only log critical events, such as system health issues. */ * Only valid for AuthenticationClient. public void disableMetrics() { * @return true if the client is authenticating for a crypto operation. mShouldLogMetrics = false; */ protected boolean isCryptoOperation() { return false; } protected void setShouldLog(boolean shouldLog) { mShouldLogMetrics = shouldLog; } } /** {@link BiometricsProtoEnums} CLIENT_* constants */ public int getStatsClient() { public int getStatsClient() { return mStatsClient; return mStatsClient; } } Loading @@ -171,8 +132,9 @@ public abstract class LoggableMonitor { return shouldSkipLogging; return shouldSkipLogging; } } protected final void logOnAcquired(Context context, int acquiredInfo, int vendorCode, /** Log an acquisition event. */ int targetUserId) { public void logOnAcquired(Context context, int acquiredInfo, int vendorCode, boolean isCrypto, int targetUserId) { if (!mShouldLogMetrics) { if (!mShouldLogMetrics) { return; return; } } Loading @@ -192,7 +154,7 @@ public abstract class LoggableMonitor { if (DEBUG) { if (DEBUG) { Slog.v(TAG, "Acquired! Modality: " + mStatsModality Slog.v(TAG, "Acquired! Modality: " + mStatsModality + ", User: " + targetUserId + ", User: " + targetUserId + ", IsCrypto: " + isCryptoOperation() + ", IsCrypto: " + isCrypto + ", Action: " + mStatsAction + ", Action: " + mStatsAction + ", Client: " + mStatsClient + ", Client: " + mStatsClient + ", AcquiredInfo: " + acquiredInfo + ", AcquiredInfo: " + acquiredInfo Loading @@ -203,19 +165,14 @@ public abstract class LoggableMonitor { return; return; } } FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ACQUIRED, mSink.acquired(mStatsModality, mStatsAction, mStatsClient, mStatsModality, targetUserId, isCryptoOperation(), mStatsAction, mStatsClient, acquiredInfo, vendorCode, Utils.isDebugEnabled(context, targetUserId), Utils.isDebugEnabled(context, targetUserId), -1 /* sensorId */); acquiredInfo, vendorCode, isCrypto, targetUserId); } } protected final void logOnError(Context context, int error, int vendorCode, int targetUserId) { /** Log an error during an operation. */ public void logOnError(Context context, int error, int vendorCode, boolean isCrypto, int targetUserId) { if (!mShouldLogMetrics) { if (!mShouldLogMetrics) { return; return; } } Loading @@ -226,7 +183,7 @@ public abstract class LoggableMonitor { if (DEBUG) { if (DEBUG) { Slog.v(TAG, "Error! Modality: " + mStatsModality Slog.v(TAG, "Error! Modality: " + mStatsModality + ", User: " + targetUserId + ", User: " + targetUserId + ", IsCrypto: " + isCryptoOperation() + ", IsCrypto: " + isCrypto + ", Action: " + mStatsAction + ", Action: " + mStatsAction + ", Client: " + mStatsClient + ", Client: " + mStatsClient + ", Error: " + error + ", Error: " + error Loading @@ -240,21 +197,15 @@ public abstract class LoggableMonitor { return; return; } } FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED, mSink.error(mStatsModality, mStatsAction, mStatsClient, mStatsModality, Utils.isDebugEnabled(context, targetUserId), latency, targetUserId, error, vendorCode, isCrypto, targetUserId); isCryptoOperation(), mStatsAction, mStatsClient, error, vendorCode, Utils.isDebugEnabled(context, targetUserId), sanitizeLatency(latency), -1 /* sensorId */); } } protected final void logOnAuthenticated(Context context, boolean authenticated, /** Log authentication attempt. */ boolean requireConfirmation, int targetUserId, boolean isBiometricPrompt) { public void logOnAuthenticated(Context context, boolean authenticated, boolean requireConfirmation, boolean isCrypto, int targetUserId, boolean isBiometricPrompt) { if (!mShouldLogMetrics) { if (!mShouldLogMetrics) { return; return; } } Loading @@ -279,7 +230,7 @@ public abstract class LoggableMonitor { if (DEBUG) { if (DEBUG) { Slog.v(TAG, "Authenticated! Modality: " + mStatsModality Slog.v(TAG, "Authenticated! Modality: " + mStatsModality + ", User: " + targetUserId + ", User: " + targetUserId + ", IsCrypto: " + isCryptoOperation() + ", IsCrypto: " + isCrypto + ", Client: " + mStatsClient + ", Client: " + mStatsClient + ", RequireConfirmation: " + requireConfirmation + ", RequireConfirmation: " + requireConfirmation + ", State: " + authState + ", State: " + authState Loading @@ -293,20 +244,14 @@ public abstract class LoggableMonitor { return; return; } } FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_AUTHENTICATED, mSink.authenticate(mStatsModality, mStatsAction, mStatsClient, mStatsModality, targetUserId, isCryptoOperation(), mStatsClient, requireConfirmation, authState, sanitizeLatency(latency), Utils.isDebugEnabled(context, targetUserId), Utils.isDebugEnabled(context, targetUserId), -1 /* sensorId */, latency, authenticated, authState, requireConfirmation, isCrypto, mLastAmbientLux /* ambientLightLux */); targetUserId, isBiometricPrompt, mLastAmbientLux); } } protected final void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) { /** Log enrollment outcome. */ public void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) { if (!mShouldLogMetrics) { if (!mShouldLogMetrics) { return; return; } } Loading @@ -326,25 +271,30 @@ public abstract class LoggableMonitor { return; return; } } FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ENROLLED, mSink.enroll(mStatsModality, mStatsAction, mStatsClient, mStatsModality, targetUserId, latency, enrollSuccessful, mLastAmbientLux); targetUserId, sanitizeLatency(latency), enrollSuccessful, -1, /* sensorId */ mLastAmbientLux /* ambientLightLux */); } } private long sanitizeLatency(long latency) { /** Report unexpected enrollment reported by the HAL. */ if (latency < 0) { public void logUnknownEnrollmentInHal() { Slog.w(TAG, "found a negative latency : " + latency); if (shouldSkipLogging()) { return -1; return; } } return latency; mSink.reportUnknownTemplateEnrolledHal(mStatsModality); } /** Report unknown enrollment in framework settings */ public void logUnknownEnrollmentInFramework() { if (shouldSkipLogging()) { return; } mSink.reportUnknownTemplateEnrolledFramework(mStatsModality); } } /** /** * Get a callback to start/stop ALS capture when client runs. * Get a callback to start/stop ALS capture when a client runs. * * * If the probe should not run for the entire operation, do not set startWithClient and * If the probe should not run for the entire operation, do not set startWithClient and * start/stop the problem when needed. * start/stop the problem when needed. Loading @@ -352,7 +302,7 @@ public abstract class LoggableMonitor { * @param startWithClient if probe should start automatically when the operation starts. * @param startWithClient if probe should start automatically when the operation starts. */ */ @NonNull @NonNull protected CallbackWithProbe<Probe> createALSCallback(boolean startWithClient) { public CallbackWithProbe<Probe> createALSCallback(boolean startWithClient) { return new CallbackWithProbe<>(new ALSProbe(), startWithClient); return new CallbackWithProbe<>(new ALSProbe(), startWithClient); } } Loading services/core/java/com/android/server/biometrics/log/CallbackWithProbe.java 0 → 100644 +55 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2022 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.log; import android.annotation.NonNull; import com.android.server.biometrics.sensors.BaseClientMonitor; /** * Client monitor callback that exposes a probe. * * Disables the probe when the operation completes. * * @param <T> probe type */ public class CallbackWithProbe<T extends Probe> implements BaseClientMonitor.Callback { private final boolean mStartWithClient; private final T mProbe; public CallbackWithProbe(@NonNull T probe, boolean startWithClient) { mProbe = probe; mStartWithClient = startWithClient; } @Override public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { if (mStartWithClient) { mProbe.enable(); } } @Override public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) { mProbe.disable(); } @NonNull public T getProbe() { return mProbe; } } services/core/java/com/android/server/biometrics/log/Probe.java 0 → 100644 +30 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2022 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.log; /** * Probe for loggable attributes that can be continuously monitored, such as ambient light. * * Disable probes when the sensors are in states that are not interesting for monitoring * purposes to save power. */ public interface Probe { /** Ensure the probe is actively sampling for new data. */ void enable(); /** Stop sampling data. */ void disable(); } services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java +4 −2 Original line number Original line Diff line number Diff line Loading @@ -105,7 +105,8 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement // that do not handle lockout under the HAL. In these cases, ensure that the framework only // that do not handle lockout under the HAL. In these cases, ensure that the framework only // sends errors once per ClientMonitor. // sends errors once per ClientMonitor. if (mShouldSendErrorToClient) { if (mShouldSendErrorToClient) { logOnError(getContext(), errorCode, vendorCode, getTargetUserId()); getLogger().logOnError(getContext(), errorCode, vendorCode, isCryptoOperation(), getTargetUserId()); try { try { if (getListener() != null) { if (getListener() != null) { mShouldSendErrorToClient = false; mShouldSendErrorToClient = false; Loading Loading @@ -163,7 +164,8 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement protected final void onAcquiredInternal(int acquiredInfo, int vendorCode, protected final void onAcquiredInternal(int acquiredInfo, int vendorCode, boolean shouldSend) { boolean shouldSend) { super.logOnAcquired(getContext(), acquiredInfo, vendorCode, getTargetUserId()); getLogger().logOnAcquired(getContext(), acquiredInfo, vendorCode, isCryptoOperation(), getTargetUserId()); if (DEBUG) { if (DEBUG) { Slog.v(TAG, "Acquired: " + acquiredInfo + " " + vendorCode Slog.v(TAG, "Acquired: " + acquiredInfo + " " + vendorCode + ", shouldSend: " + shouldSend); + ", shouldSend: " + shouldSend); Loading Loading
services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java 0 → 100644 +126 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2022 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.log; import android.hardware.biometrics.BiometricsProtoEnums; import android.util.Slog; import com.android.internal.util.FrameworkStatsLog; /** * Wrapper for {@link FrameworkStatsLog} to isolate the testable parts. */ public class BiometricFrameworkStatsLogger { private static final String TAG = "BiometricFrameworkStatsLogger"; private static final BiometricFrameworkStatsLogger sInstance = new BiometricFrameworkStatsLogger(); private BiometricFrameworkStatsLogger() {} public static BiometricFrameworkStatsLogger getInstance() { return sInstance; } /** {@see FrameworkStatsLog.BIOMETRIC_ACQUIRED}. */ public void acquired( int statsModality, int statsAction, int statsClient, boolean isDebug, int acquiredInfo, int vendorCode, boolean isCrypto, int targetUserId) { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ACQUIRED, statsModality, targetUserId, isCrypto, statsAction, statsClient, acquiredInfo, vendorCode, isDebug, -1 /* sensorId */); } /** {@see FrameworkStatsLog.BIOMETRIC_AUTHENTICATED}. */ public void authenticate( int statsModality, int statsAction, int statsClient, boolean isDebug, long latency, boolean authenticated, int authState, boolean requireConfirmation, boolean isCrypto, int targetUserId, boolean isBiometricPrompt, float ambientLightLux) { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_AUTHENTICATED, statsModality, targetUserId, isCrypto, statsClient, requireConfirmation, authState, sanitizeLatency(latency), isDebug, -1 /* sensorId */, ambientLightLux); } /** {@see FrameworkStatsLog.BIOMETRIC_ENROLLED}. */ public void enroll(int statsModality, int statsAction, int statsClient, int targetUserId, long latency, boolean enrollSuccessful, float ambientLightLux) { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ENROLLED, statsModality, targetUserId, sanitizeLatency(latency), enrollSuccessful, -1, /* sensorId */ ambientLightLux); } /** {@see FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED}. */ public void error( int statsModality, int statsAction, int statsClient, boolean isDebug, long latency, int error, int vendorCode, boolean isCrypto, int targetUserId) { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED, statsModality, targetUserId, isCrypto, statsAction, statsClient, error, vendorCode, isDebug, sanitizeLatency(latency), -1 /* sensorId */); } /** {@see FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED}. */ public void reportUnknownTemplateEnrolledHal(int statsModality) { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality, BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL, -1 /* sensorId */); } /** {@see FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED}. */ public void reportUnknownTemplateEnrolledFramework(int statsModality) { FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality, BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK, -1 /* sensorId */); } private long sanitizeLatency(long latency) { if (latency < 0) { Slog.w(TAG, "found a negative latency : " + latency); return -1; } return latency; } }
services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java→services/core/java/com/android/server/biometrics/log/BiometricLogger.java +68 −118 Original line number Original line Diff line number Diff line /* /* * Copyright (C) 2020 The Android Open Source Project * Copyright (C) 2022 The Android Open Source Project * * * Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License. Loading @@ -14,7 +14,7 @@ * limitations under the License. * limitations under the License. */ */ package com.android.server.biometrics.sensors; package com.android.server.biometrics.log; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; Loading @@ -29,71 +29,28 @@ import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager; import android.util.Slog; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.FrameworkStatsLog; import com.android.server.biometrics.Utils; import com.android.server.biometrics.Utils; /** /** * Abstract class that adds logging functionality to the ClientMonitor classes. * Logger for all reported Biometric framework events. */ */ public abstract class LoggableMonitor { public class BiometricLogger { public static final String TAG = "Biometrics/LoggableMonitor"; public static final String TAG = "BiometricLogger"; public static final boolean DEBUG = false; public static final boolean DEBUG = false; final int mStatsModality; private final int mStatsModality; private final int mStatsAction; private final int mStatsAction; private final int mStatsClient; private final int mStatsClient; private final BiometricFrameworkStatsLogger mSink; @NonNull private final SensorManager mSensorManager; @NonNull private final SensorManager mSensorManager; private long mFirstAcquireTimeMs; private long mFirstAcquireTimeMs; private boolean mLightSensorEnabled = false; private boolean mLightSensorEnabled = false; private boolean mShouldLogMetrics = true; private boolean mShouldLogMetrics = true; /** * Probe for loggable attributes that can be continuously monitored, such as ambient light. * * Disable probes when the sensors are in states that are not interesting for monitoring * purposes to save power. */ protected interface Probe { /** Ensure the probe is actively sampling for new data. */ void enable(); /** Stop sampling data. */ void disable(); } /** * Client monitor callback that exposes a probe. * * Disables the probe when the operation completes. */ protected static class CallbackWithProbe<T extends Probe> implements BaseClientMonitor.Callback { private final boolean mStartWithClient; private final T mProbe; public CallbackWithProbe(@NonNull T probe, boolean startWithClient) { mProbe = probe; mStartWithClient = startWithClient; } @Override public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { if (mStartWithClient) { mProbe.enable(); } } @Override public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) { mProbe.disable(); } @NonNull public T getProbe() { return mProbe; } } private class ALSProbe implements Probe { private class ALSProbe implements Probe { @Override @Override public void enable() { public void enable() { Loading Loading @@ -128,26 +85,30 @@ public abstract class LoggableMonitor { * @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants. * @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants. * @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants. * @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants. */ */ public LoggableMonitor(@NonNull Context context, int statsModality, int statsAction, public BiometricLogger( int statsClient) { @NonNull Context context, int statsModality, int statsAction, int statsClient) { this(statsModality, statsAction, statsClient, BiometricFrameworkStatsLogger.getInstance(), context.getSystemService(SensorManager.class)); } @VisibleForTesting BiometricLogger( int statsModality, int statsAction, int statsClient, BiometricFrameworkStatsLogger logSink, SensorManager sensorManager) { mStatsModality = statsModality; mStatsModality = statsModality; mStatsAction = statsAction; mStatsAction = statsAction; mStatsClient = statsClient; mStatsClient = statsClient; mSensorManager = context.getSystemService(SensorManager.class); mSink = logSink; mSensorManager = sensorManager; } } /** /** Disable logging metrics and only log critical events, such as system health issues. */ * Only valid for AuthenticationClient. public void disableMetrics() { * @return true if the client is authenticating for a crypto operation. mShouldLogMetrics = false; */ protected boolean isCryptoOperation() { return false; } protected void setShouldLog(boolean shouldLog) { mShouldLogMetrics = shouldLog; } } /** {@link BiometricsProtoEnums} CLIENT_* constants */ public int getStatsClient() { public int getStatsClient() { return mStatsClient; return mStatsClient; } } Loading @@ -171,8 +132,9 @@ public abstract class LoggableMonitor { return shouldSkipLogging; return shouldSkipLogging; } } protected final void logOnAcquired(Context context, int acquiredInfo, int vendorCode, /** Log an acquisition event. */ int targetUserId) { public void logOnAcquired(Context context, int acquiredInfo, int vendorCode, boolean isCrypto, int targetUserId) { if (!mShouldLogMetrics) { if (!mShouldLogMetrics) { return; return; } } Loading @@ -192,7 +154,7 @@ public abstract class LoggableMonitor { if (DEBUG) { if (DEBUG) { Slog.v(TAG, "Acquired! Modality: " + mStatsModality Slog.v(TAG, "Acquired! Modality: " + mStatsModality + ", User: " + targetUserId + ", User: " + targetUserId + ", IsCrypto: " + isCryptoOperation() + ", IsCrypto: " + isCrypto + ", Action: " + mStatsAction + ", Action: " + mStatsAction + ", Client: " + mStatsClient + ", Client: " + mStatsClient + ", AcquiredInfo: " + acquiredInfo + ", AcquiredInfo: " + acquiredInfo Loading @@ -203,19 +165,14 @@ public abstract class LoggableMonitor { return; return; } } FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ACQUIRED, mSink.acquired(mStatsModality, mStatsAction, mStatsClient, mStatsModality, targetUserId, isCryptoOperation(), mStatsAction, mStatsClient, acquiredInfo, vendorCode, Utils.isDebugEnabled(context, targetUserId), Utils.isDebugEnabled(context, targetUserId), -1 /* sensorId */); acquiredInfo, vendorCode, isCrypto, targetUserId); } } protected final void logOnError(Context context, int error, int vendorCode, int targetUserId) { /** Log an error during an operation. */ public void logOnError(Context context, int error, int vendorCode, boolean isCrypto, int targetUserId) { if (!mShouldLogMetrics) { if (!mShouldLogMetrics) { return; return; } } Loading @@ -226,7 +183,7 @@ public abstract class LoggableMonitor { if (DEBUG) { if (DEBUG) { Slog.v(TAG, "Error! Modality: " + mStatsModality Slog.v(TAG, "Error! Modality: " + mStatsModality + ", User: " + targetUserId + ", User: " + targetUserId + ", IsCrypto: " + isCryptoOperation() + ", IsCrypto: " + isCrypto + ", Action: " + mStatsAction + ", Action: " + mStatsAction + ", Client: " + mStatsClient + ", Client: " + mStatsClient + ", Error: " + error + ", Error: " + error Loading @@ -240,21 +197,15 @@ public abstract class LoggableMonitor { return; return; } } FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED, mSink.error(mStatsModality, mStatsAction, mStatsClient, mStatsModality, Utils.isDebugEnabled(context, targetUserId), latency, targetUserId, error, vendorCode, isCrypto, targetUserId); isCryptoOperation(), mStatsAction, mStatsClient, error, vendorCode, Utils.isDebugEnabled(context, targetUserId), sanitizeLatency(latency), -1 /* sensorId */); } } protected final void logOnAuthenticated(Context context, boolean authenticated, /** Log authentication attempt. */ boolean requireConfirmation, int targetUserId, boolean isBiometricPrompt) { public void logOnAuthenticated(Context context, boolean authenticated, boolean requireConfirmation, boolean isCrypto, int targetUserId, boolean isBiometricPrompt) { if (!mShouldLogMetrics) { if (!mShouldLogMetrics) { return; return; } } Loading @@ -279,7 +230,7 @@ public abstract class LoggableMonitor { if (DEBUG) { if (DEBUG) { Slog.v(TAG, "Authenticated! Modality: " + mStatsModality Slog.v(TAG, "Authenticated! Modality: " + mStatsModality + ", User: " + targetUserId + ", User: " + targetUserId + ", IsCrypto: " + isCryptoOperation() + ", IsCrypto: " + isCrypto + ", Client: " + mStatsClient + ", Client: " + mStatsClient + ", RequireConfirmation: " + requireConfirmation + ", RequireConfirmation: " + requireConfirmation + ", State: " + authState + ", State: " + authState Loading @@ -293,20 +244,14 @@ public abstract class LoggableMonitor { return; return; } } FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_AUTHENTICATED, mSink.authenticate(mStatsModality, mStatsAction, mStatsClient, mStatsModality, targetUserId, isCryptoOperation(), mStatsClient, requireConfirmation, authState, sanitizeLatency(latency), Utils.isDebugEnabled(context, targetUserId), Utils.isDebugEnabled(context, targetUserId), -1 /* sensorId */, latency, authenticated, authState, requireConfirmation, isCrypto, mLastAmbientLux /* ambientLightLux */); targetUserId, isBiometricPrompt, mLastAmbientLux); } } protected final void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) { /** Log enrollment outcome. */ public void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) { if (!mShouldLogMetrics) { if (!mShouldLogMetrics) { return; return; } } Loading @@ -326,25 +271,30 @@ public abstract class LoggableMonitor { return; return; } } FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ENROLLED, mSink.enroll(mStatsModality, mStatsAction, mStatsClient, mStatsModality, targetUserId, latency, enrollSuccessful, mLastAmbientLux); targetUserId, sanitizeLatency(latency), enrollSuccessful, -1, /* sensorId */ mLastAmbientLux /* ambientLightLux */); } } private long sanitizeLatency(long latency) { /** Report unexpected enrollment reported by the HAL. */ if (latency < 0) { public void logUnknownEnrollmentInHal() { Slog.w(TAG, "found a negative latency : " + latency); if (shouldSkipLogging()) { return -1; return; } } return latency; mSink.reportUnknownTemplateEnrolledHal(mStatsModality); } /** Report unknown enrollment in framework settings */ public void logUnknownEnrollmentInFramework() { if (shouldSkipLogging()) { return; } mSink.reportUnknownTemplateEnrolledFramework(mStatsModality); } } /** /** * Get a callback to start/stop ALS capture when client runs. * Get a callback to start/stop ALS capture when a client runs. * * * If the probe should not run for the entire operation, do not set startWithClient and * If the probe should not run for the entire operation, do not set startWithClient and * start/stop the problem when needed. * start/stop the problem when needed. Loading @@ -352,7 +302,7 @@ public abstract class LoggableMonitor { * @param startWithClient if probe should start automatically when the operation starts. * @param startWithClient if probe should start automatically when the operation starts. */ */ @NonNull @NonNull protected CallbackWithProbe<Probe> createALSCallback(boolean startWithClient) { public CallbackWithProbe<Probe> createALSCallback(boolean startWithClient) { return new CallbackWithProbe<>(new ALSProbe(), startWithClient); return new CallbackWithProbe<>(new ALSProbe(), startWithClient); } } Loading
services/core/java/com/android/server/biometrics/log/CallbackWithProbe.java 0 → 100644 +55 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2022 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.log; import android.annotation.NonNull; import com.android.server.biometrics.sensors.BaseClientMonitor; /** * Client monitor callback that exposes a probe. * * Disables the probe when the operation completes. * * @param <T> probe type */ public class CallbackWithProbe<T extends Probe> implements BaseClientMonitor.Callback { private final boolean mStartWithClient; private final T mProbe; public CallbackWithProbe(@NonNull T probe, boolean startWithClient) { mProbe = probe; mStartWithClient = startWithClient; } @Override public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { if (mStartWithClient) { mProbe.enable(); } } @Override public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) { mProbe.disable(); } @NonNull public T getProbe() { return mProbe; } }
services/core/java/com/android/server/biometrics/log/Probe.java 0 → 100644 +30 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2022 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.log; /** * Probe for loggable attributes that can be continuously monitored, such as ambient light. * * Disable probes when the sensors are in states that are not interesting for monitoring * purposes to save power. */ public interface Probe { /** Ensure the probe is actively sampling for new data. */ void enable(); /** Stop sampling data. */ void disable(); }
services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java +4 −2 Original line number Original line Diff line number Diff line Loading @@ -105,7 +105,8 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement // that do not handle lockout under the HAL. In these cases, ensure that the framework only // that do not handle lockout under the HAL. In these cases, ensure that the framework only // sends errors once per ClientMonitor. // sends errors once per ClientMonitor. if (mShouldSendErrorToClient) { if (mShouldSendErrorToClient) { logOnError(getContext(), errorCode, vendorCode, getTargetUserId()); getLogger().logOnError(getContext(), errorCode, vendorCode, isCryptoOperation(), getTargetUserId()); try { try { if (getListener() != null) { if (getListener() != null) { mShouldSendErrorToClient = false; mShouldSendErrorToClient = false; Loading Loading @@ -163,7 +164,8 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement protected final void onAcquiredInternal(int acquiredInfo, int vendorCode, protected final void onAcquiredInternal(int acquiredInfo, int vendorCode, boolean shouldSend) { boolean shouldSend) { super.logOnAcquired(getContext(), acquiredInfo, vendorCode, getTargetUserId()); getLogger().logOnAcquired(getContext(), acquiredInfo, vendorCode, isCryptoOperation(), getTargetUserId()); if (DEBUG) { if (DEBUG) { Slog.v(TAG, "Acquired: " + acquiredInfo + " " + vendorCode Slog.v(TAG, "Acquired: " + acquiredInfo + " " + vendorCode + ", shouldSend: " + shouldSend); + ", shouldSend: " + shouldSend); Loading