summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java45
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java46
2 files changed, 88 insertions, 3 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
index 428f2cbaefc2..0f385efae5cc 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
@@ -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;
@@ -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() {
@@ -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();
@@ -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);
@@ -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
@@ -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);
@@ -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();
}
@@ -536,6 +570,11 @@ public class PrefetchController extends StateController {
//////////////////////// TESTING HELPERS /////////////////////////////
@VisibleForTesting
+ long getLaunchTimeAllowanceMs() {
+ return mLaunchTimeAllowanceMs;
+ }
+
+ @VisibleForTesting
long getLaunchTimeThresholdMs() {
return mLaunchTimeThresholdMs;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
index 8a954caad939..5f9f1b226958 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
@@ -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);
@@ -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);
@@ -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))
@@ -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);
@@ -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);
@@ -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);
@@ -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);
+ }
}