Loading apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +16 −6 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.util.Slog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.server.LocalServices; import com.android.server.job.GrantedUriPermissions; Loading Loading @@ -96,6 +97,15 @@ public final class JobStatus { | CONSTRAINT_CONNECTIVITY | CONSTRAINT_IDLE; /** * Standard media URIs that contain the media files that might be important to the user. * @see #mHasMediaBackupExemption */ private static final Uri[] MEDIA_URIS_FOR_STANDBY_EXEMPTION = { MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Video.Media.EXTERNAL_CONTENT_URI, }; /** * The constraints that we want to log to statsd. * Loading Loading @@ -441,13 +451,13 @@ public final class JobStatus { if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) { requiredConstraints |= CONSTRAINT_DEADLINE; } boolean mediaOnly = false; boolean exemptedMediaUrisOnly = false; if (job.getTriggerContentUris() != null) { requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER; mediaOnly = true; exemptedMediaUrisOnly = true; for (JobInfo.TriggerContentUri uri : job.getTriggerContentUris()) { if (!MediaStore.AUTHORITY.equals(uri.getUri().getAuthority())) { mediaOnly = false; if (!ArrayUtils.contains(MEDIA_URIS_FOR_STANDBY_EXEMPTION, uri.getUri())) { exemptedMediaUrisOnly = false; break; } } Loading Loading @@ -475,8 +485,8 @@ public final class JobStatus { job.getRequiredNetwork().networkCapabilities.setSingleUid(this.sourceUid); } final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class); mHasMediaBackupExemption = !job.hasLateConstraint() && mediaOnly && requiresNetwork && this.sourcePackageName.equals(jsi.getMediaBackupPackage()); mHasMediaBackupExemption = !job.hasLateConstraint() && exemptedMediaUrisOnly && requiresNetwork && this.sourcePackageName.equals(jsi.getMediaBackupPackage()); } /** Copy constructor: used specifically when cloning JobStatus objects for persistence, Loading services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java +28 −12 Original line number Diff line number Diff line Loading @@ -73,7 +73,9 @@ public class JobStatusTest { private static final double DELTA = 0.00001; private static final String TEST_PACKAGE = "job.test.package"; private static final ComponentName TEST_JOB_COMPONENT = new ComponentName(TEST_PACKAGE, "test"); private static final Uri TEST_MEDIA_URI = Uri.parse("content://media/path/to/media"); private static final Uri IMAGES_MEDIA_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; private static final Uri VIDEO_MEDIA_URI = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; @Mock private JobSchedulerInternal mJobSchedulerInternal; Loading Loading @@ -127,7 +129,7 @@ public class JobStatusTest { @Test public void testMediaBackupExemption_lateConstraint() { final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .setOverrideDeadline(12) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); Loading @@ -138,7 +140,7 @@ public class JobStatusTest { @Test public void testMediaBackupExemption_noConnectivityConstraint() { final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .build(); when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE); assertEffectiveBucketForMediaExemption(createJobStatus(triggerContentJob), false); Loading @@ -156,7 +158,7 @@ public class JobStatusTest { @Test public void testMediaBackupExemption_wrongSourcePackage() { final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn("not.test.package"); Loading @@ -164,11 +166,12 @@ public class JobStatusTest { } @Test public void testMediaBackupExemption_nonMediaUri() { final Uri nonMediaUri = Uri.parse("content://not-media/any/path"); public void testMediaBackupExemption_nonEligibleUri() { final Uri nonEligibleUri = MediaStore.AUTHORITY_URI.buildUpon() .appendPath("any_path").build(); final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(nonMediaUri, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(nonEligibleUri, 0)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE); Loading @@ -177,12 +180,25 @@ public class JobStatusTest { @Test public void testMediaBackupExemptionGranted() { final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE); final JobInfo imageUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE); assertEffectiveBucketForMediaExemption(createJobStatus(networkContentJob), true); assertEffectiveBucketForMediaExemption(createJobStatus(imageUriJob), true); final JobInfo videoUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(VIDEO_MEDIA_URI, 0)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); assertEffectiveBucketForMediaExemption(createJobStatus(videoUriJob), true); final JobInfo bothUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(VIDEO_MEDIA_URI, 0)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); assertEffectiveBucketForMediaExemption(createJobStatus(bothUriJob), true); } @Test Loading Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +16 −6 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.util.Slog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.server.LocalServices; import com.android.server.job.GrantedUriPermissions; Loading Loading @@ -96,6 +97,15 @@ public final class JobStatus { | CONSTRAINT_CONNECTIVITY | CONSTRAINT_IDLE; /** * Standard media URIs that contain the media files that might be important to the user. * @see #mHasMediaBackupExemption */ private static final Uri[] MEDIA_URIS_FOR_STANDBY_EXEMPTION = { MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Video.Media.EXTERNAL_CONTENT_URI, }; /** * The constraints that we want to log to statsd. * Loading Loading @@ -441,13 +451,13 @@ public final class JobStatus { if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) { requiredConstraints |= CONSTRAINT_DEADLINE; } boolean mediaOnly = false; boolean exemptedMediaUrisOnly = false; if (job.getTriggerContentUris() != null) { requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER; mediaOnly = true; exemptedMediaUrisOnly = true; for (JobInfo.TriggerContentUri uri : job.getTriggerContentUris()) { if (!MediaStore.AUTHORITY.equals(uri.getUri().getAuthority())) { mediaOnly = false; if (!ArrayUtils.contains(MEDIA_URIS_FOR_STANDBY_EXEMPTION, uri.getUri())) { exemptedMediaUrisOnly = false; break; } } Loading Loading @@ -475,8 +485,8 @@ public final class JobStatus { job.getRequiredNetwork().networkCapabilities.setSingleUid(this.sourceUid); } final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class); mHasMediaBackupExemption = !job.hasLateConstraint() && mediaOnly && requiresNetwork && this.sourcePackageName.equals(jsi.getMediaBackupPackage()); mHasMediaBackupExemption = !job.hasLateConstraint() && exemptedMediaUrisOnly && requiresNetwork && this.sourcePackageName.equals(jsi.getMediaBackupPackage()); } /** Copy constructor: used specifically when cloning JobStatus objects for persistence, Loading
services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java +28 −12 Original line number Diff line number Diff line Loading @@ -73,7 +73,9 @@ public class JobStatusTest { private static final double DELTA = 0.00001; private static final String TEST_PACKAGE = "job.test.package"; private static final ComponentName TEST_JOB_COMPONENT = new ComponentName(TEST_PACKAGE, "test"); private static final Uri TEST_MEDIA_URI = Uri.parse("content://media/path/to/media"); private static final Uri IMAGES_MEDIA_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; private static final Uri VIDEO_MEDIA_URI = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; @Mock private JobSchedulerInternal mJobSchedulerInternal; Loading Loading @@ -127,7 +129,7 @@ public class JobStatusTest { @Test public void testMediaBackupExemption_lateConstraint() { final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .setOverrideDeadline(12) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); Loading @@ -138,7 +140,7 @@ public class JobStatusTest { @Test public void testMediaBackupExemption_noConnectivityConstraint() { final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .build(); when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE); assertEffectiveBucketForMediaExemption(createJobStatus(triggerContentJob), false); Loading @@ -156,7 +158,7 @@ public class JobStatusTest { @Test public void testMediaBackupExemption_wrongSourcePackage() { final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn("not.test.package"); Loading @@ -164,11 +166,12 @@ public class JobStatusTest { } @Test public void testMediaBackupExemption_nonMediaUri() { final Uri nonMediaUri = Uri.parse("content://not-media/any/path"); public void testMediaBackupExemption_nonEligibleUri() { final Uri nonEligibleUri = MediaStore.AUTHORITY_URI.buildUpon() .appendPath("any_path").build(); final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(nonMediaUri, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(nonEligibleUri, 0)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE); Loading @@ -177,12 +180,25 @@ public class JobStatusTest { @Test public void testMediaBackupExemptionGranted() { final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0)) when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE); final JobInfo imageUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE); assertEffectiveBucketForMediaExemption(createJobStatus(networkContentJob), true); assertEffectiveBucketForMediaExemption(createJobStatus(imageUriJob), true); final JobInfo videoUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(VIDEO_MEDIA_URI, 0)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); assertEffectiveBucketForMediaExemption(createJobStatus(videoUriJob), true); final JobInfo bothUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) .addTriggerContentUri(new JobInfo.TriggerContentUri(VIDEO_MEDIA_URI, 0)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); assertEffectiveBucketForMediaExemption(createJobStatus(bothUriJob), true); } @Test Loading