Merge "Add initial unit tests for WebViewUpdateService." into nyc-dev
am: ce2cb76
* commit 'ce2cb7630c94c4d394f3a12ab5fd5475f61e343c':
Add initial unit tests for WebViewUpdateService.
Change-Id: I303ed7db8d03183891912ff979c39dae4f1ae16d
This commit is contained in:
@@ -119,6 +119,8 @@ public class WebViewUpdateServiceImpl {
|
||||
}
|
||||
|
||||
private void updateFallbackStateOnBoot() {
|
||||
if (!mSystemInterface.isFallbackLogicEnabled()) return;
|
||||
|
||||
WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
|
||||
updateFallbackState(webviewProviders, true);
|
||||
}
|
||||
@@ -497,8 +499,15 @@ public class WebViewUpdateServiceImpl {
|
||||
mWebViewPackageDirty = false;
|
||||
// If we have changed provider since we started the relro creation we need to
|
||||
// redo the whole process using the new package instead.
|
||||
PackageInfo newPackage = findPreferredWebViewPackage();
|
||||
onWebViewProviderChanged(newPackage);
|
||||
try {
|
||||
PackageInfo newPackage = findPreferredWebViewPackage();
|
||||
onWebViewProviderChanged(newPackage);
|
||||
} catch (WebViewFactory.MissingWebViewPackageException e) {
|
||||
// If we can't find any valid WebView package we are now in a state where
|
||||
// mAnyWebViewInstalled is false, so loading WebView will be blocked and we
|
||||
// should simply wait until we receive an intent declaring a new package was
|
||||
// installed.
|
||||
}
|
||||
} else {
|
||||
mLock.notifyAll();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.webkit;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.webkit.WebViewProviderInfo;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class TestSystemImpl implements SystemInterface {
|
||||
private String mUserProvider = "";
|
||||
private final WebViewProviderInfo[] mPackageConfigs;
|
||||
HashMap<String, PackageInfo> mPackages = new HashMap();
|
||||
private boolean mFallbackLogicEnabled;
|
||||
private final int mNumRelros;
|
||||
private final boolean mIsDebuggable;
|
||||
|
||||
public TestSystemImpl(WebViewProviderInfo[] packageConfigs, boolean fallbackLogicEnabled,
|
||||
int numRelros, boolean isDebuggable) {
|
||||
mPackageConfigs = packageConfigs;
|
||||
mFallbackLogicEnabled = fallbackLogicEnabled;
|
||||
mNumRelros = numRelros;
|
||||
mIsDebuggable = isDebuggable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebViewProviderInfo[] getWebViewPackages() {
|
||||
return mPackageConfigs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onWebViewProviderChanged(PackageInfo packageInfo) {
|
||||
return mNumRelros;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserChosenWebViewProvider(Context context) { return mUserProvider; }
|
||||
|
||||
@Override
|
||||
public void updateUserSetting(Context context, String newProviderName) {
|
||||
mUserProvider = newProviderName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void killPackageDependents(String packageName) {}
|
||||
|
||||
@Override
|
||||
public boolean isFallbackLogicEnabled() {
|
||||
return mFallbackLogicEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableFallbackLogic(boolean enable) {
|
||||
mFallbackLogicEnabled = enable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallAndDisablePackageForAllUsers(Context context, String packageName) {
|
||||
enablePackageForAllUsers(context, packageName, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enablePackageForAllUsers(Context context, String packageName, boolean enable) {
|
||||
enablePackageForUser(packageName, enable, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enablePackageForUser(String packageName, boolean enable, int userId) {
|
||||
PackageInfo packageInfo = mPackages.get(packageName);
|
||||
if (packageInfo == null) {
|
||||
throw new IllegalArgumentException("There is no package called " + packageName);
|
||||
}
|
||||
packageInfo.applicationInfo.enabled = enable;
|
||||
setPackageInfo(packageInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean systemIsDebuggable() { return mIsDebuggable; }
|
||||
|
||||
@Override
|
||||
public PackageInfo getPackageInfoForProvider(WebViewProviderInfo info) throws
|
||||
NameNotFoundException {
|
||||
PackageInfo ret = mPackages.get(info.packageName);
|
||||
if (ret == null) throw new NameNotFoundException(info.packageName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void setPackageInfo(PackageInfo pi) {
|
||||
mPackages.put(pi.packageName, pi);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFactoryPackageVersion(String packageName) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,613 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.webkit;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.Bundle;
|
||||
import android.util.Base64;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import android.webkit.WebViewFactory;
|
||||
import android.webkit.WebViewProviderInfo;
|
||||
import android.webkit.WebViewProviderResponse;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.Matchers;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
|
||||
|
||||
/**
|
||||
* Tests for WebViewUpdateService
|
||||
*/
|
||||
public class WebViewUpdateServiceTest extends AndroidTestCase {
|
||||
private final static String TAG = WebViewUpdateServiceTest.class.getSimpleName();
|
||||
|
||||
private WebViewUpdateServiceImpl mWebViewUpdateServiceImpl;
|
||||
private TestSystemImpl mTestSystemImpl;
|
||||
|
||||
private static final String WEBVIEW_LIBRARY_FLAG = "com.android.webview.WebViewLibrary";
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public WebViewUpdateServiceTest() {
|
||||
}
|
||||
|
||||
private void setupWithPackages(WebViewProviderInfo[] packages) {
|
||||
setupWithPackages(packages, true);
|
||||
}
|
||||
|
||||
private void setupWithPackages(WebViewProviderInfo[] packages,
|
||||
boolean fallbackLogicEnabled) {
|
||||
setupWithPackages(packages, fallbackLogicEnabled, 1);
|
||||
}
|
||||
|
||||
private void setupWithPackages(WebViewProviderInfo[] packages,
|
||||
boolean fallbackLogicEnabled, int numRelros) {
|
||||
setupWithPackages(packages, fallbackLogicEnabled, numRelros,
|
||||
true /* isDebuggable == true -> don't check package signatures */);
|
||||
}
|
||||
|
||||
private void setupWithPackages(WebViewProviderInfo[] packages,
|
||||
boolean fallbackLogicEnabled, int numRelros, boolean isDebuggable) {
|
||||
TestSystemImpl testing = new TestSystemImpl(packages, fallbackLogicEnabled, numRelros,
|
||||
isDebuggable);
|
||||
mTestSystemImpl = Mockito.spy(testing);
|
||||
mWebViewUpdateServiceImpl =
|
||||
new WebViewUpdateServiceImpl(null /*Context*/, mTestSystemImpl);
|
||||
}
|
||||
|
||||
private void setEnabledAndValidPackageInfos(WebViewProviderInfo[] providers) {
|
||||
for(WebViewProviderInfo wpi : providers) {
|
||||
mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true /* enabled */,
|
||||
true /* valid */));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCertainPackageUsedAfterWebViewPreparation(String expectedProviderName,
|
||||
WebViewProviderInfo[] webviewPackages) {
|
||||
checkCertainPackageUsedAfterWebViewPreparation(expectedProviderName, webviewPackages, 1);
|
||||
}
|
||||
|
||||
private void checkCertainPackageUsedAfterWebViewPreparation(String expectedProviderName,
|
||||
WebViewProviderInfo[] webviewPackages, int numRelros) {
|
||||
setupWithPackages(webviewPackages, true, numRelros);
|
||||
// Add (enabled and valid) package infos for each provider
|
||||
setEnabledAndValidPackageInfos(webviewPackages);
|
||||
|
||||
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
|
||||
|
||||
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
|
||||
Mockito.argThat(new IsPackageInfoWithName(expectedProviderName)));
|
||||
|
||||
for (int n = 0; n < numRelros; n++) {
|
||||
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
|
||||
}
|
||||
|
||||
WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
|
||||
assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
|
||||
assertEquals(expectedProviderName, response.packageInfo.packageName);
|
||||
}
|
||||
|
||||
// For matching the package name of a PackageInfo
|
||||
private class IsPackageInfoWithName extends ArgumentMatcher<PackageInfo> {
|
||||
private final String mPackageName;
|
||||
|
||||
IsPackageInfoWithName(String name) {
|
||||
mPackageName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object p) {
|
||||
return ((PackageInfo) p).packageName.equals(mPackageName);
|
||||
}
|
||||
|
||||
// Provide a more useful description in case of mismatch
|
||||
@Override
|
||||
public void describeTo (Description description) {
|
||||
description.appendText(String.format("PackageInfo with name '%s'", mPackageName));
|
||||
}
|
||||
}
|
||||
|
||||
private static PackageInfo createPackageInfo(
|
||||
String packageName, boolean enabled, boolean valid) {
|
||||
PackageInfo p = new PackageInfo();
|
||||
p.packageName = packageName;
|
||||
p.applicationInfo = new ApplicationInfo();
|
||||
p.applicationInfo.enabled = enabled;
|
||||
p.applicationInfo.metaData = new Bundle();
|
||||
if (valid) {
|
||||
// no flag means invalid
|
||||
p.applicationInfo.metaData.putString(WEBVIEW_LIBRARY_FLAG, "blah");
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
private static PackageInfo createPackageInfo(
|
||||
String packageName, boolean enabled, boolean valid, Signature[] signatures) {
|
||||
PackageInfo p = createPackageInfo(packageName, enabled, valid);
|
||||
p.signatures = signatures;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
// ****************
|
||||
// Tests
|
||||
// ****************
|
||||
|
||||
|
||||
public void testWithSinglePackage() {
|
||||
String testPackageName = "test.package.name";
|
||||
checkCertainPackageUsedAfterWebViewPreparation(testPackageName,
|
||||
new WebViewProviderInfo[] {
|
||||
new WebViewProviderInfo(testPackageName, "",
|
||||
true /*default available*/, false /* fallback */, null)});
|
||||
}
|
||||
|
||||
public void testDefaultPackageUsedOverNonDefault() {
|
||||
String defaultPackage = "defaultPackage";
|
||||
String nonDefaultPackage = "nonDefaultPackage";
|
||||
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
|
||||
new WebViewProviderInfo(nonDefaultPackage, "", false, false, null),
|
||||
new WebViewProviderInfo(defaultPackage, "", true, false, null)};
|
||||
checkCertainPackageUsedAfterWebViewPreparation(defaultPackage, packages);
|
||||
}
|
||||
|
||||
public void testSeveralRelros() {
|
||||
String singlePackage = "singlePackage";
|
||||
checkCertainPackageUsedAfterWebViewPreparation(
|
||||
singlePackage,
|
||||
new WebViewProviderInfo[] {
|
||||
new WebViewProviderInfo(singlePackage, "", true /*def av*/, false, null)},
|
||||
2);
|
||||
}
|
||||
|
||||
// Ensure that package with valid signatures is chosen rather than package with invalid
|
||||
// signatures.
|
||||
public void testWithSignatures() {
|
||||
String validPackage = "valid package";
|
||||
String invalidPackage = "invalid package";
|
||||
|
||||
Signature validSignature = new Signature("11");
|
||||
Signature invalidExpectedSignature = new Signature("22");
|
||||
Signature invalidPackageSignature = new Signature("33");
|
||||
|
||||
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
|
||||
new WebViewProviderInfo(invalidPackage, "", true, false, new String[]{
|
||||
Base64.encodeToString(
|
||||
invalidExpectedSignature.toByteArray(), Base64.DEFAULT)}),
|
||||
new WebViewProviderInfo(validPackage, "", true, false, new String[]{
|
||||
Base64.encodeToString(
|
||||
validSignature.toByteArray(), Base64.DEFAULT)})
|
||||
};
|
||||
setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */,
|
||||
false /* isDebuggable */);
|
||||
mTestSystemImpl.setPackageInfo(createPackageInfo(invalidPackage, true /* enabled */,
|
||||
true /* valid */, new Signature[]{invalidPackageSignature}));
|
||||
mTestSystemImpl.setPackageInfo(createPackageInfo(validPackage, true /* enabled */,
|
||||
true /* valid */, new Signature[]{validSignature}));
|
||||
|
||||
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);
|
||||
|
||||
WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
|
||||
assertEquals(1, validPackages.length);
|
||||
assertEquals(validPackage, validPackages[0].packageName);
|
||||
}
|
||||
|
||||
public void testFailWaitingForRelro() {
|
||||
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
|
||||
new WebViewProviderInfo("packagename", "", true, true, null)};
|
||||
setupWithPackages(packages);
|
||||
setEnabledAndValidPackageInfos(packages);
|
||||
|
||||
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
|
||||
|
||||
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
|
||||
Mockito.argThat(new IsPackageInfoWithName(packages[0].packageName)));
|
||||
|
||||
// Never call notifyRelroCreation()
|
||||
|
||||
WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
|
||||
assertEquals(WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO, response.status);
|
||||
}
|
||||
|
||||
public void testFailListingEmptyWebviewPackages() {
|
||||
WebViewProviderInfo[] packages = new WebViewProviderInfo[0];
|
||||
setupWithPackages(packages);
|
||||
setEnabledAndValidPackageInfos(packages);
|
||||
|
||||
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
|
||||
|
||||
Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
|
||||
Matchers.anyObject());
|
||||
|
||||
WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
|
||||
assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
|
||||
}
|
||||
|
||||
public void testFailListingInvalidWebviewPackage() {
|
||||
WebViewProviderInfo wpi = new WebViewProviderInfo("", "", true, true, null);
|
||||
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {wpi};
|
||||
setupWithPackages(packages);
|
||||
mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true, false));
|
||||
|
||||
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
|
||||
WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
|
||||
assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
|
||||
}
|
||||
|
||||
// Test that switching provider using changeProviderAndSetting works.
|
||||
public void testSwitchingProvider() {
|
||||
String firstPackage = "first";
|
||||
String secondPackage = "second";
|
||||
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
|
||||
new WebViewProviderInfo(firstPackage, "", true, false, null),
|
||||
new WebViewProviderInfo(secondPackage, "", true, false, null)};
|
||||
checkSwitchingProvider(packages, firstPackage, secondPackage);
|
||||
}
|
||||
|
||||
public void testSwitchingProviderToNonDefault() {
|
||||
String defaultPackage = "defaultPackage";
|
||||
String nonDefaultPackage = "nonDefaultPackage";
|
||||
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
|
||||
new WebViewProviderInfo(defaultPackage, "", true, false, null),
|
||||
new WebViewProviderInfo(nonDefaultPackage, "", false, false, null)};
|
||||
checkSwitchingProvider(packages, defaultPackage, nonDefaultPackage);
|
||||
}
|
||||
|
||||
private void checkSwitchingProvider(WebViewProviderInfo[] packages, String initialPackage,
|
||||
String finalPackage) {
|
||||
checkCertainPackageUsedAfterWebViewPreparation(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);
|
||||
|
||||
Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(initialPackage));
|
||||
}
|
||||
|
||||
// Change provider during relro creation by using changeProviderAndSetting
|
||||
public void testSwitchingProviderDuringRelroCreation() {
|
||||
checkChangingProviderDuringRelroCreation(true);
|
||||
}
|
||||
|
||||
// Change provider during relro creation by enabling a provider
|
||||
public void testChangingProviderThroughEnablingDuringRelroCreation() {
|
||||
checkChangingProviderDuringRelroCreation(false);
|
||||
}
|
||||
|
||||
private void checkChangingProviderDuringRelroCreation(boolean settingsChange) {
|
||||
String firstPackage = "first";
|
||||
String secondPackage = "second";
|
||||
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
|
||||
new WebViewProviderInfo(firstPackage, "", true, false, null),
|
||||
new WebViewProviderInfo(secondPackage, "", true, false, null)};
|
||||
setupWithPackages(packages);
|
||||
if (settingsChange) {
|
||||
// Have all packages be enabled, so that we can change provider however we want to
|
||||
setEnabledAndValidPackageInfos(packages);
|
||||
} else {
|
||||
// Have all packages be disabled so that we can change one to enabled later
|
||||
for(WebViewProviderInfo wpi : packages) {
|
||||
mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName,
|
||||
false /* enabled */, true /* valid */));
|
||||
}
|
||||
}
|
||||
|
||||
CountDownLatch countdown = new CountDownLatch(1);
|
||||
|
||||
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
|
||||
|
||||
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
|
||||
Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
|
||||
|
||||
assertEquals(firstPackage, mWebViewUpdateServiceImpl.getCurrentWebViewPackageName());
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
WebViewProviderResponse threadResponse =
|
||||
mWebViewUpdateServiceImpl.waitForAndGetProvider();
|
||||
assertEquals(WebViewFactory.LIBLOAD_SUCCESS, threadResponse.status);
|
||||
assertEquals(secondPackage, threadResponse.packageInfo.packageName);
|
||||
// Verify that we killed the first package
|
||||
Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage));
|
||||
countdown.countDown();
|
||||
}
|
||||
}).start();
|
||||
try {
|
||||
Thread.sleep(1000); // Let the new thread run / be blocked
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
|
||||
if (settingsChange) {
|
||||
mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
|
||||
} else {
|
||||
// Switch provider by enabling the second one
|
||||
mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
|
||||
true /* valid */));
|
||||
mWebViewUpdateServiceImpl.packageStateChanged(
|
||||
secondPackage, WebViewUpdateService.PACKAGE_CHANGED);
|
||||
}
|
||||
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
|
||||
// first package done, should start on second
|
||||
|
||||
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
|
||||
Mockito.argThat(new IsPackageInfoWithName(secondPackage)));
|
||||
|
||||
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
|
||||
// second package done, the other thread should now be unblocked
|
||||
try {
|
||||
countdown.await();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testRunFallbackLogicIfEnabled() {
|
||||
checkFallbackLogicBeingRun(true);
|
||||
}
|
||||
|
||||
public void testDontRunFallbackLogicIfDisabled() {
|
||||
checkFallbackLogicBeingRun(false);
|
||||
}
|
||||
|
||||
private void checkFallbackLogicBeingRun(boolean fallbackLogicEnabled) {
|
||||
String primaryPackage = "primary";
|
||||
String fallbackPackage = "fallback";
|
||||
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
|
||||
new WebViewProviderInfo(
|
||||
primaryPackage, "", true /* default available */, false /* fallback */, null),
|
||||
new WebViewProviderInfo(
|
||||
fallbackPackage, "", true /* default available */, true /* fallback */, null)};
|
||||
setupWithPackages(packages, fallbackLogicEnabled);
|
||||
setEnabledAndValidPackageInfos(packages);
|
||||
|
||||
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
|
||||
// Verify that we disable the fallback package if fallback logic enabled, and don't disable
|
||||
// the fallback package if that logic is disabled
|
||||
if (fallbackLogicEnabled) {
|
||||
Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
|
||||
Matchers.anyObject(), Mockito.eq(fallbackPackage));
|
||||
} else {
|
||||
Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
|
||||
Matchers.anyObject(), Matchers.anyObject());
|
||||
}
|
||||
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
|
||||
Mockito.argThat(new IsPackageInfoWithName(primaryPackage)));
|
||||
|
||||
// Enable fallback package
|
||||
mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
|
||||
true /* valid */));
|
||||
mWebViewUpdateServiceImpl.packageStateChanged(
|
||||
fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED);
|
||||
|
||||
if (fallbackLogicEnabled) {
|
||||
// Check that we have now disabled the fallback package twice
|
||||
Mockito.verify(mTestSystemImpl, Mockito.times(2)).uninstallAndDisablePackageForAllUsers(
|
||||
Matchers.anyObject(), Mockito.eq(fallbackPackage));
|
||||
} else {
|
||||
// Check that we still haven't disabled any package
|
||||
Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
|
||||
Matchers.anyObject(), Matchers.anyObject());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario for installing primary package when fallback enabled.
|
||||
* 1. Start with only fallback installed
|
||||
* 2. Install non-fallback
|
||||
* 3. Fallback should be disabled
|
||||
*/
|
||||
public void testInstallingNonFallbackPackage() {
|
||||
String primaryPackage = "primary";
|
||||
String fallbackPackage = "fallback";
|
||||
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
|
||||
new WebViewProviderInfo(
|
||||
primaryPackage, "", true /* default available */, false /* fallback */, null),
|
||||
new WebViewProviderInfo(
|
||||
fallbackPackage, "", true /* default available */, true /* fallback */, null)};
|
||||
setupWithPackages(packages, true /* isFallbackLogicEnabled */);
|
||||
mTestSystemImpl.setPackageInfo(
|
||||
createPackageInfo(fallbackPackage, true /* enabled */ , true /* valid */));
|
||||
|
||||
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);
|
||||
|
||||
// Install primary package
|
||||
mTestSystemImpl.setPackageInfo(
|
||||
createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */));
|
||||
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
|
||||
WebViewUpdateService.PACKAGE_ADDED);
|
||||
|
||||
// Verify fallback disabled and primary package used as provider
|
||||
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);
|
||||
Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(fallbackPackage));
|
||||
}
|
||||
|
||||
public void testFallbackChangesEnabledState() {
|
||||
String primaryPackage = "primary";
|
||||
String fallbackPackage = "fallback";
|
||||
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
|
||||
new WebViewProviderInfo(
|
||||
primaryPackage, "", true /* default available */, false /* fallback */, null),
|
||||
new WebViewProviderInfo(
|
||||
fallbackPackage, "", true /* default available */, true /* fallback */, null)};
|
||||
setupWithPackages(packages, true /* fallbackLogicEnabled */);
|
||||
setEnabledAndValidPackageInfos(packages);
|
||||
|
||||
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
|
||||
|
||||
// Verify fallback disabled at boot when primary package enabled
|
||||
Mockito.verify(mTestSystemImpl).enablePackageForUser(
|
||||
Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
|
||||
Matchers.anyInt());
|
||||
|
||||
mTestSystemImpl.setPackageInfo(
|
||||
createPackageInfo(primaryPackage, false /* enabled */, true /* valid */));
|
||||
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
|
||||
WebViewUpdateService.PACKAGE_CHANGED);
|
||||
|
||||
// Verify fallback becomes enabled when primary package becomes disabled
|
||||
Mockito.verify(mTestSystemImpl).enablePackageForUser(
|
||||
Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */,
|
||||
Matchers.anyInt());
|
||||
|
||||
mTestSystemImpl.setPackageInfo(
|
||||
createPackageInfo(primaryPackage, true /* enabled */, true /* valid */));
|
||||
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
|
||||
WebViewUpdateService.PACKAGE_CHANGED);
|
||||
|
||||
// Verify fallback is disabled a second time when primary package becomes enabled
|
||||
Mockito.verify(mTestSystemImpl, Mockito.times(2)).enablePackageForUser(
|
||||
Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
|
||||
Matchers.anyInt());
|
||||
}
|
||||
|
||||
public void testAddUserWhenFallbackLogicEnabled() {
|
||||
checkAddingNewUser(true);
|
||||
}
|
||||
|
||||
public void testAddUserWhenFallbackLogicDisabled() {
|
||||
checkAddingNewUser(false);
|
||||
}
|
||||
|
||||
public void checkAddingNewUser(boolean fallbackLogicEnabled) {
|
||||
String primaryPackage = "primary";
|
||||
String fallbackPackage = "fallback";
|
||||
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
|
||||
new WebViewProviderInfo(
|
||||
primaryPackage, "", true /* default available */, false /* fallback */, null),
|
||||
new WebViewProviderInfo(
|
||||
fallbackPackage, "", true /* default available */, true /* fallback */, null)};
|
||||
setupWithPackages(packages, fallbackLogicEnabled);
|
||||
setEnabledAndValidPackageInfos(packages);
|
||||
int newUser = 100;
|
||||
mWebViewUpdateServiceImpl.handleNewUser(newUser);
|
||||
if (fallbackLogicEnabled) {
|
||||
// Verify fallback package becomes disabled for new user
|
||||
Mockito.verify(mTestSystemImpl).enablePackageForUser(
|
||||
Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
|
||||
Mockito.eq(newUser));
|
||||
} else {
|
||||
// Verify that we don't disable fallback for new user
|
||||
Mockito.verify(mTestSystemImpl, Mockito.never()).enablePackageForUser(
|
||||
Mockito.anyObject(), Matchers.anyBoolean() /* enable */,
|
||||
Matchers.anyInt() /* user */);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Timing dependent test where we verify that the list of valid webview packages becoming empty
|
||||
* at a certain point doesn't crash us or break our state.
|
||||
*/
|
||||
public void testNotifyRelroDoesntCrashIfNoPackages() {
|
||||
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)};
|
||||
setupWithPackages(packages);
|
||||
// Add (enabled and valid) package infos for each provider
|
||||
setEnabledAndValidPackageInfos(packages);
|
||||
|
||||
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
|
||||
|
||||
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
|
||||
Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
|
||||
|
||||
mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
|
||||
|
||||
// Make packages invalid to cause exception to be thrown
|
||||
mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
|
||||
false /* valid */));
|
||||
mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
|
||||
false /* valid */));
|
||||
|
||||
// This shouldn't throw an exception!
|
||||
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
|
||||
|
||||
WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
|
||||
assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
|
||||
|
||||
// Now make a package valid again and verify that we can switch back to that
|
||||
mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
|
||||
true /* valid */));
|
||||
|
||||
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)));
|
||||
|
||||
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
|
||||
|
||||
response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
|
||||
assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
|
||||
assertEquals(firstPackage, response.packageInfo.packageName);
|
||||
}
|
||||
|
||||
// TODO (gsennton) add more tests for ensuring killPackageDependents is called / not called
|
||||
}
|
||||
Reference in New Issue
Block a user