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

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

Merge "Prevent prefetch jobs from having deadlines."

parents 3c134b58 85033f33
Loading
Loading
Loading
Loading
+43 −4
Original line number Diff line number Diff line
@@ -29,6 +29,9 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
import android.content.ComponentName;
@@ -63,6 +66,25 @@ import java.util.Objects;
public class JobInfo implements Parcelable {
    private static String TAG = "JobInfo";

    /**
     * Disallow setting a deadline (via {@link Builder#setOverrideDeadline(long)}) for prefetch
     * jobs ({@link Builder#setPrefetch(boolean)}. Prefetch jobs are meant to run close to the next
     * app launch, so there's no good reason to allow them to have deadlines.
     *
     * We don't drop or cancel any previously scheduled prefetch jobs with a deadline.
     * There's no way for an app to keep a perpetually scheduled prefetch job with a deadline.
     * Prefetch jobs with a deadline will run and apps under this restriction won't be able to
     * schedule new prefetch jobs with a deadline. If a job is rescheduled (by providing
     * {@code true} via {@link JobService#jobFinished(JobParameters, boolean)} or
     * {@link JobService#onStopJob(JobParameters)}'s return value),the deadline is dropped.
     * Periodic jobs require all constraints to be met, so there's no issue with their deadlines.
     *
     * @hide
     */
    @ChangeId
    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
    public static final long DISALLOW_DEADLINES_FOR_PREFETCH_JOBS = 194532703L;

