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

Commit 1c12f9c3 authored by Hao Dong's avatar Hao Dong Committed by Automerger Merge Worker
Browse files

Merge "Remove self-maintained timed lockout in MultiBiometricLockoutState"...

Merge "Remove self-maintained timed lockout in MultiBiometricLockoutState" into udc-dev am: 172c4fb2

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22514707



Change-Id: Ie6390d30cb9bb040bf60c191acb73d0e27dda543
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents f9c5ef03 172c4fb2
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -37,13 +37,17 @@ class AuthResultCoordinator {
     */
    static final int AUTHENTICATOR_DEFAULT = 0;
    /**
     * Indicated this authenticator has received a lockout.
     * Indicated this authenticator has received a permanent lockout.
     */
    static final int AUTHENTICATOR_LOCKED = 1 << 0;
    static final int AUTHENTICATOR_PERMANENT_LOCKED = 1 << 0;
    /**
     * Indicates this authenticator has received a timed unlock.
     */
    static final int AUTHENTICATOR_TIMED_LOCKED = 1 << 1;
    /**
     * Indicates this authenticator has received a successful unlock.
     */
    static final int AUTHENTICATOR_UNLOCKED = 1 << 1;
    static final int AUTHENTICATOR_UNLOCKED = 1 << 2;
    private static final String TAG = "AuthResultCoordinator";
    private final Map<Integer, Integer> mAuthenticatorState;

@@ -85,7 +89,14 @@ class AuthResultCoordinator {
     * Adds a lock out of a given strength to the current operation list.
     */
    void lockedOutFor(@Authenticators.Types int strength) {
        updateState(strength, (old) -> AUTHENTICATOR_LOCKED | old);
        updateState(strength, (old) -> AUTHENTICATOR_PERMANENT_LOCKED | old);
    }

    /**
     * Adds a timed lock out of a given strength to the current operation list.
     */
    void lockOutTimed(@Authenticators.Types int strength) {
        updateState(strength, (old) -> AUTHENTICATOR_TIMED_LOCKED | old);
    }

    /**
+21 −39
Original line number Diff line number Diff line
@@ -16,21 +16,19 @@

package com.android.server.biometrics.sensors;

import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_LOCKED;
import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_PERMANENT_LOCKED;
import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_TIMED_LOCKED;
import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_UNLOCKED;

import android.hardware.biometrics.BiometricManager.Authenticators;
import android.os.SystemClock;
import android.util.Pair;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;

import java.time.Clock;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@@ -45,9 +43,7 @@ public class AuthSessionCoordinator implements AuthSessionListener {

    private final Set<Integer> mAuthOperations;
    private final MultiBiometricLockoutState mMultiBiometricLockoutState;
    private final List<Pair<Integer, Long>> mTimedLockouts;
    private final RingBuffer mRingBuffer;
    private final Clock mClock;

    private int mUserId;
    private boolean mIsAuthenticating;
@@ -63,8 +59,6 @@ public class AuthSessionCoordinator implements AuthSessionListener {
        mAuthResultCoordinator = new AuthResultCoordinator();
        mMultiBiometricLockoutState = new MultiBiometricLockoutState(clock);
        mRingBuffer = new RingBuffer(100);
        mTimedLockouts = new ArrayList<>();
        mClock = clock;
    }

    /**
@@ -74,8 +68,6 @@ public class AuthSessionCoordinator implements AuthSessionListener {
        mAuthOperations.clear();
        mUserId = userId;
        mIsAuthenticating = true;
        mAuthOperations.clear();
        mTimedLockouts.clear();
        mAuthResultCoordinator = new AuthResultCoordinator();
        mRingBuffer.addApiCall("internal : onAuthSessionStarted(" + userId + ")");
    }
@@ -85,39 +77,30 @@ public class AuthSessionCoordinator implements AuthSessionListener {
     *
     * This can happen two ways.
     * 1. Manually calling this API
     * 2. If authStartedFor() was called, and all authentication attempts finish.
     * 2. If authStartedFor() was called, and any authentication attempts finish.
     */
    void endAuthSession() {
        if (mIsAuthenticating) {
            final long currentTime = mClock.millis();
            for (Pair<Integer, Long> timedLockouts : mTimedLockouts) {
                mMultiBiometricLockoutState.increaseLockoutTime(mUserId, timedLockouts.first,
                        timedLockouts.second + currentTime);
            }
        // User unlocks can also unlock timed lockout Authenticator.Types
        final Map<Integer, Integer> result = mAuthResultCoordinator.getResult();
        for (int authenticator : Arrays.asList(Authenticators.BIOMETRIC_CONVENIENCE,
                Authenticators.BIOMETRIC_WEAK, Authenticators.BIOMETRIC_STRONG)) {
            final Integer value = result.get(authenticator);
            if ((value & AUTHENTICATOR_UNLOCKED) == AUTHENTICATOR_UNLOCKED) {
                    mMultiBiometricLockoutState.setAuthenticatorTo(mUserId, authenticator,
                            true /* canAuthenticate */);
                    mMultiBiometricLockoutState.clearLockoutTime(mUserId, authenticator);
                } else if ((value & AUTHENTICATOR_LOCKED) == AUTHENTICATOR_LOCKED) {
                    mMultiBiometricLockoutState.setAuthenticatorTo(mUserId, authenticator,
                            false /* canAuthenticate */);
                mMultiBiometricLockoutState.clearPermanentLockOut(mUserId, authenticator);
                mMultiBiometricLockoutState.clearTimedLockout(mUserId, authenticator);
            } else if ((value & AUTHENTICATOR_PERMANENT_LOCKED) == AUTHENTICATOR_PERMANENT_LOCKED) {
                mMultiBiometricLockoutState.setPermanentLockOut(mUserId, authenticator);
            } else if ((value & AUTHENTICATOR_TIMED_LOCKED) == AUTHENTICATOR_TIMED_LOCKED) {
                mMultiBiometricLockoutState.setTimedLockout(mUserId, authenticator);
            }

        }

        mRingBuffer.addApiCall("internal : onAuthSessionEnded(" + mUserId + ")");
        clearSession();
    }
    }

    private void clearSession() {
        mIsAuthenticating = false;
        mTimedLockouts.clear();
        mAuthOperations.clear();
    }

@@ -171,7 +154,7 @@ public class AuthSessionCoordinator implements AuthSessionListener {
                        + ", sensorId=" + sensorId + "time=" + time + ", requestId=" + requestId
                        + ")";
        mRingBuffer.addApiCall(lockedOutStr);
        mTimedLockouts.add(new Pair<>(biometricStrength, time));
        mAuthResultCoordinator.lockOutTimed(biometricStrength);
        attemptToFinish(userId, sensorId, lockedOutStr);
    }

@@ -202,9 +185,8 @@ public class AuthSessionCoordinator implements AuthSessionListener {
            // Lockouts cannot be reset by non-strong biometrics
            return;
        }
        mMultiBiometricLockoutState.setAuthenticatorTo(userId, biometricStrength,
                true /*canAuthenticate */);
        mMultiBiometricLockoutState.clearLockoutTime(userId, biometricStrength);
        mMultiBiometricLockoutState.clearPermanentLockOut(userId, biometricStrength);
        mMultiBiometricLockoutState.clearTimedLockout(userId, biometricStrength);
    }

    private void attemptToFinish(int userId, int sensorId, String description) {
+40 −44
Original line number Diff line number Diff line
@@ -50,10 +50,11 @@ class MultiBiometricLockoutState {
    private Map<Integer, AuthenticatorState> createUnlockedMap() {
        Map<Integer, AuthenticatorState> lockOutMap = new HashMap<>();
        lockOutMap.put(BIOMETRIC_STRONG,
                new AuthenticatorState(BIOMETRIC_STRONG, false, 0, mClock));
        lockOutMap.put(BIOMETRIC_WEAK, new AuthenticatorState(BIOMETRIC_WEAK, false, 0, mClock));
                new AuthenticatorState(BIOMETRIC_STRONG, false, false));
        lockOutMap.put(BIOMETRIC_WEAK,
                new AuthenticatorState(BIOMETRIC_WEAK, false, false));
        lockOutMap.put(BIOMETRIC_CONVENIENCE,
                new AuthenticatorState(BIOMETRIC_CONVENIENCE, false, 0, mClock));
                new AuthenticatorState(BIOMETRIC_CONVENIENCE, false, false));
        return lockOutMap;
    }

@@ -64,54 +65,71 @@ class MultiBiometricLockoutState {
        return mCanUserAuthenticate.get(userId);
    }

    void setAuthenticatorTo(int userId, @Authenticators.Types int strength, boolean canAuth) {
    void setPermanentLockOut(int userId, @Authenticators.Types int strength) {
        final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId);
        switch (strength) {
            case Authenticators.BIOMETRIC_STRONG:
                authMap.get(BIOMETRIC_STRONG).mPermanentlyLockedOut = !canAuth;
                authMap.get(BIOMETRIC_STRONG).mPermanentlyLockedOut = true;
                // fall through
            case Authenticators.BIOMETRIC_WEAK:
                authMap.get(BIOMETRIC_WEAK).mPermanentlyLockedOut = !canAuth;
                authMap.get(BIOMETRIC_WEAK).mPermanentlyLockedOut = true;
                // fall through
            case Authenticators.BIOMETRIC_CONVENIENCE:
                authMap.get(BIOMETRIC_CONVENIENCE).mPermanentlyLockedOut = !canAuth;
                authMap.get(BIOMETRIC_CONVENIENCE).mPermanentlyLockedOut = true;
                return;
            default:
                Slog.e(TAG, "increaseLockoutTime called for invalid strength : "  + strength);
        }
    }

    void increaseLockoutTime(int userId, @Authenticators.Types int strength, long duration) {
    void clearPermanentLockOut(int userId, @Authenticators.Types int strength) {
        final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId);
        switch (strength) {
            case Authenticators.BIOMETRIC_STRONG:
                authMap.get(BIOMETRIC_STRONG).increaseLockoutTo(duration);
                authMap.get(BIOMETRIC_STRONG).mPermanentlyLockedOut = false;
                // fall through
            case Authenticators.BIOMETRIC_WEAK:
                authMap.get(BIOMETRIC_WEAK).increaseLockoutTo(duration);
                authMap.get(BIOMETRIC_WEAK).mPermanentlyLockedOut = false;
                // fall through
            case Authenticators.BIOMETRIC_CONVENIENCE:
                authMap.get(BIOMETRIC_CONVENIENCE).increaseLockoutTo(duration);
                authMap.get(BIOMETRIC_CONVENIENCE).mPermanentlyLockedOut = false;
                return;
            default:
                Slog.e(TAG, "increaseLockoutTime called for invalid strength : "  + strength);
        }
    }

    void clearLockoutTime(int userId, @Authenticators.Types int strength) {
    void setTimedLockout(int userId, @Authenticators.Types int strength) {
        final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId);
        switch (strength) {
            case Authenticators.BIOMETRIC_STRONG:
                authMap.get(BIOMETRIC_STRONG).setTimedLockout(0);
                authMap.get(BIOMETRIC_STRONG).mTimedLockout = true;
                // fall through
            case Authenticators.BIOMETRIC_WEAK:
                authMap.get(BIOMETRIC_WEAK).setTimedLockout(0);
                authMap.get(BIOMETRIC_WEAK).mTimedLockout = true;
                // fall through
            case Authenticators.BIOMETRIC_CONVENIENCE:
                authMap.get(BIOMETRIC_CONVENIENCE).setTimedLockout(0);
                authMap.get(BIOMETRIC_CONVENIENCE).mTimedLockout = true;
                return;
            default:
                Slog.e(TAG, "clearLockoutTime called for invalid strength : "  + strength);
                Slog.e(TAG, "increaseLockoutTime called for invalid strength : "  + strength);
        }
    }

    void clearTimedLockout(int userId, @Authenticators.Types int strength) {
        final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId);
        switch (strength) {
            case Authenticators.BIOMETRIC_STRONG:
                authMap.get(BIOMETRIC_STRONG).mTimedLockout = false;
                // fall through
            case Authenticators.BIOMETRIC_WEAK:
                authMap.get(BIOMETRIC_WEAK).mTimedLockout = false;
                // fall through
            case Authenticators.BIOMETRIC_CONVENIENCE:
                authMap.get(BIOMETRIC_CONVENIENCE).mTimedLockout = false;
                return;
            default:
                Slog.e(TAG, "increaseLockoutTime called for invalid strength : "  + strength);
        }
    }

