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

Commit 87a4cd5b authored by Kweku Adams's avatar Kweku Adams
Browse files

Fix JobThrottling tests, take 2.

1. Reset execution quotas between tests so earlier run tests don't
affect later ones.
2. Ensure uidActive overrides even the NEVER bucket. Also log a wtf if
we ever get into this situation.

Bug: 138253466
Bug: 149931359
Test: atest android.jobscheduler.cts.JobThrottlingTest
Change-Id: I1caf92fe8dda3c661ef68ca56c32fcd709e26856
parent 27f83cdb
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -3015,6 +3015,10 @@ public class JobSchedulerService extends com.android.server.SystemService
        return 0;
    }

    void resetExecutionQuota(@NonNull String pkgName, int userId) {
        mQuotaController.clearAppStats(pkgName, userId);
    }

    void resetScheduleQuota() {
        mQuotaTracker.clear();
    }
+36 −0
Original line number Diff line number Diff line
@@ -66,6 +66,8 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler {
                    return getJobState(pw);
                case "heartbeat":
                    return doHeartbeat(pw);
                case "reset-execution-quota":
                    return resetExecutionQuota(pw);
                case "reset-schedule-quota":
                    return resetScheduleQuota(pw);
                case "trigger-dock-state":
@@ -346,6 +348,40 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler {
        return -1;
    }

    private int resetExecutionQuota(PrintWriter pw) throws Exception {
        checkPermission("reset execution quota");

        int userId = UserHandle.USER_SYSTEM;

        String opt;
        while ((opt = getNextOption()) != null) {
            switch (opt) {
                case "-u":
                case "--user":
                    userId = UserHandle.parseUserArg(getNextArgRequired());
                    break;

                default:
                    pw.println("Error: unknown option '" + opt + "'");
                    return -1;
            }
        }

        if (userId == UserHandle.USER_CURRENT) {
            userId = ActivityManager.getCurrentUser();
        }

        final String pkgName = getNextArgRequired();

        final long ident = Binder.clearCallingIdentity();
        try {
            mInternal.resetExecutionQuota(pkgName, userId);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        return 0;
    }

    private int resetScheduleQuota(PrintWriter pw) throws Exception {
        checkPermission("reset schedule quota");

+5 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.job.controllers;

import static com.android.server.job.JobSchedulerService.NEVER_INDEX;

import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
@@ -196,6 +198,9 @@ public final class BackgroundJobsController extends StateController {
        } else {
            isActive = (activeState == KNOWN_ACTIVE);
        }
        if (isActive && jobStatus.getStandbyBucket() == NEVER_INDEX) {
            Slog.wtf(TAG, "App became active but still in NEVER bucket");
        }
        boolean didChange = jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
        didChange |= jobStatus.setUidActive(isActive);
        return didChange;
+2 −1
Original line number Diff line number Diff line
@@ -1271,7 +1271,8 @@ public final class JobStatus {
        // sessions (exempt from dynamic restrictions), we need the additional check to ensure
        // that NEVER jobs don't run.
        // TODO: cleanup quota and standby bucket management so we don't need the additional checks
        if ((!mReadyWithinQuota && !mReadyDynamicSatisfied) || standbyBucket == NEVER_INDEX) {
        if ((!mReadyWithinQuota && !mReadyDynamicSatisfied)
                || getEffectiveStandbyBucket() == NEVER_INDEX) {
            return false;
        }
        // Deadline constraint trumps other constraints besides quota and dynamic (except for
+18 −14
Original line number Diff line number Diff line
@@ -579,12 +579,28 @@ public final class QuotaController extends StateController {
            Slog.wtf(TAG, "Told app removed but given null package name.");
            return;
        }
        final int userId = UserHandle.getUserId(uid);
        clearAppStats(packageName, UserHandle.getUserId(uid));
        mForegroundUids.delete(uid);
        mUidToPackageCache.remove(uid);
    }

    @Override
    public void onUserRemovedLocked(int userId) {
        mTrackedJobs.delete(userId);
        mPkgTimers.delete(userId);
        mTimingSessions.delete(userId);
        mInQuotaAlarmListeners.delete(userId);
        mExecutionStatsCache.delete(userId);
        mUidToPackageCache.clear();
    }

    /** Drop all historical stats and stop tracking any active sessions for the specified app. */
    public void clearAppStats(@NonNull String packageName, int userId) {
        mTrackedJobs.delete(userId, packageName);
        Timer timer = mPkgTimers.get(userId, packageName);
        if (timer != null) {
            if (timer.isActive()) {
                Slog.wtf(TAG, "onAppRemovedLocked called before Timer turned off.");
                Slog.e(TAG, "clearAppStats called before Timer turned off.");
                timer.dropEverythingLocked();
            }
            mPkgTimers.delete(userId, packageName);
@@ -596,18 +612,6 @@ public final class QuotaController extends StateController {
            mInQuotaAlarmListeners.delete(userId, packageName);
        }
        mExecutionStatsCache.delete(userId, packageName);
        mForegroundUids.delete(uid);
        mUidToPackageCache.remove(uid);
    }

    @Override
    public void onUserRemovedLocked(int userId) {
        mTrackedJobs.delete(userId);
        mPkgTimers.delete(userId);
        mTimingSessions.delete(userId);
        mInQuotaAlarmListeners.delete(userId);
        mExecutionStatsCache.delete(userId);
        mUidToPackageCache.clear();
    }

    private boolean isUidInForeground(int uid) {