    /** @hide */
    @IntDef(prefix = { "NETWORK_TYPE_" }, value = {
            NETWORK_TYPE_NONE,
@@ -1445,7 +1467,9 @@ public class JobInfo implements Parcelable {
        /**
         * Specify that this job should recur with the provided interval, not more than once per
         * period. You have no control over when within this interval this job will be executed,
         * only the guarantee that it will be executed at most once within this interval.
         * only the guarantee that it will be executed at most once within this interval, as long
         * as the constraints are satisfied. If the constraints are not satisfied within this
         * interval, the job will wait until the constraints are satisfied.
         * Setting this function on the builder with {@link #setMinimumLatency(long)} or
         * {@link #setOverrideDeadline(long)} will result in an error.
         * @param intervalMillis Millisecond interval for which this job will repeat.
@@ -1641,6 +1665,9 @@ public class JobInfo implements Parcelable {
         * the specific user of this device. For example, fetching top headlines
         * of interest to the current user.
         * <p>
         * Starting with Android version {@link Build.VERSION_CODES#TIRAMISU}, prefetch jobs are
         * not allowed to have deadlines (set via {@link #setOverrideDeadline(long)}.
         * <p>
         * The system may use this signal to relax the network constraints you
         * originally requested, such as allowing a
         * {@link JobInfo#NETWORK_TYPE_UNMETERED} job to run over a metered
@@ -1675,6 +1702,11 @@ public class JobInfo implements Parcelable {
         * @return The job object to hand to the JobScheduler. This object is immutable.
         */
        public JobInfo build() {
            return build(Compatibility.isChangeEnabled(DISALLOW_DEADLINES_FOR_PREFETCH_JOBS));
        }

        /** @hide */
        public JobInfo build(boolean disallowPrefetchDeadlines) {
            // This check doesn't need to be inside enforceValidity. It's an unnecessary legacy
            // check that would ideally be phased out instead.
            if (mBackoffPolicySet && (mConstraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0) {
@@ -1683,7 +1715,7 @@ public class JobInfo implements Parcelable {
                        " setRequiresDeviceIdle is an error.");
            }
            JobInfo jobInfo = new JobInfo(this);
            jobInfo.enforceValidity();
            jobInfo.enforceValidity(disallowPrefetchDeadlines);
            return jobInfo;
        }

@@ -1701,7 +1733,7 @@ public class JobInfo implements Parcelable {
    /**
     * @hide
     */
    public final void enforceValidity() {
    public final void enforceValidity(boolean disallowPrefetchDeadlines) {
        // Check that network estimates require network type and are reasonable values.
        if ((networkDownloadBytes > 0 || networkUploadBytes > 0 || minimumNetworkChunkBytes > 0)
                && networkRequest == null) {
@@ -1725,9 +1757,10 @@ public class JobInfo implements Parcelable {
            throw new IllegalArgumentException("Minimum chunk size must be positive");
        }

        final boolean hasDeadline = maxExecutionDelayMillis != 0L;
        // Check that a deadline was not set on a periodic job.
        if (isPeriodic) {
            if (maxExecutionDelayMillis != 0L) {
            if (hasDeadline) {
                throw new IllegalArgumentException(
                        "Can't call setOverrideDeadline() on a periodic job.");
            }
@@ -1741,6 +1774,12 @@ public class JobInfo implements Parcelable {
            }
        }

        // Prefetch jobs should not have deadlines
        if (disallowPrefetchDeadlines && hasDeadline && (flags & FLAG_PREFETCH) != 0) {
            throw new IllegalArgumentException(
                    "Can't call setOverrideDeadline() on a prefetch job.");
        }

        if (isPersisted) {
            // We can't serialize network specifiers
            if (networkRequest != null
+4 −1
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.IUidObserver;
import android.app.compat.CompatChanges;
import android.app.job.IJobScheduler;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
@@ -2932,7 +2933,9 @@ public class JobSchedulerService extends com.android.server.SystemService
        }

        private void validateJobFlags(JobInfo job, int callingUid) {
            job.enforceValidity();
            job.enforceValidity(
                    CompatChanges.isChangeEnabled(
                            JobInfo.DISALLOW_DEADLINES_FOR_PREFETCH_JOBS, callingUid));
            if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) {
                getContext().enforceCallingOrSelfPermission(
                        android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG);
+11 −6
Original line number Diff line number Diff line
@@ -49,7 +49,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.BitUtils;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerInternal.JobStorePersistStats;
import com.android.server.job.controllers.JobStatus;

@@ -978,10 +977,17 @@ public final class JobStore {

            final JobInfo builtJob;
            try {
                builtJob = jobBuilder.build();
                // Don't perform prefetch-deadline check here. Apps targeting S- shouldn't have
                // any prefetch-with-deadline jobs accidentally dropped. It's not worth doing
                // target SDK version checks here for apps targeting T+. There's no way for an
                // app to keep a perpetually scheduled prefetch job with a deadline. Prefetch jobs
                // with a deadline would run and then any newly scheduled prefetch jobs wouldn't
                // have a deadline. If a job is rescheduled (via jobFinished(true) or onStopJob()'s
                // return value), the deadline is dropped. Periodic jobs require all constraints
                // to be met, so there's no issue with their deadlines.
                builtJob = jobBuilder.build(false);
            } catch (Exception e) {
                Slog.w(TAG, "Unable to build job from XML, ignoring: "
                        + jobBuilder.summarize());
                Slog.w(TAG, "Unable to build job from XML, ignoring: " + jobBuilder.summarize(), e);
                return null;
            }

@@ -997,11 +1003,10 @@ public final class JobStore {
            }

            // And now we're done
            JobSchedulerInternal service = LocalServices.getService(JobSchedulerInternal.class);
            final int appBucket = JobSchedulerService.standbyBucketForPackage(sourcePackageName,
                    sourceUserId, elapsedNow);
            JobStatus js = new JobStatus(
                    jobBuilder.build(), uid, sourcePackageName, sourceUserId,
                    builtJob, uid, sourcePackageName, sourceUserId,
                    appBucket, sourceTag,
                    elapsedRuntimes.first, elapsedRuntimes.second,
                    lastSuccessfulRunTime, lastFailedRunTime,
+3 −1
Original line number Diff line number Diff line
@@ -555,7 +555,9 @@ public final class JobStatus {
            requestBuilder.setUids(
                    Collections.singleton(new Range<Integer>(this.sourceUid, this.sourceUid)));
            builder.setRequiredNetwork(requestBuilder.build());
            job = builder.build();
            // Don't perform prefetch-deadline check at this point. We've already passed the
            // initial validation check.
            job = builder.build(false);
        }

        final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class);