Merge "Throttle how frequently delay alarms are set."
This commit is contained in:
committed by
Android (Google) Code Review
commit
70780830c2
@@ -50,6 +50,9 @@ public final class TimeController extends StateController {
|
||||
private static final boolean DEBUG = JobSchedulerService.DEBUG
|
||||
|| Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
@VisibleForTesting
|
||||
static final long DELAY_COALESCE_TIME_MS = 30_000L;
|
||||
|
||||
/** Deadline alarm tag for logging purposes */
|
||||
private final String DEADLINE_TAG = "*job.deadline*";
|
||||
/** Delay alarm tag for logging purposes */
|
||||
@@ -57,6 +60,7 @@ public final class TimeController extends StateController {
|
||||
|
||||
private long mNextJobExpiredElapsedMillis;
|
||||
private long mNextDelayExpiredElapsedMillis;
|
||||
private volatile long mLastFiredDelayExpiredElapsedMillis;
|
||||
|
||||
private final boolean mChainedAttributionEnabled;
|
||||
|
||||
@@ -273,7 +277,6 @@ public final class TimeController extends StateController {
|
||||
@VisibleForTesting
|
||||
void checkExpiredDelaysAndResetAlarm() {
|
||||
synchronized (mLock) {
|
||||
final long nowElapsedMillis = sElapsedRealtimeClock.millis();
|
||||
long nextDelayTime = Long.MAX_VALUE;
|
||||
int nextDelayUid = 0;
|
||||
String nextDelayPackageName = null;
|
||||
@@ -284,7 +287,7 @@ public final class TimeController extends StateController {
|
||||
if (!job.hasTimingDelayConstraint()) {
|
||||
continue;
|
||||
}
|
||||
if (evaluateTimingDelayConstraint(job, nowElapsedMillis)) {
|
||||
if (evaluateTimingDelayConstraint(job, sElapsedRealtimeClock.millis())) {
|
||||
if (canStopTrackingJobLocked(job)) {
|
||||
it.remove();
|
||||
}
|
||||
@@ -356,7 +359,11 @@ public final class TimeController extends StateController {
|
||||
* This alarm <b>will not</b> wake up the phone.
|
||||
*/
|
||||
private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
|
||||
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
|
||||
// To avoid spamming AlarmManager in the case where many delay times are a few milliseconds
|
||||
// apart, make sure the alarm is set no earlier than DELAY_COALESCE_TIME_MS since the last
|
||||
// time a delay alarm went off and that the alarm is not scheduled for the past.
|
||||
alarmTimeElapsedMillis = maybeAdjustAlarmTime(Math.max(alarmTimeElapsedMillis,
|
||||
mLastFiredDelayExpiredElapsedMillis + DELAY_COALESCE_TIME_MS));
|
||||
if (mNextDelayExpiredElapsedMillis == alarmTimeElapsedMillis) {
|
||||
return;
|
||||
}
|
||||
@@ -416,6 +423,7 @@ public final class TimeController extends StateController {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Delay-expired alarm fired");
|
||||
}
|
||||
mLastFiredDelayExpiredElapsedMillis = sElapsedRealtimeClock.millis();
|
||||
checkExpiredDelaysAndResetAlarm();
|
||||
}
|
||||
};
|
||||
@@ -429,6 +437,9 @@ public final class TimeController extends StateController {
|
||||
pw.print("Next delay alarm in ");
|
||||
TimeUtils.formatDuration(mNextDelayExpiredElapsedMillis, nowElapsed, pw);
|
||||
pw.println();
|
||||
pw.print("Last delay alarm fired @ ");
|
||||
TimeUtils.formatDuration(nowElapsed, mLastFiredDelayExpiredElapsedMillis, pw);
|
||||
pw.println();
|
||||
pw.print("Next deadline alarm in ");
|
||||
TimeUtils.formatDuration(mNextJobExpiredElapsedMillis, nowElapsed, pw);
|
||||
pw.println();
|
||||
|
||||
@@ -52,6 +52,7 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoSession;
|
||||
@@ -631,6 +632,50 @@ public class TimeControllerTest {
|
||||
.set(anyInt(), anyLong(), anyLong(), anyLong(), anyString(), any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelayAlarmSchedulingCoalescedIntervals() {
|
||||
doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
|
||||
|
||||
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
|
||||
|
||||
JobStatus jobLatest = createJobStatus("testDelayAlarmSchedulingCoalescedIntervals",
|
||||
createJob().setMinimumLatency(HOUR_IN_MILLIS));
|
||||
JobStatus jobMiddle = createJobStatus("testDelayAlarmSchedulingCoalescedIntervals",
|
||||
createJob().setMinimumLatency(TimeController.DELAY_COALESCE_TIME_MS / 2));
|
||||
JobStatus jobEarliest = createJobStatus("testDelayAlarmSchedulingCoalescedIntervals",
|
||||
createJob().setMinimumLatency(TimeController.DELAY_COALESCE_TIME_MS / 10));
|
||||
|
||||
ArgumentCaptor<AlarmManager.OnAlarmListener> listenerCaptor =
|
||||
ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
|
||||
InOrder inOrder = inOrder(mAlarmManager);
|
||||
|
||||
mTimeController.maybeStartTrackingJobLocked(jobEarliest, null);
|
||||
mTimeController.maybeStartTrackingJobLocked(jobMiddle, null);
|
||||
mTimeController.maybeStartTrackingJobLocked(jobLatest, null);
|
||||
inOrder.verify(mAlarmManager, times(1))
|
||||
.set(anyInt(), eq(now + TimeController.DELAY_COALESCE_TIME_MS / 10), anyLong(),
|
||||
anyLong(), eq(TAG_DELAY),
|
||||
listenerCaptor.capture(), any(), any());
|
||||
final AlarmManager.OnAlarmListener delayListener = listenerCaptor.getValue();
|
||||
|
||||
advanceElapsedClock(TimeController.DELAY_COALESCE_TIME_MS / 10);
|
||||
delayListener.onAlarm();
|
||||
// The next delay alarm time should be TimeController.DELAY_COALESCE_TIME_MS after the last
|
||||
// time the delay alarm fired.
|
||||
inOrder.verify(mAlarmManager, times(1))
|
||||
.set(anyInt(), eq(now + TimeController.DELAY_COALESCE_TIME_MS / 10
|
||||
+ TimeController.DELAY_COALESCE_TIME_MS), anyLong(),
|
||||
anyLong(), eq(TAG_DELAY), any(), any(), any());
|
||||
|
||||
advanceElapsedClock(TimeController.DELAY_COALESCE_TIME_MS);
|
||||
delayListener.onAlarm();
|
||||
// The last job is significantly after the coalesce time, so the 3rd scheduling shouldn't be
|
||||
// affected by the first two jobs' alarms.
|
||||
inOrder.verify(mAlarmManager, times(1))
|
||||
.set(anyInt(), eq(now + HOUR_IN_MILLIS), anyLong(),
|
||||
anyLong(), eq(TAG_DELAY), any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateStateLocked_Delay() {
|
||||
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
|
||||
|
||||
Reference in New Issue
Block a user