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

Commit 12353831 authored by Kweku Adams's avatar Kweku Adams Committed by Android (Google) Code Review
Browse files

Merge "Fix RESTRICTED app handling."

parents d1d95ec6 5951fa21
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -1371,18 +1371,8 @@ public class JobSchedulerService extends com.android.server.SystemService
                    // Effective standby bucket can change after this in some situations so use
                    // the real bucket so that the job is tracked by the controllers.
                    if (js.getStandbyBucket() == RESTRICTED_INDEX) {
                        js.addDynamicConstraint(JobStatus.CONSTRAINT_BATTERY_NOT_LOW);
                        js.addDynamicConstraint(JobStatus.CONSTRAINT_CHARGING);
                        js.addDynamicConstraint(JobStatus.CONSTRAINT_CONNECTIVITY);
                        js.addDynamicConstraint(JobStatus.CONSTRAINT_IDLE);

                        mRestrictiveControllers.get(j).startTrackingRestrictedJobLocked(js);
                    } else {
                        js.removeDynamicConstraint(JobStatus.CONSTRAINT_BATTERY_NOT_LOW);
                        js.removeDynamicConstraint(JobStatus.CONSTRAINT_CHARGING);
                        js.removeDynamicConstraint(JobStatus.CONSTRAINT_CONNECTIVITY);
                        js.removeDynamicConstraint(JobStatus.CONSTRAINT_IDLE);

                        mRestrictiveControllers.get(j).stopTrackingRestrictedJobLocked(js);
                    }
                }
+55 −20
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.server.job.controllers;

import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;

import android.app.AppGlobals;
@@ -63,25 +65,35 @@ import java.util.function.Predicate;
 * @hide
 */
public final class JobStatus {
    static final String TAG = "JobSchedulerService";
    private static final String TAG = "JobScheduler.JobStatus";
    static final boolean DEBUG = JobSchedulerService.DEBUG;

    public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
    public static final long NO_EARLIEST_RUNTIME = 0L;

    public static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING; // 1 < 0
    public static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE;  // 1 << 2
    public static final int CONSTRAINT_BATTERY_NOT_LOW =
            JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW; // 1 << 1
    static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING; // 1 < 0
    static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE;  // 1 << 2
    static final int CONSTRAINT_BATTERY_NOT_LOW = JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW; // 1 << 1
    static final int CONSTRAINT_STORAGE_NOT_LOW = JobInfo.CONSTRAINT_FLAG_STORAGE_NOT_LOW; // 1 << 3
    static final int CONSTRAINT_TIMING_DELAY = 1<<31;
    static final int CONSTRAINT_DEADLINE = 1<<30;
    public static final int CONSTRAINT_CONNECTIVITY = 1 << 28;
    static final int CONSTRAINT_CONNECTIVITY = 1 << 28;
    static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
    static final int CONSTRAINT_DEVICE_NOT_DOZING = 1 << 25; // Implicit constraint
    static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24;      // Implicit constraint
    static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1 << 22; // Implicit constraint

    /**
     * The additional set of dynamic constraints that must be met if the job's effective bucket is
     * {@link JobSchedulerService#RESTRICTED_INDEX}. Connectivity can be ignored if the job doesn't
     * need network.
     */
    private static final int DYNAMIC_RESTRICTED_CONSTRAINTS =
            CONSTRAINT_BATTERY_NOT_LOW
                    | CONSTRAINT_CHARGING
                    | CONSTRAINT_CONNECTIVITY
                    | CONSTRAINT_IDLE;

    /**
     * The constraints that we want to log to statsd.
     *
@@ -419,7 +431,11 @@ public final class JobStatus {
        this.requiredConstraints = requiredConstraints;
        mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST;
        mReadyNotDozing = (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
        if (standbyBucket == RESTRICTED_INDEX) {
            addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS);
        } else {
            mReadyDynamicSatisfied = true;
        }

        mLastSuccessfulRunTime = lastSuccessfulRunTime;
        mLastFailedRunTime = lastFailedRunTime;
@@ -727,6 +743,14 @@ public final class JobStatus {
    }

    public void setStandbyBucket(int newBucket) {
        if (newBucket == RESTRICTED_INDEX) {
            // Adding to the bucket.
            addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS);
        } else if (standbyBucket == RESTRICTED_INDEX) {
            // Removing from the RESTRICTED bucket.
            removeDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS);
        }

        standbyBucket = newBucket;
    }

@@ -1054,6 +1078,11 @@ public final class JobStatus {
        if (old == state) {
            return false;
        }
        if (DEBUG) {
            Slog.v(TAG,
                    "Constraint " + constraint + " is " + (!state ? "NOT " : "") + "satisfied for "
                            + toShortString());
        }
        satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
        mSatisfiedConstraintsOfInterest = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
        mReadyDynamicSatisfied =
@@ -1086,38 +1115,40 @@ public final class JobStatus {
    }

    /**
     * Indicates that this job cannot run without the specified constraint. This is evaluated
     * Indicates that this job cannot run without the specified constraints. This is evaluated
     * separately from the job's explicitly requested constraints and MUST be satisfied before
     * the job can run if the app doesn't have quota.
     *
     */
    public void addDynamicConstraint(int constraint) {
        if (constraint == CONSTRAINT_WITHIN_QUOTA) {
    private void addDynamicConstraints(int constraints) {
        if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
            // Quota should never be used as a dynamic constraint.
            Slog.wtf(TAG, "Tried to set quota as a dynamic constraint");
            return;
            constraints &= ~CONSTRAINT_WITHIN_QUOTA;
        }

        // Connectivity and content trigger are special since they're only valid to add if the
        // job has requested network or specific content URIs. Adding these constraints to jobs
        // that don't need them doesn't make sense.
        if ((constraint == CONSTRAINT_CONNECTIVITY && !hasConnectivityConstraint())
                || (constraint == CONSTRAINT_CONTENT_TRIGGER && !hasContentTriggerConstraint())) {
            return;
        if (!hasConnectivityConstraint()) {
            constraints &= ~CONSTRAINT_CONNECTIVITY;
        }
        if (!hasContentTriggerConstraint()) {
            constraints &= ~CONSTRAINT_CONTENT_TRIGGER;
        }

        mDynamicConstraints |= constraint;
        mDynamicConstraints |= constraints;
        mReadyDynamicSatisfied =
                mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
    }

    /**
     * Removes a dynamic constraint from a job, meaning that the requirement is not required for
     * Removes dynamic constraints from a job, meaning that the requirements are not required for
     * the job to run (if the job itself hasn't requested the constraint. This is separate from
     * the job's explicitly requested constraints and does not remove those requested constraints.
     *
     */
    public void removeDynamicConstraint(int constraint) {
        mDynamicConstraints &= ~constraint;
    private void removeDynamicConstraints(int constraints) {
        mDynamicConstraints &= ~constraints;
        mReadyDynamicSatisfied =
                mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
    }
@@ -1193,7 +1224,11 @@ public final class JobStatus {

    private boolean isReady(int satisfiedConstraints) {
        // Quota and dynamic constraints trump all other constraints.
        if (!mReadyWithinQuota && !mReadyDynamicSatisfied) {
        // NEVER jobs are not supposed to run at all. Since we're using quota to allow parole
        // 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) {
            return false;
        }
        // Deadline constraint trumps other constraints besides quota and dynamic (except for