Loading core/java/android/app/job/JobInfo.java +15 −0 Original line number Original line Diff line number Diff line Loading @@ -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 */ */ Loading Loading @@ -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). Loading services/core/java/com/android/server/job/JobSchedulerService.java +22 −13 Original line number Original line Diff line number Diff line Loading @@ -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 // 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 Loading Loading @@ -2339,6 +2341,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 { Loading @@ -2357,10 +2375,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 { Loading Loading @@ -2388,10 +2403,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 { Loading Loading @@ -2422,10 +2434,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 { Loading Loading
core/java/android/app/job/JobInfo.java +15 −0 Original line number Original line Diff line number Diff line Loading @@ -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 */ */ Loading Loading @@ -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). Loading
services/core/java/com/android/server/job/JobSchedulerService.java +22 −13 Original line number Original line Diff line number Diff line Loading @@ -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 // 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 Loading Loading @@ -2339,6 +2341,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 { Loading @@ -2357,10 +2375,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 { Loading Loading @@ -2388,10 +2403,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 { Loading Loading @@ -2422,10 +2434,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 { Loading