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

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

Fix expedited job exemptions.

Ensure requested EJs' battery saver, Doze, and network constraints are
updated anytime EJ quota changes.

Bug: 171305774
Test: atest CtsJobSchedulerTestCases
Test: atest FrameworksMockingServicesTests:ConnectivityControllerTest
Test: atest FrameworksMockingServicesTests:JobSchedulerServiceTest
Test: atest FrameworksMockingServicesTests:JobStatusTest
Test: atest FrameworksMockingServicesTests:QuotaControllerTest
Test: atest FrameworksServicesTests:JobStoreTest
Change-Id: I88e6bf8d0395dd65d2233dfe68237d30ba868735
parent 81585a24
Loading
Loading
Loading
Loading
+5 −2
Original line number Original line Diff line number Diff line
@@ -1502,11 +1502,14 @@ public class JobSchedulerService extends com.android.server.SystemService
        mControllers.add(mBatteryController);
        mControllers.add(mBatteryController);
        mStorageController = new StorageController(this);
        mStorageController = new StorageController(this);
        mControllers.add(mStorageController);
        mControllers.add(mStorageController);
        mControllers.add(new BackgroundJobsController(this));
        final BackgroundJobsController backgroundJobsController =
                new BackgroundJobsController(this);
        mControllers.add(backgroundJobsController);
        mControllers.add(new ContentObserverController(this));
        mControllers.add(new ContentObserverController(this));
        mDeviceIdleJobsController = new DeviceIdleJobsController(this);
        mDeviceIdleJobsController = new DeviceIdleJobsController(this);
        mControllers.add(mDeviceIdleJobsController);
        mControllers.add(mDeviceIdleJobsController);
        mQuotaController = new QuotaController(this);
        mQuotaController =
                new QuotaController(this, backgroundJobsController, connectivityController);
        mControllers.add(mQuotaController);
        mControllers.add(mQuotaController);
        mControllers.add(new ComponentController(this));
        mControllers.add(new ComponentController(this));


