Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 057b8da1 authored by Suprabh Shukla's avatar Suprabh Shukla
Browse files

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
parent 08126470
Loading
Loading
Loading
Loading
+16 −6
Original line number Diff line number Diff line
@@ -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,
+28 −12
Original line number Diff line number Diff line
@@ -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