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

Commit 26a3b846 authored by Xin Guan's avatar Xin Guan
Browse files

JobScheduler: Enable quota parameters tuning overrides

Introduce new compatibility override to default quota parameters tuning

The override only takes effective if the quota optimization is enabled

Bug: 378129159
Test: atest FrameworksMockingServicesTests:com.android.server.job
Test: atest CtsJobSchedulerTestCases:android.jobscheduler.cts.JobThrottlingTest
Test: manual test.
Flag: EXEMPT bugfix
Change-Id: I5ce8f111462fd2512c0a37ca08e27d9b13f8ac69
parent 70de18e2
Loading
Loading
Loading
Loading
+109 −43
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.UidObserver;
import android.app.compat.CompatChanges;
import android.app.job.JobInfo;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
@@ -54,6 +53,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.Trace;
import android.os.UserHandle;
import android.provider.DeviceConfig;
@@ -74,6 +74,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.server.AppSchedulingModuleThread;
import com.android.server.LocalServices;
import com.android.server.PowerAllowlistInternal;
import com.android.server.compat.PlatformCompat;
import com.android.server.job.ConstantsProto;
import com.android.server.job.Flags;
import com.android.server.job.JobSchedulerService;
@@ -157,6 +158,15 @@ public final class QuotaController extends StateController {
    @Overridable // The change can be overridden in user build.
    static final long OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS = 374323858L;

    /**
     * When enabled this change id overrides the default quota parameters adjustment.
     */
    @VisibleForTesting
    @ChangeId
    @Disabled // Disabled by default
    @Overridable // The change can be overridden in user build.
    static final long OVERRIDE_QUOTA_ADJUST_DEFAULT_CONSTANTS = 378129159L;

    @VisibleForTesting
    static class ExecutionStats {
        /**
@@ -536,6 +546,8 @@ public final class QuotaController extends StateController {
     */
    private final SparseSetArray<String> mSystemInstallers = new SparseSetArray<>();

    private final PlatformCompat mPlatformCompat;

    /** An app has reached its quota. The message should contain a {@link UserPackage} object. */
    @VisibleForTesting
    static final int MSG_REACHED_TIME_QUOTA = 0;
@@ -587,6 +599,13 @@ public final class QuotaController extends StateController {
        PowerAllowlistInternal pai = LocalServices.getService(PowerAllowlistInternal.class);
        pai.registerTempAllowlistChangeListener(new TempAllowlistTracker());

        mPlatformCompat = (PlatformCompat)
                ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
        if (Flags.adjustQuotaDefaultConstants()) {
            mPlatformCompat.registerListener(OVERRIDE_QUOTA_ADJUST_DEFAULT_CONSTANTS,
                    (packageName) -> handleQuotaDefaultConstantsCompatChange());
        }

        try {
            ActivityManager.getService().registerUidObserver(new QcUidObserver(),
                    ActivityManager.UID_OBSERVER_PROCSTATE,
@@ -651,8 +670,9 @@ public final class QuotaController extends StateController {

        final int uid = jobStatus.getSourceUid();
        if ((!Flags.enforceQuotaPolicyToTopStartedJobs()
                || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
                        uid)) && mTopAppCache.get(uid)) {
                || mPlatformCompat.isChangeEnabledByUid(
                        OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS, uid))
                && mTopAppCache.get(uid)) {
            if (DEBUG) {
                Slog.d(TAG, jobStatus.toShortString() + " is top started job");
            }
@@ -690,8 +710,8 @@ public final class QuotaController extends StateController {
            }
        }
        if (!Flags.enforceQuotaPolicyToTopStartedJobs()
                || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
                        jobStatus.getSourceUid())) {
                || mPlatformCompat.isChangeEnabledByUid(
                        OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS, jobStatus.getSourceUid())) {
            mTopStartedJobs.remove(jobStatus);
        }
    }
@@ -805,8 +825,8 @@ public final class QuotaController extends StateController {
    /** @return true if the job was started while the app was in the TOP state. */
    private boolean isTopStartedJobLocked(@NonNull final JobStatus jobStatus) {
        if (!Flags.enforceQuotaPolicyToTopStartedJobs()
                || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
                        jobStatus.getSourceUid())) {
                || mPlatformCompat.isChangeEnabledByUid(
                        OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS, jobStatus.getSourceUid())) {
            return mTopStartedJobs.contains(jobStatus);
        }

@@ -1102,6 +1122,7 @@ public final class QuotaController extends StateController {
            final int standbyBucket) {
        final long baseLimitMs = mAllowedTimePerPeriodMs[standbyBucket];
        if (Flags.adjustQuotaDefaultConstants()
                && !isCompatOverridedForQuotaConstantAdjustment()
                && Flags.additionalQuotaForSystemInstaller()
                && standbyBucket == EXEMPTED_INDEX
                && mSystemInstallers.contains(userId, pkgName)) {
@@ -1473,10 +1494,21 @@ public final class QuotaController extends StateController {
        }
    }

    void handleQuotaDefaultConstantsCompatChange() {
        synchronized (mLock) {
            final boolean isCompatEnabled = isCompatOverridedForQuotaConstantAdjustment();
            mQcConstants.adjustDefaultBucketWindowSizes(isCompatEnabled);
            mQcConstants.adjustDefaultEjLimits(isCompatEnabled);
            mQcConstants.mShouldReevaluateConstraints = true;
            onConstantsUpdatedLocked();
        }
    }

    void processQuotaConstantsAdjustment() {
        if (Flags.adjustQuotaDefaultConstants()) {
            mQcConstants.adjustDefaultBucketWindowSizes();
            mQcConstants.adjustDefaultEjLimits();
        if (Flags.adjustQuotaDefaultConstants()
                && !isCompatOverridedForQuotaConstantAdjustment()) {
            mQcConstants.adjustDefaultBucketWindowSizes(false);
            mQcConstants.adjustDefaultEjLimits(false);
        }
    }

@@ -1505,6 +1537,11 @@ public final class QuotaController extends StateController {
        }
    }

    private boolean isCompatOverridedForQuotaConstantAdjustment() {
        return mPlatformCompat.isChangeEnabledByPackageName(
                OVERRIDE_QUOTA_ADJUST_DEFAULT_CONSTANTS, "android", UserHandle.USER_SYSTEM);
    }

    private void incrementTimingSessionCountLocked(final int userId,
            @NonNull final String packageName) {
        final long now = sElapsedRealtimeClock.millis();
@@ -2689,7 +2726,8 @@ public final class QuotaController extends StateController {
    @VisibleForTesting
    int getProcessStateQuotaFreeThreshold(int uid) {
        if (Flags.enforceQuotaPolicyToFgsJobs()
                && !CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS, uid)) {
                && !mPlatformCompat.isChangeEnabledByUid(
                        OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS, uid)) {
            return ActivityManager.PROCESS_STATE_BOUND_TOP;
        }

@@ -3596,14 +3634,28 @@ public final class QuotaController extends StateController {
         */
        public long EJ_GRACE_PERIOD_TOP_APP_MS = DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS;

        void adjustDefaultBucketWindowSizes() {
        void adjustDefaultBucketWindowSizes(boolean useLegacyQuotaConstants) {
            if (useLegacyQuotaConstants) {
                ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS =
                        DEFAULT_LEGACY_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS;
                ALLOWED_TIME_PER_PERIOD_ACTIVE_MS =
                        DEFAULT_LEGACY_ALLOWED_TIME_PER_PERIOD_ACTIVE_MS;
                ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS =
                        DEFAULT_ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS;

                WINDOW_SIZE_EXEMPTED_MS = DEFAULT_LEGACY_WINDOW_SIZE_EXEMPTED_MS;
                WINDOW_SIZE_ACTIVE_MS = DEFAULT_LEGACY_WINDOW_SIZE_ACTIVE_MS;
                WINDOW_SIZE_WORKING_MS = DEFAULT_LEGACY_WINDOW_SIZE_WORKING_MS;
                WINDOW_SIZE_FREQUENT_MS = DEFAULT_LEGACY_WINDOW_SIZE_FREQUENT_MS;
            } else {
                ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS = Flags.tuneQuotaWindowDefaultParameters()
                        ? DEFAULT_CURRENT_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS :
                        DEFAULT_LEGACY_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS;
                ALLOWED_TIME_PER_PERIOD_ACTIVE_MS = Flags.tuneQuotaWindowDefaultParameters()
                        ? DEFAULT_CURRENT_ALLOWED_TIME_PER_PERIOD_ACTIVE_MS :
                        DEFAULT_LEGACY_ALLOWED_TIME_PER_PERIOD_ACTIVE_MS;
            ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS = Flags.tuneQuotaWindowDefaultParameters()
                ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS =
                        Flags.tuneQuotaWindowDefaultParameters()
                                ? DEFAULT_CURRENT_ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS :
                                DEFAULT_ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS;

@@ -3615,6 +3667,7 @@ public final class QuotaController extends StateController {
                        DEFAULT_CURRENT_WINDOW_SIZE_ACTIVE_MS;
                WINDOW_SIZE_WORKING_MS = DEFAULT_CURRENT_WINDOW_SIZE_WORKING_MS;
                WINDOW_SIZE_FREQUENT_MS = DEFAULT_CURRENT_WINDOW_SIZE_FREQUENT_MS;
            }

            mAllowedTimePerPeriodMs[EXEMPTED_INDEX] = Math.min(MAX_PERIOD_MS,
                    Math.max(MINUTE_IN_MILLIS, ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS));
@@ -3640,10 +3693,15 @@ public final class QuotaController extends StateController {
                            ALLOWED_TIME_PER_PERIOD_ADDITION_INSTALLER_MS);
        }

        void adjustDefaultEjLimits() {
            EJ_LIMIT_WORKING_MS = DEFAULT_CURRENT_EJ_LIMIT_WORKING_MS;
            EJ_TOP_APP_TIME_CHUNK_SIZE_MS = DEFAULT_CURRENT_EJ_TOP_APP_TIME_CHUNK_SIZE_MS;
            EJ_REWARD_INTERACTION_MS = DEFAULT_CURRENT_EJ_REWARD_INTERACTION_MS;
        void adjustDefaultEjLimits(boolean useLegacyQuotaConstants) {
            EJ_LIMIT_WORKING_MS = useLegacyQuotaConstants ? DEFAULT_LEGACY_EJ_LIMIT_WORKING_MS
                    : DEFAULT_CURRENT_EJ_LIMIT_WORKING_MS;
            EJ_TOP_APP_TIME_CHUNK_SIZE_MS = useLegacyQuotaConstants
                    ? DEFAULT_LEGACY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS :
                    DEFAULT_CURRENT_EJ_TOP_APP_TIME_CHUNK_SIZE_MS;
            EJ_REWARD_INTERACTION_MS = useLegacyQuotaConstants
                    ? DEFAULT_LEGACY_EJ_REWARD_INTERACTION_MS
                    : DEFAULT_CURRENT_EJ_REWARD_INTERACTION_MS;

            // The limit must be in the range [15 minutes, active limit].
            mEJLimitsMs[WORKING_INDEX] = Math.max(15 * MINUTE_IN_MILLIS,
@@ -3668,6 +3726,8 @@ public final class QuotaController extends StateController {

        public void processConstantLocked(@NonNull DeviceConfig.Properties properties,
                @NonNull String key) {
            final boolean isCompatEnabled = isCompatOverridedForQuotaConstantAdjustment();

            switch (key) {
                case KEY_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS:
                case KEY_ALLOWED_TIME_PER_PERIOD_ACTIVE_MS:
@@ -3835,7 +3895,8 @@ public final class QuotaController extends StateController {
                case KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS:
                    // We don't need to re-evaluate execution stats or constraint status for this.
                    EJ_TOP_APP_TIME_CHUNK_SIZE_MS =
                            properties.getLong(key, Flags.adjustQuotaDefaultConstants()
                            properties.getLong(key,
                                    Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
                                    ? DEFAULT_CURRENT_EJ_TOP_APP_TIME_CHUNK_SIZE_MS :
                                    DEFAULT_LEGACY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS);
                    // Limit chunking to be in the range [1 millisecond, 15 minutes] per event.
@@ -3873,7 +3934,8 @@ public final class QuotaController extends StateController {
                case KEY_EJ_REWARD_INTERACTION_MS:
                    // We don't need to re-evaluate execution stats or constraint status for this.
                    EJ_REWARD_INTERACTION_MS =
                            properties.getLong(key, Flags.adjustQuotaDefaultConstants()
                            properties.getLong(key,
                                    Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
                                    ? DEFAULT_CURRENT_EJ_REWARD_INTERACTION_MS :
                                    DEFAULT_LEGACY_EJ_REWARD_INTERACTION_MS);
                    // Limit interaction reward to be in the range [5 seconds, 15 minutes] per
@@ -3914,6 +3976,8 @@ public final class QuotaController extends StateController {
            }
            mExecutionPeriodConstantsUpdated = true;

            final boolean isCompatEnabled = isCompatOverridedForQuotaConstantAdjustment();

            // Query the values as an atomic set.
            final DeviceConfig.Properties properties = DeviceConfig.getProperties(
                    DeviceConfig.NAMESPACE_JOB_SCHEDULER,
@@ -3958,27 +4022,27 @@ public final class QuotaController extends StateController {
            MAX_EXECUTION_TIME_MS = properties.getLong(KEY_MAX_EXECUTION_TIME_MS,
                    DEFAULT_MAX_EXECUTION_TIME_MS);
            WINDOW_SIZE_EXEMPTED_MS = properties.getLong(KEY_WINDOW_SIZE_EXEMPTED_MS,
                    (Flags.adjustQuotaDefaultConstants()
                    (Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
                            && Flags.tuneQuotaWindowDefaultParameters())
                            ? DEFAULT_LATEST_WINDOW_SIZE_EXEMPTED_MS :
                            (Flags.adjustQuotaDefaultConstants()
                            (Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
                                    ? DEFAULT_CURRENT_WINDOW_SIZE_EXEMPTED_MS :
                                    DEFAULT_LEGACY_WINDOW_SIZE_EXEMPTED_MS));
            WINDOW_SIZE_ACTIVE_MS = properties.getLong(KEY_WINDOW_SIZE_ACTIVE_MS,
                    (Flags.adjustQuotaDefaultConstants()
                    (Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
                            && Flags.tuneQuotaWindowDefaultParameters())
                            ? DEFAULT_LATEST_WINDOW_SIZE_ACTIVE_MS :
                            (Flags.adjustQuotaDefaultConstants()
                            (Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
                                    ? DEFAULT_CURRENT_WINDOW_SIZE_ACTIVE_MS :
                                    DEFAULT_LEGACY_WINDOW_SIZE_ACTIVE_MS));
            WINDOW_SIZE_WORKING_MS =
                    properties.getLong(KEY_WINDOW_SIZE_WORKING_MS,
                            Flags.adjustQuotaDefaultConstants()
                            Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
                                    ? DEFAULT_CURRENT_WINDOW_SIZE_WORKING_MS :
                                    DEFAULT_LEGACY_WINDOW_SIZE_WORKING_MS);
            WINDOW_SIZE_FREQUENT_MS =
                    properties.getLong(KEY_WINDOW_SIZE_FREQUENT_MS,
                            Flags.adjustQuotaDefaultConstants()
                            Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
                                    ? DEFAULT_CURRENT_WINDOW_SIZE_FREQUENT_MS :
                                    DEFAULT_LEGACY_WINDOW_SIZE_FREQUENT_MS);
            WINDOW_SIZE_RARE_MS = properties.getLong(KEY_WINDOW_SIZE_RARE_MS,
@@ -4149,6 +4213,8 @@ public final class QuotaController extends StateController {
            }
            mEJLimitConstantsUpdated = true;

            final boolean isCompatEnabled = isCompatOverridedForQuotaConstantAdjustment();

            // Query the values as an atomic set.
            final DeviceConfig.Properties properties = DeviceConfig.getProperties(
                    DeviceConfig.NAMESPACE_JOB_SCHEDULER,
@@ -4163,7 +4229,7 @@ public final class QuotaController extends StateController {
            EJ_LIMIT_ACTIVE_MS = properties.getLong(
                    KEY_EJ_LIMIT_ACTIVE_MS, DEFAULT_EJ_LIMIT_ACTIVE_MS);
            EJ_LIMIT_WORKING_MS = properties.getLong(
                    KEY_EJ_LIMIT_WORKING_MS, Flags.adjustQuotaDefaultConstants()
                    KEY_EJ_LIMIT_WORKING_MS, Flags.adjustQuotaDefaultConstants() && !isCompatEnabled
                            ? DEFAULT_CURRENT_EJ_LIMIT_WORKING_MS :
                            DEFAULT_LEGACY_EJ_LIMIT_WORKING_MS);
            EJ_LIMIT_FREQUENT_MS = properties.getLong(
+18 −11
Original line number Diff line number Diff line
@@ -56,12 +56,12 @@ import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.UiModeManager;
import android.app.compat.CompatChanges;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobWorkItem;
import android.app.usage.UsageStatsManagerInternal;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -81,6 +81,7 @@ import android.os.BatteryManagerInternal.ChargingPolicyChangeListener;
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
@@ -98,6 +99,7 @@ import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.PowerAllowlistInternal;
import com.android.server.SystemServiceManager;
import com.android.server.compat.PlatformCompat;
import com.android.server.job.controllers.ConnectivityController;
import com.android.server.job.controllers.JobStatus;
import com.android.server.job.controllers.QuotaController;
@@ -106,14 +108,10 @@ import com.android.server.job.restrictions.ThermalStatusRestriction;
import com.android.server.pm.UserManagerInternal;
import com.android.server.usage.AppStandbyInternal;

import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
@@ -147,9 +145,6 @@ public class JobSchedulerServiceTest {
    @Rule
    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();

    @Rule
    public TestRule compatChangeRule = new PlatformCompatChangeRule();

    private ChargingPolicyChangeListener mChargingPolicyChangeListener;

    private int mSourceUid;
@@ -166,8 +161,10 @@ public class JobSchedulerServiceTest {
        mMockingSession = mockitoSession()
                .initMocks(this)
                .strictness(Strictness.LENIENT)
                .mockStatic(CompatChanges.class)
                .mockStatic(LocalServices.class)
                .mockStatic(PermissionChecker.class)
                .mockStatic(ServiceManager.class)
                .startMocking();

        // Called in JobSchedulerService constructor.
@@ -230,6 +227,9 @@ public class JobSchedulerServiceTest {
        ArgumentCaptor<ChargingPolicyChangeListener> chargingPolicyChangeListenerCaptor =
                ArgumentCaptor.forClass(ChargingPolicyChangeListener.class);

        doReturn(mock(PlatformCompat.class))
                .when(() -> ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));

        mService = new TestJobSchedulerService(mContext);
        mService.waitOnAsyncLoadingForTesting();

@@ -1074,12 +1074,15 @@ public class JobSchedulerServiceTest {
     */
    @Test
    @EnableFlags(FLAG_HANDLE_ABANDONED_JOBS)
    @DisableCompatChanges({JobParameters.OVERRIDE_HANDLE_ABANDONED_JOBS})
    public void testGetRescheduleJobForFailure_abandonedJob() {
        final long nowElapsed = sElapsedRealtimeClock.millis();
        final long initialBackoffMs = MINUTE_IN_MILLIS;
        mService.mConstants.SYSTEM_STOP_TO_FAILURE_RATIO = 3;

        // Mock the OVERRIDE_HANDLE_ABANDONED_JOBS compat change overrides.
        when(CompatChanges.isChangeEnabled(
                eq(JobParameters.OVERRIDE_HANDLE_ABANDONED_JOBS), anyInt())).thenReturn(false);

        JobStatus originalJob = createJobStatus("testGetRescheduleJobForFailure",
                createJobInfo()
                        .setBackoffCriteria(initialBackoffMs, JobInfo.BACKOFF_POLICY_LINEAR));
@@ -1148,8 +1151,10 @@ public class JobSchedulerServiceTest {
     */
    @Test
    @EnableFlags(FLAG_HANDLE_ABANDONED_JOBS)
    @DisableCompatChanges({JobParameters.OVERRIDE_HANDLE_ABANDONED_JOBS})
    public void testGetRescheduleJobForFailure_EnableFlagDisableCompatCheckAggressiveBackoff() {
        // Mock the OVERRIDE_HANDLE_ABANDONED_JOBS compat change overrides.
        when(CompatChanges.isChangeEnabled(
                eq(JobParameters.OVERRIDE_HANDLE_ABANDONED_JOBS), anyInt())).thenReturn(false);
        assertFalse(mService.shouldUseAggressiveBackoff(
                        mService.mConstants.ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF - 1,
                        mSourceUid));
@@ -1167,8 +1172,10 @@ public class JobSchedulerServiceTest {
     */
    @Test
    @EnableFlags(FLAG_HANDLE_ABANDONED_JOBS)
    @EnableCompatChanges({JobParameters.OVERRIDE_HANDLE_ABANDONED_JOBS})
    public void testGetRescheduleJobForFailure_EnableFlagEnableCompatCheckAggressiveBackoff() {
        // Mock the OVERRIDE_HANDLE_ABANDONED_JOBS compat change overrides.
        when(CompatChanges.isChangeEnabled(
                eq(JobParameters.OVERRIDE_HANDLE_ABANDONED_JOBS), anyInt())).thenReturn(true);
        assertFalse(mService.shouldUseAggressiveBackoff(
                        mService.mConstants.ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF - 1,
                        mSourceUid));
+14 −4
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ import android.os.BatteryManagerInternal;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
@@ -93,6 +94,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.PowerAllowlistInternal;
import com.android.server.compat.PlatformCompat;
import com.android.server.job.Flags;
import com.android.server.job.JobSchedulerInternal;
import com.android.server.job.JobSchedulerService;
@@ -104,8 +106,6 @@ import com.android.server.job.controllers.QuotaController.TimedEvent;
import com.android.server.job.controllers.QuotaController.TimingSession;
import com.android.server.usage.AppStandbyInternal;

import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -168,6 +168,8 @@ public class QuotaControllerTest {
    private PowerAllowlistInternal mPowerAllowlistInternal;
    @Mock
    private UsageStatsManagerInternal mUsageStatsManager;
    @Mock
    private PlatformCompat mPlatformCompat;

    @Rule
    public final CheckFlagsRule mCheckFlagsRule =
@@ -182,6 +184,7 @@ public class QuotaControllerTest {
                .strictness(Strictness.LENIENT)
                .spyStatic(DeviceConfig.class)
                .mockStatic(LocalServices.class)
                .mockStatic(ServiceManager.class)
                .startMocking();

        // Called in StateController constructor.
@@ -198,6 +201,7 @@ public class QuotaControllerTest {
        }
        when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
        when(mContext.getSystemService(AlarmManager.class)).thenReturn(mAlarmManager);

        doReturn(mActivityMangerInternal)
                .when(() -> LocalServices.getService(ActivityManagerInternal.class));
        doReturn(mock(AppStandbyInternal.class))
@@ -253,6 +257,8 @@ public class QuotaControllerTest {
                ArgumentCaptor.forClass(PowerAllowlistInternal.TempAllowlistChangeListener.class);
        ArgumentCaptor<UsageStatsManagerInternal.UsageEventListener> ueListenerCaptor =
                ArgumentCaptor.forClass(UsageStatsManagerInternal.UsageEventListener.class);
        doReturn(mPlatformCompat)
                .when(() -> ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
        mQuotaController = new QuotaController(mJobSchedulerService,
                mock(BackgroundJobsController.class), mock(ConnectivityController.class));

@@ -5591,13 +5597,17 @@ public class QuotaControllerTest {
    }

    @Test
    @EnableCompatChanges({QuotaController.OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
            QuotaController.OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS})
    @RequiresFlagsEnabled({Flags.FLAG_ENFORCE_QUOTA_POLICY_TO_TOP_STARTED_JOBS,
            Flags.FLAG_ENFORCE_QUOTA_POLICY_TO_FGS_JOBS})
    public void testTracking_OutOfQuota_ForegroundAndBackground_CompactChangeOverrides() {
        setDischarging();

        // Mock the OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS compat change overrides.
        doReturn(true).when(mPlatformCompat).isChangeEnabledByUid(
                eq(QuotaController.OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS), anyInt());
        doReturn(true).when(mPlatformCompat).isChangeEnabledByUid(
                eq(QuotaController.OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS), anyInt());

        JobStatus jobBg = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 1);
        JobStatus jobTop = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 2);
        trackJobs(jobBg, jobTop);