Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cabd0863 authored by Joe Bolinger's avatar Joe Bolinger
Browse files

Add snapshot of ambient light value to log during enrollment and authentication operations.

Bug: 189241048
Test: manual (via statsd_testdrive)
Change-Id: Icd0f7abfe328322f6b8192f056c26a4db9f96c91
parent 81cac3a9
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -677,7 +677,8 @@ public final class AuthSession implements IBinder.DeathRecipient {
                    FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED,
                    latency,
                    mDebugEnabled,
                    -1 /* sensorId */);
                    -1 /* sensorId */,
                    -1f /* ambientLightLux */);
        } else {
            final long latency = System.currentTimeMillis() - mStartTimeMs;

+36 −2
Original line number Diff line number Diff line
@@ -69,6 +69,31 @@ public abstract class BaseClientMonitor extends LoggableMonitor
        }
    }

    /** Holder for wrapping multiple handlers into a single Callback. */
    protected static class CompositeCallback implements Callback {
        @NonNull
        private final Callback[] mCallbacks;

        public CompositeCallback(@NonNull Callback... callbacks) {
            mCallbacks = callbacks;
        }

        @Override
        public final void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
            for (int i = 0; i < mCallbacks.length; i++) {
                mCallbacks[i].onClientStarted(clientMonitor);
            }
        }

        @Override
        public final void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
                boolean success) {
            for (int i = mCallbacks.length - 1; i >= 0; i--) {
                mCallbacks[i].onClientFinished(clientMonitor, success);
            }
        }
    }

    private final int mSequentialId;
    @NonNull private final Context mContext;
    private final int mTargetUserId;
