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

Commit 579d8658 authored by Kweku Adams's avatar Kweku Adams
Browse files

Exempt user-initiated jobs from quota.

Don't apply quotas to user-initiated jobs and don't count them towards
the quota applied to other jobs.

Bug: 261999509
Test: atest FrameworksMockingServicesTests:QuotaControllerTest
Change-Id: I8f830d2917ee6ebc1599d1bba07f7ceec75b69a4
parent 99998391
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -641,6 +641,9 @@ public final class QuotaController extends StateController {
            mTopStartedJobs.add(jobStatus);
            // Top jobs won't count towards quota so there's no need to involve the Timer.
            return;
        } else if (jobStatus.shouldTreatAsUserInitiated()) {
            // User-initiated jobs won't count towards quota.
            return;
        }

        final int userId = jobStatus.getSourceUserId();
@@ -892,7 +895,8 @@ public final class QuotaController extends StateController {
        //   1. it was started while the app was in the TOP state
        //   2. the app is currently in the foreground
        //   3. the app overall is within its quota
        return isTopStartedJobLocked(jobStatus)
        return jobStatus.shouldTreatAsUserInitiated()
                || isTopStartedJobLocked(jobStatus)
                || isUidInForeground(jobStatus.getSourceUid())
                || isWithinQuotaLocked(
                jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket);
@@ -2116,6 +2120,13 @@ public final class QuotaController extends StateController {
        }

        void startTrackingJobLocked(@NonNull JobStatus jobStatus) {
            if (jobStatus.shouldTreatAsUserInitiated()) {
                if (DEBUG) {
                    Slog.v(TAG, "Timer ignoring " + jobStatus.toShortString()
                            + " because it's user-initiated");
                }
                return;
            }
            if (isTopStartedJobLocked(jobStatus)) {
                // We intentionally don't pay attention to fg state changes after a TOP job has
                // started.
+20 −0
Original line number Diff line number Diff line
@@ -313,6 +313,11 @@ public class TareController extends StateController {
    @GuardedBy("mLock")
    public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
        final long nowElapsed = sElapsedRealtimeClock.millis();
        if (jobStatus.shouldTreatAsUserInitiated()) {
            // User-initiated jobs should always be allowed to run.
            jobStatus.setTareWealthConstraintSatisfied(nowElapsed, true);
            return;
        }
        jobStatus.setTareWealthConstraintSatisfied(nowElapsed, hasEnoughWealthLocked(jobStatus));
        setExpeditedTareApproved(jobStatus, nowElapsed,
                jobStatus.isRequestedExpeditedJob() && canAffordExpeditedBillLocked(jobStatus));
@@ -326,6 +331,11 @@ public class TareController extends StateController {
    @Override
    @GuardedBy("mLock")
    public void prepareForExecutionLocked(JobStatus jobStatus) {
        if (jobStatus.shouldTreatAsUserInitiated()) {
            // TODO(202954395): consider noting execution with the EconomyManager even though it
            //                  won't affect this job
            return;
        }
        final int userId = jobStatus.getSourceUserId();
        final String pkgName = jobStatus.getSourcePackageName();
        ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
@@ -355,6 +365,9 @@ public class TareController extends StateController {
    @Override
    @GuardedBy("mLock")
    public void unprepareFromExecutionLocked(JobStatus jobStatus) {
        if (jobStatus.shouldTreatAsUserInitiated()) {
            return;
        }
        final int userId = jobStatus.getSourceUserId();
        final String pkgName = jobStatus.getSourcePackageName();
        // If this method is called, then jobStatus.madeActive was never updated, so don't use it
@@ -384,6 +397,9 @@ public class TareController extends StateController {
    @Override
    @GuardedBy("mLock")
    public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob) {
        if (jobStatus.shouldTreatAsUserInitiated()) {
            return;
        }
        final int userId = jobStatus.getSourceUserId();
        final String pkgName = jobStatus.getSourcePackageName();
        if (!mTopStartedJobs.remove(jobStatus) && jobStatus.madeActive > 0) {
@@ -637,6 +653,10 @@ public class TareController extends StateController {
        if (!mIsEnabled) {
            return true;
        }
        if (jobStatus.shouldTreatAsUserInitiated()) {
            // Always allow user-initiated jobs.
            return true;
        }
        if (mService.getUidBias(jobStatus.getSourceUid()) == JobInfo.BIAS_TOP_APP
                || isTopStartedJobLocked(jobStatus)) {
            // Jobs for the top app should always be allowed to run, and any jobs started while
+25 −0
Original line number Diff line number Diff line
@@ -2162,6 +2162,31 @@ public class QuotaControllerTest {
        }
    }

    @Test
    public void testIsWithinQuotaLocked_UserInitiated() {
        // Put app in a state where regular jobs are out of quota.
        setDischarging();
        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
        final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW;
        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25), false);
        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount),
                false);
        JobStatus job = createJobStatus("testIsWithinQuotaLocked_UserInitiated", 1);
        spyOn(job);
        synchronized (mQuotaController.mLock) {
            mQuotaController.incrementJobCountLocked(SOURCE_USER_ID, SOURCE_PACKAGE, jobCount);
            assertFalse(mQuotaController
                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
            doReturn(false).when(job).shouldTreatAsUserInitiated();
            assertFalse(mQuotaController.isWithinQuotaLocked(job));
            // User-initiated job should still be allowed.
            doReturn(true).when(job).shouldTreatAsUserInitiated();
            assertTrue(mQuotaController.isWithinQuotaLocked(job));
        }
    }

    @Test
    public void testIsWithinQuotaLocked_WithQuotaBump_Duration() {
        setDischarging();