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

Commit 4a011591 authored by Kweku Adams's avatar Kweku Adams
Browse files

Adjust concurrency limits based on device.

The concurrency limits haven't really changed much since JobScheduler
was first created. Since we're moving to a world where we want apps to
run jobs instead of FGS, we need to adjust them to handle the new
reality (fewer FGS, more jobs) and make sense given modern device
characteristics. We now set the concurrency limit based on the device's
RAM size and set min and max slots as a percentage of that dynamic
limit.

Bug: 262613827
Test: atest CtsJobSchedulerTestCases:ExpeditedJobTest
Test: atest CtsJobSchedulerTestCases:JobSchedulingTest
Test: atest FrameworksMockingServicesTests:JobConcurrencyManagerTest
Test: atest FrameworksServicesTests:BiasSchedulingTest
Test: atest FrameworksServicesTests:WorkCountTrackerTest
Test: atest FrameworksServicesTests:WorkTypeConfigTest
Change-Id: Ic0aa25f8d2c6af5800f9b33359ac58d1b96435f3
parent 404b7181
Loading
Loading
Loading
Loading
+266 −155

File changed.

Preview size limit exceeded, changes collapsed.

+45 −43
Original line number Diff line number Diff line
@@ -213,7 +213,7 @@ public final class JobConcurrencyManagerTest {
        mJobConcurrencyManager.prepareForAssignmentDeterminationLocked(
                idle, preferredUidOnly, stoppable, assignmentInfo);

        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, idle.size());
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, idle.size());
        assertEquals(0, preferredUidOnly.size());
        assertEquals(0, stoppable.size());
        assertEquals(0, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
@@ -222,7 +222,7 @@ public final class JobConcurrencyManagerTest {

    @Test
    public void testPrepareForAssignmentDetermination_onlyPendingJobs() {
        for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
        for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
            JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i);
            mPendingJobQueue.add(job);
        }
@@ -235,7 +235,7 @@ public final class JobConcurrencyManagerTest {
        mJobConcurrencyManager.prepareForAssignmentDeterminationLocked(
                idle, preferredUidOnly, stoppable, assignmentInfo);

        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, idle.size());
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, idle.size());
        assertEquals(0, preferredUidOnly.size());
        assertEquals(0, stoppable.size());
        assertEquals(0, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
@@ -244,7 +244,7 @@ public final class JobConcurrencyManagerTest {

    @Test
    public void testPrepareForAssignmentDetermination_onlyPreferredUidOnly() {
        for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
        for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
            JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i);
            mJobConcurrencyManager.addRunningJobForTesting(job);
        }
@@ -262,7 +262,7 @@ public final class JobConcurrencyManagerTest {
                idle, preferredUidOnly, stoppable, assignmentInfo);

        assertEquals(0, idle.size());
        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());
        assertEquals(0, stoppable.size());
        assertEquals(0, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
        assertEquals(0, assignmentInfo.numRunningImmediacyPrivileged);
@@ -270,7 +270,7 @@ public final class JobConcurrencyManagerTest {

    @Test
    public void testPrepareForAssignmentDetermination_onlyStartedWithImmediacyPrivilege() {
        for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
        for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
            JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i);
            job.startedWithImmediacyPrivilege = true;
            mJobConcurrencyManager.addRunningJobForTesting(job);
@@ -289,19 +289,19 @@ public final class JobConcurrencyManagerTest {
                idle, preferredUidOnly, stoppable, assignmentInfo);

        assertEquals(0, idle.size());
        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT / 2, preferredUidOnly.size());
        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT / 2, stoppable.size());
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT / 2, preferredUidOnly.size());
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT / 2, stoppable.size());
        assertEquals(0, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT,
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT,
                assignmentInfo.numRunningImmediacyPrivileged);
    }

    @Test
    public void testDetermineAssignments_allRegular() throws Exception {
        setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT,
                new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT));
        setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT,
                new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT));
        final ArraySet<JobStatus> jobs = new ArraySet<>();
        for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
        for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
            final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE + i;
            final String sourcePkgName = "com.source.package." + UserHandle.getAppId(uid);
            setPackageUid(sourcePkgName, uid);
@@ -322,7 +322,7 @@ public final class JobConcurrencyManagerTest {
                .determineAssignmentsLocked(changed, idle, preferredUidOnly, stoppable,
                        assignmentInfo);

        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, changed.size());
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, changed.size());
        for (int i = changed.size() - 1; i >= 0; --i) {
            jobs.remove(changed.valueAt(i).newJob);
        }
