diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index 784e85414e005..c534aa4195951 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -231,15 +231,6 @@ message ConstantsProto { // will use heartbeats, false will use a rolling window. optional bool use_heartbeats = 23; - message TimeController { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - // Whether or not TimeController should skip setting wakeup alarms for jobs that aren't - // ready now. - optional bool skip_not_ready_jobs = 1; - } - optional TimeController time_controller = 25; - message QuotaController { option (.android.msg_privacy).dest = DEST_AUTOMATIC; @@ -304,6 +295,15 @@ message ConstantsProto { } optional QuotaController quota_controller = 24; + message TimeController { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + // Whether or not TimeController should skip setting wakeup alarms for jobs that aren't + // ready now. + reserved 1; // skip_not_ready_jobs + } + optional TimeController time_controller = 25; + // Max number of jobs, when screen is ON. optional MaxJobCountsPerMemoryTrimLevelProto max_job_counts_screen_on = 26; diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java index ababad961c2de..4c11947212f97 100644 --- a/services/core/java/com/android/server/job/controllers/TimeController.java +++ b/services/core/java/com/android/server/job/controllers/TimeController.java @@ -18,20 +18,13 @@ package com.android.server.job.controllers; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlarmManager; import android.app.AlarmManager.OnAlarmListener; -import android.content.ContentResolver; import android.content.Context; -import android.database.ContentObserver; -import android.net.Uri; -import android.os.Handler; import android.os.Process; import android.os.UserHandle; import android.os.WorkSource; -import android.provider.Settings; -import android.util.KeyValueListParser; import android.util.Log; import android.util.Slog; import android.util.TimeUtils; @@ -39,7 +32,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; -import com.android.server.job.ConstantsProto; import com.android.server.job.JobSchedulerService; import com.android.server.job.StateControllerProto; @@ -63,9 +55,6 @@ public final class TimeController extends StateController { /** Delay alarm tag for logging purposes */ private final String DELAY_TAG = "*job.delay*"; - private final Handler mHandler; - private final TcConstants mTcConstants; - private long mNextJobExpiredElapsedMillis; private long mNextDelayExpiredElapsedMillis; @@ -81,14 +70,6 @@ public final class TimeController extends StateController { mNextJobExpiredElapsedMillis = Long.MAX_VALUE; mNextDelayExpiredElapsedMillis = Long.MAX_VALUE; mChainedAttributionEnabled = mService.isChainedAttributionEnabled(); - - mHandler = new Handler(mContext.getMainLooper()); - mTcConstants = new TcConstants(mHandler); - } - - @Override - public void onSystemServicesReady() { - mTcConstants.start(mContext.getContentResolver()); } /** @@ -133,20 +114,16 @@ public final class TimeController extends StateController { job.setTrackingController(JobStatus.TRACKING_TIME); WorkSource ws = deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()); - final long deadlineExpiredElapsed = - job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE; - final long delayExpiredElapsed = - job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE; - if (mTcConstants.SKIP_NOT_READY_JOBS) { - if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) { - maybeUpdateDelayAlarmLocked(delayExpiredElapsed, ws); - } - if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_DEADLINE)) { - maybeUpdateDeadlineAlarmLocked(deadlineExpiredElapsed, ws); - } - } else { - maybeUpdateDelayAlarmLocked(delayExpiredElapsed, ws); - maybeUpdateDeadlineAlarmLocked(deadlineExpiredElapsed, ws); + + // Only update alarms if the job would be ready with the relevant timing constraint + // satisfied. + if (job.hasTimingDelayConstraint() + && wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) { + maybeUpdateDelayAlarmLocked(job.getEarliestRunTime(), ws); + } + if (job.hasDeadlineConstraint() + && wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_DEADLINE)) { + maybeUpdateDeadlineAlarmLocked(job.getLatestRunTimeElapsed(), ws); } } } @@ -168,10 +145,6 @@ public final class TimeController extends StateController { @Override public void evaluateStateLocked(JobStatus job) { - if (!mTcConstants.SKIP_NOT_READY_JOBS) { - return; - } - final long nowElapsedMillis = sElapsedRealtimeClock.millis(); // Check deadline constraint first because if it's satisfied, we avoid a little bit of @@ -261,9 +234,7 @@ public final class TimeController extends StateController { } it.remove(); } else { // Sorted by expiry time, so take the next one and stop. - if (mTcConstants.SKIP_NOT_READY_JOBS - && !wouldBeReadyWithConstraintLocked( - job, JobStatus.CONSTRAINT_DEADLINE)) { + if (!wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_DEADLINE)) { if (DEBUG) { Slog.i(TAG, "Skipping " + job + " because deadline won't make it ready."); @@ -321,9 +292,7 @@ public final class TimeController extends StateController { ready = true; } } else { - if (mTcConstants.SKIP_NOT_READY_JOBS - && !wouldBeReadyWithConstraintLocked( - job, JobStatus.CONSTRAINT_TIMING_DELAY)) { + if (!wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) { if (DEBUG) { Slog.i(TAG, "Skipping " + job + " because delay won't make it ready."); @@ -458,81 +427,6 @@ public final class TimeController extends StateController { checkExpiredDelaysAndResetAlarm(); } - @VisibleForTesting - class TcConstants extends ContentObserver { - private ContentResolver mResolver; - private final KeyValueListParser mParser = new KeyValueListParser(','); - - private static final String KEY_SKIP_NOT_READY_JOBS = "skip_not_ready_jobs"; - - private static final boolean DEFAULT_SKIP_NOT_READY_JOBS = true; - - /** - * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't - * ready now. - */ - public boolean SKIP_NOT_READY_JOBS = DEFAULT_SKIP_NOT_READY_JOBS; - - /** - * Creates a content observer. - * - * @param handler The handler to run {@link #onChange} on, or null if none. - */ - TcConstants(Handler handler) { - super(handler); - } - - private void start(ContentResolver resolver) { - mResolver = resolver; - mResolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS), false, this); - onChange(true, null); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - final String constants = Settings.Global.getString( - mResolver, Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS); - - try { - mParser.setString(constants); - } catch (Exception e) { - // Failed to parse the settings string, log this and move on with defaults. - Slog.e(TAG, "Bad jobscheduler time controller settings", e); - } - - final boolean oldVal = SKIP_NOT_READY_JOBS; - SKIP_NOT_READY_JOBS = mParser.getBoolean( - KEY_SKIP_NOT_READY_JOBS, DEFAULT_SKIP_NOT_READY_JOBS); - - if (oldVal != SKIP_NOT_READY_JOBS) { - synchronized (mLock) { - recheckAlarmsLocked(); - } - } - } - - private void dump(IndentingPrintWriter pw) { - pw.println(); - pw.println("TimeController:"); - pw.increaseIndent(); - pw.printPair(KEY_SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS).println(); - pw.decreaseIndent(); - } - - private void dump(ProtoOutputStream proto) { - final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER); - proto.write(ConstantsProto.TimeController.SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS); - proto.end(tcToken); - } - } - - @VisibleForTesting - @NonNull - TcConstants getTcConstants() { - return mTcConstants; - } - @Override public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate predicate) { @@ -607,14 +501,4 @@ public final class TimeController extends StateController { proto.end(mToken); proto.end(token); } - - @Override - public void dumpConstants(IndentingPrintWriter pw) { - mTcConstants.dump(pw); - } - - @Override - public void dumpConstants(ProtoOutputStream proto) { - mTcConstants.dump(proto); - } } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java index 70b7bb6249206..3614763fecabb 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java @@ -71,7 +71,6 @@ public class TimeControllerTest { private static final String SOURCE_PACKAGE = "com.android.frameworks.mockingservicestests"; private static final int SOURCE_USER_ID = 0; - private TimeController.TcConstants mConstants; private TimeController mTimeController; private MockitoSession mMockingSession; @@ -111,7 +110,6 @@ public class TimeControllerTest { // Initialize real objects. mTimeController = new TimeController(mJobSchedulerService); - mConstants = mTimeController.getTcConstants(); spyOn(mTimeController); } @@ -159,18 +157,7 @@ public class TimeControllerTest { } @Test - public void testMaybeStartTrackingJobLocked_DelayInOrder_NoSkipping() { - mConstants.SKIP_NOT_READY_JOBS = false; - mTimeController.onConstantsUpdatedLocked(); - - runTestMaybeStartTrackingJobLocked_DelayInOrder(); - } - - @Test - public void testMaybeStartTrackingJobLocked_DelayInOrder_WithSkipping_AllReady() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); - + public void testMaybeStartTrackingJobLocked_DelayInOrder_AllReady() { doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); runTestMaybeStartTrackingJobLocked_DelayInOrder(); @@ -201,9 +188,7 @@ public class TimeControllerTest { } @Test - public void testMaybeStartTrackingJobLocked_DelayInOrder_WithSkipping_SomeNotReady() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); + public void testMaybeStartTrackingJobLocked_DelayInOrder_SomeNotReady() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); JobStatus jobLatest = createJobStatus("testMaybeStartTrackingJobLocked_DelayInOrder", @@ -235,18 +220,7 @@ public class TimeControllerTest { } @Test - public void testMaybeStartTrackingJobLocked_DelayReverseOrder_NoSkipping() { - mConstants.SKIP_NOT_READY_JOBS = false; - mTimeController.onConstantsUpdatedLocked(); - - runTestMaybeStartTrackingJobLocked_DelayReverseOrder(); - } - - @Test - public void testMaybeStartTrackingJobLocked_DelayReverseOrder_WithSkipping_AllReady() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); - + public void testMaybeStartTrackingJobLocked_DelayReverseOrder_AllReady() { doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); runTestMaybeStartTrackingJobLocked_DelayReverseOrder(); @@ -279,9 +253,7 @@ public class TimeControllerTest { } @Test - public void testMaybeStartTrackingJobLocked_DelayReverseOrder_WithSkipping_SomeNotReady() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); + public void testMaybeStartTrackingJobLocked_DelayReverseOrder_SomeNotReady() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); JobStatus jobLatest = createJobStatus("testMaybeStartTrackingJobLocked_DelayReverseOrder", @@ -315,18 +287,7 @@ public class TimeControllerTest { } @Test - public void testMaybeStartTrackingJobLocked_DeadlineInOrder_NoSkipping() { - mConstants.SKIP_NOT_READY_JOBS = false; - mTimeController.onConstantsUpdatedLocked(); - - runTestMaybeStartTrackingJobLocked_DeadlineInOrder(); - } - - @Test - public void testMaybeStartTrackingJobLocked_DeadlineInOrder_WithSkipping_AllReady() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); - + public void testMaybeStartTrackingJobLocked_DeadlineInOrder_AllReady() { doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); runTestMaybeStartTrackingJobLocked_DeadlineInOrder(); @@ -357,9 +318,7 @@ public class TimeControllerTest { } @Test - public void testMaybeStartTrackingJobLocked_DeadlineInOrder_WithSkipping_SomeNotReady() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); + public void testMaybeStartTrackingJobLocked_DeadlineInOrder_SomeNotReady() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); JobStatus jobLatest = createJobStatus("testMaybeStartTrackingJobLocked_DeadlineInOrder", @@ -391,18 +350,7 @@ public class TimeControllerTest { } @Test - public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_NoSkipping() { - mConstants.SKIP_NOT_READY_JOBS = false; - mTimeController.onConstantsUpdatedLocked(); - - runTestMaybeStartTrackingJobLocked_DeadlineReverseOrder(); - } - - @Test - public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_WithSkipping_AllReady() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); - + public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_AllReady() { doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); runTestMaybeStartTrackingJobLocked_DeadlineReverseOrder(); @@ -438,9 +386,7 @@ public class TimeControllerTest { } @Test - public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_WithSkipping_SomeNotReady() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); + public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_SomeNotReady() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); JobStatus jobLatest = createJobStatus( @@ -478,62 +424,7 @@ public class TimeControllerTest { } @Test - public void testJobSkipToggling() { - final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); - - JobStatus jobLatest = createJobStatus( - "testMaybeStartTrackingJobLocked_DeadlineReverseOrder", - createJob().setOverrideDeadline(HOUR_IN_MILLIS)); - JobStatus jobEarliest = createJobStatus( - "testMaybeStartTrackingJobLocked_DeadlineReverseOrder", - createJob().setOverrideDeadline(5 * MINUTE_IN_MILLIS)); - - doReturn(true).when(mTimeController) - .wouldBeReadyWithConstraintLocked(eq(jobLatest), anyInt()); - doReturn(false).when(mTimeController) - .wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt()); - - // Starting off with the skipping off, we should still set an alarm for the earlier job. - mConstants.SKIP_NOT_READY_JOBS = false; - mTimeController.recheckAlarmsLocked(); - InOrder inOrder = inOrder(mAlarmManager); - - mTimeController.maybeStartTrackingJobLocked(jobEarliest, null); - mTimeController.maybeStartTrackingJobLocked(jobLatest, null); - inOrder.verify(mAlarmManager, times(1)) - .set(anyInt(), eq(now + 5 * MINUTE_IN_MILLIS), anyLong(), anyLong(), - eq(TAG_DEADLINE), any(), any(), any()); - - // Turn it on, use alarm for later job. - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.recheckAlarmsLocked(); - - inOrder.verify(mAlarmManager, times(1)) - .set(anyInt(), eq(now + HOUR_IN_MILLIS), anyLong(), anyLong(), eq(TAG_DEADLINE), - any(), any(), any()); - - // Back off, use alarm for earlier job. - mConstants.SKIP_NOT_READY_JOBS = false; - mTimeController.recheckAlarmsLocked(); - - inOrder.verify(mAlarmManager, times(1)) - .set(anyInt(), eq(now + 5 * MINUTE_IN_MILLIS), anyLong(), anyLong(), - eq(TAG_DEADLINE), any(), any(), any()); - } - - @Test - public void testCheckExpiredDelaysAndResetAlarm_NoSkipping() { - mConstants.SKIP_NOT_READY_JOBS = false; - mTimeController.recheckAlarmsLocked(); - - runTestCheckExpiredDelaysAndResetAlarm(); - } - - @Test - public void testCheckExpiredDelaysAndResetAlarm_WithSkipping_AllReady() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.recheckAlarmsLocked(); - + public void testCheckExpiredDelaysAndResetAlarm_AllReady() { doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); runTestCheckExpiredDelaysAndResetAlarm(); @@ -589,9 +480,7 @@ public class TimeControllerTest { } @Test - public void testCheckExpiredDelaysAndResetAlarm_WithSkipping_SomeNotReady() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.recheckAlarmsLocked(); + public void testCheckExpiredDelaysAndResetAlarm_SomeNotReady() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); JobStatus jobLatest = createJobStatus("testCheckExpiredDelaysAndResetAlarm", @@ -639,18 +528,7 @@ public class TimeControllerTest { } @Test - public void testCheckExpiredDeadlinesAndResetAlarm_NoSkipping() { - mConstants.SKIP_NOT_READY_JOBS = false; - mTimeController.recheckAlarmsLocked(); - - runTestCheckExpiredDeadlinesAndResetAlarm(); - } - - @Test - public void testCheckExpiredDeadlinesAndResetAlarm_WithSkipping_AllReady() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.recheckAlarmsLocked(); - + public void testCheckExpiredDeadlinesAndResetAlarm_AllReady() { doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); runTestCheckExpiredDeadlinesAndResetAlarm(); @@ -706,9 +584,7 @@ public class TimeControllerTest { } @Test - public void testCheckExpiredDeadlinesAndResetAlarm_WithSkipping_SomeNotReady() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.recheckAlarmsLocked(); + public void testCheckExpiredDeadlinesAndResetAlarm_SomeNotReady() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); JobStatus jobLatest = createJobStatus("testCheckExpiredDeadlinesAndResetAlarm", @@ -756,28 +632,14 @@ public class TimeControllerTest { } @Test - public void testEvaluateStateLocked_SkippingOff() { - mConstants.SKIP_NOT_READY_JOBS = false; - mTimeController.recheckAlarmsLocked(); - JobStatus job = createJobStatus("testEvaluateStateLocked_SkippingOff", - createJob().setOverrideDeadline(HOUR_IN_MILLIS)); - - mTimeController.evaluateStateLocked(job); - verify(mAlarmManager, never()) - .set(anyInt(), anyLong(), anyLong(), anyLong(), anyString(), any(), any(), any()); - } - - @Test - public void testEvaluateStateLocked_SkippingOn_Delay() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.recheckAlarmsLocked(); + public void testEvaluateStateLocked_Delay() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); - JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_SkippingOn_Delay", + JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_Delay", createJob().setMinimumLatency(HOUR_IN_MILLIS)); - JobStatus jobMiddle = createJobStatus("testEvaluateStateLocked_SkippingOn_Delay", + JobStatus jobMiddle = createJobStatus("testEvaluateStateLocked_Delay", createJob().setMinimumLatency(30 * MINUTE_IN_MILLIS)); - JobStatus jobEarliest = createJobStatus("testEvaluateStateLocked_SkippingOn_Delay", + JobStatus jobEarliest = createJobStatus("testEvaluateStateLocked_Delay", createJob().setMinimumLatency(5 * MINUTE_IN_MILLIS)); doReturn(false).when(mTimeController) @@ -827,16 +689,14 @@ public class TimeControllerTest { } @Test - public void testEvaluateStateLocked_SkippingOn_Deadline() { - mConstants.SKIP_NOT_READY_JOBS = true; - mTimeController.recheckAlarmsLocked(); + public void testEvaluateStateLocked_Deadline() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); - JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_SkippingOn_Deadline", + JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_Deadline", createJob().setOverrideDeadline(HOUR_IN_MILLIS)); - JobStatus jobMiddle = createJobStatus("testEvaluateStateLocked_SkippingOn_Deadline", + JobStatus jobMiddle = createJobStatus("testEvaluateStateLocked_Deadline", createJob().setOverrideDeadline(30 * MINUTE_IN_MILLIS)); - JobStatus jobEarliest = createJobStatus("testEvaluateStateLocked_SkippingOn_Deadline", + JobStatus jobEarliest = createJobStatus("testEvaluateStateLocked_Deadline", createJob().setOverrideDeadline(5 * MINUTE_IN_MILLIS)); doReturn(false).when(mTimeController)