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

Commit 27971da7 authored by Kweku Adams's avatar Kweku Adams
Browse files

Stop processing jobs whose state hasn't changed.

Only process (check the status) of jobs that the controller says had a
state change. That way, we regularly only process a subset of jobs.

Bug: 138469672
Test: atest frameworks/base/services/tests/mockingservicestests/src/com/android/server/job
Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/job
Test: atest CtsJobSchedulerTestCases
Change-Id: I866d358797e4745b8ab5b9d855c96ec6006985e0
parent 1ae18bb7
Loading
Loading
Loading
Loading
+5 −1
Original line number Original line Diff line number Diff line
@@ -43,6 +43,9 @@ import java.lang.annotation.RetentionPolicy;
 */
 */
public class JobParameters implements Parcelable {
public class JobParameters implements Parcelable {


    /** @hide */
    public static final int INTERNAL_STOP_REASON_UNKNOWN = -1;

    /** @hide */
    /** @hide */
    public static final int INTERNAL_STOP_REASON_CANCELED =
    public static final int INTERNAL_STOP_REASON_CANCELED =
            JobProtoEnums.INTERNAL_STOP_REASON_CANCELLED; // 0.
            JobProtoEnums.INTERNAL_STOP_REASON_CANCELLED; // 0.
@@ -106,6 +109,7 @@ public class JobParameters implements Parcelable {
     * @hide
     * @hide
     */
     */
    public static final int[] JOB_STOP_REASON_CODES = {
    public static final int[] JOB_STOP_REASON_CODES = {
            INTERNAL_STOP_REASON_UNKNOWN,
            INTERNAL_STOP_REASON_CANCELED,
            INTERNAL_STOP_REASON_CANCELED,
            INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
            INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
            INTERNAL_STOP_REASON_PREEMPT,
            INTERNAL_STOP_REASON_PREEMPT,
@@ -269,7 +273,7 @@ public class JobParameters implements Parcelable {
    private final Network network;
    private final Network network;


    private int mStopReason = STOP_REASON_UNDEFINED;
    private int mStopReason = STOP_REASON_UNDEFINED;
    private int mInternalStopReason; // Default value is REASON_CANCELED
    private int mInternalStopReason = INTERNAL_STOP_REASON_UNKNOWN;
    private String debugStopReason; // Human readable stop reason for debugging.
    private String debugStopReason; // Human readable stop reason for debugging.


    /** @hide */
    /** @hide */
+81 −9
Original line number Original line Diff line number Diff line
@@ -227,6 +227,7 @@ public class JobSchedulerService extends com.android.server.SystemService
    static final int MSG_UID_GONE = 5;
    static final int MSG_UID_GONE = 5;
    static final int MSG_UID_ACTIVE = 6;
    static final int MSG_UID_ACTIVE = 6;
    static final int MSG_UID_IDLE = 7;
    static final int MSG_UID_IDLE = 7;
    static final int MSG_CHECK_CHANGED_JOB_LIST = 8;


    /**
    /**
     * Track Services that have currently active or pending jobs. The index is provided by
     * Track Services that have currently active or pending jobs. The index is provided by
@@ -326,6 +327,10 @@ public class JobSchedulerService extends com.android.server.SystemService
    /** Cached mapping of UIDs (for all users) to a list of packages in the UID. */
    /** Cached mapping of UIDs (for all users) to a list of packages in the UID. */
    private final SparseSetArray<String> mUidToPackageCache = new SparseSetArray<>();
    private final SparseSetArray<String> mUidToPackageCache = new SparseSetArray<>();


    /** List of jobs whose controller state has changed since the last time we evaluated the job. */
    @GuardedBy("mLock")
    private final ArraySet<JobStatus> mChangedJobList = new ArraySet<>();

    /**
    /**
     * Named indices into standby bucket arrays, for clarity in referring to
     * Named indices into standby bucket arrays, for clarity in referring to
     * specific buckets' bookkeeping.
     * specific buckets' bookkeeping.
@@ -1718,10 +1723,13 @@ public class JobSchedulerService extends com.android.server.SystemService
        return mConcurrencyManager.isJobRunningLocked(job);
        return mConcurrencyManager.isJobRunningLocked(job);
    }
    }


    private void noteJobPending(JobStatus job) {
        mJobPackageTracker.notePending(job);
    }

    void noteJobsPending(List<JobStatus> jobs) {
    void noteJobsPending(List<JobStatus> jobs) {
        for (int i = jobs.size() - 1; i >= 0; i--) {
        for (int i = jobs.size() - 1; i >= 0; i--) {
            JobStatus job = jobs.get(i);
            noteJobPending(jobs.get(i));
            mJobPackageTracker.notePending(job);
        }
        }
    }
    }


@@ -1971,13 +1979,19 @@ public class JobSchedulerService extends com.android.server.SystemService
    // StateChangedListener implementations.
    // StateChangedListener implementations.


    /**
    /**
     * Posts a message to the {@link com.android.server.job.JobSchedulerService.JobHandler} that
     * Posts a message to the {@link com.android.server.job.JobSchedulerService.JobHandler} to run
     * some controller's state has changed, so as to run through the list of jobs and start/stop
     * through a list of jobs and start/stop any whose status has changed.
     * any that are eligible.
     */
     */
    @Override
    @Override
    public void onControllerStateChanged() {
    public void onControllerStateChanged(@Nullable ArraySet<JobStatus> changedJobs) {
        if (changedJobs == null) {
            mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
            mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
        } else if (changedJobs.size() > 0) {
            synchronized (mLock) {
                mChangedJobList.addAll(changedJobs);
            }
            mHandler.obtainMessage(MSG_CHECK_CHANGED_JOB_LIST).sendToTarget();
        }
    }
    }


    @Override
    @Override
@@ -2009,6 +2023,7 @@ public class JobSchedulerService extends com.android.server.SystemService
                                mJobPackageTracker.notePending(js);
                                mJobPackageTracker.notePending(js);
                                addOrderedItem(mPendingJobs, js, mPendingJobComparator);
                                addOrderedItem(mPendingJobs, js, mPendingJobComparator);
                            }
                            }
                            mChangedJobList.remove(js);
                        } else {
                        } else {
                            Slog.e(TAG, "Given null job to check individually");
                            Slog.e(TAG, "Given null job to check individually");
                        }
                        }
@@ -2017,7 +2032,6 @@ public class JobSchedulerService extends com.android.server.SystemService
                        if (DEBUG) {
                        if (DEBUG) {
                            Slog.d(TAG, "MSG_CHECK_JOB");
                            Slog.d(TAG, "MSG_CHECK_JOB");
                        }
                        }
                        removeMessages(MSG_CHECK_JOB);
                        if (mReportedActive) {
                        if (mReportedActive) {
                            // if jobs are currently being run, queue all ready jobs for execution.
                            // if jobs are currently being run, queue all ready jobs for execution.
                            queueReadyJobsForExecutionLocked();
                            queueReadyJobsForExecutionLocked();
@@ -2032,6 +2046,12 @@ public class JobSchedulerService extends com.android.server.SystemService
                        }
                        }
                        queueReadyJobsForExecutionLocked();
                        queueReadyJobsForExecutionLocked();
                        break;
                        break;
                    case MSG_CHECK_CHANGED_JOB_LIST:
                        if (DEBUG) {
                            Slog.d(TAG, "MSG_CHECK_CHANGED_JOB_LIST");
                        }
                        checkChangedJobListLocked();
                        break;
                    case MSG_STOP_JOB:
                    case MSG_STOP_JOB:
                        cancelJobImplLocked((JobStatus) message.obj, null, message.arg1,
                        cancelJobImplLocked((JobStatus) message.obj, null, message.arg1,
                                JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
                                JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
@@ -2158,6 +2178,11 @@ public class JobSchedulerService extends com.android.server.SystemService
        // MSG_CHECK_JOB is a weaker form of _GREEDY. Since we're checking and queueing all ready
        // MSG_CHECK_JOB is a weaker form of _GREEDY. Since we're checking and queueing all ready
        // jobs, we don't need to keep any MSG_CHECK_JOB messages in the queue.
        // jobs, we don't need to keep any MSG_CHECK_JOB messages in the queue.
        mHandler.removeMessages(MSG_CHECK_JOB);
        mHandler.removeMessages(MSG_CHECK_JOB);
        // MSG_CHECK_CHANGED_JOB_LIST is a weaker form of _GREEDY. Since we're checking and queueing
        // all ready jobs, we don't need to keep any MSG_CHECK_CHANGED_JOB_LIST messages in the
        // queue.
        mHandler.removeMessages(MSG_CHECK_CHANGED_JOB_LIST);
        mChangedJobList.clear();
        if (DEBUG) {
        if (DEBUG) {
            Slog.d(TAG, "queuing all ready jobs for execution:");
            Slog.d(TAG, "queuing all ready jobs for execution:");
        }
        }
@@ -2220,7 +2245,6 @@ public class JobSchedulerService extends com.android.server.SystemService
            reset();
            reset();
        }
        }


