Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 39cc594d authored by Kweku Adams's avatar Kweku Adams
Browse files

Reduce job readiness checking.

Don't check the full list of jobs whenever we evaluate a single job's
state. Every job that's not ready would be checked anyway.

Note, however, that not checking the list if a job would not be ready
means we will not defer an already set alarm, so we will have more
alarms go off even though we know the job would not be ready at that
time.

Bug: 138469672
Bug: 176987520
Test: atest CtsJobSchedulerTestCases
Test: atest FrameworksMockingServicesTests:JobSchedulerServiceTes
Test: atest FrameworksMockingServicesTests:TimeControllerTest
Change-Id: I41d17ae1df10484f79deb48b197afadbd9cee693
parent 7e8ae00d
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -1978,9 +1978,12 @@ public class JobSchedulerService extends com.android.server.SystemService
                        JobStatus runNow = (JobStatus) message.obj;
                        // runNow can be null, which is a controller's way of indicating that its
                        // state is such that all ready jobs should be run immediately.
                        if (runNow != null && isReadyToBeExecutedLocked(runNow)) {
                        if (runNow != null) {
                            if (!isCurrentlyActiveLocked(runNow)
                                    && isReadyToBeExecutedLocked(runNow)) {
                                mJobPackageTracker.notePending(runNow);
                                addOrderedItem(mPendingJobs, runNow, sPendingJobComparator);
                            }
                        } else {
                            queueReadyJobsForExecutionLocked();
                        }
+15 −19
Original line number Diff line number Diff line
@@ -157,31 +157,27 @@ public final class TimeController extends StateController {
                && !job.isConstraintSatisfied(JobStatus.CONSTRAINT_DEADLINE)
                && job.getLatestRunTimeElapsed() <= mNextJobExpiredElapsedMillis) {
            if (evaluateDeadlineConstraint(job, nowElapsedMillis)) {
                checkExpiredDeadlinesAndResetAlarm();
                checkExpiredDelaysAndResetAlarm();
            } else {
                final boolean isAlarmForJob =
                        job.getLatestRunTimeElapsed() == mNextJobExpiredElapsedMillis;
                final boolean wouldBeReady = wouldBeReadyWithConstraintLocked(
                        job, JobStatus.CONSTRAINT_DEADLINE);
                if ((isAlarmForJob && !wouldBeReady) || (!isAlarmForJob && wouldBeReady)) {
                    checkExpiredDeadlinesAndResetAlarm();
                if (job.isReady()) {
                    // If the job still isn't ready, there's no point trying to rush the
                    // Scheduler.
                    mStateChangedListener.onRunJobNow(job);
                }
            } else if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_DEADLINE)) {
                // This job's deadline is earlier than the current set alarm. Update the alarm.
                setDeadlineExpiredAlarmLocked(job.getLatestRunTimeElapsed(),
                        deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()));
            }
        }
        if (job.hasTimingDelayConstraint()
                && !job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY)
                && job.getEarliestRunTime() <= mNextDelayExpiredElapsedMillis) {
            if (evaluateTimingDelayConstraint(job, nowElapsedMillis)) {
                checkExpiredDelaysAndResetAlarm();
            } else {
                final boolean isAlarmForJob =
                        job.getEarliestRunTime() == mNextDelayExpiredElapsedMillis;
                final boolean wouldBeReady = wouldBeReadyWithConstraintLocked(
                        job, JobStatus.CONSTRAINT_TIMING_DELAY);
                if ((isAlarmForJob && !wouldBeReady) || (!isAlarmForJob && wouldBeReady)) {
                    checkExpiredDelaysAndResetAlarm();
                }
            // Since this is just the delay, we don't need to rush the Scheduler to run the job
            // immediately if the constraint is satisfied here.
            if (!evaluateTimingDelayConstraint(job, nowElapsedMillis)
                    && wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
                // This job's delay is earlier than the current set alarm. Update the alarm.
                setDelayExpiredAlarmLocked(job.getEarliestRunTime(),
                        deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()));
            }
        }
    }
