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

Commit 48e6d159 authored by Dianne Hackborn's avatar Dianne Hackborn Committed by android-build-merger
Browse files

Merge "Fix issue #38210653: Few more tweaks of job scheduler" into oc-dev

am: c75bd416

Change-Id: I6c7cf4506c73fbed60bff0d43fb0a588d780d93a
parents e093068e c75bd416
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -111,8 +111,11 @@ public class JobInfo implements Parcelable {
    /* Minimum flex for a periodic job, in milliseconds. */
    private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes

    /* Minimum backoff interval for a job, in milliseconds */
    private static final long MIN_BACKOFF_MILLIS = 10 * 1000L;      // 10 seconds
    /**
     * Minimum backoff interval for a job, in milliseconds
     * @hide
     */
    public static final long MIN_BACKOFF_MILLIS = 10 * 1000L;      // 10 seconds

    /**
     * Query the minimum interval allowed for periodic scheduled jobs.  Attempting
@@ -431,7 +434,7 @@ public class JobInfo implements Parcelable {
    /**
     * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
     * will be increased depending on the backoff policy specified at job creation time. Defaults
     * to 5 seconds.
     * to 30 seconds, minimum is currently 10 seconds.
     */
    public long getInitialBackoffMillis() {
        final long minBackoff = getMinBackoffMillis();
+23 −1
Original line number Diff line number Diff line
@@ -330,10 +330,32 @@ public abstract class BroadcastReceiver {
     * This can be called by an application in {@link #onReceive} to allow
     * it to keep the broadcast active after returning from that function.
     * This does <em>not</em> change the expectation of being relatively
     * responsive to the broadcast (finishing it within 10s), but does allow
     * responsive to the broadcast, but does allow
     * the implementation to move work related to it over to another thread
     * to avoid glitching the main UI thread due to disk IO.
     *
     * <p>As a general rule, broadcast receivers are allowed to run for up to 10 seconds
     * before they system will consider them non-responsive and ANR the app.  Since these usually
     * execute on the app's main thread, they are already bound by the ~5 second time limit
     * of various operations that can happen there (not to mention just avoiding UI jank), so
     * the receive limit is generally not of concern.  However, once you use {@goAsync}, though
     * able to be off the main thread, the broadcast execution limit still applies, and that
     * includes the time spent between calling this method and ultimately
     * {@link PendingResult#finish() PendingResult.finish()}.</p>
     *
     * <p>If you are taking advantage of this method to have more time to execute, it is useful
     * to know that the available time can be longer in certain situations.  In particular, if
     * the broadcast you are receiving is not a foreground broadcast (that is, the sender has not
     * used {@link Intent#FLAG_RECEIVER_FOREGROUND}), then more time is allowed for the receivers
     * to run, allowing them to execute for 30 seconds or even a bit more.  This is something that
     * receivers should rarely take advantage of (long work should be punted to another system
     * facility such as {@link android.app.job.JobScheduler}, {@link android.app.Service}, or
     * see especially {@link android.support.v4.app.JobIntentService}), but can be useful in
     * certain rare cases where it is necessary to do some work as soon as the broadcast is
     * delivered.  Keep in mind that the work you do here will block further broadcasts until
     * it completes, so taking advantage of this at all excessively can be counter-productive
     * and cause later events to be received more slowly.</p>
     *
     * @return Returns a {@link PendingResult} representing the result of
     * the active broadcast.  The BroadcastRecord itself is no longer active;
     * all data and other interaction must go through {@link PendingResult}
+5 −3
Original line number Diff line number Diff line
@@ -5391,8 +5391,9 @@ public class ActivityManagerService extends IActivityManager.Stub
            boolean doLowMem = app.instr == null;
            boolean doOomAdj = doLowMem;
            if (!app.killedByAm) {
                Slog.i(TAG, "Process " + app.processName + " (pid " + pid
                        + ") has died");
                Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died: "
                        + ProcessList.makeOomAdjString(app.setAdj)
                        + ProcessList.makeProcStateString(app.setProcState));
                mAllowLowerMemLevel = true;
            } else {
                // Note that we always want to do oom adj to update our state with the
@@ -5400,7 +5401,8 @@ public class ActivityManagerService extends IActivityManager.Stub
                mAllowLowerMemLevel = false;
                doLowMem = false;
            }
            EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
            EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName,
                    app.setAdj, app.setProcState);
            if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
                "Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder());
            handleAppDiedLocked(app, false, true);
+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ option java_package com.android.server.am
# Application process bound to work
30010 am_proc_bound (User|1|5),(PID|1|5),(Process Name|3)
# Application process died
30011 am_proc_died (User|1|5),(PID|1|5),(Process Name|3)
30011 am_proc_died (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(ProcState|1|5)
# The Activity Manager failed to pause the given activity.
30012 am_failed_to_pause (User|1|5),(Token|1|5),(Wanting to pause|3),(Currently pausing|3)
# Attempting to pause the current activity
+115 −29
Original line number Diff line number Diff line
@@ -218,6 +218,11 @@ public final class JobSchedulerService extends com.android.server.SystemService
        private static final String KEY_BG_MODERATE_JOB_COUNT = "bg_moderate_job_count";
        private static final String KEY_BG_LOW_JOB_COUNT = "bg_low_job_count";
        private static final String KEY_BG_CRITICAL_JOB_COUNT = "bg_critical_job_count";
        private static final String KEY_MAX_STANDARD_RESCHEDULE_COUNT
                = "max_standard_reschedule_count";
        private static final String KEY_MAX_WORK_RESCHEDULE_COUNT = "max_work_reschedule_count";
        private static final String KEY_MIN_LINEAR_BACKOFF_TIME = "min_linear_backoff_time";
        private static final String KEY_MIN_EXP_BACKOFF_TIME = "min_exp_backoff_time";

        private static final int DEFAULT_MIN_IDLE_COUNT = 1;
        private static final int DEFAULT_MIN_CHARGING_COUNT = 1;
@@ -233,6 +238,10 @@ public final class JobSchedulerService extends com.android.server.SystemService
        private static final int DEFAULT_BG_MODERATE_JOB_COUNT = 4;
        private static final int DEFAULT_BG_LOW_JOB_COUNT = 1;
        private static final int DEFAULT_BG_CRITICAL_JOB_COUNT = 1;
        private static final int DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT = Integer.MAX_VALUE;
        private static final int DEFAULT_MAX_WORK_RESCHEDULE_COUNT = Integer.MAX_VALUE;
        private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
        private static final long DEFAULT_MIN_EXP_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;

        /**
         * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
@@ -303,6 +312,24 @@ public final class JobSchedulerService extends com.android.server.SystemService
         * memory state.
         */
        int BG_CRITICAL_JOB_COUNT = DEFAULT_BG_CRITICAL_JOB_COUNT;
        /**
         * The maximum number of times we allow a job to have itself rescheduled before
         * giving up on it, for standard jobs.
         */
        int MAX_STANDARD_RESCHEDULE_COUNT = DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT;
        /**
         * The maximum number of times we allow a job to have itself rescheduled before
         * giving up on it, for jobs that are executing work.
         */
        int MAX_WORK_RESCHEDULE_COUNT = DEFAULT_MAX_WORK_RESCHEDULE_COUNT;
        /**
         * The minimum backoff time to allow for linear backoff.
         */
        long MIN_LINEAR_BACKOFF_TIME = DEFAULT_MIN_LINEAR_BACKOFF_TIME;
        /**
         * The minimum backoff time to allow for exponential backoff.
         */
        long MIN_EXP_BACKOFF_TIME = DEFAULT_MIN_EXP_BACKOFF_TIME;

        private ContentResolver mResolver;
        private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -374,6 +401,14 @@ public final class JobSchedulerService extends com.android.server.SystemService
                if ((FG_JOB_COUNT+BG_CRITICAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
                    BG_CRITICAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
                }
                MAX_STANDARD_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_STANDARD_RESCHEDULE_COUNT,
                        DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT);
                MAX_WORK_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_WORK_RESCHEDULE_COUNT,
                        DEFAULT_MAX_WORK_RESCHEDULE_COUNT);
                MIN_LINEAR_BACKOFF_TIME = mParser.getLong(KEY_MIN_LINEAR_BACKOFF_TIME,
                        DEFAULT_MIN_LINEAR_BACKOFF_TIME);
                MIN_EXP_BACKOFF_TIME = mParser.getLong(KEY_MIN_EXP_BACKOFF_TIME,
                        DEFAULT_MIN_EXP_BACKOFF_TIME);
            }
        }

@@ -421,11 +456,38 @@ public final class JobSchedulerService extends com.android.server.SystemService

            pw.print("    "); pw.print(KEY_BG_CRITICAL_JOB_COUNT); pw.print("=");
            pw.print(BG_CRITICAL_JOB_COUNT); pw.println();

            pw.print("    "); pw.print(KEY_MAX_STANDARD_RESCHEDULE_COUNT); pw.print("=");
            pw.print(MAX_STANDARD_RESCHEDULE_COUNT); pw.println();

            pw.print("    "); pw.print(KEY_MAX_WORK_RESCHEDULE_COUNT); pw.print("=");
            pw.print(MAX_WORK_RESCHEDULE_COUNT); pw.println();

            pw.print("    "); pw.print(KEY_MIN_LINEAR_BACKOFF_TIME); pw.print("=");
            pw.print(MIN_LINEAR_BACKOFF_TIME); pw.println();

            pw.print("    "); pw.print(KEY_MIN_EXP_BACKOFF_TIME); pw.print("=");
            pw.print(MIN_EXP_BACKOFF_TIME); pw.println();
        }
    }

    final Constants mConstants;

    static final Comparator<JobStatus> mEnqueueTimeComparator = (o1, o2) -> {
        if (o1.enqueueTime < o2.enqueueTime) {
            return -1;
        }
        return o1.enqueueTime > o2.enqueueTime ? 1 : 0;
    };

    static <T> void addOrderedItem(ArrayList<T> array, T newItem, Comparator<T> comparator) {
        int where = Collections.binarySearch(array, newItem, comparator);
        if (where < 0) {
            where = ~where;
        }
        array.add(where, newItem);
    }

    /**
     * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
     * still clean up. On reinstall the package will have a new uid.
@@ -647,7 +709,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
                // This is a new job, we can just immediately put it on the pending
                // list and try to run it.
                mJobPackageTracker.notePending(jobStatus);
                mPendingJobs.add(jobStatus);
                addOrderedItem(mPendingJobs, jobStatus, mEnqueueTimeComparator);
                maybeRunPendingJobsLocked();
            }
        }
@@ -771,7 +833,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
                // except those using the idle exemption flag.
                for (int i=0; i<mActiveServices.size(); i++) {
                    JobServiceContext jsc = mActiveServices.get(i);
                    final JobStatus executing = jsc.getRunningJob();
                    final JobStatus executing = jsc.getRunningJobLocked();
                    if (executing != null
                            && (executing.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0) {
                        jsc.cancelExecutingJobLocked(JobParameters.REASON_DEVICE_IDLE);
@@ -798,7 +860,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
        if (mPendingJobs.size() <= 0) {
            for (int i=0; i<mActiveServices.size(); i++) {
                final JobServiceContext jsc = mActiveServices.get(i);
                final JobStatus job = jsc.getRunningJob();
                final JobStatus job = jsc.getRunningJobLocked();
                if (job != null
                        && (job.getJob().getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0
                        && !job.dozeWhitelisted) {
@@ -918,6 +980,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
        if (!jobStatus.isPreparedLocked()) {
            Slog.wtf(TAG, "Not yet prepared when started tracking: " + jobStatus);
        }
        jobStatus.enqueueTime = SystemClock.elapsedRealtime();
        final boolean update = mJobs.add(jobStatus);
        if (mReadyToRock) {
            for (int i = 0; i < mControllers.size(); i++) {
@@ -953,7 +1016,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
    private boolean stopJobOnServiceContextLocked(JobStatus job, int reason) {
        for (int i=0; i<mActiveServices.size(); i++) {
            JobServiceContext jsc = mActiveServices.get(i);
            final JobStatus executing = jsc.getRunningJob();
            final JobStatus executing = jsc.getRunningJobLocked();
            if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
                jsc.cancelExecutingJobLocked(reason);
                return true;
@@ -970,11 +1033,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
    private boolean isCurrentlyActiveLocked(JobStatus job) {
        for (int i=0; i<mActiveServices.size(); i++) {
            JobServiceContext serviceContext = mActiveServices.get(i);
            // The 'unsafe' direct-internal-reference running-job inspector is okay to
            // use here because we are already holding the necessary lock *and* we
            // immediately discard the returned object reference, if any; we return
            // only a boolean state indicator to the caller.
            final JobStatus running = serviceContext.getRunningJobUnsafeLocked();
            final JobStatus running = serviceContext.getRunningJobLocked();
            if (running != null && running.matches(job.getUid(), job.getJobId())) {
                return true;
            }
@@ -1016,18 +1075,38 @@ public final class JobSchedulerService extends com.android.server.SystemService
        final int backoffAttempts = failureToReschedule.getNumFailures() + 1;
        long delayMillis;

        if (failureToReschedule.hasWorkLocked()) {
            if (backoffAttempts > mConstants.MAX_WORK_RESCHEDULE_COUNT) {
                Slog.w(TAG, "Not rescheduling " + failureToReschedule + ": attempt #"
                        + backoffAttempts + " > work limit "
                        + mConstants.MAX_STANDARD_RESCHEDULE_COUNT);
                return null;
            }
        } else if (backoffAttempts > mConstants.MAX_STANDARD_RESCHEDULE_COUNT) {
            Slog.w(TAG, "Not rescheduling " + failureToReschedule + ": attempt #"
                    + backoffAttempts + " > std limit " + mConstants.MAX_STANDARD_RESCHEDULE_COUNT);
            return null;
        }

        switch (job.getBackoffPolicy()) {
            case JobInfo.BACKOFF_POLICY_LINEAR:
                delayMillis = initialBackoffMillis * backoffAttempts;
                break;
            case JobInfo.BACKOFF_POLICY_LINEAR: {
                long backoff = initialBackoffMillis;
                if (backoff < mConstants.MIN_LINEAR_BACKOFF_TIME) {
                    backoff = mConstants.MIN_LINEAR_BACKOFF_TIME;
                }
                delayMillis = backoff * backoffAttempts;
            } break;
            default:
                if (DEBUG) {
                    Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
                }
            case JobInfo.BACKOFF_POLICY_EXPONENTIAL:
                delayMillis =
                        (long) Math.scalb(initialBackoffMillis, backoffAttempts - 1);
                break;
            case JobInfo.BACKOFF_POLICY_EXPONENTIAL: {
                long backoff = initialBackoffMillis;
                if (backoff < mConstants.MIN_EXP_BACKOFF_TIME) {
                    backoff = mConstants.MIN_EXP_BACKOFF_TIME;
                }
                delayMillis = (long) Math.scalb(backoff, backoffAttempts - 1);
            } break;
        }
        delayMillis =
                Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
@@ -1163,7 +1242,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
                        // state is such that all ready jobs should be run immediately.
                        if (runNow != null && isReadyToBeExecutedLocked(runNow)) {
                            mJobPackageTracker.notePending(runNow);
                            mPendingJobs.add(runNow);
                            addOrderedItem(mPendingJobs, runNow, mEnqueueTimeComparator);
                        } else {
                            queueReadyJobsForExecutionLocked();
                        }
@@ -1237,6 +1316,9 @@ public final class JobSchedulerService extends com.android.server.SystemService
            if (newReadyJobs != null) {
                noteJobsPending(newReadyJobs);
                mPendingJobs.addAll(newReadyJobs);
                if (mPendingJobs.size() > 1) {
                    mPendingJobs.sort(mEnqueueTimeComparator);
                }
            }
            newReadyJobs = null;
        }
@@ -1326,6 +1408,9 @@ public final class JobSchedulerService extends com.android.server.SystemService
                }
                noteJobsPending(runnableJobs);
                mPendingJobs.addAll(runnableJobs);
                if (mPendingJobs.size() > 1) {
                    mPendingJobs.sort(mEnqueueTimeComparator);
                }
            } else {
                if (DEBUG) {
                    Slog.d(TAG, "maybeQueueReadyJobsForExecutionLocked: Not running anything.");
@@ -1515,7 +1600,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
        int numForeground = 0;
        for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
            final JobServiceContext js = mActiveServices.get(i);
            final JobStatus status = js.getRunningJob();
            final JobStatus status = js.getRunningJobLocked();
            if ((contextIdToJobMap[i] = status) != null) {
                numActive++;
                if (status.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
@@ -1591,10 +1676,10 @@ public final class JobSchedulerService extends com.android.server.SystemService
        for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
            boolean preservePreferredUid = false;
            if (act[i]) {
                JobStatus js = mActiveServices.get(i).getRunningJob();
                JobStatus js = mActiveServices.get(i).getRunningJobLocked();
                if (js != null) {
                    if (DEBUG) {
                        Slog.d(TAG, "preempting job: " + mActiveServices.get(i).getRunningJob());
                        Slog.d(TAG, "preempting job: " + mActiveServices.get(i).getRunningJobLocked());
                    }
                    // preferredUid will be set to uid of currently running job.
                    mActiveServices.get(i).preemptExecutingJobLocked();
@@ -2099,7 +2184,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
                        continue;
                    }

                    job.dump(pw, "    ", true);
                    job.dump(pw, "    ", true, now);
                    pw.print("    Ready: ");
                    pw.print(isReadyToBeExecutedLocked(job));
                    pw.print(" (job=");
@@ -2169,22 +2254,22 @@ public final class JobSchedulerService extends com.android.server.SystemService
                JobStatus job = mPendingJobs.get(i);
                pw.print("  Pending #"); pw.print(i); pw.print(": ");
                pw.println(job.toShortString());
                job.dump(pw, "    ", false);
                job.dump(pw, "    ", false, now);
                int priority = evaluateJobPriorityLocked(job);
                if (priority != JobInfo.PRIORITY_DEFAULT) {
                    pw.print("    Evaluated priority: "); pw.println(priority);
                }
                pw.print("    Tag: "); pw.println(job.getTag());
                pw.print("    Enq: ");
                TimeUtils.formatDuration(now - job.madePending, pw);
                pw.println(" ago");
                TimeUtils.formatDuration(job.madePending - now, pw);
                pw.println();
            }
            pw.println();
            pw.println("Active jobs:");
            for (int i=0; i<mActiveServices.size(); i++) {
                JobServiceContext jsc = mActiveServices.get(i);
                pw.print("  Slot #"); pw.print(i); pw.print(": ");
                final JobStatus job = jsc.getRunningJob();
                final JobStatus job = jsc.getRunningJobLocked();
                if (job == null) {
                    pw.println("inactive");
                    continue;
@@ -2195,13 +2280,14 @@ public final class JobSchedulerService extends com.android.server.SystemService
                    pw.print(", timeout at: ");
                    TimeUtils.formatDuration(jsc.getTimeoutElapsed() - now, pw);
                    pw.println();
                    job.dump(pw, "    ", false);
                    int priority = evaluateJobPriorityLocked(jsc.getRunningJob());
                    job.dump(pw, "    ", false, now);
                    int priority = evaluateJobPriorityLocked(jsc.getRunningJobLocked());
                    if (priority != JobInfo.PRIORITY_DEFAULT) {
                        pw.print("    Evaluated priority: "); pw.println(priority);
                    }
                    pw.print("    Active at "); pw.println(job.madeActive);
                    pw.print("    Pending for ");
                    pw.print("    Active at ");
                    TimeUtils.formatDuration(job.madeActive - now, pw);
                    pw.print(", pending for ");
                    TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
                    pw.println();
                }
Loading