Merge "Add permission check to setBias." into main
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 5dc994e..a92a01f 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -1265,6 +1265,7 @@
/** @hide */
@NonNull
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public Builder setBias(int bias) {
mBias = bias;
return this;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 592aff8..1287cb4 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -202,6 +202,15 @@
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
static final long REQUIRE_NETWORK_PERMISSIONS_FOR_CONNECTIVITY_JOBS = 271850009L;
+ /**
+ * Throw an exception when biases are set by an unsupported client.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public static final long THROW_ON_UNSUPPORTED_BIAS_USAGE = 300477393L;
+
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public static Clock sSystemClock = Clock.systemUTC();
@@ -4331,6 +4340,24 @@
}
}
+ private JobInfo enforceBuilderApiPermissions(int uid, int pid, JobInfo job) {
+ if (job.getBias() != JobInfo.BIAS_DEFAULT
+ && !hasPermission(uid, pid, Manifest.permission.UPDATE_DEVICE_STATS)) {
+ if (CompatChanges.isChangeEnabled(THROW_ON_UNSUPPORTED_BIAS_USAGE, uid)) {
+ throw new SecurityException("Apps may not call setBias()");
+ } else {
+ // We can't throw the exception. Log the issue and modify the job to remove
+ // the invalid value.
+ Slog.w(TAG, "Uid " + uid + " set bias on its job");
+ return new JobInfo.Builder(job)
+ .setBias(JobInfo.BIAS_DEFAULT)
+ .build(false, false);
+ }
+ }
+
+ return job;
+ }
+
private boolean canPersistJobs(int pid, int uid) {
// Persisting jobs is tantamount to running at boot, so we permit
// it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED
@@ -4512,6 +4539,8 @@
namespace = validateNamespace(namespace);
+ job = enforceBuilderApiPermissions(uid, pid, job);
+
final long ident = Binder.clearCallingIdentity();
try {
return JobSchedulerService.this.scheduleAsPackage(job, null, uid, null, userId,
@@ -4543,6 +4572,8 @@
namespace = validateNamespace(namespace);
+ job = enforceBuilderApiPermissions(uid, pid, job);
+
final long ident = Binder.clearCallingIdentity();
try {
return JobSchedulerService.this.scheduleAsPackage(job, work, uid, null, userId,
@@ -4582,6 +4613,8 @@
namespace = validateNamespace(namespace);
+ job = enforceBuilderApiPermissions(callerUid, callerPid, job);
+
final long ident = Binder.clearCallingIdentity();
try {
return JobSchedulerService.this.scheduleAsPackage(job, null, callerUid,