diff options
| author | 2023-03-30 17:16:19 +0000 | |
|---|---|---|
| committer | 2023-03-30 17:59:51 +0000 | |
| commit | a6843af7302e36fb0b8b2b72207af0a9b23bdb02 (patch) | |
| tree | 74907f8cee1ce5f7004511005dbeb846e9cca4f0 | |
| parent | 8b84c481cc637478bc0a1e096e42a9b7997cc00a (diff) | |
Don't allow empty namespaces.
An empty namespace (""), or a string made up of only whitespace,
isn't very descriptive and may cause issues with debugging in the
future. This blocks clients from using such namespaces in the first
place.
Bug: 276313158
Test: atest CtsJobSchedulerTestCases:JobSchedulingTest
Change-Id: I2b8da58fc1836b8547270b2c6f39fe44fd34f936
3 files changed, 40 insertions, 15 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java b/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java index 776d913e56cb..3cfddc6d8e2b 100644 --- a/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java +++ b/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java @@ -65,8 +65,12 @@ public class JobSchedulerImpl extends JobScheduler { @NonNull @Override public JobScheduler forNamespace(@NonNull String namespace) { + namespace = sanitizeNamespace(namespace); if (namespace == null) { - throw new IllegalArgumentException("namespace cannot be null"); + throw new NullPointerException("namespace cannot be null"); + } + if (namespace.isEmpty()) { + throw new IllegalArgumentException("namespace cannot be empty"); } return new JobSchedulerImpl(this, namespace); } diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java index b8847add0734..d59d430e0b78 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java @@ -270,6 +270,9 @@ public abstract class JobScheduler { * otherwise. Attempting to update a job scheduled in another namespace will not be possible * but will instead create or update the job inside the current namespace. A JobScheduler * instance dedicated to a namespace must be used to schedule or update jobs in that namespace. + * + * <p class="note">Since leading and trailing whitespace can lead to hard-to-debug issues, + * they will be {@link String#trim() trimmed}. An empty String (after trimming) is not allowed. * @see #getNamespace() */ @NonNull @@ -287,6 +290,15 @@ public abstract class JobScheduler { throw new RuntimeException("Not implemented. Must override in a subclass."); } + /** @hide */ + @Nullable + public static String sanitizeNamespace(@Nullable String namespace) { + if (namespace == null) { + return null; + } + return namespace.trim().intern(); + } + /** * Schedule a job to be executed. Will replace any currently scheduled job with the same * ID with the new information in the {@link JobInfo}. If a job with the given ID is currently 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 3fe83a64b5ec..bad4060ca775 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -4024,6 +4024,18 @@ public class JobSchedulerService extends com.android.server.SystemService return JobScheduler.RESULT_SUCCESS; } + /** Returns a sanitized namespace if valid, or throws an exception if not. */ + private String validateNamespace(@Nullable String namespace) { + namespace = JobScheduler.sanitizeNamespace(namespace); + if (namespace != null) { + if (namespace.isEmpty()) { + throw new IllegalArgumentException("namespace cannot be empty"); + } + namespace = namespace.intern(); + } + return namespace; + } + private int validateRunUserInitiatedJobsPermission(int uid, String packageName) { final int state = getRunUserInitiatedJobsPermissionState(uid, packageName); if (state == PermissionChecker.PERMISSION_HARD_DENIED) { @@ -4071,9 +4083,7 @@ public class JobSchedulerService extends com.android.server.SystemService return result; } - if (namespace != null) { - namespace = namespace.intern(); - } + namespace = validateNamespace(namespace); final long ident = Binder.clearCallingIdentity(); try { @@ -4104,9 +4114,7 @@ public class JobSchedulerService extends com.android.server.SystemService return result; } - if (namespace != null) { - namespace = namespace.intern(); - } + namespace = validateNamespace(namespace); final long ident = Binder.clearCallingIdentity(); try { @@ -4145,9 +4153,7 @@ public class JobSchedulerService extends com.android.server.SystemService return result; } - if (namespace != null) { - namespace = namespace.intern(); - } + namespace = validateNamespace(namespace); final long ident = Binder.clearCallingIdentity(); try { @@ -4184,7 +4190,8 @@ public class JobSchedulerService extends com.android.server.SystemService final long ident = Binder.clearCallingIdentity(); try { return new ParceledListSlice<>( - JobSchedulerService.this.getPendingJobsInNamespace(uid, namespace)); + JobSchedulerService.this.getPendingJobsInNamespace(uid, + validateNamespace(namespace))); } finally { Binder.restoreCallingIdentity(ident); } @@ -4196,7 +4203,8 @@ public class JobSchedulerService extends com.android.server.SystemService final long ident = Binder.clearCallingIdentity(); try { - return JobSchedulerService.this.getPendingJob(uid, namespace, jobId); + return JobSchedulerService.this.getPendingJob( + uid, validateNamespace(namespace), jobId); } finally { Binder.restoreCallingIdentity(ident); } @@ -4208,7 +4216,8 @@ public class JobSchedulerService extends com.android.server.SystemService final long ident = Binder.clearCallingIdentity(); try { - return JobSchedulerService.this.getPendingJobReason(uid, namespace, jobId); + return JobSchedulerService.this.getPendingJobReason( + uid, validateNamespace(namespace), jobId); } finally { Binder.restoreCallingIdentity(ident); } @@ -4238,7 +4247,7 @@ public class JobSchedulerService extends com.android.server.SystemService JobSchedulerService.this.cancelJobsForUid(uid, // Documentation says only jobs scheduled BY the app will be cancelled /* includeSourceApp */ false, - /* namespaceOnly */ true, namespace, + /* namespaceOnly */ true, validateNamespace(namespace), JobParameters.STOP_REASON_CANCELLED_BY_APP, JobParameters.INTERNAL_STOP_REASON_CANCELED, "cancelAllInNamespace() called by app, callingUid=" + uid); @@ -4253,7 +4262,7 @@ public class JobSchedulerService extends com.android.server.SystemService final long ident = Binder.clearCallingIdentity(); try { - JobSchedulerService.this.cancelJob(uid, namespace, jobId, uid, + JobSchedulerService.this.cancelJob(uid, validateNamespace(namespace), jobId, uid, JobParameters.STOP_REASON_CANCELLED_BY_APP); } finally { Binder.restoreCallingIdentity(ident); |