+25 −12
Original line number Diff line number Diff line
@@ -711,25 +711,31 @@ public class TimeControllerTest {
                .set(anyInt(), anyLong(), anyLong(), anyLong(), anyString(), any(), any(), any());

        // Test evaluating something before the current deadline.
        doReturn(false).when(mTimeController)
                .wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
        mTimeController.evaluateStateLocked(jobEarliest);
        inOrder.verify(mAlarmManager, never())
                .set(anyInt(), anyLong(), anyLong(), anyLong(), eq(TAG_DELAY), any(), any(), any());
        doReturn(true).when(mTimeController)
                .wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
        mTimeController.evaluateStateLocked(jobEarliest);
        inOrder.verify(mAlarmManager, times(1))
                .set(anyInt(), eq(now + 5 * MINUTE_IN_MILLIS), anyLong(), anyLong(), eq(TAG_DELAY),
                        any(), any(), any());
        // Job goes back to not being ready. Middle is still true, so use that alarm.
        // Job goes back to not being ready. Middle is still true, but we don't check and actively
        // defer alarm.
        doReturn(false).when(mTimeController)
                .wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
        mTimeController.evaluateStateLocked(jobEarliest);
        inOrder.verify(mAlarmManager, times(1))
                .set(anyInt(), eq(now + 30 * MINUTE_IN_MILLIS), anyLong(), anyLong(),
        inOrder.verify(mAlarmManager, never())
                .set(anyInt(), anyLong(), anyLong(), anyLong(),
                        eq(TAG_DELAY), any(), any(), any());
        // Turn middle off. Latest is true, so use that alarm.
        // Turn middle off. Latest is true, but we don't check and actively defer alarm.
        doReturn(false).when(mTimeController)
                .wouldBeReadyWithConstraintLocked(eq(jobMiddle), anyInt());
        mTimeController.evaluateStateLocked(jobMiddle);
        inOrder.verify(mAlarmManager, times(1))
                .set(anyInt(), eq(now + HOUR_IN_MILLIS), anyLong(), anyLong(),
        inOrder.verify(mAlarmManager, never())
                .set(anyInt(), anyLong(), anyLong(), anyLong(),
                        eq(TAG_DELAY), any(), any(), any());
    }

@@ -768,25 +774,32 @@ public class TimeControllerTest {
                .set(anyInt(), anyLong(), anyLong(), anyLong(), anyString(), any(), any(), any());

        // Test evaluating something before the current deadline.
        doReturn(false).when(mTimeController)
                .wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
        mTimeController.evaluateStateLocked(jobEarliest);
        inOrder.verify(mAlarmManager, never())
                .set(anyInt(), anyLong(), anyLong(), anyLong(),
                        eq(TAG_DEADLINE), any(), any(), any());
        doReturn(true).when(mTimeController)
                .wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
        mTimeController.evaluateStateLocked(jobEarliest);
        inOrder.verify(mAlarmManager, times(1))
                .set(anyInt(), eq(now + 5 * MINUTE_IN_MILLIS), anyLong(), anyLong(),
                        eq(TAG_DEADLINE), any(), any(), any());
        // Job goes back to not being ready. Middle is still true, so use that alarm.
        // Job goes back to not being ready. Middle is still true, but we don't check and actively
        // defer alarm.
        doReturn(false).when(mTimeController)
                .wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
        mTimeController.evaluateStateLocked(jobEarliest);
        inOrder.verify(mAlarmManager, times(1))
                .set(anyInt(), eq(now + 30 * MINUTE_IN_MILLIS), anyLong(), anyLong(),
        inOrder.verify(mAlarmManager, never())
                .set(anyInt(), anyLong(), anyLong(), anyLong(),
                        eq(TAG_DEADLINE), any(), any(), any());
        // Turn middle off. Latest is true, so use that alarm.
        // Turn middle off. Latest is true, but we don't check and actively defer alarm.
        doReturn(false).when(mTimeController)
                .wouldBeReadyWithConstraintLocked(eq(jobMiddle), anyInt());
        mTimeController.evaluateStateLocked(jobMiddle);
        inOrder.verify(mAlarmManager, times(1))
                .set(anyInt(), eq(now + HOUR_IN_MILLIS), anyLong(), anyLong(),
        inOrder.verify(mAlarmManager, never())
                .set(anyInt(), anyLong(), anyLong(), anyLong(),
                        eq(TAG_DEADLINE), any(), any(), any());
    }
}