WebViewUpdateServiceTest.java revision 95f7e8e06dd0003a813f7a4b3c718c68d0fa4a01
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 android.content.Context; 20import android.content.pm.ApplicationInfo; 21import android.content.pm.PackageInfo; 22import android.content.pm.Signature; 23import android.os.Bundle; 24import android.util.Base64; 25import android.test.AndroidTestCase; 26 27import android.webkit.WebViewFactory; 28import android.webkit.WebViewProviderInfo; 29import android.webkit.WebViewProviderResponse; 30 31import java.util.concurrent.CountDownLatch; 32 33import org.hamcrest.Description; 34 35import org.mockito.Mockito; 36import org.mockito.Matchers; 37import org.mockito.ArgumentMatcher; 38 39 40/** 41 * Tests for WebViewUpdateService 42 */ 43public class WebViewUpdateServiceTest extends AndroidTestCase { 44 private final static String TAG = WebViewUpdateServiceTest.class.getSimpleName(); 45 46 private WebViewUpdateServiceImpl mWebViewUpdateServiceImpl; 47 private TestSystemImpl mTestSystemImpl; 48 49 private static final String WEBVIEW_LIBRARY_FLAG = "com.android.webview.WebViewLibrary"; 50 51 @Override 52 protected void setUp() throws Exception { 53 super.setUp(); 54 } 55 56 /** 57 * Creates a new instance. 58 */ 59 public WebViewUpdateServiceTest() { 60 } 61 62 private void setupWithPackages(WebViewProviderInfo[] packages) { 63 setupWithPackages(packages, true); 64 } 65 66 private void setupWithPackages(WebViewProviderInfo[] packages, 67 boolean fallbackLogicEnabled) { 68 setupWithPackages(packages, fallbackLogicEnabled, 1); 69 } 70 71 private void setupWithPackages(WebViewProviderInfo[] packages, 72 boolean fallbackLogicEnabled, int numRelros) { 73 setupWithPackages(packages, fallbackLogicEnabled, numRelros, 74 true /* isDebuggable == true -> don't check package signatures */); 75 } 76 77 private void setupWithPackages(WebViewProviderInfo[] packages, 78 boolean fallbackLogicEnabled, int numRelros, boolean isDebuggable) { 79 TestSystemImpl testing = new TestSystemImpl(packages, fallbackLogicEnabled, numRelros, 80 isDebuggable); 81 mTestSystemImpl = Mockito.spy(testing); 82 mWebViewUpdateServiceImpl = 83 new WebViewUpdateServiceImpl(null /*Context*/, mTestSystemImpl); 84 } 85 86 private void setEnabledAndValidPackageInfos(WebViewProviderInfo[] providers) { 87 for(WebViewProviderInfo wpi : providers) { 88 mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true /* enabled */, 89 true /* valid */)); 90 } 91 } 92 93 private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName, 94 WebViewProviderInfo[] webviewPackages) { 95 checkCertainPackageUsedAfterWebViewBootPreparation( 96 expectedProviderName, webviewPackages, 1); 97 } 98 99 private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName, 100 WebViewProviderInfo[] webviewPackages, int numRelros) { 101 setupWithPackages(webviewPackages, true, numRelros); 102 // Add (enabled and valid) package infos for each provider 103 setEnabledAndValidPackageInfos(webviewPackages); 104 105 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 106 107 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 108 Mockito.argThat(new IsPackageInfoWithName(expectedProviderName))); 109 110 for (int n = 0; n < numRelros; n++) { 111 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 112 } 113 114 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 115 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); 116 assertEquals(expectedProviderName, response.packageInfo.packageName); 117 } 118 119 // For matching the package name of a PackageInfo 120 private class IsPackageInfoWithName extends ArgumentMatcher<PackageInfo> { 121 private final String mPackageName; 122 123 IsPackageInfoWithName(String name) { 124 mPackageName = name; 125 } 126 127 @Override 128 public boolean matches(Object p) { 129 return ((PackageInfo) p).packageName.equals(mPackageName); 130 } 131 132 // Provide a more useful description in case of mismatch 133 @Override 134 public void describeTo (Description description) { 135 description.appendText(String.format("PackageInfo with name '%s'", mPackageName)); 136 } 137 } 138 139 private static PackageInfo createPackageInfo( 140 String packageName, boolean enabled, boolean valid) { 141 PackageInfo p = new PackageInfo(); 142 p.packageName = packageName; 143 p.applicationInfo = new ApplicationInfo(); 144 p.applicationInfo.enabled = enabled; 145 p.applicationInfo.metaData = new Bundle(); 146 if (valid) { 147 // no flag means invalid 148 p.applicationInfo.metaData.putString(WEBVIEW_LIBRARY_FLAG, "blah"); 149 } 150 return p; 151 } 152 153 private static PackageInfo createPackageInfo( 154 String packageName, boolean enabled, boolean valid, Signature[] signatures) { 155 PackageInfo p = createPackageInfo(packageName, enabled, valid); 156 p.signatures = signatures; 157 return p; 158 } 159 160 private void checkPreparationPhasesForPackage(String expectedPackage, int numPreparation) { 161 // Verify that onWebViewProviderChanged was called for the numPreparation'th time for the 162 // expected package 163 Mockito.verify(mTestSystemImpl, Mockito.times(numPreparation)).onWebViewProviderChanged( 164 Mockito.argThat(new IsPackageInfoWithName(expectedPackage))); 165 166 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 167 168 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 169 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); 170 assertEquals(expectedPackage, response.packageInfo.packageName); 171 } 172 173 174 // **************** 175 // Tests 176 // **************** 177 178 179 public void testWithSinglePackage() { 180 String testPackageName = "test.package.name"; 181 checkCertainPackageUsedAfterWebViewBootPreparation(testPackageName, 182 new WebViewProviderInfo[] { 183 new WebViewProviderInfo(testPackageName, "", 184 true /*default available*/, false /* fallback */, null)}); 185 } 186 187 public void testDefaultPackageUsedOverNonDefault() { 188 String defaultPackage = "defaultPackage"; 189 String nonDefaultPackage = "nonDefaultPackage"; 190 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 191 new WebViewProviderInfo(nonDefaultPackage, "", false, false, null), 192 new WebViewProviderInfo(defaultPackage, "", true, false, null)}; 193 checkCertainPackageUsedAfterWebViewBootPreparation(defaultPackage, packages); 194 } 195 196 public void testSeveralRelros() { 197 String singlePackage = "singlePackage"; 198 checkCertainPackageUsedAfterWebViewBootPreparation( 199 singlePackage, 200 new WebViewProviderInfo[] { 201 new WebViewProviderInfo(singlePackage, "", true /*def av*/, false, null)}, 202 2); 203 } 204 205 // Ensure that package with valid signatures is chosen rather than package with invalid 206 // signatures. 207 public void testWithSignatures() { 208 String validPackage = "valid package"; 209 String invalidPackage = "invalid package"; 210 211 Signature validSignature = new Signature("11"); 212 Signature invalidExpectedSignature = new Signature("22"); 213 Signature invalidPackageSignature = new Signature("33"); 214 215 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 216 new WebViewProviderInfo(invalidPackage, "", true, false, new String[]{ 217 Base64.encodeToString( 218 invalidExpectedSignature.toByteArray(), Base64.DEFAULT)}), 219 new WebViewProviderInfo(validPackage, "", true, false, new String[]{ 220 Base64.encodeToString( 221 validSignature.toByteArray(), Base64.DEFAULT)}) 222 }; 223 setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */, 224 false /* isDebuggable */); 225 mTestSystemImpl.setPackageInfo(createPackageInfo(invalidPackage, true /* enabled */, 226 true /* valid */, new Signature[]{invalidPackageSignature})); 227 mTestSystemImpl.setPackageInfo(createPackageInfo(validPackage, true /* enabled */, 228 true /* valid */, new Signature[]{validSignature})); 229 230 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 231 232 233 checkPreparationPhasesForPackage(validPackage, 1 /* first preparation for this package */); 234 235 WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages(); 236 assertEquals(1, validPackages.length); 237 assertEquals(validPackage, validPackages[0].packageName); 238 } 239 240 public void testFailWaitingForRelro() { 241 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 242 new WebViewProviderInfo("packagename", "", true, true, null)}; 243 setupWithPackages(packages); 244 setEnabledAndValidPackageInfos(packages); 245 246 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 247 248 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 249 Mockito.argThat(new IsPackageInfoWithName(packages[0].packageName))); 250 251 // Never call notifyRelroCreation() 252 253 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 254 assertEquals(WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO, response.status); 255 } 256 257 public void testFailListingEmptyWebviewPackages() { 258 WebViewProviderInfo[] packages = new WebViewProviderInfo[0]; 259 setupWithPackages(packages); 260 setEnabledAndValidPackageInfos(packages); 261 262 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 263 264 Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged( 265 Matchers.anyObject()); 266 267 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 268 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 269 } 270 271 public void testFailListingInvalidWebviewPackage() { 272 WebViewProviderInfo wpi = new WebViewProviderInfo("package", "", true, true, null); 273 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {wpi}; 274 setupWithPackages(packages); 275 mTestSystemImpl.setPackageInfo( 276 createPackageInfo(wpi.packageName, true /* enabled */, false /* valid */)); 277 278 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 279 280 Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged( 281 Matchers.anyObject()); 282 283 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 284 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 285 286 // Verify that we can recover from failing to list webview packages. 287 mTestSystemImpl.setPackageInfo( 288 createPackageInfo(wpi.packageName, true /* enabled */, true /* valid */)); 289 mWebViewUpdateServiceImpl.packageStateChanged(wpi.packageName, 290 WebViewUpdateService.PACKAGE_ADDED_REPLACED); 291 292 checkPreparationPhasesForPackage(wpi.packageName, 1); 293 } 294 295 // Test that switching provider using changeProviderAndSetting works. 296 public void testSwitchingProvider() { 297 String firstPackage = "first"; 298 String secondPackage = "second"; 299 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 300 new WebViewProviderInfo(firstPackage, "", true, false, null), 301 new WebViewProviderInfo(secondPackage, "", true, false, null)}; 302 checkSwitchingProvider(packages, firstPackage, secondPackage); 303 } 304 305 public void testSwitchingProviderToNonDefault() { 306 String defaultPackage = "defaultPackage"; 307 String nonDefaultPackage = "nonDefaultPackage"; 308 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 309 new WebViewProviderInfo(defaultPackage, "", true, false, null), 310 new WebViewProviderInfo(nonDefaultPackage, "", false, false, null)}; 311 checkSwitchingProvider(packages, defaultPackage, nonDefaultPackage); 312 } 313 314 private void checkSwitchingProvider(WebViewProviderInfo[] packages, String initialPackage, 315 String finalPackage) { 316 checkCertainPackageUsedAfterWebViewBootPreparation(initialPackage, packages); 317 318 mWebViewUpdateServiceImpl.changeProviderAndSetting(finalPackage); 319 checkPreparationPhasesForPackage(finalPackage, 1 /* first preparation for this package */); 320 321 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(initialPackage)); 322 } 323 324 // Change provider during relro creation by using changeProviderAndSetting 325 public void testSwitchingProviderDuringRelroCreation() { 326 checkChangingProviderDuringRelroCreation(true); 327 } 328 329 // Change provider during relro creation by enabling a provider 330 public void testChangingProviderThroughEnablingDuringRelroCreation() { 331 checkChangingProviderDuringRelroCreation(false); 332 } 333 334 private void checkChangingProviderDuringRelroCreation(boolean settingsChange) { 335 String firstPackage = "first"; 336 String secondPackage = "second"; 337 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 338 new WebViewProviderInfo(firstPackage, "", true, false, null), 339 new WebViewProviderInfo(secondPackage, "", true, false, null)}; 340 setupWithPackages(packages); 341 if (settingsChange) { 342 // Have all packages be enabled, so that we can change provider however we want to 343 setEnabledAndValidPackageInfos(packages); 344 } else { 345 // Have all packages be disabled so that we can change one to enabled later 346 for(WebViewProviderInfo wpi : packages) { 347 mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, 348 false /* enabled */, true /* valid */)); 349 } 350 } 351 352 CountDownLatch countdown = new CountDownLatch(1); 353 354 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 355 356 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 357 Mockito.argThat(new IsPackageInfoWithName(firstPackage))); 358 359 assertEquals(firstPackage, mWebViewUpdateServiceImpl.getCurrentWebViewPackageName()); 360 361 new Thread(new Runnable() { 362 @Override 363 public void run() { 364 WebViewProviderResponse threadResponse = 365 mWebViewUpdateServiceImpl.waitForAndGetProvider(); 366 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, threadResponse.status); 367 assertEquals(secondPackage, threadResponse.packageInfo.packageName); 368 // Verify that we killed the first package 369 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage)); 370 countdown.countDown(); 371 } 372 }).start(); 373 try { 374 Thread.sleep(1000); // Let the new thread run / be blocked 375 } catch (InterruptedException e) { 376 } 377 378 if (settingsChange) { 379 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 380 } else { 381 // Switch provider by enabling the second one 382 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 383 true /* valid */)); 384 mWebViewUpdateServiceImpl.packageStateChanged( 385 secondPackage, WebViewUpdateService.PACKAGE_CHANGED); 386 } 387 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 388 // first package done, should start on second 389 390 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 391 Mockito.argThat(new IsPackageInfoWithName(secondPackage))); 392 393 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 394 // second package done, the other thread should now be unblocked 395 try { 396 countdown.await(); 397 } catch (InterruptedException e) { 398 } 399 } 400 401 public void testRunFallbackLogicIfEnabled() { 402 checkFallbackLogicBeingRun(true); 403 } 404 405 public void testDontRunFallbackLogicIfDisabled() { 406 checkFallbackLogicBeingRun(false); 407 } 408 409 private void checkFallbackLogicBeingRun(boolean fallbackLogicEnabled) { 410 String primaryPackage = "primary"; 411 String fallbackPackage = "fallback"; 412 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 413 new WebViewProviderInfo( 414 primaryPackage, "", true /* default available */, false /* fallback */, null), 415 new WebViewProviderInfo( 416 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 417 setupWithPackages(packages, fallbackLogicEnabled); 418 setEnabledAndValidPackageInfos(packages); 419 420 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 421 // Verify that we disable the fallback package if fallback logic enabled, and don't disable 422 // the fallback package if that logic is disabled 423 if (fallbackLogicEnabled) { 424 Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers( 425 Matchers.anyObject(), Mockito.eq(fallbackPackage)); 426 } else { 427 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers( 428 Matchers.anyObject(), Matchers.anyObject()); 429 } 430 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 431 Mockito.argThat(new IsPackageInfoWithName(primaryPackage))); 432 433 // Enable fallback package 434 mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */, 435 true /* valid */)); 436 mWebViewUpdateServiceImpl.packageStateChanged( 437 fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED); 438 439 if (fallbackLogicEnabled) { 440 // Check that we have now disabled the fallback package twice 441 Mockito.verify(mTestSystemImpl, Mockito.times(2)).uninstallAndDisablePackageForAllUsers( 442 Matchers.anyObject(), Mockito.eq(fallbackPackage)); 443 } else { 444 // Check that we still haven't disabled any package 445 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers( 446 Matchers.anyObject(), Matchers.anyObject()); 447 } 448 } 449 450 /** 451 * Scenario for installing primary package when fallback enabled. 452 * 1. Start with only fallback installed 453 * 2. Install non-fallback 454 * 3. Fallback should be disabled 455 */ 456 public void testInstallingNonFallbackPackage() { 457 String primaryPackage = "primary"; 458 String fallbackPackage = "fallback"; 459 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 460 new WebViewProviderInfo( 461 primaryPackage, "", true /* default available */, false /* fallback */, null), 462 new WebViewProviderInfo( 463 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 464 setupWithPackages(packages, true /* isFallbackLogicEnabled */); 465 mTestSystemImpl.setPackageInfo( 466 createPackageInfo(fallbackPackage, true /* enabled */ , true /* valid */)); 467 468 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 469 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers( 470 Matchers.anyObject(), Matchers.anyObject()); 471 472 checkPreparationPhasesForPackage(fallbackPackage, 473 1 /* first preparation for this package*/); 474 475 // Install primary package 476 mTestSystemImpl.setPackageInfo( 477 createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */)); 478 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 479 WebViewUpdateService.PACKAGE_ADDED_REPLACED); 480 481 // Verify fallback disabled, primary package used as provider, and fallback package killed 482 Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers( 483 Matchers.anyObject(), Mockito.eq(fallbackPackage)); 484 checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation for this package*/); 485 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(fallbackPackage)); 486 } 487 488 public void testFallbackChangesEnabledState() { 489 String primaryPackage = "primary"; 490 String fallbackPackage = "fallback"; 491 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 492 new WebViewProviderInfo( 493 primaryPackage, "", true /* default available */, false /* fallback */, null), 494 new WebViewProviderInfo( 495 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 496 setupWithPackages(packages, true /* fallbackLogicEnabled */); 497 setEnabledAndValidPackageInfos(packages); 498 499 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 500 501 // Verify fallback disabled at boot when primary package enabled 502 Mockito.verify(mTestSystemImpl).enablePackageForUser( 503 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, 504 Matchers.anyInt()); 505 506 checkPreparationPhasesForPackage(primaryPackage, 1); 507 508 // Disable primary package and ensure fallback becomes enabled and used 509 mTestSystemImpl.setPackageInfo( 510 createPackageInfo(primaryPackage, false /* enabled */, true /* valid */)); 511 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 512 WebViewUpdateService.PACKAGE_CHANGED); 513 514 Mockito.verify(mTestSystemImpl).enablePackageForUser( 515 Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */, 516 Matchers.anyInt()); 517 518 checkPreparationPhasesForPackage(fallbackPackage, 1); 519 520 521 // Again enable primary package and verify primary is used and fallback becomes disabled 522 mTestSystemImpl.setPackageInfo( 523 createPackageInfo(primaryPackage, true /* enabled */, true /* valid */)); 524 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 525 WebViewUpdateService.PACKAGE_CHANGED); 526 527 // Verify fallback is disabled a second time when primary package becomes enabled 528 Mockito.verify(mTestSystemImpl, Mockito.times(2)).enablePackageForUser( 529 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, 530 Matchers.anyInt()); 531 532 checkPreparationPhasesForPackage(primaryPackage, 2); 533 } 534 535 public void testAddUserWhenFallbackLogicEnabled() { 536 checkAddingNewUser(true); 537 } 538 539 public void testAddUserWhenFallbackLogicDisabled() { 540 checkAddingNewUser(false); 541 } 542 543 public void checkAddingNewUser(boolean fallbackLogicEnabled) { 544 String primaryPackage = "primary"; 545 String fallbackPackage = "fallback"; 546 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 547 new WebViewProviderInfo( 548 primaryPackage, "", true /* default available */, false /* fallback */, null), 549 new WebViewProviderInfo( 550 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 551 setupWithPackages(packages, fallbackLogicEnabled); 552 setEnabledAndValidPackageInfos(packages); 553 int newUser = 100; 554 mWebViewUpdateServiceImpl.handleNewUser(newUser); 555 if (fallbackLogicEnabled) { 556 // Verify fallback package becomes disabled for new user 557 Mockito.verify(mTestSystemImpl).enablePackageForUser( 558 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, 559 Mockito.eq(newUser)); 560 } else { 561 // Verify that we don't disable fallback for new user 562 Mockito.verify(mTestSystemImpl, Mockito.never()).enablePackageForUser( 563 Mockito.anyObject(), Matchers.anyBoolean() /* enable */, 564 Matchers.anyInt() /* user */); 565 } 566 } 567 568 /** 569 * Timing dependent test where we verify that the list of valid webview packages becoming empty 570 * at a certain point doesn't crash us or break our state. 571 */ 572 public void testNotifyRelroDoesntCrashIfNoPackages() { 573 String firstPackage = "first"; 574 String secondPackage = "second"; 575 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 576 new WebViewProviderInfo(firstPackage, "", true /* default available */, 577 false /* fallback */, null), 578 new WebViewProviderInfo(secondPackage, "", true /* default available */, 579 false /* fallback */, null)}; 580 setupWithPackages(packages); 581 // Add (enabled and valid) package infos for each provider 582 setEnabledAndValidPackageInfos(packages); 583 584 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 585 586 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 587 Mockito.argThat(new IsPackageInfoWithName(firstPackage))); 588 589 // Change provider during relro creation to enter a state where we are 590 // waiting for relro creation to complete just to re-run relro creation. 591 // (so that in next notifyRelroCreationCompleted() call we have to list webview packages) 592 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 593 594 // Make packages invalid to cause exception to be thrown 595 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */, 596 false /* valid */)); 597 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 598 false /* valid */)); 599 600 // This shouldn't throw an exception! 601 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 602 603 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 604 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 605 606 // Now make a package valid again and verify that we can switch back to that 607 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */, 608 true /* valid */)); 609 610 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage, 611 WebViewUpdateService.PACKAGE_ADDED_REPLACED); 612 613 // Ensure we use firstPackage 614 checkPreparationPhasesForPackage(firstPackage, 2 /* second preparation for this package */); 615 } 616 617 /** 618 * Verify that even if a user-chosen package is removed temporarily we start using it again when 619 * it is added back. 620 */ 621 public void testTempRemovePackageDoesntSwitchProviderPermanently() { 622 String firstPackage = "first"; 623 String secondPackage = "second"; 624 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 625 new WebViewProviderInfo(firstPackage, "", true /* default available */, 626 false /* fallback */, null), 627 new WebViewProviderInfo(secondPackage, "", true /* default available */, 628 false /* fallback */, null)}; 629 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages); 630 631 // Explicitly use the second package 632 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 633 checkPreparationPhasesForPackage(secondPackage, 1 /* first time for this package */); 634 635 // Remove second package (invalidate it) and verify that first package is used 636 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 637 false /* valid */)); 638 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage, 639 WebViewUpdateService.PACKAGE_ADDED); 640 checkPreparationPhasesForPackage(firstPackage, 2 /* second time for this package */); 641 642 // Now make the second package valid again and verify that it is used again 643 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 644 true /* valid */)); 645 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage, 646 WebViewUpdateService.PACKAGE_ADDED); 647 checkPreparationPhasesForPackage(secondPackage, 2 /* second time for this package */); 648 } 649 650 /** 651 * Ensure that we update the user-chosen setting across boots if the chosen package is no 652 * longer installed and valid. 653 */ 654 public void testProviderSettingChangedDuringBootIfProviderNotAvailable() { 655 String chosenPackage = "chosenPackage"; 656 String nonChosenPackage = "non-chosenPackage"; 657 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 658 new WebViewProviderInfo(chosenPackage, "", true /* default available */, 659 false /* fallback */, null), 660 new WebViewProviderInfo(nonChosenPackage, "", true /* default available */, 661 false /* fallback */, null)}; 662 663 setupWithPackages(packages); 664 // Only 'install' nonChosenPackage 665 mTestSystemImpl.setPackageInfo( 666 createPackageInfo(nonChosenPackage, true /* enabled */, true /* valid */)); 667 668 // Set user-chosen package 669 mTestSystemImpl.updateUserSetting(null, chosenPackage); 670 671 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 672 673 // Verify that we switch the setting to point to the current package 674 Mockito.verify(mTestSystemImpl).updateUserSetting( 675 Mockito.anyObject(), Mockito.eq(nonChosenPackage)); 676 assertEquals(nonChosenPackage, mTestSystemImpl.getUserChosenWebViewProvider(null)); 677 678 checkPreparationPhasesForPackage(nonChosenPackage, 1); 679 } 680 681 public void testRecoverFailedListingWebViewPackagesSettingsChange() { 682 checkRecoverAfterFailListingWebviewPackages(true); 683 } 684 685 public void testRecoverFailedListingWebViewPackagesAddedPackage() { 686 checkRecoverAfterFailListingWebviewPackages(false); 687 } 688 689 /** 690 * Test that we can recover correctly from failing to list WebView packages. 691 * settingsChange: whether to fail during changeProviderAndSetting or packageStateChanged 692 */ 693 public void checkRecoverAfterFailListingWebviewPackages(boolean settingsChange) { 694 String firstPackage = "first"; 695 String secondPackage = "second"; 696 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 697 new WebViewProviderInfo(firstPackage, "", true /* default available */, 698 false /* fallback */, null), 699 new WebViewProviderInfo(secondPackage, "", true /* default available */, 700 false /* fallback */, null)}; 701 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages); 702 703 // Make both packages invalid so that we fail listing WebView packages 704 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */, 705 false /* valid */)); 706 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 707 false /* valid */)); 708 709 // Change package to hit the webview packages listing problem. 710 if (settingsChange) { 711 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 712 } else { 713 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage, 714 WebViewUpdateService.PACKAGE_ADDED_REPLACED); 715 } 716 717 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 718 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 719 720 // Make second package valid and verify that we can load it again 721 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 722 true /* valid */)); 723 724 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage, 725 WebViewUpdateService.PACKAGE_ADDED_REPLACED); 726 727 728 checkPreparationPhasesForPackage(secondPackage, 1); 729 } 730 731 public void testDontKillIfPackageReplaced() { 732 checkDontKillIfPackageRemoved(true); 733 } 734 735 public void testDontKillIfPackageRemoved() { 736 checkDontKillIfPackageRemoved(false); 737 } 738 739 public void checkDontKillIfPackageRemoved(boolean replaced) { 740 String firstPackage = "first"; 741 String secondPackage = "second"; 742 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 743 new WebViewProviderInfo(firstPackage, "", true /* default available */, 744 false /* fallback */, null), 745 new WebViewProviderInfo(secondPackage, "", true /* default available */, 746 false /* fallback */, null)}; 747 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages); 748 749 // Replace or remove the current webview package 750 if (replaced) { 751 mTestSystemImpl.setPackageInfo( 752 createPackageInfo(firstPackage, true /* enabled */, false /* valid */)); 753 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage, 754 WebViewUpdateService.PACKAGE_ADDED_REPLACED); 755 } else { 756 mTestSystemImpl.removePackageInfo(firstPackage); 757 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage, 758 WebViewUpdateService.PACKAGE_REMOVED); 759 } 760 761 checkPreparationPhasesForPackage(secondPackage, 1); 762 763 Mockito.verify(mTestSystemImpl, Mockito.never()).killPackageDependents( 764 Mockito.anyObject()); 765 } 766 767 public void testKillIfSettingChanged() { 768 String firstPackage = "first"; 769 String secondPackage = "second"; 770 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 771 new WebViewProviderInfo(firstPackage, "", true /* default available */, 772 false /* fallback */, null), 773 new WebViewProviderInfo(secondPackage, "", true /* default available */, 774 false /* fallback */, null)}; 775 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages); 776 777 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 778 779 checkPreparationPhasesForPackage(secondPackage, 1); 780 781 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage)); 782 } 783 784 /** 785 * Test that we kill apps using an old provider when we change the provider setting, even if the 786 * new provider is not the one we intended to change to. 787 */ 788 public void testKillIfChangeProviderIncorrectly() { 789 String firstPackage = "first"; 790 String secondPackage = "second"; 791 String thirdPackage = "third"; 792 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 793 new WebViewProviderInfo(firstPackage, "", true /* default available */, 794 false /* fallback */, null), 795 new WebViewProviderInfo(secondPackage, "", true /* default available */, 796 false /* fallback */, null), 797 new WebViewProviderInfo(thirdPackage, "", true /* default available */, 798 false /* fallback */, null)}; 799 setupWithPackages(packages); 800 setEnabledAndValidPackageInfos(packages); 801 802 // Start with the setting pointing to the third package 803 mTestSystemImpl.updateUserSetting(null, thirdPackage); 804 805 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 806 checkPreparationPhasesForPackage(thirdPackage, 1); 807 808 mTestSystemImpl.setPackageInfo( 809 createPackageInfo(secondPackage, true /* enabled */, false /* valid */)); 810 811 // Try to switch to the invalid second package, this should result in switching to the first 812 // package, since that is more preferred than the third one. 813 assertEquals(firstPackage, 814 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage)); 815 816 checkPreparationPhasesForPackage(firstPackage, 1); 817 818 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(thirdPackage)); 819 } 820} 821