+5 −0
Original line number Original line Diff line number Diff line
@@ -77,6 +77,11 @@ public final class BackgroundJobsController extends StateController {
            boolean forUpdate) {
            boolean forUpdate) {
    }
    }


    @Override
    public void evaluateStateLocked(JobStatus jobStatus) {
        updateSingleJobRestrictionLocked(jobStatus, UNKNOWN);
    }

    @Override
    @Override
    public void dumpControllerStateLocked(final IndentingPrintWriter pw,
    public void dumpControllerStateLocked(final IndentingPrintWriter pw,
            final Predicate<JobStatus> predicate) {
            final Predicate<JobStatus> predicate) {
+5 −0
Original line number Original line Diff line number Diff line
@@ -1151,6 +1151,11 @@ public final class JobStatus {
        if (setConstraintSatisfied(CONSTRAINT_WITHIN_EXPEDITED_QUOTA, state)) {
        if (setConstraintSatisfied(CONSTRAINT_WITHIN_EXPEDITED_QUOTA, state)) {
            // The constraint was changed. Update the ready flag.
            // The constraint was changed. Update the ready flag.
            mReadyWithinExpeditedQuota = state;
            mReadyWithinExpeditedQuota = state;
            // DeviceIdleJobsController currently only tracks jobs with the WILL_BE_FOREGROUND flag.
            // Making it also track requested-expedited jobs would add unnecessary hops since the
            // controller would then defer to canRunInDoze. Avoid the hops and just update
            // mReadyNotDozing directly.
            mReadyNotDozing = isConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING) || canRunInDoze();
            return true;
            return true;
        }
        }
        return false;
        return false;
+28 −4
Original line number Original line Diff line number Diff line
@@ -347,6 +347,9 @@ public final class QuotaController extends StateController {
    private final QcHandler mHandler;
    private final QcHandler mHandler;
    private final QcConstants mQcConstants;
    private final QcConstants mQcConstants;


    private final BackgroundJobsController mBackgroundJobsController;
    private final ConnectivityController mConnectivityController;

    /** How much time each app will have to run jobs within their standby bucket window. */
    /** How much time each app will have to run jobs within their standby bucket window. */
    private long mAllowedTimePerPeriodMs = QcConstants.DEFAULT_ALLOWED_TIME_PER_PERIOD_MS;
    private long mAllowedTimePerPeriodMs = QcConstants.DEFAULT_ALLOWED_TIME_PER_PERIOD_MS;


@@ -552,7 +555,9 @@ public final class QuotaController extends StateController {
     */
     */
    private static final int MSG_PROCESS_USAGE_EVENT = 5;
    private static final int MSG_PROCESS_USAGE_EVENT = 5;


    public QuotaController(JobSchedulerService service) {
    public QuotaController(@NonNull JobSchedulerService service,
            @NonNull BackgroundJobsController backgroundJobsController,
            @NonNull ConnectivityController connectivityController) {
        super(service);
        super(service);
        mHandler = new QcHandler(mContext.getMainLooper());
        mHandler = new QcHandler(mContext.getMainLooper());
        mChargeTracker = new ChargingTracker();
        mChargeTracker = new ChargingTracker();
@@ -560,6 +565,8 @@ public final class QuotaController extends StateController {
        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
        mQcConstants = new QcConstants();
        mQcConstants = new QcConstants();
        mBackgroundJobsController = backgroundJobsController;
        mConnectivityController = connectivityController;


        final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
        final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
        mContext.registerReceiverAsUser(mPackageAddedReceiver, UserHandle.ALL, filter, null, null);
        mContext.registerReceiverAsUser(mPackageAddedReceiver, UserHandle.ALL, filter, null, null);
@@ -596,7 +603,7 @@ public final class QuotaController extends StateController {
        final boolean outOfEJQuota;
        final boolean outOfEJQuota;
        if (jobStatus.isRequestedExpeditedJob()) {
        if (jobStatus.isRequestedExpeditedJob()) {
            final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus);
            final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus);
            jobStatus.setExpeditedJobQuotaConstraintSatisfied(isWithinEJQuota);
            setExpeditedConstraintSatisfied(jobStatus, isWithinEJQuota);
            outOfEJQuota = !isWithinEJQuota;
            outOfEJQuota = !isWithinEJQuota;
        } else {
        } else {
            outOfEJQuota = false;
            outOfEJQuota = false;
@@ -1473,7 +1480,7 @@ public final class QuotaController extends StateController {


            if (js.isRequestedExpeditedJob()) {
            if (js.isRequestedExpeditedJob()) {
                boolean isWithinEJQuota = isWithinEJQuotaLocked(js);
                boolean isWithinEJQuota = isWithinEJQuotaLocked(js);
                changed |= js.setExpeditedJobQuotaConstraintSatisfied(isWithinEJQuota);
                changed |= setExpeditedConstraintSatisfied(js, isWithinEJQuota);
                outOfEJQuota |= !isWithinEJQuota;
                outOfEJQuota |= !isWithinEJQuota;
            }
            }
        }
        }
@@ -1499,7 +1506,7 @@ public final class QuotaController extends StateController {
            final boolean outOfEJQuota;
            final boolean outOfEJQuota;
            if (jobStatus.isRequestedExpeditedJob()) {
            if (jobStatus.isRequestedExpeditedJob()) {
                final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus);
                final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus);
                wasJobChanged |= jobStatus.setExpeditedJobQuotaConstraintSatisfied(isWithinEJQuota);
                wasJobChanged |= setExpeditedConstraintSatisfied(jobStatus, isWithinEJQuota);
                outOfEJQuota = !isWithinEJQuota;
                outOfEJQuota = !isWithinEJQuota;
            } else {
            } else {
                outOfEJQuota = false;
                outOfEJQuota = false;
@@ -1650,6 +1657,23 @@ public final class QuotaController extends StateController {
        return jobStatus.setQuotaConstraintSatisfied(isWithinQuota);
        return jobStatus.setQuotaConstraintSatisfied(isWithinQuota);
    }
    }


    /**
     * If the satisfaction changes, this will tell connectivity & background jobs controller to
     * also re-evaluate their state.
     */
    private boolean setExpeditedConstraintSatisfied(@NonNull JobStatus jobStatus,
            boolean isWithinQuota) {
        if (jobStatus.setExpeditedJobQuotaConstraintSatisfied(isWithinQuota)) {
            mBackgroundJobsController.evaluateStateLocked(jobStatus);
            mConnectivityController.evaluateStateLocked(jobStatus);
            if (isWithinQuota && jobStatus.isReady()) {
                mStateChangedListener.onRunJobNow(jobStatus);
            }
            return true;
        }
        return false;
    }

    private final class ChargingTracker extends BroadcastReceiver {
    private final class ChargingTracker extends BroadcastReceiver {
        /**
        /**
         * Track whether we're charging. This has a slightly different definition than that of
         * Track whether we're charging. This has a slightly different definition than that of
+2 −1
Original line number Original line Diff line number Diff line
@@ -209,7 +209,8 @@ public class QuotaControllerTest {
                ArgumentCaptor.forClass(BroadcastReceiver.class);
                ArgumentCaptor.forClass(BroadcastReceiver.class);
        ArgumentCaptor<IUidObserver> uidObserverCaptor =
        ArgumentCaptor<IUidObserver> uidObserverCaptor =
                ArgumentCaptor.forClass(IUidObserver.class);
                ArgumentCaptor.forClass(IUidObserver.class);
        mQuotaController = new QuotaController(mJobSchedulerService);
        mQuotaController = new QuotaController(mJobSchedulerService,
                mock(BackgroundJobsController.class), mock(ConnectivityController.class));


        verify(mContext).registerReceiver(receiverCaptor.capture(), any());
        verify(mContext).registerReceiver(receiverCaptor.capture(), any());
        mChargingReceiver = receiverCaptor.getValue();
        mChargingReceiver = receiverCaptor.getValue();