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.assertArrayEquals; 20import static org.junit.Assert.assertEquals; 21import static org.junit.Assert.assertFalse; 22import static org.junit.Assert.assertTrue; 23 24import android.content.Context; 25import android.content.pm.ApplicationInfo; 26import android.content.pm.PackageInfo; 27import android.content.pm.Signature; 28import android.os.Build; 29import android.os.Bundle; 30import android.support.test.InstrumentationRegistry; 31import android.support.test.runner.AndroidJUnit4; 32import android.test.suitebuilder.annotation.MediumTest; 33import android.util.Base64; 34import android.webkit.WebViewFactory; 35import android.webkit.WebViewProviderInfo; 36import android.webkit.WebViewProviderResponse; 37 38import org.junit.Test; 39import org.junit.runner.RunWith; 40 41import org.mockito.Mockito; 42import org.mockito.Matchers; 43import org.mockito.compat.ArgumentMatcher; 44 45import java.lang.Integer; 46import java.util.concurrent.CountDownLatch; 47 48 49/** 50 * Tests for WebViewUpdateService 51 runtest --path frameworks/base/services/tests/servicestests/ \ 52 -c com.android.server.webkit.WebViewUpdateServiceTest 53 */ 54// Use MediumTest instead of SmallTest as the implementation of WebViewUpdateService 55// is intended to work on several threads and uses at least one sleep/wait-statement. 56@RunWith(AndroidJUnit4.class) 57@MediumTest 58public class WebViewUpdateServiceTest { 59 private final static String TAG = WebViewUpdateServiceTest.class.getSimpleName(); 60 61 private WebViewUpdateServiceImpl mWebViewUpdateServiceImpl; 62 private TestSystemImpl mTestSystemImpl; 63 64 private static final String WEBVIEW_LIBRARY_FLAG = "com.android.webview.WebViewLibrary"; 65 66 /** 67 * Creates a new instance. 68 */ 69 public WebViewUpdateServiceTest() { 70 } 71 72 private void setupWithPackages(WebViewProviderInfo[] packages) { 73 setupWithPackages(packages, true); 74 } 75 76 private void setupWithPackages(WebViewProviderInfo[] packages, 77 boolean fallbackLogicEnabled) { 78 setupWithPackages(packages, fallbackLogicEnabled, 1); 79 } 80 81 private void setupWithPackages(WebViewProviderInfo[] packages, 82 boolean fallbackLogicEnabled, int numRelros) { 83 setupWithPackages(packages, fallbackLogicEnabled, numRelros, 84 true /* isDebuggable == true -> don't check package signatures */); 85 } 86 87 private void setupWithPackages(WebViewProviderInfo[] packages, 88 boolean fallbackLogicEnabled, int numRelros, boolean isDebuggable) { 89 setupWithPackages(packages, fallbackLogicEnabled, numRelros, isDebuggable, 90 false /* multiProcessDefault */); 91 } 92 93 private void setupWithPackages(WebViewProviderInfo[] packages, 94 boolean fallbackLogicEnabled, int numRelros, boolean isDebuggable, 95 boolean multiProcessDefault) { 96 TestSystemImpl testing = new TestSystemImpl(packages, fallbackLogicEnabled, numRelros, 97 isDebuggable, multiProcessDefault); 98 mTestSystemImpl = Mockito.spy(testing); 99 mWebViewUpdateServiceImpl = 100 new WebViewUpdateServiceImpl(null /*Context*/, mTestSystemImpl); 101 } 102 103 private void setEnabledAndValidPackageInfos(WebViewProviderInfo[] providers) { 104 // Set package infos for the primary user (user 0). 105 setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, providers); 106 } 107 108 private void setEnabledAndValidPackageInfosForUser(int userId, 109 WebViewProviderInfo[] providers) { 110 for(WebViewProviderInfo wpi : providers) { 111 mTestSystemImpl.setPackageInfoForUser(userId, createPackageInfo(wpi.packageName, 112 true /* enabled */, true /* valid */, true /* installed */)); 113 } 114 } 115 116 private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName, 117 WebViewProviderInfo[] webviewPackages) { 118 checkCertainPackageUsedAfterWebViewBootPreparation( 119 expectedProviderName, webviewPackages, 1); 120 } 121 122 private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName, 123 WebViewProviderInfo[] webviewPackages, int numRelros) { 124 setupWithPackages(webviewPackages, true, numRelros); 125 // Add (enabled and valid) package infos for each provider 126 setEnabledAndValidPackageInfos(webviewPackages); 127 128 runWebViewBootPreparationOnMainSync(); 129 130 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 131 Mockito.argThat(new IsPackageInfoWithName(expectedProviderName))); 132 133 for (int n = 0; n < numRelros; n++) { 134 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 135 } 136 137 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 138 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); 139 assertEquals(expectedProviderName, response.packageInfo.packageName); 140 } 141 142 // For matching the package name of a PackageInfo 143 private class IsPackageInfoWithName extends ArgumentMatcher<PackageInfo> { 144 private final String mPackageName; 145 146 IsPackageInfoWithName(String name) { 147 mPackageName = name; 148 } 149 150 @Override 151 public boolean matchesObject(Object p) { 152 return ((PackageInfo) p).packageName.equals(mPackageName); 153 } 154 155 @Override 156 public String toString() { 157 return String.format("PackageInfo with name '%s'", mPackageName); 158 } 159 } 160 161 private static PackageInfo createPackageInfo( 162 String packageName, boolean enabled, boolean valid, boolean installed) { 163 PackageInfo p = new PackageInfo(); 164 p.packageName = packageName; 165 p.applicationInfo = new ApplicationInfo(); 166 p.applicationInfo.enabled = enabled; 167 p.applicationInfo.metaData = new Bundle(); 168 if (installed) { 169 p.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED; 170 } else { 171 p.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED; 172 } 173 if (valid) { 174 // no flag means invalid 175 p.applicationInfo.metaData.putString(WEBVIEW_LIBRARY_FLAG, "blah"); 176 } 177 // Default to this package being valid in terms of targetSdkVersion. 178 p.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; 179 return p; 180 } 181 182 private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid, 183 boolean installed, Signature[] signatures, long updateTime) { 184 PackageInfo p = createPackageInfo(packageName, enabled, valid, installed); 185 p.signatures = signatures; 186 p.lastUpdateTime = updateTime; 187 return p; 188 } 189 190 private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid, 191 boolean installed, Signature[] signatures, long updateTime, boolean hidden) { 192 PackageInfo p = 193 createPackageInfo(packageName, enabled, valid, installed, signatures, updateTime); 194 if (hidden) { 195 p.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN; 196 } else { 197 p.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN; 198 } 199 return p; 200 } 201 202 private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid, 203 boolean installed, Signature[] signatures, long updateTime, boolean hidden, 204 int versionCode, boolean isSystemApp) { 205 PackageInfo p = createPackageInfo(packageName, enabled, valid, installed, signatures, 206 updateTime, hidden); 207 p.versionCode = versionCode; 208 p.applicationInfo.versionCode = versionCode; 209 if (isSystemApp) p.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; 210 return p; 211 } 212 213 private void checkPreparationPhasesForPackage(String expectedPackage, int numPreparation) { 214 // Verify that onWebViewProviderChanged was called for the numPreparation'th time for the 215 // expected package 216 Mockito.verify(mTestSystemImpl, Mockito.times(numPreparation)).onWebViewProviderChanged( 217 Mockito.argThat(new IsPackageInfoWithName(expectedPackage))); 218 219 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 220 221 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 222 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); 223 assertEquals(expectedPackage, response.packageInfo.packageName); 224 } 225 226 /** 227 * The WebView preparation boot phase is run on the main thread (especially on a thread with a 228 * looper) so to avoid bugs where our tests fail because a looper hasn't been attached to the 229 * thread running prepareWebViewInSystemServer we run it on the main thread. 230 */ 231 private void runWebViewBootPreparationOnMainSync() { 232 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 233 @Override 234 public void run() { 235 mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); 236 } 237 }); 238 } 239 240 241 // **************** 242 // Tests 243 // **************** 244 245 246 @Test 247 public void testWithSinglePackage() { 248 String testPackageName = "test.package.name"; 249 checkCertainPackageUsedAfterWebViewBootPreparation(testPackageName, 250 new WebViewProviderInfo[] { 251 new WebViewProviderInfo(testPackageName, "", 252 true /*default available*/, false /* fallback */, null)}); 253 } 254 255 @Test 256 public void testDefaultPackageUsedOverNonDefault() { 257 String defaultPackage = "defaultPackage"; 258 String nonDefaultPackage = "nonDefaultPackage"; 259 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 260 new WebViewProviderInfo(nonDefaultPackage, "", false, false, null), 261 new WebViewProviderInfo(defaultPackage, "", true, false, null)}; 262 checkCertainPackageUsedAfterWebViewBootPreparation(defaultPackage, packages); 263 } 264 265 @Test 266 public void testSeveralRelros() { 267 String singlePackage = "singlePackage"; 268 checkCertainPackageUsedAfterWebViewBootPreparation( 269 singlePackage, 270 new WebViewProviderInfo[] { 271 new WebViewProviderInfo(singlePackage, "", true /*def av*/, false, null)}, 272 2); 273 } 274 275 // Ensure that package with valid signatures is chosen rather than package with invalid 276 // signatures. 277 @Test 278 public void testWithSignatures() { 279 String validPackage = "valid package"; 280 String invalidPackage = "invalid package"; 281 282 Signature validSignature = new Signature("11"); 283 Signature invalidExpectedSignature = new Signature("22"); 284 Signature invalidPackageSignature = new Signature("33"); 285 286 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 287 new WebViewProviderInfo(invalidPackage, "", true, false, new String[]{ 288 Base64.encodeToString( 289 invalidExpectedSignature.toByteArray(), Base64.DEFAULT)}), 290 new WebViewProviderInfo(validPackage, "", true, false, new String[]{ 291 Base64.encodeToString( 292 validSignature.toByteArray(), Base64.DEFAULT)}) 293 }; 294 setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */, 295 false /* isDebuggable */); 296 mTestSystemImpl.setPackageInfo(createPackageInfo(invalidPackage, true /* enabled */, 297 true /* valid */, true /* installed */, new Signature[]{invalidPackageSignature} 298 , 0 /* updateTime */)); 299 mTestSystemImpl.setPackageInfo(createPackageInfo(validPackage, true /* enabled */, 300 true /* valid */, true /* installed */, new Signature[]{validSignature} 301 , 0 /* updateTime */)); 302 303 runWebViewBootPreparationOnMainSync(); 304 305 306 checkPreparationPhasesForPackage(validPackage, 1 /* first preparation for this package */); 307 308 WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages(); 309 assertEquals(1, validPackages.length); 310 assertEquals(validPackage, validPackages[0].packageName); 311 } 312 313 @Test 314 public void testFailWaitingForRelro() { 315 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 316 new WebViewProviderInfo("packagename", "", true, true, null)}; 317 setupWithPackages(packages); 318 setEnabledAndValidPackageInfos(packages); 319 320 runWebViewBootPreparationOnMainSync(); 321 322 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 323 Mockito.argThat(new IsPackageInfoWithName(packages[0].packageName))); 324 325 // Never call notifyRelroCreation() 326 327 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 328 assertEquals(WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO, response.status); 329 } 330 331 @Test 332 public void testFailListingEmptyWebviewPackages() { 333 WebViewProviderInfo[] packages = new WebViewProviderInfo[0]; 334 setupWithPackages(packages); 335 setEnabledAndValidPackageInfos(packages); 336 337 runWebViewBootPreparationOnMainSync(); 338 339 Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged( 340 Matchers.anyObject()); 341 342 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 343 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 344 assertEquals(null, mWebViewUpdateServiceImpl.getCurrentWebViewPackage()); 345 346 // Now install a package 347 String singlePackage = "singlePackage"; 348 packages = new WebViewProviderInfo[]{ 349 new WebViewProviderInfo(singlePackage, "", true, false, null)}; 350 setupWithPackages(packages); 351 setEnabledAndValidPackageInfos(packages); 352 353 mWebViewUpdateServiceImpl.packageStateChanged(singlePackage, 354 WebViewUpdateService.PACKAGE_ADDED, TestSystemImpl.PRIMARY_USER_ID); 355 356 checkPreparationPhasesForPackage(singlePackage, 1 /* number of finished preparations */); 357 assertEquals(singlePackage, 358 mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName); 359 360 // Remove the package again 361 mTestSystemImpl.removePackageInfo(singlePackage); 362 mWebViewUpdateServiceImpl.packageStateChanged(singlePackage, 363 WebViewUpdateService.PACKAGE_ADDED, TestSystemImpl.PRIMARY_USER_ID); 364 365 // Package removed - ensure our interface states that there is no package 366 response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 367 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 368 assertEquals(null, mWebViewUpdateServiceImpl.getCurrentWebViewPackage()); 369 } 370 371 @Test 372 public void testFailListingInvalidWebviewPackage() { 373 WebViewProviderInfo wpi = new WebViewProviderInfo("package", "", true, true, null); 374 WebViewProviderInfo[] packages = new WebViewProviderInfo[] {wpi}; 375 setupWithPackages(packages); 376 mTestSystemImpl.setPackageInfo( 377 createPackageInfo(wpi.packageName, true /* enabled */, false /* valid */, 378 true /* installed */)); 379 380 runWebViewBootPreparationOnMainSync(); 381 382 Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged( 383 Matchers.anyObject()); 384 385 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 386 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 387 388 // Verify that we can recover from failing to list webview packages. 389 mTestSystemImpl.setPackageInfo( 390 createPackageInfo(wpi.packageName, true /* enabled */, true /* valid */, 391 true /* installed */)); 392 mWebViewUpdateServiceImpl.packageStateChanged(wpi.packageName, 393 WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID); 394 395 checkPreparationPhasesForPackage(wpi.packageName, 1); 396 } 397 398 // Test that switching provider using changeProviderAndSetting works. 399 @Test 400 public void testSwitchingProvider() { 401 String firstPackage = "first"; 402 String secondPackage = "second"; 403 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 404 new WebViewProviderInfo(firstPackage, "", true, false, null), 405 new WebViewProviderInfo(secondPackage, "", true, false, null)}; 406 checkSwitchingProvider(packages, firstPackage, secondPackage); 407 } 408 409 @Test 410 public void testSwitchingProviderToNonDefault() { 411 String defaultPackage = "defaultPackage"; 412 String nonDefaultPackage = "nonDefaultPackage"; 413 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 414 new WebViewProviderInfo(defaultPackage, "", true, false, null), 415 new WebViewProviderInfo(nonDefaultPackage, "", false, false, null)}; 416 checkSwitchingProvider(packages, defaultPackage, nonDefaultPackage); 417 } 418 419 private void checkSwitchingProvider(WebViewProviderInfo[] packages, String initialPackage, 420 String finalPackage) { 421 checkCertainPackageUsedAfterWebViewBootPreparation(initialPackage, packages); 422 423 mWebViewUpdateServiceImpl.changeProviderAndSetting(finalPackage); 424 checkPreparationPhasesForPackage(finalPackage, 1 /* first preparation for this package */); 425 426 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(initialPackage)); 427 } 428 429 // Change provider during relro creation by using changeProviderAndSetting 430 @Test 431 public void testSwitchingProviderDuringRelroCreation() { 432 checkChangingProviderDuringRelroCreation(true); 433 } 434 435 // Change provider during relro creation by enabling a provider 436 @Test 437 public void testChangingProviderThroughEnablingDuringRelroCreation() { 438 checkChangingProviderDuringRelroCreation(false); 439 } 440 441 private void checkChangingProviderDuringRelroCreation(boolean settingsChange) { 442 String firstPackage = "first"; 443 String secondPackage = "second"; 444 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 445 new WebViewProviderInfo(firstPackage, "", true, false, null), 446 new WebViewProviderInfo(secondPackage, "", true, false, null)}; 447 setupWithPackages(packages); 448 // Have all packages be enabled, so that we can change provider however we want to 449 setEnabledAndValidPackageInfos(packages); 450 451 CountDownLatch countdown = new CountDownLatch(1); 452 453 runWebViewBootPreparationOnMainSync(); 454 455 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 456 Mockito.argThat(new IsPackageInfoWithName(firstPackage))); 457 458 assertEquals(firstPackage, 459 mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName); 460 461 new Thread(new Runnable() { 462 @Override 463 public void run() { 464 WebViewProviderResponse threadResponse = 465 mWebViewUpdateServiceImpl.waitForAndGetProvider(); 466 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, threadResponse.status); 467 assertEquals(secondPackage, threadResponse.packageInfo.packageName); 468 // Verify that we killed the first package if we performed a settings change - 469 // otherwise we had to disable the first package, in which case its dependents 470 // should have been killed by the framework. 471 if (settingsChange) { 472 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage)); 473 } 474 countdown.countDown(); 475 } 476 }).start(); 477 try { 478 Thread.sleep(500); // Let the new thread run / be blocked 479 } catch (InterruptedException e) { 480 } 481 482 if (settingsChange) { 483 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 484 } else { 485 // Enable the second provider 486 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 487 true /* valid */, true /* installed */)); 488 mWebViewUpdateServiceImpl.packageStateChanged( 489 secondPackage, WebViewUpdateService.PACKAGE_CHANGED, TestSystemImpl.PRIMARY_USER_ID); 490 491 // Ensure we haven't changed package yet. 492 assertEquals(firstPackage, 493 mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName); 494 495 // Switch provider by disabling the first one 496 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, false /* enabled */, 497 true /* valid */, true /* installed */)); 498 mWebViewUpdateServiceImpl.packageStateChanged( 499 firstPackage, WebViewUpdateService.PACKAGE_CHANGED, TestSystemImpl.PRIMARY_USER_ID); 500 } 501 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 502 // first package done, should start on second 503 504 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 505 Mockito.argThat(new IsPackageInfoWithName(secondPackage))); 506 507 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 508 // second package done, the other thread should now be unblocked 509 try { 510 countdown.await(); 511 } catch (InterruptedException e) { 512 } 513 } 514 515 @Test 516 public void testRunFallbackLogicIfEnabled() { 517 checkFallbackLogicBeingRun(true); 518 } 519 520 @Test 521 public void testDontRunFallbackLogicIfDisabled() { 522 checkFallbackLogicBeingRun(false); 523 } 524 525 private void checkFallbackLogicBeingRun(boolean fallbackLogicEnabled) { 526 String primaryPackage = "primary"; 527 String fallbackPackage = "fallback"; 528 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 529 new WebViewProviderInfo( 530 primaryPackage, "", true /* default available */, false /* fallback */, null), 531 new WebViewProviderInfo( 532 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 533 setupWithPackages(packages, fallbackLogicEnabled); 534 setEnabledAndValidPackageInfos(packages); 535 536 runWebViewBootPreparationOnMainSync(); 537 // Verify that we disable the fallback package if fallback logic enabled, and don't disable 538 // the fallback package if that logic is disabled 539 if (fallbackLogicEnabled) { 540 Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers( 541 Matchers.anyObject(), Mockito.eq(fallbackPackage)); 542 } else { 543 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers( 544 Matchers.anyObject(), Matchers.anyObject()); 545 } 546 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 547 Mockito.argThat(new IsPackageInfoWithName(primaryPackage))); 548 549 // Enable fallback package 550 mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */, 551 true /* valid */, true /* installed */)); 552 mWebViewUpdateServiceImpl.packageStateChanged( 553 fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED, TestSystemImpl.PRIMARY_USER_ID); 554 555 if (fallbackLogicEnabled) { 556 // Check that we have now disabled the fallback package twice 557 Mockito.verify(mTestSystemImpl, Mockito.times(2)).uninstallAndDisablePackageForAllUsers( 558 Matchers.anyObject(), Mockito.eq(fallbackPackage)); 559 } else { 560 // Check that we still haven't disabled any package 561 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers( 562 Matchers.anyObject(), Matchers.anyObject()); 563 } 564 } 565 566 /** 567 * Scenario for installing primary package when fallback enabled. 568 * 1. Start with only fallback installed 569 * 2. Install non-fallback 570 * 3. Fallback should be disabled 571 */ 572 @Test 573 public void testInstallingNonFallbackPackage() { 574 String primaryPackage = "primary"; 575 String fallbackPackage = "fallback"; 576 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 577 new WebViewProviderInfo( 578 primaryPackage, "", true /* default available */, false /* fallback */, null), 579 new WebViewProviderInfo( 580 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 581 setupWithPackages(packages, true /* isFallbackLogicEnabled */); 582 mTestSystemImpl.setPackageInfo( 583 createPackageInfo(fallbackPackage, true /* enabled */ , true /* valid */, 584 true /* installed */)); 585 586 runWebViewBootPreparationOnMainSync(); 587 Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers( 588 Matchers.anyObject(), Matchers.anyObject()); 589 590 checkPreparationPhasesForPackage(fallbackPackage, 591 1 /* first preparation for this package*/); 592 593 // Install primary package 594 mTestSystemImpl.setPackageInfo( 595 createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */, 596 true /* installed */)); 597 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 598 WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID); 599 600 // Verify fallback disabled, primary package used as provider, and fallback package killed 601 Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers( 602 Matchers.anyObject(), Mockito.eq(fallbackPackage)); 603 checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation for this package*/); 604 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(fallbackPackage)); 605 } 606 607 @Test 608 public void testFallbackChangesEnabledStateSingleUser() { 609 for (PackageRemovalType removalType : REMOVAL_TYPES) { 610 checkFallbackChangesEnabledState(false /* multiUser */, removalType); 611 } 612 } 613 614 @Test 615 public void testFallbackChangesEnabledStateMultiUser() { 616 for (PackageRemovalType removalType : REMOVAL_TYPES) { 617 checkFallbackChangesEnabledState(true /* multiUser */, removalType); 618 } 619 } 620 621 /** 622 * Represents how to remove a package during a tests (disabling it / uninstalling it / hiding 623 * it). 624 */ 625 private enum PackageRemovalType { 626 UNINSTALL, DISABLE, HIDE 627 } 628 629 private PackageRemovalType[] REMOVAL_TYPES = PackageRemovalType.class.getEnumConstants(); 630 631 public void checkFallbackChangesEnabledState(boolean multiUser, 632 PackageRemovalType removalType) { 633 String primaryPackage = "primary"; 634 String fallbackPackage = "fallback"; 635 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 636 new WebViewProviderInfo( 637 primaryPackage, "", true /* default available */, false /* fallback */, null), 638 new WebViewProviderInfo( 639 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 640 setupWithPackages(packages, true /* fallbackLogicEnabled */); 641 int secondaryUserId = 10; 642 int userIdToChangePackageFor = multiUser ? secondaryUserId : TestSystemImpl.PRIMARY_USER_ID; 643 if (multiUser) { 644 mTestSystemImpl.addUser(secondaryUserId); 645 setEnabledAndValidPackageInfosForUser(secondaryUserId, packages); 646 } 647 setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, packages); 648 649 runWebViewBootPreparationOnMainSync(); 650 651 // Verify fallback disabled at boot when primary package enabled 652 checkEnablePackageForUserCalled(fallbackPackage, false, multiUser 653 ? new int[] {TestSystemImpl.PRIMARY_USER_ID, secondaryUserId} 654 : new int[] {TestSystemImpl.PRIMARY_USER_ID}, 1 /* numUsages */); 655 656 checkPreparationPhasesForPackage(primaryPackage, 1); 657 658 boolean enabled = !(removalType == PackageRemovalType.DISABLE); 659 boolean installed = !(removalType == PackageRemovalType.UNINSTALL); 660 boolean hidden = (removalType == PackageRemovalType.HIDE); 661 // Disable primary package and ensure fallback becomes enabled and used 662 mTestSystemImpl.setPackageInfoForUser(userIdToChangePackageFor, 663 createPackageInfo(primaryPackage, enabled /* enabled */, true /* valid */, 664 installed /* installed */, null /* signature */, 0 /* updateTime */, 665 hidden /* hidden */)); 666 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 667 removalType == PackageRemovalType.DISABLE 668 ? WebViewUpdateService.PACKAGE_CHANGED : WebViewUpdateService.PACKAGE_REMOVED, 669 userIdToChangePackageFor); // USER ID 670 671 checkEnablePackageForUserCalled(fallbackPackage, true, multiUser 672 ? new int[] {TestSystemImpl.PRIMARY_USER_ID, secondaryUserId} 673 : new int[] {TestSystemImpl.PRIMARY_USER_ID}, 1 /* numUsages */); 674 675 checkPreparationPhasesForPackage(fallbackPackage, 1); 676 677 678 // Again enable primary package and verify primary is used and fallback becomes disabled 679 mTestSystemImpl.setPackageInfoForUser(userIdToChangePackageFor, 680 createPackageInfo(primaryPackage, true /* enabled */, true /* valid */, 681 true /* installed */)); 682 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 683 removalType == PackageRemovalType.DISABLE 684 ? WebViewUpdateService.PACKAGE_CHANGED : WebViewUpdateService.PACKAGE_ADDED, 685 userIdToChangePackageFor); 686 687 // Verify fallback is disabled a second time when primary package becomes enabled 688 checkEnablePackageForUserCalled(fallbackPackage, false, multiUser 689 ? new int[] {TestSystemImpl.PRIMARY_USER_ID, secondaryUserId} 690 : new int[] {TestSystemImpl.PRIMARY_USER_ID}, 2 /* numUsages */); 691 692 checkPreparationPhasesForPackage(primaryPackage, 2); 693 } 694 695 private void checkEnablePackageForUserCalled(String packageName, boolean expectEnabled, 696 int[] userIds, int numUsages) { 697 for (int userId : userIds) { 698 Mockito.verify(mTestSystemImpl, Mockito.times(numUsages)).enablePackageForUser( 699 Mockito.eq(packageName), Mockito.eq(expectEnabled), Mockito.eq(userId)); 700 } 701 } 702 703 @Test 704 public void testAddUserWhenFallbackLogicEnabled() { 705 checkAddingNewUser(true); 706 } 707 708 @Test 709 public void testAddUserWhenFallbackLogicDisabled() { 710 checkAddingNewUser(false); 711 } 712 713 public void checkAddingNewUser(boolean fallbackLogicEnabled) { 714 String primaryPackage = "primary"; 715 String fallbackPackage = "fallback"; 716 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 717 new WebViewProviderInfo( 718 primaryPackage, "", true /* default available */, false /* fallback */, null), 719 new WebViewProviderInfo( 720 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 721 setupWithPackages(packages, fallbackLogicEnabled); 722 setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, packages); 723 int newUser = 100; 724 mTestSystemImpl.addUser(newUser); 725 setEnabledAndValidPackageInfosForUser(newUser, packages); 726 mWebViewUpdateServiceImpl.handleNewUser(newUser); 727 if (fallbackLogicEnabled) { 728 // Verify fallback package becomes disabled for new user 729 Mockito.verify(mTestSystemImpl).enablePackageForUser( 730 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, 731 Mockito.eq(newUser)); 732 } else { 733 // Verify that we don't disable fallback for new user 734 Mockito.verify(mTestSystemImpl, Mockito.never()).enablePackageForUser( 735 Mockito.anyObject(), Matchers.anyBoolean() /* enable */, 736 Matchers.anyInt() /* user */); 737 } 738 } 739 740 /** 741 * Ensures that adding a new user for which the current WebView package is uninstalled causes a 742 * change of WebView provider. 743 */ 744 @Test 745 public void testAddingNewUserWithUninstalledPackage() { 746 String primaryPackage = "primary"; 747 String fallbackPackage = "fallback"; 748 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 749 new WebViewProviderInfo( 750 primaryPackage, "", true /* default available */, false /* fallback */, null), 751 new WebViewProviderInfo( 752 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 753 setupWithPackages(packages, true /* fallbackLogicEnabled */); 754 setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, packages); 755 int newUser = 100; 756 mTestSystemImpl.addUser(newUser); 757 // Let the primary package be uninstalled for the new user 758 mTestSystemImpl.setPackageInfoForUser(newUser, 759 createPackageInfo(primaryPackage, true /* enabled */, true /* valid */, 760 false /* installed */)); 761 mTestSystemImpl.setPackageInfoForUser(newUser, 762 createPackageInfo(fallbackPackage, false /* enabled */, true /* valid */, 763 true /* installed */)); 764 mWebViewUpdateServiceImpl.handleNewUser(newUser); 765 // Verify fallback package doesn't become disabled for the primary user. 766 Mockito.verify(mTestSystemImpl, Mockito.never()).enablePackageForUser( 767 Mockito.anyObject(), Mockito.eq(false) /* enable */, 768 Mockito.eq(TestSystemImpl.PRIMARY_USER_ID) /* user */); 769 // Verify that we enable the fallback package for the secondary user. 770 Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser( 771 Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */, 772 Mockito.eq(newUser) /* user */); 773 checkPreparationPhasesForPackage(fallbackPackage, 1 /* numRelros */); 774 } 775 776 /** 777 * Timing dependent test where we verify that the list of valid webview packages becoming empty 778 * at a certain point doesn't crash us or break our state. 779 */ 780 @Test 781 public void testNotifyRelroDoesntCrashIfNoPackages() { 782 String firstPackage = "first"; 783 String secondPackage = "second"; 784 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 785 new WebViewProviderInfo(firstPackage, "", true /* default available */, 786 false /* fallback */, null), 787 new WebViewProviderInfo(secondPackage, "", true /* default available */, 788 false /* fallback */, null)}; 789 setupWithPackages(packages); 790 // Add (enabled and valid) package infos for each provider 791 setEnabledAndValidPackageInfos(packages); 792 793 runWebViewBootPreparationOnMainSync(); 794 795 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 796 Mockito.argThat(new IsPackageInfoWithName(firstPackage))); 797 798 // Change provider during relro creation to enter a state where we are 799 // waiting for relro creation to complete just to re-run relro creation. 800 // (so that in next notifyRelroCreationCompleted() call we have to list webview packages) 801 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 802 803 // Make packages invalid to cause exception to be thrown 804 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */, 805 false /* valid */, true /* installed */, null /* signatures */, 806 0 /* updateTime */)); 807 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 808 false /* valid */, true /* installed */)); 809 810 // This shouldn't throw an exception! 811 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 812 813 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 814 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 815 816 // Now make a package valid again and verify that we can switch back to that 817 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */, 818 true /* valid */, true /* installed */, null /* signatures */, 819 1 /* updateTime */ )); 820 821 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage, 822 WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID); 823 824 // Ensure we use firstPackage 825 checkPreparationPhasesForPackage(firstPackage, 2 /* second preparation for this package */); 826 } 827 828 /** 829 * Verify that even if a user-chosen package is removed temporarily we start using it again when 830 * it is added back. 831 */ 832 @Test 833 public void testTempRemovePackageDoesntSwitchProviderPermanently() { 834 String firstPackage = "first"; 835 String secondPackage = "second"; 836 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 837 new WebViewProviderInfo(firstPackage, "", true /* default available */, 838 false /* fallback */, null), 839 new WebViewProviderInfo(secondPackage, "", true /* default available */, 840 false /* fallback */, null)}; 841 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages); 842 843 // Explicitly use the second package 844 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 845 checkPreparationPhasesForPackage(secondPackage, 1 /* first time for this package */); 846 847 // Remove second package (invalidate it) and verify that first package is used 848 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 849 false /* valid */, true /* installed */)); 850 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage, 851 WebViewUpdateService.PACKAGE_ADDED, TestSystemImpl.PRIMARY_USER_ID); 852 checkPreparationPhasesForPackage(firstPackage, 2 /* second time for this package */); 853 854 // Now make the second package valid again and verify that it is used again 855 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 856 true /* valid */, true /* installed */)); 857 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage, 858 WebViewUpdateService.PACKAGE_ADDED, TestSystemImpl.PRIMARY_USER_ID); 859 checkPreparationPhasesForPackage(secondPackage, 2 /* second time for this package */); 860 } 861 862 /** 863 * Ensure that we update the user-chosen setting across boots if the chosen package is no 864 * longer installed and valid. 865 */ 866 @Test 867 public void testProviderSettingChangedDuringBootIfProviderNotAvailable() { 868 String chosenPackage = "chosenPackage"; 869 String nonChosenPackage = "non-chosenPackage"; 870 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 871 new WebViewProviderInfo(chosenPackage, "", true /* default available */, 872 false /* fallback */, null), 873 new WebViewProviderInfo(nonChosenPackage, "", true /* default available */, 874 false /* fallback */, null)}; 875 876 setupWithPackages(packages); 877 // Only 'install' nonChosenPackage 878 mTestSystemImpl.setPackageInfo( 879 createPackageInfo(nonChosenPackage, true /* enabled */, true /* valid */, true /* installed */)); 880 881 // Set user-chosen package 882 mTestSystemImpl.updateUserSetting(null, chosenPackage); 883 884 runWebViewBootPreparationOnMainSync(); 885 886 // Verify that we switch the setting to point to the current package 887 Mockito.verify(mTestSystemImpl).updateUserSetting( 888 Mockito.anyObject(), Mockito.eq(nonChosenPackage)); 889 assertEquals(nonChosenPackage, mTestSystemImpl.getUserChosenWebViewProvider(null)); 890 891 checkPreparationPhasesForPackage(nonChosenPackage, 1); 892 } 893 894 @Test 895 public void testRecoverFailedListingWebViewPackagesSettingsChange() { 896 checkRecoverAfterFailListingWebviewPackages(true); 897 } 898 899 @Test 900 public void testRecoverFailedListingWebViewPackagesAddedPackage() { 901 checkRecoverAfterFailListingWebviewPackages(false); 902 } 903 904 /** 905 * Test that we can recover correctly from failing to list WebView packages. 906 * settingsChange: whether to fail during changeProviderAndSetting or packageStateChanged 907 */ 908 public void checkRecoverAfterFailListingWebviewPackages(boolean settingsChange) { 909 String firstPackage = "first"; 910 String secondPackage = "second"; 911 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 912 new WebViewProviderInfo(firstPackage, "", true /* default available */, 913 false /* fallback */, null), 914 new WebViewProviderInfo(secondPackage, "", true /* default available */, 915 false /* fallback */, null)}; 916 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages); 917 918 // Make both packages invalid so that we fail listing WebView packages 919 mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */, 920 false /* valid */, true /* installed */)); 921 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 922 false /* valid */, true /* installed */)); 923 924 // Change package to hit the webview packages listing problem. 925 if (settingsChange) { 926 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 927 } else { 928 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage, 929 WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID); 930 } 931 932 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 933 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 934 935 // Make second package valid and verify that we can load it again 936 mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, 937 true /* valid */, true /* installed */)); 938 939 mWebViewUpdateServiceImpl.packageStateChanged(secondPackage, 940 WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID); 941 942 943 checkPreparationPhasesForPackage(secondPackage, 1); 944 } 945 946 @Test 947 public void testDontKillIfPackageReplaced() { 948 checkDontKillIfPackageRemoved(true); 949 } 950 951 @Test 952 public void testDontKillIfPackageRemoved() { 953 checkDontKillIfPackageRemoved(false); 954 } 955 956 public void checkDontKillIfPackageRemoved(boolean replaced) { 957 String firstPackage = "first"; 958 String secondPackage = "second"; 959 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 960 new WebViewProviderInfo(firstPackage, "", true /* default available */, 961 false /* fallback */, null), 962 new WebViewProviderInfo(secondPackage, "", true /* default available */, 963 false /* fallback */, null)}; 964 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages); 965 966 // Replace or remove the current webview package 967 if (replaced) { 968 mTestSystemImpl.setPackageInfo( 969 createPackageInfo(firstPackage, true /* enabled */, false /* valid */, 970 true /* installed */)); 971 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage, 972 WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID); 973 } else { 974 mTestSystemImpl.removePackageInfo(firstPackage); 975 mWebViewUpdateServiceImpl.packageStateChanged(firstPackage, 976 WebViewUpdateService.PACKAGE_REMOVED, TestSystemImpl.PRIMARY_USER_ID); 977 } 978 979 checkPreparationPhasesForPackage(secondPackage, 1); 980 981 Mockito.verify(mTestSystemImpl, Mockito.never()).killPackageDependents( 982 Mockito.anyObject()); 983 } 984 985 @Test 986 public void testKillIfSettingChanged() { 987 String firstPackage = "first"; 988 String secondPackage = "second"; 989 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 990 new WebViewProviderInfo(firstPackage, "", true /* default available */, 991 false /* fallback */, null), 992 new WebViewProviderInfo(secondPackage, "", true /* default available */, 993 false /* fallback */, null)}; 994 checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages); 995 996 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); 997 998 checkPreparationPhasesForPackage(secondPackage, 1); 999 1000 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage)); 1001 } 1002 1003 /** 1004 * Test that we kill apps using an old provider when we change the provider setting, even if the 1005 * new provider is not the one we intended to change to. 1006 */ 1007 @Test 1008 public void testKillIfChangeProviderIncorrectly() { 1009 String firstPackage = "first"; 1010 String secondPackage = "second"; 1011 String thirdPackage = "third"; 1012 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 1013 new WebViewProviderInfo(firstPackage, "", true /* default available */, 1014 false /* fallback */, null), 1015 new WebViewProviderInfo(secondPackage, "", true /* default available */, 1016 false /* fallback */, null), 1017 new WebViewProviderInfo(thirdPackage, "", true /* default available */, 1018 false /* fallback */, null)}; 1019 setupWithPackages(packages); 1020 setEnabledAndValidPackageInfos(packages); 1021 1022 // Start with the setting pointing to the third package 1023 mTestSystemImpl.updateUserSetting(null, thirdPackage); 1024 1025 runWebViewBootPreparationOnMainSync(); 1026 checkPreparationPhasesForPackage(thirdPackage, 1); 1027 1028 mTestSystemImpl.setPackageInfo( 1029 createPackageInfo(secondPackage, true /* enabled */, false /* valid */, true /* installed */)); 1030 1031 // Try to switch to the invalid second package, this should result in switching to the first 1032 // package, since that is more preferred than the third one. 1033 assertEquals(firstPackage, 1034 mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage)); 1035 1036 checkPreparationPhasesForPackage(firstPackage, 1); 1037 1038 Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(thirdPackage)); 1039 } 1040 1041 @Test 1042 public void testLowerPackageVersionNotValid() { 1043 checkPackageVersions(new int[]{200000} /* system version */, 100000/* candidate version */, 1044 false /* expected validity */); 1045 } 1046 1047 @Test 1048 public void testEqualPackageVersionValid() { 1049 checkPackageVersions(new int[]{100000} /* system version */, 100000 /* candidate version */, 1050 true /* expected validity */); 1051 } 1052 1053 @Test 1054 public void testGreaterPackageVersionValid() { 1055 checkPackageVersions(new int[]{100000} /* system versions */, 200000 /* candidate version */, 1056 true /* expected validity */); 1057 } 1058 1059 @Test 1060 public void testLastFiveDigitsIgnored() { 1061 checkPackageVersions(new int[]{654321} /* system version */, 612345 /* candidate version */, 1062 true /* expected validity */); 1063 } 1064 1065 @Test 1066 public void testMinimumSystemVersionUsedTwoDefaultsCandidateValid() { 1067 checkPackageVersions(new int[]{300000, 100000} /* system versions */, 1068 200000 /* candidate version */, true /* expected validity */); 1069 } 1070 1071 @Test 1072 public void testMinimumSystemVersionUsedTwoDefaultsCandidateInvalid() { 1073 checkPackageVersions(new int[]{300000, 200000} /* system versions */, 1074 100000 /* candidate version */, false /* expected validity */); 1075 } 1076 1077 @Test 1078 public void testMinimumSystemVersionUsedSeveralDefaultsCandidateValid() { 1079 checkPackageVersions(new int[]{100000, 200000, 300000, 400000, 500000} /* system versions */, 1080 100000 /* candidate version */, true /* expected validity */); 1081 } 1082 1083 @Test 1084 public void testMinimumSystemVersionUsedSeveralDefaultsCandidateInvalid() { 1085 checkPackageVersions(new int[]{200000, 300000, 400000, 500000, 600000} /* system versions */, 1086 100000 /* candidate version */, false /* expected validity */); 1087 } 1088 1089 @Test 1090 public void testMinimumSystemVersionUsedFallbackIgnored() { 1091 checkPackageVersions(new int[]{300000, 400000, 500000, 600000, 700000} /* system versions */, 1092 200000 /* candidate version */, false /* expected validity */, true /* add fallback */, 1093 100000 /* fallback version */, false /* expected validity of fallback */); 1094 } 1095 1096 @Test 1097 public void testFallbackValid() { 1098 checkPackageVersions(new int[]{300000, 400000, 500000, 600000, 700000} /* system versions */, 1099 200000/* candidate version */, false /* expected validity */, true /* add fallback */, 1100 300000 /* fallback version */, true /* expected validity of fallback */); 1101 } 1102 1103 private void checkPackageVersions(int[] systemVersions, int candidateVersion, 1104 boolean candidateShouldBeValid) { 1105 checkPackageVersions(systemVersions, candidateVersion, candidateShouldBeValid, 1106 false, 0, false); 1107 } 1108 1109 /** 1110 * Utility method for checking that package version restriction works as it should. 1111 * I.e. that a package with lower version than the system-default is not valid and that a 1112 * package with greater than or equal version code is considered valid. 1113 */ 1114 private void checkPackageVersions(int[] systemVersions, int candidateVersion, 1115 boolean candidateShouldBeValid, boolean addFallback, int fallbackVersion, 1116 boolean fallbackShouldBeValid) { 1117 int numSystemPackages = systemVersions.length; 1118 int numFallbackPackages = (addFallback ? 1 : 0); 1119 int numPackages = systemVersions.length + 1 + numFallbackPackages; 1120 String candidatePackage = "candidatePackage"; 1121 String systemPackage = "systemPackage"; 1122 String fallbackPackage = "fallbackPackage"; 1123 1124 // Each package needs a valid signature since we set isDebuggable to false 1125 Signature signature = new Signature("11"); 1126 String encodedSignatureString = 1127 Base64.encodeToString(signature.toByteArray(), Base64.DEFAULT); 1128 1129 // Set up config 1130 // 1. candidatePackage 1131 // 2-N. default available non-fallback packages 1132 // N+1. default available fallback package 1133 WebViewProviderInfo[] packages = new WebViewProviderInfo[numPackages]; 1134 packages[0] = new WebViewProviderInfo(candidatePackage, "", 1135 false /* available by default */, false /* fallback */, 1136 new String[]{encodedSignatureString}); 1137 for(int n = 1; n < numSystemPackages + 1; n++) { 1138 packages[n] = new WebViewProviderInfo(systemPackage + n, "", 1139 true /* available by default */, false /* fallback */, 1140 new String[]{encodedSignatureString}); 1141 } 1142 if (addFallback) { 1143 packages[packages.length-1] = new WebViewProviderInfo(fallbackPackage, "", 1144 true /* available by default */, true /* fallback */, 1145 new String[]{encodedSignatureString}); 1146 } 1147 1148 setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */, 1149 false /* isDebuggable */); 1150 1151 // Set package infos 1152 mTestSystemImpl.setPackageInfo( 1153 createPackageInfo(candidatePackage, true /* enabled */, true /* valid */, 1154 true /* installed */, new Signature[]{signature}, 0 /* updateTime */, 1155 false /* hidden */, candidateVersion, false /* isSystemApp */)); 1156 for(int n = 1; n < numSystemPackages + 1; n++) { 1157 mTestSystemImpl.setPackageInfo( 1158 createPackageInfo(systemPackage + n, true /* enabled */, true /* valid */, 1159 true /* installed */, new Signature[]{signature}, 0 /* updateTime */, 1160 false /* hidden */, systemVersions[n-1], true /* isSystemApp */)); 1161 } 1162 if (addFallback) { 1163 mTestSystemImpl.setPackageInfo( 1164 createPackageInfo(fallbackPackage, true /* enabled */, true /* valid */, 1165 true /* installed */, new Signature[]{signature}, 0 /* updateTime */, 1166 false /* hidden */, fallbackVersion, true /* isSystemApp */)); 1167 } 1168 1169 WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages(); 1170 int expectedNumValidPackages = numSystemPackages; 1171 if (candidateShouldBeValid) { 1172 expectedNumValidPackages++; 1173 } else { 1174 // Ensure the candidate package is not one of the valid packages 1175 for(int n = 0; n < validPackages.length; n++) { 1176 assertFalse(candidatePackage.equals(validPackages[n].packageName)); 1177 } 1178 } 1179 1180 if (fallbackShouldBeValid) { 1181 expectedNumValidPackages += numFallbackPackages; 1182 } else { 1183 // Ensure the fallback package is not one of the valid packages 1184 for(int n = 0; n < validPackages.length; n++) { 1185 assertFalse(fallbackPackage.equals(validPackages[n].packageName)); 1186 } 1187 } 1188 1189 assertEquals(expectedNumValidPackages, validPackages.length); 1190 1191 runWebViewBootPreparationOnMainSync(); 1192 1193 // The non-system package is not available by default so it shouldn't be used here 1194 checkPreparationPhasesForPackage(systemPackage + "1", 1); 1195 1196 // Try explicitly switching to the candidate package 1197 String packageChange = mWebViewUpdateServiceImpl.changeProviderAndSetting(candidatePackage); 1198 if (candidateShouldBeValid) { 1199 assertEquals(candidatePackage, packageChange); 1200 checkPreparationPhasesForPackage(candidatePackage, 1); 1201 } else { 1202 assertEquals(systemPackage + "1", packageChange); 1203 // We didn't change package so the webview preparation won't run here 1204 } 1205 } 1206 1207 /** 1208 * Ensure that the update service does use an uninstalled package when that is the only 1209 * package available. 1210 */ 1211 @Test 1212 public void testWithSingleUninstalledPackage() { 1213 String testPackageName = "test.package.name"; 1214 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] { 1215 new WebViewProviderInfo(testPackageName, "", 1216 true /*default available*/, false /* fallback */, null)}; 1217 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */); 1218 mTestSystemImpl.setPackageInfo(createPackageInfo(testPackageName, true /* enabled */, 1219 true /* valid */, false /* installed */)); 1220 1221 runWebViewBootPreparationOnMainSync(); 1222 1223 Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged( 1224 Matchers.anyObject()); 1225 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 1226 assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); 1227 assertEquals(null, mWebViewUpdateServiceImpl.getCurrentWebViewPackage()); 1228 } 1229 1230 @Test 1231 public void testNonhiddenPackageUserOverHidden() { 1232 checkVisiblePackageUserOverNonVisible(false /* multiUser*/, PackageRemovalType.HIDE); 1233 checkVisiblePackageUserOverNonVisible(true /* multiUser*/, PackageRemovalType.HIDE); 1234 } 1235 1236 @Test 1237 public void testInstalledPackageUsedOverUninstalled() { 1238 checkVisiblePackageUserOverNonVisible(false /* multiUser*/, PackageRemovalType.UNINSTALL); 1239 checkVisiblePackageUserOverNonVisible(true /* multiUser*/, PackageRemovalType.UNINSTALL); 1240 } 1241 1242 private void checkVisiblePackageUserOverNonVisible(boolean multiUser, 1243 PackageRemovalType removalType) { 1244 assert removalType != PackageRemovalType.DISABLE; 1245 boolean testUninstalled = removalType == PackageRemovalType.UNINSTALL; 1246 boolean testHidden = removalType == PackageRemovalType.HIDE; 1247 String installedPackage = "installedPackage"; 1248 String uninstalledPackage = "uninstalledPackage"; 1249 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] { 1250 new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */, 1251 false /* fallback */, null), 1252 new WebViewProviderInfo(installedPackage, "", true /* available by default */, 1253 false /* fallback */, null)}; 1254 1255 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */); 1256 int secondaryUserId = 5; 1257 if (multiUser) { 1258 mTestSystemImpl.addUser(secondaryUserId); 1259 // Install all packages for the primary user. 1260 setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, webviewPackages); 1261 mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo( 1262 installedPackage, true /* enabled */, true /* valid */, true /* installed */)); 1263 // Hide or uninstall the primary package for the second user 1264 mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */, 1265 true /* valid */, (testUninstalled ? false : true) /* installed */, 1266 null /* signatures */, 0 /* updateTime */, (testHidden ? true : false))); 1267 } else { 1268 mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */, 1269 true /* valid */, true /* installed */)); 1270 // Hide or uninstall the primary package 1271 mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */, 1272 true /* valid */, (testUninstalled ? false : true) /* installed */, 1273 null /* signatures */, 0 /* updateTime */, (testHidden ? true : false))); 1274 } 1275 1276 runWebViewBootPreparationOnMainSync(); 1277 1278 checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */); 1279 } 1280 1281 @Test 1282 public void testCantSwitchToHiddenPackage () { 1283 checkCantSwitchToNonVisiblePackage(false /* true == uninstalled, false == hidden */); 1284 } 1285 1286 1287 @Test 1288 public void testCantSwitchToUninstalledPackage () { 1289 checkCantSwitchToNonVisiblePackage(true /* true == uninstalled, false == hidden */); 1290 } 1291 1292 /** 1293 * Ensure that we won't prioritize an uninstalled (or hidden) package even if it is user-chosen. 1294 */ 1295 private void checkCantSwitchToNonVisiblePackage(boolean uninstalledNotHidden) { 1296 boolean testUninstalled = uninstalledNotHidden; 1297 boolean testHidden = !uninstalledNotHidden; 1298 String installedPackage = "installedPackage"; 1299 String uninstalledPackage = "uninstalledPackage"; 1300 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] { 1301 new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */, 1302 false /* fallback */, null), 1303 new WebViewProviderInfo(installedPackage, "", true /* available by default */, 1304 false /* fallback */, null)}; 1305 1306 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */); 1307 int secondaryUserId = 412; 1308 mTestSystemImpl.addUser(secondaryUserId); 1309 1310 // Let all packages be installed and enabled for the primary user. 1311 setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, webviewPackages); 1312 // Only uninstall the 'uninstalled package' for the secondary user. 1313 mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(installedPackage, 1314 true /* enabled */, true /* valid */, true /* installed */)); 1315 mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(uninstalledPackage, 1316 true /* enabled */, true /* valid */, !testUninstalled /* installed */, 1317 null /* signatures */, 0 /* updateTime */, testHidden /* hidden */)); 1318 1319 runWebViewBootPreparationOnMainSync(); 1320 1321 checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */); 1322 1323 // ensure that we don't switch to the uninstalled package (it will be used if it becomes 1324 // installed later) 1325 assertEquals(installedPackage, 1326 mWebViewUpdateServiceImpl.changeProviderAndSetting(uninstalledPackage)); 1327 1328 // Ensure both packages are considered valid. 1329 assertEquals(2, mWebViewUpdateServiceImpl.getValidWebViewPackages().length); 1330 1331 1332 // We should only have called onWebViewProviderChanged once (before calling 1333 // changeProviderAndSetting 1334 Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged( 1335 Mockito.argThat(new IsPackageInfoWithName(installedPackage))); 1336 } 1337 1338 @Test 1339 public void testHiddenPackageNotPrioritizedEvenIfChosen() { 1340 checkNonvisiblePackageNotPrioritizedEvenIfChosen( 1341 false /* true == uninstalled, false == hidden */); 1342 } 1343 1344 @Test 1345 public void testUninstalledPackageNotPrioritizedEvenIfChosen() { 1346 checkNonvisiblePackageNotPrioritizedEvenIfChosen( 1347 true /* true == uninstalled, false == hidden */); 1348 } 1349 1350 public void checkNonvisiblePackageNotPrioritizedEvenIfChosen(boolean uninstalledNotHidden) { 1351 boolean testUninstalled = uninstalledNotHidden; 1352 boolean testHidden = !uninstalledNotHidden; 1353 String installedPackage = "installedPackage"; 1354 String uninstalledPackage = "uninstalledPackage"; 1355 WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] { 1356 new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */, 1357 false /* fallback */, null), 1358 new WebViewProviderInfo(installedPackage, "", true /* available by default */, 1359 false /* fallback */, null)}; 1360 1361 setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */); 1362 int secondaryUserId = 4; 1363 mTestSystemImpl.addUser(secondaryUserId); 1364 1365 setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, webviewPackages); 1366 mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(installedPackage, 1367 true /* enabled */, true /* valid */, true /* installed */)); 1368 mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(uninstalledPackage, 1369 true /* enabled */, true /* valid */, 1370 (testUninstalled ? false : true) /* installed */, null /* signatures */, 1371 0 /* updateTime */, (testHidden ? true : false) /* hidden */)); 1372 1373 // Start with the setting pointing to the uninstalled package 1374 mTestSystemImpl.updateUserSetting(null, uninstalledPackage); 1375 1376 runWebViewBootPreparationOnMainSync(); 1377 1378 checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */); 1379 } 1380 1381 @Test 1382 public void testFallbackEnabledIfPrimaryUninstalledSingleUser() { 1383 checkFallbackEnabledIfPrimaryUninstalled(false /* multiUser */); 1384 } 1385 1386 @Test 1387 public void testFallbackEnabledIfPrimaryUninstalledMultiUser() { 1388 checkFallbackEnabledIfPrimaryUninstalled(true /* multiUser */); 1389 } 1390 1391 /** 1392 * Ensures that fallback becomes enabled at boot if the primary package is uninstalled for some 1393 * user. 1394 */ 1395 private void checkFallbackEnabledIfPrimaryUninstalled(boolean multiUser) { 1396 String primaryPackage = "primary"; 1397 String fallbackPackage = "fallback"; 1398 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 1399 new WebViewProviderInfo( 1400 primaryPackage, "", true /* default available */, false /* fallback */, null), 1401 new WebViewProviderInfo( 1402 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 1403 setupWithPackages(packages, true /* fallback logic enabled */); 1404 int secondaryUserId = 5; 1405 if (multiUser) { 1406 mTestSystemImpl.addUser(secondaryUserId); 1407 // Install all packages for the primary user. 1408 setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, packages); 1409 // Only install fallback package for secondary user. 1410 mTestSystemImpl.setPackageInfoForUser(secondaryUserId, 1411 createPackageInfo(primaryPackage, true /* enabled */, 1412 true /* valid */, false /* installed */)); 1413 mTestSystemImpl.setPackageInfoForUser(secondaryUserId, 1414 createPackageInfo(fallbackPackage, false /* enabled */, 1415 true /* valid */, true /* installed */)); 1416 } else { 1417 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */, 1418 true /* valid */, false /* installed */)); 1419 mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, false /* enabled */, 1420 true /* valid */, true /* installed */)); 1421 } 1422 1423 runWebViewBootPreparationOnMainSync(); 1424 // Verify that we enable the fallback package 1425 Mockito.verify(mTestSystemImpl).enablePackageForAllUsers( 1426 Mockito.anyObject(), Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */); 1427 1428 checkPreparationPhasesForPackage(fallbackPackage, 1 /* first preparation phase */); 1429 } 1430 1431 @Test 1432 public void testPreparationRunsIffNewPackage() { 1433 String primaryPackage = "primary"; 1434 String fallbackPackage = "fallback"; 1435 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 1436 new WebViewProviderInfo( 1437 primaryPackage, "", true /* default available */, false /* fallback */, null), 1438 new WebViewProviderInfo( 1439 fallbackPackage, "", true /* default available */, true /* fallback */, null)}; 1440 setupWithPackages(packages, true /* fallback logic enabled */); 1441 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */, 1442 true /* valid */, true /* installed */, null /* signatures */, 1443 10 /* lastUpdateTime*/ )); 1444 mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */, 1445 true /* valid */, true /* installed */)); 1446 1447 runWebViewBootPreparationOnMainSync(); 1448 1449 checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */); 1450 Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser( 1451 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, 1452 Matchers.anyInt() /* user */); 1453 1454 1455 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 1456 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0 /* userId */); 1457 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 1458 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 1 /* userId */); 1459 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 1460 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 2 /* userId */); 1461 // package still has the same update-time so we shouldn't run preparation here 1462 Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged( 1463 Mockito.argThat(new IsPackageInfoWithName(primaryPackage))); 1464 Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser( 1465 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, 1466 Matchers.anyInt() /* user */); 1467 1468 // Ensure we can still load the package 1469 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 1470 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); 1471 assertEquals(primaryPackage, response.packageInfo.packageName); 1472 1473 1474 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */, 1475 true /* valid */, true /* installed */, null /* signatures */, 1476 20 /* lastUpdateTime*/ )); 1477 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 1478 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0); 1479 // The package has now changed - ensure that we have run the preparation phase a second time 1480 checkPreparationPhasesForPackage(primaryPackage, 2 /* second preparation phase */); 1481 1482 1483 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */, 1484 true /* valid */, true /* installed */, null /* signatures */, 1485 50 /* lastUpdateTime*/ )); 1486 // Receive intent for different user 1487 mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, 1488 WebViewUpdateService.PACKAGE_ADDED_REPLACED, 2); 1489 1490 checkPreparationPhasesForPackage(primaryPackage, 3 /* third preparation phase */); 1491 } 1492 1493 @Test 1494 public void testGetCurrentWebViewPackage() { 1495 PackageInfo firstPackage = createPackageInfo("first", true /* enabled */, 1496 true /* valid */, true /* installed */); 1497 firstPackage.versionCode = 100; 1498 firstPackage.versionName = "first package version"; 1499 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 1500 new WebViewProviderInfo(firstPackage.packageName, "", true, false, null)}; 1501 setupWithPackages(packages, true); 1502 mTestSystemImpl.setPackageInfo(firstPackage); 1503 1504 runWebViewBootPreparationOnMainSync(); 1505 1506 Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( 1507 Mockito.argThat(new IsPackageInfoWithName(firstPackage.packageName))); 1508 1509 mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); 1510 1511 // Ensure the API is correct before running waitForAndGetProvider 1512 assertEquals(firstPackage.packageName, 1513 mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName); 1514 assertEquals(firstPackage.versionCode, 1515 mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionCode); 1516 assertEquals(firstPackage.versionName, 1517 mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionName); 1518 1519 WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); 1520 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); 1521 assertEquals(firstPackage.packageName, response.packageInfo.packageName); 1522 1523 // Ensure the API is still correct after running waitForAndGetProvider 1524 assertEquals(firstPackage.packageName, 1525 mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName); 1526 assertEquals(firstPackage.versionCode, 1527 mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionCode); 1528 assertEquals(firstPackage.versionName, 1529 mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionName); 1530 } 1531 1532 @Test 1533 public void testMultiProcessEnabledByDefault() { 1534 testMultiProcessByDefault(true /* enabledByDefault */); 1535 } 1536 1537 @Test 1538 public void testMultiProcessDisabledByDefault() { 1539 testMultiProcessByDefault(false /* enabledByDefault */); 1540 } 1541 1542 private void testMultiProcessByDefault(boolean enabledByDefault) { 1543 String primaryPackage = "primary"; 1544 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 1545 new WebViewProviderInfo( 1546 primaryPackage, "", true /* default available */, false /* fallback */, null)}; 1547 setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */, 1548 true /* debuggable */, 1549 enabledByDefault /* not multiprocess by default */); 1550 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */, 1551 true /* valid */, true /* installed */, null /* signatures */, 1552 10 /* lastUpdateTime*/, false /* not hidden */, 1000 /* versionCode */, 1553 false /* isSystemApp */)); 1554 1555 runWebViewBootPreparationOnMainSync(); 1556 checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */); 1557 1558 // Check it's off by default 1559 assertEquals(enabledByDefault, mWebViewUpdateServiceImpl.isMultiProcessEnabled()); 1560 1561 // Test toggling it 1562 mWebViewUpdateServiceImpl.enableMultiProcess(!enabledByDefault); 1563 assertEquals(!enabledByDefault, mWebViewUpdateServiceImpl.isMultiProcessEnabled()); 1564 mWebViewUpdateServiceImpl.enableMultiProcess(enabledByDefault); 1565 assertEquals(enabledByDefault, mWebViewUpdateServiceImpl.isMultiProcessEnabled()); 1566 } 1567 1568 @Test 1569 public void testMultiProcessEnabledByDefaultWithSettingsValue() { 1570 testMultiProcessByDefaultWithSettingsValue( 1571 true /* enabledByDefault */, Integer.MIN_VALUE, false /* expectEnabled */); 1572 testMultiProcessByDefaultWithSettingsValue( 1573 true /* enabledByDefault */, -999999, true /* expectEnabled */); 1574 testMultiProcessByDefaultWithSettingsValue( 1575 true /* enabledByDefault */, 0, true /* expectEnabled */); 1576 testMultiProcessByDefaultWithSettingsValue( 1577 true /* enabledByDefault */, 999999, true /* expectEnabled */); 1578 } 1579 1580 @Test 1581 public void testMultiProcessDisabledByDefaultWithSettingsValue() { 1582 testMultiProcessByDefaultWithSettingsValue( 1583 false /* enabledByDefault */, Integer.MIN_VALUE, false /* expectEnabled */); 1584 testMultiProcessByDefaultWithSettingsValue( 1585 false /* enabledByDefault */, 0, false /* expectEnabled */); 1586 testMultiProcessByDefaultWithSettingsValue( 1587 false /* enabledByDefault */, 999999, false /* expectEnabled */); 1588 testMultiProcessByDefaultWithSettingsValue( 1589 false /* enabledByDefault */, Integer.MAX_VALUE, true /* expectEnabled */); 1590 } 1591 1592 /** 1593 * Test the logic of the multiprocess setting depending on whether multiprocess is enabled by 1594 * default, and what the setting is set to. 1595 * @param enabledByDefault whether multiprocess is enabled by default. 1596 * @param settingValue value of the multiprocess setting. 1597 */ 1598 private void testMultiProcessByDefaultWithSettingsValue( 1599 boolean enabledByDefault, int settingValue, boolean expectEnabled) { 1600 String primaryPackage = "primary"; 1601 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 1602 new WebViewProviderInfo( 1603 primaryPackage, "", true /* default available */, false /* fallback */, null)}; 1604 setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */, 1605 true /* debuggable */, enabledByDefault /* multiprocess by default */); 1606 mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */, 1607 true /* valid */, true /* installed */, null /* signatures */, 1608 10 /* lastUpdateTime*/, false /* not hidden */, 1000 /* versionCode */, 1609 false /* isSystemApp */)); 1610 1611 runWebViewBootPreparationOnMainSync(); 1612 checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */); 1613 1614 mTestSystemImpl.setMultiProcessSetting(null /* context */, settingValue); 1615 1616 assertEquals(expectEnabled, mWebViewUpdateServiceImpl.isMultiProcessEnabled()); 1617 } 1618 1619 1620 /** 1621 * Ensure that packages with a targetSdkVersion targeting the current platform are valid, and 1622 * that packages targeting an older version are not valid. 1623 */ 1624 @Test 1625 public void testTargetSdkVersionValidity() { 1626 PackageInfo newSdkPackage = createPackageInfo("newTargetSdkPackage", 1627 true /* enabled */, true /* valid */, true /* installed */); 1628 newSdkPackage.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; 1629 PackageInfo currentSdkPackage = createPackageInfo("currentTargetSdkPackage", 1630 true /* enabled */, true /* valid */, true /* installed */); 1631 currentSdkPackage.applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1+1; 1632 PackageInfo oldSdkPackage = createPackageInfo("oldTargetSdkPackage", 1633 true /* enabled */, true /* valid */, true /* installed */); 1634 oldSdkPackage.applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1; 1635 1636 WebViewProviderInfo newSdkProviderInfo = 1637 new WebViewProviderInfo(newSdkPackage.packageName, "", true, false, null); 1638 WebViewProviderInfo currentSdkProviderInfo = 1639 new WebViewProviderInfo(currentSdkPackage.packageName, "", true, false, null); 1640 WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 1641 new WebViewProviderInfo(oldSdkPackage.packageName, "", true, false, null), 1642 currentSdkProviderInfo, newSdkProviderInfo}; 1643 setupWithPackages(packages, true); 1644; 1645 mTestSystemImpl.setPackageInfo(newSdkPackage); 1646 mTestSystemImpl.setPackageInfo(currentSdkPackage); 1647 mTestSystemImpl.setPackageInfo(oldSdkPackage); 1648 1649 assertArrayEquals(new WebViewProviderInfo[]{currentSdkProviderInfo, newSdkProviderInfo}, 1650 mWebViewUpdateServiceImpl.getValidWebViewPackages()); 1651 1652 runWebViewBootPreparationOnMainSync(); 1653 1654 checkPreparationPhasesForPackage(currentSdkPackage.packageName, 1655 1 /* first preparation phase */); 1656 } 1657} 1658