Loading apex/jobscheduler/framework/java/android/app/job/JobInfo.java +202 −9 Original line number Diff line number Diff line Loading @@ -85,6 +85,17 @@ public class JobInfo implements Parcelable { @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) public static final long DISALLOW_DEADLINES_FOR_PREFETCH_JOBS = 194532703L; /** * Whether to throw an exception when an app provides an invalid priority value via * {@link Builder#setPriority(int)}. Legacy apps may be incorrectly using the API and * so the call will silently fail for them if they continue using the API. * * @hide */ @ChangeId @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) public static final long THROW_ON_INVALID_PRIORITY_VALUE = 140852299L; /** @hide */ @IntDef(prefix = { "NETWORK_TYPE_" }, value = { NETWORK_TYPE_NONE, Loading Loading @@ -206,6 +217,67 @@ public class JobInfo implements Parcelable { */ public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL; /** * Job has minimal value to the user. The user has absolutely no expectation * or knowledge of this task and it has no bearing on the user's perception of * the app whatsoever. JobScheduler <i>may</i> decide to defer these tasks while * there are higher priority tasks in order to ensure there is sufficient quota * available for the higher priority tasks. * A sample task of min priority: uploading analytics */ public static final int PRIORITY_MIN = 100; /** * Low priority. The task provides some benefit to users, but is not critical * and is more of a nice-to-have. This is more important than minimum priority * jobs and will be prioritized ahead of them, but may still be deferred in lieu * of higher priority jobs. JobScheduler <i>may</i> decide to defer these tasks * while there are higher priority tasks in order to ensure there is sufficient * quota available for the higher priority tasks. * A sample task of low priority: prefetching data the user hasn't requested */ public static final int PRIORITY_LOW = 200; /** * Default value for all regular jobs. As noted in {@link JobScheduler}, * these jobs have a general maximum execution time of 10 minutes. * Receives the standard job management policy. */ public static final int PRIORITY_DEFAULT = 300; /** * This task should be ordered ahead of most other tasks. It may be * deferred a little, but if it doesn't run at some point, the user may think * something is wrong. Assuming all constraints remain satisfied * (including ideal system load conditions), these jobs will have a maximum * execution time of at least 4 minutes. Setting all of your jobs to high * priority will not be beneficial to your app and in fact may hurt its * performance in the long run. */ public static final int PRIORITY_HIGH = 400; /** * This task should be run ahead of all other tasks. Only Expedited Jobs * {@link Builder#setExpedited(boolean)} can have this priority and as such, * are subject to the same maximum execution time details noted in * {@link Builder#setExpedited(boolean)}. * A sample task of max priority: receiving a text message and processing it to * show a notification */ public static final int PRIORITY_MAX = 500; /** @hide */ @IntDef(prefix = {"PRIORITY_"}, value = { PRIORITY_MIN, PRIORITY_LOW, PRIORITY_DEFAULT, PRIORITY_HIGH, PRIORITY_MAX, }) @Retention(RetentionPolicy.SOURCE) public @interface Priority { } /** * Default of {@link #getBias}. * @hide Loading Loading @@ -359,6 +431,8 @@ public class JobInfo implements Parcelable { private final long initialBackoffMillis; private final int backoffPolicy; private final int mBias; @Priority private final int mPriority; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final int flags; Loading Loading @@ -410,6 +484,14 @@ public class JobInfo implements Parcelable { return mBias; } /** * @see JobInfo.Builder#setPriority(int) */ @Priority public int getPriority() { return mPriority; } /** @hide */ public int getFlags() { return flags; Loading Loading @@ -746,6 +828,9 @@ public class JobInfo implements Parcelable { if (mBias != j.mBias) { return false; } if (mPriority != j.mPriority) { return false; } if (flags != j.flags) { return false; } Loading Loading @@ -791,6 +876,7 @@ public class JobInfo implements Parcelable { hashCode = 31 * hashCode + Long.hashCode(initialBackoffMillis); hashCode = 31 * hashCode + backoffPolicy; hashCode = 31 * hashCode + mBias; hashCode = 31 * hashCode + mPriority; hashCode = 31 * hashCode + flags; return hashCode; } Loading Loading @@ -830,6 +916,7 @@ public class JobInfo implements Parcelable { hasEarlyConstraint = in.readInt() == 1; hasLateConstraint = in.readInt() == 1; mBias = in.readInt(); mPriority = in.readInt(); flags = in.readInt(); } Loading Loading @@ -861,6 +948,7 @@ public class JobInfo implements Parcelable { hasEarlyConstraint = b.mHasEarlyConstraint; hasLateConstraint = b.mHasLateConstraint; mBias = b.mBias; mPriority = b.mPriority; flags = b.mFlags; } Loading Loading @@ -906,6 +994,7 @@ public class JobInfo implements Parcelable { out.writeInt(hasEarlyConstraint ? 1 : 0); out.writeInt(hasLateConstraint ? 1 : 0); out.writeInt(mBias); out.writeInt(mPriority); out.writeInt(this.flags); } Loading Loading @@ -1024,6 +1113,8 @@ public class JobInfo implements Parcelable { private ClipData mClipData; private int mClipGrantFlags; private int mBias = BIAS_DEFAULT; @Priority private int mPriority = PRIORITY_DEFAULT; private int mFlags; // Requirements. private int mConstraintFlags; Loading Loading @@ -1100,6 +1191,7 @@ public class JobInfo implements Parcelable { // mBackoffPolicySet isn't set but it's fine since this is copying from an already valid // job. mBackoffPolicy = job.getBackoffPolicy(); mPriority = job.getPriority(); } /** @hide */ Loading @@ -1109,11 +1201,36 @@ public class JobInfo implements Parcelable { return this; } /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public Builder setPriority(int priority) { // No-op for invalid calls. This wasn't a supported API before Tiramisu, so anyone // calling this that isn't targeting T isn't guaranteed a behavior change. /** * Indicate the priority for this job. The priority set here will be used to sort jobs * for a single app and apply slightly different policies based on the priority. * The priority will <b>NOT</b> be used as a global sorting value to sort between * different app's jobs. Use this to inform the system about which jobs it should try * to run before other jobs. Giving the same priority to all of your jobs will result * in them all being treated the same. The priorities each have slightly different * behaviors, as noted in their relevant javadoc. * * <b>NOTE:</b> Setting all of your jobs to high priority will not be * beneficial to your app and in fact may hurt its performance in the * long run. * * In order to prevent starvation, repeatedly retried jobs (because of failures) will slowly * have their priorities lowered. * * @see JobInfo#getPriority() */ @NonNull public Builder setPriority(@Priority int priority) { if (priority > PRIORITY_MAX || priority < PRIORITY_MIN) { if (Compatibility.isChangeEnabled(THROW_ON_INVALID_PRIORITY_VALUE)) { throw new IllegalArgumentException("Invalid priority value"); } // No-op for invalid calls of apps that are targeting S-. This was an unsupported // API before Tiramisu, so anyone calling this that isn't targeting T isn't // guaranteed a behavior change. return this; } mPriority = priority; return this; } Loading Loading @@ -1637,7 +1754,17 @@ public class JobInfo implements Parcelable { public Builder setExpedited(boolean expedited) { if (expedited) { mFlags |= FLAG_EXPEDITED; if (mPriority == PRIORITY_DEFAULT) { // The default priority for EJs is MAX, but only change this if .setPriority() // hasn't been called yet. mPriority = PRIORITY_MAX; } } else { if (mPriority == PRIORITY_MAX && (mFlags & FLAG_EXPEDITED) != 0) { // Reset the priority for the job, but only change this if .setPriority() // hasn't been called yet. mPriority = PRIORITY_DEFAULT; } mFlags &= (~FLAG_EXPEDITED); } return this; Loading @@ -1664,7 +1791,18 @@ public class JobInfo implements Parcelable { public Builder setImportantWhileForeground(boolean importantWhileForeground) { if (importantWhileForeground) { mFlags |= FLAG_IMPORTANT_WHILE_FOREGROUND; if (mPriority == PRIORITY_DEFAULT) { // The default priority for important-while-foreground is HIGH, but only change // this if .setPriority() hasn't been called yet. mPriority = PRIORITY_HIGH; } } else { if (mPriority == PRIORITY_HIGH && (mFlags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0) { // Reset the priority for the job, but only change this if .setPriority() // hasn't been called yet. mPriority = PRIORITY_DEFAULT; } mFlags &= (~FLAG_IMPORTANT_WHILE_FOREGROUND); } return this; Loading Loading @@ -1812,12 +1950,42 @@ public class JobInfo implements Parcelable { } } if ((flags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0 && hasEarlyConstraint) { if ((flags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0) { if (hasEarlyConstraint) { throw new IllegalArgumentException( "An important while foreground job cannot have a time delay"); } if (mPriority != PRIORITY_HIGH && mPriority != PRIORITY_DEFAULT) { throw new IllegalArgumentException( "An important while foreground job must be high or default priority." + " Don't mark unimportant tasks as important while foreground."); } } final boolean isExpedited = (flags & FLAG_EXPEDITED) != 0; switch (mPriority) { case PRIORITY_MAX: if (!isExpedited) { throw new IllegalArgumentException("Only expedited jobs can have max priority"); } break; case PRIORITY_HIGH: if ((flags & FLAG_PREFETCH) != 0) { throw new IllegalArgumentException("Prefetch jobs cannot be high priority"); } if (isPeriodic) { throw new IllegalArgumentException("Periodic jobs cannot be high priority"); } break; case PRIORITY_DEFAULT: case PRIORITY_LOW: case PRIORITY_MIN: break; default: throw new IllegalArgumentException("Invalid priority level provided: " + mPriority); } if ((flags & FLAG_EXPEDITED) != 0) { if (isExpedited) { if (hasEarlyConstraint) { throw new IllegalArgumentException("An expedited job cannot have a time delay"); } Loading @@ -1827,6 +1995,11 @@ public class JobInfo implements Parcelable { if (isPeriodic) { throw new IllegalArgumentException("An expedited job cannot be periodic"); } if (mPriority != PRIORITY_MAX && mPriority != PRIORITY_HIGH) { throw new IllegalArgumentException( "An expedited job must be high or max priority. Don't use expedited jobs" + " for unimportant tasks."); } if ((constraintFlags & ~CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0 || (flags & ~(FLAG_EXPEDITED | FLAG_EXEMPT_FROM_APP_STANDBY)) != 0) { throw new IllegalArgumentException( Loading Loading @@ -1863,4 +2036,24 @@ public class JobInfo implements Parcelable { } return bias + " [UNKNOWN]"; } /** * Convert a priority integer into a human readable string for debugging. * @hide */ public static String getPriorityString(@Priority int priority) { switch (priority) { case PRIORITY_MIN: return priority + " [MIN]"; case PRIORITY_LOW: return priority + " [LOW]"; case PRIORITY_DEFAULT: return priority + " [DEFAULT]"; case PRIORITY_HIGH: return priority + " [HIGH]"; case PRIORITY_MAX: return priority + " [MAX]"; } return priority + " [UNKNOWN]"; } } apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +148 −36 File changed.Preview size limit exceeded, changes collapsed. Show changes apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +30 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.job; import static android.app.job.JobInfo.getPriorityString; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; Loading Loading @@ -378,19 +380,41 @@ public final class JobServiceContext implements ServiceConnection { @EconomicPolicy.AppAction private static int getStartActionId(@NonNull JobStatus job) { if (job.startedAsExpeditedJob || job.shouldTreatAsExpeditedJob()) { switch (job.getEffectivePriority()) { case JobInfo.PRIORITY_MAX: return JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START; } case JobInfo.PRIORITY_HIGH: return JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START; case JobInfo.PRIORITY_LOW: return JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START; case JobInfo.PRIORITY_MIN: return JobSchedulerEconomicPolicy.ACTION_JOB_MIN_START; default: Slog.wtf(TAG, "Unknown priority: " + getPriorityString(job.getEffectivePriority())); // Intentional fallthrough case JobInfo.PRIORITY_DEFAULT: return JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START; } } @EconomicPolicy.AppAction private static int getRunningActionId(@NonNull JobStatus job) { if (job.startedAsExpeditedJob || job.shouldTreatAsExpeditedJob()) { switch (job.getEffectivePriority()) { case JobInfo.PRIORITY_MAX: return JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING; } case JobInfo.PRIORITY_HIGH: return JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING; case JobInfo.PRIORITY_LOW: return JobSchedulerEconomicPolicy.ACTION_JOB_LOW_RUNNING; case JobInfo.PRIORITY_MIN: return JobSchedulerEconomicPolicy.ACTION_JOB_MIN_RUNNING; default: Slog.wtf(TAG, "Unknown priority: " + getPriorityString(job.getEffectivePriority())); // Intentional fallthrough case JobInfo.PRIORITY_DEFAULT: return JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING; } } /** * Used externally to query the running job. Will return null if there is no job running. Loading apex/jobscheduler/service/java/com/android/server/job/JobStore.java +22 −11 Original line number Diff line number Diff line Loading @@ -335,7 +335,7 @@ public final class JobStore { } /** Version of the db schema. */ private static final int JOBS_FILE_VERSION = 0; private static final int JOBS_FILE_VERSION = 1; /** Tag corresponds to constraints this job needs. */ private static final String XML_TAG_PARAMS_CONSTRAINTS = "constraints"; /** Tag corresponds to execution parameters. */ Loading Loading @@ -548,6 +548,7 @@ public final class JobStore { out.attribute(null, "sourceUserId", String.valueOf(jobStatus.getSourceUserId())); out.attribute(null, "uid", Integer.toString(jobStatus.getUid())); out.attribute(null, "bias", String.valueOf(jobStatus.getBias())); out.attribute(null, "priority", String.valueOf(jobStatus.getEffectivePriority())); out.attribute(null, "flags", String.valueOf(jobStatus.getFlags())); if (jobStatus.getInternalFlags() != 0) { out.attribute(null, "internalFlags", String.valueOf(jobStatus.getInternalFlags())); Loading Loading @@ -771,10 +772,11 @@ public final class JobStore { String tagName = parser.getName(); if ("job-info".equals(tagName)) { final List<JobStatus> jobs = new ArrayList<JobStatus>(); final int version; // Read in version info. try { int version = Integer.parseInt(parser.getAttributeValue(null, "version")); if (version != JOBS_FILE_VERSION) { version = Integer.parseInt(parser.getAttributeValue(null, "version")); if (version > JOBS_FILE_VERSION || version < 0) { Slog.d(TAG, "Invalid version number, aborting jobs file read."); return null; } Loading @@ -789,7 +791,7 @@ public final class JobStore { tagName = parser.getName(); // Start reading job. if ("job".equals(tagName)) { JobStatus persistedJob = restoreJobFromXml(rtcIsGood, parser); JobStatus persistedJob = restoreJobFromXml(rtcIsGood, parser, version); if (persistedJob != null) { if (DEBUG) { Slog.d(TAG, "Read out " + persistedJob); Loading @@ -812,8 +814,8 @@ public final class JobStore { * will take the parser into the body of the job tag. * @return Newly instantiated job holding all the information we just read out of the xml tag. */ private JobStatus restoreJobFromXml(boolean rtcIsGood, XmlPullParser parser) throws XmlPullParserException, IOException { private JobStatus restoreJobFromXml(boolean rtcIsGood, XmlPullParser parser, int schemaVersion) throws XmlPullParserException, IOException { JobInfo.Builder jobBuilder; int uid, sourceUserId; long lastSuccessfulRunTime; Loading @@ -826,13 +828,22 @@ public final class JobStore { jobBuilder.setPersisted(true); uid = Integer.parseInt(parser.getAttributeValue(null, "uid")); String val = parser.getAttributeValue(null, "bias"); if (val == null) { String val; if (schemaVersion == 0) { val = parser.getAttributeValue(null, "priority"); if (val != null) { jobBuilder.setBias(Integer.parseInt(val)); } } else if (schemaVersion >= 1) { val = parser.getAttributeValue(null, "bias"); if (val != null) { jobBuilder.setBias(Integer.parseInt(val)); } val = parser.getAttributeValue(null, "priority"); if (val != null) { jobBuilder.setPriority(Integer.parseInt(val)); } } val = parser.getAttributeValue(null, "flags"); if (val != null) { jobBuilder.setFlags(Integer.parseInt(val)); Loading apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING +3 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ "name": "CtsJobSchedulerTestCases", "options": [ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"}, {"exclude-annotation": "android.platform.test.annotations.LargeTest"}, {"exclude-annotation": "androidx.test.filters.FlakyTest"}, {"exclude-annotation": "androidx.test.filters.LargeTest"} ] Loading @@ -13,6 +14,7 @@ "options": [ {"include-filter": "com.android.server.job"}, {"exclude-annotation": "android.platform.test.annotations.FlakyTest"}, {"exclude-annotation": "android.platform.test.annotations.LargeTest"}, {"exclude-annotation": "androidx.test.filters.FlakyTest"} ] }, Loading @@ -21,6 +23,7 @@ "options": [ {"include-filter": "com.android.server.job"}, {"exclude-annotation": "android.platform.test.annotations.FlakyTest"}, {"exclude-annotation": "android.platform.test.annotations.LargeTest"}, {"exclude-annotation": "androidx.test.filters.FlakyTest"} ] } Loading Loading
apex/jobscheduler/framework/java/android/app/job/JobInfo.java +202 −9 Original line number Diff line number Diff line Loading @@ -85,6 +85,17 @@ public class JobInfo implements Parcelable { @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) public static final long DISALLOW_DEADLINES_FOR_PREFETCH_JOBS = 194532703L; /** * Whether to throw an exception when an app provides an invalid priority value via * {@link Builder#setPriority(int)}. Legacy apps may be incorrectly using the API and * so the call will silently fail for them if they continue using the API. * * @hide */ @ChangeId @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) public static final long THROW_ON_INVALID_PRIORITY_VALUE = 140852299L; /** @hide */ @IntDef(prefix = { "NETWORK_TYPE_" }, value = { NETWORK_TYPE_NONE, Loading Loading @@ -206,6 +217,67 @@ public class JobInfo implements Parcelable { */ public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL; /** * Job has minimal value to the user. The user has absolutely no expectation * or knowledge of this task and it has no bearing on the user's perception of * the app whatsoever. JobScheduler <i>may</i> decide to defer these tasks while * there are higher priority tasks in order to ensure there is sufficient quota * available for the higher priority tasks. * A sample task of min priority: uploading analytics */ public static final int PRIORITY_MIN = 100; /** * Low priority. The task provides some benefit to users, but is not critical * and is more of a nice-to-have. This is more important than minimum priority * jobs and will be prioritized ahead of them, but may still be deferred in lieu * of higher priority jobs. JobScheduler <i>may</i> decide to defer these tasks * while there are higher priority tasks in order to ensure there is sufficient * quota available for the higher priority tasks. * A sample task of low priority: prefetching data the user hasn't requested */ public static final int PRIORITY_LOW = 200; /** * Default value for all regular jobs. As noted in {@link JobScheduler}, * these jobs have a general maximum execution time of 10 minutes. * Receives the standard job management policy. */ public static final int PRIORITY_DEFAULT = 300; /** * This task should be ordered ahead of most other tasks. It may be * deferred a little, but if it doesn't run at some point, the user may think * something is wrong. Assuming all constraints remain satisfied * (including ideal system load conditions), these jobs will have a maximum * execution time of at least 4 minutes. Setting all of your jobs to high * priority will not be beneficial to your app and in fact may hurt its * performance in the long run. */ public static final int PRIORITY_HIGH = 400; /** * This task should be run ahead of all other tasks. Only Expedited Jobs * {@link Builder#setExpedited(boolean)} can have this priority and as such, * are subject to the same maximum execution time details noted in * {@link Builder#setExpedited(boolean)}. * A sample task of max priority: receiving a text message and processing it to * show a notification */ public static final int PRIORITY_MAX = 500; /** @hide */ @IntDef(prefix = {"PRIORITY_"}, value = { PRIORITY_MIN, PRIORITY_LOW, PRIORITY_DEFAULT, PRIORITY_HIGH, PRIORITY_MAX, }) @Retention(RetentionPolicy.SOURCE) public @interface Priority { } /** * Default of {@link #getBias}. * @hide Loading Loading @@ -359,6 +431,8 @@ public class JobInfo implements Parcelable { private final long initialBackoffMillis; private final int backoffPolicy; private final int mBias; @Priority private final int mPriority; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final int flags; Loading Loading @@ -410,6 +484,14 @@ public class JobInfo implements Parcelable { return mBias; } /** * @see JobInfo.Builder#setPriority(int) */ @Priority public int getPriority() { return mPriority; } /** @hide */ public int getFlags() { return flags; Loading Loading @@ -746,6 +828,9 @@ public class JobInfo implements Parcelable { if (mBias != j.mBias) { return false; } if (mPriority != j.mPriority) { return false; } if (flags != j.flags) { return false; } Loading Loading @@ -791,6 +876,7 @@ public class JobInfo implements Parcelable { hashCode = 31 * hashCode + Long.hashCode(initialBackoffMillis); hashCode = 31 * hashCode + backoffPolicy; hashCode = 31 * hashCode + mBias; hashCode = 31 * hashCode + mPriority; hashCode = 31 * hashCode + flags; return hashCode; } Loading Loading @@ -830,6 +916,7 @@ public class JobInfo implements Parcelable { hasEarlyConstraint = in.readInt() == 1; hasLateConstraint = in.readInt() == 1; mBias = in.readInt(); mPriority = in.readInt(); flags = in.readInt(); } Loading Loading @@ -861,6 +948,7 @@ public class JobInfo implements Parcelable { hasEarlyConstraint = b.mHasEarlyConstraint; hasLateConstraint = b.mHasLateConstraint; mBias = b.mBias; mPriority = b.mPriority; flags = b.mFlags; } Loading Loading @@ -906,6 +994,7 @@ public class JobInfo implements Parcelable { out.writeInt(hasEarlyConstraint ? 1 : 0); out.writeInt(hasLateConstraint ? 1 : 0); out.writeInt(mBias); out.writeInt(mPriority); out.writeInt(this.flags); } Loading Loading @@ -1024,6 +1113,8 @@ public class JobInfo implements Parcelable { private ClipData mClipData; private int mClipGrantFlags; private int mBias = BIAS_DEFAULT; @Priority private int mPriority = PRIORITY_DEFAULT; private int mFlags; // Requirements. private int mConstraintFlags; Loading Loading @@ -1100,6 +1191,7 @@ public class JobInfo implements Parcelable { // mBackoffPolicySet isn't set but it's fine since this is copying from an already valid // job. mBackoffPolicy = job.getBackoffPolicy(); mPriority = job.getPriority(); } /** @hide */ Loading @@ -1109,11 +1201,36 @@ public class JobInfo implements Parcelable { return this; } /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public Builder setPriority(int priority) { // No-op for invalid calls. This wasn't a supported API before Tiramisu, so anyone // calling this that isn't targeting T isn't guaranteed a behavior change. /** * Indicate the priority for this job. The priority set here will be used to sort jobs * for a single app and apply slightly different policies based on the priority. * The priority will <b>NOT</b> be used as a global sorting value to sort between * different app's jobs. Use this to inform the system about which jobs it should try * to run before other jobs. Giving the same priority to all of your jobs will result * in them all being treated the same. The priorities each have slightly different * behaviors, as noted in their relevant javadoc. * * <b>NOTE:</b> Setting all of your jobs to high priority will not be * beneficial to your app and in fact may hurt its performance in the * long run. * * In order to prevent starvation, repeatedly retried jobs (because of failures) will slowly * have their priorities lowered. * * @see JobInfo#getPriority() */ @NonNull public Builder setPriority(@Priority int priority) { if (priority > PRIORITY_MAX || priority < PRIORITY_MIN) { if (Compatibility.isChangeEnabled(THROW_ON_INVALID_PRIORITY_VALUE)) { throw new IllegalArgumentException("Invalid priority value"); } // No-op for invalid calls of apps that are targeting S-. This was an unsupported // API before Tiramisu, so anyone calling this that isn't targeting T isn't // guaranteed a behavior change. return this; } mPriority = priority; return this; } Loading Loading @@ -1637,7 +1754,17 @@ public class JobInfo implements Parcelable { public Builder setExpedited(boolean expedited) { if (expedited) { mFlags |= FLAG_EXPEDITED; if (mPriority == PRIORITY_DEFAULT) { // The default priority for EJs is MAX, but only change this if .setPriority() // hasn't been called yet. mPriority = PRIORITY_MAX; } } else { if (mPriority == PRIORITY_MAX && (mFlags & FLAG_EXPEDITED) != 0) { // Reset the priority for the job, but only change this if .setPriority() // hasn't been called yet. mPriority = PRIORITY_DEFAULT; } mFlags &= (~FLAG_EXPEDITED); } return this; Loading @@ -1664,7 +1791,18 @@ public class JobInfo implements Parcelable { public Builder setImportantWhileForeground(boolean importantWhileForeground) { if (importantWhileForeground) { mFlags |= FLAG_IMPORTANT_WHILE_FOREGROUND; if (mPriority == PRIORITY_DEFAULT) { // The default priority for important-while-foreground is HIGH, but only change // this if .setPriority() hasn't been called yet. mPriority = PRIORITY_HIGH; } } else { if (mPriority == PRIORITY_HIGH && (mFlags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0) { // Reset the priority for the job, but only change this if .setPriority() // hasn't been called yet. mPriority = PRIORITY_DEFAULT; } mFlags &= (~FLAG_IMPORTANT_WHILE_FOREGROUND); } return this; Loading Loading @@ -1812,12 +1950,42 @@ public class JobInfo implements Parcelable { } } if ((flags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0 && hasEarlyConstraint) { if ((flags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0) { if (hasEarlyConstraint) { throw new IllegalArgumentException( "An important while foreground job cannot have a time delay"); } if (mPriority != PRIORITY_HIGH && mPriority != PRIORITY_DEFAULT) { throw new IllegalArgumentException( "An important while foreground job must be high or default priority." + " Don't mark unimportant tasks as important while foreground."); } } final boolean isExpedited = (flags & FLAG_EXPEDITED) != 0; switch (mPriority) { case PRIORITY_MAX: if (!isExpedited) { throw new IllegalArgumentException("Only expedited jobs can have max priority"); } break; case PRIORITY_HIGH: if ((flags & FLAG_PREFETCH) != 0) { throw new IllegalArgumentException("Prefetch jobs cannot be high priority"); } if (isPeriodic) { throw new IllegalArgumentException("Periodic jobs cannot be high priority"); } break; case PRIORITY_DEFAULT: case PRIORITY_LOW: case PRIORITY_MIN: break; default: throw new IllegalArgumentException("Invalid priority level provided: " + mPriority); } if ((flags & FLAG_EXPEDITED) != 0) { if (isExpedited) { if (hasEarlyConstraint) { throw new IllegalArgumentException("An expedited job cannot have a time delay"); } Loading @@ -1827,6 +1995,11 @@ public class JobInfo implements Parcelable { if (isPeriodic) { throw new IllegalArgumentException("An expedited job cannot be periodic"); } if (mPriority != PRIORITY_MAX && mPriority != PRIORITY_HIGH) { throw new IllegalArgumentException( "An expedited job must be high or max priority. Don't use expedited jobs" + " for unimportant tasks."); } if ((constraintFlags & ~CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0 || (flags & ~(FLAG_EXPEDITED | FLAG_EXEMPT_FROM_APP_STANDBY)) != 0) { throw new IllegalArgumentException( Loading Loading @@ -1863,4 +2036,24 @@ public class JobInfo implements Parcelable { } return bias + " [UNKNOWN]"; } /** * Convert a priority integer into a human readable string for debugging. * @hide */ public static String getPriorityString(@Priority int priority) { switch (priority) { case PRIORITY_MIN: return priority + " [MIN]"; case PRIORITY_LOW: return priority + " [LOW]"; case PRIORITY_DEFAULT: return priority + " [DEFAULT]"; case PRIORITY_HIGH: return priority + " [HIGH]"; case PRIORITY_MAX: return priority + " [MAX]"; } return priority + " [UNKNOWN]"; } }
apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +148 −36 File changed.Preview size limit exceeded, changes collapsed. Show changes
apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +30 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.job; import static android.app.job.JobInfo.getPriorityString; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; Loading Loading @@ -378,19 +380,41 @@ public final class JobServiceContext implements ServiceConnection { @EconomicPolicy.AppAction private static int getStartActionId(@NonNull JobStatus job) { if (job.startedAsExpeditedJob || job.shouldTreatAsExpeditedJob()) { switch (job.getEffectivePriority()) { case JobInfo.PRIORITY_MAX: return JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START; } case JobInfo.PRIORITY_HIGH: return JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START; case JobInfo.PRIORITY_LOW: return JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START; case JobInfo.PRIORITY_MIN: return JobSchedulerEconomicPolicy.ACTION_JOB_MIN_START; default: Slog.wtf(TAG, "Unknown priority: " + getPriorityString(job.getEffectivePriority())); // Intentional fallthrough case JobInfo.PRIORITY_DEFAULT: return JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START; } } @EconomicPolicy.AppAction private static int getRunningActionId(@NonNull JobStatus job) { if (job.startedAsExpeditedJob || job.shouldTreatAsExpeditedJob()) { switch (job.getEffectivePriority()) { case JobInfo.PRIORITY_MAX: return JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING; } case JobInfo.PRIORITY_HIGH: return JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING; case JobInfo.PRIORITY_LOW: return JobSchedulerEconomicPolicy.ACTION_JOB_LOW_RUNNING; case JobInfo.PRIORITY_MIN: return JobSchedulerEconomicPolicy.ACTION_JOB_MIN_RUNNING; default: Slog.wtf(TAG, "Unknown priority: " + getPriorityString(job.getEffectivePriority())); // Intentional fallthrough case JobInfo.PRIORITY_DEFAULT: return JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING; } } /** * Used externally to query the running job. Will return null if there is no job running. Loading
apex/jobscheduler/service/java/com/android/server/job/JobStore.java +22 −11 Original line number Diff line number Diff line Loading @@ -335,7 +335,7 @@ public final class JobStore { } /** Version of the db schema. */ private static final int JOBS_FILE_VERSION = 0; private static final int JOBS_FILE_VERSION = 1; /** Tag corresponds to constraints this job needs. */ private static final String XML_TAG_PARAMS_CONSTRAINTS = "constraints"; /** Tag corresponds to execution parameters. */ Loading Loading @@ -548,6 +548,7 @@ public final class JobStore { out.attribute(null, "sourceUserId", String.valueOf(jobStatus.getSourceUserId())); out.attribute(null, "uid", Integer.toString(jobStatus.getUid())); out.attribute(null, "bias", String.valueOf(jobStatus.getBias())); out.attribute(null, "priority", String.valueOf(jobStatus.getEffectivePriority())); out.attribute(null, "flags", String.valueOf(jobStatus.getFlags())); if (jobStatus.getInternalFlags() != 0) { out.attribute(null, "internalFlags", String.valueOf(jobStatus.getInternalFlags())); Loading Loading @@ -771,10 +772,11 @@ public final class JobStore { String tagName = parser.getName(); if ("job-info".equals(tagName)) { final List<JobStatus> jobs = new ArrayList<JobStatus>(); final int version; // Read in version info. try { int version = Integer.parseInt(parser.getAttributeValue(null, "version")); if (version != JOBS_FILE_VERSION) { version = Integer.parseInt(parser.getAttributeValue(null, "version")); if (version > JOBS_FILE_VERSION || version < 0) { Slog.d(TAG, "Invalid version number, aborting jobs file read."); return null; } Loading @@ -789,7 +791,7 @@ public final class JobStore { tagName = parser.getName(); // Start reading job. if ("job".equals(tagName)) { JobStatus persistedJob = restoreJobFromXml(rtcIsGood, parser); JobStatus persistedJob = restoreJobFromXml(rtcIsGood, parser, version); if (persistedJob != null) { if (DEBUG) { Slog.d(TAG, "Read out " + persistedJob); Loading @@ -812,8 +814,8 @@ public final class JobStore { * will take the parser into the body of the job tag. * @return Newly instantiated job holding all the information we just read out of the xml tag. */ private JobStatus restoreJobFromXml(boolean rtcIsGood, XmlPullParser parser) throws XmlPullParserException, IOException { private JobStatus restoreJobFromXml(boolean rtcIsGood, XmlPullParser parser, int schemaVersion) throws XmlPullParserException, IOException { JobInfo.Builder jobBuilder; int uid, sourceUserId; long lastSuccessfulRunTime; Loading @@ -826,13 +828,22 @@ public final class JobStore { jobBuilder.setPersisted(true); uid = Integer.parseInt(parser.getAttributeValue(null, "uid")); String val = parser.getAttributeValue(null, "bias"); if (val == null) { String val; if (schemaVersion == 0) { val = parser.getAttributeValue(null, "priority"); if (val != null) { jobBuilder.setBias(Integer.parseInt(val)); } } else if (schemaVersion >= 1) { val = parser.getAttributeValue(null, "bias"); if (val != null) { jobBuilder.setBias(Integer.parseInt(val)); } val = parser.getAttributeValue(null, "priority"); if (val != null) { jobBuilder.setPriority(Integer.parseInt(val)); } } val = parser.getAttributeValue(null, "flags"); if (val != null) { jobBuilder.setFlags(Integer.parseInt(val)); Loading
apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING +3 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ "name": "CtsJobSchedulerTestCases", "options": [ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"}, {"exclude-annotation": "android.platform.test.annotations.LargeTest"}, {"exclude-annotation": "androidx.test.filters.FlakyTest"}, {"exclude-annotation": "androidx.test.filters.LargeTest"} ] Loading @@ -13,6 +14,7 @@ "options": [ {"include-filter": "com.android.server.job"}, {"exclude-annotation": "android.platform.test.annotations.FlakyTest"}, {"exclude-annotation": "android.platform.test.annotations.LargeTest"}, {"exclude-annotation": "androidx.test.filters.FlakyTest"} ] }, Loading @@ -21,6 +23,7 @@ "options": [ {"include-filter": "com.android.server.job"}, {"exclude-annotation": "android.platform.test.annotations.FlakyTest"}, {"exclude-annotation": "android.platform.test.annotations.LargeTest"}, {"exclude-annotation": "androidx.test.filters.FlakyTest"} ] } Loading