@@ -132,7 +150,7 @@ class MultiBiometricLockoutState {
        final AuthenticatorState state = authMap.get(strength);
        if (state.mPermanentlyLockedOut) {
            return LockoutTracker.LOCKOUT_PERMANENT;
        } else if (state.isTimedLockout()) {
        } else if (state.mTimedLockout) {
            return LockoutTracker.LOCKOUT_TIMED;
        } else {
            return LockoutTracker.LOCKOUT_NONE;
@@ -158,43 +176,21 @@ class MultiBiometricLockoutState {
    private static class AuthenticatorState {
        private Integer mAuthenticatorType;
        private boolean mPermanentlyLockedOut;
        private long mTimedLockout;
        private Clock mClock;
        private boolean mTimedLockout;

        AuthenticatorState(Integer authenticatorId, boolean permanentlyLockedOut,
                long timedLockout, Clock clock) {
                boolean timedLockout) {
            mAuthenticatorType = authenticatorId;
            mPermanentlyLockedOut = permanentlyLockedOut;
            mTimedLockout = timedLockout;
            mClock = clock;
        }

        boolean canAuthenticate() {
            return !mPermanentlyLockedOut && !isTimedLockout();
        }

        boolean isTimedLockout() {
            return mClock.millis() - mTimedLockout < 0;
        }

        void setTimedLockout(long duration) {
            mTimedLockout = duration;
        }

        /**
         * Either increases the lockout to duration, or leaves it as it, whichever is longer.
         */
        void increaseLockoutTo(long duration) {
            mTimedLockout = Math.max(mTimedLockout, duration);
        }

        String toString(long currentTime) {
            final String duration =
                    mTimedLockout - currentTime > 0 ? (mTimedLockout - currentTime) + "ms" : "none";
            final String timedLockout = mTimedLockout ? "true" : "false";
            final String permanentLockout = mPermanentlyLockedOut ? "true" : "false";
            return String.format("(%s, permanentLockout=%s, timedLockoutRemaining=%s)",
            return String.format("(%s, permanentLockout=%s, timedLockout=%s)",
                    BiometricManager.authenticatorToStr(mAuthenticatorType), permanentLockout,
                    duration);
                    timedLockout);
        }
    }
}
+7 −4
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ErrorConsumer;
import com.android.server.biometrics.sensors.HalClientMonitor;
@@ -88,10 +89,9 @@ public class FaceResetLockoutClient extends HalClientMonitor<AidlSession> implem

    void onLockoutCleared() {
        resetLocalLockoutStateToNone(getSensorId(), getTargetUserId(), mLockoutCache,
                mLockoutResetDispatcher);
                mLockoutResetDispatcher, getBiometricContext().getAuthSessionCoordinator(),
                mBiometricStrength, getRequestId());
        mCallback.onClientFinished(this, true /* success */);
        getBiometricContext().getAuthSessionCoordinator()
                .resetLockoutFor(getTargetUserId(), mBiometricStrength, getRequestId());
    }

    public boolean interruptsPrecedingClients() {
@@ -108,7 +108,10 @@ public class FaceResetLockoutClient extends HalClientMonitor<AidlSession> implem
     */
    static void resetLocalLockoutStateToNone(int sensorId, int userId,
            @NonNull LockoutCache lockoutTracker,
            @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
            @NonNull LockoutResetDispatcher lockoutResetDispatcher,
            @NonNull AuthSessionCoordinator authSessionCoordinator,
            @Authenticators.Types int biometricStrength, long requestId) {
        authSessionCoordinator.resetLockoutFor(userId, biometricStrength, requestId);
        lockoutTracker.setLockoutModeForUser(userId, LockoutTracker.LOCKOUT_NONE);
        lockoutResetDispatcher.notifyLockoutResetCallbacks(sensorId);
    }
+13 −2
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ import com.android.server.biometrics.UserStateProto;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
@@ -127,6 +128,9 @@ public class Sensor {
        private final LockoutCache mLockoutCache;
        @NonNull
        private final LockoutResetDispatcher mLockoutResetDispatcher;

        @NonNull
        private AuthSessionCoordinator mAuthSessionCoordinator;
        @NonNull
        private final Callback mCallback;

@@ -134,6 +138,7 @@ public class Sensor {
                @NonNull UserAwareBiometricScheduler scheduler, int sensorId, int userId,
                @NonNull LockoutCache lockoutTracker,
                @NonNull LockoutResetDispatcher lockoutResetDispatcher,
                @NonNull AuthSessionCoordinator authSessionCoordinator,
                @NonNull Callback callback) {
            mContext = context;
            mHandler = handler;
@@ -143,6 +148,7 @@ public class Sensor {
            mUserId = userId;
            mLockoutCache = lockoutTracker;
            mLockoutResetDispatcher = lockoutResetDispatcher;
            mAuthSessionCoordinator = authSessionCoordinator;
            mCallback = callback;
        }

@@ -346,8 +352,12 @@ public class Sensor {
                final BaseClientMonitor client = mScheduler.getCurrentClient();
                if (!(client instanceof FaceResetLockoutClient)) {
                    Slog.d(mTag, "onLockoutCleared outside of resetLockout by HAL");
                    // Given that onLockoutCleared() can happen at any time, and is not necessarily
                    // coming from a specific client, set this to -1 to indicate it wasn't for a
                    // specific request.
                    FaceResetLockoutClient.resetLocalLockoutStateToNone(mSensorId, mUserId,
                            mLockoutCache, mLockoutResetDispatcher);
                            mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator,
                            Utils.getCurrentStrength(mSensorId), -1 /* requestId */);
                } else {
                    Slog.d(mTag, "onLockoutCleared after resetLockout");
                    final FaceResetLockoutClient resetLockoutClient =
@@ -514,7 +524,8 @@ public class Sensor {

                        final HalSessionCallback resultController = new HalSessionCallback(mContext,
                                mHandler, mTag, mScheduler, sensorId, newUserId, mLockoutCache,
                                lockoutResetDispatcher, () -> {
                                lockoutResetDispatcher,
                                biometricContext.getAuthSessionCoordinator(), () -> {
                            Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE");
                            mCurrentSession = null;
                        });
Loading