WebViewUpdateServiceTest.java revision 86f7bbe134a274a4936b73e2fc2287482ac0157e
1/* 2 * Copyright (C) 2016 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.webkit; 18 19import static org.junit.Assert.assertEquals; 20import static org.junit.Assert.assertFalse; 21 22import android.content.Context; 23import android.content.pm.ApplicationInfo; 24import android.content.pm.PackageInfo; 25import android.content.pm.Signature; 26import android.os.Bundle; 27import android.support.test.InstrumentationRegistry; 28import android.support.test.runner.AndroidJUnit4; 29import android.test.suitebuilder.annotation.MediumTest; 30import android.util.Base64; 31import android.webkit.WebViewFactory; 32import android.webkit.WebViewProviderInfo; 33import android.webkit.WebViewProviderResponse; 34 35import org.hamcrest.Description; 36 37import org.junit.Test; 38import org.junit.runner.RunWith; 39 40import org.mockito.Mockito; 41import org.mockito.Matchers; 42import org.mockito.ArgumentMatcher; 43 44import java.util.concurrent.CountDownLatch; 45 46 47/** 48 * Tests for WebViewUpdateService 49 */ 50// Use MediumTest instead of SmallTest as the implementation of WebViewUpdateService 51// is intended to work on several threads and uses at least one sleep/wait-statement. 52@RunWith(AndroidJUnit4.class) 53@MediumTest 54public class WebViewUpdateServiceTest { 55 private final static String TAG = WebViewUpdateServiceTest.class.getSimpleName(); 56 57 private WebViewUpdateServiceImpl mWebViewUpdateServiceImpl; 58 private TestSystemImpl mTestSystemImpl; 59 60 private static final String WEBVIEW_LIBRARY_FLAG = "com.android.webview.WebViewLibrary"; 61 62 /** 63 * Creates a new instance. 64 */ 65 public WebViewUpdateServiceTest() { 66 } 67 68 private void setupWithPackages(WebViewProviderInfo[] packages) { 69 setupWithPackages(packages, true); 70 } 71 72 private void setupWithPackages(WebViewProviderInfo[] packages, 73 boolean fallbackLogicEnabled) { 74 setupWithPackages(packages, fallbackLogicEnabled, 1); 75 } 76 77 private void setupWithPackages(WebViewProviderInfo[] packages, 78 boolean fallbackLogicEnabled, int numRelros) { 79 setupWithPackages(packages, fallbackLogicEnabled, numRelros, 80 true /* isDebuggable == true -> don't check package signatures */); 81 } 82 83 private void setupWithPackages(WebViewProviderInfo[] packages, 84 boolean fallbackLogicEnabled, int numRelros, boolean isDebuggable) { 85 TestSystemImpl testing = new TestSystemImpl(packages, fallbackLogicEnabled, numRelros, 86 isDebuggable); 87 mTestSystemImpl = Mockito.spy(testing); 88 mWebViewUpdateServiceImpl = 89 new WebViewUpdateServiceImpl(null /*Context*/, mTestSystemImpl); 90 } 91 92 private void setEnabledAndValidPackageInfos(WebViewProviderInfo[] providers) { 93 for(WebViewProviderInfo wpi : providers) { 94 mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true /* enabled */, 95 true /* valid */, true /* installed */)); 96 } 97 } 98 99 private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName, 100 WebViewProviderInfo[] webviewPackages) { 101 checkCertainPackageUsedAfterWebViewBootPreparation( 102 expectedProviderName, webviewPackages, 1); 103 } 104 105 private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName, 106 WebViewProviderInfo[] webviewPackages, int numRelros) { 107 setupWithPackages(webviewPackages, true, numRelros); 108 // Add (enabled and valid) package infos for each provider 109 setEnabledAndValidPackageInfos(webviewPackages); 110 111 runWebViewBootPreparationOnMainSync(); 112 113 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 114 Mockito.argThat(new IsPackageInfoWithName(expectedProviderName))); 115 116 for (int n = 0; n < numRelros; n++) { 117 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 118 } 119 120 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 121 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); 122 assertEquals(expectedProviderName, response.packageInfo.packageName); 123 } 124 125 // For matching the package name of a PackageInfo 126 private class IsPackageInfoWithName extends ArgumentMatcher<PackageInfo> { 127 private final String mPackageName; 128 129 IsPackageInfoWithName(String name) { 130 mPackageName = name; 131 } 132 133 @Override 134 public boolean matches(Object p) { 135 return ((PackageInfo) p).packageName.equals(mPackageName); 136 } 137 138 // Provide a more useful description in case of mismatch 139 @Override 140 public void describeTo (Description description) { 141 description.appendText(String.format("PackageInfo with name '%s'", mPackageName)); 142 } 143 } 144 145 private static PackageInfo createPackageInfo( 146 String packageName, boolean enabled, boolean valid, boolean installed) { 147 PackageInfo p = new PackageInfo(); 148 p.packageName = packageName; 149 p.applicationInfo = new ApplicationInfo(); 150 p.applicationInfo.enabled = enabled; 151 p.applicationInfo.metaData = new Bundle(); 152 if (installed) { 153 p.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED; 154 } else { 155 p.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED; 156 } 157 if (valid) { 158 // no flag means invalid 159 p.applicationInfo.metaData.putString(WEBVIEW_LIBRARY_FLAG, "blah"); 160 } 161 return p; 162 } 163 164 private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid, 165 boolean installed, Signature[] signatures, long updateTime) { 166 PackageInfo p = createPackageInfo(packageName, enabled, valid, installed); 167 p.signatures = signatures; 168 p.lastUpdateTime = updateTime; 169 return p; 170 } 171 172 private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid, 173 boolean installed, Signature[] signatures, long updateTime, boolean hidden) { 174 PackageInfo p = 175 createPackageInfo(packageName, enabled, valid, installed, signatures, updateTime); 176 if (hidden) { 177 p.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN; 178 } else { 179 p.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN; 180 } 181 return p; 182 } 183 184 private void checkPreparationPhasesForPackage(String expectedPackage, int numPreparation) { 185 // Verify that onWebViewProviderChanged was called for the numPreparation'th time for the 186 // expected package 187 Mockito.verify(mTestSystemImpl, Mockito.times(numPreparation)).onWebViewProviderChanged( 188 Mockito.argThat(new IsPackageInfoWithName(expectedPackage))); 189 190 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 191 192 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 193 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); 194 assertEquals(expectedPackage, response.packageInfo.packageName); 195 } 196 197 /** 198 * The WebView preparation boot phase is run on the main thread (especially on a thread with a 199 * looper) so to avoid bugs where our tests fail because a looper hasn't been attached to the 200 * thread running prepareWebViewInSystemServer we run it on the main thread. 201 */ 202 private void runWebViewBootPreparationOnMainSync() { 203 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 204 @Override 205 public void run() { 206 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 207 } 208 }); 209 } 210 211 212 // **************** 213 // Tests 214 // **************** 215 216 217 @Test 218 public void testWithSinglePackage() { 219 String testPackageName = "test.package.name"; 220 checkCertainPackageUsedAfterWebViewBootPreparation(testPackageName, 221 new WebViewProviderInfo[] { 222 new WebViewProviderInfo(testPackageName, "", 223 true /*default available*/, false /* fallback */, null)}); 224 } 225 226 @Test 227 public void testDefaultPackageUsedOverNonDefault() { 228 String defaultPackage = "defaultPackage"; 229 String nonDefaultPackage = "nonDefaultPackage"; 230 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 231 new WebViewProviderInfo(nonDefaultPackage, "", false, false, null), 232 new WebViewProviderInfo(defaultPackage, "", true, false, null)}; 233 checkCertainPackageUsedAfterWebViewBootPreparation(defaultPackage, packages); 234 } 235 236 @Test 237 public void testSeveralRelros() { 238 String singlePackage = "singlePackage"; 239 checkCertainPackageUsedAfterWebViewBootPreparation( 240 singlePackage, 241 new WebViewProviderInfo[] { 242 new WebViewProviderInfo(singlePackage, "", true /*def av*/, false, null)}, 243 2); 244 } 245 246 // Ensure that package with valid signatures is chosen rather than package with invalid 247 // signatures. 248 @Test 249 public void testWithSignatures() { 250 String validPackage = "valid package"; 251 String invalidPackage = "invalid package"; 252 253 Signature validSignature = new Signature("11"); 254 Signature invalidExpectedSignature = new Signature("22"); 255 Signature invalidPackageSignature = new Signature("33"); 256 257 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 258 new WebViewProviderInfo(invalidPackage, "", true, false, new String[]{ 259 Base64.encodeToString( 260 invalidExpectedSignature.toByteArray(), Base64.DEFAULT)}), 261 new WebViewProviderInfo(validPackage, "", true, false, new String[]{ 262 Base64.encodeToString( 263 validSignature.toByteArray(), Base64.DEFAULT)}) 264 }; 265 setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */, 266 false /* isDebuggable */); 267 mTestSystemImpl.setPackageInfo(createPackageInfo(invalidPackage, true /* enabled */, 268 true /* valid */, true /* installed */, new Signature[]{invalidPackageSignature} 269 , 0 /* updateTime */)); 270 mTestSystemImpl.setPackageInfo(createPackageInfo(validPackage, true /* enabled */, 271 true /* valid */, true /* installed */, new Signature[]{validSignature} 272 , 0 /* updateTime */)); 273 274 runWebViewBootPreparationOnMainSync(); 275 276 277 checkPreparationPhasesForPackage(validPackage, 1 /* first preparation for this package */); 278 279 WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages(); 280 assertEquals(1, validPackages.length); 281 assertEquals(validPackage, validPackages[0].packageName); 282 } 283 284 @Test 285 public void testFailWaitingForRelro() { 286 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 287 new WebViewProviderInfo("packagename", "", true, true, null)}; 288 setupWithPackages(packages); 289 setEnabledAndValidPackageInfos(packages); 290 291 runWebViewBootPreparationOnMainSync(); 292 293 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 294 Mockito.argThat(new IsPackageInfoWithName(packages[0].packageName))); 295 296 // Never call notifyRelroCreation() 297 298 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 299 assertEquals(WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO, response.status); 300 } 301 302 @Test 303 public void testFailListingEmptyWebviewPackages() { 304 WebViewProviderInfo[] packages = new WebViewProviderInfo[0]; 305 setupWithPackages(packages); 306 setEnabledAndValidPackageInfos(packages); 307 308 runWebViewBootPreparationOnMainSync(); 309 310 Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged( 311 Matchers.anyObject()); 312 313 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 314 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 315 } 316 317 @Test 318 public void testFailListingInvalidWebviewPackage() { 319 WebViewProviderInfo wpi = new WebViewProviderInfo("package", "", true, true, null); 320 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {wpi}; 321 setupWithPackages(packages); 322 mTestSystemImpl.setPackageInfo( 323 createPackageInfo(wpi.packageName, true /* enabled */, false /* valid */, 324 true /* installed */)); 325 326 runWebViewBootPreparationOnMainSync(); 327 328 Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged( 329 Matchers.anyObject()); 330 331 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 332 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 333 334 // Verify that we can recover from failing to list webview packages. 335 mTestSystemImpl.setPackageInfo( 336 createPackageInfo(wpi.packageName, true /* enabled */, true /* valid */, 337 true /* installed */)); 338 mWebViewUpdateServiceImpl.packageStateChanged(wpi.packageName, 339 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0); 340 341 checkPreparationPhasesForPackage(wpi.packageName, 1); 342 } 343 344 // Test that switching provider using changeProviderAndSetting works. 345 @Test 346 public void testSwitchingProvider() { 347 String firstPackage = "first"; 348 String secondPackage = "second"; 349 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 350 new WebViewProviderInfo(firstPackage, "", true, false, null), 351 new WebViewProviderInfo(secondPackage, "", true, false, null)}; 352 checkSwitchingProvider(packages, firstPackage, secondPackage); 353 } 354 355 @Test 356 public void testSwitchingProviderToNonDefault() { 357 String defaultPackage = "defaultPackage"; 358 String nonDefaultPackage = "nonDefaultPackage"; 359 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 360 new WebViewProviderInfo(defaultPackage, "", true, false, null), 361 new WebViewProviderInfo(nonDefaultPackage, "", false, false, null)}; 362 checkSwitchingProvider(packages, defaultPackage, nonDefaultPackage); 363 } 364 365 private void checkSwitchingProvider(WebViewProviderInfo[] packages, String initialPackage, 366 String finalPackage) { 367 checkCertainPackageUsedAfterWebViewBootPreparation(initialPackage, packages); 368 369 mWebViewUpdateServiceImpl.changeProviderAndSetting(finalPackage); 370 checkPreparationPhasesForPackage(finalPackage, 1 /* first preparation for this package */); 371 372 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(initialPackage)); 373 } 374 375 // Change provider during relro creation by using changeProviderAndSetting 376 @Test 377 public void testSwitchingProviderDuringRelroCreation() { 378 checkChangingProviderDuringRelroCreation(true); 379 } 380 381 // Change provider during relro creation by enabling a provider 382 @Test 383 public void testChangingProviderThroughEnablingDuringRelroCreation() { 384 checkChangingProviderDuringRelroCreation(false); 385 } 386 387 private void checkChangingProviderDuringRelroCreation(boolean settingsChange) { 388 String firstPackage = "first"; 389 String secondPackage = "second"; 390 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 391 new WebViewProviderInfo(firstPackage, "", true, false, null), 392 new WebViewProviderInfo(secondPackage, "", true, false, null)}; 393 setupWithPackages(packages); 394 if (settingsChange) { 395 // Have all packages be enabled, so that we can change provider however we want to 396 setEnabledAndValidPackageInfos(packages); 397 } else { 398 // Have all packages be disabled so that we can change one to enabled later 399 for(WebViewProviderInfo wpi : packages) { 400 mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, 401 false /* enabled */, true /* valid */, true /* installed */)); 402 } 403 } 404 405 CountDownLatch countdown = new CountDownLatch(1); 406 407 runWebViewBootPreparationOnMainSync(); 408 409 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 410 Mockito.argThat(new IsPackageInfoWithName(firstPackage))); 411 412 assertEquals(firstPackage, mWebViewUpdateServiceImpl.getCurrentWebViewPackageName()); 413 414 new Thread(new Runnable() { 415 @Override 416 public void run() { 417 WebViewProviderResponse threadResponse = 418 mWebViewUpdateServiceImpl.waitForAndGetProvider(); 419 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, threadResponse.status); 420 assertEquals(secondPackage, threadResponse.packageInfo.packageName); 421 // Verify that we killed the first package 422 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage)); 423 countdown.countDown(); 424 } 425 }).start(); 426 try { 427 Thread.sleep(500); // Let the new thread run / be blocked 428 } catch (InterruptedException e) { 429 } 430 431 if (settingsChange) { 432 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 433 } else { 434 // Switch provider by enabling the second one 435 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 436 true /* valid */, true /* installed */)); 437 mWebViewUpdateServiceImpl.packageStateChanged( 438 secondPackage, WebViewUpdateService.PACKAGE_CHANGED, 0); 439 } 440 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 441 // first package done, should start on second 442 443 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 444 Mockito.argThat(new IsPackageInfoWithName(secondPackage))); 445 446 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 447 // second package done, the other thread should now be unblocked 448 try { 449 countdown.await(); 450 } catch (InterruptedException e) { 451 } 452 } 453 454 @Test 455 public void testRunFallbackLogicIfEnabled() { 456 checkFallbackLogicBeingRun(true); 457 } 458 459 @Test 460 public void testDontRunFallbackLogicIfDisabled() { 461 checkFallbackLogicBeingRun(false); 462 } 463 464 private void checkFallbackLogicBeingRun(boolean fallbackLogicEnabled) { 465 String primaryPackage = "primary"; 466 String fallbackPackage = "fallback"; 467 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 468 new WebViewProviderInfo( 469 primaryPackage, "", true /* default available */, false /* fallback */, null), 470 new WebViewProviderInfo( 471 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 472 setupWithPackages(packages, fallbackLogicEnabled); 473 setEnabledAndValidPackageInfos(packages); 474 475 runWebViewBootPreparationOnMainSync(); 476 // Verify that we disable the fallback package if fallback logic enabled, and don't disable 477 // the fallback package if that logic is disabled 478 if (fallbackLogicEnabled) { 479 Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers( 480 Matchers.anyObject(), Mockito.eq(fallbackPackage)); 481 } else { 482 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers( 483 Matchers.anyObject(), Matchers.anyObject()); 484 } 485 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 486 Mockito.argThat(new IsPackageInfoWithName(primaryPackage))); 487 488 // Enable fallback package 489 mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */, 490 true /* valid */, true /* installed */)); 491 mWebViewUpdateServiceImpl.packageStateChanged( 492 fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED, 0); 493 494 if (fallbackLogicEnabled) { 495 // Check that we have now disabled the fallback package twice 496 Mockito.verify(mTestSystemImpl, Mockito.times(2)).uninstallAndDisablePackageForAllUsers( 497 Matchers.anyObject(), Mockito.eq(fallbackPackage)); 498 } else { 499 // Check that we still haven't disabled any package 500 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers( 501 Matchers.anyObject(), Matchers.anyObject()); 502 } 503 } 504 505 /** 506 * Scenario for installing primary package when fallback enabled. 507 * 1. Start with only fallback installed 508 * 2. Install non-fallback 509 * 3. Fallback should be disabled 510 */ 511 @Test 512 public void testInstallingNonFallbackPackage() { 513 String primaryPackage = "primary"; 514 String fallbackPackage = "fallback"; 515 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 516 new WebViewProviderInfo( 517 primaryPackage, "", true /* default available */, false /* fallback */, null), 518 new WebViewProviderInfo( 519 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 520 setupWithPackages(packages, true /* isFallbackLogicEnabled */); 521 mTestSystemImpl.setPackageInfo( 522 createPackageInfo(fallbackPackage, true /* enabled */ , true /* valid */, 523 true /* installed */)); 524 525 runWebViewBootPreparationOnMainSync(); 526 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers( 527 Matchers.anyObject(), Matchers.anyObject()); 528 529 checkPreparationPhasesForPackage(fallbackPackage, 530 1 /* first preparation for this package*/); 531 532 // Install primary package 533 mTestSystemImpl.setPackageInfo( 534 createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */, 535 true /* installed */)); 536 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 537 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0); 538 539 // Verify fallback disabled, primary package used as provider, and fallback package killed 540 Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers( 541 Matchers.anyObject(), Mockito.eq(fallbackPackage)); 542 checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation for this package*/); 543 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(fallbackPackage)); 544 } 545 546 @Test 547 public void testFallbackChangesEnabledState() { 548 String primaryPackage = "primary"; 549 String fallbackPackage = "fallback"; 550 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 551 new WebViewProviderInfo( 552 primaryPackage, "", true /* default available */, false /* fallback */, null), 553 new WebViewProviderInfo( 554 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 555 setupWithPackages(packages, true /* fallbackLogicEnabled */); 556 setEnabledAndValidPackageInfos(packages); 557 558 runWebViewBootPreparationOnMainSync(); 559 560 // Verify fallback disabled at boot when primary package enabled 561 Mockito.verify(mTestSystemImpl).enablePackageForUser( 562 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, 563 Matchers.anyInt()); 564 565 checkPreparationPhasesForPackage(primaryPackage, 1); 566 567 // Disable primary package and ensure fallback becomes enabled and used 568 mTestSystemImpl.setPackageInfo( 569 createPackageInfo(primaryPackage, false /* enabled */, true /* valid */, 570 true /* installed */)); 571 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 572 WebViewUpdateService.PACKAGE_CHANGED, 0); 573 574 Mockito.verify(mTestSystemImpl).enablePackageForUser( 575 Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */, 576 Matchers.anyInt()); 577 578 checkPreparationPhasesForPackage(fallbackPackage, 1); 579 580 581 // Again enable primary package and verify primary is used and fallback becomes disabled 582 mTestSystemImpl.setPackageInfo( 583 createPackageInfo(primaryPackage, true /* enabled */, true /* valid */, 584 true /* installed */)); 585 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 586 WebViewUpdateService.PACKAGE_CHANGED, 0); 587 588 // Verify fallback is disabled a second time when primary package becomes enabled 589 Mockito.verify(mTestSystemImpl, Mockito.times(2)).enablePackageForUser( 590 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, 591 Matchers.anyInt()); 592 593 checkPreparationPhasesForPackage(primaryPackage, 2); 594 } 595 596 @Test 597 public void testAddUserWhenFallbackLogicEnabled() { 598 checkAddingNewUser(true); 599 } 600 601 @Test 602 public void testAddUserWhenFallbackLogicDisabled() { 603 checkAddingNewUser(false); 604 } 605 606 public void checkAddingNewUser(boolean fallbackLogicEnabled) { 607 String primaryPackage = "primary"; 608 String fallbackPackage = "fallback"; 609 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 610 new WebViewProviderInfo( 611 primaryPackage, "", true /* default available */, false /* fallback */, null), 612 new WebViewProviderInfo( 613 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 614 setupWithPackages(packages, fallbackLogicEnabled); 615 setEnabledAndValidPackageInfos(packages); 616 int newUser = 100; 617 mWebViewUpdateServiceImpl.handleNewUser(newUser); 618 if (fallbackLogicEnabled) { 619 // Verify fallback package becomes disabled for new user 620 Mockito.verify(mTestSystemImpl).enablePackageForUser( 621 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, 622 Mockito.eq(newUser)); 623 } else { 624 // Verify that we don't disable fallback for new user 625 Mockito.verify(mTestSystemImpl, Mockito.never()).enablePackageForUser( 626 Mockito.anyObject(), Matchers.anyBoolean() /* enable */, 627 Matchers.anyInt() /* user */); 628 } 629 } 630 631 /** 632 * Timing dependent test where we verify that the list of valid webview packages becoming empty 633 * at a certain point doesn't crash us or break our state. 634 */ 635 @Test 636 public void testNotifyRelroDoesntCrashIfNoPackages() { 637 String firstPackage = "first"; 638 String secondPackage = "second"; 639 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 640 new WebViewProviderInfo(firstPackage, "", true /* default available */, 641 false /* fallback */, null), 642 new WebViewProviderInfo(secondPackage, "", true /* default available */, 643 false /* fallback */, null)}; 644 setupWithPackages(packages); 645 // Add (enabled and valid) package infos for each provider 646 setEnabledAndValidPackageInfos(packages); 647 648 runWebViewBootPreparationOnMainSync(); 649 650 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 651 Mockito.argThat(new IsPackageInfoWithName(firstPackage))); 652 653 // Change provider during relro creation to enter a state where we are 654 // waiting for relro creation to complete just to re-run relro creation. 655 // (so that in next notifyRelroCreationCompleted() call we have to list webview packages) 656 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 657 658 // Make packages invalid to cause exception to be thrown 659 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */, 660 false /* valid */, true /* installed */, null /* signatures */, 661 0 /* updateTime */)); 662 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 663 false /* valid */, true /* installed */)); 664 665 // This shouldn't throw an exception! 666 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 667 668 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 669 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 670 671 // Now make a package valid again and verify that we can switch back to that 672 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */, 673 true /* valid */, true /* installed */, null /* signatures */, 674 1 /* updateTime */ )); 675 676 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage, 677 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0); 678 679 // Ensure we use firstPackage 680 checkPreparationPhasesForPackage(firstPackage, 2 /* second preparation for this package */); 681 } 682 683 /** 684 * Verify that even if a user-chosen package is removed temporarily we start using it again when 685 * it is added back. 686 */ 687 @Test 688 public void testTempRemovePackageDoesntSwitchProviderPermanently() { 689 String firstPackage = "first"; 690 String secondPackage = "second"; 691 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 692 new WebViewProviderInfo(firstPackage, "", true /* default available */, 693 false /* fallback */, null), 694 new WebViewProviderInfo(secondPackage, "", true /* default available */, 695 false /* fallback */, null)}; 696 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages); 697 698 // Explicitly use the second package 699 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 700 checkPreparationPhasesForPackage(secondPackage, 1 /* first time for this package */); 701 702 // Remove second package (invalidate it) and verify that first package is used 703 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 704 false /* valid */, true /* installed */)); 705 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage, 706 WebViewUpdateService.PACKAGE_ADDED, 0); 707 checkPreparationPhasesForPackage(firstPackage, 2 /* second time for this package */); 708 709 // Now make the second package valid again and verify that it is used again 710 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 711 true /* valid */, true /* installed */)); 712 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage, 713 WebViewUpdateService.PACKAGE_ADDED, 0); 714 checkPreparationPhasesForPackage(secondPackage, 2 /* second time for this package */); 715 } 716 717 /** 718 * Ensure that we update the user-chosen setting across boots if the chosen package is no 719 * longer installed and valid. 720 */ 721 @Test 722 public void testProviderSettingChangedDuringBootIfProviderNotAvailable() { 723 String chosenPackage = "chosenPackage"; 724 String nonChosenPackage = "non-chosenPackage"; 725 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 726 new WebViewProviderInfo(chosenPackage, "", true /* default available */, 727 false /* fallback */, null), 728 new WebViewProviderInfo(nonChosenPackage, "", true /* default available */, 729 false /* fallback */, null)}; 730 731 setupWithPackages(packages); 732 // Only 'install' nonChosenPackage 733 mTestSystemImpl.setPackageInfo( 734 createPackageInfo(nonChosenPackage, true /* enabled */, true /* valid */, true /* installed */)); 735 736 // Set user-chosen package 737 mTestSystemImpl.updateUserSetting(null, chosenPackage); 738 739 runWebViewBootPreparationOnMainSync(); 740 741 // Verify that we switch the setting to point to the current package 742 Mockito.verify(mTestSystemImpl).updateUserSetting( 743 Mockito.anyObject(), Mockito.eq(nonChosenPackage)); 744 assertEquals(nonChosenPackage, mTestSystemImpl.getUserChosenWebViewProvider(null)); 745 746 checkPreparationPhasesForPackage(nonChosenPackage, 1); 747 } 748 749 @Test 750 public void testRecoverFailedListingWebViewPackagesSettingsChange() { 751 checkRecoverAfterFailListingWebviewPackages(true); 752 } 753 754 @Test 755 public void testRecoverFailedListingWebViewPackagesAddedPackage() { 756 checkRecoverAfterFailListingWebviewPackages(false); 757 } 758 759 /** 760 * Test that we can recover correctly from failing to list WebView packages. 761 * settingsChange: whether to fail during changeProviderAndSetting or packageStateChanged 762 */ 763 public void checkRecoverAfterFailListingWebviewPackages(boolean settingsChange) { 764 String firstPackage = "first"; 765 String secondPackage = "second"; 766 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 767 new WebViewProviderInfo(firstPackage, "", true /* default available */, 768 false /* fallback */, null), 769 new WebViewProviderInfo(secondPackage, "", true /* default available */, 770 false /* fallback */, null)}; 771 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages); 772 773 // Make both packages invalid so that we fail listing WebView packages 774 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */, 775 false /* valid */, true /* installed */)); 776 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 777 false /* valid */, true /* installed */)); 778 779 // Change package to hit the webview packages listing problem. 780 if (settingsChange) { 781 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 782 } else { 783 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage, 784 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0); 785 } 786 787 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 788 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 789 790 // Make second package valid and verify that we can load it again 791 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 792 true /* valid */, true /* installed */)); 793 794 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage, 795 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0); 796 797 798 checkPreparationPhasesForPackage(secondPackage, 1); 799 } 800 801 @Test 802 public void testDontKillIfPackageReplaced() { 803 checkDontKillIfPackageRemoved(true); 804 } 805 806 @Test 807 public void testDontKillIfPackageRemoved() { 808 checkDontKillIfPackageRemoved(false); 809 } 810 811 public void checkDontKillIfPackageRemoved(boolean replaced) { 812 String firstPackage = "first"; 813 String secondPackage = "second"; 814 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 815 new WebViewProviderInfo(firstPackage, "", true /* default available */, 816 false /* fallback */, null), 817 new WebViewProviderInfo(secondPackage, "", true /* default available */, 818 false /* fallback */, null)}; 819 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages); 820 821 // Replace or remove the current webview package 822 if (replaced) { 823 mTestSystemImpl.setPackageInfo( 824 createPackageInfo(firstPackage, true /* enabled */, false /* valid */, 825 true /* installed */)); 826 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage, 827 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0); 828 } else { 829 mTestSystemImpl.removePackageInfo(firstPackage); 830 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage, 831 WebViewUpdateService.PACKAGE_REMOVED, 0); 832 } 833 834 checkPreparationPhasesForPackage(secondPackage, 1); 835 836 Mockito.verify(mTestSystemImpl, Mockito.never()).killPackageDependents( 837 Mockito.anyObject()); 838 } 839 840 @Test 841 public void testKillIfSettingChanged() { 842 String firstPackage = "first"; 843 String secondPackage = "second"; 844 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 845 new WebViewProviderInfo(firstPackage, "", true /* default available */, 846 false /* fallback */, null), 847 new WebViewProviderInfo(secondPackage, "", true /* default available */, 848 false /* fallback */, null)}; 849 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages); 850 851 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 852 853 checkPreparationPhasesForPackage(secondPackage, 1); 854 855 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage)); 856 } 857 858 /** 859 * Test that we kill apps using an old provider when we change the provider setting, even if the 860 * new provider is not the one we intended to change to. 861 */ 862 @Test 863 public void testKillIfChangeProviderIncorrectly() { 864 String firstPackage = "first"; 865 String secondPackage = "second"; 866 String thirdPackage = "third"; 867 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 868 new WebViewProviderInfo(firstPackage, "", true /* default available */, 869 false /* fallback */, null), 870 new WebViewProviderInfo(secondPackage, "", true /* default available */, 871 false /* fallback */, null), 872 new WebViewProviderInfo(thirdPackage, "", true /* default available */, 873 false /* fallback */, null)}; 874 setupWithPackages(packages); 875 setEnabledAndValidPackageInfos(packages); 876 877 // Start with the setting pointing to the third package 878 mTestSystemImpl.updateUserSetting(null, thirdPackage); 879 880 runWebViewBootPreparationOnMainSync(); 881 checkPreparationPhasesForPackage(thirdPackage, 1); 882 883 mTestSystemImpl.setPackageInfo( 884 createPackageInfo(secondPackage, true /* enabled */, false /* valid */, true /* installed */)); 885 886 // Try to switch to the invalid second package, this should result in switching to the first 887 // package, since that is more preferred than the third one. 888 assertEquals(firstPackage, 889 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage)); 890 891 checkPreparationPhasesForPackage(firstPackage, 1); 892 893 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(thirdPackage)); 894 } 895 896 // Ensure that the update service uses an uninstalled package if that is the only package 897 // available. 898 @Test 899 public void testWithSingleUninstalledPackage() { 900 String testPackageName = "test.package.name"; 901 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] { 902 new WebViewProviderInfo(testPackageName, "", 903 true /*default available*/, false /* fallback */, null)}; 904 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */); 905 mTestSystemImpl.setPackageInfo(createPackageInfo(testPackageName, true /* enabled */, 906 true /* valid */, false /* installed */)); 907 908 runWebViewBootPreparationOnMainSync(); 909 910 checkPreparationPhasesForPackage(testPackageName, 1 /* first preparation phase */); 911 } 912 913 @Test 914 public void testNonhiddenPackageUserOverHidden() { 915 checkVisiblePackageUserOverNonVisible(false /* true == uninstalled, false == hidden */); 916 } 917 918 @Test 919 public void testInstalledPackageUsedOverUninstalled() { 920 checkVisiblePackageUserOverNonVisible(true /* true == uninstalled, false == hidden */); 921 } 922 923 private void checkVisiblePackageUserOverNonVisible(boolean uninstalledNotHidden) { 924 boolean testUninstalled = uninstalledNotHidden; 925 boolean testHidden = !uninstalledNotHidden; 926 String installedPackage = "installedPackage"; 927 String uninstalledPackage = "uninstalledPackage"; 928 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] { 929 new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */, 930 false /* fallback */, null), 931 new WebViewProviderInfo(installedPackage, "", true /* available by default */, 932 false /* fallback */, null)}; 933 934 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */); 935 mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */, 936 true /* valid */, true /* installed */)); 937 mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */, 938 true /* valid */, (testUninstalled ? false : true) /* installed */, 939 null /* signatures */, 0 /* updateTime */, (testHidden ? true : false))); 940 941 runWebViewBootPreparationOnMainSync(); 942 943 checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */); 944 } 945 946 @Test 947 public void testCantSwitchToHiddenPackage () { 948 checkCantSwitchToNonVisiblePackage(false /* true == uninstalled, false == hidden */); 949 } 950 951 952 @Test 953 public void testCantSwitchToUninstalledPackage () { 954 checkCantSwitchToNonVisiblePackage(true /* true == uninstalled, false == hidden */); 955 } 956 957 /** 958 * Ensure that we won't prioritize an uninstalled (or hidden) package even if it is user-chosen, 959 * and that an uninstalled (or hidden) package is not considered valid (in the 960 * getValidWebViewPackages() API). 961 */ 962 private void checkCantSwitchToNonVisiblePackage(boolean uninstalledNotHidden) { 963 boolean testUninstalled = uninstalledNotHidden; 964 boolean testHidden = !uninstalledNotHidden; 965 String installedPackage = "installedPackage"; 966 String uninstalledPackage = "uninstalledPackage"; 967 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] { 968 new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */, 969 false /* fallback */, null), 970 new WebViewProviderInfo(installedPackage, "", true /* available by default */, 971 false /* fallback */, null)}; 972 973 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */); 974 mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */, 975 true /* valid */, true /* installed */)); 976 mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */, 977 true /* valid */, (testUninstalled ? false : true) /* installed */, 978 null /* signatures */, 0 /* updateTime */, 979 (testHidden ? true : false) /* hidden */)); 980 981 runWebViewBootPreparationOnMainSync(); 982 983 checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */); 984 985 // Ensure that only the installed package is considered valid 986 WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages(); 987 assertEquals(1, validPackages.length); 988 assertEquals(installedPackage, validPackages[0].packageName); 989 990 // ensure that we don't switch to the uninstalled package (it will be used if it becomes 991 // installed later) 992 assertEquals(installedPackage, 993 mWebViewUpdateServiceImpl.changeProviderAndSetting(uninstalledPackage)); 994 995 // We should only have called onWebViewProviderChanged once (before calling 996 // changeProviderAndSetting 997 Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged( 998 Mockito.argThat(new IsPackageInfoWithName(installedPackage))); 999 } 1000 1001 @Test 1002 public void testHiddenPackageNotPrioritizedEvenIfChosen() { 1003 checkNonvisiblePackageNotPrioritizedEvenIfChosen( 1004 false /* true == uninstalled, false == hidden */); 1005 } 1006 1007 @Test 1008 public void testUninstalledPackageNotPrioritizedEvenIfChosen() { 1009 checkNonvisiblePackageNotPrioritizedEvenIfChosen( 1010 true /* true == uninstalled, false == hidden */); 1011 } 1012 1013 public void checkNonvisiblePackageNotPrioritizedEvenIfChosen(boolean uninstalledNotHidden) { 1014 boolean testUninstalled = uninstalledNotHidden; 1015 boolean testHidden = !uninstalledNotHidden; 1016 String installedPackage = "installedPackage"; 1017 String uninstalledPackage = "uninstalledPackage"; 1018 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] { 1019 new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */, 1020 false /* fallback */, null), 1021 new WebViewProviderInfo(installedPackage, "", true /* available by default */, 1022 false /* fallback */, null)}; 1023 1024 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */); 1025 mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */, 1026 true /* valid */, true /* installed */)); 1027 mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */, 1028 true /* valid */, (testUninstalled ? false : true) /* installed */, 1029 null /* signatures */, 0 /* updateTime */, 1030 (testHidden ? true : false) /* hidden */)); 1031 1032 // Start with the setting pointing to the uninstalled package 1033 mTestSystemImpl.updateUserSetting(null, uninstalledPackage); 1034 1035 runWebViewBootPreparationOnMainSync(); 1036 1037 checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */); 1038 } 1039 1040 /** 1041 * Ensures that fallback becomes enabled if the primary package is uninstalled for the current 1042 * user. 1043 */ 1044 @Test 1045 public void testFallbackEnabledIfPrimaryUninstalled() { 1046 String primaryPackage = "primary"; 1047 String fallbackPackage = "fallback"; 1048 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 1049 new WebViewProviderInfo( 1050 primaryPackage, "", true /* default available */, false /* fallback */, null), 1051 new WebViewProviderInfo( 1052 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 1053 setupWithPackages(packages, true /* fallback logic enabled */); 1054 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */, 1055 true /* valid */, false /* installed */)); 1056 mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */, 1057 true /* valid */, true /* installed */)); 1058 1059 runWebViewBootPreparationOnMainSync(); 1060 // Verify that we enable the fallback package 1061 Mockito.verify(mTestSystemImpl).enablePackageForAllUsers( 1062 Mockito.anyObject(), Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */); 1063 1064 checkPreparationPhasesForPackage(fallbackPackage, 1 /* first preparation phase */); 1065 } 1066 1067 @Test 1068 public void testPreparationRunsIffNewPackage() { 1069 String primaryPackage = "primary"; 1070 String fallbackPackage = "fallback"; 1071 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 1072 new WebViewProviderInfo( 1073 primaryPackage, "", true /* default available */, false /* fallback */, null), 1074 new WebViewProviderInfo( 1075 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 1076 setupWithPackages(packages, true /* fallback logic enabled */); 1077 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */, 1078 true /* valid */, true /* installed */, null /* signatures */, 1079 10 /* lastUpdateTime*/ )); 1080 mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */, 1081 true /* valid */, true /* installed */)); 1082 1083 runWebViewBootPreparationOnMainSync(); 1084 1085 checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */); 1086 Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser( 1087 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, 1088 Matchers.anyInt() /* user */); 1089 1090 1091 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 1092 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0 /* userId */); 1093 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 1094 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 1 /* userId */); 1095 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 1096 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 2 /* userId */); 1097 // package still has the same update-time so we shouldn't run preparation here 1098 Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged( 1099 Mockito.argThat(new IsPackageInfoWithName(primaryPackage))); 1100 Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser( 1101 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, 1102 Matchers.anyInt() /* user */); 1103 1104 // Ensure we can still load the package 1105 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 1106 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); 1107 assertEquals(primaryPackage, response.packageInfo.packageName); 1108 1109 1110 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */, 1111 true /* valid */, true /* installed */, null /* signatures */, 1112 20 /* lastUpdateTime*/ )); 1113 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 1114 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0); 1115 // The package has now changed - ensure that we have run the preparation phase a second time 1116 checkPreparationPhasesForPackage(primaryPackage, 2 /* second preparation phase */); 1117 1118 1119 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */, 1120 true /* valid */, true /* installed */, null /* signatures */, 1121 50 /* lastUpdateTime*/ )); 1122 // Receive intent for different user 1123 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 1124 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 2); 1125 1126 checkPreparationPhasesForPackage(primaryPackage, 3 /* third preparation phase */); 1127 } 1128} 1129