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