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

Commit 3d64c041 authored by Kweku Adams's avatar Kweku Adams Committed by Hung-ying Tyan
Browse files

Informing app idle listeners on enabled state changes.

Currently, if AppStandbyController is enabled after some listeners have
already registered, the listeners will be told that the system is in a
state of parole even though AppStandbyController thinks it's not in
parole. This change informs AppIdleStateChangeListeners when
AppStandbyController's enabled state changes as well so that they can be
in the correct state.

I also removed the call to setAppIdleEnabled() in onBootPhase() since
updateSettings() is called right afterwards and that also calls
setAppIdleEnabled().

Bug: 112329453
Test: atest AppStandbyControllerTests
also check logs to confirm that NetworkPolicyManagerService and
JobSchedulerService's listeners switch from ON to OFF when the system is
ready.

Change-Id: I88bc293c70b459f54f75f92126ad306d6ab8d9b7
Merged-In: I88bc293c70b459f54f75f92126ad306d6ab8d9b7
parent 607e7979
Loading
Loading
Loading
Loading
+78 −2
Original line number Diff line number Diff line
@@ -124,6 +124,7 @@ public class AppStandbyControllerTests {

    static class MyInjector extends AppStandbyController.Injector {
        long mElapsedRealtime;
        boolean mIsAppIdleEnabled = true;
        boolean mIsCharging;
        List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
        boolean mDisplayOn;
@@ -155,7 +156,7 @@ public class AppStandbyControllerTests {

        @Override
        boolean isAppIdleEnabled() {
            return true;
            return mIsAppIdleEnabled;
        }

        @Override
@@ -266,6 +267,13 @@ public class AppStandbyControllerTests {
        }
    }

    private void setAppIdleEnabled(AppStandbyController controller, boolean enabled) {
        mInjector.mIsAppIdleEnabled = enabled;
        if (controller != null) {
            controller.setAppIdleEnabled(enabled);
        }
    }

    private AppStandbyController setupController() throws Exception {
        mInjector.mElapsedRealtime = 0;
        setupPm(mInjector.getContext().getPackageManager());
@@ -335,7 +343,7 @@ public class AppStandbyControllerTests {
        public void onParoleStateChanged(boolean isParoleOn) {
            synchronized (this) {
                // Only record information if it is being looked for
                if (mLatch.getCount() > 0) {
                if (mLatch != null && mLatch.getCount() > 0) {
                    mOnParole = isParoleOn;
                    mLastParoleChangeTime = getCurrentTime();
                    mLatch.countDown();
@@ -396,6 +404,74 @@ public class AppStandbyControllerTests {
                marginOfError);
    }

    @Test
    public void testEnabledState() throws Exception {
        TestParoleListener paroleListener = new TestParoleListener();
        mController.addListener(paroleListener);
        long lastUpdateTime;

        // Test that listeners are notified if enabled changes when the device is not in parole.
        setChargingState(mController, false);

        // Start off not enabled. Device is effectively on permanent parole.
        setAppIdleEnabled(mController, false);

        // Enable controller
        paroleListener.rearmLatch();
        setAppIdleEnabled(mController, true);
        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
        assertFalse(paroleListener.mOnParole);
        lastUpdateTime = paroleListener.getLastParoleChangeTime();

        paroleListener.rearmLatch();
        setAppIdleEnabled(mController, true);
        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
        assertFalse(paroleListener.mOnParole);
        // Make sure AppStandbyController doesn't notify listeners when there's no change.
        assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());

        // Disable controller
        paroleListener.rearmLatch();
        setAppIdleEnabled(mController, false);
        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
        assertTrue(paroleListener.mOnParole);
        lastUpdateTime = paroleListener.getLastParoleChangeTime();

        paroleListener.rearmLatch();
        setAppIdleEnabled(mController, false);
        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
        assertTrue(paroleListener.mOnParole);
        // Make sure AppStandbyController doesn't notify listeners when there's no change.
        assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());


        // Test that listeners aren't notified if enabled status changes when the device is already
        // in parole.

        // A device is in parole whenever it's charging.
        setChargingState(mController, true);

        // Start off not enabled.
        paroleListener.rearmLatch();
        setAppIdleEnabled(mController, false);
        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
        assertTrue(paroleListener.mOnParole);
        lastUpdateTime = paroleListener.getLastParoleChangeTime();

        // Test that toggling doesn't notify the listener.
        paroleListener.rearmLatch();
        setAppIdleEnabled(mController, true);
        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
        assertTrue(paroleListener.mOnParole);
        assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());

        paroleListener.rearmLatch();
        setAppIdleEnabled(mController, false);
        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
        assertTrue(paroleListener.mOnParole);
        assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
    }

    private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
        mInjector.mElapsedRealtime = elapsedTime;
        controller.checkIdleStates(USER_ID);
+16 −6
Original line number Diff line number Diff line
@@ -30,18 +30,19 @@ import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;

import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;

@@ -340,14 +341,21 @@ public class AppStandbyController {
    }

    void setAppIdleEnabled(boolean enabled) {
        synchronized (mAppIdleLock) {
            if (mAppIdleEnabled != enabled) {
                final boolean oldParoleState = isParoledOrCharging();
                mAppIdleEnabled = enabled;
                if (isParoledOrCharging() != oldParoleState) {
                    postParoleStateChanged();
                }
            }
        }
    }

    public void onBootPhase(int phase) {
        mInjector.onBootPhase(phase);
        if (phase == PHASE_SYSTEM_SERVICES_READY) {
            Slog.d(TAG, "Setting app idle enabled state");
            setAppIdleEnabled(mInjector.isAppIdleEnabled());
            // Observe changes to the threshold
            SettingsObserver settingsObserver = new SettingsObserver(mHandler);
            settingsObserver.registerObserver();
@@ -1807,8 +1815,6 @@ public class AppStandbyController {
                        mContext.getContentResolver(),
                        Global.APP_IDLE_CONSTANTS));
            }
            // Check if app_idle_enabled has changed
            setAppIdleEnabled(mInjector.isAppIdleEnabled());

            // Look at global settings for this.
            // TODO: Maybe apply different thresholds for different users.
@@ -1880,6 +1886,10 @@ public class AppStandbyController {
                        (KEY_STABLE_CHARGING_THRESHOLD,
                                COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STABLE_CHARGING_THRESHOLD);
            }

            // Check if app_idle_enabled has changed. Do this after getting the rest of the settings
            // in case we need to change something based on the new values.
            setAppIdleEnabled(mInjector.isAppIdleEnabled());
        }

        long[] parseLongArray(String values, long[] defaults) {