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

Commit 959acb52 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Allow system jobs to be exempted from app-standby

This flag will allow the sync manager to exempt certain kind of sync requests.

- This will only exempt jobs from app-standby.

- EBS still won't exempt them. Battery saver cuts background network anyway, so
background syncs will still not work, and it didn't used to work pre-P either.

- Manual force-app standby still doesn't allow them to run.

Bug: 72443754
Test: Build and boot. The behavior shouldn't change since none uses the flag yet.
Test: atest CtsJobSchedulerTestCases
Change-Id: I806b97bb4b7da773479e878e6eccb792b03eadc1
parent 83f489b5
Loading
Loading
Loading
Loading
+15 −0
Original line number Original line Diff line number Diff line
@@ -255,6 +255,14 @@ public class JobInfo implements Parcelable {
     */
     */
    public static final int FLAG_IS_PREFETCH = 1 << 2;
    public static final int FLAG_IS_PREFETCH = 1 << 2;


    /**
     * This job needs to be exempted from the app standby throttling. Only the system (UID 1000)
     * can set it. Jobs with a time constrant must not have it.
     *
     * @hide
     */
    public static final int FLAG_EXEMPT_FROM_APP_STANDBY = 1 << 3;

    /**
    /**
     * @hide
     * @hide
     */
     */
@@ -355,6 +363,13 @@ public class JobInfo implements Parcelable {
        return flags;
        return flags;
    }
    }


    /** @hide */
    public boolean isExemptedFromAppStandby() {
        return ((flags & FLAG_EXEMPT_FROM_APP_STANDBY) != 0)
                && !hasEarlyConstraint()
                && !hasLateConstraint();
    }

    /**
    /**
     * Whether this job requires that the device be charging (or be a non-battery-powered
     * Whether this job requires that the device be charging (or be a non-battery-powered
     * device connected to permanent power, such as Android TV devices).
     * device connected to permanent power, such as Android TV devices).
+22 −13
Original line number Original line Diff line number Diff line
@@ -1809,7 +1809,9 @@ public final class JobSchedulerService extends com.android.server.SystemService
        // If the app is in a non-active standby bucket, make sure we've waited
        // If the app is in a non-active standby bucket, make sure we've waited
        // an appropriate amount of time since the last invocation.  During device-
        // an appropriate amount of time since the last invocation.  During device-
        // wide parole, standby bucketing is ignored.
        // wide parole, standby bucketing is ignored.
        if (!mInParole) {
        //
        // But if a job has FLAG_EXEMPT_FROM_APP_STANDBY, don't check it.
        if (!mInParole && !job.getJob().isExemptedFromAppStandby()) {
            final int bucket = job.getStandbyBucket();
            final int bucket = job.getStandbyBucket();
            if (mHeartbeat < mNextBucketHeartbeat[bucket]) {
            if (mHeartbeat < mNextBucketHeartbeat[bucket]) {
                // Only skip this job if it's still waiting for the end of its (initial) nominal
                // Only skip this job if it's still waiting for the end of its (initial) nominal
@@ -2295,6 +2297,22 @@ public final class JobSchedulerService extends com.android.server.SystemService
            return canPersist;
            return canPersist;
        }
        }


        private void validateJobFlags(JobInfo job, int callingUid) {
            if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) {
                getContext().enforceCallingOrSelfPermission(
                        android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG);
            }
            if ((job.getFlags() & JobInfo.FLAG_EXEMPT_FROM_APP_STANDBY) != 0) {
                if (callingUid != Process.SYSTEM_UID) {
                    throw new SecurityException("Job has invalid flags");
                }
                if (job.hasLateConstraint() || job.hasEarlyConstraint()) {
                    Slog.wtf(TAG, "Jobs with time-constraints mustn't have"
                            +" FLAG_EXEMPT_FROM_APP_STANDBY. Job=" + job);
                }
            }
        }

        // IJobScheduler implementation
        // IJobScheduler implementation
        @Override
        @Override
        public int schedule(JobInfo job) throws RemoteException {
        public int schedule(JobInfo job) throws RemoteException {
@@ -2313,10 +2331,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
                }
                }
            }
            }


            if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) {
            validateJobFlags(job, uid);
                getContext().enforceCallingOrSelfPermission(
                        android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG);
            }


            long ident = Binder.clearCallingIdentity();
            long ident = Binder.clearCallingIdentity();
            try {
            try {
@@ -2344,10 +2359,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
                throw new NullPointerException("work is null");
                throw new NullPointerException("work is null");
            }
            }


            if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) {
            validateJobFlags(job, uid);
                getContext().enforceCallingOrSelfPermission(
                        android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG);
            }


            long ident = Binder.clearCallingIdentity();
            long ident = Binder.clearCallingIdentity();
            try {
            try {
@@ -2378,10 +2390,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
                        + " not permitted to schedule jobs for other apps");
                        + " not permitted to schedule jobs for other apps");
            }
            }


            if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) {
            validateJobFlags(job, callerUid);
                getContext().enforceCallingOrSelfPermission(
                        android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG);
            }


            long ident = Binder.clearCallingIdentity();
            long ident = Binder.clearCallingIdentity();
            try {
            try {