        // Functor method invoked for each job via JobStore.forEachJob()
        @Override
        @Override
        public void accept(JobStatus job) {
        public void accept(JobStatus job) {
            final boolean isRunning = isCurrentlyRunningLocked(job);
            final boolean isRunning = isCurrentlyRunningLocked(job);
@@ -2272,6 +2296,37 @@ public class JobSchedulerService extends com.android.server.SystemService
                    runnableJobs.add(job);
                    runnableJobs.add(job);
                }
                }
            } else {
            } else {
                if (isRunning) {
                    final int internalStopReason;
                    final String debugReason;
                    if (!job.isReady()) {
                        if (job.getEffectiveStandbyBucket() == RESTRICTED_INDEX
                                && job.getStopReason() == JobParameters.STOP_REASON_APP_STANDBY) {
                            internalStopReason =
                                    JobParameters.INTERNAL_STOP_REASON_RESTRICTED_BUCKET;
                            debugReason = "cancelled due to restricted bucket";
                        } else {
                            internalStopReason =
                                    JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED;
                            debugReason = "cancelled due to unsatisfied constraints";
                        }
                    } else {
                        final JobRestriction restriction = checkIfRestricted(job);
                        if (restriction != null) {
                            internalStopReason = restriction.getInternalReason();
                            debugReason = "restricted due to "
                                    + JobParameters.getInternalReasonCodeDescription(
                                    internalStopReason);
                        } else {
                            internalStopReason = JobParameters.INTERNAL_STOP_REASON_UNKNOWN;
                            debugReason = "couldn't figure out why the job should stop running";
                        }
                    }
                    stopJobOnServiceContextLocked(job, job.getStopReason(),
                            internalStopReason, debugReason);
                } else if (mPendingJobs.remove(job)) {
                    noteJobNonPending(job);
                }
                evaluateControllerStatesLocked(job);
                evaluateControllerStatesLocked(job);
            }
            }
        }
        }
