package com.android.server.webkit;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
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.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.MediumTest;
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.junit.Test;
+import org.junit.runner.RunWith;
+
import org.mockito.Mockito;
import org.mockito.Matchers;
import org.mockito.ArgumentMatcher;
+import java.util.concurrent.CountDownLatch;
+
/**
* Tests for WebViewUpdateService
*/
-public class WebViewUpdateServiceTest extends AndroidTestCase {
+// Use MediumTest instead of SmallTest as the implementation of WebViewUpdateService
+// is intended to work on several threads and uses at least one sleep/wait-statement.
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class WebViewUpdateServiceTest {
private final static String TAG = WebViewUpdateServiceTest.class.getSimpleName();
private WebViewUpdateServiceImpl mWebViewUpdateServiceImpl;
private static final String WEBVIEW_LIBRARY_FLAG = "com.android.webview.WebViewLibrary";
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- }
-
/**
* Creates a new instance.
*/
// Add (enabled and valid) package infos for each provider
setEnabledAndValidPackageInfos(webviewPackages);
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
Mockito.argThat(new IsPackageInfoWithName(expectedProviderName)));
assertEquals(expectedPackage, response.packageInfo.packageName);
}
+ /**
+ * The WebView preparation boot phase is run on the main thread (especially on a thread with a
+ * looper) so to avoid bugs where our tests fail because a looper hasn't been attached to the
+ * thread running prepareWebViewInSystemServer we run it on the main thread.
+ */
+ private void runWebViewBootPreparationOnMainSync() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ }
+ });
+ }
+
// ****************
// Tests
// ****************
+ @Test
public void testWithSinglePackage() {
String testPackageName = "test.package.name";
checkCertainPackageUsedAfterWebViewBootPreparation(testPackageName,
true /*default available*/, false /* fallback */, null)});
}
+ @Test
public void testDefaultPackageUsedOverNonDefault() {
String defaultPackage = "defaultPackage";
String nonDefaultPackage = "nonDefaultPackage";
checkCertainPackageUsedAfterWebViewBootPreparation(defaultPackage, packages);
}
+ @Test
public void testSeveralRelros() {
String singlePackage = "singlePackage";
checkCertainPackageUsedAfterWebViewBootPreparation(
// Ensure that package with valid signatures is chosen rather than package with invalid
// signatures.
+ @Test
public void testWithSignatures() {
String validPackage = "valid package";
String invalidPackage = "invalid package";
true /* valid */, true /* installed */, new Signature[]{validSignature}
, 0 /* updateTime */));
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
checkPreparationPhasesForPackage(validPackage, 1 /* first preparation for this package */);
assertEquals(validPackage, validPackages[0].packageName);
}
+ @Test
public void testFailWaitingForRelro() {
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
new WebViewProviderInfo("packagename", "", true, true, null)};
setupWithPackages(packages);
setEnabledAndValidPackageInfos(packages);
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
Mockito.argThat(new IsPackageInfoWithName(packages[0].packageName)));
assertEquals(WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO, response.status);
}
+ @Test
public void testFailListingEmptyWebviewPackages() {
WebViewProviderInfo[] packages = new WebViewProviderInfo[0];
setupWithPackages(packages);
setEnabledAndValidPackageInfos(packages);
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
Matchers.anyObject());
assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
}
+ @Test
public void testFailListingInvalidWebviewPackage() {
WebViewProviderInfo wpi = new WebViewProviderInfo("package", "", true, true, null);
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {wpi};
createPackageInfo(wpi.packageName, true /* enabled */, false /* valid */,
true /* installed */));
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
Matchers.anyObject());
}
// Test that switching provider using changeProviderAndSetting works.
+ @Test
public void testSwitchingProvider() {
String firstPackage = "first";
String secondPackage = "second";
checkSwitchingProvider(packages, firstPackage, secondPackage);
}
+ @Test
public void testSwitchingProviderToNonDefault() {
String defaultPackage = "defaultPackage";
String nonDefaultPackage = "nonDefaultPackage";
}
// Change provider during relro creation by using changeProviderAndSetting
+ @Test
public void testSwitchingProviderDuringRelroCreation() {
checkChangingProviderDuringRelroCreation(true);
}
// Change provider during relro creation by enabling a provider
+ @Test
public void testChangingProviderThroughEnablingDuringRelroCreation() {
checkChangingProviderDuringRelroCreation(false);
}
CountDownLatch countdown = new CountDownLatch(1);
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
}
}
+ @Test
public void testRunFallbackLogicIfEnabled() {
checkFallbackLogicBeingRun(true);
}
+ @Test
public void testDontRunFallbackLogicIfDisabled() {
checkFallbackLogicBeingRun(false);
}
setupWithPackages(packages, fallbackLogicEnabled);
setEnabledAndValidPackageInfos(packages);
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
// 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) {
* 2. Install non-fallback
* 3. Fallback should be disabled
*/
+ @Test
public void testInstallingNonFallbackPackage() {
String primaryPackage = "primary";
String fallbackPackage = "fallback";
createPackageInfo(fallbackPackage, true /* enabled */ , true /* valid */,
true /* installed */));
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
Matchers.anyObject(), Matchers.anyObject());
Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(fallbackPackage));
}
+ @Test
public void testFallbackChangesEnabledState() {
String primaryPackage = "primary";
String fallbackPackage = "fallback";
setupWithPackages(packages, true /* fallbackLogicEnabled */);
setEnabledAndValidPackageInfos(packages);
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
// Verify fallback disabled at boot when primary package enabled
Mockito.verify(mTestSystemImpl).enablePackageForUser(
checkPreparationPhasesForPackage(primaryPackage, 2);
}
+ @Test
public void testAddUserWhenFallbackLogicEnabled() {
checkAddingNewUser(true);
}
+ @Test
public void testAddUserWhenFallbackLogicDisabled() {
checkAddingNewUser(false);
}
* 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.
*/
+ @Test
public void testNotifyRelroDoesntCrashIfNoPackages() {
String firstPackage = "first";
String secondPackage = "second";
// Add (enabled and valid) package infos for each provider
setEnabledAndValidPackageInfos(packages);
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
* Verify that even if a user-chosen package is removed temporarily we start using it again when
* it is added back.
*/
+ @Test
public void testTempRemovePackageDoesntSwitchProviderPermanently() {
String firstPackage = "first";
String secondPackage = "second";
* Ensure that we update the user-chosen setting across boots if the chosen package is no
* longer installed and valid.
*/
+ @Test
public void testProviderSettingChangedDuringBootIfProviderNotAvailable() {
String chosenPackage = "chosenPackage";
String nonChosenPackage = "non-chosenPackage";
// Set user-chosen package
mTestSystemImpl.updateUserSetting(null, chosenPackage);
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
// Verify that we switch the setting to point to the current package
Mockito.verify(mTestSystemImpl).updateUserSetting(
checkPreparationPhasesForPackage(nonChosenPackage, 1);
}
+ @Test
public void testRecoverFailedListingWebViewPackagesSettingsChange() {
checkRecoverAfterFailListingWebviewPackages(true);
}
+ @Test
public void testRecoverFailedListingWebViewPackagesAddedPackage() {
checkRecoverAfterFailListingWebviewPackages(false);
}
checkPreparationPhasesForPackage(secondPackage, 1);
}
+ @Test
public void testDontKillIfPackageReplaced() {
checkDontKillIfPackageRemoved(true);
}
+ @Test
public void testDontKillIfPackageRemoved() {
checkDontKillIfPackageRemoved(false);
}
Mockito.anyObject());
}
+ @Test
public void testKillIfSettingChanged() {
String firstPackage = "first";
String secondPackage = "second";
* Test that we kill apps using an old provider when we change the provider setting, even if the
* new provider is not the one we intended to change to.
*/
+ @Test
public void testKillIfChangeProviderIncorrectly() {
String firstPackage = "first";
String secondPackage = "second";
// Start with the setting pointing to the third package
mTestSystemImpl.updateUserSetting(null, thirdPackage);
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
checkPreparationPhasesForPackage(thirdPackage, 1);
mTestSystemImpl.setPackageInfo(
// Ensure that the update service uses an uninstalled package if that is the only package
// available.
+ @Test
public void testWithSingleUninstalledPackage() {
String testPackageName = "test.package.name";
WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
mTestSystemImpl.setPackageInfo(createPackageInfo(testPackageName, true /* enabled */,
true /* valid */, false /* installed */));
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
checkPreparationPhasesForPackage(testPackageName, 1 /* first preparation phase */);
}
+ @Test
public void testNonhiddenPackageUserOverHidden() {
checkVisiblePackageUserOverNonVisible(false /* true == uninstalled, false == hidden */);
}
+ @Test
public void testInstalledPackageUsedOverUninstalled() {
checkVisiblePackageUserOverNonVisible(true /* true == uninstalled, false == hidden */);
}
true /* valid */, (testUninstalled ? false : true) /* installed */,
null /* signatures */, 0 /* updateTime */, (testHidden ? true : false)));
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
}
+ @Test
public void testCantSwitchToHiddenPackage () {
checkCantSwitchToNonVisiblePackage(false /* true == uninstalled, false == hidden */);
}
+ @Test
public void testCantSwitchToUninstalledPackage () {
checkCantSwitchToNonVisiblePackage(true /* true == uninstalled, false == hidden */);
}
null /* signatures */, 0 /* updateTime */,
(testHidden ? true : false) /* hidden */));
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
Mockito.argThat(new IsPackageInfoWithName(installedPackage)));
}
+ @Test
public void testHiddenPackageNotPrioritizedEvenIfChosen() {
checkNonvisiblePackageNotPrioritizedEvenIfChosen(
false /* true == uninstalled, false == hidden */);
}
+ @Test
public void testUninstalledPackageNotPrioritizedEvenIfChosen() {
checkNonvisiblePackageNotPrioritizedEvenIfChosen(
true /* true == uninstalled, false == hidden */);
// Start with the setting pointing to the uninstalled package
mTestSystemImpl.updateUserSetting(null, uninstalledPackage);
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
}
* Ensures that fallback becomes enabled if the primary package is uninstalled for the current
* user.
*/
+ @Test
public void testFallbackEnabledIfPrimaryUninstalled() {
String primaryPackage = "primary";
String fallbackPackage = "fallback";
mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
true /* valid */, true /* installed */));
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
// Verify that we enable the fallback package
Mockito.verify(mTestSystemImpl).enablePackageForAllUsers(
Mockito.anyObject(), Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */);
checkPreparationPhasesForPackage(fallbackPackage, 1 /* first preparation phase */);
}
+ @Test
public void testPreparationRunsIffNewPackage() {
String primaryPackage = "primary";
String fallbackPackage = "fallback";
mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
true /* valid */, true /* installed */));
- mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ runWebViewBootPreparationOnMainSync();
checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */);
Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser(
checkPreparationPhasesForPackage(primaryPackage, 3 /* third preparation phase */);
}
-
}