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