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

Commit 63600482 authored by Makoto Onuki's avatar Makoto Onuki Committed by Android (Google) Code Review
Browse files

Merge "Clean up job concurrency calculation"

parents 6d8e8091 0f6499c5
Loading
Loading
Loading
Loading
+53 −39
Original line number Original line Diff line number Diff line
@@ -44,17 +44,11 @@ class JobConcurrencyManager {
     * We manipulate this array until we arrive at what jobs should be running on
     * We manipulate this array until we arrive at what jobs should be running on
     * what JobServiceContext.
     * what JobServiceContext.
     */
     */
    JobStatus[] mTmpAssignContextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT];
    JobStatus[] mRecycledAssignContextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT];


    /**
    boolean[] mRecycledSlotChanged = new boolean[MAX_JOB_CONTEXTS_COUNT];
     * Indicates whether we need to act on this jobContext id
     */
    boolean[] mTmpAssignAct = new boolean[MAX_JOB_CONTEXTS_COUNT];


    /**
    int[] mRecycledPreferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT];
     * The uid whose jobs we would like to assign to a context.
     */
    int[] mTmpAssignPreferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT];


    JobConcurrencyManager(JobSchedulerService service) {
    JobConcurrencyManager(JobSchedulerService service) {
        mService = service;
        mService = service;
@@ -99,28 +93,30 @@ class JobConcurrencyManager {
                break;
                break;
        }
        }


        JobStatus[] contextIdToJobMap = mTmpAssignContextIdToJobMap;
        // To avoid GC churn, we recycle the arrays.
        boolean[] act = mTmpAssignAct;
        JobStatus[] contextIdToJobMap = mRecycledAssignContextIdToJobMap;
        int[] preferredUidForContext = mTmpAssignPreferredUidForContext;
        boolean[] slotChanged = mRecycledSlotChanged;
        int numActive = 0;
        int[] preferredUidForContext = mRecycledPreferredUidForContext;
        int numForeground = 0;

        int numTotalRunningJobs = 0;
        int numForegroundJobs = 0;
        for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
        for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
            final JobServiceContext js = mService.mActiveServices.get(i);
            final JobServiceContext js = mService.mActiveServices.get(i);
            final JobStatus status = js.getRunningJobLocked();
            final JobStatus status = js.getRunningJobLocked();
            if ((contextIdToJobMap[i] = status) != null) {
            if ((contextIdToJobMap[i] = status) != null) {
                numActive++;
                numTotalRunningJobs++;
                if (status.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
                if (status.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
                    numForeground++;
                    numForegroundJobs++;
                }
                }
            }
            }
            act[i] = false;
            slotChanged[i] = false;
            preferredUidForContext[i] = js.getPreferredUid();
            preferredUidForContext[i] = js.getPreferredUid();
        }
        }
        if (DEBUG) {
        if (DEBUG) {
            Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial"));
            Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial"));
        }
        }
        for (int i=0; i<pendingJobs.size(); i++) {
        for (int i=0; i<pendingJobs.size(); i++) {
            JobStatus nextPending = pendingJobs.get(i);
            final JobStatus nextPending = pendingJobs.get(i);


            // If job is already running, go to next job.
            // If job is already running, go to next job.
            int jobRunningContext = findJobContextIdFromMap(nextPending, contextIdToJobMap);
            int jobRunningContext = findJobContextIdFromMap(nextPending, contextIdToJobMap);
@@ -131,23 +127,32 @@ class JobConcurrencyManager {
            final int priority = mService.evaluateJobPriorityLocked(nextPending);
            final int priority = mService.evaluateJobPriorityLocked(nextPending);
            nextPending.lastEvaluatedPriority = priority;
            nextPending.lastEvaluatedPriority = priority;


            // Find a context for nextPending. The context should be available OR
            // Find an available slot for nextPending. The context should be available OR
            // it should have lowest priority among all running jobs
            // it should have lowest priority among all running jobs
            // (sharing the same Uid as nextPending)
            // (sharing the same Uid as nextPending)
            int minPriority = Integer.MAX_VALUE;
            int minPriorityForPreemption = Integer.MAX_VALUE;
            int minPriorityContextId = -1;
            int selectedContextId = -1;
            boolean startingJob = false;
            for (int j=0; j<MAX_JOB_CONTEXTS_COUNT; j++) {
            for (int j=0; j<MAX_JOB_CONTEXTS_COUNT; j++) {
                JobStatus job = contextIdToJobMap[j];
                JobStatus job = contextIdToJobMap[j];
                int preferredUid = preferredUidForContext[j];
                int preferredUid = preferredUidForContext[j];
                if (job == null) {
                if (job == null) {
                    if ((numActive < mService.mMaxActiveJobs ||
                    final boolean totalCountOk = numTotalRunningJobs < mService.mMaxActiveJobs;
                            (priority >= JobInfo.PRIORITY_TOP_APP &&
                    final boolean fgCountOk = (priority >= JobInfo.PRIORITY_TOP_APP)
                                    numForeground < mConstants.FG_JOB_COUNT)) &&
                            && (numForegroundJobs < mConstants.FG_JOB_COUNT);
                            (preferredUid == nextPending.getUid() ||
                    final boolean preferredUidOkay = (preferredUid == nextPending.getUid())
                                    preferredUid == JobServiceContext.NO_PREFERRED_UID)) {
                            || (preferredUid == JobServiceContext.NO_PREFERRED_UID);

                    // TODO: The following check is slightly wrong.
                    // Depending on how the pending jobs are sorted, we sometimes cap the total
                    // job count at mMaxActiveJobs (when all jobs are FG jobs), or
                    // at [mMaxActiveJobs + FG_JOB_COUNT] (when there are mMaxActiveJobs BG jobs
                    // and then FG_JOB_COUNT FG jobs.)
                    if ((totalCountOk || fgCountOk) && preferredUidOkay) {
                        // This slot is free, and we haven't yet hit the limit on
                        // This slot is free, and we haven't yet hit the limit on
                        // concurrent jobs...  we can just throw the job in to here.
                        // concurrent jobs...  we can just throw the job in to here.
                        minPriorityContextId = j;
                        selectedContextId = j;
                        startingJob = true;
                        break;
                        break;
                    }
                    }
                    // No job on this context, but nextPending can't run here because
                    // No job on this context, but nextPending can't run here because
@@ -158,30 +163,39 @@ class JobConcurrencyManager {
                if (job.getUid() != nextPending.getUid()) {
                if (job.getUid() != nextPending.getUid()) {
                    continue;
                    continue;
                }
                }
                if (mService.evaluateJobPriorityLocked(job) >= nextPending.lastEvaluatedPriority) {

                final int jobPriority = mService.evaluateJobPriorityLocked(job);
                if (jobPriority >= nextPending.lastEvaluatedPriority) {
                    continue;
                    continue;
                }
                }
                if (minPriority > nextPending.lastEvaluatedPriority) {

                    minPriority = nextPending.lastEvaluatedPriority;
                // TODO lastEvaluatedPriority should be evaluateJobPriorityLocked. (double check it)
                    minPriorityContextId = j;
                if (minPriorityForPreemption > nextPending.lastEvaluatedPriority) {
                    minPriorityForPreemption = nextPending.lastEvaluatedPriority;
                    selectedContextId = j;
                    // In this case, we're just going to preempt a low priority job, we're not
                    // actually starting a job, so don't set startingJob.
                }
            }
            }
            if (selectedContextId != -1) {
                contextIdToJobMap[selectedContextId] = nextPending;
                slotChanged[selectedContextId] = true;
            }
            }
            if (minPriorityContextId != -1) {
            if (startingJob) {
                contextIdToJobMap[minPriorityContextId] = nextPending;
                // Increase the counters when we're going to start a job.
                act[minPriorityContextId] = true;
                numTotalRunningJobs++;
                numActive++;
                if (priority >= JobInfo.PRIORITY_TOP_APP) {
                if (priority >= JobInfo.PRIORITY_TOP_APP) {
                    numForeground++;
                    numForegroundJobs++;
                }
                }
            }
            }
        }
        }
        if (DEBUG) {
        if (DEBUG) {
            Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final"));
            Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final"));
        }
        }
        tracker.noteConcurrency(numActive, numForeground);
        tracker.noteConcurrency(numTotalRunningJobs, numForegroundJobs);
        for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
        for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
            boolean preservePreferredUid = false;
            boolean preservePreferredUid = false;
            if (act[i]) {
            if (slotChanged[i]) {
                JobStatus js = activeServices.get(i).getRunningJobLocked();
                JobStatus js = activeServices.get(i).getRunningJobLocked();
                if (js != null) {
                if (js != null) {
                    if (DEBUG) {
                    if (DEBUG) {
@@ -195,7 +209,7 @@ class JobConcurrencyManager {
                    final JobStatus pendingJob = contextIdToJobMap[i];
                    final JobStatus pendingJob = contextIdToJobMap[i];
                    if (DEBUG) {
                    if (DEBUG) {
                        Slog.d(TAG, "About to run job on context "
                        Slog.d(TAG, "About to run job on context "
                                + String.valueOf(i) + ", job: " + pendingJob);
                                + i + ", job: " + pendingJob);
                    }
                    }
                    for (int ic=0; ic<controllers.size(); ic++) {
                    for (int ic=0; ic<controllers.size(); ic++) {
                        controllers.get(ic).prepareForExecutionLocked(pendingJob);
                        controllers.get(ic).prepareForExecutionLocked(pendingJob);
+9 −0
Original line number Original line Diff line number Diff line
@@ -1261,6 +1261,9 @@ public class JobSchedulerService extends com.android.server.SystemService
    @Override
    @Override
    public void onDeviceIdleStateChanged(boolean deviceIdle) {
    public void onDeviceIdleStateChanged(boolean deviceIdle) {
        synchronized (mLock) {
        synchronized (mLock) {
            if (DEBUG) {
                Slog.d(TAG, "Doze state changed: " + deviceIdle);
            }
            if (deviceIdle) {
            if (deviceIdle) {
                // When becoming idle, make sure no jobs are actively running,
                // When becoming idle, make sure no jobs are actively running,
                // except those using the idle exemption flag.
                // except those using the idle exemption flag.
@@ -1829,6 +1832,9 @@ public class JobSchedulerService extends com.android.server.SystemService
                        }
                        }
                    } break;
                    } break;
                    case MSG_CHECK_JOB:
                    case MSG_CHECK_JOB:
                        if (DEBUG) {
                            Slog.d(TAG, "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();
@@ -1838,6 +1844,9 @@ public class JobSchedulerService extends com.android.server.SystemService
                        }
                        }
                        break;
                        break;
                    case MSG_CHECK_JOB_GREEDY:
                    case MSG_CHECK_JOB_GREEDY:
                        if (DEBUG) {
                            Slog.d(TAG, "MSG_CHECK_JOB_GREEDY");
                        }
                        queueReadyJobsForExecutionLocked();
                        queueReadyJobsForExecutionLocked();
                        break;
                        break;
                    case MSG_STOP_JOB:
                    case MSG_STOP_JOB: