Loading apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java +42 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.job.controllers; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import static com.android.server.job.JobSchedulerService.sSystemClock; Loading Loading @@ -90,6 +91,14 @@ public class PrefetchController extends StateController { @CurrentTimeMillisLong private long mLaunchTimeThresholdMs = PcConstants.DEFAULT_LAUNCH_TIME_THRESHOLD_MS; /** * The additional time we'll add to a launch time estimate before considering it obsolete and * try to get a new estimate. This will help make prefetch jobs more viable in case an estimate * is a few minutes early. */ @GuardedBy("mLock") private long mLaunchTimeAllowanceMs = PcConstants.DEFAULT_LAUNCH_TIME_ALLOWANCE_MS; @SuppressWarnings("FieldCanBeLocal") private final EstimatedLaunchTimeChangedListener mEstimatedLaunchTimeChangedListener = new EstimatedLaunchTimeChangedListener() { Loading Loading @@ -204,7 +213,8 @@ public class PrefetchController extends StateController { private long getNextEstimatedLaunchTimeLocked(int userId, @NonNull String pkgName, @CurrentTimeMillisLong long now) { final Long nextEstimatedLaunchTime = mEstimatedLaunchTimes.get(userId, pkgName); if (nextEstimatedLaunchTime == null || nextEstimatedLaunchTime < now) { if (nextEstimatedLaunchTime == null || nextEstimatedLaunchTime < now - mLaunchTimeAllowanceMs) { // Don't query usage stats here because it may have to read from disk. mHandler.obtainMessage(MSG_RETRIEVE_ESTIMATED_LAUNCH_TIME, userId, 0, pkgName) .sendToTarget(); Loading Loading @@ -335,7 +345,9 @@ public class PrefetchController extends StateController { } final long nextEstimatedLaunchTime = getNextEstimatedLaunchTimeLocked(userId, pkgName, now); if (nextEstimatedLaunchTime - now > mLaunchTimeThresholdMs) { // Avoid setting an alarm for the end of time. if (nextEstimatedLaunchTime != Long.MAX_VALUE && nextEstimatedLaunchTime - now > mLaunchTimeThresholdMs) { // Set alarm to be notified when this crosses the threshold. final long timeToCrossThresholdMs = nextEstimatedLaunchTime - (now + mLaunchTimeThresholdMs); Loading @@ -354,7 +366,7 @@ public class PrefetchController extends StateController { private boolean willBeLaunchedSoonLocked(int userId, @NonNull String pkgName, @CurrentTimeMillisLong long now) { return getNextEstimatedLaunchTimeLocked(userId, pkgName, now) <= now + mLaunchTimeThresholdMs; <= now + mLaunchTimeThresholdMs - mLaunchTimeAllowanceMs; } @Override Loading Loading @@ -494,16 +506,37 @@ public class PrefetchController extends StateController { @VisibleForTesting static final String KEY_LAUNCH_TIME_THRESHOLD_MS = PC_CONSTANT_PREFIX + "launch_time_threshold_ms"; @VisibleForTesting static final String KEY_LAUNCH_TIME_ALLOWANCE_MS = PC_CONSTANT_PREFIX + "launch_time_allowance_ms"; private static final long DEFAULT_LAUNCH_TIME_THRESHOLD_MS = 7 * HOUR_IN_MILLIS; private static final long DEFAULT_LAUNCH_TIME_ALLOWANCE_MS = 20 * MINUTE_IN_MILLIS; /** How much time each app will have to run jobs within their standby bucket window. */ public long LAUNCH_TIME_THRESHOLD_MS = DEFAULT_LAUNCH_TIME_THRESHOLD_MS; /** * How much additional time to add to an estimated launch time before considering it * unusable. */ public long LAUNCH_TIME_ALLOWANCE_MS = DEFAULT_LAUNCH_TIME_ALLOWANCE_MS; @GuardedBy("mLock") public void processConstantLocked(@NonNull DeviceConfig.Properties properties, @NonNull String key) { switch (key) { case KEY_LAUNCH_TIME_ALLOWANCE_MS: LAUNCH_TIME_ALLOWANCE_MS = properties.getLong(key, DEFAULT_LAUNCH_TIME_ALLOWANCE_MS); // Limit the allowance to the range [0 minutes, 2 hours]. long newLaunchTimeAllowanceMs = Math.min(2 * HOUR_IN_MILLIS, Math.max(0, LAUNCH_TIME_ALLOWANCE_MS)); if (mLaunchTimeAllowanceMs != newLaunchTimeAllowanceMs) { mLaunchTimeAllowanceMs = newLaunchTimeAllowanceMs; mShouldReevaluateConstraints = true; } break; case KEY_LAUNCH_TIME_THRESHOLD_MS: LAUNCH_TIME_THRESHOLD_MS = properties.getLong(key, DEFAULT_LAUNCH_TIME_THRESHOLD_MS); Loading @@ -528,6 +561,7 @@ public class PrefetchController extends StateController { pw.increaseIndent(); pw.print(KEY_LAUNCH_TIME_THRESHOLD_MS, LAUNCH_TIME_THRESHOLD_MS).println(); pw.print(KEY_LAUNCH_TIME_ALLOWANCE_MS, LAUNCH_TIME_ALLOWANCE_MS).println(); pw.decreaseIndent(); } Loading @@ -535,6 +569,11 @@ public class PrefetchController extends StateController { //////////////////////// TESTING HELPERS ///////////////////////////// @VisibleForTesting long getLaunchTimeAllowanceMs() { return mLaunchTimeAllowanceMs; } @VisibleForTesting long getLaunchTimeThresholdMs() { return mLaunchTimeThresholdMs; Loading services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java +46 −0 Original line number Diff line number Diff line Loading @@ -233,27 +233,34 @@ public class PrefetchControllerTest { @Test public void testConstantsUpdating_ValidValues() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 5 * HOUR_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 5 * MINUTE_IN_MILLIS); assertEquals(5 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs()); assertEquals(5 * MINUTE_IN_MILLIS, mPrefetchController.getLaunchTimeAllowanceMs()); } @Test public void testConstantsUpdating_InvalidValues() { // Test negatives/too low. setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 4 * MINUTE_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, -MINUTE_IN_MILLIS); assertEquals(HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs()); assertEquals(0, mPrefetchController.getLaunchTimeAllowanceMs()); // Test larger than a day. Controller should cap at one day. setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 5 * HOUR_IN_MILLIS); assertEquals(24 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs()); assertEquals(2 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeAllowanceMs()); } @Test public void testConstantsUpdating_ThresholdChangesAlarms() { final long launchDelayMs = 11 * HOUR_IN_MILLIS; setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0); when(mUsageStatsManagerInternal .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID)) .thenReturn(sSystemClock.millis() + launchDelayMs); Loading @@ -276,6 +283,7 @@ public class PrefetchControllerTest { @Test public void testConstraintNotSatisfiedWhenLaunchLate() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS); final JobStatus job = createJobStatus("testConstraintNotSatisfiedWhenLaunchLate", 1); Loading @@ -290,6 +298,8 @@ public class PrefetchControllerTest { @Test public void testConstraintSatisfiedWhenLaunchSoon() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0); final JobStatus job = createJobStatus("testConstraintSatisfiedWhenLaunchSoon", 2); when(mUsageStatsManagerInternal .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID)) Loading Loading @@ -338,6 +348,8 @@ public class PrefetchControllerTest { @Test public void testConstraintSatisfiedWhenWidget() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0); final JobStatus jobNonWidget = createJobStatus("testConstraintSatisfiedWhenWidget", 1); final JobStatus jobWidget = createJobStatus("testConstraintSatisfiedWhenWidget", 2); Loading Loading @@ -365,6 +377,7 @@ public class PrefetchControllerTest { @Test public void testEstimatedLaunchTimeChangedToLate() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0); when(mUsageStatsManagerInternal .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID)) .thenReturn(sSystemClock.millis() + HOUR_IN_MILLIS); Loading Loading @@ -393,6 +406,7 @@ public class PrefetchControllerTest { @Test public void testEstimatedLaunchTimeChangedToSoon() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0); when(mUsageStatsManagerInternal .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID)) .thenReturn(sSystemClock.millis() + 10 * HOUR_IN_MILLIS); Loading @@ -413,4 +427,36 @@ public class PrefetchControllerTest { verify(mJobSchedulerService, timeout(DEFAULT_WAIT_MS)).onControllerStateChanged(any()); assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH)); } @Test public void testEstimatedLaunchTimeAllowance() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 15 * MINUTE_IN_MILLIS); when(mUsageStatsManagerInternal .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID)) .thenReturn(sSystemClock.millis() + 10 * HOUR_IN_MILLIS); InOrder inOrder = inOrder(mUsageStatsManagerInternal); JobStatus jobStatus = createJobStatus("testEstimatedLaunchTimeAllowance", 1); trackJobs(jobStatus); inOrder.verify(mUsageStatsManagerInternal, timeout(DEFAULT_WAIT_MS)) .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID); // The allowance shouldn't shift the alarm verify(mAlarmManager, timeout(DEFAULT_WAIT_MS).times(1)) .setWindow( anyInt(), eq(sElapsedRealtimeClock.millis() + 3 * HOUR_IN_MILLIS), anyLong(), eq(TAG_PREFETCH), any(), any()); assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH)); mEstimatedLaunchTimeChangedListener.onEstimatedLaunchTimeChanged(SOURCE_USER_ID, SOURCE_PACKAGE, sSystemClock.millis() + HOUR_IN_MILLIS); inOrder.verify(mUsageStatsManagerInternal, timeout(DEFAULT_WAIT_MS).times(0)) .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID); verify(mJobSchedulerService, timeout(DEFAULT_WAIT_MS)).onControllerStateChanged(any()); assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH)); sSystemClock = getShiftedClock(sSystemClock, HOUR_IN_MILLIS + MINUTE_IN_MILLIS); } } Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java +42 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.job.controllers; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import static com.android.server.job.JobSchedulerService.sSystemClock; Loading Loading @@ -90,6 +91,14 @@ public class PrefetchController extends StateController { @CurrentTimeMillisLong private long mLaunchTimeThresholdMs = PcConstants.DEFAULT_LAUNCH_TIME_THRESHOLD_MS; /** * The additional time we'll add to a launch time estimate before considering it obsolete and * try to get a new estimate. This will help make prefetch jobs more viable in case an estimate * is a few minutes early. */ @GuardedBy("mLock") private long mLaunchTimeAllowanceMs = PcConstants.DEFAULT_LAUNCH_TIME_ALLOWANCE_MS; @SuppressWarnings("FieldCanBeLocal") private final EstimatedLaunchTimeChangedListener mEstimatedLaunchTimeChangedListener = new EstimatedLaunchTimeChangedListener() { Loading Loading @@ -204,7 +213,8 @@ public class PrefetchController extends StateController { private long getNextEstimatedLaunchTimeLocked(int userId, @NonNull String pkgName, @CurrentTimeMillisLong long now) { final Long nextEstimatedLaunchTime = mEstimatedLaunchTimes.get(userId, pkgName); if (nextEstimatedLaunchTime == null || nextEstimatedLaunchTime < now) { if (nextEstimatedLaunchTime == null || nextEstimatedLaunchTime < now - mLaunchTimeAllowanceMs) { // Don't query usage stats here because it may have to read from disk. mHandler.obtainMessage(MSG_RETRIEVE_ESTIMATED_LAUNCH_TIME, userId, 0, pkgName) .sendToTarget(); Loading Loading @@ -335,7 +345,9 @@ public class PrefetchController extends StateController { } final long nextEstimatedLaunchTime = getNextEstimatedLaunchTimeLocked(userId, pkgName, now); if (nextEstimatedLaunchTime - now > mLaunchTimeThresholdMs) { // Avoid setting an alarm for the end of time. if (nextEstimatedLaunchTime != Long.MAX_VALUE && nextEstimatedLaunchTime - now > mLaunchTimeThresholdMs) { // Set alarm to be notified when this crosses the threshold. final long timeToCrossThresholdMs = nextEstimatedLaunchTime - (now + mLaunchTimeThresholdMs); Loading @@ -354,7 +366,7 @@ public class PrefetchController extends StateController { private boolean willBeLaunchedSoonLocked(int userId, @NonNull String pkgName, @CurrentTimeMillisLong long now) { return getNextEstimatedLaunchTimeLocked(userId, pkgName, now) <= now + mLaunchTimeThresholdMs; <= now + mLaunchTimeThresholdMs - mLaunchTimeAllowanceMs; } @Override Loading Loading @@ -494,16 +506,37 @@ public class PrefetchController extends StateController { @VisibleForTesting static final String KEY_LAUNCH_TIME_THRESHOLD_MS = PC_CONSTANT_PREFIX + "launch_time_threshold_ms"; @VisibleForTesting static final String KEY_LAUNCH_TIME_ALLOWANCE_MS = PC_CONSTANT_PREFIX + "launch_time_allowance_ms"; private static final long DEFAULT_LAUNCH_TIME_THRESHOLD_MS = 7 * HOUR_IN_MILLIS; private static final long DEFAULT_LAUNCH_TIME_ALLOWANCE_MS = 20 * MINUTE_IN_MILLIS; /** How much time each app will have to run jobs within their standby bucket window. */ public long LAUNCH_TIME_THRESHOLD_MS = DEFAULT_LAUNCH_TIME_THRESHOLD_MS; /** * How much additional time to add to an estimated launch time before considering it * unusable. */ public long LAUNCH_TIME_ALLOWANCE_MS = DEFAULT_LAUNCH_TIME_ALLOWANCE_MS; @GuardedBy("mLock") public void processConstantLocked(@NonNull DeviceConfig.Properties properties, @NonNull String key) { switch (key) { case KEY_LAUNCH_TIME_ALLOWANCE_MS: LAUNCH_TIME_ALLOWANCE_MS = properties.getLong(key, DEFAULT_LAUNCH_TIME_ALLOWANCE_MS); // Limit the allowance to the range [0 minutes, 2 hours]. long newLaunchTimeAllowanceMs = Math.min(2 * HOUR_IN_MILLIS, Math.max(0, LAUNCH_TIME_ALLOWANCE_MS)); if (mLaunchTimeAllowanceMs != newLaunchTimeAllowanceMs) { mLaunchTimeAllowanceMs = newLaunchTimeAllowanceMs; mShouldReevaluateConstraints = true; } break; case KEY_LAUNCH_TIME_THRESHOLD_MS: LAUNCH_TIME_THRESHOLD_MS = properties.getLong(key, DEFAULT_LAUNCH_TIME_THRESHOLD_MS); Loading @@ -528,6 +561,7 @@ public class PrefetchController extends StateController { pw.increaseIndent(); pw.print(KEY_LAUNCH_TIME_THRESHOLD_MS, LAUNCH_TIME_THRESHOLD_MS).println(); pw.print(KEY_LAUNCH_TIME_ALLOWANCE_MS, LAUNCH_TIME_ALLOWANCE_MS).println(); pw.decreaseIndent(); } Loading @@ -535,6 +569,11 @@ public class PrefetchController extends StateController { //////////////////////// TESTING HELPERS ///////////////////////////// @VisibleForTesting long getLaunchTimeAllowanceMs() { return mLaunchTimeAllowanceMs; } @VisibleForTesting long getLaunchTimeThresholdMs() { return mLaunchTimeThresholdMs; Loading
services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java +46 −0 Original line number Diff line number Diff line Loading @@ -233,27 +233,34 @@ public class PrefetchControllerTest { @Test public void testConstantsUpdating_ValidValues() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 5 * HOUR_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 5 * MINUTE_IN_MILLIS); assertEquals(5 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs()); assertEquals(5 * MINUTE_IN_MILLIS, mPrefetchController.getLaunchTimeAllowanceMs()); } @Test public void testConstantsUpdating_InvalidValues() { // Test negatives/too low. setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 4 * MINUTE_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, -MINUTE_IN_MILLIS); assertEquals(HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs()); assertEquals(0, mPrefetchController.getLaunchTimeAllowanceMs()); // Test larger than a day. Controller should cap at one day. setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 5 * HOUR_IN_MILLIS); assertEquals(24 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs()); assertEquals(2 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeAllowanceMs()); } @Test public void testConstantsUpdating_ThresholdChangesAlarms() { final long launchDelayMs = 11 * HOUR_IN_MILLIS; setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0); when(mUsageStatsManagerInternal .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID)) .thenReturn(sSystemClock.millis() + launchDelayMs); Loading @@ -276,6 +283,7 @@ public class PrefetchControllerTest { @Test public void testConstraintNotSatisfiedWhenLaunchLate() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS); final JobStatus job = createJobStatus("testConstraintNotSatisfiedWhenLaunchLate", 1); Loading @@ -290,6 +298,8 @@ public class PrefetchControllerTest { @Test public void testConstraintSatisfiedWhenLaunchSoon() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0); final JobStatus job = createJobStatus("testConstraintSatisfiedWhenLaunchSoon", 2); when(mUsageStatsManagerInternal .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID)) Loading Loading @@ -338,6 +348,8 @@ public class PrefetchControllerTest { @Test public void testConstraintSatisfiedWhenWidget() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0); final JobStatus jobNonWidget = createJobStatus("testConstraintSatisfiedWhenWidget", 1); final JobStatus jobWidget = createJobStatus("testConstraintSatisfiedWhenWidget", 2); Loading Loading @@ -365,6 +377,7 @@ public class PrefetchControllerTest { @Test public void testEstimatedLaunchTimeChangedToLate() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0); when(mUsageStatsManagerInternal .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID)) .thenReturn(sSystemClock.millis() + HOUR_IN_MILLIS); Loading Loading @@ -393,6 +406,7 @@ public class PrefetchControllerTest { @Test public void testEstimatedLaunchTimeChangedToSoon() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0); when(mUsageStatsManagerInternal .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID)) .thenReturn(sSystemClock.millis() + 10 * HOUR_IN_MILLIS); Loading @@ -413,4 +427,36 @@ public class PrefetchControllerTest { verify(mJobSchedulerService, timeout(DEFAULT_WAIT_MS)).onControllerStateChanged(any()); assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH)); } @Test public void testEstimatedLaunchTimeAllowance() { setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 15 * MINUTE_IN_MILLIS); when(mUsageStatsManagerInternal .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID)) .thenReturn(sSystemClock.millis() + 10 * HOUR_IN_MILLIS); InOrder inOrder = inOrder(mUsageStatsManagerInternal); JobStatus jobStatus = createJobStatus("testEstimatedLaunchTimeAllowance", 1); trackJobs(jobStatus); inOrder.verify(mUsageStatsManagerInternal, timeout(DEFAULT_WAIT_MS)) .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID); // The allowance shouldn't shift the alarm verify(mAlarmManager, timeout(DEFAULT_WAIT_MS).times(1)) .setWindow( anyInt(), eq(sElapsedRealtimeClock.millis() + 3 * HOUR_IN_MILLIS), anyLong(), eq(TAG_PREFETCH), any(), any()); assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH)); mEstimatedLaunchTimeChangedListener.onEstimatedLaunchTimeChanged(SOURCE_USER_ID, SOURCE_PACKAGE, sSystemClock.millis() + HOUR_IN_MILLIS); inOrder.verify(mUsageStatsManagerInternal, timeout(DEFAULT_WAIT_MS).times(0)) .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID); verify(mJobSchedulerService, timeout(DEFAULT_WAIT_MS)).onControllerStateChanged(any()); assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH)); sSystemClock = getShiftedClock(sSystemClock, HOUR_IN_MILLIS + MINUTE_IN_MILLIS); } }