@@ -332,16 +332,16 @@ public final class JobConcurrencyManagerTest {
    @Test
    public void testDetermineAssignments_allPreferredUidOnly_shortTimeLeft() throws Exception {
        mConfigBuilder.setBoolean(JobConcurrencyManager.KEY_ENABLE_MAX_WAIT_TIME_BYPASS, true);
        setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT,
                new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT));
        for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT * 2; ++i) {
        setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT,
                new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT));
        for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT * 2; ++i) {
            final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE + i;
            final String sourcePkgName = "com.source.package." + UserHandle.getAppId(uid);
            setPackageUid(sourcePkgName, uid);
            final JobStatus job = createJob(uid, sourcePkgName);
            spyOn(job);
            doReturn(i % 2 == 0).when(job).shouldTreatAsExpeditedJob();
            if (i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT) {
            if (i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT) {
                mJobConcurrencyManager.addRunningJobForTesting(job);
            } else {
                mPendingJobQueue.add(job);
@@ -366,30 +366,30 @@ public final class JobConcurrencyManagerTest {
        mJobConcurrencyManager.prepareForAssignmentDeterminationLocked(
                idle, preferredUidOnly, stoppable, assignmentInfo);
        assertEquals(remainingTimeMs, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());

        mJobConcurrencyManager
                .determineAssignmentsLocked(changed, idle, preferredUidOnly, stoppable,
                        assignmentInfo);

        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());
        assertEquals(0, changed.size());
    }

    @Test
    public void testDetermineAssignments_allPreferredUidOnly_mediumTimeLeft() throws Exception {
        mConfigBuilder.setBoolean(JobConcurrencyManager.KEY_ENABLE_MAX_WAIT_TIME_BYPASS, true);
        setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT,
                new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT));
        setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT,
                new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT));
        final ArraySet<JobStatus> jobs = new ArraySet<>();
        for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT * 2; ++i) {
        for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT * 2; ++i) {
            final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE + i;
            final String sourcePkgName = "com.source.package." + UserHandle.getAppId(uid);
            setPackageUid(sourcePkgName, uid);
            final JobStatus job = createJob(uid, sourcePkgName);
            spyOn(job);
            doReturn(i % 2 == 0).when(job).shouldTreatAsExpeditedJob();
            if (i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT) {
            if (i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT) {
                mJobConcurrencyManager.addRunningJobForTesting(job);
            } else {
                mPendingJobQueue.add(job);
@@ -417,17 +417,17 @@ public final class JobConcurrencyManagerTest {
        mJobConcurrencyManager.prepareForAssignmentDeterminationLocked(
                idle, preferredUidOnly, stoppable, assignmentInfo);
        assertEquals(remainingTimeMs, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());

        mJobConcurrencyManager
                .determineAssignmentsLocked(changed, idle, preferredUidOnly, stoppable,
                        assignmentInfo);

        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());
        for (int i = changed.size() - 1; i >= 0; --i) {
            jobs.remove(changed.valueAt(i).newJob);
        }
        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT - 1, jobs.size());
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT - 1, jobs.size());
        assertEquals(1, changed.size());
        JobStatus assignedJob = changed.valueAt(0).newJob;
        assertTrue(assignedJob.shouldTreatAsExpeditedJob());
@@ -436,17 +436,17 @@ public final class JobConcurrencyManagerTest {
    @Test
    public void testDetermineAssignments_allPreferredUidOnly_longTimeLeft() throws Exception {
        mConfigBuilder.setBoolean(JobConcurrencyManager.KEY_ENABLE_MAX_WAIT_TIME_BYPASS, true);
        setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT,
                new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT));
        setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT,
                new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT));
        final ArraySet<JobStatus> jobs = new ArraySet<>();
        for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT * 2; ++i) {
        for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT * 2; ++i) {
            final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE + i;
            final String sourcePkgName = "com.source.package." + UserHandle.getAppId(uid);
            setPackageUid(sourcePkgName, uid);
            final JobStatus job = createJob(uid, sourcePkgName);
            spyOn(job);
            doReturn(i % 2 == 0).when(job).shouldTreatAsExpeditedJob();
            if (i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT) {
            if (i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT) {
                mJobConcurrencyManager.addRunningJobForTesting(job);
            } else {
                mPendingJobQueue.add(job);
@@ -473,13 +473,13 @@ public final class JobConcurrencyManagerTest {
        mJobConcurrencyManager.prepareForAssignmentDeterminationLocked(
                idle, preferredUidOnly, stoppable, assignmentInfo);
        assertEquals(remainingTimeMs, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());

        mJobConcurrencyManager
                .determineAssignmentsLocked(changed, idle, preferredUidOnly, stoppable,
                        assignmentInfo);

        assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
        assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());
        // Depending on iteration order, we may create 1 or 2 contexts.
        final long numAssignedJobs = changed.size();
        assertTrue(numAssignedJobs > 0);
@@ -488,7 +488,7 @@ public final class JobConcurrencyManagerTest {
            jobs.remove(changed.valueAt(i).newJob);
        }
        assertEquals(numAssignedJobs,
                JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT - jobs.size());
                JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT - jobs.size());
        JobStatus firstAssignedJob = changed.valueAt(0).newJob;
        if (!firstAssignedJob.shouldTreatAsExpeditedJob()) {
            assertEquals(2, numAssignedJobs);
@@ -538,14 +538,14 @@ public final class JobConcurrencyManagerTest {
        assertFalse(mJobConcurrencyManager.isPkgConcurrencyLimitedLocked(topJob));

        // Pending jobs shouldn't affect TOP job's status.
        for (int i = 1; i <= JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
        for (int i = 1; i <= JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
            final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i);
            mPendingJobQueue.add(job);
        }
        assertFalse(mJobConcurrencyManager.isPkgConcurrencyLimitedLocked(topJob));

        // Already running jobs shouldn't affect TOP job's status.
        for (int i = 1; i <= JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
        for (int i = 1; i <= JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
            final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE, i);
            mJobConcurrencyManager.addRunningJobForTesting(job);
        }
@@ -605,9 +605,9 @@ public final class JobConcurrencyManagerTest {
        spyOn(testEj);
        doReturn(true).when(testEj).shouldTreatAsExpeditedJob();

        setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT);
        setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT);

        for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
        for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
            final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i, i + 1);
            mPendingJobQueue.add(job);
        }
@@ -887,12 +887,14 @@ public final class JobConcurrencyManagerTest {
            mConfigBuilder
                    .setInt(WorkTypeConfig.KEY_PREFIX_MAX_TOTAL + identifier, total);
            for (TypeConfig config : typeConfigs) {
                mConfigBuilder.setInt(
                        WorkTypeConfig.KEY_PREFIX_MAX + config.workTypeString + "_" + identifier,
                        config.max);
                mConfigBuilder.setInt(
                        WorkTypeConfig.KEY_PREFIX_MIN + config.workTypeString + "_" + identifier,
                        config.min);
                mConfigBuilder.setFloat(
                        WorkTypeConfig.KEY_PREFIX_MAX_RATIO + config.workTypeString + "_"
                                + identifier,
                        (float) config.max / total);
                mConfigBuilder.setFloat(
                        WorkTypeConfig.KEY_PREFIX_MIN_RATIO + config.workTypeString + "_"
                                + identifier,
                        (float) config.min / total);
            }
        }
        updateDeviceConfig();
+4 −4
Original line number Diff line number Diff line
@@ -57,14 +57,14 @@ public class BiasSchedulingTest extends AndroidTestCase {
    }

    public void testLowerBiasJobPreempted() throws Exception {
        for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
        for (int i = 0; i < JobConcurrencyManager.MAX_CONCURRENCY_LIMIT; ++i) {
            JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent)
                    .setBias(LOW_BIAS)
                    .setOverrideDeadline(0)
                    .build();
            mJobScheduler.schedule(job);
        }
        final int higherBiasJobId = 100 + JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT;
        final int higherBiasJobId = 100 + JobConcurrencyManager.MAX_CONCURRENCY_LIMIT;
        JobInfo jobHigher = new JobInfo.Builder(higherBiasJobId, sJobServiceComponent)
                .setBias(HIGH_BIAS)
                .setMinimumLatency(2000)
@@ -88,14 +88,14 @@ public class BiasSchedulingTest extends AndroidTestCase {
    }

    public void testHigherBiasJobNotPreempted() throws Exception {
        for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
        for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
            JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent)
                    .setBias(HIGH_BIAS)
                    .setOverrideDeadline(0)
                    .build();
            mJobScheduler.schedule(job);
        }
        final int lowerBiasJobId = 100 + JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT;
        final int lowerBiasJobId = 100 + JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT;
        JobInfo jobLower = new JobInfo.Builder(lowerBiasJobId, sJobServiceComponent)
                .setBias(LOW_BIAS)
                .setMinimumLatency(2000)
+175 −137

File changed.

Preview size limit exceeded, changes collapsed.

+146 −106

File changed.

Preview size limit exceeded, changes collapsed.