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

Commit 483a0e95 authored by Jigar Thakkar's avatar Jigar Thakkar Committed by Android Build Coastguard Worker
Browse files

Use AlarmManager to schedule private space lock requests

We currently use Handler.postDelayed() to schedule the private space
auto-lock message if the auto-lock setting to lock after 5 mins of
screen timeout have been turned on. However, this timer does not take
into the account the time spent by the device in "sleep" state. To fix
this, we are moving to use AlarmManager timers with this change. Here we
use AlarmManager.setWindow with ELAPSED_REALTIME_WAKEUP to ensure the
alarm gets reeven when the device is asleep.

We will be using setWindow with a windowLength of 1 min, ensuring the
alarm gets delivered between 5 mins and 6 minutes of scheduling time to
offset the system health cost of the alarm, while honoring the auto-lock
promise.

Test: atest
UserManagerServiceTest#testAutoLockAfterInactityForPrivateProfile.
Test: Also tested manually by flashing changes on a test device,
keeping the device with PS installed idle for 6 mins and checking the
logs.
Bug: 342660878
Flag: android.multiuser.support_autolock_for_private_space
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ca97127b14461c0635723eb38b991cec8bccee54)
Merged-In: I6d7feb23076b0b8dcd0aceffa6a8fdd2ffa2be26
Change-Id: I6d7feb23076b0b8dcd0aceffa6a8fdd2ffa2be26
parent 3c75c64b
Loading
Loading
Loading
Loading
+79 −20
Original line number Original line Diff line number Diff line
@@ -58,6 +58,7 @@ import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.ActivityOptions;
import android.app.AlarmManager;
import android.app.BroadcastOptions;
import android.app.BroadcastOptions;
import android.app.IActivityManager;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
import android.app.IStopUserCallback;
@@ -322,6 +323,12 @@ public class UserManagerService extends IUserManager.Stub {
     */
     */
    private static final long PRIVATE_SPACE_AUTO_LOCK_INACTIVITY_TIMEOUT_MS = 5 * 60 * 1000;
    private static final long PRIVATE_SPACE_AUTO_LOCK_INACTIVITY_TIMEOUT_MS = 5 * 60 * 1000;


    /**
     * The time duration (in milliseconds) of the window length for the auto-lock message alarm
     */
    private static final long PRIVATE_SPACE_AUTO_LOCK_INACTIVITY_ALARM_WINDOW_MS =
            TimeUnit.SECONDS.toMillis(55);

    // Tron counters
    // Tron counters
    private static final String TRON_GUEST_CREATED = "users_guest_created";
    private static final String TRON_GUEST_CREATED = "users_guest_created";
    private static final String TRON_USER_CREATED = "users_user_created";
    private static final String TRON_USER_CREATED = "users_user_created";
@@ -552,8 +559,15 @@ public class UserManagerService extends IUserManager.Stub {


    private KeyguardManager.KeyguardLockedStateListener mKeyguardLockedStateListener;
    private KeyguardManager.KeyguardLockedStateListener mKeyguardLockedStateListener;


    /** Token to identify and remove already scheduled private space auto-lock messages */
    /**
    private static final Object PRIVATE_SPACE_AUTO_LOCK_MESSAGE_TOKEN = new Object();
     * {@link android.app.AlarmManager.OnAlarmListener} to schedule an alarm to enable
     * auto-locking private space after screen timeout
     */
    private PrivateSpaceAutoLockTimer mPrivateSpaceAutoLockTimer;

    /** Tag representing the alarm manager timer for auto-locking private space */
    private static final String PRIVATE_SPACE_AUTO_LOCK_TIMER_TAG = "PrivateSpaceAutoLockTimer";



    /** Content observer to get callbacks for privte space autolock settings changes */
    /** Content observer to get callbacks for privte space autolock settings changes */
    private final SettingsObserver mPrivateSpaceAutoLockSettingsObserver;
    private final SettingsObserver mPrivateSpaceAutoLockSettingsObserver;
@@ -604,22 +618,28 @@ public class UserManagerService extends IUserManager.Stub {
        public void onReceive(Context context, Intent intent) {
        public void onReceive(Context context, Intent intent) {
            if (isAutoLockForPrivateSpaceEnabled()) {
            if (isAutoLockForPrivateSpaceEnabled()) {
                if (ACTION_SCREEN_OFF.equals(intent.getAction())) {
                if (ACTION_SCREEN_OFF.equals(intent.getAction())) {
                    Slog.d(LOG_TAG, "SCREEN_OFF broadcast received");
                    maybeScheduleAlarmToAutoLockPrivateSpace();
                    maybeScheduleMessageToAutoLockPrivateSpace();
                } else if (ACTION_SCREEN_ON.equals(intent.getAction())) {
                } else if (ACTION_SCREEN_ON.equals(intent.getAction())) {
                    Slog.d(LOG_TAG, "SCREEN_ON broadcast received, "
                    Slog.d(LOG_TAG, "SCREEN_ON broadcast received, "
                            + "removing queued message to auto-lock private space");
                            + "removing pending alarms to auto-lock private space");
                    // Remove any queued messages since the device is interactive again
                    // Remove any pending alarm since the device is interactive again
                    mHandler.removeCallbacksAndMessages(PRIVATE_SPACE_AUTO_LOCK_MESSAGE_TOKEN);
                    cancelPendingAutoLockAlarms();
                }
                }
            }
            }
        }
        }
    };
    };


    private void cancelPendingAutoLockAlarms() {
        final AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
        if (alarmManager != null && mPrivateSpaceAutoLockTimer != null) {
            alarmManager.cancel(mPrivateSpaceAutoLockTimer);
        }
    }

    @VisibleForTesting
    @VisibleForTesting
    void maybeScheduleMessageToAutoLockPrivateSpace() {
    void maybeScheduleAlarmToAutoLockPrivateSpace() {
        // No action needed if auto-lock on inactivity not selected
        // No action needed if auto-lock on inactivity not selected
        int privateSpaceAutoLockPreference =
        final int privateSpaceAutoLockPreference =
                Settings.Secure.getIntForUser(mContext.getContentResolver(),
                Settings.Secure.getIntForUser(mContext.getContentResolver(),
                        Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
                        Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
                        Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
                        Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
@@ -632,26 +652,65 @@ public class UserManagerService extends IUserManager.Stub {
        }
        }
        int privateProfileUserId = getPrivateProfileUserId();
        int privateProfileUserId = getPrivateProfileUserId();
        if (privateProfileUserId != UserHandle.USER_NULL) {
        if (privateProfileUserId != UserHandle.USER_NULL) {
            scheduleMessageToAutoLockPrivateSpace(privateProfileUserId,
            if (isQuietModeEnabled(privateProfileUserId)) {
                    PRIVATE_SPACE_AUTO_LOCK_MESSAGE_TOKEN,
                Slogf.d(LOG_TAG, "Not scheduling auto-lock alarm for %d, "
                        + "quiet mode already enabled", privateProfileUserId);
                return;
            }
            scheduleAlarmToAutoLockPrivateSpace(privateProfileUserId,
                    PRIVATE_SPACE_AUTO_LOCK_INACTIVITY_TIMEOUT_MS);
                    PRIVATE_SPACE_AUTO_LOCK_INACTIVITY_TIMEOUT_MS);
        }
        }
    }
    }


    @VisibleForTesting
    @VisibleForTesting
    void scheduleMessageToAutoLockPrivateSpace(int userId, Object token,
    void scheduleAlarmToAutoLockPrivateSpace(int userId, long delayInMillis) {
            long delayInMillis) {
        final AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
        Slog.i(LOG_TAG, "Scheduling auto-lock message");
        if (alarmManager == null) {
        mHandler.postDelayed(() -> {
            Slog.e(LOG_TAG, "AlarmManager not available, cannot schedule auto-lock alarm");
            return;
        }
        initPrivateSpaceAutoLockTimer(userId);
        final long alarmWindowStartTime = SystemClock.elapsedRealtime() + delayInMillis;
        alarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                alarmWindowStartTime,
                PRIVATE_SPACE_AUTO_LOCK_INACTIVITY_ALARM_WINDOW_MS,
                PRIVATE_SPACE_AUTO_LOCK_TIMER_TAG,
                new HandlerExecutor(mHandler),
                mPrivateSpaceAutoLockTimer);
    }

    private void initPrivateSpaceAutoLockTimer(int userId) {
        cancelPendingAutoLockAlarms();
        if (mPrivateSpaceAutoLockTimer == null
                || mPrivateSpaceAutoLockTimer.getUserId() != userId) {
            mPrivateSpaceAutoLockTimer = new PrivateSpaceAutoLockTimer(userId);
        }
    }

    private class PrivateSpaceAutoLockTimer implements AlarmManager.OnAlarmListener {

        private final int mUserId;

        PrivateSpaceAutoLockTimer(int userId) {
            mUserId = userId;
        }

        int getUserId() {
            return mUserId;
        }

        @Override
        public void onAlarm() {
            final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
            final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
            if (powerManager != null && !powerManager.isInteractive()) {
            if (powerManager != null && !powerManager.isInteractive()) {
                Slog.i(LOG_TAG, "Auto-locking private space with user-id " + userId);
                Slog.i(LOG_TAG, "Auto-locking private space with user-id " + mUserId);
                setQuietModeEnabledAsync(userId, true,
                setQuietModeEnabledAsync(mUserId, true,
                        /* target */ null, mContext.getPackageName());
                        /* target */ null, mContext.getPackageName());
            } else {
            } else {
                Slog.i(LOG_TAG, "Device is interactive, skipping auto-lock");
                Slog.i(LOG_TAG, "Device is interactive, skipping auto-lock for profile user "
                        + mUserId);
            }
        }
        }
        }, token, delayInMillis);
    }
    }


    @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
    @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
@@ -697,7 +756,7 @@ public class UserManagerService extends IUserManager.Stub {
            // Unregister device inactivity broadcasts
            // Unregister device inactivity broadcasts
            if (mIsDeviceInactivityBroadcastReceiverRegistered) {
            if (mIsDeviceInactivityBroadcastReceiverRegistered) {
                Slog.i(LOG_TAG, "Removing device inactivity broadcast receivers");
                Slog.i(LOG_TAG, "Removing device inactivity broadcast receivers");
                mHandler.removeCallbacksAndMessages(PRIVATE_SPACE_AUTO_LOCK_MESSAGE_TOKEN);
                cancelPendingAutoLockAlarms();
                mContext.unregisterReceiver(mDeviceInactivityBroadcastReceiver);
                mContext.unregisterReceiver(mDeviceInactivityBroadcastReceiver);
                mIsDeviceInactivityBroadcastReceiverRegistered = false;
                mIsDeviceInactivityBroadcastReceiverRegistered = false;
            }
            }
+5 −6
Original line number Original line Diff line number Diff line
@@ -683,15 +683,14 @@ public final class UserManagerServiceTest {
        UserInfo privateProfileUser =
        UserInfo privateProfileUser =
                mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,
                mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,
                        USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null);
                        USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null);
        Mockito.doNothing().when(mSpiedUms).scheduleMessageToAutoLockPrivateSpace(
        Mockito.doNothing().when(mSpiedUms).scheduleAlarmToAutoLockPrivateSpace(
                eq(privateProfileUser.getUserHandle().getIdentifier()), any(),
                eq(privateProfileUser.getUserHandle().getIdentifier()), anyLong());
                anyLong());




        mSpiedUms.maybeScheduleMessageToAutoLockPrivateSpace();
        mSpiedUms.maybeScheduleAlarmToAutoLockPrivateSpace();


        Mockito.verify(mSpiedUms).scheduleMessageToAutoLockPrivateSpace(
        Mockito.verify(mSpiedUms).scheduleAlarmToAutoLockPrivateSpace(
                eq(privateProfileUser.getUserHandle().getIdentifier()), any(), anyLong());
                eq(privateProfileUser.getUserHandle().getIdentifier()), anyLong());
    }
    }


    @Test
    @Test