Loading apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java +64 −22 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.job.controllers; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; Loading Loading @@ -98,8 +99,11 @@ public final class FlexibilityController extends StateController { private long mFallbackFlexibilityDeadlineMs = FcConfig.DEFAULT_FALLBACK_FLEXIBILITY_DEADLINE_MS; @GuardedBy("mLock") private long mRescheduledJobDeadline = FcConfig.DEFAULT_RESCHEDULED_JOB_DEADLINE_MS; private long mMaxRescheduledDeadline = FcConfig.DEFAULT_MAX_RESCHEDULED_DEADLINE_MS; @VisibleForTesting @GuardedBy("mLock") boolean mFlexibilityEnabled = FcConfig.DEFAULT_FLEXIBILITY_ENABLED; private long mMinTimeBetweenFlexibilityAlarmsMs = Loading Loading @@ -321,6 +325,12 @@ public final class FlexibilityController extends StateController { // There is no deadline and no estimated launch time. return NO_LIFECYCLE_END; } if (js.getNumFailures() > 1) { // Number of failures will not equal one as per restriction in JobStatus constructor. return earliest + Math.min( (long) Math.scalb(mRescheduledJobDeadline, js.getNumFailures() - 2), mMaxRescheduledDeadline); } return js.getLatestRunTimeElapsed() == JobStatus.NO_LATEST_RUNTIME ? earliest + mFallbackFlexibilityDeadlineMs : js.getLatestRunTimeElapsed(); } Loading @@ -340,7 +350,6 @@ public final class FlexibilityController extends StateController { return percentInTime; } /** The elapsed time that marks when the next constraint should be dropped. */ @VisibleForTesting @ElapsedRealtimeLong @GuardedBy("mLock") Loading @@ -351,7 +360,6 @@ public final class FlexibilityController extends StateController { } /** The elapsed time that marks when the next constraint should be dropped. */ @VisibleForTesting @ElapsedRealtimeLong @GuardedBy("mLock") long getNextConstraintDropTimeElapsedLocked(JobStatus js, long earliest, long latest) { Loading Loading @@ -531,6 +539,8 @@ public final class FlexibilityController extends StateController { js.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, js.getSourceUid()); pw.print(" Num Required Constraints: "); pw.print(js.getNumRequiredFlexibleConstraints()); pw.println(); } } Loading @@ -551,20 +561,24 @@ public final class FlexibilityController extends StateController { } public void scheduleDropNumConstraintsAlarm(JobStatus js, long nowElapsed) { long nextTimeElapsed; synchronized (mLock) { final long earliest = getLifeCycleBeginningElapsedLocked(js); final long latest = getLifeCycleEndElapsedLocked(js, earliest); nextTimeElapsed = getNextConstraintDropTimeElapsedLocked(js, earliest, latest); final long nextTimeElapsed = getNextConstraintDropTimeElapsedLocked(js, earliest, latest); if (latest - nowElapsed < mDeadlineProximityLimitMs) { mFlexibilityTracker.adjustJobsRequiredConstraints(js, -js.getNumRequiredFlexibleConstraints(), nowElapsed); return; } if (nextTimeElapsed == NO_LIFECYCLE_END) { // There is no known or estimated next time to drop a constraint. removeAlarmForKey(js); return; } if (latest - nextTimeElapsed < mDeadlineProximityLimitMs) { mFlexibilityTracker.adjustJobsRequiredConstraints( js, -js.getNumRequiredFlexibleConstraints(), nowElapsed); addAlarm(js, latest - mDeadlineProximityLimitMs); return; } addAlarm(js, nextTimeElapsed); Loading @@ -579,20 +593,8 @@ public final class FlexibilityController extends StateController { for (int i = 0; i < expired.size(); i++) { JobStatus js = expired.valueAt(i); boolean wasFlexibilitySatisfied = js.isConstraintSatisfied(CONSTRAINT_FLEXIBLE); final long earliest = getLifeCycleBeginningElapsedLocked(js); final long latest = getLifeCycleEndElapsedLocked(js, earliest); if (latest - nowElapsed < mDeadlineProximityLimitMs) { mFlexibilityTracker.adjustJobsRequiredConstraints(js, -js.getNumRequiredFlexibleConstraints(), nowElapsed); } else { long nextTimeElapsed = getNextConstraintDropTimeElapsedLocked(js, earliest, latest); if (mFlexibilityTracker.adjustJobsRequiredConstraints(js, -1, nowElapsed) && nextTimeElapsed != NO_LIFECYCLE_END) { mFlexibilityAlarmQueue.addAlarm(js, nextTimeElapsed); } if (mFlexibilityTracker.adjustJobsRequiredConstraints(js, -1, nowElapsed)) { scheduleDropNumConstraintsAlarm(js, nowElapsed); } if (wasFlexibilitySatisfied != js.isConstraintSatisfied(CONSTRAINT_FLEXIBLE)) { changedJobs.add(js); Loading @@ -619,6 +621,10 @@ public final class FlexibilityController extends StateController { FC_CONFIG_PREFIX + "min_alarm_time_flexibility_ms"; static final String KEY_PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS = FC_CONFIG_PREFIX + "percents_to_drop_num_flexible_constraints"; static final String KEY_MAX_RESCHEDULED_DEADLINE_MS = FC_CONFIG_PREFIX + "max_rescheduled_deadline_ms"; static final String KEY_RESCHEDULED_JOB_DEADLINE_MS = FC_CONFIG_PREFIX + "rescheduled_job_deadline_ms"; private static final boolean DEFAULT_FLEXIBILITY_ENABLED = false; @VisibleForTesting Loading @@ -628,6 +634,8 @@ public final class FlexibilityController extends StateController { private static final long DEFAULT_MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS = MINUTE_IN_MILLIS; @VisibleForTesting final int[] DEFAULT_PERCENT_TO_DROP_FLEXIBLE_CONSTRAINTS = {50, 60, 70, 80}; private static final long DEFAULT_RESCHEDULED_JOB_DEADLINE_MS = HOUR_IN_MILLIS; private static final long DEFAULT_MAX_RESCHEDULED_DEADLINE_MS = 5 * DAY_IN_MILLIS; /** * If false the controller will not track new jobs Loading @@ -643,6 +651,10 @@ public final class FlexibilityController extends StateController { /** The percentages of a jobs' lifecycle to drop the number of required constraints. */ public int[] PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS = DEFAULT_PERCENT_TO_DROP_FLEXIBLE_CONSTRAINTS; /** Initial fallback flexible deadline for rescheduled jobs. */ public long RESCHEDULED_JOB_DEADLINE_MS = DEFAULT_RESCHEDULED_JOB_DEADLINE_MS; /** The max deadline for rescheduled jobs. */ public long MAX_RESCHEDULED_DEADLINE_MS = DEFAULT_MAX_RESCHEDULED_DEADLINE_MS; @GuardedBy("mLock") public void processConstantLocked(@NonNull DeviceConfig.Properties properties, Loading @@ -662,6 +674,22 @@ public final class FlexibilityController extends StateController { } } break; case KEY_RESCHEDULED_JOB_DEADLINE_MS: RESCHEDULED_JOB_DEADLINE_MS = properties.getLong(key, DEFAULT_RESCHEDULED_JOB_DEADLINE_MS); if (mRescheduledJobDeadline != RESCHEDULED_JOB_DEADLINE_MS) { mRescheduledJobDeadline = RESCHEDULED_JOB_DEADLINE_MS; mShouldReevaluateConstraints = true; } break; case KEY_MAX_RESCHEDULED_DEADLINE_MS: MAX_RESCHEDULED_DEADLINE_MS = properties.getLong(key, DEFAULT_MAX_RESCHEDULED_DEADLINE_MS); if (mMaxRescheduledDeadline != MAX_RESCHEDULED_DEADLINE_MS) { mMaxRescheduledDeadline = MAX_RESCHEDULED_DEADLINE_MS; mShouldReevaluateConstraints = true; } break; case KEY_DEADLINE_PROXIMITY_LIMIT: DEADLINE_PROXIMITY_LIMIT_MS = properties.getLong(key, DEFAULT_DEADLINE_PROXIMITY_LIMIT_MS); Loading Loading @@ -733,6 +761,14 @@ public final class FlexibilityController extends StateController { pw.increaseIndent(); pw.print(KEY_FLEXIBILITY_ENABLED, FLEXIBILITY_ENABLED).println(); pw.print(KEY_DEADLINE_PROXIMITY_LIMIT, DEADLINE_PROXIMITY_LIMIT_MS).println(); pw.print(KEY_FALLBACK_FLEXIBILITY_DEADLINE, FALLBACK_FLEXIBILITY_DEADLINE_MS).println(); pw.print(KEY_MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS, MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS).println(); pw.print(KEY_PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS, PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS).println(); pw.print(KEY_RESCHEDULED_JOB_DEADLINE_MS, RESCHEDULED_JOB_DEADLINE_MS).println(); pw.print(KEY_MAX_RESCHEDULED_DEADLINE_MS, MAX_RESCHEDULED_DEADLINE_MS).println(); pw.decreaseIndent(); } Loading @@ -748,9 +784,15 @@ public final class FlexibilityController extends StateController { @GuardedBy("mLock") public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) { pw.println("# Constraints Satisfied: " + Integer.bitCount(mSatisfiedFlexibleConstraints)); pw.print("Satisfied Flexible Constraints: "); JobStatus.dumpConstraints(pw, mSatisfiedFlexibleConstraints); pw.println(); pw.println(); mFlexibilityTracker.dump(pw, predicate); pw.println(); mFlexibilityAlarmQueue.dump(pw); pw.println(); mFcConfig.dump(pw); } } apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +25 −11 Original line number Diff line number Diff line Loading @@ -572,8 +572,11 @@ public final class JobStatus { (latestRunTimeElapsedMillis - earliestRunTimeElapsedMillis) >= MIN_WINDOW_FOR_FLEXIBILITY_MS; // The first time a job is rescheduled it will not be subject to flexible constraints. // Otherwise, every consecutive reschedule increases a jobs' flexibility deadline. if (!isRequestedExpeditedJob() && satisfiesMinWindowException && numFailures != 1 && lacksSomeFlexibleConstraints) { mNumRequiredFlexibleConstraints = NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS + (mPreferUnmetered ? 1 : 0); Loading Loading @@ -1928,7 +1931,7 @@ public final class JobStatus { proto.end(token); } void dumpConstraints(PrintWriter pw, int constraints) { static void dumpConstraints(PrintWriter pw, int constraints) { if ((constraints & CONSTRAINT_CHARGING) != 0) { pw.print(" CHARGING"); } Loading @@ -1950,6 +1953,9 @@ public final class JobStatus { if ((constraints & CONSTRAINT_CONNECTIVITY) != 0) { pw.print(" CONNECTIVITY"); } if ((constraints & CONSTRAINT_FLEXIBLE) != 0) { pw.print(" FLEXIBILITY"); } if ((constraints & CONSTRAINT_CONTENT_TRIGGER) != 0) { pw.print(" CONTENT_TRIGGER"); } Loading Loading @@ -2242,6 +2248,14 @@ public final class JobStatus { ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA | CONSTRAINT_TARE_WEALTH) & ~satisfiedConstraints)); pw.println(); if (hasFlexibilityConstraint()) { pw.print("Num Required Flexible constraints: "); pw.print(getNumRequiredFlexibleConstraints()); pw.println(); pw.print("Num Dropped Flexible constraints: "); pw.print(getNumDroppedFlexibleConstraints()); pw.println(); } pw.println("Constraint history:"); pw.increaseIndent(); Loading services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java +37 −4 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import static com.android.server.job.controllers.JobStatus.CONSTRAINT_BATTERY_NO import static com.android.server.job.controllers.JobStatus.CONSTRAINT_CHARGING; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_FLEXIBLE; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_IDLE; import static com.android.server.job.controllers.JobStatus.NO_LATEST_RUNTIME; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; Loading Loading @@ -390,7 +391,7 @@ public class FlexibilityControllerTest { } @Test public void testGetLifeCycleBeginningElapsedLocked_prefetch() { public void testGetLifeCycleBeginningElapsedLocked_Prefetch() { // prefetch with lifecycle when(mPrefetchController.getLaunchTimeThresholdMs()).thenReturn(700L); JobInfo.Builder jb = createJob(0).setPrefetch(true); Loading @@ -417,7 +418,7 @@ public class FlexibilityControllerTest { } @Test public void testGetLifeCycleBeginningElapsedLocked_nonPrefetch() { public void testGetLifeCycleBeginningElapsedLocked_NonPrefetch() { // delay long delay = 100; JobInfo.Builder jb = createJob(0).setMinimumLatency(delay); Loading @@ -432,7 +433,7 @@ public class FlexibilityControllerTest { } @Test public void testGetLifeCycleEndElapsedLocked_prefetch() { public void testGetLifeCycleEndElapsedLocked_Prefetch() { // prefetch no estimate JobInfo.Builder jb = createJob(0).setPrefetch(true); JobStatus js = createJobStatus("time", jb); Loading @@ -444,8 +445,9 @@ public class FlexibilityControllerTest { when(mPrefetchController.getNextEstimatedLaunchTimeLocked(js)).thenReturn(1000L); assertEquals(1000L, mFlexibilityController.getLifeCycleEndElapsedLocked(js, 0)); } @Test public void testGetLifeCycleEndElapsedLocked_nonPrefetch() { public void testGetLifeCycleEndElapsedLocked_NonPrefetch() { // deadline JobInfo.Builder jb = createJob(0).setOverrideDeadline(1000L); JobStatus js = createJobStatus("time", jb); Loading @@ -458,6 +460,28 @@ public class FlexibilityControllerTest { mFlexibilityController.getLifeCycleEndElapsedLocked(js, 100L)); } @Test public void testGetLifeCycleEndElapsedLocked_Rescheduled() { JobInfo.Builder jb = createJob(0).setOverrideDeadline(1000L); JobStatus js = createJobStatus("time", jb); js = new JobStatus( js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2, FROZEN_TIME, FROZEN_TIME); assertEquals(mFcConfig.RESCHEDULED_JOB_DEADLINE_MS, mFlexibilityController.getLifeCycleEndElapsedLocked(js, 0)); js = new JobStatus( js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 3, FROZEN_TIME, FROZEN_TIME); assertEquals(2 * mFcConfig.RESCHEDULED_JOB_DEADLINE_MS, mFlexibilityController.getLifeCycleEndElapsedLocked(js, 0)); js = new JobStatus( js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 10, FROZEN_TIME, FROZEN_TIME); assertEquals(mFcConfig.MAX_RESCHEDULED_DEADLINE_MS, mFlexibilityController.getLifeCycleEndElapsedLocked(js, 0)); } @Test public void testWontStopJobFromRunning() { JobStatus js = createJobStatus("testWontStopJobFromRunning", createJob(101)); Loading Loading @@ -577,6 +601,15 @@ public class FlexibilityControllerTest { assertFalse(js.hasFlexibilityConstraint()); } @Test public void testExceptions_RescheduledOnce() { JobInfo.Builder jb = createJob(0); JobStatus js = createJobStatus("time", jb); js = new JobStatus( js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 1, FROZEN_TIME, FROZEN_TIME); assertFalse(js.hasFlexibilityConstraint()); } @Test public void testExceptions_None() { JobInfo.Builder jb = createJob(0); Loading Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java +64 −22 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.job.controllers; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; Loading Loading @@ -98,8 +99,11 @@ public final class FlexibilityController extends StateController { private long mFallbackFlexibilityDeadlineMs = FcConfig.DEFAULT_FALLBACK_FLEXIBILITY_DEADLINE_MS; @GuardedBy("mLock") private long mRescheduledJobDeadline = FcConfig.DEFAULT_RESCHEDULED_JOB_DEADLINE_MS; private long mMaxRescheduledDeadline = FcConfig.DEFAULT_MAX_RESCHEDULED_DEADLINE_MS; @VisibleForTesting @GuardedBy("mLock") boolean mFlexibilityEnabled = FcConfig.DEFAULT_FLEXIBILITY_ENABLED; private long mMinTimeBetweenFlexibilityAlarmsMs = Loading Loading @@ -321,6 +325,12 @@ public final class FlexibilityController extends StateController { // There is no deadline and no estimated launch time. return NO_LIFECYCLE_END; } if (js.getNumFailures() > 1) { // Number of failures will not equal one as per restriction in JobStatus constructor. return earliest + Math.min( (long) Math.scalb(mRescheduledJobDeadline, js.getNumFailures() - 2), mMaxRescheduledDeadline); } return js.getLatestRunTimeElapsed() == JobStatus.NO_LATEST_RUNTIME ? earliest + mFallbackFlexibilityDeadlineMs : js.getLatestRunTimeElapsed(); } Loading @@ -340,7 +350,6 @@ public final class FlexibilityController extends StateController { return percentInTime; } /** The elapsed time that marks when the next constraint should be dropped. */ @VisibleForTesting @ElapsedRealtimeLong @GuardedBy("mLock") Loading @@ -351,7 +360,6 @@ public final class FlexibilityController extends StateController { } /** The elapsed time that marks when the next constraint should be dropped. */ @VisibleForTesting @ElapsedRealtimeLong @GuardedBy("mLock") long getNextConstraintDropTimeElapsedLocked(JobStatus js, long earliest, long latest) { Loading Loading @@ -531,6 +539,8 @@ public final class FlexibilityController extends StateController { js.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, js.getSourceUid()); pw.print(" Num Required Constraints: "); pw.print(js.getNumRequiredFlexibleConstraints()); pw.println(); } } Loading @@ -551,20 +561,24 @@ public final class FlexibilityController extends StateController { } public void scheduleDropNumConstraintsAlarm(JobStatus js, long nowElapsed) { long nextTimeElapsed; synchronized (mLock) { final long earliest = getLifeCycleBeginningElapsedLocked(js); final long latest = getLifeCycleEndElapsedLocked(js, earliest); nextTimeElapsed = getNextConstraintDropTimeElapsedLocked(js, earliest, latest); final long nextTimeElapsed = getNextConstraintDropTimeElapsedLocked(js, earliest, latest); if (latest - nowElapsed < mDeadlineProximityLimitMs) { mFlexibilityTracker.adjustJobsRequiredConstraints(js, -js.getNumRequiredFlexibleConstraints(), nowElapsed); return; } if (nextTimeElapsed == NO_LIFECYCLE_END) { // There is no known or estimated next time to drop a constraint. removeAlarmForKey(js); return; } if (latest - nextTimeElapsed < mDeadlineProximityLimitMs) { mFlexibilityTracker.adjustJobsRequiredConstraints( js, -js.getNumRequiredFlexibleConstraints(), nowElapsed); addAlarm(js, latest - mDeadlineProximityLimitMs); return; } addAlarm(js, nextTimeElapsed); Loading @@ -579,20 +593,8 @@ public final class FlexibilityController extends StateController { for (int i = 0; i < expired.size(); i++) { JobStatus js = expired.valueAt(i); boolean wasFlexibilitySatisfied = js.isConstraintSatisfied(CONSTRAINT_FLEXIBLE); final long earliest = getLifeCycleBeginningElapsedLocked(js); final long latest = getLifeCycleEndElapsedLocked(js, earliest); if (latest - nowElapsed < mDeadlineProximityLimitMs) { mFlexibilityTracker.adjustJobsRequiredConstraints(js, -js.getNumRequiredFlexibleConstraints(), nowElapsed); } else { long nextTimeElapsed = getNextConstraintDropTimeElapsedLocked(js, earliest, latest); if (mFlexibilityTracker.adjustJobsRequiredConstraints(js, -1, nowElapsed) && nextTimeElapsed != NO_LIFECYCLE_END) { mFlexibilityAlarmQueue.addAlarm(js, nextTimeElapsed); } if (mFlexibilityTracker.adjustJobsRequiredConstraints(js, -1, nowElapsed)) { scheduleDropNumConstraintsAlarm(js, nowElapsed); } if (wasFlexibilitySatisfied != js.isConstraintSatisfied(CONSTRAINT_FLEXIBLE)) { changedJobs.add(js); Loading @@ -619,6 +621,10 @@ public final class FlexibilityController extends StateController { FC_CONFIG_PREFIX + "min_alarm_time_flexibility_ms"; static final String KEY_PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS = FC_CONFIG_PREFIX + "percents_to_drop_num_flexible_constraints"; static final String KEY_MAX_RESCHEDULED_DEADLINE_MS = FC_CONFIG_PREFIX + "max_rescheduled_deadline_ms"; static final String KEY_RESCHEDULED_JOB_DEADLINE_MS = FC_CONFIG_PREFIX + "rescheduled_job_deadline_ms"; private static final boolean DEFAULT_FLEXIBILITY_ENABLED = false; @VisibleForTesting Loading @@ -628,6 +634,8 @@ public final class FlexibilityController extends StateController { private static final long DEFAULT_MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS = MINUTE_IN_MILLIS; @VisibleForTesting final int[] DEFAULT_PERCENT_TO_DROP_FLEXIBLE_CONSTRAINTS = {50, 60, 70, 80}; private static final long DEFAULT_RESCHEDULED_JOB_DEADLINE_MS = HOUR_IN_MILLIS; private static final long DEFAULT_MAX_RESCHEDULED_DEADLINE_MS = 5 * DAY_IN_MILLIS; /** * If false the controller will not track new jobs Loading @@ -643,6 +651,10 @@ public final class FlexibilityController extends StateController { /** The percentages of a jobs' lifecycle to drop the number of required constraints. */ public int[] PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS = DEFAULT_PERCENT_TO_DROP_FLEXIBLE_CONSTRAINTS; /** Initial fallback flexible deadline for rescheduled jobs. */ public long RESCHEDULED_JOB_DEADLINE_MS = DEFAULT_RESCHEDULED_JOB_DEADLINE_MS; /** The max deadline for rescheduled jobs. */ public long MAX_RESCHEDULED_DEADLINE_MS = DEFAULT_MAX_RESCHEDULED_DEADLINE_MS; @GuardedBy("mLock") public void processConstantLocked(@NonNull DeviceConfig.Properties properties, Loading @@ -662,6 +674,22 @@ public final class FlexibilityController extends StateController { } } break; case KEY_RESCHEDULED_JOB_DEADLINE_MS: RESCHEDULED_JOB_DEADLINE_MS = properties.getLong(key, DEFAULT_RESCHEDULED_JOB_DEADLINE_MS); if (mRescheduledJobDeadline != RESCHEDULED_JOB_DEADLINE_MS) { mRescheduledJobDeadline = RESCHEDULED_JOB_DEADLINE_MS; mShouldReevaluateConstraints = true; } break; case KEY_MAX_RESCHEDULED_DEADLINE_MS: MAX_RESCHEDULED_DEADLINE_MS = properties.getLong(key, DEFAULT_MAX_RESCHEDULED_DEADLINE_MS); if (mMaxRescheduledDeadline != MAX_RESCHEDULED_DEADLINE_MS) { mMaxRescheduledDeadline = MAX_RESCHEDULED_DEADLINE_MS; mShouldReevaluateConstraints = true; } break; case KEY_DEADLINE_PROXIMITY_LIMIT: DEADLINE_PROXIMITY_LIMIT_MS = properties.getLong(key, DEFAULT_DEADLINE_PROXIMITY_LIMIT_MS); Loading Loading @@ -733,6 +761,14 @@ public final class FlexibilityController extends StateController { pw.increaseIndent(); pw.print(KEY_FLEXIBILITY_ENABLED, FLEXIBILITY_ENABLED).println(); pw.print(KEY_DEADLINE_PROXIMITY_LIMIT, DEADLINE_PROXIMITY_LIMIT_MS).println(); pw.print(KEY_FALLBACK_FLEXIBILITY_DEADLINE, FALLBACK_FLEXIBILITY_DEADLINE_MS).println(); pw.print(KEY_MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS, MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS).println(); pw.print(KEY_PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS, PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS).println(); pw.print(KEY_RESCHEDULED_JOB_DEADLINE_MS, RESCHEDULED_JOB_DEADLINE_MS).println(); pw.print(KEY_MAX_RESCHEDULED_DEADLINE_MS, MAX_RESCHEDULED_DEADLINE_MS).println(); pw.decreaseIndent(); } Loading @@ -748,9 +784,15 @@ public final class FlexibilityController extends StateController { @GuardedBy("mLock") public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) { pw.println("# Constraints Satisfied: " + Integer.bitCount(mSatisfiedFlexibleConstraints)); pw.print("Satisfied Flexible Constraints: "); JobStatus.dumpConstraints(pw, mSatisfiedFlexibleConstraints); pw.println(); pw.println(); mFlexibilityTracker.dump(pw, predicate); pw.println(); mFlexibilityAlarmQueue.dump(pw); pw.println(); mFcConfig.dump(pw); } }
apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +25 −11 Original line number Diff line number Diff line Loading @@ -572,8 +572,11 @@ public final class JobStatus { (latestRunTimeElapsedMillis - earliestRunTimeElapsedMillis) >= MIN_WINDOW_FOR_FLEXIBILITY_MS; // The first time a job is rescheduled it will not be subject to flexible constraints. // Otherwise, every consecutive reschedule increases a jobs' flexibility deadline. if (!isRequestedExpeditedJob() && satisfiesMinWindowException && numFailures != 1 && lacksSomeFlexibleConstraints) { mNumRequiredFlexibleConstraints = NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS + (mPreferUnmetered ? 1 : 0); Loading Loading @@ -1928,7 +1931,7 @@ public final class JobStatus { proto.end(token); } void dumpConstraints(PrintWriter pw, int constraints) { static void dumpConstraints(PrintWriter pw, int constraints) { if ((constraints & CONSTRAINT_CHARGING) != 0) { pw.print(" CHARGING"); } Loading @@ -1950,6 +1953,9 @@ public final class JobStatus { if ((constraints & CONSTRAINT_CONNECTIVITY) != 0) { pw.print(" CONNECTIVITY"); } if ((constraints & CONSTRAINT_FLEXIBLE) != 0) { pw.print(" FLEXIBILITY"); } if ((constraints & CONSTRAINT_CONTENT_TRIGGER) != 0) { pw.print(" CONTENT_TRIGGER"); } Loading Loading @@ -2242,6 +2248,14 @@ public final class JobStatus { ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA | CONSTRAINT_TARE_WEALTH) & ~satisfiedConstraints)); pw.println(); if (hasFlexibilityConstraint()) { pw.print("Num Required Flexible constraints: "); pw.print(getNumRequiredFlexibleConstraints()); pw.println(); pw.print("Num Dropped Flexible constraints: "); pw.print(getNumDroppedFlexibleConstraints()); pw.println(); } pw.println("Constraint history:"); pw.increaseIndent(); Loading
services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java +37 −4 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import static com.android.server.job.controllers.JobStatus.CONSTRAINT_BATTERY_NO import static com.android.server.job.controllers.JobStatus.CONSTRAINT_CHARGING; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_FLEXIBLE; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_IDLE; import static com.android.server.job.controllers.JobStatus.NO_LATEST_RUNTIME; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; Loading Loading @@ -390,7 +391,7 @@ public class FlexibilityControllerTest { } @Test public void testGetLifeCycleBeginningElapsedLocked_prefetch() { public void testGetLifeCycleBeginningElapsedLocked_Prefetch() { // prefetch with lifecycle when(mPrefetchController.getLaunchTimeThresholdMs()).thenReturn(700L); JobInfo.Builder jb = createJob(0).setPrefetch(true); Loading @@ -417,7 +418,7 @@ public class FlexibilityControllerTest { } @Test public void testGetLifeCycleBeginningElapsedLocked_nonPrefetch() { public void testGetLifeCycleBeginningElapsedLocked_NonPrefetch() { // delay long delay = 100; JobInfo.Builder jb = createJob(0).setMinimumLatency(delay); Loading @@ -432,7 +433,7 @@ public class FlexibilityControllerTest { } @Test public void testGetLifeCycleEndElapsedLocked_prefetch() { public void testGetLifeCycleEndElapsedLocked_Prefetch() { // prefetch no estimate JobInfo.Builder jb = createJob(0).setPrefetch(true); JobStatus js = createJobStatus("time", jb); Loading @@ -444,8 +445,9 @@ public class FlexibilityControllerTest { when(mPrefetchController.getNextEstimatedLaunchTimeLocked(js)).thenReturn(1000L); assertEquals(1000L, mFlexibilityController.getLifeCycleEndElapsedLocked(js, 0)); } @Test public void testGetLifeCycleEndElapsedLocked_nonPrefetch() { public void testGetLifeCycleEndElapsedLocked_NonPrefetch() { // deadline JobInfo.Builder jb = createJob(0).setOverrideDeadline(1000L); JobStatus js = createJobStatus("time", jb); Loading @@ -458,6 +460,28 @@ public class FlexibilityControllerTest { mFlexibilityController.getLifeCycleEndElapsedLocked(js, 100L)); } @Test public void testGetLifeCycleEndElapsedLocked_Rescheduled() { JobInfo.Builder jb = createJob(0).setOverrideDeadline(1000L); JobStatus js = createJobStatus("time", jb); js = new JobStatus( js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2, FROZEN_TIME, FROZEN_TIME); assertEquals(mFcConfig.RESCHEDULED_JOB_DEADLINE_MS, mFlexibilityController.getLifeCycleEndElapsedLocked(js, 0)); js = new JobStatus( js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 3, FROZEN_TIME, FROZEN_TIME); assertEquals(2 * mFcConfig.RESCHEDULED_JOB_DEADLINE_MS, mFlexibilityController.getLifeCycleEndElapsedLocked(js, 0)); js = new JobStatus( js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 10, FROZEN_TIME, FROZEN_TIME); assertEquals(mFcConfig.MAX_RESCHEDULED_DEADLINE_MS, mFlexibilityController.getLifeCycleEndElapsedLocked(js, 0)); } @Test public void testWontStopJobFromRunning() { JobStatus js = createJobStatus("testWontStopJobFromRunning", createJob(101)); Loading Loading @@ -577,6 +601,15 @@ public class FlexibilityControllerTest { assertFalse(js.hasFlexibilityConstraint()); } @Test public void testExceptions_RescheduledOnce() { JobInfo.Builder jb = createJob(0); JobStatus js = createJobStatus("time", jb); js = new JobStatus( js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 1, FROZEN_TIME, FROZEN_TIME); assertFalse(js.hasFlexibilityConstraint()); } @Test public void testExceptions_None() { JobInfo.Builder jb = createJob(0); Loading