summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/job/JobInfo.java15
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java35
2 files changed, 37 insertions, 13 deletions
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index cba9dcc3c4cc..a1ad825c3a29 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -256,6 +256,14 @@ public class JobInfo implements Parcelable {
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
*/
public static final int CONSTRAINT_FLAG_CHARGING = 1 << 0;
@@ -355,6 +363,13 @@ public class JobInfo implements Parcelable {
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
* device connected to permanent power, such as Android TV devices).
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 0a21f12c1f87..8fa331880abc 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -1814,7 +1814,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
// an appropriate amount of time since the last invocation. During device-
// 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();
if (mHeartbeat < mNextBucketHeartbeat[bucket]) {
// Only skip this job if it's still waiting for the end of its (initial) nominal
@@ -2339,6 +2341,22 @@ public final class JobSchedulerService extends com.android.server.SystemService
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
@Override
public int schedule(JobInfo job) throws RemoteException {
@@ -2357,10 +2375,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
}
}
- if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) {
- getContext().enforceCallingOrSelfPermission(
- android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG);
- }
+ validateJobFlags(job, uid);
long ident = Binder.clearCallingIdentity();
try {
@@ -2388,10 +2403,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
throw new NullPointerException("work is null");
}
- if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) {
- getContext().enforceCallingOrSelfPermission(
- android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG);
- }
+ validateJobFlags(job, uid);
long ident = Binder.clearCallingIdentity();
try {
@@ -2422,10 +2434,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
+ " not permitted to schedule jobs for other apps");
}
- if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) {
- getContext().enforceCallingOrSelfPermission(
- android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG);
- }
+ validateJobFlags(job, callerUid);
long ident = Binder.clearCallingIdentity();
try {