1/*
2 * Copyright (C) 2017 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
17package com.android.server.timezone;
18
19import org.hamcrest.BaseMatcher;
20import org.hamcrest.Description;
21import org.hamcrest.Matcher;
22import org.junit.After;
23import org.junit.Before;
24import org.junit.Test;
25
26import android.app.timezone.RulesUpdaterContract;
27import android.content.Context;
28import android.content.Intent;
29import android.provider.TimeZoneRulesDataContract;
30import android.support.test.InstrumentationRegistry;
31import android.support.test.filters.SmallTest;
32
33import java.io.File;
34import java.io.PrintWriter;
35import java.io.StringWriter;
36import java.time.Clock;
37import java.time.Instant;
38import java.time.ZoneId;
39
40import static org.junit.Assert.assertEquals;
41import static org.junit.Assert.assertFalse;
42import static org.junit.Assert.assertNotNull;
43import static org.junit.Assert.assertNull;
44import static org.junit.Assert.assertTrue;
45import static org.junit.Assert.fail;
46import static org.mockito.Mockito.eq;
47import static org.mockito.Mockito.mock;
48import static org.mockito.Mockito.when;
49import static org.mockito.hamcrest.MockitoHamcrest.argThat;
50
51/**
52 * White box interaction / unit testing of the {@link PackageTracker}.
53 */
54@SmallTest
55public class PackageTrackerTest {
56    private static final String UPDATE_APP_PACKAGE_NAME = "updateAppPackageName";
57    private static final String DATA_APP_PACKAGE_NAME = "dataAppPackageName";
58    private static final PackageVersions INITIAL_APP_PACKAGE_VERSIONS =
59            new PackageVersions(2 /* updateAppVersion */, 2 /* dataAppVersion */);
60
61    private ConfigHelper mMockConfigHelper;
62    private PackageManagerHelper mMockPackageManagerHelper;
63
64    private FakeClock mFakeClock;
65    private FakeIntentHelper mFakeIntentHelper;
66    private PackageStatusStorage mPackageStatusStorage;
67    private PackageTracker mPackageTracker;
68
69    @Before
70    public void setUp() throws Exception {
71        Context context = InstrumentationRegistry.getContext();
72
73        mFakeClock = new FakeClock();
74
75        // Read-only interfaces so are easy to mock.
76        mMockConfigHelper = mock(ConfigHelper.class);
77        mMockPackageManagerHelper = mock(PackageManagerHelper.class);
78
79        // Using the instrumentation context means the database is created in a test app-specific
80        // directory. We can use the real thing for this test.
81        mPackageStatusStorage = new PackageStatusStorage(context.getFilesDir());
82
83        // For other interactions with the Android framework we create a fake object.
84        mFakeIntentHelper = new FakeIntentHelper();
85
86        // Create the PackageTracker to use in tests.
87        mPackageTracker = new PackageTracker(
88                mFakeClock,
89                mMockConfigHelper,
90                mMockPackageManagerHelper,
91                mPackageStatusStorage,
92                mFakeIntentHelper);
93    }
94
95    @After
96    public void tearDown() throws Exception {
97        if (mPackageStatusStorage != null) {
98            mPackageStatusStorage.deleteFileForTests();
99        }
100    }
101
102    @Test
103    public void trackingDisabled_intentHelperNotUsed() {
104        // Set up device configuration.
105        configureTrackingDisabled();
106
107        // Initialize the tracker.
108        assertFalse(mPackageTracker.start());
109
110        // Check the IntentHelper was not initialized.
111        mFakeIntentHelper.assertNotInitialized();
112
113        // Check reliability triggering state.
114        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
115    }
116
117    @Test
118    public void trackingDisabled_triggerUpdateIfNeededNotAllowed() {
119        // Set up device configuration.
120        configureTrackingDisabled();
121
122        // Initialize the tracker.
123        assertFalse(mPackageTracker.start());
124
125        // Check reliability triggering state.
126        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
127
128        try {
129            // This call should also not be allowed and will throw an exception if tracking is
130            // disabled.
131            mPackageTracker.triggerUpdateIfNeeded(true);
132            fail();
133        } catch (IllegalStateException expected) {}
134
135        // Check reliability triggering state.
136        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
137    }
138
139    @Test
140    public void trackingDisabled_unsolicitedResultsIgnored_withoutToken() {
141        // Set up device configuration.
142        configureTrackingDisabled();
143
144        // Initialize the tracker.
145        assertFalse(mPackageTracker.start());
146
147        // Check reliability triggering state.
148        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
149
150        // Receiving a check result when tracking is disabled should cause the storage to be
151        // reset.
152        mPackageTracker.recordCheckResult(null /* checkToken */, true /* success */);
153
154        // Check reliability triggering state.
155        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
156
157        // Assert the storage was reset.
158        checkPackageStorageStatusIsInitialOrReset();
159    }
160
161    @Test
162    public void trackingDisabled_unsolicitedResultsIgnored_withToken() {
163        // Set up device configuration.
164        configureTrackingDisabled();
165
166        // Set the storage into an arbitrary state so we can detect a reset.
167        mPackageStatusStorage.generateCheckToken(INITIAL_APP_PACKAGE_VERSIONS);
168
169        // Initialize the tracker.
170        assertFalse(mPackageTracker.start());
171
172        // Check reliability triggering state.
173        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
174
175        // Receiving a check result when tracking is disabled should cause the storage to be reset.
176        mPackageTracker.recordCheckResult(createArbitraryCheckToken(), true /* success */);
177
178        // Check reliability triggering state.
179        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
180
181        // Assert the storage was reset.
182        checkPackageStorageStatusIsInitialOrReset();
183    }
184
185    @Test
186    public void trackingEnabled_updateAppConfigMissing() throws Exception {
187        // Set up device configuration.
188        configureTrackingEnabled();
189        configureReliabilityConfigSettingsOk();
190        configureUpdateAppPackageNameMissing();
191        configureDataAppPackageOk(DATA_APP_PACKAGE_NAME);
192
193        try {
194            // Initialize the tracker.
195            mPackageTracker.start();
196            fail();
197        } catch (RuntimeException expected) {}
198
199        mFakeIntentHelper.assertNotInitialized();
200
201        // Check reliability triggering state.
202        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
203    }
204
205    @Test
206    public void trackingEnabled_updateAppNotPrivileged() throws Exception {
207        // Set up device configuration.
208        configureTrackingEnabled();
209        configureReliabilityConfigSettingsOk();
210        configureUpdateAppPackageNotPrivileged(UPDATE_APP_PACKAGE_NAME);
211        configureDataAppPackageOk(DATA_APP_PACKAGE_NAME);
212
213        try {
214            // Initialize the tracker.
215            mPackageTracker.start();
216            fail();
217        } catch (RuntimeException expected) {}
218
219        mFakeIntentHelper.assertNotInitialized();
220
221        // Check reliability triggering state.
222        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
223    }
224
225    @Test
226    public void trackingEnabled_dataAppConfigMissing() throws Exception {
227        // Set up device configuration.
228        configureTrackingEnabled();
229        configureReliabilityConfigSettingsOk();
230        configureUpdateAppPackageOk(UPDATE_APP_PACKAGE_NAME);
231        configureDataAppPackageNameMissing();
232
233        try {
234            // Initialize the tracker.
235            mPackageTracker.start();
236            fail();
237        } catch (RuntimeException expected) {}
238
239        mFakeIntentHelper.assertNotInitialized();
240
241        // Check reliability triggering state.
242        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
243    }
244
245    @Test
246    public void trackingEnabled_dataAppNotPrivileged() throws Exception {
247        // Set up device configuration.
248        configureTrackingEnabled();
249        configureReliabilityConfigSettingsOk();
250        configureUpdateAppPackageOk(UPDATE_APP_PACKAGE_NAME);
251        configureDataAppPackageNotPrivileged(DATA_APP_PACKAGE_NAME);
252
253        try {
254            // Initialize the tracker.
255            mPackageTracker.start();
256            fail();
257        } catch (RuntimeException expected) {}
258
259        mFakeIntentHelper.assertNotInitialized();
260
261        // Check reliability triggering state.
262        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
263     }
264
265    @Test
266    public void trackingEnabled_storageInitializationFails() throws Exception {
267        // Create a PackageStateStorage that will fail to initialize.
268        PackageStatusStorage packageStatusStorage =
269                new PackageStatusStorage(new File("/system/does/not/exist"));
270
271        // Create a new PackageTracker to use the bad storage.
272        mPackageTracker = new PackageTracker(
273                mFakeClock,
274                mMockConfigHelper,
275                mMockPackageManagerHelper,
276                packageStatusStorage,
277                mFakeIntentHelper);
278
279        // Set up device configuration.
280        configureTrackingEnabled();
281        configureReliabilityConfigSettingsOk();
282        configureValidApplications();
283
284        // Initialize the tracker.
285        assertFalse(mPackageTracker.start());
286
287        // Check the IntentHelper was not initialized.
288        mFakeIntentHelper.assertNotInitialized();
289
290        // Check reliability triggering state.
291        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
292    }
293
294    @Test
295    public void trackingEnabled_packageUpdate_badUpdateAppManifestEntry() throws Exception {
296        // Set up device configuration.
297        configureTrackingEnabled();
298        configureReliabilityConfigSettingsOk();
299        configureValidApplications();
300
301        // Initialize the tracker.
302        assertTrue(mPackageTracker.start());
303
304        // Check the intent helper is properly configured.
305        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
306
307        // Check the initial storage state.
308        checkPackageStorageStatusIsInitialOrReset();
309
310        // Configure a bad manifest for the update app. Should effectively turn off tracking.
311        PackageVersions packageVersions =
312                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
313        configureUpdateAppManifestBad(UPDATE_APP_PACKAGE_NAME);
314        configureDataAppManifestOk(DATA_APP_PACKAGE_NAME);
315        configureUpdateAppPackageVersion(
316                UPDATE_APP_PACKAGE_NAME, packageVersions.mUpdateAppVersion);
317        configureDataAppPackageVersion(DATA_APP_PACKAGE_NAME, packageVersions.mDataAppVersion);
318        // Simulate a tracked package being updated.
319        mFakeIntentHelper.simulatePackageUpdatedEvent();
320
321        // Assert the PackageTracker did not attempt to trigger an update.
322        mFakeIntentHelper.assertUpdateNotTriggered();
323
324        // Check reliability triggering state.
325        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
326
327        // Assert the storage was not touched.
328        checkPackageStorageStatusIsInitialOrReset();
329    }
330
331    @Test
332    public void trackingEnabled_packageUpdate_badDataAppManifestEntry() throws Exception {
333        // Set up device configuration.
334        configureTrackingEnabled();
335        configureReliabilityConfigSettingsOk();
336        configureValidApplications();
337
338        // Initialize the tracker.
339        assertTrue(mPackageTracker.start());
340
341        // Check the intent helper is properly configured.
342        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
343
344        // Check the initial storage state.
345        checkPackageStorageStatusIsInitialOrReset();
346
347        // Configure a bad manifest for the data app. Should effectively turn off tracking.
348        PackageVersions packageVersions =
349                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
350        configureUpdateAppManifestOk(UPDATE_APP_PACKAGE_NAME);
351        configureDataAppManifestBad(DATA_APP_PACKAGE_NAME);
352        configureUpdateAppPackageVersion(
353                UPDATE_APP_PACKAGE_NAME, packageVersions.mUpdateAppVersion);
354        configureDataAppPackageVersion(DATA_APP_PACKAGE_NAME, packageVersions.mDataAppVersion);
355        mFakeIntentHelper.simulatePackageUpdatedEvent();
356
357        // Assert the PackageTracker did not attempt to trigger an update.
358        mFakeIntentHelper.assertUpdateNotTriggered();
359
360        // Check reliability triggering state.
361        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
362
363        // Assert the storage was not touched.
364        checkPackageStorageStatusIsInitialOrReset();
365    }
366
367    @Test
368    public void trackingEnabled_packageUpdate_responseWithToken_success() throws Exception {
369        trackingEnabled_packageUpdate_responseWithToken(true);
370    }
371
372    @Test
373    public void trackingEnabled_packageUpdate_responseWithToken_failed() throws Exception {
374        trackingEnabled_packageUpdate_responseWithToken(false);
375    }
376
377    private void trackingEnabled_packageUpdate_responseWithToken(boolean success) throws Exception {
378        // Set up device configuration.
379        configureTrackingEnabled();
380        configureReliabilityConfigSettingsOk();
381        configureValidApplications();
382
383        // Initialize the tracker.
384        assertTrue(mPackageTracker.start());
385
386        // Check the intent helper is properly configured.
387        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
388
389        // Check the initial storage state.
390        checkPackageStorageStatusIsInitialOrReset();
391
392        // Simulate a tracked package being updated.
393        PackageVersions packageVersions =
394                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
395        simulatePackageInstallation(packageVersions);
396
397        // Confirm an update was triggered.
398        checkUpdateCheckTriggered(packageVersions);
399
400        // Get the token that was passed to the intent helper, and pass it back.
401        CheckToken token = mFakeIntentHelper.captureAndResetLastToken();
402        mPackageTracker.recordCheckResult(token, success);
403
404        // Check storage and reliability triggering state.
405        if (success) {
406            checkUpdateCheckSuccessful(packageVersions);
407        } else {
408            checkUpdateCheckFailed(packageVersions);
409        }
410    }
411
412    @Test
413    public void trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset_success()
414            throws Exception {
415        trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset(true);
416    }
417
418    @Test
419    public void trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset_failed()
420            throws Exception {
421        trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset(false);
422    }
423
424    private void trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset(
425            boolean success) throws Exception {
426        // Set up device configuration.
427        configureTrackingEnabled();
428        configureReliabilityConfigSettingsOk();
429        configureValidApplications();
430
431        // Initialize the tracker.
432        assertTrue(mPackageTracker.start());
433
434        // Check the intent helper is properly configured.
435        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
436
437        // Check the initial storage state.
438        checkPackageStorageStatusIsInitialOrReset();
439
440        // Set up installed app versions / manifests.
441        PackageVersions packageVersions =
442                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
443        simulatePackageInstallation(packageVersions);
444
445        // Confirm an update was triggered.
446        checkUpdateCheckTriggered(packageVersions);
447
448        // Ignore the token that was given to the intent helper, just pass null.
449        mPackageTracker.recordCheckResult(null /* checkToken */, success);
450
451        // Check reliability triggering state.
452        mFakeIntentHelper.assertReliabilityTriggerScheduled();
453
454        // Assert the storage was reset.
455        checkPackageStorageStatusIsInitialOrReset();
456    }
457
458    /**
459     * Two package updates triggered for the same package versions. The second is triggered while
460     * the first is still happening.
461     */
462    @Test
463    public void trackingEnabled_packageUpdate_twoChecksNoPackageChange_secondWhileFirstInProgress()
464            throws Exception {
465        // Set up device configuration.
466        configureTrackingEnabled();
467        configureReliabilityConfigSettingsOk();
468        configureValidApplications();
469
470        // Initialize the tracker.
471        assertTrue(mPackageTracker.start());
472
473        // Check the intent helper is properly configured.
474        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
475
476        // Check the initial storage state.
477        checkPackageStorageStatusIsInitialOrReset();
478
479        // Simulate package installation.
480        PackageVersions packageVersions =
481                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
482        simulatePackageInstallation(packageVersions);
483
484        // Confirm an update was triggered.
485        checkUpdateCheckTriggered(packageVersions);
486
487        // Get the first token.
488        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
489        assertEquals(packageVersions, token1.mPackageVersions);
490
491        // Now attempt to generate another check while the first is in progress and without having
492        // updated the package versions. The PackageTracker should trigger again for safety.
493        simulatePackageInstallation(packageVersions);
494
495        // Confirm an update was triggered.
496        checkUpdateCheckTriggered(packageVersions);
497
498        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
499        assertEquals(packageVersions, token2.mPackageVersions);
500        assertEquals(token1.mPackageVersions, token2.mPackageVersions);
501        assertTrue(token1.mOptimisticLockId != token2.mOptimisticLockId);
502    }
503
504    /**
505     * Two package updates triggered for the same package versions. The second happens after
506     * the first has succeeded.
507     */
508    @Test
509    public void trackingEnabled_packageUpdate_twoChecksNoPackageChange_sequential()
510            throws Exception {
511        // Set up device configuration.
512        configureTrackingEnabled();
513        configureReliabilityConfigSettingsOk();
514        configureValidApplications();
515
516        // Initialize the tracker.
517        assertTrue(mPackageTracker.start());
518
519        // Check the intent helper is properly configured.
520        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
521
522        // Check the initial storage state.
523        checkPackageStorageStatusIsInitialOrReset();
524
525        // Simulate package installation.
526        PackageVersions packageVersions =
527                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
528        simulatePackageInstallation(packageVersions);
529
530        // Confirm an update was triggered.
531        checkUpdateCheckTriggered(packageVersions);
532
533        // Get the token.
534        CheckToken token = mFakeIntentHelper.captureAndResetLastToken();
535        assertEquals(packageVersions, token.mPackageVersions);
536
537        // Simulate a successful check.
538        mPackageTracker.recordCheckResult(token, true /* success */);
539
540        // Check storage and reliability triggering state.
541        checkUpdateCheckSuccessful(packageVersions);
542
543        // Now attempt to generate another check, but without having updated the package. The
544        // PackageTracker should be smart enough to recognize there's nothing to do here.
545        simulatePackageInstallation(packageVersions);
546
547        // Assert the PackageTracker did not attempt to trigger an update.
548        mFakeIntentHelper.assertUpdateNotTriggered();
549
550        // Check storage and reliability triggering state.
551        checkUpdateCheckSuccessful(packageVersions);
552    }
553
554    /**
555     * Two package updates triggered for the same package versions. The second is triggered after
556     * the first has failed.
557     */
558    @Test
559    public void trackingEnabled_packageUpdate_afterFailure() throws Exception {
560        // Set up device configuration.
561        configureTrackingEnabled();
562        configureReliabilityConfigSettingsOk();
563        configureValidApplications();
564
565        // Initialize the tracker.
566        assertTrue(mPackageTracker.start());
567
568        // Check the intent helper is properly configured.
569        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
570
571        // Check the initial storage state.
572        checkPackageStorageStatusIsInitialOrReset();
573
574        // Simulate package installation.
575        PackageVersions packageVersions =
576                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
577        simulatePackageInstallation(packageVersions);
578
579        // Confirm an update was triggered.
580        checkUpdateCheckTriggered(packageVersions);
581
582        // Get the first token.
583        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
584        assertEquals(packageVersions, token1.mPackageVersions);
585
586        // Simulate an *unsuccessful* check.
587        mPackageTracker.recordCheckResult(token1, false /* success */);
588
589        // Check storage and reliability triggering state.
590        checkUpdateCheckFailed(packageVersions);
591
592        // Now generate another check, but without having updated the package. The
593        // PackageTracker should recognize the last check failed and trigger again.
594        simulatePackageInstallation(packageVersions);
595
596        // Confirm an update was triggered.
597        checkUpdateCheckTriggered(packageVersions);
598
599        // Get the second token.
600        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
601
602        // Assert some things about the tokens.
603        assertEquals(packageVersions, token2.mPackageVersions);
604        assertTrue(token1.mOptimisticLockId != token2.mOptimisticLockId);
605
606        // For completeness, now simulate this check was successful.
607        mPackageTracker.recordCheckResult(token2, true /* success */);
608
609        // Check storage and reliability triggering state.
610        checkUpdateCheckSuccessful(packageVersions);
611    }
612
613    /**
614     * Two package updates triggered for different package versions. The second is triggered while
615     * the first is still happening.
616     */
617    @Test
618    public void trackingEnabled_packageUpdate_twoChecksWithPackageChange_firstCheckInProcess()
619            throws Exception {
620        // Set up device configuration.
621        configureTrackingEnabled();
622        configureReliabilityConfigSettingsOk();
623        configureValidApplications();
624
625        // Initialize the package tracker.
626        assertTrue(mPackageTracker.start());
627
628        // Check the intent helper is properly configured.
629        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
630
631        // Check the initial storage state.
632        checkPackageStorageStatusIsInitialOrReset();
633
634        // Simulate package installation.
635        PackageVersions packageVersions1 =
636                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
637        simulatePackageInstallation(packageVersions1);
638
639        // Confirm an update was triggered.
640        checkUpdateCheckTriggered(packageVersions1);
641
642        // Get the first token.
643        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
644        assertEquals(packageVersions1, token1.mPackageVersions);
645
646        // Simulate a tracked package being updated a second time (before the response for the
647        // first has been received).
648        PackageVersions packageVersions2 =
649                new PackageVersions(3 /* updateAppPackageVersion */, 4 /* dataAppPackageVersion */);
650        simulatePackageInstallation(packageVersions2);
651
652        // Confirm an update was triggered.
653        checkUpdateCheckTriggered(packageVersions2);
654
655        // Get the second token.
656        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
657        assertEquals(packageVersions2, token2.mPackageVersions);
658
659        // token1 should be invalid because the token2 was generated.
660        mPackageTracker.recordCheckResult(token1, true /* success */);
661
662        // Reliability triggering should still be enabled.
663        mFakeIntentHelper.assertReliabilityTriggerScheduled();
664
665        // Check the expected storage state.
666        checkPackageStorageStatus(PackageStatus.CHECK_STARTED, packageVersions2);
667
668        // token2 should still be accepted.
669        mPackageTracker.recordCheckResult(token2, true /* success */);
670
671        // Check storage and reliability triggering state.
672        checkUpdateCheckSuccessful(packageVersions2);
673    }
674
675    /**
676     * Two package updates triggered for different package versions. The second is triggered after
677     * the first has completed successfully.
678     */
679    @Test
680    public void trackingEnabled_packageUpdate_twoChecksWithPackageChange_sequential()
681            throws Exception {
682        // Set up device configuration.
683        configureTrackingEnabled();
684        configureReliabilityConfigSettingsOk();
685        configureValidApplications();
686
687        // Initialize the package tracker.
688        assertTrue(mPackageTracker.start());
689
690        // Check the intent helper is properly configured.
691        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
692
693        // Check the initial storage state.
694        checkPackageStorageStatusIsInitialOrReset();
695
696        // Simulate package installation.
697        PackageVersions packageVersions1 =
698                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
699        simulatePackageInstallation(packageVersions1);
700
701        // Confirm an update was triggered.
702        checkUpdateCheckTriggered(packageVersions1);
703
704        // Get the first token.
705        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
706        assertEquals(packageVersions1, token1.mPackageVersions);
707
708        // token1 should be accepted.
709        mPackageTracker.recordCheckResult(token1, true /* success */);
710
711        // Check storage and reliability triggering state.
712        checkUpdateCheckSuccessful(packageVersions1);
713
714        // Simulate a tracked package being updated a second time.
715        PackageVersions packageVersions2 =
716                new PackageVersions(3 /* updateAppPackageVersion */, 4 /* dataAppPackageVersion */);
717        simulatePackageInstallation(packageVersions2);
718
719        // Confirm an update was triggered.
720        checkUpdateCheckTriggered(packageVersions2);
721
722        // Get the second token.
723        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
724        assertEquals(packageVersions2, token2.mPackageVersions);
725
726        // token2 should still be accepted.
727        mPackageTracker.recordCheckResult(token2, true /* success */);
728
729        // Check storage and reliability triggering state.
730        checkUpdateCheckSuccessful(packageVersions2);
731    }
732
733    /**
734     * Replaying the same token twice.
735     */
736    @Test
737    public void trackingEnabled_packageUpdate_sameTokenReplayFails() throws Exception {
738        // Set up device configuration.
739        configureTrackingEnabled();
740        configureReliabilityConfigSettingsOk();
741        configureValidApplications();
742
743        // Initialize the package tracker.
744        assertTrue(mPackageTracker.start());
745
746        // Check the intent helper is properly configured.
747        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
748
749        // Check the initial storage state.
750        checkPackageStorageStatusIsInitialOrReset();
751
752        // Simulate package installation.
753        PackageVersions packageVersions1 =
754                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
755        simulatePackageInstallation(packageVersions1);
756
757        // Confirm an update was triggered.
758        checkUpdateCheckTriggered(packageVersions1);
759
760        // Get the first token.
761        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
762        assertEquals(packageVersions1, token1.mPackageVersions);
763
764        // token1 should be accepted.
765        mPackageTracker.recordCheckResult(token1, true /* success */);
766
767        // Check storage and reliability triggering state.
768        checkUpdateCheckSuccessful(packageVersions1);
769
770        // Apply token1 again.
771        mPackageTracker.recordCheckResult(token1, true /* success */);
772
773        // Check the expected storage state. No real way to tell if it has been updated, but
774        // we can check the final state is still what it should be.
775        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions1);
776
777        // Under the covers we expect it to fail to update because the storage should recognize that
778        // the token is no longer valid.
779        mFakeIntentHelper.assertReliabilityTriggerScheduled();
780
781        // Peek inside the package tracker to make sure it is tracking failure counts properly.
782        assertEquals(1, mPackageTracker.getCheckFailureCountForTests());
783    }
784
785    @Test
786    public void trackingEnabled_reliabilityTrigger_firstTime_initialStorage() throws Exception {
787        // Set up device configuration.
788        configureTrackingEnabled();
789        configureReliabilityConfigSettingsOk();
790        PackageVersions packageVersions = configureValidApplications();
791
792        // Initialize the package tracker.
793        assertTrue(mPackageTracker.start());
794
795        // Check the intent helper is properly configured.
796        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
797
798        // Check the initial storage state.
799        checkPackageStorageStatusIsInitialOrReset();
800
801        // Simulate a reliability trigger.
802        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
803
804        // Assert the PackageTracker did trigger an update.
805        checkUpdateCheckTriggered(packageVersions);
806
807        // Confirm the token was correct.
808        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
809        assertEquals(packageVersions, token1.mPackageVersions);
810
811        // token1 should be accepted.
812        mPackageTracker.recordCheckResult(token1, true /* success */);
813
814        // Check storage and reliability triggering state.
815        checkUpdateCheckSuccessful(packageVersions);
816    }
817
818    @Test
819    public void trackingEnabled_reliabilityTrigger_afterRebootNoTriggerNeeded() throws Exception {
820        // Set up device configuration.
821        configureTrackingEnabled();
822        configureReliabilityConfigSettingsOk();
823        PackageVersions packageVersions = configureValidApplications();
824
825        // Force the storage into a state we want.
826        mPackageStatusStorage.forceCheckStateForTests(
827                PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
828
829        // Initialize the package tracker.
830        assertTrue(mPackageTracker.start());
831
832        // Check the intent helper is properly configured.
833        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
834
835        // Check the initial storage state.
836        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
837
838        // Simulate a reliability trigger.
839        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
840
841        // Assert the PackageTracker did not attempt to trigger an update.
842        mFakeIntentHelper.assertUpdateNotTriggered();
843
844        // Check storage and reliability triggering state.
845        checkUpdateCheckSuccessful(packageVersions);
846    }
847
848    /**
849     * Simulates the device starting where the storage records do not match the installed app
850     * versions. The reliability trigger should cause the package tracker to perform a check.
851     */
852    @Test
853    public void trackingEnabled_reliabilityTrigger_afterRebootTriggerNeededBecausePreviousFailed()
854            throws Exception {
855        // Set up device configuration.
856        configureTrackingEnabled();
857        configureReliabilityConfigSettingsOk();
858
859        PackageVersions oldPackageVersions = new PackageVersions(1, 1);
860        PackageVersions currentPackageVersions = new PackageVersions(2, 2);
861
862        // Simulate there being a newer version installed than the one recorded in storage.
863        configureValidApplications(currentPackageVersions);
864
865        // Force the storage into a state we want.
866        mPackageStatusStorage.forceCheckStateForTests(
867                PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
868
869        // Initialize the package tracker.
870        assertTrue(mPackageTracker.start());
871
872        // Check the intent helper is properly configured.
873        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
874
875        // Check the initial storage state.
876        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
877
878        // Simulate a reliability trigger.
879        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
880
881        // Assert the PackageTracker did trigger an update.
882        checkUpdateCheckTriggered(currentPackageVersions);
883
884        // Simulate the update check completing successfully.
885        CheckToken checkToken = mFakeIntentHelper.captureAndResetLastToken();
886        mPackageTracker.recordCheckResult(checkToken, true /* success */);
887
888        // Check storage and reliability triggering state.
889        checkUpdateCheckSuccessful(currentPackageVersions);
890    }
891
892    /**
893     * Simulates persistent failures of the reliability check. It should stop after the configured
894     * number of checks.
895     */
896    @Test
897    public void trackingEnabled_reliabilityTrigger_repeatedFailures() throws Exception {
898        // Set up device configuration.
899        configureTrackingEnabled();
900
901        int retriesAllowed = 3;
902        int checkDelayMillis = 5 * 60 * 1000;
903        configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
904
905        PackageVersions oldPackageVersions = new PackageVersions(1, 1);
906        PackageVersions currentPackageVersions = new PackageVersions(2, 2);
907
908        // Simulate there being a newer version installed than the one recorded in storage.
909        configureValidApplications(currentPackageVersions);
910
911        // Force the storage into a state we want.
912        mPackageStatusStorage.forceCheckStateForTests(
913                PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
914
915        // Initialize the package tracker.
916        assertTrue(mPackageTracker.start());
917
918        // Check the intent helper is properly configured.
919        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
920
921        // Check the initial storage state.
922        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
923
924        for (int i = 0; i < retriesAllowed + 1; i++) {
925            // Simulate a reliability trigger.
926            mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
927
928            // Assert the PackageTracker did trigger an update.
929            checkUpdateCheckTriggered(currentPackageVersions);
930
931            // Check the PackageTracker failure count before calling recordCheckResult.
932            assertEquals(i, mPackageTracker.getCheckFailureCountForTests());
933
934            // Simulate a check failure.
935            CheckToken checkToken = mFakeIntentHelper.captureAndResetLastToken();
936            mPackageTracker.recordCheckResult(checkToken, false /* success */);
937
938            // Peek inside the package tracker to make sure it is tracking failure counts properly.
939            assertEquals(i + 1, mPackageTracker.getCheckFailureCountForTests());
940
941            // Confirm nothing has changed.
942            mFakeIntentHelper.assertUpdateNotTriggered();
943            checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE,
944                    currentPackageVersions);
945
946            // Check reliability triggering is in the correct state.
947            if (i <= retriesAllowed) {
948                mFakeIntentHelper.assertReliabilityTriggerScheduled();
949            } else {
950                mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
951            }
952        }
953    }
954
955    @Test
956    public void trackingEnabled_reliabilityTrigger_failureCountIsReset() throws Exception {
957        // Set up device configuration.
958        configureTrackingEnabled();
959
960        int retriesAllowed = 3;
961        int checkDelayMillis = 5 * 60 * 1000;
962        configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
963
964        PackageVersions oldPackageVersions = new PackageVersions(1, 1);
965        PackageVersions currentPackageVersions = new PackageVersions(2, 2);
966
967        // Simulate there being a newer version installed than the one recorded in storage.
968        configureValidApplications(currentPackageVersions);
969
970        // Force the storage into a state we want.
971        mPackageStatusStorage.forceCheckStateForTests(
972                PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
973
974        // Initialize the package tracker.
975        assertTrue(mPackageTracker.start());
976
977        // Check the intent helper is properly configured.
978        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
979
980        // Check the initial storage state.
981        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
982
983        // Fail (retries - 1) times.
984        for (int i = 0; i < retriesAllowed - 1; i++) {
985            // Simulate a reliability trigger.
986            mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
987
988            // Assert the PackageTracker did trigger an update.
989            checkUpdateCheckTriggered(currentPackageVersions);
990
991            // Check the PackageTracker failure count before calling recordCheckResult.
992            assertEquals(i, mPackageTracker.getCheckFailureCountForTests());
993
994            // Simulate a check failure.
995            CheckToken checkToken = mFakeIntentHelper.captureAndResetLastToken();
996            mPackageTracker.recordCheckResult(checkToken, false /* success */);
997
998            // Peek inside the package tracker to make sure it is tracking failure counts properly.
999            assertEquals(i + 1, mPackageTracker.getCheckFailureCountForTests());
1000
1001            // Confirm nothing has changed.
1002            mFakeIntentHelper.assertUpdateNotTriggered();
1003            checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE,
1004                    currentPackageVersions);
1005
1006            // Check reliability triggering is still enabled.
1007            mFakeIntentHelper.assertReliabilityTriggerScheduled();
1008        }
1009
1010        // Simulate a reliability trigger.
1011        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
1012
1013        // Assert the PackageTracker did trigger an update.
1014        checkUpdateCheckTriggered(currentPackageVersions);
1015
1016        // Check the PackageTracker failure count before calling recordCheckResult.
1017        assertEquals(retriesAllowed - 1, mPackageTracker.getCheckFailureCountForTests());
1018
1019        // On the last possible try, succeed.
1020        CheckToken checkToken = mFakeIntentHelper.captureAndResetLastToken();
1021        mPackageTracker.recordCheckResult(checkToken, true /* success */);
1022
1023        checkUpdateCheckSuccessful(currentPackageVersions);
1024    }
1025
1026    /**
1027     * Simulates reliability triggers happening too close together. Package tracker should ignore
1028     * the ones it doesn't need.
1029     */
1030    @Test
1031    public void trackingEnabled_reliabilityTrigger_tooSoon() throws Exception {
1032        // Set up device configuration.
1033        configureTrackingEnabled();
1034
1035        int retriesAllowed = 5;
1036        int checkDelayMillis = 5 * 60 * 1000;
1037        configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
1038
1039        PackageVersions oldPackageVersions = new PackageVersions(1, 1);
1040        PackageVersions currentPackageVersions = new PackageVersions(2, 2);
1041
1042        // Simulate there being a newer version installed than the one recorded in storage.
1043        configureValidApplications(currentPackageVersions);
1044
1045        // Force the storage into a state we want.
1046        mPackageStatusStorage.forceCheckStateForTests(
1047                PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
1048
1049        // Initialize the package tracker.
1050        assertTrue(mPackageTracker.start());
1051
1052        // Check the intent helper is properly configured.
1053        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
1054
1055        // Check the initial storage state.
1056        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
1057
1058        // Simulate a reliability trigger.
1059        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
1060
1061        // Assert the PackageTracker did trigger an update.
1062        checkUpdateCheckTriggered(currentPackageVersions);
1063        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
1064
1065        // Increment the clock, but not enough.
1066        mFakeClock.incrementClock(checkDelayMillis - 1);
1067
1068        // Simulate a reliability trigger.
1069        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
1070
1071        // Assert the PackageTracker did not trigger an update.
1072        mFakeIntentHelper.assertUpdateNotTriggered();
1073        checkPackageStorageStatus(PackageStatus.CHECK_STARTED, currentPackageVersions);
1074        mFakeIntentHelper.assertReliabilityTriggerScheduled();
1075
1076        // Increment the clock slightly more. Should now consider the response overdue.
1077        mFakeClock.incrementClock(2);
1078
1079        // Simulate a reliability trigger.
1080        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
1081
1082        // Triggering should have happened.
1083        checkUpdateCheckTriggered(currentPackageVersions);
1084        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
1085
1086        // Check a new token was generated.
1087        assertFalse(token1.equals(token2));
1088    }
1089
1090    /**
1091     * Tests what happens when a package update doesn't complete and a reliability trigger cleans
1092     * up for it.
1093     */
1094    @Test
1095    public void trackingEnabled_reliabilityTrigger_afterPackageUpdateDidNotComplete()
1096            throws Exception {
1097
1098        // Set up device configuration.
1099        configureTrackingEnabled();
1100
1101        int retriesAllowed = 5;
1102        int checkDelayMillis = 5 * 60 * 1000;
1103        configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
1104
1105        PackageVersions currentPackageVersions = new PackageVersions(1, 1);
1106        PackageVersions newPackageVersions = new PackageVersions(2, 2);
1107
1108        // Simulate there being a newer version installed than the one recorded in storage.
1109        configureValidApplications(currentPackageVersions);
1110
1111        // Force the storage into a state we want.
1112        mPackageStatusStorage.forceCheckStateForTests(
1113                PackageStatus.CHECK_COMPLETED_SUCCESS, currentPackageVersions);
1114
1115        // Initialize the package tracker.
1116        assertTrue(mPackageTracker.start());
1117
1118        // Check the intent helper is properly configured.
1119        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
1120
1121        // Simulate a reliability trigger.
1122        simulatePackageInstallation(newPackageVersions);
1123
1124        // Assert the PackageTracker did trigger an update.
1125        checkUpdateCheckTriggered(newPackageVersions);
1126        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
1127
1128        // Increment the clock, but not enough.
1129        mFakeClock.incrementClock(checkDelayMillis + 1);
1130
1131        // Simulate a reliability trigger.
1132        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
1133
1134        // Assert the PackageTracker triggered an update.
1135        checkUpdateCheckTriggered(newPackageVersions);
1136        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
1137
1138        // Check a new token was generated.
1139        assertFalse(token1.equals(token2));
1140
1141        // Simulate the reliability check completing.
1142        mPackageTracker.recordCheckResult(token2, true /* success */);
1143
1144        // Check everything is now as it should be.
1145        checkUpdateCheckSuccessful(newPackageVersions);
1146    }
1147
1148    /**
1149     * Simulates a reliability trigger happening too soon after a package update trigger occurred.
1150     */
1151    @Test
1152    public void trackingEnabled_reliabilityTriggerAfterUpdate_tooSoon() throws Exception {
1153        // Set up device configuration.
1154        configureTrackingEnabled();
1155
1156        int retriesAllowed = 5;
1157        int checkDelayMillis = 5 * 60 * 1000;
1158        configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
1159
1160        PackageVersions currentPackageVersions = new PackageVersions(1, 1);
1161        PackageVersions newPackageVersions = new PackageVersions(2, 2);
1162
1163        // Simulate there being a newer version installed than the one recorded in storage.
1164        configureValidApplications(currentPackageVersions);
1165
1166        // Force the storage into a state we want.
1167        mPackageStatusStorage.forceCheckStateForTests(
1168                PackageStatus.CHECK_COMPLETED_SUCCESS, currentPackageVersions);
1169
1170        // Initialize the package tracker.
1171        assertTrue(mPackageTracker.start());
1172
1173        // Check the intent helper is properly configured.
1174        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
1175
1176        // Check the initial storage state.
1177        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, currentPackageVersions);
1178
1179        // Simulate a package update trigger.
1180        simulatePackageInstallation(newPackageVersions);
1181
1182        // Assert the PackageTracker did trigger an update.
1183        checkUpdateCheckTriggered(newPackageVersions);
1184        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
1185
1186        // Increment the clock, but not enough.
1187        mFakeClock.incrementClock(checkDelayMillis - 1);
1188
1189        // Simulate a reliability trigger.
1190        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
1191
1192        // Assert the PackageTracker did not trigger an update.
1193        mFakeIntentHelper.assertUpdateNotTriggered();
1194        checkPackageStorageStatus(PackageStatus.CHECK_STARTED, newPackageVersions);
1195        mFakeIntentHelper.assertReliabilityTriggerScheduled();
1196
1197        // Increment the clock slightly more. Should now consider the response overdue.
1198        mFakeClock.incrementClock(2);
1199
1200        // Simulate a reliability trigger.
1201        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
1202
1203        // Triggering should have happened.
1204        checkUpdateCheckTriggered(newPackageVersions);
1205        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
1206
1207        // Check a new token was generated.
1208        assertFalse(token1.equals(token2));
1209    }
1210
1211    @Test
1212    public void dump() {
1213        StringWriter stringWriter = new StringWriter();
1214        PrintWriter printWriter = new PrintWriter(stringWriter);
1215
1216        mPackageTracker.dump(printWriter);
1217
1218        assertFalse(stringWriter.toString().isEmpty());
1219    }
1220
1221    private void simulatePackageInstallation(PackageVersions packageVersions) throws Exception {
1222        configureApplicationsValidManifests(packageVersions);
1223
1224        // Simulate a tracked package being updated.
1225        mFakeIntentHelper.simulatePackageUpdatedEvent();
1226    }
1227
1228    /**
1229     * Checks an update check was triggered, reliability triggering is therefore enabled and the
1230     * storage state reflects that there is a check in progress.
1231     */
1232    private void checkUpdateCheckTriggered(PackageVersions packageVersions) {
1233        // Assert the PackageTracker attempted to trigger an update.
1234        mFakeIntentHelper.assertUpdateTriggered();
1235
1236        // If an update check was triggered reliability triggering should always be enabled to
1237        // ensure that it can be completed if it fails.
1238        mFakeIntentHelper.assertReliabilityTriggerScheduled();
1239
1240        // Check the expected storage state.
1241        checkPackageStorageStatus(PackageStatus.CHECK_STARTED, packageVersions);
1242    }
1243
1244    private void checkUpdateCheckFailed(PackageVersions packageVersions) {
1245        // Check reliability triggering state.
1246        mFakeIntentHelper.assertReliabilityTriggerScheduled();
1247
1248        // Assert the storage was updated.
1249        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, packageVersions);
1250    }
1251
1252    private void checkUpdateCheckSuccessful(PackageVersions packageVersions) {
1253        // Check reliability triggering state.
1254        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
1255
1256        // Assert the storage was updated.
1257        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
1258
1259        // Peek inside the package tracker to make sure it is tracking failure counts properly.
1260        assertEquals(0, mPackageTracker.getCheckFailureCountForTests());
1261    }
1262
1263    private PackageVersions configureValidApplications() throws Exception {
1264        configureValidApplications(INITIAL_APP_PACKAGE_VERSIONS);
1265        return INITIAL_APP_PACKAGE_VERSIONS;
1266    }
1267
1268    private void configureValidApplications(PackageVersions versions) throws Exception {
1269        configureUpdateAppPackageOk(UPDATE_APP_PACKAGE_NAME);
1270        configureDataAppPackageOk(DATA_APP_PACKAGE_NAME);
1271        configureApplicationsValidManifests(versions);
1272    }
1273
1274    private void configureApplicationsValidManifests(PackageVersions versions) throws Exception {
1275        configureUpdateAppManifestOk(UPDATE_APP_PACKAGE_NAME);
1276        configureDataAppManifestOk(DATA_APP_PACKAGE_NAME);
1277        configureUpdateAppPackageVersion(UPDATE_APP_PACKAGE_NAME, versions.mUpdateAppVersion);
1278        configureDataAppPackageVersion(DATA_APP_PACKAGE_NAME, versions.mDataAppVersion);
1279    }
1280
1281    private void configureUpdateAppPackageVersion(String updateAppPackageName,
1282            long updataAppPackageVersion) throws Exception {
1283        when(mMockPackageManagerHelper.getInstalledPackageVersion(updateAppPackageName))
1284                .thenReturn(updataAppPackageVersion);
1285    }
1286
1287    private void configureDataAppPackageVersion(String dataAppPackageName,
1288            long dataAppPackageVersion) throws Exception {
1289        when(mMockPackageManagerHelper.getInstalledPackageVersion(dataAppPackageName))
1290                .thenReturn(dataAppPackageVersion);
1291    }
1292
1293    private void configureUpdateAppManifestOk(String updateAppPackageName) throws Exception {
1294        Intent expectedIntent = RulesUpdaterContract.createUpdaterIntent(updateAppPackageName);
1295        when(mMockPackageManagerHelper.receiverRegistered(
1296                filterEquals(expectedIntent),
1297                eq(RulesUpdaterContract.TRIGGER_TIME_ZONE_RULES_CHECK_PERMISSION)))
1298                .thenReturn(true);
1299        when(mMockPackageManagerHelper.usesPermission(
1300                updateAppPackageName, RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION))
1301                .thenReturn(true);
1302    }
1303
1304    private void configureUpdateAppManifestBad(String updateAppPackageName) throws Exception {
1305        Intent expectedIntent = RulesUpdaterContract.createUpdaterIntent(updateAppPackageName);
1306        when(mMockPackageManagerHelper.receiverRegistered(
1307                filterEquals(expectedIntent),
1308                eq(RulesUpdaterContract.TRIGGER_TIME_ZONE_RULES_CHECK_PERMISSION)))
1309                .thenReturn(false);
1310        // Has permission, but that shouldn't matter if the check above is false.
1311        when(mMockPackageManagerHelper.usesPermission(
1312                updateAppPackageName, RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION))
1313                .thenReturn(true);
1314    }
1315
1316    private void configureDataAppManifestOk(String dataAppPackageName) throws Exception {
1317        when(mMockPackageManagerHelper.contentProviderRegistered(
1318                TimeZoneRulesDataContract.AUTHORITY, dataAppPackageName))
1319                .thenReturn(true);
1320    }
1321
1322    private void configureDataAppManifestBad(String dataAppPackageName) throws Exception {
1323        // Simulate the data app not exposing the content provider we require.
1324        when(mMockPackageManagerHelper.contentProviderRegistered(
1325                TimeZoneRulesDataContract.AUTHORITY, dataAppPackageName))
1326                .thenReturn(false);
1327    }
1328
1329    private void configureTrackingEnabled() {
1330        when(mMockConfigHelper.isTrackingEnabled()).thenReturn(true);
1331    }
1332
1333    private void configureTrackingDisabled() {
1334        when(mMockConfigHelper.isTrackingEnabled()).thenReturn(false);
1335    }
1336
1337    private void configureReliabilityConfigSettings(int retriesAllowed, int checkDelayMillis) {
1338        when(mMockConfigHelper.getFailedCheckRetryCount()).thenReturn(retriesAllowed);
1339        when(mMockConfigHelper.getCheckTimeAllowedMillis()).thenReturn(checkDelayMillis);
1340    }
1341
1342    private void configureReliabilityConfigSettingsOk() {
1343        configureReliabilityConfigSettings(5, 5 * 60 * 1000);
1344    }
1345
1346    private void configureUpdateAppPackageOk(String updateAppPackageName) throws Exception {
1347        when(mMockConfigHelper.getUpdateAppPackageName()).thenReturn(updateAppPackageName);
1348        when(mMockPackageManagerHelper.isPrivilegedApp(updateAppPackageName)).thenReturn(true);
1349    }
1350
1351    private void configureUpdateAppPackageNotPrivileged(String updateAppPackageName)
1352            throws Exception {
1353        when(mMockConfigHelper.getUpdateAppPackageName()).thenReturn(updateAppPackageName);
1354        when(mMockPackageManagerHelper.isPrivilegedApp(updateAppPackageName)).thenReturn(false);
1355    }
1356
1357    private void configureUpdateAppPackageNameMissing() {
1358        when(mMockConfigHelper.getUpdateAppPackageName()).thenReturn(null);
1359    }
1360
1361    private void configureDataAppPackageOk(String dataAppPackageName) throws Exception {
1362        when(mMockConfigHelper.getDataAppPackageName()).thenReturn(dataAppPackageName);
1363        when(mMockPackageManagerHelper.isPrivilegedApp(dataAppPackageName)).thenReturn(true);
1364    }
1365
1366    private void configureDataAppPackageNotPrivileged(String dataAppPackageName)
1367            throws Exception {
1368        when(mMockConfigHelper.getUpdateAppPackageName()).thenReturn(dataAppPackageName);
1369        when(mMockPackageManagerHelper.isPrivilegedApp(dataAppPackageName)).thenReturn(false);
1370    }
1371
1372    private void configureDataAppPackageNameMissing() {
1373        when(mMockConfigHelper.getDataAppPackageName()).thenThrow(new RuntimeException());
1374    }
1375
1376    private void checkIntentHelperInitializedAndReliabilityTrackingEnabled() {
1377        // Verify that calling start initialized the IntentHelper as well.
1378        mFakeIntentHelper.assertInitialized(UPDATE_APP_PACKAGE_NAME, DATA_APP_PACKAGE_NAME);
1379
1380        // Assert that reliability tracking is always enabled after initialization.
1381        mFakeIntentHelper.assertReliabilityTriggerScheduled();
1382    }
1383
1384    private void checkPackageStorageStatus(
1385            int expectedCheckStatus, PackageVersions expectedPackageVersions) {
1386        PackageStatus packageStatus = mPackageStatusStorage.getPackageStatus();
1387        assertEquals(expectedCheckStatus, packageStatus.mCheckStatus);
1388        assertEquals(expectedPackageVersions, packageStatus.mVersions);
1389    }
1390
1391    private void checkPackageStorageStatusIsInitialOrReset() {
1392        assertNull(mPackageStatusStorage.getPackageStatus());
1393    }
1394
1395    private static CheckToken createArbitraryCheckToken() {
1396        return new CheckToken(1, INITIAL_APP_PACKAGE_VERSIONS);
1397    }
1398
1399    /**
1400     * A fake IntentHelper implementation for use in tests.
1401     */
1402    private static class FakeIntentHelper implements PackageTrackerIntentHelper {
1403
1404        private PackageTracker mPackageTracker;
1405        private String mUpdateAppPackageName;
1406        private String mDataAppPackageName;
1407
1408        private CheckToken mLastToken;
1409
1410        private boolean mReliabilityTriggerScheduled;
1411
1412        @Override
1413        public void initialize(String updateAppPackageName, String dataAppPackageName,
1414                PackageTracker packageTracker) {
1415            assertNotNull(updateAppPackageName);
1416            assertNotNull(dataAppPackageName);
1417            assertNotNull(packageTracker);
1418            mPackageTracker = packageTracker;
1419            mUpdateAppPackageName = updateAppPackageName;
1420            mDataAppPackageName = dataAppPackageName;
1421        }
1422
1423        public void assertInitialized(
1424                String expectedUpdateAppPackageName, String expectedDataAppPackageName) {
1425            assertNotNull(mPackageTracker);
1426            assertEquals(expectedUpdateAppPackageName, mUpdateAppPackageName);
1427            assertEquals(expectedDataAppPackageName, mDataAppPackageName);
1428        }
1429
1430        public void assertNotInitialized() {
1431            assertNull(mPackageTracker);
1432        }
1433
1434        @Override
1435        public void sendTriggerUpdateCheck(CheckToken checkToken) {
1436            if (mLastToken != null) {
1437                fail("lastToken already set");
1438            }
1439            mLastToken = checkToken;
1440        }
1441
1442        @Override
1443        public void scheduleReliabilityTrigger(long minimumDelayMillis) {
1444            mReliabilityTriggerScheduled = true;
1445        }
1446
1447        @Override
1448        public void unscheduleReliabilityTrigger() {
1449            mReliabilityTriggerScheduled = false;
1450        }
1451
1452        public void assertReliabilityTriggerScheduled() {
1453            assertTrue(mReliabilityTriggerScheduled);
1454        }
1455
1456        public void assertReliabilityTriggerNotScheduled() {
1457            assertFalse(mReliabilityTriggerScheduled);
1458        }
1459
1460        public void assertUpdateTriggered() {
1461            assertNotNull(mLastToken);
1462        }
1463
1464        public void assertUpdateNotTriggered() {
1465            assertNull(mLastToken);
1466        }
1467
1468        public CheckToken captureAndResetLastToken() {
1469            CheckToken toReturn = mLastToken;
1470            assertNotNull("No update triggered", toReturn);
1471            mLastToken = null;
1472            return toReturn;
1473        }
1474
1475        public void simulatePackageUpdatedEvent() {
1476            mPackageTracker.triggerUpdateIfNeeded(true /* packageChanged */);
1477        }
1478    }
1479
1480    private static class FakeClock extends Clock {
1481
1482        private long currentTime = 1000;
1483
1484        @Override
1485        public long millis() {
1486            return currentTime;
1487        }
1488
1489        public void incrementClock(long millis) {
1490            currentTime += millis;
1491        }
1492
1493        @Override
1494        public ZoneId getZone() {
1495            throw new UnsupportedOperationException();
1496        }
1497
1498        @Override
1499        public Clock withZone(ZoneId zone) {
1500            throw new UnsupportedOperationException();
1501        }
1502
1503        @Override
1504        public Instant instant() {
1505            throw new UnsupportedOperationException();
1506        }
1507    }
1508
1509    /**
1510     * Registers a mockito parameter matcher that uses {@link Intent#filterEquals(Intent)}. to
1511     * check the parameter against the intent supplied.
1512     */
1513    private static Intent filterEquals(final Intent expected) {
1514        final Matcher<Intent> m = new BaseMatcher<Intent>() {
1515            @Override
1516            public boolean matches(Object actual) {
1517                return actual != null && expected.filterEquals((Intent) actual);
1518            }
1519            @Override
1520            public void describeTo(Description description) {
1521                description.appendText(expected.toString());
1522            }
1523        };
1524        return argThat(m);
1525    }
1526}
1527