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 df44a07829c95..f1bfa0411978e 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -663,7 +663,7 @@ public class AppStandbyController implements AppStandbyInternal { if (app.lastRestrictAttemptElapsedTime > app.lastUsedByUserElapsedTime && elapsedTimeAdjusted - app.lastUsedByUserElapsedTime - >= mInjector.getRestrictedBucketDelayMs()) { + >= mInjector.getAutoRestrictedBucketDelayMs()) { newBucket = STANDBY_BUCKET_RESTRICTED; reason = app.lastRestrictReason; if (DEBUG) { @@ -1219,7 +1219,7 @@ public class AppStandbyController implements AppStandbyInternal { } } else { final long timeUntilRestrictPossibleMs = app.lastUsedByUserElapsedTime - + mInjector.getRestrictedBucketDelayMs() - elapsedRealtime; + + mInjector.getAutoRestrictedBucketDelayMs() - elapsedRealtime; if (timeUntilRestrictPossibleMs > 0) { Slog.w(TAG, "Tried to restrict recently used app: " + packageName + " due to " + reason); @@ -1566,10 +1566,9 @@ public class AppStandbyController implements AppStandbyInternal { int mBootPhase; /** * The minimum amount of time required since the last user interaction before an app can be - * placed in the RESTRICTED bucket. + * automatically placed in the RESTRICTED bucket. */ - // TODO: make configurable via DeviceConfig - private long mRestrictedBucketDelayMs = ONE_DAY; + long mAutoRestrictedBucketDelayMs = ONE_DAY; Injector(Context context, Looper looper) { mContext = context; @@ -1598,7 +1597,7 @@ public class AppStandbyController implements AppStandbyInternal { final ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); if (activityManager.isLowRamDevice() || ActivityManager.isSmallBatteryDevice()) { - mRestrictedBucketDelayMs = 12 * ONE_HOUR; + mAutoRestrictedBucketDelayMs = 12 * ONE_HOUR; } } mBootPhase = phase; @@ -1639,8 +1638,13 @@ public class AppStandbyController implements AppStandbyInternal { return Environment.getDataSystemDirectory(); } - long getRestrictedBucketDelayMs() { - return mRestrictedBucketDelayMs; + /** + * Return the minimum amount of time that must have passed since the last user usage before + * an app can be automatically put into the + * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket. + */ + long getAutoRestrictedBucketDelayMs() { + return mAutoRestrictedBucketDelayMs; } void noteEvent(int event, String packageName, int uid) throws RemoteException { @@ -1816,6 +1820,8 @@ public class AppStandbyController implements AppStandbyInternal { "system_interaction_duration"; private static final String KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION = "initial_foreground_service_start_duration"; + private static final String KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS = + "auto_restricted_bucket_delay_ms"; public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR; public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR; public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR; @@ -1826,6 +1832,7 @@ public class AppStandbyController implements AppStandbyInternal { public static final long DEFAULT_EXEMPTED_SYNC_START_TIMEOUT = 10 * ONE_MINUTE; public static final long DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT = 10 * ONE_MINUTE; public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 30 * ONE_MINUTE; + public static final long DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS = ONE_DAY; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -1925,6 +1932,12 @@ public class AppStandbyController implements AppStandbyInternal { KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION, COMPRESS_TIME ? ONE_MINUTE : DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT); + + mInjector.mAutoRestrictedBucketDelayMs = Math.max( + COMPRESS_TIME ? ONE_MINUTE : 2 * ONE_HOUR, + mParser.getDurationMillis(KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS, + COMPRESS_TIME + ? ONE_MINUTE : DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS)); } // Check if app_idle_enabled has changed. Do this after getting the rest of the settings 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 290683ddb7a13..e768205c2cf49 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -685,7 +685,30 @@ public class AppStandbyControllerTests { reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); assertBucket(STANDBY_BUCKET_ACTIVE); - mInjector.mElapsedRealtime += mInjector.getRestrictedBucketDelayMs() - 5000; + mInjector.mElapsedRealtime += mInjector.getAutoRestrictedBucketDelayMs() - 5000; + mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED, + REASON_MAIN_FORCED_BY_SYSTEM); + // Bucket shouldn't change + assertBucket(STANDBY_BUCKET_ACTIVE); + + // bucketing works after timeout + mInjector.mElapsedRealtime += 6000; + + Thread.sleep(6000); + // Enough time has passed. The app should automatically be put into the RESTRICTED bucket. + assertBucket(STANDBY_BUCKET_RESTRICTED); + } + + /** + * Test that an app is put into the RESTRICTED bucket after enough time has passed. + */ + @Test + public void testRestrictedDelay_DelayChange() throws Exception { + reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); + assertBucket(STANDBY_BUCKET_ACTIVE); + + mInjector.mAutoRestrictedBucketDelayMs = 2 * HOUR_MS; + mInjector.mElapsedRealtime += 2 * HOUR_MS - 5000; mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED, REASON_MAIN_FORCED_BY_SYSTEM); // Bucket shouldn't change