@@ -2312,6 +2367,11 @@ public class JobSchedulerService extends com.android.server.SystemService


    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private void maybeQueueReadyJobsForExecutionLocked() {
    private void maybeQueueReadyJobsForExecutionLocked() {
        mHandler.removeMessages(MSG_CHECK_JOB);
        // This method will evaluate all jobs, so we don't need to keep any messages for a suubset
        // of jobs in the queue.
        mHandler.removeMessages(MSG_CHECK_CHANGED_JOB_LIST);
        mChangedJobList.clear();
        if (DEBUG) Slog.d(TAG, "Maybe queuing ready jobs...");
        if (DEBUG) Slog.d(TAG, "Maybe queuing ready jobs...");


        noteJobsNonpending(mPendingJobs);
        noteJobsNonpending(mPendingJobs);
@@ -2321,6 +2381,18 @@ public class JobSchedulerService extends com.android.server.SystemService
        mMaybeQueueFunctor.postProcessLocked();
        mMaybeQueueFunctor.postProcessLocked();
    }
    }


    @GuardedBy("mLock")
    private void checkChangedJobListLocked() {
        mHandler.removeMessages(MSG_CHECK_CHANGED_JOB_LIST);
        if (DEBUG) {
            Slog.d(TAG, "Check changed jobs...");
        }

        mChangedJobList.forEach(mMaybeQueueFunctor);
        mMaybeQueueFunctor.postProcessLocked();
        mChangedJobList.clear();
    }

    /** Returns true if both the calling and source users for the job are started. */
    /** Returns true if both the calling and source users for the job are started. */
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    public boolean areUsersStartedLocked(final JobStatus job) {
    public boolean areUsersStartedLocked(final JobStatus job) {
+5 −3
Original line number Original line Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.server.job;
package com.android.server.job;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArraySet;


import com.android.server.job.controllers.JobStatus;
import com.android.server.job.controllers.JobStatus;


@@ -29,10 +31,10 @@ import java.util.List;
 */
 */
public interface StateChangedListener {
public interface StateChangedListener {
    /**
    /**
     * Called by the controller to notify the JobManager that it should check on the state of a
     * Called by the controller to notify the JobScheduler that it should check on the state of a
     * task.
     * set of jobs. If {@code changedJobs} is null, then all registered jobs will be evaluated.
     */
     */
    public void onControllerStateChanged();
    void onControllerStateChanged(@Nullable ArraySet<JobStatus> changedJobs);


    /**
    /**
     * Called by the controller to notify the JobManager that regardless of the state of the task,
     * Called by the controller to notify the JobManager that regardless of the state of the task,
+6 −5
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;


import android.os.SystemClock;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Log;
import android.util.Slog;
import android.util.Slog;
@@ -191,8 +192,8 @@ public final class BackgroundJobsController extends StateController {
            ));
            ));
        }
        }


        if (mUpdateJobFunctor.mChanged) {
        if (mUpdateJobFunctor.mChangedJobs.size() > 0) {
            mStateChangedListener.onControllerStateChanged();
            mStateChangedListener.onControllerStateChanged(mUpdateJobFunctor.mChangedJobs);
        }
        }
    }
    }


@@ -222,7 +223,7 @@ public final class BackgroundJobsController extends StateController {


    private final class UpdateJobFunctor implements Consumer<JobStatus> {
    private final class UpdateJobFunctor implements Consumer<JobStatus> {
        int mActiveState;
        int mActiveState;
        boolean mChanged = false;
        final ArraySet<JobStatus> mChangedJobs = new ArraySet<>();
        int mTotalCount = 0;
        int mTotalCount = 0;
        int mCheckedCount = 0;
        int mCheckedCount = 0;
        long mUpdateTimeElapsed = 0;
        long mUpdateTimeElapsed = 0;
@@ -230,7 +231,7 @@ public final class BackgroundJobsController extends StateController {
        void prepare(int newActiveState) {
        void prepare(int newActiveState) {
            mActiveState = newActiveState;
            mActiveState = newActiveState;
            mUpdateTimeElapsed = sElapsedRealtimeClock.millis();
            mUpdateTimeElapsed = sElapsedRealtimeClock.millis();
            mChanged = false;
            mChangedJobs.clear();
            mTotalCount = 0;
            mTotalCount = 0;
            mCheckedCount = 0;
            mCheckedCount = 0;
        }
        }
@@ -240,7 +241,7 @@ public final class BackgroundJobsController extends StateController {
            mTotalCount++;
            mTotalCount++;
            mCheckedCount++;
            mCheckedCount++;
            if (updateSingleJobRestrictionLocked(jobStatus, mUpdateTimeElapsed, mActiveState)) {
            if (updateSingleJobRestrictionLocked(jobStatus, mUpdateTimeElapsed, mActiveState)) {
                mChanged = true;
                mChangedJobs.add(jobStatus);
            }
            }
        }
        }
    }
    }
+1 −1
Original line number Original line Diff line number Diff line
@@ -112,7 +112,7 @@ public final class BatteryController extends RestrictingController {
        } else if (reportChange) {
        } else if (reportChange) {
            // Otherwise, just let the job scheduler know the state has changed and take care of it
            // Otherwise, just let the job scheduler know the state has changed and take care of it
            // as it thinks is best.
            // as it thinks is best.
            mStateChangedListener.onControllerStateChanged();
            mStateChangedListener.onControllerStateChanged(mTrackedTasks);
        }
        }
    }
    }


Loading