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

Commit 2d79ce5f authored by Kweku Adams's avatar Kweku Adams
Browse files

Add master switch to enable/disable RESTRICTED bucket.

Adding a master on/off switch for the new bucket such that when it's off,
apps aren't be put into the bucket and any apps already in it are brought
out.

Bug: 155670438
Test: atest FrameworksServicesTests:AppIdleHistoryTests
Test: atest FrameworksServicesTests:AppStandbyControllerTests
Test: atest SettingsProviderTest:SettingsBackupTest
Change-Id: Iaeabefa14cbaa2d07a13555ecbc29e6fbf11a29c
parent bf8d4b44
Loading
Loading
Loading
Loading
+37 −3
Original line number Diff line number Diff line
@@ -293,6 +293,13 @@ public class AppStandbyController implements AppStandbyInternal {
     * {@link #setAppStandbyBucket(String, int, int, int, int)} will not be propagated.
     */
    boolean mLinkCrossProfileApps;
    /**
     * Whether we should allow apps into the
     * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket or not.
     * If false, any attempts to put an app into the bucket will put the app into the
     * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RARE} bucket instead.
     */
    private boolean mAllowRestrictedBucket;

    private volatile boolean mAppIdleEnabled;
    private boolean mIsCharging;
@@ -667,6 +674,10 @@ public class AppStandbyController implements AppStandbyInternal {
                    return;
                }
                final int oldBucket = app.currentBucket;
                if (oldBucket == STANDBY_BUCKET_NEVER) {
                    // None of this should bring an app out of the NEVER bucket.
                    return;
                }
                int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED
                boolean predictionLate = predictionTimedOut(app, elapsedRealtime);
                // Compute age-based bucket
@@ -722,11 +733,18 @@ public class AppStandbyController implements AppStandbyInternal {
                        Slog.d(TAG, "Bringing down to RESTRICTED due to timeout");
                    }
                }
                if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) {
                    newBucket = STANDBY_BUCKET_RARE;
                    // Leave the reason alone.
                    if (DEBUG) {
                        Slog.d(TAG, "Bringing up from RESTRICTED to RARE due to off switch");
                    }
                }
                if (DEBUG) {
                    Slog.d(TAG, "     Old bucket=" + oldBucket
                            + ", newBucket=" + newBucket);
                }
                if (oldBucket < newBucket || predictionLate) {
                if (oldBucket != newBucket || predictionLate) {
                    mAppIdleHistory.setAppStandbyBucket(packageName, userId,
                            elapsedRealtime, newBucket, reason);
                    maybeInformListeners(packageName, userId, elapsedRealtime,
@@ -1176,8 +1194,8 @@ public class AppStandbyController implements AppStandbyInternal {

        final int reason = REASON_MAIN_FORCED_BY_SYSTEM | (REASON_SUB_MASK & restrictReason);
        final long nowElapsed = mInjector.elapsedRealtime();
        setAppStandbyBucket(packageName, userId, STANDBY_BUCKET_RESTRICTED, reason,
                nowElapsed, false);
        final int bucket = mAllowRestrictedBucket ? STANDBY_BUCKET_RESTRICTED : STANDBY_BUCKET_RARE;
        setAppStandbyBucket(packageName, userId, bucket, reason, nowElapsed, false);
    }

    @Override
@@ -1247,6 +1265,9 @@ public class AppStandbyController implements AppStandbyInternal {
                Slog.e(TAG, "Tried to set bucket of uninstalled app: " + packageName);
                return;
            }
            if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) {
                newBucket = STANDBY_BUCKET_RARE;
            }
            AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName,
                    userId, elapsedRealtime);
            boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED;
@@ -1365,6 +1386,7 @@ public class AppStandbyController implements AppStandbyInternal {
                        Slog.d(TAG, "    Keeping at WORKING_SET due to min timeout");
                    }
                } else if (newBucket == STANDBY_BUCKET_RARE
                        && mAllowRestrictedBucket
                        && getBucketForLocked(packageName, userId, elapsedRealtime)
                        == STANDBY_BUCKET_RESTRICTED) {
                    // Prediction doesn't think the app will be used anytime soon and
@@ -1697,6 +1719,8 @@ public class AppStandbyController implements AppStandbyInternal {

        pw.println();
        pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
        pw.print(" mAllowRestrictedBucket=");
        pw.print(mAllowRestrictedBucket);
        pw.print(" mIsCharging=");
        pw.print(mIsCharging);
        pw.println();
@@ -1798,6 +1822,12 @@ public class AppStandbyController implements AppStandbyInternal {
            return mPowerWhitelistManager.isWhitelisted(packageName, false);
        }

        boolean isRestrictedBucketEnabled() {
            return Global.getInt(mContext.getContentResolver(),
                    Global.ENABLE_RESTRICTED_BUCKET,
                    Global.DEFAULT_ENABLE_RESTRICTED_BUCKET) == 1;
        }

        File getDataSystemDirectory() {
            return Environment.getDataSystemDirectory();
        }
@@ -2031,6 +2061,8 @@ public class AppStandbyController implements AppStandbyInternal {
            final ContentResolver cr = mContext.getContentResolver();
            cr.registerContentObserver(Global.getUriFor(Global.APP_IDLE_CONSTANTS), false, this);
            cr.registerContentObserver(Global.getUriFor(Global.APP_STANDBY_ENABLED), false, this);
            cr.registerContentObserver(Global.getUriFor(Global.ENABLE_RESTRICTED_BUCKET),
                    false, this);
            cr.registerContentObserver(Global.getUriFor(Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED),
                    false, this);
        }
@@ -2129,6 +2161,8 @@ public class AppStandbyController implements AppStandbyInternal {
                mLinkCrossProfileApps = mParser.getBoolean(
                        KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS,
                        DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS);

                mAllowRestrictedBucket = mInjector.isRestrictedBucketEnabled();
            }

            // Check if app_idle_enabled has changed. Do this after getting the rest of the settings
+17 −1
Original line number Diff line number Diff line
@@ -11947,6 +11947,22 @@ public final class Settings {
        public static final String ADAPTIVE_BATTERY_MANAGEMENT_ENABLED =
                "adaptive_battery_management_enabled";
        /**
         * Whether or not apps are allowed into the
         * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket.
         * Type: int (0 for false, 1 for true)
         * Default: {@value #DEFAULT_ENABLE_RESTRICTED_BUCKET}
         *
         * @hide
         */
        public static final String ENABLE_RESTRICTED_BUCKET = "enable_restricted_bucket";
        /**
         * @see #ENABLE_RESTRICTED_BUCKET
         * @hide
         */
        public static final int DEFAULT_ENABLE_RESTRICTED_BUCKET = 1;
        /**
         * Whether or not app auto restriction is enabled. When it is enabled, settings app will
         * auto restrict the app if it has bad behavior (e.g. hold wakelock for long time).
+1 −0
Original line number Diff line number Diff line
@@ -264,6 +264,7 @@ public class SettingsBackupTest {
                    Settings.Global.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE,
                    Settings.Global.ENABLE_DISKSTATS_LOGGING,
                    Settings.Global.ENABLE_EPHEMERAL_FEATURE,
                    Settings.Global.ENABLE_RESTRICTED_BUCKET,
                    Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
                    Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
                    Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
+52 −0
Original line number Diff line number Diff line
@@ -165,6 +165,7 @@ public class AppStandbyControllerTests {
        long mElapsedRealtime;
        boolean mIsAppIdleEnabled = true;
        boolean mIsCharging;
        boolean mIsRestrictedBucketEnabled = true;
        List<String> mNonIdleWhitelistApps = new ArrayList<>();
        boolean mDisplayOn;
        DisplayManager.DisplayListener mDisplayListener;
@@ -211,6 +212,11 @@ public class AppStandbyControllerTests {
            return mNonIdleWhitelistApps.contains(packageName);
        }

        @Override
        boolean isRestrictedBucketEnabled() {
            return mIsRestrictedBucketEnabled;
        }

        @Override
        File getDataSystemDirectory() {
            return new File(getContext().getFilesDir(), Long.toString(Math.randomLongInternal()));
@@ -447,6 +453,10 @@ public class AppStandbyControllerTests {
        assertEquals(bucket, getStandbyBucket(mController, PACKAGE_1));
    }

    private void assertNotBucket(int bucket) {
        assertNotEquals(bucket, getStandbyBucket(mController, PACKAGE_1));
    }

    @Test
    public void testBuckets() throws Exception {
        assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
@@ -881,6 +891,48 @@ public class AppStandbyControllerTests {
        assertBucket(STANDBY_BUCKET_RESTRICTED);
    }

    @Test
    public void testRestrictedBucketDisabled() {
        mInjector.mIsRestrictedBucketEnabled = false;
        // Get the controller to read the new value. Capturing the ContentObserver isn't possible
        // at the moment.
        mController.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);

        reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
        mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;

        // Nothing should be able to put it into the RESTRICTED bucket.
        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
                REASON_MAIN_TIMEOUT);
        assertNotBucket(STANDBY_BUCKET_RESTRICTED);
        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
                REASON_MAIN_PREDICTED);
        assertNotBucket(STANDBY_BUCKET_RESTRICTED);
        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
                REASON_MAIN_FORCED_BY_SYSTEM);
        assertNotBucket(STANDBY_BUCKET_RESTRICTED);
        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
                REASON_MAIN_FORCED_BY_USER);
        assertNotBucket(STANDBY_BUCKET_RESTRICTED);
    }

    @Test
    public void testRestrictedBucket_EnabledToDisabled() {
        reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
        mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
                REASON_MAIN_FORCED_BY_SYSTEM);
        assertBucket(STANDBY_BUCKET_RESTRICTED);

        mInjector.mIsRestrictedBucketEnabled = false;
        // Get the controller to read the new value. Capturing the ContentObserver isn't possible
        // at the moment.
        mController.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);

        mController.checkIdleStates(USER_ID);
        assertNotBucket(STANDBY_BUCKET_RESTRICTED);
    }

    @Test
    public void testPredictionRaiseFromRestrictedTimeout_highBucket() {
        reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);