Merge "Update persistent WebView packages setting only when user changes it." into nyc-dev

am: 45e2966

* commit '45e2966da9f81077777bb6df61e9a880790741ec':
  Update persistent WebView packages setting only when user changes it.

Change-Id: I8cc5ad1e7bd0dae467413362a23dc803e5aab9ee
This commit is contained in:
Gustav Sennton
2016-04-14 11:05:33 +00:00
committed by android-build-merger
2 changed files with 103 additions and 49 deletions

View File

@@ -291,6 +291,13 @@ public class WebViewUpdateServiceImpl {
try {
synchronized(mLock) {
mCurrentWebViewPackage = findPreferredWebViewPackage();
// Don't persist the user-chosen setting across boots if the package being
// chosen is not used (could be disabled or uninstalled) so that the user won't
// be surprised by the device switching to using a certain webview package,
// that was uninstalled/disabled a long time ago, if it is installed/enabled
// again.
mSystemInterface.updateUserSetting(mContext,
mCurrentWebViewPackage.packageName);
onWebViewProviderChanged(mCurrentWebViewPackage);
}
} catch (Throwable t) {
@@ -345,7 +352,6 @@ public class WebViewUpdateServiceImpl {
mAnyWebViewInstalled = true;
if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
mCurrentWebViewPackage = newPackage;
mSystemInterface.updateUserSetting(mContext, newPackage.packageName);
// The relro creations might 'finish' (not start at all) before
// WebViewFactory.onWebViewProviderChanged which means we might not know the
@@ -432,9 +438,12 @@ public class WebViewUpdateServiceImpl {
}
}
// Could not find any enabled package either, use the most stable provider.
// Could not find any enabled package either, use the most stable and default-available
// provider.
for (ProviderAndPackageInfo providerAndPackage : providers) {
return providerAndPackage.packageInfo;
if (providerAndPackage.provider.availableByDefault) {
return providerAndPackage.packageInfo;
}
}
mAnyWebViewInstalled = false;

View File

@@ -90,12 +90,13 @@ public class WebViewUpdateServiceTest extends AndroidTestCase {
}
}
private void checkCertainPackageUsedAfterWebViewPreparation(String expectedProviderName,
private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
WebViewProviderInfo[] webviewPackages) {
checkCertainPackageUsedAfterWebViewPreparation(expectedProviderName, webviewPackages, 1);
checkCertainPackageUsedAfterWebViewBootPreparation(
expectedProviderName, webviewPackages, 1);
}
private void checkCertainPackageUsedAfterWebViewPreparation(String expectedProviderName,
private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
WebViewProviderInfo[] webviewPackages, int numRelros) {
setupWithPackages(webviewPackages, true, numRelros);
// Add (enabled and valid) package infos for each provider
@@ -156,6 +157,19 @@ public class WebViewUpdateServiceTest extends AndroidTestCase {
return p;
}
private void checkPreparationPhasesForPackage(String expectedPackage, int numPreparation) {
// Verify that onWebViewProviderChanged was called for the numPreparation'th time for the
// expected package
Mockito.verify(mTestSystemImpl, Mockito.times(numPreparation)).onWebViewProviderChanged(
Mockito.argThat(new IsPackageInfoWithName(expectedPackage)));
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
assertEquals(expectedPackage, response.packageInfo.packageName);
}
// ****************
// Tests
@@ -164,7 +178,7 @@ public class WebViewUpdateServiceTest extends AndroidTestCase {
public void testWithSinglePackage() {
String testPackageName = "test.package.name";
checkCertainPackageUsedAfterWebViewPreparation(testPackageName,
checkCertainPackageUsedAfterWebViewBootPreparation(testPackageName,
new WebViewProviderInfo[] {
new WebViewProviderInfo(testPackageName, "",
true /*default available*/, false /* fallback */, null)});
@@ -176,12 +190,12 @@ public class WebViewUpdateServiceTest extends AndroidTestCase {
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
new WebViewProviderInfo(nonDefaultPackage, "", false, false, null),
new WebViewProviderInfo(defaultPackage, "", true, false, null)};
checkCertainPackageUsedAfterWebViewPreparation(defaultPackage, packages);
checkCertainPackageUsedAfterWebViewBootPreparation(defaultPackage, packages);
}
public void testSeveralRelros() {
String singlePackage = "singlePackage";
checkCertainPackageUsedAfterWebViewPreparation(
checkCertainPackageUsedAfterWebViewBootPreparation(
singlePackage,
new WebViewProviderInfo[] {
new WebViewProviderInfo(singlePackage, "", true /*def av*/, false, null)},
@@ -215,14 +229,8 @@ public class WebViewUpdateServiceTest extends AndroidTestCase {
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
Mockito.argThat(new IsPackageInfoWithName(validPackage)));
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
assertEquals(validPackage, response.packageInfo.packageName);
checkPreparationPhasesForPackage(validPackage, 1 /* first preparation for this package */);
WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
assertEquals(1, validPackages.length);
@@ -292,18 +300,10 @@ public class WebViewUpdateServiceTest extends AndroidTestCase {
private void checkSwitchingProvider(WebViewProviderInfo[] packages, String initialPackage,
String finalPackage) {
checkCertainPackageUsedAfterWebViewPreparation(initialPackage, packages);
checkCertainPackageUsedAfterWebViewBootPreparation(initialPackage, packages);
mWebViewUpdateServiceImpl.changeProviderAndSetting(finalPackage);
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
Mockito.argThat(new IsPackageInfoWithName(finalPackage)));
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
WebViewProviderResponse secondResponse = mWebViewUpdateServiceImpl.waitForAndGetProvider();
assertEquals(WebViewFactory.LIBLOAD_SUCCESS, secondResponse.status);
assertEquals(finalPackage, secondResponse.packageInfo.packageName);
checkPreparationPhasesForPackage(finalPackage, 1 /* first preparation for this package */);
Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(initialPackage));
}
@@ -455,14 +455,9 @@ public class WebViewUpdateServiceTest extends AndroidTestCase {
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
Matchers.anyObject(), Matchers.anyObject());
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
Mockito.argThat(new IsPackageInfoWithName(fallbackPackage)));
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
assertEquals(fallbackPackage, response.packageInfo.packageName);
checkPreparationPhasesForPackage(fallbackPackage,
1 /* first preparation for this package*/);
// Install primary package
mTestSystemImpl.setPackageInfo(
@@ -470,17 +465,10 @@ public class WebViewUpdateServiceTest extends AndroidTestCase {
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
WebViewUpdateService.PACKAGE_ADDED);
// Verify fallback disabled and primary package used as provider
// Verify fallback disabled, primary package used as provider, and fallback package killed
Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
Matchers.anyObject(), Mockito.eq(fallbackPackage));
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
Mockito.argThat(new IsPackageInfoWithName(primaryPackage)));
// Finish the webview preparation and ensure primary package used and fallback killed
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
assertEquals(primaryPackage, response.packageInfo.packageName);
checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation for this package*/);
Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(fallbackPackage));
}
@@ -598,15 +586,72 @@ public class WebViewUpdateServiceTest extends AndroidTestCase {
mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
WebViewUpdateService.PACKAGE_ADDED);
// Second time we call onWebViewProviderChanged for firstPackage
Mockito.verify(mTestSystemImpl, Mockito.times(2)).onWebViewProviderChanged(
Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
// Ensure we use firstPackage
checkPreparationPhasesForPackage(firstPackage, 2 /* second preparation for this package */);
}
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
/**
* Verify that even if a user-chosen package is removed temporarily we start using it again when
* it is added back.
*/
public void testTempRemovePackageDoesntSwitchProviderPermanently() {
String firstPackage = "first";
String secondPackage = "second";
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
new WebViewProviderInfo(firstPackage, "", true /* default available */,
false /* fallback */, null),
new WebViewProviderInfo(secondPackage, "", true /* default available */,
false /* fallback */, null)};
checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
assertEquals(firstPackage, response.packageInfo.packageName);
// Explicitly use the second package
mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
checkPreparationPhasesForPackage(secondPackage, 1 /* first time for this package */);
// Remove second package (invalidate it) and verify that first package is used
mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
false /* valid */));
mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
WebViewUpdateService.PACKAGE_ADDED);
checkPreparationPhasesForPackage(firstPackage, 2 /* second time for this package */);
// Now make the second package valid again and verify that it is used again
mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
true /* valid */));
mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
WebViewUpdateService.PACKAGE_ADDED);
checkPreparationPhasesForPackage(secondPackage, 2 /* second time for this package */);
}
/**
* Ensure that we update the user-chosen setting across boots if the chosen package is no
* longer installed and valid.
*/
public void testProviderSettingChangedDuringBootIfProviderNotAvailable() {
String chosenPackage = "chosenPackage";
String nonChosenPackage = "non-chosenPackage";
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
new WebViewProviderInfo(chosenPackage, "", true /* default available */,
false /* fallback */, null),
new WebViewProviderInfo(nonChosenPackage, "", true /* default available */,
false /* fallback */, null)};
setupWithPackages(packages);
// Only 'install' nonChosenPackage
mTestSystemImpl.setPackageInfo(
createPackageInfo(nonChosenPackage, true /* enabled */, true /* valid */));
// Set user-chosen package
mTestSystemImpl.updateUserSetting(null, chosenPackage);
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
// Verify that we switch the setting to point to the current package
Mockito.verify(mTestSystemImpl).updateUserSetting(
Mockito.anyObject(), Mockito.eq(nonChosenPackage));
assertEquals(nonChosenPackage, mTestSystemImpl.getUserChosenWebViewProvider(null));
checkPreparationPhasesForPackage(nonChosenPackage, 1);
}
// TODO (gsennton) add more tests for ensuring killPackageDependents is called / not called