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

Commit 9e765abc authored by Rubin Xu's avatar Rubin Xu
Browse files

Refresh strong auth alarm when admin changes policy

When admin sets a new strong auth timeout policy, replace the existing
alarm (which enforces strong auth after the timeout) with a new one
with updated timeout.

Bug: 146188984
Test: atest com.android.server.locksettings.LockSettingsStrongAuthTest
Test: atest MixedManagedProfileTest#testRequiredStrongAuthTimeout
Change-Id: Ibcc13eb0d66697aff44192769b8fd817ca6800b8
parent 3b145e0b
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -107,4 +107,10 @@ public abstract class LockSettingsInternal {
     * @return true if the arming worked
     */
    public abstract boolean armRebootEscrow();


    /**
     * Refreshes pending strong auth timeout with the latest admin requirement set by device policy.
     */
    public abstract void refreshStrongAuthTimeout(int userId);
}
+5 −0
Original line number Diff line number Diff line
@@ -3441,6 +3441,11 @@ public class LockSettingsService extends ILockSettings.Stub {
        public boolean armRebootEscrow() {
            return mRebootEscrowManager.armRebootEscrowIfNeeded();
        }

        @Override
        public void refreshStrongAuthTimeout(int userId) {
            mStrongAuth.refreshStrongAuthTimeout(userId);
        }
    }

    private class RebootEscrowCallbacks implements RebootEscrowManager.Callbacks {
+61 −5
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ public class LockSettingsStrongAuth {
    private static final int MSG_SCHEDULE_NON_STRONG_BIOMETRIC_TIMEOUT = 7;
    private static final int MSG_STRONG_BIOMETRIC_UNLOCK = 8;
    private static final int MSG_SCHEDULE_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT = 9;
    private static final int MSG_REFRESH_STRONG_AUTH_TIMEOUT = 10;

    @VisibleForTesting
    protected static final String STRONG_AUTH_TIMEOUT_ALARM_TAG =
@@ -143,6 +144,15 @@ public class LockSettingsStrongAuth {
        public long getNextAlarmTimeMs(long timeout) {
            return SystemClock.elapsedRealtime() + timeout;
        }

        /**
         * Wraps around {@link SystemClock#elapsedRealtime}, which returns the number of
         * milliseconds since boot, including time spent in sleep.
         */
        @VisibleForTesting
        public long getElapsedRealtimeMs() {
            return SystemClock.elapsedRealtime();
        }
    }

    private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
@@ -231,22 +241,33 @@ public class LockSettingsStrongAuth {
        }
    }

    private void handleScheduleStrongAuthTimeout(int userId) {
    /**
     * Re-schedule the strong auth timeout alarm with latest information on the most recent
     * successful strong auth time and strong auth timeout from device policy.
     */
    private void rescheduleStrongAuthTimeoutAlarm(long strongAuthTime, int userId) {
        final DevicePolicyManager dpm =
                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
        long nextAlarmTime =
                mInjector.getNextAlarmTimeMs(dpm.getRequiredStrongAuthTimeout(null, userId));
        // cancel current alarm listener for the user (if there was one)
        StrongAuthTimeoutAlarmListener alarm = mStrongAuthTimeoutAlarmListenerForUser.get(userId);
        if (alarm != null) {
            mAlarmManager.cancel(alarm);
            alarm.setLatestStrongAuthTime(strongAuthTime);
        } else {
            alarm = new StrongAuthTimeoutAlarmListener(userId);
            alarm = new StrongAuthTimeoutAlarmListener(strongAuthTime, userId);
            mStrongAuthTimeoutAlarmListenerForUser.put(userId, alarm);
        }
        // AlarmManager.set() correctly handles the case where nextAlarmTime has already been in
        // the past (by firing the listener straight away), so nothing special for us to do here.
        long nextAlarmTime = strongAuthTime + dpm.getRequiredStrongAuthTimeout(null, userId);

        // schedule a new alarm listener for the user
        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, nextAlarmTime,
                STRONG_AUTH_TIMEOUT_ALARM_TAG, alarm, mHandler);
    }

    private void handleScheduleStrongAuthTimeout(int userId) {
        rescheduleStrongAuthTimeoutAlarm(mInjector.getElapsedRealtimeMs(), userId);

        // cancel current non-strong biometric alarm listener for the user (if there was one)
        cancelNonStrongBiometricAlarmListener(userId);
@@ -256,6 +277,13 @@ public class LockSettingsStrongAuth {
        setIsNonStrongBiometricAllowed(true, userId);
    }

    private void handleRefreshStrongAuthTimeout(int userId) {
        StrongAuthTimeoutAlarmListener alarm = mStrongAuthTimeoutAlarmListenerForUser.get(userId);
        if (alarm != null) {
            rescheduleStrongAuthTimeoutAlarm(alarm.getLatestStrongAuthTime(), userId);
        }
    }

    private void handleScheduleNonStrongBiometricTimeout(int userId) {
        if (DEBUG) Slog.d(TAG, "handleScheduleNonStrongBiometricTimeout for userId=" + userId);
        long nextAlarmTime = mInjector.getNextAlarmTimeMs(DEFAULT_NON_STRONG_BIOMETRIC_TIMEOUT_MS);
@@ -455,6 +483,13 @@ public class LockSettingsStrongAuth {
        mHandler.obtainMessage(MSG_SCHEDULE_STRONG_AUTH_TIMEOUT, userId, argNotUsed).sendToTarget();
    }

    /**
     * Refreshes pending strong auth timeout with the latest admin requirement set by device policy.
     */
    public void refreshStrongAuthTimeout(int userId) {
        mHandler.obtainMessage(MSG_REFRESH_STRONG_AUTH_TIMEOUT, userId, 0).sendToTarget();
    }

    /**
     * Report successful unlocking with biometric
     */
@@ -489,12 +524,30 @@ public class LockSettingsStrongAuth {
    @VisibleForTesting
    protected class StrongAuthTimeoutAlarmListener implements OnAlarmListener {

        private long mLatestStrongAuthTime;
        private final int mUserId;

        public StrongAuthTimeoutAlarmListener(int userId) {
        public StrongAuthTimeoutAlarmListener(long latestStrongAuthTime, int userId) {
            mLatestStrongAuthTime = latestStrongAuthTime;
            mUserId = userId;
        }

        /**
         * Sets the most recent time when a successful strong auth happened, in number of
         * milliseconds.
         */
        public void setLatestStrongAuthTime(long strongAuthTime) {
            mLatestStrongAuthTime = strongAuthTime;
        }

        /**
         * Returns the most recent time when a successful strong auth happened, in number of
         * milliseconds.
         */
        public long getLatestStrongAuthTime() {
            return mLatestStrongAuthTime;
        }

        @Override
        public void onAlarm() {
            requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, mUserId);
@@ -558,6 +611,9 @@ public class LockSettingsStrongAuth {
                case MSG_SCHEDULE_STRONG_AUTH_TIMEOUT:
                    handleScheduleStrongAuthTimeout(msg.arg1);
                    break;
                case MSG_REFRESH_STRONG_AUTH_TIMEOUT:
                    handleRefreshStrongAuthTimeout(msg.arg1);
                    break;
                case MSG_NO_LONGER_REQUIRE_STRONG_AUTH:
                    handleNoLongerRequireStrongAuth(msg.arg1, msg.arg2);
                    break;
+10 −0
Original line number Diff line number Diff line
@@ -5904,12 +5904,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
        final int userHandle = mInjector.userHandleGetCallingUserId();
        boolean changed = false;
        synchronized (getLockObject()) {
            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
            if (ap.strongAuthUnlockTimeout != timeoutMs) {
                ap.strongAuthUnlockTimeout = timeoutMs;
                saveSettingsLocked(userHandle);
                changed = true;
            }
        }
        if (changed) {
            mLockSettingsInternal.refreshStrongAuthTimeout(userHandle);
            // Refreshes the parent if profile has unified challenge, since the timeout would
            // also affect the parent user in this case.
            if (isManagedProfile(userHandle) && !isSeparateProfileChallengeEnabled(userHandle)) {
                mLockSettingsInternal.refreshStrongAuthTimeout(getProfileParentId(userHandle));
            }
        }
    }
+29 −3
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static com.android.server.locksettings.LockSettingsStrongAuth.NON_STRONG_
import static com.android.server.locksettings.LockSettingsStrongAuth.NON_STRONG_BIOMETRIC_TIMEOUT_ALARM_TAG;
import static com.android.server.locksettings.LockSettingsStrongAuth.STRONG_AUTH_TIMEOUT_ALARM_TAG;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
@@ -163,9 +164,11 @@ public class LockSettingsStrongAuthTest {

    @Test
    public void testReportSuccessfulStrongAuthUnlock_schedulePrimaryAuthTimeout() {
        final long nextAlarmTime = 1000;
        when(mInjector.getNextAlarmTimeMs(mDPM.getRequiredStrongAuthTimeout(null, PRIMARY_USER_ID)))
                .thenReturn(nextAlarmTime);
        final long currentTime = 1000;
        final long timeout = 1000;
        final long nextAlarmTime = currentTime + timeout;
        when(mInjector.getElapsedRealtimeMs()).thenReturn(currentTime);
        when(mDPM.getRequiredStrongAuthTimeout(null, PRIMARY_USER_ID)).thenReturn(timeout);
        mStrongAuth.reportSuccessfulStrongAuthUnlock(PRIMARY_USER_ID);

        waitForIdle();
@@ -177,6 +180,29 @@ public class LockSettingsStrongAuthTest {
        verifyAlarm(nextAlarmTime, STRONG_AUTH_TIMEOUT_ALARM_TAG, alarm);
    }

    @Test
    public void testReportSuccessfulStrongAuthUnlock_testRefreshStrongAuthTimeout() {
        final long currentTime = 1000;
        final long oldTimeout = 5000;
        final long nextAlarmTime = currentTime + oldTimeout;
        when(mInjector.getElapsedRealtimeMs()).thenReturn(currentTime);
        when(mDPM.getRequiredStrongAuthTimeout(null, PRIMARY_USER_ID)).thenReturn(oldTimeout);
        mStrongAuth.reportSuccessfulStrongAuthUnlock(PRIMARY_USER_ID);
        waitForIdle();

        StrongAuthTimeoutAlarmListener alarm =
                mStrongAuth.mStrongAuthTimeoutAlarmListenerForUser.get(PRIMARY_USER_ID);
        assertEquals(currentTime, alarm.getLatestStrongAuthTime());
        verifyAlarm(nextAlarmTime, STRONG_AUTH_TIMEOUT_ALARM_TAG, alarm);

        final long newTimeout = 3000;
        when(mDPM.getRequiredStrongAuthTimeout(null, PRIMARY_USER_ID)).thenReturn(newTimeout);
        mStrongAuth.refreshStrongAuthTimeout(PRIMARY_USER_ID);
        waitForIdle();
        verify(mAlarmManager).cancel(alarm);
        verifyAlarm(currentTime + newTimeout, STRONG_AUTH_TIMEOUT_ALARM_TAG, alarm);
    }

    @Test
    public void testReportSuccessfulStrongAuthUnlock_cancelAlarmsAndAllowNonStrongBio() {
        setupAlarms(PRIMARY_USER_ID);