Home | History | Annotate | Download | only in shareduidtests
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.jobscheduler.cts.shareduidtests;
     18 
     19 import android.annotation.TargetApi;
     20 import android.app.job.JobInfo;
     21 import android.app.job.JobWorkItem;
     22 import android.content.ContentProviderClient;
     23 import android.content.Intent;
     24 import android.jobscheduler.MockJobService.TestWorkItem;
     25 import android.net.Uri;
     26 
     27 import com.android.compatibility.common.util.SystemUtil;
     28 
     29 import java.util.ArrayList;
     30 
     31 /**
     32  * Schedules jobs with the {@link android.app.job.JobScheduler} by enqueue work in to
     33  * them and processing it.
     34  */
     35 @TargetApi(26)
     36 public class EnqueueJobWorkTest extends ConstraintTest {
     37     private static final String TAG = "ClipDataJobTest";
     38 
     39     /** Unique identifier for the job scheduled by this suite of tests. */
     40     public static final int ENQUEUE_WORK_JOB_ID = EnqueueJobWorkTest.class.hashCode();
     41 
     42     private JobInfo.Builder mBuilder;
     43     private ContentProviderClient mProvider;
     44 
     45     @Override
     46     public void setUp() throws Exception {
     47         super.setUp();
     48 
     49         mBuilder = new JobInfo.Builder(ENQUEUE_WORK_JOB_ID, kJobServiceComponent);
     50         mProvider = getContext().getContentResolver().acquireContentProviderClient(mFirstUri);
     51     }
     52 
     53     @Override
     54     public void tearDown() throws Exception {
     55         super.tearDown();
     56         mProvider.close();
     57         mJobScheduler.cancel(ENQUEUE_WORK_JOB_ID);
     58     }
     59 
     60     private boolean intentEquals(Intent i1, Intent i2) {
     61         if (i1 == i2) {
     62             return true;
     63         }
     64         if (i1 == null || i2 == null) {
     65             return false;
     66         }
     67         return i1.filterEquals(i2);
     68     }
     69 
     70     private void compareWork(TestWorkItem[] expected, ArrayList<JobWorkItem> received) {
     71         if (received == null) {
     72             fail("Didn't receive any expected work.");
     73         }
     74         ArrayList<TestWorkItem> expectedArray = new ArrayList<>();
     75         for (int i = 0; i < expected.length; i++) {
     76             expectedArray.add(expected[i]);
     77         }
     78         for (int i = 0; i < received.size(); i++) {
     79             JobWorkItem work = received.get(i);
     80             if (i < expected.length && expected[i].subitems != null) {
     81                 TestWorkItem[] sub = expected[i].subitems;
     82                 for (int j = 0; j < sub.length; j++) {
     83                     expectedArray.add(sub[j]);
     84                 }
     85             }
     86             if (i >= expectedArray.size()) {
     87                 fail("Received more than " + expected.length + " work items, first extra is "
     88                         + work);
     89             }
     90             if (!intentEquals(work.getIntent(), expectedArray.get(i).intent)) {
     91                 fail("Received work #" + i + " " + work.getIntent() + " but expected " + expected[i]);
     92             }
     93             if (work.getDeliveryCount() != expectedArray.get(i).deliveryCount) {
     94                 fail("Received work #" + i + " " + work.getIntent() + " delivery count is "
     95                         + work.getDeliveryCount() + " but expected "
     96                         + expectedArray.get(i).deliveryCount);
     97             }
     98         }
     99         if (received.size() < expected.length) {
    100             fail("Received only " + received.size() + " work items, but expected "
    101                             + expected.length);
    102         }
    103     }
    104 
    105     /**
    106      * Test basic enqueueing of work.
    107      */
    108     public void testEnqueueOneWork() throws Exception {
    109         Intent work1 = new Intent("work1");
    110         TestWorkItem[] work = new TestWorkItem[] { new TestWorkItem(work1) };
    111         kTestEnvironment.setExpectedExecutions(1);
    112         kTestEnvironment.setExpectedWork(work);
    113         mJobScheduler.enqueue(mBuilder.setOverrideDeadline(0).build(), new JobWorkItem(work1));
    114         kTestEnvironment.readyToWork();
    115         assertTrue("Job with work enqueued did not fire.",
    116                 kTestEnvironment.awaitExecution());
    117         compareWork(work, kTestEnvironment.getLastReceivedWork());
    118         if (kTestEnvironment.getLastErrorMessage() != null) {
    119             fail(kTestEnvironment.getLastErrorMessage());
    120         }
    121     }
    122 
    123     /**
    124      * Test basic enqueueing batches of work.
    125      */
    126     public void testEnqueueMultipleWork() throws Exception {
    127         Intent work1 = new Intent("work1");
    128         Intent work2 = new Intent("work2");
    129         Intent work3 = new Intent("work3");
    130         Intent work4 = new Intent("work4");
    131         Intent work5 = new Intent("work5");
    132         Intent work6 = new Intent("work6");
    133         Intent work7 = new Intent("work7");
    134         Intent work8 = new Intent("work8");
    135         TestWorkItem[] work = new TestWorkItem[] {
    136                 new TestWorkItem(work1), new TestWorkItem(work2), new TestWorkItem(work3),
    137                 new TestWorkItem(work4), new TestWorkItem(work5), new TestWorkItem(work6),
    138                 new TestWorkItem(work7), new TestWorkItem(work8) };
    139         kTestEnvironment.setExpectedExecutions(1);
    140         kTestEnvironment.setExpectedWork(work);
    141         JobInfo ji = mBuilder.setOverrideDeadline(0).build();
    142         mJobScheduler.enqueue(ji, new JobWorkItem(work1));
    143         mJobScheduler.enqueue(ji, new JobWorkItem(work2));
    144         mJobScheduler.enqueue(ji, new JobWorkItem(work3));
    145         mJobScheduler.enqueue(ji, new JobWorkItem(work4));
    146         mJobScheduler.enqueue(ji, new JobWorkItem(work5));
    147         mJobScheduler.enqueue(ji, new JobWorkItem(work6));
    148         mJobScheduler.enqueue(ji, new JobWorkItem(work7));
    149         mJobScheduler.enqueue(ji, new JobWorkItem(work8));
    150         kTestEnvironment.readyToWork();
    151         assertTrue("Job with work enqueued did not fire.",
    152                 kTestEnvironment.awaitExecution());
    153         compareWork(work, kTestEnvironment.getLastReceivedWork());
    154     }
    155 
    156     /**
    157      * Test basic enqueueing batches of work, with new work coming in while processing existing
    158      * work.
    159      */
    160     public void testEnqueueMultipleSubWork() throws Exception {
    161         Intent work1 = new Intent("work1");
    162         Intent work2 = new Intent("work2");
    163         Intent work3 = new Intent("work3");
    164         Intent work4 = new Intent("work4");
    165         Intent work5 = new Intent("work5");
    166         Intent work6 = new Intent("work6");
    167         Intent work7 = new Intent("work7");
    168         Intent work8 = new Intent("work8");
    169         JobInfo ji = mBuilder.setOverrideDeadline(0).build();
    170         TestWorkItem[] work = new TestWorkItem[]{
    171                 new TestWorkItem(work1), new TestWorkItem(work2), new TestWorkItem(work3),
    172                 new TestWorkItem(work4, ji, new TestWorkItem[] {
    173                         new TestWorkItem(work5), new TestWorkItem(work6),
    174                         new TestWorkItem(work7), new TestWorkItem(work8)})
    175         };
    176         kTestEnvironment.setExpectedExecutions(1);
    177         kTestEnvironment.setExpectedWork(work);
    178         mJobScheduler.enqueue(ji, new JobWorkItem(work1));
    179         mJobScheduler.enqueue(ji, new JobWorkItem(work2));
    180         mJobScheduler.enqueue(ji, new JobWorkItem(work3));
    181         mJobScheduler.enqueue(ji, new JobWorkItem(work4));
    182         kTestEnvironment.readyToWork();
    183         assertTrue("Job with work enqueued did not fire.",
    184                 kTestEnvironment.awaitExecution());
    185         compareWork(work, kTestEnvironment.getLastReceivedWork());
    186     }
    187 
    188     /**
    189      * Test basic enqueueing batches of work that will be executed in parallel.
    190      */
    191     public void testEnqueueParallel2Work() throws Exception {
    192         Intent work1 = new Intent("work1");
    193         Intent work2 = new Intent("work2");
    194         TestWorkItem[] work = new TestWorkItem[] {
    195                 new TestWorkItem(work1, TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_BACK),
    196                 new TestWorkItem(work2, TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_BACK) };
    197         kTestEnvironment.setExpectedExecutions(1);
    198         kTestEnvironment.setExpectedWork(work);
    199         JobInfo ji = mBuilder.setOverrideDeadline(0).build();
    200         mJobScheduler.enqueue(ji, new JobWorkItem(work1));
    201         mJobScheduler.enqueue(ji, new JobWorkItem(work2));
    202         kTestEnvironment.readyToWork();
    203         assertTrue("Job with work enqueued did not fire.",
    204                 kTestEnvironment.awaitExecution());
    205         compareWork(work, kTestEnvironment.getLastReceivedWork());
    206     }
    207 
    208     /**
    209      * Test basic enqueueing batches of work that will be executed in parallel and completed
    210      * in reverse order.
    211      */
    212     public void testEnqueueParallel2ReverseWork() throws Exception {
    213         Intent work1 = new Intent("work1");
    214         Intent work2 = new Intent("work2");
    215         TestWorkItem[] work = new TestWorkItem[] {
    216                 new TestWorkItem(work1, TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_BACK),
    217                 new TestWorkItem(work2, TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_TOP) };
    218         kTestEnvironment.setExpectedExecutions(1);
    219         kTestEnvironment.setExpectedWork(work);
    220         JobInfo ji = mBuilder.setOverrideDeadline(0).build();
    221         mJobScheduler.enqueue(ji, new JobWorkItem(work1));
    222         mJobScheduler.enqueue(ji, new JobWorkItem(work2));
    223         kTestEnvironment.readyToWork();
    224         assertTrue("Job with work enqueued did not fire.",
    225                 kTestEnvironment.awaitExecution());
    226         compareWork(work, kTestEnvironment.getLastReceivedWork());
    227     }
    228 
    229     /**
    230      * Test basic enqueueing batches of work that will be executed in parallel.
    231      */
    232     public void testEnqueueMultipleParallelWork() throws Exception {
    233         Intent work1 = new Intent("work1");
    234         Intent work2 = new Intent("work2");
    235         Intent work3 = new Intent("work3");
    236         Intent work4 = new Intent("work4");
    237         Intent work5 = new Intent("work5");
    238         Intent work6 = new Intent("work6");
    239         Intent work7 = new Intent("work7");
    240         Intent work8 = new Intent("work8");
    241         TestWorkItem[] work = new TestWorkItem[] {
    242                 new TestWorkItem(work1, TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_BACK),
    243                 new TestWorkItem(work2, TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_TOP),
    244                 new TestWorkItem(work3, TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_BACK
    245                         | TestWorkItem.FLAG_COMPLETE_NEXT),
    246                 new TestWorkItem(work4, TestWorkItem.FLAG_COMPLETE_NEXT),
    247                 new TestWorkItem(work5, TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_TOP),
    248                 new TestWorkItem(work6, TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_TOP),
    249                 new TestWorkItem(work7, TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_TOP
    250                         | TestWorkItem.FLAG_COMPLETE_NEXT),
    251                 new TestWorkItem(work8) };
    252         kTestEnvironment.setExpectedExecutions(1);
    253         kTestEnvironment.setExpectedWork(work);
    254         JobInfo ji = mBuilder.setOverrideDeadline(0).build();
    255         mJobScheduler.enqueue(ji, new JobWorkItem(work1));
    256         mJobScheduler.enqueue(ji, new JobWorkItem(work2));
    257         mJobScheduler.enqueue(ji, new JobWorkItem(work3));
    258         mJobScheduler.enqueue(ji, new JobWorkItem(work4));
    259         mJobScheduler.enqueue(ji, new JobWorkItem(work5));
    260         mJobScheduler.enqueue(ji, new JobWorkItem(work6));
    261         mJobScheduler.enqueue(ji, new JobWorkItem(work7));
    262         mJobScheduler.enqueue(ji, new JobWorkItem(work8));
    263         kTestEnvironment.readyToWork();
    264         assertTrue("Job with work enqueued did not fire.",
    265                 kTestEnvironment.awaitExecution());
    266         compareWork(work, kTestEnvironment.getLastReceivedWork());
    267     }
    268 
    269     /**
    270      * Test job getting stopped while processing work and that work being redelivered.
    271      */
    272     public void testEnqueueMultipleRedeliver() throws Exception {
    273         Intent work1 = new Intent("work1");
    274         Intent work2 = new Intent("work2");
    275         Intent work3 = new Intent("work3");
    276         Intent work4 = new Intent("work4");
    277         Intent work5 = new Intent("work5");
    278         Intent work6 = new Intent("work6");
    279         TestWorkItem[] initialWork = new TestWorkItem[] {
    280                 new TestWorkItem(work1), new TestWorkItem(work2), new TestWorkItem(work3),
    281                 new TestWorkItem(work4, TestWorkItem.FLAG_WAIT_FOR_STOP, 1) };
    282         kTestEnvironment.setExpectedExecutions(1);
    283         kTestEnvironment.setExpectedWaitForStop();
    284         kTestEnvironment.setExpectedWork(initialWork);
    285         JobInfo ji = mBuilder.setOverrideDeadline(0).build();
    286         mJobScheduler.enqueue(ji, new JobWorkItem(work1));
    287         mJobScheduler.enqueue(ji, new JobWorkItem(work2));
    288         mJobScheduler.enqueue(ji, new JobWorkItem(work3));
    289         mJobScheduler.enqueue(ji, new JobWorkItem(work4));
    290         kTestEnvironment.readyToWork();
    291 
    292         // Now wait for the job to get to the point where it is processing the last
    293         // work and waiting for it to be stopped.
    294         assertTrue("Job with work enqueued did not wait to stop.",
    295                 kTestEnvironment.awaitWaitingForStop());
    296 
    297         // Cause the job to timeout (stop) immediately, and wait for its execution to finish.
    298         SystemUtil.runShellCommand(getInstrumentation(), "cmd jobscheduler timeout "
    299                 + kJobServiceComponent.getPackageName() + " " + ENQUEUE_WORK_JOB_ID);
    300         assertTrue("Job with work enqueued did not finish.",
    301                 kTestEnvironment.awaitExecution());
    302         compareWork(initialWork, kTestEnvironment.getLastReceivedWork());
    303 
    304         // Now we are going to add some more work, restart the job, and see if it correctly
    305         // redelivers the last work and delivers the new work.
    306         TestWorkItem[] finalWork = new TestWorkItem[] {
    307                 new TestWorkItem(work4, 0, 2), new TestWorkItem(work5), new TestWorkItem(work6) };
    308         kTestEnvironment.setExpectedExecutions(1);
    309         kTestEnvironment.setExpectedWork(finalWork);
    310         mJobScheduler.enqueue(ji, new JobWorkItem(work5));
    311         mJobScheduler.enqueue(ji, new JobWorkItem(work6));
    312         kTestEnvironment.readyToWork();
    313         SystemUtil.runShellCommand(getInstrumentation(), "cmd jobscheduler run "
    314                 + " --user " + getCurrentUser() + " "
    315                 + kJobServiceComponent.getPackageName() + " " + ENQUEUE_WORK_JOB_ID);
    316 
    317         assertTrue("Restarted with work enqueued did not execute.",
    318                 kTestEnvironment.awaitExecution());
    319         compareWork(finalWork, kTestEnvironment.getLastReceivedWork());
    320     }
    321 
    322     /**
    323      * Test job getting stopped while processing work in parallel and that work being redelivered.
    324      */
    325     public void testEnqueueMultipleParallelRedeliver() throws Exception {
    326         Intent work1 = new Intent("work1");
    327         Intent work2 = new Intent("work2");
    328         Intent work3 = new Intent("work3");
    329         Intent work4 = new Intent("work4");
    330         Intent work5 = new Intent("work5");
    331         Intent work6 = new Intent("work6");
    332         TestWorkItem[] initialWork = new TestWorkItem[] {
    333                 new TestWorkItem(work1),
    334                 new TestWorkItem(work2, TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_BACK),
    335                 new TestWorkItem(work3, TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_BACK),
    336                 new TestWorkItem(work4, TestWorkItem.FLAG_WAIT_FOR_STOP, 1) };
    337         kTestEnvironment.setExpectedExecutions(1);
    338         kTestEnvironment.setExpectedWaitForStop();
    339         kTestEnvironment.setExpectedWork(initialWork);
    340         JobInfo ji = mBuilder.setOverrideDeadline(0).build();
    341         mJobScheduler.enqueue(ji, new JobWorkItem(work1));
    342         mJobScheduler.enqueue(ji, new JobWorkItem(work2));
    343         mJobScheduler.enqueue(ji, new JobWorkItem(work3));
    344         mJobScheduler.enqueue(ji, new JobWorkItem(work4));
    345         kTestEnvironment.readyToWork();
    346 
    347         // Now wait for the job to get to the point where it is processing the last
    348         // work and waiting for it to be stopped.
    349         assertTrue("Job with work enqueued did not wait to stop.",
    350                 kTestEnvironment.awaitWaitingForStop());
    351 
    352         // Cause the job to timeout (stop) immediately, and wait for its execution to finish.
    353         SystemUtil.runShellCommand(getInstrumentation(), "cmd jobscheduler timeout "
    354                 + kJobServiceComponent.getPackageName() + " " + ENQUEUE_WORK_JOB_ID);
    355         assertTrue("Job with work enqueued did not finish.",
    356                 kTestEnvironment.awaitExecution());
    357         compareWork(initialWork, kTestEnvironment.getLastReceivedWork());
    358 
    359         // Now we are going to add some more work, restart the job, and see if it correctly
    360         // redelivers the last work and delivers the new work.
    361         TestWorkItem[] finalWork = new TestWorkItem[] {
    362                 new TestWorkItem(work2, 0, 2), new TestWorkItem(work3, 0, 2),
    363                 new TestWorkItem(work4, 0, 2), new TestWorkItem(work5), new TestWorkItem(work6) };
    364         kTestEnvironment.setExpectedExecutions(1);
    365         kTestEnvironment.setExpectedWork(finalWork);
    366         mJobScheduler.enqueue(ji, new JobWorkItem(work5));
    367         mJobScheduler.enqueue(ji, new JobWorkItem(work6));
    368         kTestEnvironment.readyToWork();
    369         SystemUtil.runShellCommand(getInstrumentation(), "cmd jobscheduler run "
    370                 + " --user " + getCurrentUser() + " "
    371                 + kJobServiceComponent.getPackageName() + " " + ENQUEUE_WORK_JOB_ID);
    372 
    373         assertTrue("Restarted with work enqueued did not execute.",
    374                 kTestEnvironment.awaitExecution());
    375         compareWork(finalWork, kTestEnvironment.getLastReceivedWork());
    376     }
    377 
    378     /**
    379      * Test basic enqueueing batches of work.
    380      */
    381     public void testEnqueueMultipleUriGrantWork() throws Exception {
    382         // Start out with storage low, so job is enqueued but not executed yet.
    383         setStorageState(true);
    384 
    385         // We need to get a permission grant so that we can grant it to ourself.
    386         mProvider.call("grant", MY_PACKAGE, mFirstUriBundle);
    387         mProvider.call("grant", MY_PACKAGE, mSecondUriBundle);
    388         assertHasUriPermission(mFirstUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
    389                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    390         assertHasUriPermission(mSecondUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
    391                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    392 
    393         Intent work1 = new Intent("work1");
    394         work1.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
    395                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    396         work1.setData(mFirstUri);
    397         work1.setClipData(mSecondClipData);
    398 
    399         Intent work2 = new Intent("work2");
    400         work2.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
    401                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    402         work2.setData(mFirstUri);
    403 
    404         TestWorkItem[] work = new TestWorkItem[] {
    405                 new TestWorkItem(work1, new Uri[] { mFirstUri, mSecondUri}, new Uri[0]),
    406                 new TestWorkItem(work2, new Uri[] { mFirstUri }, new Uri[] { mSecondUri}) };
    407         kTestEnvironment.setExpectedExecutions(1);
    408         kTestEnvironment.setExpectedWork(work);
    409         JobInfo ji = mBuilder.setOverrideDeadline(0).setRequiresStorageNotLow(true).build();
    410         mJobScheduler.enqueue(ji, new JobWorkItem(work1));
    411         mJobScheduler.enqueue(ji, new JobWorkItem(work2));
    412 
    413         // Remove the explicit grant, we should still have a grant due to the job.
    414         mProvider.call("revoke", MY_PACKAGE, mFirstUriBundle);
    415         mProvider.call("revoke", MY_PACKAGE, mSecondUriBundle);
    416         assertHasUriPermission(mFirstUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
    417                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    418         assertHasUriPermission(mSecondUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
    419                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    420 
    421         kTestEnvironment.readyToWork();
    422 
    423         // Now allow the job to run.
    424         setStorageState(false);
    425 
    426         assertTrue("Job with work enqueued did not fire.",
    427                 kTestEnvironment.awaitExecution());
    428         compareWork(work, kTestEnvironment.getLastReceivedWork());
    429 
    430         // And wait for everything to be cleaned up.
    431         waitPermissionRevoke(mFirstUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 5000);
    432         waitPermissionRevoke(mSecondUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 5000);
    433     }
    434 
    435     private static int getCurrentUser() {
    436         return android.os.Process.myUserHandle().getIdentifier();
    437     }
    438 }
    439