Loading core/java/android/app/usage/UsageStatsManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -198,6 +198,8 @@ public final class UsageStatsManager { /** @hide */ public static final int REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED = 0x000E; /** @hide */ public static final int REASON_SUB_USAGE_FOREGROUND_SERVICE_START = 0x000F; /** @hide */ public static final int REASON_SUB_PREDICTED_RESTORED = 0x0001; Loading Loading @@ -997,6 +999,9 @@ public final class UsageStatsManager { case REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED: sb.append("-uss"); break; case REASON_SUB_USAGE_FOREGROUND_SERVICE_START: sb.append("-fss"); break; } break; } Loading core/java/android/provider/Settings.java +1 −0 Original line number Diff line number Diff line Loading @@ -11861,6 +11861,7 @@ public final class Settings { * sync_adapter_duration (long) * exempted_sync_duration (long) * system_interaction_duration (long) * initial_foreground_service_start_duration (long) * stable_charging_threshold (long) * * idle_duration (long) // This is deprecated and used to circumvent b/26355386. Loading services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +36 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.usage; import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START; import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN; import static android.app.usage.UsageEvents.Event.SLICE_PINNED; import static android.app.usage.UsageEvents.Event.SLICE_PINNED_PRIV; Loading Loading @@ -820,6 +821,41 @@ public class AppStandbyControllerTests { assertBucket(STANDBY_BUCKET_RARE); } @Test public void testInitialForegroundServiceTimeout() throws Exception { setChargingState(mController, false); mInjector.mElapsedRealtime = 1 * RARE_THRESHOLD + 100; // Make sure app is in NEVER bucket mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_MAIN_FORCED, mInjector.mElapsedRealtime); mController.checkIdleStates(USER_ID); assertBucket(STANDBY_BUCKET_NEVER); mInjector.mElapsedRealtime += 100; // Trigger a FOREGROUND_SERVICE_START and verify bucket reportEvent(mController, FOREGROUND_SERVICE_START, mInjector.mElapsedRealtime, PACKAGE_1); mController.checkIdleStates(USER_ID); assertBucket(STANDBY_BUCKET_ACTIVE); // Verify it's still in ACTIVE close to end of timeout mInjector.mElapsedRealtime += mController.mInitialForegroundServiceStartTimeoutMillis - 100; mController.checkIdleStates(USER_ID); assertBucket(STANDBY_BUCKET_ACTIVE); // Verify bucket moves to RARE after timeout mInjector.mElapsedRealtime += 200; mController.checkIdleStates(USER_ID); assertBucket(STANDBY_BUCKET_RARE); // Trigger a FOREGROUND_SERVICE_START again reportEvent(mController, FOREGROUND_SERVICE_START, mInjector.mElapsedRealtime, PACKAGE_1); mController.checkIdleStates(USER_ID); // Bucket should not be immediately elevated on subsequent service starts assertBucket(STANDBY_BUCKET_RARE); } @Test public void testPredictionNotOverridden() throws Exception { reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); Loading services/usage/java/com/android/server/usage/AppStandbyController.java +29 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOU import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_START; 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; Loading Loading @@ -238,6 +239,11 @@ public class AppStandbyController { long mUnexemptedSyncScheduledTimeoutMillis; /** Maximum time a system interaction should keep the buckets elevated. */ long mSystemInteractionTimeoutMillis; /** * Maximum time a foreground service start should keep the buckets elevated if the service * start is the first usage of the app */ long mInitialForegroundServiceStartTimeoutMillis; /** The length of time phone must be charging before considered stable enough to run jobs */ long mStableChargingThresholdMillis; Loading Loading @@ -877,7 +883,8 @@ public class AppStandbyController { || event.mEventType == UsageEvents.Event.USER_INTERACTION || event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN || event.mEventType == UsageEvents.Event.SLICE_PINNED || event.mEventType == UsageEvents.Event.SLICE_PINNED_PRIV)) { || event.mEventType == UsageEvents.Event.SLICE_PINNED_PRIV || event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) { final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory( event.mPackage, userId, elapsedRealtime); Loading @@ -898,6 +905,13 @@ public class AppStandbyController { STANDBY_BUCKET_ACTIVE, subReason, 0, elapsedRealtime + mSystemInteractionTimeoutMillis); nextCheckTime = mSystemInteractionTimeoutMillis; } else if (event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_START) { // Only elevate bucket if this is the first usage of the app if (prevBucket != STANDBY_BUCKET_NEVER) return; mAppIdleHistory.reportUsage(appHistory, event.mPackage, STANDBY_BUCKET_ACTIVE, subReason, 0, elapsedRealtime + mInitialForegroundServiceStartTimeoutMillis); nextCheckTime = mInitialForegroundServiceStartTimeoutMillis; } else { mAppIdleHistory.reportUsage(appHistory, event.mPackage, STANDBY_BUCKET_ACTIVE, subReason, Loading Loading @@ -930,6 +944,8 @@ public class AppStandbyController { case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN; case UsageEvents.Event.SLICE_PINNED: return REASON_SUB_USAGE_SLICE_PINNED; case UsageEvents.Event.SLICE_PINNED_PRIV: return REASON_SUB_USAGE_SLICE_PINNED_PRIV; case UsageEvents.Event.FOREGROUND_SERVICE_START: return REASON_SUB_USAGE_FOREGROUND_SERVICE_START; default: return 0; } } Loading Loading @@ -1509,6 +1525,9 @@ public class AppStandbyController { pw.print(" mSystemInteractionTimeoutMillis="); TimeUtils.formatDuration(mSystemInteractionTimeoutMillis, pw); pw.println(); pw.print(" mInitialForegroundServiceStartTimeoutMillis="); TimeUtils.formatDuration(mInitialForegroundServiceStartTimeoutMillis, pw); pw.println(); pw.print(" mPredictionTimeoutMillis="); TimeUtils.formatDuration(mPredictionTimeoutMillis, pw); Loading Loading @@ -1848,6 +1867,8 @@ public class AppStandbyController { "unexempted_sync_scheduled_duration"; private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION = "system_interaction_duration"; private static final String KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION = "initial_foreground_service_start_duration"; private static final String KEY_STABLE_CHARGING_THRESHOLD = "stable_charging_threshold"; public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR; public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR; Loading @@ -1859,6 +1880,7 @@ public class AppStandbyController { 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_STABLE_CHARGING_THRESHOLD = 10 * ONE_MINUTE; public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 30 * ONE_MINUTE; private final KeyValueListParser mParser = new KeyValueListParser(','); Loading Loading @@ -1964,6 +1986,12 @@ public class AppStandbyController { mSystemInteractionTimeoutMillis = mParser.getDurationMillis( KEY_SYSTEM_INTERACTION_HOLD_DURATION, COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT); mInitialForegroundServiceStartTimeoutMillis = mParser.getDurationMillis( KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION, COMPRESS_TIME ? ONE_MINUTE : DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT); mStableChargingThresholdMillis = mParser.getDurationMillis( KEY_STABLE_CHARGING_THRESHOLD, COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STABLE_CHARGING_THRESHOLD); Loading Loading
core/java/android/app/usage/UsageStatsManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -198,6 +198,8 @@ public final class UsageStatsManager { /** @hide */ public static final int REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED = 0x000E; /** @hide */ public static final int REASON_SUB_USAGE_FOREGROUND_SERVICE_START = 0x000F; /** @hide */ public static final int REASON_SUB_PREDICTED_RESTORED = 0x0001; Loading Loading @@ -997,6 +999,9 @@ public final class UsageStatsManager { case REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED: sb.append("-uss"); break; case REASON_SUB_USAGE_FOREGROUND_SERVICE_START: sb.append("-fss"); break; } break; } Loading
core/java/android/provider/Settings.java +1 −0 Original line number Diff line number Diff line Loading @@ -11861,6 +11861,7 @@ public final class Settings { * sync_adapter_duration (long) * exempted_sync_duration (long) * system_interaction_duration (long) * initial_foreground_service_start_duration (long) * stable_charging_threshold (long) * * idle_duration (long) // This is deprecated and used to circumvent b/26355386. Loading
services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +36 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.usage; import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START; import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN; import static android.app.usage.UsageEvents.Event.SLICE_PINNED; import static android.app.usage.UsageEvents.Event.SLICE_PINNED_PRIV; Loading Loading @@ -820,6 +821,41 @@ public class AppStandbyControllerTests { assertBucket(STANDBY_BUCKET_RARE); } @Test public void testInitialForegroundServiceTimeout() throws Exception { setChargingState(mController, false); mInjector.mElapsedRealtime = 1 * RARE_THRESHOLD + 100; // Make sure app is in NEVER bucket mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_MAIN_FORCED, mInjector.mElapsedRealtime); mController.checkIdleStates(USER_ID); assertBucket(STANDBY_BUCKET_NEVER); mInjector.mElapsedRealtime += 100; // Trigger a FOREGROUND_SERVICE_START and verify bucket reportEvent(mController, FOREGROUND_SERVICE_START, mInjector.mElapsedRealtime, PACKAGE_1); mController.checkIdleStates(USER_ID); assertBucket(STANDBY_BUCKET_ACTIVE); // Verify it's still in ACTIVE close to end of timeout mInjector.mElapsedRealtime += mController.mInitialForegroundServiceStartTimeoutMillis - 100; mController.checkIdleStates(USER_ID); assertBucket(STANDBY_BUCKET_ACTIVE); // Verify bucket moves to RARE after timeout mInjector.mElapsedRealtime += 200; mController.checkIdleStates(USER_ID); assertBucket(STANDBY_BUCKET_RARE); // Trigger a FOREGROUND_SERVICE_START again reportEvent(mController, FOREGROUND_SERVICE_START, mInjector.mElapsedRealtime, PACKAGE_1); mController.checkIdleStates(USER_ID); // Bucket should not be immediately elevated on subsequent service starts assertBucket(STANDBY_BUCKET_RARE); } @Test public void testPredictionNotOverridden() throws Exception { reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1); Loading
services/usage/java/com/android/server/usage/AppStandbyController.java +29 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOU import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_START; 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; Loading Loading @@ -238,6 +239,11 @@ public class AppStandbyController { long mUnexemptedSyncScheduledTimeoutMillis; /** Maximum time a system interaction should keep the buckets elevated. */ long mSystemInteractionTimeoutMillis; /** * Maximum time a foreground service start should keep the buckets elevated if the service * start is the first usage of the app */ long mInitialForegroundServiceStartTimeoutMillis; /** The length of time phone must be charging before considered stable enough to run jobs */ long mStableChargingThresholdMillis; Loading Loading @@ -877,7 +883,8 @@ public class AppStandbyController { || event.mEventType == UsageEvents.Event.USER_INTERACTION || event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN || event.mEventType == UsageEvents.Event.SLICE_PINNED || event.mEventType == UsageEvents.Event.SLICE_PINNED_PRIV)) { || event.mEventType == UsageEvents.Event.SLICE_PINNED_PRIV || event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) { final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory( event.mPackage, userId, elapsedRealtime); Loading @@ -898,6 +905,13 @@ public class AppStandbyController { STANDBY_BUCKET_ACTIVE, subReason, 0, elapsedRealtime + mSystemInteractionTimeoutMillis); nextCheckTime = mSystemInteractionTimeoutMillis; } else if (event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_START) { // Only elevate bucket if this is the first usage of the app if (prevBucket != STANDBY_BUCKET_NEVER) return; mAppIdleHistory.reportUsage(appHistory, event.mPackage, STANDBY_BUCKET_ACTIVE, subReason, 0, elapsedRealtime + mInitialForegroundServiceStartTimeoutMillis); nextCheckTime = mInitialForegroundServiceStartTimeoutMillis; } else { mAppIdleHistory.reportUsage(appHistory, event.mPackage, STANDBY_BUCKET_ACTIVE, subReason, Loading Loading @@ -930,6 +944,8 @@ public class AppStandbyController { case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN; case UsageEvents.Event.SLICE_PINNED: return REASON_SUB_USAGE_SLICE_PINNED; case UsageEvents.Event.SLICE_PINNED_PRIV: return REASON_SUB_USAGE_SLICE_PINNED_PRIV; case UsageEvents.Event.FOREGROUND_SERVICE_START: return REASON_SUB_USAGE_FOREGROUND_SERVICE_START; default: return 0; } } Loading Loading @@ -1509,6 +1525,9 @@ public class AppStandbyController { pw.print(" mSystemInteractionTimeoutMillis="); TimeUtils.formatDuration(mSystemInteractionTimeoutMillis, pw); pw.println(); pw.print(" mInitialForegroundServiceStartTimeoutMillis="); TimeUtils.formatDuration(mInitialForegroundServiceStartTimeoutMillis, pw); pw.println(); pw.print(" mPredictionTimeoutMillis="); TimeUtils.formatDuration(mPredictionTimeoutMillis, pw); Loading Loading @@ -1848,6 +1867,8 @@ public class AppStandbyController { "unexempted_sync_scheduled_duration"; private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION = "system_interaction_duration"; private static final String KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION = "initial_foreground_service_start_duration"; private static final String KEY_STABLE_CHARGING_THRESHOLD = "stable_charging_threshold"; public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR; public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR; Loading @@ -1859,6 +1880,7 @@ public class AppStandbyController { 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_STABLE_CHARGING_THRESHOLD = 10 * ONE_MINUTE; public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 30 * ONE_MINUTE; private final KeyValueListParser mParser = new KeyValueListParser(','); Loading Loading @@ -1964,6 +1986,12 @@ public class AppStandbyController { mSystemInteractionTimeoutMillis = mParser.getDurationMillis( KEY_SYSTEM_INTERACTION_HOLD_DURATION, COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT); mInitialForegroundServiceStartTimeoutMillis = mParser.getDurationMillis( KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION, COMPRESS_TIME ? ONE_MINUTE : DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT); mStableChargingThresholdMillis = mParser.getDurationMillis( KEY_STABLE_CHARGING_THRESHOLD, COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STABLE_CHARGING_THRESHOLD); Loading