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

Commit a8e4b0aa authored by Kweku Adams's avatar Kweku Adams
Browse files

Limit execution extension to important jobs.

Limit the timeout execution extension for apps in privileged states to
only the jobs that are marked as important.

Bug: 284512488
Bug: 299329948
Bug: 299346198
Test: atest FrameworksMockingServicesTests:QuotaControllerTest
Change-Id: Ie6d17f091ae18cd8ff402886ca7d9a9be3c56f07
parent 8a5ee58d
Loading
Loading
Loading
Loading
+17 −11
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.UidObserver;
import android.app.job.JobInfo;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
@@ -772,7 +773,9 @@ public final class QuotaController extends StateController {
        if (!jobStatus.shouldTreatAsExpeditedJob()) {
            // If quota is currently "free", then the job can run for the full amount of time,
            // regardless of bucket (hence using charging instead of isQuotaFreeLocked()).
            if (mService.isBatteryCharging()
            if (mService.isBatteryCharging()) {
                return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
            }
            // The top and foreground cases here were added because apps in those states
            // aren't really restricted and the work could be something the user is
            // waiting for. Now that user-initiated jobs are a defined concept, we may
@@ -781,9 +784,12 @@ public final class QuotaController extends StateController {
            // rely on this exception. Once we add more UIJ types, we can re-evaluate
            // the need for these exceptions.
            // TODO: re-evaluate the need for these exceptions
                    || mTopAppCache.get(jobStatus.getSourceUid())
            final boolean isInPrivilegedState = mTopAppCache.get(jobStatus.getSourceUid())
                    || isTopStartedJobLocked(jobStatus)
                    || isUidInForeground(jobStatus.getSourceUid())) {
                    || isUidInForeground(jobStatus.getSourceUid());
            final boolean isJobImportant = jobStatus.getEffectivePriority() >= JobInfo.PRIORITY_HIGH
                    || (jobStatus.getFlags() & JobInfo.FLAG_IMPORTANT_WHILE_FOREGROUND) != 0;
            if (isInPrivilegedState && isJobImportant) {
                return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
            }
            return getTimeUntilQuotaConsumedLocked(
+43 −7
Original line number Diff line number Diff line
@@ -368,10 +368,15 @@ public class QuotaControllerTest {
        }
    }

    private JobInfo.Builder createJobInfoBuilder(int jobId) {
        return new JobInfo.Builder(jobId, new ComponentName(mContext, "TestQuotaJobService"));
    }

    private JobStatus createJobStatus(String testTag, int jobId) {
        JobInfo jobInfo = new JobInfo.Builder(jobId,
                new ComponentName(mContext, "TestQuotaJobService"))
                .build();
        return createJobStatus(testTag, createJobInfoBuilder(jobId).build());
    }

    private JobStatus createJobStatus(String testTag, JobInfo jobInfo) {
        return createJobStatus(testTag, SOURCE_PACKAGE, CALLING_UID, jobInfo);
    }

@@ -1333,39 +1338,70 @@ public class QuotaControllerTest {
        mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
                createTimingSession(sElapsedRealtimeClock.millis() - (6 * MINUTE_IN_MILLIS),
                        3 * MINUTE_IN_MILLIS, 5), false);
        final long timeUntilQuotaConsumedMs = 7 * MINUTE_IN_MILLIS;
        JobStatus job = createJobStatus("testGetMaxJobExecutionTimeLocked", 0);
        //noinspection deprecation
        JobStatus jobDefIWF = createJobStatus("testGetMaxJobExecutionTimeLocked",
                createJobInfoBuilder(1)
                        .setImportantWhileForeground(true)
                        .setPriority(JobInfo.PRIORITY_DEFAULT)
                        .build());
        JobStatus jobHigh = createJobStatus("testGetMaxJobExecutionTimeLocked",
                createJobInfoBuilder(2).setPriority(JobInfo.PRIORITY_HIGH).build());
        setStandbyBucket(RARE_INDEX, job);
        setStandbyBucket(RARE_INDEX, jobDefIWF);
        setStandbyBucket(RARE_INDEX, jobHigh);

        setCharging();
        synchronized (mQuotaController.mLock) {
            assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
                    mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
            assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
                    mQuotaController.getMaxJobExecutionTimeMsLocked((jobDefIWF)));
            assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
                    mQuotaController.getMaxJobExecutionTimeMsLocked((jobHigh)));
        }

        setDischarging();
        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
        synchronized (mQuotaController.mLock) {
            assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
            assertEquals(timeUntilQuotaConsumedMs,
                    mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
            assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
                    mQuotaController.getMaxJobExecutionTimeMsLocked((jobDefIWF)));
            assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
                    mQuotaController.getMaxJobExecutionTimeMsLocked((jobHigh)));
        }

        // Top-started job
        setProcessState(ActivityManager.PROCESS_STATE_TOP);
        synchronized (mQuotaController.mLock) {
            mQuotaController.maybeStartTrackingJobLocked(job, null);
            trackJobs(job, jobDefIWF, jobHigh);
            mQuotaController.prepareForExecutionLocked(job);
            mQuotaController.prepareForExecutionLocked(jobDefIWF);
            mQuotaController.prepareForExecutionLocked(jobHigh);
        }
        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
        synchronized (mQuotaController.mLock) {
            assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
            assertEquals(timeUntilQuotaConsumedMs,
                    mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
            assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
                    mQuotaController.getMaxJobExecutionTimeMsLocked((jobDefIWF)));
            assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
                    mQuotaController.getMaxJobExecutionTimeMsLocked((jobHigh)));
            mQuotaController.maybeStopTrackingJobLocked(job, null);
            mQuotaController.maybeStopTrackingJobLocked(jobDefIWF, null);
            mQuotaController.maybeStopTrackingJobLocked(jobHigh, null);
        }

        setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
        synchronized (mQuotaController.mLock) {
            assertEquals(7 * MINUTE_IN_MILLIS,
            assertEquals(timeUntilQuotaConsumedMs,
                    mQuotaController.getMaxJobExecutionTimeMsLocked(job));
            assertEquals(timeUntilQuotaConsumedMs,
                    mQuotaController.getMaxJobExecutionTimeMsLocked(jobDefIWF));
            assertEquals(timeUntilQuotaConsumedMs,
                    mQuotaController.getMaxJobExecutionTimeMsLocked(jobHigh));
        }
    }