Loading core/proto/android/server/jobscheduler.proto +9 −9 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading services/core/java/com/android/server/job/controllers/TimeController.java +12 −128 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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()); } /** Loading Loading @@ -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); // 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); } } else { maybeUpdateDelayAlarmLocked(delayExpiredElapsed, ws); maybeUpdateDeadlineAlarmLocked(deadlineExpiredElapsed, ws); if (job.hasDeadlineConstraint() && wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_DEADLINE)) { maybeUpdateDeadlineAlarmLocked(job.getLatestRunTimeElapsed(), ws); } } } Loading @@ -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 Loading Loading @@ -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."); Loading Loading @@ -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."); Loading Loading @@ -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<JobStatus> predicate) { Loading Loading @@ -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); } } services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java +20 −160 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -111,7 +110,6 @@ public class TimeControllerTest { // Initialize real objects. mTimeController = new TimeController(mJobSchedulerService); mConstants = mTimeController.getTcConstants(); spyOn(mTimeController); } Loading Loading @@ -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(); Loading Loading @@ -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", Loading Loading @@ -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(); Loading Loading @@ -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", Loading Loading @@ -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(); Loading Loading @@ -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", Loading Loading @@ -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(); Loading Loading @@ -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( Loading Loading @@ -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(); Loading Loading @@ -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", Loading Loading @@ -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(); Loading Loading @@ -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", Loading Loading @@ -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) Loading Loading @@ -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) Loading Loading
core/proto/android/server/jobscheduler.proto +9 −9 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading
services/core/java/com/android/server/job/controllers/TimeController.java +12 −128 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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()); } /** Loading Loading @@ -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); // 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); } } else { maybeUpdateDelayAlarmLocked(delayExpiredElapsed, ws); maybeUpdateDeadlineAlarmLocked(deadlineExpiredElapsed, ws); if (job.hasDeadlineConstraint() && wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_DEADLINE)) { maybeUpdateDeadlineAlarmLocked(job.getLatestRunTimeElapsed(), ws); } } } Loading @@ -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 Loading Loading @@ -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."); Loading Loading @@ -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."); Loading Loading @@ -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<JobStatus> predicate) { Loading Loading @@ -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); } }
services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java +20 −160 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -111,7 +110,6 @@ public class TimeControllerTest { // Initialize real objects. mTimeController = new TimeController(mJobSchedulerService); mConstants = mTimeController.getTcConstants(); spyOn(mTimeController); } Loading Loading @@ -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(); Loading Loading @@ -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", Loading Loading @@ -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(); Loading Loading @@ -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", Loading Loading @@ -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(); Loading Loading @@ -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", Loading Loading @@ -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(); Loading Loading @@ -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( Loading Loading @@ -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(); Loading Loading @@ -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", Loading Loading @@ -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(); Loading Loading @@ -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", Loading Loading @@ -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) Loading Loading @@ -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) Loading