@@ -125,7 +150,7 @@ public abstract class BaseClientMonitor extends LoggableMonitor
            @Nullable IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId,
            @NonNull String owner, int cookie, int sensorId, int statsModality, int statsAction,
            int statsClient) {
        super(statsModality, statsAction, statsClient);
        super(context, statsModality, statsAction, statsClient);
        mSequentialId = sCount++;
        mContext = context;
        mToken = token;
@@ -153,10 +178,19 @@ public abstract class BaseClientMonitor extends LoggableMonitor
     * @param callback invoked when the operation is complete (succeeds, fails, etc)
     */
    public void start(@NonNull Callback callback) {
        mCallback = callback;
        mCallback = wrapCallbackForStart(callback);
        mCallback.onClientStarted(this);
    }

    /**
     * Called during start to provide subclasses a hook for decorating the callback.
     *
     * Returns the original callback unless overridden.
     */
    @NonNull
    protected Callback wrapCallbackForStart(@NonNull Callback callback) {
        return callback;
    }

    public boolean isAlreadyDone() {
        return mAlreadyDone;
+84 −12
Original line number Diff line number Diff line
@@ -16,7 +16,13 @@

package com.android.server.biometrics.sensors;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.face.FaceManager;
@@ -37,26 +43,47 @@ public abstract class LoggableMonitor {
    final int mStatsModality;
    private final int mStatsAction;
    private final int mStatsClient;
    @NonNull private final SensorManager mSensorManager;
    private long mFirstAcquireTimeMs;
    private boolean mLightSensorEnabled = false;
    private boolean mShouldLogMetrics = true;

    /**
     * Only valid for AuthenticationClient.
     * @return true if the client is authenticating for a crypto operation.
     */
    protected boolean isCryptoOperation() {
        return false;
    // report only the most recent value
    // consider com.android.server.display.utils.AmbientFilter or similar if need arises
    private volatile float mLastAmbientLux = 0;

    private final SensorEventListener mLightSensorListener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            mLastAmbientLux = event.values[0];
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
            // Not used.
        }
    };

    /**
     * @param context system_server context
     * @param statsModality One of {@link BiometricsProtoEnums} MODALITY_* constants.
     * @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants.
     * @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants.
     */
    public LoggableMonitor(int statsModality, int statsAction, int statsClient) {
    public LoggableMonitor(@NonNull Context context, int statsModality, int statsAction,
            int statsClient) {
        mStatsModality = statsModality;
        mStatsAction = statsAction;
        mStatsClient = statsClient;
        mSensorManager = context.getSystemService(SensorManager.class);
    }

    /**
     * Only valid for AuthenticationClient.
     * @return true if the client is authenticating for a crypto operation.
     */
    protected boolean isCryptoOperation() {
        return false;
    }

    protected void setShouldLog(boolean shouldLog) {
@@ -131,7 +158,6 @@ public abstract class LoggableMonitor {
    }

    protected final void logOnError(Context context, int error, int vendorCode, int targetUserId) {

        if (!mShouldLogMetrics) {
            return;
        }
@@ -199,7 +225,8 @@ public abstract class LoggableMonitor {
                    + ", Client: " + mStatsClient
                    + ", RequireConfirmation: " + requireConfirmation
                    + ", State: " + authState
                    + ", Latency: " + latency);
                    + ", Latency: " + latency
                    + ", Lux: " + mLastAmbientLux);
        } else {
            Slog.v(TAG, "Authentication latency: " + latency);
        }
@@ -217,7 +244,8 @@ public abstract class LoggableMonitor {
                authState,
                sanitizeLatency(latency),
                Utils.isDebugEnabled(context, targetUserId),
                -1 /* sensorId */);
                -1 /* sensorId */,
                mLastAmbientLux /* ambientLightLux */);
    }

    protected final void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) {
@@ -230,6 +258,7 @@ public abstract class LoggableMonitor {
                    + ", User: " + targetUserId
                    + ", Client: " + mStatsClient
                    + ", Latency: " + latency
                    + ", Lux: " + mLastAmbientLux
                    + ", Success: " + enrollSuccessful);
        } else {
            Slog.v(TAG, "Enroll latency: " + latency);
@@ -244,7 +273,8 @@ public abstract class LoggableMonitor {
                targetUserId,
                sanitizeLatency(latency),
                enrollSuccessful,
                -1 /* sensorId */);
                -1, /* sensorId */
                mLastAmbientLux /* ambientLightLux */);
    }

    private long sanitizeLatency(long latency) {
@@ -255,4 +285,46 @@ public abstract class LoggableMonitor {
        return latency;
    }

    /** Get a callback to start/stop ALS capture when client runs. */
    @NonNull
    protected BaseClientMonitor.Callback createALSCallback() {
        return new BaseClientMonitor.Callback() {
            @Override
            public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
                setLightSensorLoggingEnabled(getAmbientLightSensor(mSensorManager));
            }

            @Override
            public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
                    boolean success) {
                setLightSensorLoggingEnabled(null);
            }
        };
    }

    /** The sensor to use for ALS logging. */
    @Nullable
    protected Sensor getAmbientLightSensor(@NonNull SensorManager sensorManager) {
        return mShouldLogMetrics ? sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) : null;
    }

    private void setLightSensorLoggingEnabled(@Nullable Sensor lightSensor) {
        if (DEBUG) {
            Slog.v(TAG, "capturing ambient light using: "
                    + (lightSensor != null ? lightSensor : "[disabled]"));
        }

        if (lightSensor != null) {
            if (!mLightSensorEnabled) {
                mLightSensorEnabled = true;
                mLastAmbientLux = 0;
                mSensorManager.registerListener(mLightSensorListener, lightSensor,
                        SensorManager.SENSOR_DELAY_NORMAL);
            }
        } else {
            mLightSensorEnabled = false;
            mLastAmbientLux = 0;
            mSensorManager.unregisterListener(mLightSensorListener);
        }
    }
}
+10 −2
Original line number Diff line number Diff line
@@ -99,6 +99,12 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
                "face_custom_success_error", 0) == 1;
    }

    @NonNull
    @Override
    protected Callback wrapCallbackForStart(@NonNull Callback callback) {
        return new CompositeCallback(createALSCallback(), callback);
    }

    @Override
    protected void startHalOperation() {
        try {
@@ -229,7 +235,8 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
        }
    }

    @Override public void onLockoutTimed(long durationMillis) {
    @Override
    public void onLockoutTimed(long durationMillis) {
        mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED);
        // Lockout metrics are logged as an error code.
        final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT;
@@ -242,7 +249,8 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
        }
    }

    @Override public void onLockoutPermanent() {
    @Override
    public void onLockoutPermanent() {
        mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT);
        // Lockout metrics are logged as an error code.
        final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT;
+6 −0
Original line number Diff line number Diff line
@@ -95,6 +95,12 @@ public class FaceEnrollClient extends EnrollClient<ISession> {
        ReEnrollNotificationUtils.cancelNotification(getContext());
    }

    @NonNull
    @Override
    protected Callback wrapCallbackForStart(@NonNull Callback callback) {
        return new CompositeCallback(createALSCallback(), callback);
    }

    @Override
    public void destroy() {
        try {
Loading