101ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williamspackage com.android.server.job; 23d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 3d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; 43ec36ef2af10558a0a94aa56331ce16bc6b18914Pavel Maltsevimport static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; 5d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport static android.net.NetworkCapabilities.TRANSPORT_WIFI; 6d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 7d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport static org.junit.Assert.assertEquals; 8d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport static org.junit.Assert.assertTrue; 9d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport static org.junit.Assert.fail; 109252b34065809731ea2f6d3ffad91f678f809c93Jeff Sharkeyimport static org.mockito.ArgumentMatchers.anyString; 119252b34065809731ea2f6d3ffad91f678f809c93Jeff Sharkeyimport static org.mockito.Mockito.mock; 129252b34065809731ea2f6d3ffad91f678f809c93Jeff Sharkeyimport static org.mockito.Mockito.when; 133d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 147060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport android.app.job.JobInfo; 157060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport android.app.job.JobInfo.Builder; 16d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport android.content.ComponentName; 17d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport android.content.Context; 189252b34065809731ea2f6d3ffad91f678f809c93Jeff Sharkeyimport android.content.pm.PackageManagerInternal; 19d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport android.net.NetworkRequest; 209252b34065809731ea2f6d3ffad91f678f809c93Jeff Sharkeyimport android.os.Build; 21d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport android.os.Parcel; 22d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport android.os.Parcelable; 233d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williamsimport android.os.PersistableBundle; 24fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williamsimport android.os.SystemClock; 25d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport android.support.test.InstrumentationRegistry; 26d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport android.support.test.runner.AndroidJUnit4; 273d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williamsimport android.test.RenamingDelegatingContext; 283d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williamsimport android.util.Log; 29616541d7016ee4440051738a8f0c7c3b7086d375Christopher Tateimport android.util.Pair; 303d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 31d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport com.android.internal.util.HexDump; 32d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport com.android.server.IoThread; 339252b34065809731ea2f6d3ffad91f678f809c93Jeff Sharkeyimport com.android.server.LocalServices; 342f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tateimport com.android.server.job.JobStore.JobSet; 357060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tateimport com.android.server.job.controllers.JobStatus; 363d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 37d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport org.junit.After; 38d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport org.junit.Before; 39d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport org.junit.Test; 40d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport org.junit.runner.RunWith; 41d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 42d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport java.time.Clock; 43d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport java.time.ZoneOffset; 44d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport java.util.Arrays; 4501ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williamsimport java.util.Iterator; 46d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport java.util.concurrent.CountDownLatch; 47d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeyimport java.util.concurrent.TimeUnit; 483d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 493d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams/** 503d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams * Test reading and writing correctly from file. 5115407846682b269e6b7fd0c24b84f709257fab5dMakoto Onuki * 5215407846682b269e6b7fd0c24b84f709257fab5dMakoto Onuki * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java 533d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams */ 54d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey@RunWith(AndroidJUnit4.class) 55d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkeypublic class JobStoreTest { 563d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams private static final String TAG = "TaskStoreTest"; 573d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams private static final String TEST_PREFIX = "_test_"; 5801ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams 59d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey private static final int SOME_UID = android.os.Process.FIRST_APPLICATION_UID; 603d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams private ComponentName mComponent; 613d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 627060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate JobStore mTaskStoreUnderTest; 633d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams Context mTestContext; 643d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 65d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey private Context getContext() { 66d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey return InstrumentationRegistry.getContext(); 67d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey } 68d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 69d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey @Before 703d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams public void setUp() throws Exception { 713d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams mTestContext = new RenamingDelegatingContext(getContext(), TEST_PREFIX); 723d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams Log.d(TAG, "Saving tasks to '" + mTestContext.getFilesDir() + "'"); 7301ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams mTaskStoreUnderTest = 7401ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams JobStore.initAndGetForTesting(mTestContext, mTestContext.getFilesDir()); 753d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams mComponent = new ComponentName(getContext().getPackageName(), StubClass.class.getName()); 76d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 779252b34065809731ea2f6d3ffad91f678f809c93Jeff Sharkey // Assume all packages are current SDK 789252b34065809731ea2f6d3ffad91f678f809c93Jeff Sharkey final PackageManagerInternal pm = mock(PackageManagerInternal.class); 799252b34065809731ea2f6d3ffad91f678f809c93Jeff Sharkey when(pm.getPackageTargetSdkVersion(anyString())) 809252b34065809731ea2f6d3ffad91f678f809c93Jeff Sharkey .thenReturn(Build.VERSION_CODES.CUR_DEVELOPMENT); 819252b34065809731ea2f6d3ffad91f678f809c93Jeff Sharkey LocalServices.removeServiceForTest(PackageManagerInternal.class); 829252b34065809731ea2f6d3ffad91f678f809c93Jeff Sharkey LocalServices.addService(PackageManagerInternal.class, pm); 839252b34065809731ea2f6d3ffad91f678f809c93Jeff Sharkey 84d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey // Freeze the clocks at this moment in time 85d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey JobSchedulerService.sSystemClock = 86d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC); 87d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey JobSchedulerService.sUptimeMillisClock = 88d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey Clock.fixed(SystemClock.uptimeMillisClock().instant(), ZoneOffset.UTC); 89d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey JobSchedulerService.sElapsedRealtimeClock = 90d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC); 913d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams } 923d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 93d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey @After 943d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams public void tearDown() throws Exception { 953d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams mTaskStoreUnderTest.clear(); 963d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams } 973d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 98d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey private void waitForPendingIo() throws Exception { 99d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey final CountDownLatch latch = new CountDownLatch(1); 100d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey IoThread.getHandler().post(() -> { 101d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey latch.countDown(); 102d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey }); 103d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey latch.await(10, TimeUnit.SECONDS); 104d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey } 105d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 106d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey @Test 1073d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams public void testMaybeWriteStatusToDisk() throws Exception { 1083d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams int taskId = 5; 1093d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams long runByMillis = 20000L; // 20s 1103d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams long runFromMillis = 2000L; // 2s 1113d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams long initialBackoff = 10000L; // 10s 1123d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 1137060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate final JobInfo task = new Builder(taskId, mComponent) 1143d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams .setRequiresCharging(true) 115d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) 116d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams .setBackoffCriteria(initialBackoff, JobInfo.BACKOFF_POLICY_EXPONENTIAL) 1173d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams .setOverrideDeadline(runByMillis) 1183d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams .setMinimumLatency(runFromMillis) 119d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams .setPersisted(true) 1203d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams .build(); 1211085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn final JobStatus ts = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null); 12215407846682b269e6b7fd0c24b84f709257fab5dMakoto Onuki ts.addInternalFlags(JobStatus.INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION); 1233d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams mTaskStoreUnderTest.add(ts); 124d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey waitForPendingIo(); 125d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 1263d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams // Manually load tasks from xml file. 1272f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate final JobSet jobStatusSet = new JobSet(); 128616541d7016ee4440051738a8f0c7c3b7086d375Christopher Tate mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); 12901ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams 13001ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams assertEquals("Didn't get expected number of persisted tasks.", 1, jobStatusSet.size()); 1312f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate final JobStatus loadedTaskStatus = jobStatusSet.getAllJobs().get(0); 13201ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams assertTasksEqual(task, loadedTaskStatus.getJob()); 13348a30db75dd0eedf8e065c89825b2af86a381b62Matthew Williams assertTrue("JobStore#contains invalid.", mTaskStoreUnderTest.containsJob(ts)); 13401ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams assertEquals("Different uids.", SOME_UID, loadedTaskStatus.getUid()); 13515407846682b269e6b7fd0c24b84f709257fab5dMakoto Onuki assertEquals(JobStatus.INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION, 13615407846682b269e6b7fd0c24b84f709257fab5dMakoto Onuki loadedTaskStatus.getInternalFlags()); 13701ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams compareTimestampsSubjectToIoLatency("Early run-times not the same after read.", 13801ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams ts.getEarliestRunTime(), loadedTaskStatus.getEarliestRunTime()); 13901ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams compareTimestampsSubjectToIoLatency("Late run-times not the same after read.", 14001ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams ts.getLatestRunTimeElapsed(), loadedTaskStatus.getLatestRunTimeElapsed()); 1413d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams } 1423d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 143d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey @Test 1443d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams public void testWritingTwoFilesToDisk() throws Exception { 1457060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate final JobInfo task1 = new Builder(8, mComponent) 1463d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams .setRequiresDeviceIdle(true) 1473d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams .setPeriodic(10000L) 1483d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams .setRequiresCharging(true) 149d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams .setPersisted(true) 1503d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams .build(); 1517060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate final JobInfo task2 = new Builder(12, mComponent) 1523d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams .setMinimumLatency(5000L) 153d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams .setBackoffCriteria(15000L, JobInfo.BACKOFF_POLICY_LINEAR) 1543d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams .setOverrideDeadline(30000L) 155d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) 156d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams .setPersisted(true) 1573d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams .build(); 1581085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn final JobStatus taskStatus1 = JobStatus.createFromJobInfo(task1, SOME_UID, null, -1, null); 1591085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn final JobStatus taskStatus2 = JobStatus.createFromJobInfo(task2, SOME_UID, null, -1, null); 1603d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams mTaskStoreUnderTest.add(taskStatus1); 1613d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams mTaskStoreUnderTest.add(taskStatus2); 162d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey waitForPendingIo(); 16301ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams 1642f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate final JobSet jobStatusSet = new JobSet(); 165616541d7016ee4440051738a8f0c7c3b7086d375Christopher Tate mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); 16601ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams assertEquals("Incorrect # of persisted tasks.", 2, jobStatusSet.size()); 1672f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate Iterator<JobStatus> it = jobStatusSet.getAllJobs().iterator(); 16801ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams JobStatus loaded1 = it.next(); 16901ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams JobStatus loaded2 = it.next(); 170fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams 171fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams // Reverse them so we know which comparison to make. 172fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams if (loaded1.getJobId() != 8) { 173fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams JobStatus tmp = loaded1; 174fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams loaded1 = loaded2; 175fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams loaded2 = tmp; 176fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams } 177fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams 17801ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams assertTasksEqual(task1, loaded1.getJob()); 17901ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams assertTasksEqual(task2, loaded2.getJob()); 18048a30db75dd0eedf8e065c89825b2af86a381b62Matthew Williams assertTrue("JobStore#contains invalid.", mTaskStoreUnderTest.containsJob(taskStatus1)); 18148a30db75dd0eedf8e065c89825b2af86a381b62Matthew Williams assertTrue("JobStore#contains invalid.", mTaskStoreUnderTest.containsJob(taskStatus2)); 18201ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams // Check that the loaded task has the correct runtimes. 18301ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams compareTimestampsSubjectToIoLatency("Early run-times not the same after read.", 18401ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams taskStatus1.getEarliestRunTime(), loaded1.getEarliestRunTime()); 18501ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams compareTimestampsSubjectToIoLatency("Late run-times not the same after read.", 18601ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams taskStatus1.getLatestRunTimeElapsed(), loaded1.getLatestRunTimeElapsed()); 18701ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams compareTimestampsSubjectToIoLatency("Early run-times not the same after read.", 18801ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams taskStatus2.getEarliestRunTime(), loaded2.getEarliestRunTime()); 18901ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams compareTimestampsSubjectToIoLatency("Late run-times not the same after read.", 19001ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams taskStatus2.getLatestRunTimeElapsed(), loaded2.getLatestRunTimeElapsed()); 1913d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams } 1923d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 193d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey @Test 1943d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams public void testWritingTaskWithExtras() throws Exception { 1957060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate JobInfo.Builder b = new Builder(8, mComponent) 1963d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams .setRequiresDeviceIdle(true) 1973d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams .setPeriodic(10000L) 198900c67fc51fc2672458dd1c9641250f2ecc01a31Matthew Williams .setRequiresCharging(true) 199d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams .setPersisted(true); 2003d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 2013d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams PersistableBundle extras = new PersistableBundle(); 2023d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams extras.putDouble("hello", 3.2); 2033d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams extras.putString("hi", "there"); 2043d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams extras.putInt("into", 3); 2053d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams b.setExtras(extras); 2067060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate final JobInfo task = b.build(); 2071085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn JobStatus taskStatus = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null); 2083d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 2093d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams mTaskStoreUnderTest.add(taskStatus); 210d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey waitForPendingIo(); 2113d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 2122f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate final JobSet jobStatusSet = new JobSet(); 213616541d7016ee4440051738a8f0c7c3b7086d375Christopher Tate mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); 21401ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); 2152f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); 21601ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams assertTasksEqual(task, loaded.getJob()); 2173d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams } 218d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 219d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey @Test 2208e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge public void testWritingTaskWithSourcePackage() throws Exception { 2218e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge JobInfo.Builder b = new Builder(8, mComponent) 2228e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge .setRequiresDeviceIdle(true) 2238e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge .setPeriodic(10000L) 2248e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge .setRequiresCharging(true) 2258e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge .setPersisted(true); 226b0001f6fb1383d9824c2733896b0b348e7f77240Dianne Hackborn JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, 2271085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn "com.google.android.gms", 0, null); 2288e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge 2298e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge mTaskStoreUnderTest.add(taskStatus); 230d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey waitForPendingIo(); 2318e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge 2322f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate final JobSet jobStatusSet = new JobSet(); 233616541d7016ee4440051738a8f0c7c3b7086d375Christopher Tate mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); 2348e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); 2352f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); 2368e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge assertEquals("Source package not equal.", loaded.getSourcePackageName(), 2378e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge taskStatus.getSourcePackageName()); 2388e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge assertEquals("Source user not equal.", loaded.getSourceUserId(), 2398e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge taskStatus.getSourceUserId()); 2408e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge } 2418e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge 242d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey @Test 2438e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge public void testWritingTaskWithFlex() throws Exception { 2448e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge JobInfo.Builder b = new Builder(8, mComponent) 2458e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge .setRequiresDeviceIdle(true) 2468e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge .setPeriodic(5*60*60*1000, 1*60*60*1000) 2478e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge .setRequiresCharging(true) 2488e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge .setPersisted(true); 2491085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null); 2508e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge 2518e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge mTaskStoreUnderTest.add(taskStatus); 252d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey waitForPendingIo(); 2538e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge 2542f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate final JobSet jobStatusSet = new JobSet(); 255616541d7016ee4440051738a8f0c7c3b7086d375Christopher Tate mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); 2568e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); 2572f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); 2588e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge assertEquals("Period not equal.", loaded.getJob().getIntervalMillis(), 2598e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge taskStatus.getJob().getIntervalMillis()); 2608e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge assertEquals("Flex not equal.", loaded.getJob().getFlexMillis(), 2618e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge taskStatus.getJob().getFlexMillis()); 2628e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge } 2633d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 264d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey @Test 265fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams public void testMassivePeriodClampedOnRead() throws Exception { 2668e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge final long ONE_HOUR = 60*60*1000L; // flex 2678e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge final long TWO_HOURS = 2 * ONE_HOUR; // period 268fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams JobInfo.Builder b = new Builder(8, mComponent) 2698e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge .setPeriodic(TWO_HOURS, ONE_HOUR) 270fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams .setPersisted(true); 271616541d7016ee4440051738a8f0c7c3b7086d375Christopher Tate final long rtcNow = System.currentTimeMillis(); 272fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams final long invalidLateRuntimeElapsedMillis = 2738e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge SystemClock.elapsedRealtime() + (TWO_HOURS * ONE_HOUR) + TWO_HOURS; // > period+flex 274fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams final long invalidEarlyRuntimeElapsedMillis = 2758e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge invalidLateRuntimeElapsedMillis - TWO_HOURS; // Early is (late - period). 276616541d7016ee4440051738a8f0c7c3b7086d375Christopher Tate final Pair<Long, Long> persistedExecutionTimesUTC = new Pair<>(rtcNow, rtcNow + ONE_HOUR); 277b0001f6fb1383d9824c2733896b0b348e7f77240Dianne Hackborn final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage", 278a732f014c5743af0dbb7eb2e63474a7147576f9dChristopher Tate 0 /* sourceUserId */, 0, 0, "someTag", 279ab8a67fa78fc8e03ae8eb73d633d3e5e70867f02Makoto Onuki invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis, 280616541d7016ee4440051738a8f0c7c3b7086d375Christopher Tate 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */, 28115407846682b269e6b7fd0c24b84f709257fab5dMakoto Onuki persistedExecutionTimesUTC, 0 /* innerFlagg */); 282fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams 283fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams mTaskStoreUnderTest.add(js); 284d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey waitForPendingIo(); 285fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams 2862f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate final JobSet jobStatusSet = new JobSet(); 287616541d7016ee4440051738a8f0c7c3b7086d375Christopher Tate mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); 288fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); 2892f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); 290fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams 291fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams // Assert early runtime was clamped to be under now + period. We can do <= here b/c we'll 292fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams // call SystemClock.elapsedRealtime after doing the disk i/o. 293fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams final long newNowElapsed = SystemClock.elapsedRealtime(); 294fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams assertTrue("Early runtime wasn't correctly clamped.", 2958e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge loaded.getEarliestRunTime() <= newNowElapsed + TWO_HOURS); 2968e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge // Assert late runtime was clamped to be now + period + flex. 297fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams assertTrue("Early runtime wasn't correctly clamped.", 2988e64e2e6a4d2964b6a4147f5cccd03de934c86cdShreyas Basarge loaded.getEarliestRunTime() <= newNowElapsed + TWO_HOURS + ONE_HOUR); 2995db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge } 3005db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge 301d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey @Test 3025db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge public void testPriorityPersisted() throws Exception { 3035db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge JobInfo.Builder b = new Builder(92, mComponent) 3045db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge .setOverrideDeadline(5000) 3055db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge .setPriority(42) 3065db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge .setPersisted(true); 3071085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null); 3085db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge mTaskStoreUnderTest.add(js); 309d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey waitForPendingIo(); 310d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 3112f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate final JobSet jobStatusSet = new JobSet(); 312616541d7016ee4440051738a8f0c7c3b7086d375Christopher Tate mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); 3132f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); 3145db09084c8e4efc6311754243c39962fc8e7a766Shreyas Basarge assertEquals("Priority not correctly persisted.", 42, loaded.getPriority()); 315fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams } 316fa8e5084eed63ab8d92c71fcff656690a30293c3Matthew Williams 3173d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams /** 3187ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge * Test that non persisted job is not written to disk. 3197ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge */ 320d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey @Test 3217ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge public void testNonPersistedTaskIsNotPersisted() throws Exception { 3227ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge JobInfo.Builder b = new Builder(42, mComponent) 3237ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge .setOverrideDeadline(10000) 3247ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge .setPersisted(false); 3251085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn JobStatus jsNonPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null); 3267ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge mTaskStoreUnderTest.add(jsNonPersisted); 3277ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge b = new Builder(43, mComponent) 3287ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge .setOverrideDeadline(10000) 3297ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge .setPersisted(true); 3301085ff6ee531931ef7f55cbadbc83616f619b292Dianne Hackborn JobStatus jsPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null); 3317ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge mTaskStoreUnderTest.add(jsPersisted); 332d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey waitForPendingIo(); 333d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 3342f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate final JobSet jobStatusSet = new JobSet(); 335616541d7016ee4440051738a8f0c7c3b7086d375Christopher Tate mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); 3367ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge assertEquals("Job count is incorrect.", 1, jobStatusSet.size()); 3372f36fd6fc94b62b8ccd03cdcea89826d05414f93Christopher Tate JobStatus jobStatus = jobStatusSet.getAllJobs().iterator().next(); 3387ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge assertEquals("Wrong job persisted.", 43, jobStatus.getJobId()); 3397ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge } 3407ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge 341d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey @Test 342d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey public void testRequiredNetworkType() throws Exception { 343d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey assertPersistedEquals(new JobInfo.Builder(0, mComponent) 344d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setPersisted(true) 345d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setRequiresDeviceIdle(true) 346d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE).build()); 347d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey assertPersistedEquals(new JobInfo.Builder(0, mComponent) 348d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setPersisted(true) 349d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build()); 350d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey assertPersistedEquals(new JobInfo.Builder(0, mComponent) 351d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setPersisted(true) 352d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED).build()); 353d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey assertPersistedEquals(new JobInfo.Builder(0, mComponent) 354d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setPersisted(true) 355d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NOT_ROAMING).build()); 356d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey assertPersistedEquals(new JobInfo.Builder(0, mComponent) 357d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setPersisted(true) 358d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setRequiredNetworkType(JobInfo.NETWORK_TYPE_CELLULAR).build()); 359d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey } 360d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 361d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey @Test 362d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey public void testRequiredNetwork() throws Exception { 363d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey assertPersistedEquals(new JobInfo.Builder(0, mComponent) 364d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setPersisted(true) 365d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setRequiresDeviceIdle(true) 366d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setRequiredNetwork(null).build()); 367d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey assertPersistedEquals(new JobInfo.Builder(0, mComponent) 368d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setPersisted(true) 369d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setRequiredNetwork(new NetworkRequest.Builder().build()).build()); 370d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey assertPersistedEquals(new JobInfo.Builder(0, mComponent) 371d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setPersisted(true) 372d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setRequiredNetwork(new NetworkRequest.Builder() 373d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .addTransportType(TRANSPORT_WIFI).build()) 374d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .build()); 375d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey assertPersistedEquals(new JobInfo.Builder(0, mComponent) 376d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setPersisted(true) 377d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .setRequiredNetwork(new NetworkRequest.Builder() 3783ec36ef2af10558a0a94aa56331ce16bc6b18914Pavel Maltsev .addCapability(NET_CAPABILITY_IMS) 3793ec36ef2af10558a0a94aa56331ce16bc6b18914Pavel Maltsev .addUnwantedCapability(NET_CAPABILITY_OEM_PAID) 3803ec36ef2af10558a0a94aa56331ce16bc6b18914Pavel Maltsev .build()) 381d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey .build()); 382d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey } 383d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 384d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey /** 385d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey * Helper function to kick a {@link JobInfo} through a persistence cycle and 386d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey * assert that it's unchanged. 387d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey */ 388d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey private void assertPersistedEquals(JobInfo first) throws Exception { 389d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey mTaskStoreUnderTest.clear(); 390d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey mTaskStoreUnderTest.add(JobStatus.createFromJobInfo(first, SOME_UID, null, -1, null)); 391d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey waitForPendingIo(); 392d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 393d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey final JobSet jobStatusSet = new JobSet(); 394d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); 395d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey final JobStatus second = jobStatusSet.getAllJobs().iterator().next(); 396d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey assertTasksEqual(first, second.getJob()); 397d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey } 398d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 3997ef490fab68ee93f92eb5728cc4d3cb691315412Shreyas Basarge /** 4003d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams * Helper function to throw an error if the provided task and TaskStatus objects are not equal. 4013d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams */ 4027060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate private void assertTasksEqual(JobInfo first, JobInfo second) { 4033d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams assertEquals("Different task ids.", first.getId(), second.getId()); 4043d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams assertEquals("Different components.", first.getService(), second.getService()); 4053d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams assertEquals("Different periodic status.", first.isPeriodic(), second.isPeriodic()); 4063d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams assertEquals("Different period.", first.getIntervalMillis(), second.getIntervalMillis()); 4073d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams assertEquals("Different inital backoff.", first.getInitialBackoffMillis(), 4083d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams second.getInitialBackoffMillis()); 4093d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams assertEquals("Different backoff policy.", first.getBackoffPolicy(), 4103d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams second.getBackoffPolicy()); 4113d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 4123d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams assertEquals("Invalid charging constraint.", first.isRequireCharging(), 4133d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams second.isRequireCharging()); 414a06ec6a9435f9555142e700f54cf20278bc1982fDianne Hackborn assertEquals("Invalid battery not low constraint.", first.isRequireBatteryNotLow(), 415a06ec6a9435f9555142e700f54cf20278bc1982fDianne Hackborn second.isRequireBatteryNotLow()); 4163d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams assertEquals("Invalid idle constraint.", first.isRequireDeviceIdle(), 4173d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams second.isRequireDeviceIdle()); 418d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey assertEquals("Invalid network type.", 419d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey first.getNetworkType(), second.getNetworkType()); 420d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey assertEquals("Invalid network.", 421d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey first.getRequiredNetwork(), second.getRequiredNetwork()); 4223d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams assertEquals("Invalid deadline constraint.", 4233d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams first.hasLateConstraint(), 4243d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams second.hasLateConstraint()); 4253d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams assertEquals("Invalid delay constraint.", 4263d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams first.hasEarlyConstraint(), 4273d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams second.hasEarlyConstraint()); 4283d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams assertEquals("Extras don't match", 4293d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams first.getExtras().toString(), second.getExtras().toString()); 430ba60473a6539d16bef8720d79b5559512303bddfDianne Hackborn assertEquals("Transient xtras don't match", 431ba60473a6539d16bef8720d79b5559512303bddfDianne Hackborn first.getTransientExtras().toString(), second.getTransientExtras().toString()); 432d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 433d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey // Since people can forget to add tests here for new fields, do one last 434d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey // sanity check based on bits-on-wire equality. 435d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey final byte[] firstBytes = marshall(first); 436d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey final byte[] secondBytes = marshall(second); 437d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey if (!Arrays.equals(firstBytes, secondBytes)) { 438d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey Log.w(TAG, "First: " + HexDump.dumpHexString(firstBytes)); 439d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey Log.w(TAG, "Second: " + HexDump.dumpHexString(secondBytes)); 440d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey fail("Raw JobInfo aren't equal; see logs for details"); 441d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey } 442d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey } 443d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey 444d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey private static byte[] marshall(Parcelable p) { 445d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey final Parcel parcel = Parcel.obtain(); 446d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey try { 447d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey p.writeToParcel(parcel, 0); 448d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey return parcel.marshall(); 449d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey } finally { 450d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey parcel.recycle(); 451d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey } 4523d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams } 4533d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 4543d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams /** 4553d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams * When comparing timestamps before and after DB read/writes (to make sure we're saving/loading 4563d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams * the correct values), there is some latency involved that terrorises a naive assertEquals(). 4573d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams * We define a <code>DELTA_MILLIS</code> as a function variable here to make this comparision 4583d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams * more reasonable. 4593d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams */ 4603d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams private void compareTimestampsSubjectToIoLatency(String error, long ts1, long ts2) { 4613d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams final long DELTA_MILLIS = 700L; // We allow up to 700ms of latency for IO read/writes. 462d0fff2eac4fe878071dd170e885a4a9c0a1b20e8Jeff Sharkey assertTrue(error, Math.abs(ts1 - ts2) < DELTA_MILLIS); 4633d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams } 4643d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 4653d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams private static class StubClass {} 4663d86fd2bb9db6067c49634bc4c6cdb4d5235ad36Matthew Williams 46701ac45b6ff2334925c8d24b5278b44e5e30f5622Matthew Williams} 468