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

Commit 3e911ca2 authored by Alex Bianchi's avatar Alex Bianchi Committed by Android (Google) Code Review
Browse files

Merge "Adjust Flex Deadline For Rescheduled Jobs"

parents 9d92f2c8 7a9fe088
Loading
Loading
Loading
Loading
+64 −22
Original line number Diff line number Diff line
@@ -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;

@@ -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 =
@@ -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();
    }
@@ -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")
@@ -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) {
@@ -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();
                }
            }
@@ -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);
@@ -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);
@@ -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
@@ -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
@@ -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,
@@ -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);
@@ -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();
        }
@@ -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);
    }
}
+25 −11
Original line number Diff line number Diff line
@@ -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);
@@ -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");
        }
@@ -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");
        }
@@ -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();
+37 −4
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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));
@@ -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);