Narrowing the set of Media URI exemptions for jobs

Only jobs watching for changes to EXTERNAL_CONTENT_URI for Images and
Vidoes will get exemption for jobs.
MediaScanner will scan and insert an entry under each of these URIs
for respective file types.

Test: atest com.android.server.job.controllers.JobStatusTest

Bug: 148887841
Change-Id: I6f9a07d2c0f06c002929056891187f22a6e87e21
This commit is contained in:
Suprabh Shukla
2020-02-19 17:15:14 -08:00
parent 0812647050
commit 057b8da1a1
2 changed files with 44 additions and 18 deletions

View File

@@ -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;
@@ -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.
*
@@ -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;
}
}
@@ -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,

View File

@@ -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;
@@ -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();
@@ -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);
@@ -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");
@@ -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);
@@ -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