summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java40
-rwxr-xr-xcore/java/android/provider/Settings.java18
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java52
4 files changed, 107 insertions, 4 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index cb5cb175ff24..980372d58f33 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -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;
@@ -688,6 +695,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
@@ -743,11 +754,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,
@@ -1197,8 +1215,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
@@ -1268,6 +1286,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;
@@ -1386,6 +1407,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
@@ -1727,6 +1749,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();
@@ -1828,6 +1852,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();
}
@@ -2066,6 +2096,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);
}
@@ -2164,6 +2196,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
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c0d0c21af1ab..ae88ba5e08c5 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11956,8 +11956,24 @@ public final class Settings {
"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).
+ * auto restrict the app if it has bad behavior (e.g. hold wakelock for long time).
*
* Type: boolean (0 for false, 1 for true)
* Default: 1
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 4a9eba2202e3..29c31eaddfa6 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -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,
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 6718db768fdb..48e22f6c685c 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -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;
@@ -212,6 +213,11 @@ public class AppStandbyControllerTests {
}
@Override
+ boolean isRestrictedBucketEnabled() {
+ return mIsRestrictedBucketEnabled;
+ }
+
+ @Override
File getDataSystemDirectory() {
return new File(getContext().getFilesDir(), Long.toString(Math.randomLongInternal()));
}
@@ -511,6 +517,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);
@@ -946,6 +956,48 @@ public class AppStandbyControllerTests {
}
@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);