Merge "Change WebView fallback mechanism to consider all users' package states."

This commit is contained in:
TreeHugger Robot
2017-01-23 20:20:10 +00:00
committed by Android (Google) Code Review
7 changed files with 537 additions and 189 deletions

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2017 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 android.webkit;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.os.UserManager;
import java.util.ArrayList;
import java.util.List;
/**
* Utility class for storing a (user,PackageInfo) mapping.
* @hide
*/
public class UserPackage {
private final UserInfo mUserInfo;
private final PackageInfo mPackageInfo;
public UserPackage(UserInfo user, PackageInfo packageInfo) {
this.mUserInfo = user;
this.mPackageInfo = packageInfo;
}
/**
* Returns a list of (User,PackageInfo) pairs corresponding to the PackageInfos for all
* device users for the package named {@param packageName}.
*/
public static List<UserPackage> getPackageInfosAllUsers(Context context,
String packageName, int packageFlags) {
List<UserInfo> users = getAllUsers(context);
List<UserPackage> userPackages = new ArrayList<UserPackage>(users.size());
for (UserInfo user : users) {
PackageInfo packageInfo = null;
try {
packageInfo = context.getPackageManager().getPackageInfoAsUser(
packageName, packageFlags, user.id);
} catch (NameNotFoundException e) {
}
userPackages.add(new UserPackage(user, packageInfo));
}
return userPackages;
}
/**
* Returns whether the given package is enabled.
* This state can be changed by the user from Settings->Apps
*/
public boolean isEnabledPackage() {
if (mPackageInfo == null) return false;
return mPackageInfo.applicationInfo.enabled;
}
/**
* Return true if the package is installed and not hidden
*/
public boolean isInstalledPackage() {
if (mPackageInfo == null) return false;
return (((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0)
&& ((mPackageInfo.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_HIDDEN) == 0));
}
public UserInfo getUserInfo() {
return mUserInfo;
}
public PackageInfo getPackageInfo() {
return mPackageInfo;
}
private static List<UserInfo> getAllUsers(Context context) {
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
return userManager.getUsers(false);
}
}

View File

@@ -35,6 +35,7 @@ import android.provider.Settings.Global;
import android.provider.Settings;
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.webkit.UserPackage;
import android.webkit.WebViewFactory;
import android.webkit.WebViewProviderInfo;
import android.webkit.WebViewZygote;
@@ -270,6 +271,12 @@ public class SystemImpl implements SystemInterface {
return pm.getPackageInfo(configInfo.packageName, PACKAGE_FLAGS);
}
@Override
public List<UserPackage> getPackageInfoForProviderAllUsers(Context context,
WebViewProviderInfo configInfo) {
return UserPackage.getPackageInfosAllUsers(context, configInfo.packageName, PACKAGE_FLAGS);
}
@Override
public int getMultiProcessSetting(Context context) {
return Settings.Global.getInt(context.getContentResolver(),

View File

@@ -20,8 +20,11 @@ import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
import android.webkit.UserPackage;
import android.webkit.WebViewProviderInfo;
import java.util.List;
/**
* System interface for the WebViewUpdateService.
* This interface provides a way to test the WebView preparation mechanism - during normal use this
@@ -49,6 +52,14 @@ public interface SystemInterface {
public boolean systemIsDebuggable();
public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
throws NameNotFoundException;
/**
* Get the PackageInfos of all users for the package represented by {@param configInfo}.
* @return an array of UserPackages for a certain package, each UserPackage being belonging to a
* certain user. The returned array can contain null PackageInfos if the given package
* is uninstalled for some user.
*/
public List<UserPackage> getPackageInfoForProviderAllUsers(Context context,
WebViewProviderInfo configInfo);
public int getMultiProcessSetting(Context context);
public void setMultiProcessSetting(Context context, int value);

View File

@@ -94,6 +94,9 @@ public class WebViewUpdateService extends SystemService {
case Intent.ACTION_USER_ADDED:
mImpl.handleNewUser(userId);
break;
case Intent.ACTION_USER_REMOVED:
mImpl.handleUserRemoved(userId);
break;
}
}
};
@@ -112,6 +115,7 @@ public class WebViewUpdateService extends SystemService {
IntentFilter userAddedFilter = new IntentFilter();
userAddedFilter.addAction(Intent.ACTION_USER_ADDED);
userAddedFilter.addAction(Intent.ACTION_USER_REMOVED);
getContext().registerReceiverAsUser(mWebViewUpdatedReceiver, UserHandle.ALL,
userAddedFilter, null /* broadcast permission */, null /* handler */);

View File

@@ -24,6 +24,7 @@ import android.os.Handler;
import android.os.UserHandle;
import android.util.Base64;
import android.util.Slog;
import android.webkit.UserPackage;
import android.webkit.WebViewFactory;
import android.webkit.WebViewProviderInfo;
import android.webkit.WebViewProviderResponse;
@@ -100,32 +101,41 @@ public class WebViewUpdateServiceImpl {
private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
for (WebViewProviderInfo provider : providers) {
if (provider.availableByDefault && !provider.isFallback) {
try {
PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(provider);
if (isInstalledPackage(packageInfo) && isEnabledPackage(packageInfo)
&& mWebViewUpdater.isValidProvider(provider, packageInfo)) {
return true;
}
} catch (NameNotFoundException e) {
// A non-existent provider is neither valid nor enabled
// userPackages can contain null objects.
List<UserPackage> userPackages =
mSystemInterface.getPackageInfoForProviderAllUsers(mContext, provider);
if (isInstalledAndEnabledForAllUsers(userPackages) &&
// Checking validity of the package for the system user (rather than all
// users) since package validity depends not on the user but on the package
// itself.
mWebViewUpdater.isValidProvider(provider,
userPackages.get(UserHandle.USER_SYSTEM).getPackageInfo())) {
return true;
}
}
}
return false;
}
/**
* Called when a new user has been added to update the state of its fallback package.
*/
void handleNewUser(int userId) {
if (!mSystemInterface.isFallbackLogicEnabled()) return;
handleUserChange();
}
WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
if (fallbackProvider == null) return;
void handleUserRemoved(int userId) {
handleUserChange();
}
mSystemInterface.enablePackageForUser(fallbackProvider.packageName,
!existsValidNonFallbackProvider(webviewProviders), userId);
/**
* Called when a user was added or removed to ensure fallback logic and WebView preparation are
* triggered. This has to be done since the WebView package we use depends on the enabled-state
* of packages for all users (so adding or removing a user might cause us to change package).
*/
private void handleUserChange() {
if (mSystemInterface.isFallbackLogicEnabled()) {
updateFallbackState(mSystemInterface.getWebViewPackages());
}
// Potentially trigger package-changing logic.
mWebViewUpdater.updateCurrentWebViewPackage(null);
}
void notifyRelroCreationCompleted() {
@@ -141,7 +151,7 @@ public class WebViewUpdateServiceImpl {
}
WebViewProviderInfo[] getValidWebViewPackages() {
return mWebViewUpdater.getValidAndInstalledWebViewPackages();
return mWebViewUpdater.getValidWebViewPackages();
}
WebViewProviderInfo[] getWebViewPackages() {
@@ -160,7 +170,7 @@ public class WebViewUpdateServiceImpl {
if (!mSystemInterface.isFallbackLogicEnabled()) return;
WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
updateFallbackState(webviewProviders, true);
updateFallbackState(webviewProviders);
}
/**
@@ -185,35 +195,23 @@ public class WebViewUpdateServiceImpl {
}
}
if (!changedPackageAvailableByDefault) return;
updateFallbackState(webviewProviders, false);
updateFallbackState(webviewProviders);
}
private void updateFallbackState(WebViewProviderInfo[] webviewProviders, boolean isBoot) {
private void updateFallbackState(WebViewProviderInfo[] webviewProviders) {
// If there exists a valid and enabled non-fallback package - disable the fallback
// package, otherwise, enable it.
WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
if (fallbackProvider == null) return;
boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
boolean isFallbackEnabled = false;
try {
isFallbackEnabled = isEnabledPackage(
mSystemInterface.getPackageInfoForProvider(fallbackProvider));
} catch (NameNotFoundException e) {
// No fallback package installed -> early out.
return;
}
if (existsValidNonFallbackProvider
// During an OTA the primary user's WebView state might differ from other users', so
// ignore the state of that user during boot.
&& (isFallbackEnabled || isBoot)) {
List<UserPackage> userPackages =
mSystemInterface.getPackageInfoForProviderAllUsers(mContext, fallbackProvider);
if (existsValidNonFallbackProvider && !isDisabledForAllUsers(userPackages)) {
mSystemInterface.uninstallAndDisablePackageForAllUsers(mContext,
fallbackProvider.packageName);
} else if (!existsValidNonFallbackProvider
// During an OTA the primary user's WebView state might differ from other users', so
// ignore the state of that user during boot.
&& (!isFallbackEnabled || isBoot)) {
&& !isInstalledAndEnabledForAllUsers(userPackages)) {
// Enable the fallback package for all users.
mSystemInterface.enablePackageForAllUsers(mContext,
fallbackProvider.packageName, true);
@@ -376,38 +374,8 @@ public class WebViewUpdateServiceImpl {
* or the replacement are done).
*/
public String changeProviderAndSetting(String newProviderName) {
PackageInfo oldPackage = null;
PackageInfo newPackage = null;
boolean providerChanged = false;
synchronized(mLock) {
oldPackage = mCurrentWebViewPackage;
mSystemInterface.updateUserSetting(mContext, newProviderName);
try {
newPackage = findPreferredWebViewPackage();
providerChanged = (oldPackage == null)
|| !newPackage.packageName.equals(oldPackage.packageName);
} catch (WebViewPackageMissingException e) {
mCurrentWebViewPackage = null;
Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView " +
"package " + e);
// If we don't perform the user change but don't have an installed WebView
// package, we will have changed the setting and it will be used when a package
// is available.
return "";
}
// Perform the provider change if we chose a new provider
if (providerChanged) {
onWebViewProviderChanged(newPackage);
}
}
// Kill apps using the old provider only if we changed provider
if (providerChanged && oldPackage != null) {
mSystemInterface.killPackageDependents(oldPackage.packageName);
}
// Return the new provider, this is not necessarily the one we were asked to switch to
// But the persistent setting will now be pointing to the provider we were asked to
// switch to anyway
PackageInfo newPackage = updateCurrentWebViewPackage(newProviderName);
if (newPackage == null) return "";
return newPackage.packageName;
}
@@ -437,15 +405,14 @@ public class WebViewUpdateServiceImpl {
}
}
private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos(boolean onlyInstalled) {
private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos() {
WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages();
List<ProviderAndPackageInfo> providers = new ArrayList<>();
for(int n = 0; n < allProviders.length; n++) {
try {
PackageInfo packageInfo =
mSystemInterface.getPackageInfoForProvider(allProviders[n]);
if ((!onlyInstalled || isInstalledPackage(packageInfo))
&& isValidProvider(allProviders[n], packageInfo)) {
if (isValidProvider(allProviders[n], packageInfo)) {
providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
}
} catch (NameNotFoundException e) {
@@ -458,9 +425,8 @@ public class WebViewUpdateServiceImpl {
/**
* Fetch only the currently valid WebView packages.
**/
public WebViewProviderInfo[] getValidAndInstalledWebViewPackages() {
ProviderAndPackageInfo[] providersAndPackageInfos =
getValidWebViewPackagesAndInfos(true /* only fetch installed packages */);
public WebViewProviderInfo[] getValidWebViewPackages() {
ProviderAndPackageInfo[] providersAndPackageInfos = getValidWebViewPackagesAndInfos();
WebViewProviderInfo[] providers =
new WebViewProviderInfo[providersAndPackageInfos.length];
for(int n = 0; n < providersAndPackageInfos.length; n++) {
@@ -487,39 +453,49 @@ public class WebViewUpdateServiceImpl {
*
*/
private PackageInfo findPreferredWebViewPackage() throws WebViewPackageMissingException {
ProviderAndPackageInfo[] providers =
getValidWebViewPackagesAndInfos(false /* onlyInstalled */);
ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos();
String userChosenProvider = mSystemInterface.getUserChosenWebViewProvider(mContext);
// If the user has chosen provider, use that
// If the user has chosen provider, use that (if it's installed and enabled for all
// users).
for (ProviderAndPackageInfo providerAndPackage : providers) {
if (providerAndPackage.provider.packageName.equals(userChosenProvider)
&& isInstalledPackage(providerAndPackage.packageInfo)
&& isEnabledPackage(providerAndPackage.packageInfo)) {
return providerAndPackage.packageInfo;
if (providerAndPackage.provider.packageName.equals(userChosenProvider)) {
// userPackages can contain null objects.
List<UserPackage> userPackages =
mSystemInterface.getPackageInfoForProviderAllUsers(mContext,
providerAndPackage.provider);
if (isInstalledAndEnabledForAllUsers(userPackages)) {
return providerAndPackage.packageInfo;
}
}
}
// User did not choose, or the choice failed; use the most stable provider that is
// installed and enabled for the device owner, and available by default (not through
// installed and enabled for all users, and available by default (not through
// user choice).
for (ProviderAndPackageInfo providerAndPackage : providers) {
if (providerAndPackage.provider.availableByDefault
&& isInstalledPackage(providerAndPackage.packageInfo)
&& isEnabledPackage(providerAndPackage.packageInfo)) {
return providerAndPackage.packageInfo;
if (providerAndPackage.provider.availableByDefault) {
// userPackages can contain null objects.
List<UserPackage> userPackages =
mSystemInterface.getPackageInfoForProviderAllUsers(mContext,
providerAndPackage.provider);
if (isInstalledAndEnabledForAllUsers(userPackages)) {
return providerAndPackage.packageInfo;
}
}
}
// Could not find any installed and enabled package either, use the most stable and
// default-available provider.
// TODO(gsennton) remove this when we have a functional WebView stub.
for (ProviderAndPackageInfo providerAndPackage : providers) {
if (providerAndPackage.provider.availableByDefault) {
return providerAndPackage.packageInfo;
}
}
// This should never happen during normal operation (only with modified system images).
mAnyWebViewInstalled = false;
throw new WebViewPackageMissingException("Could not find a loadable WebView package");
}
@@ -702,6 +678,48 @@ public class WebViewUpdateServiceImpl {
mAnyWebViewInstalled));
}
}
/**
* Update the current WebView package.
* @param newProviderName the package to switch to, null if no package has been explicitly
* chosen.
*/
public PackageInfo updateCurrentWebViewPackage(String newProviderName) {
PackageInfo oldPackage = null;
PackageInfo newPackage = null;
boolean providerChanged = false;
synchronized(mLock) {
oldPackage = mCurrentWebViewPackage;
if (newProviderName != null) {
mSystemInterface.updateUserSetting(mContext, newProviderName);
}
try {
newPackage = findPreferredWebViewPackage();
providerChanged = (oldPackage == null)
|| !newPackage.packageName.equals(oldPackage.packageName);
} catch (WebViewPackageMissingException e) {
// If updated the Setting but don't have an installed WebView package, the
// Setting will be used when a package is available.
mCurrentWebViewPackage = null;
Slog.e(TAG, "Couldn't find WebView package to use " + e);
return null;
}
// Perform the provider change if we chose a new provider
if (providerChanged) {
onWebViewProviderChanged(newPackage);
}
}
// Kill apps using the old provider only if we changed provider
if (providerChanged && oldPackage != null) {
mSystemInterface.killPackageDependents(oldPackage.packageName);
}
// Return the new provider, this is not necessarily the one we were asked to switch to,
// but the persistent setting will now be pointing to the provider we were asked to
// switch to anyway.
return newPackage;
}
}
private static boolean providerHasValidSignature(WebViewProviderInfo provider,
@@ -730,20 +748,27 @@ public class WebViewUpdateServiceImpl {
}
/**
* Returns whether the given package is enabled.
* This state can be changed by the user from Settings->Apps
* Return true iff {@param packageInfos} point to only installed and enabled packages.
* The given packages {@param packageInfos} should all be pointing to the same package, but each
* PackageInfo representing a different user's package.
*/
private static boolean isEnabledPackage(PackageInfo packageInfo) {
return packageInfo.applicationInfo.enabled;
private static boolean isInstalledAndEnabledForAllUsers(
List<UserPackage> userPackages) {
for (UserPackage userPackage : userPackages) {
if (!userPackage.isInstalledPackage() || !userPackage.isEnabledPackage()) {
return false;
}
}
return true;
}
/**
* Return true if the package is installed and not hidden
*/
private static boolean isInstalledPackage(PackageInfo packageInfo) {
return (((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0)
&& ((packageInfo.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_HIDDEN) == 0));
private static boolean isDisabledForAllUsers(List<UserPackage> userPackages) {
for (UserPackage userPackage : userPackages) {
if (userPackage.getPackageInfo() != null && userPackage.isEnabledPackage()) {
return false;
}
}
return true;
}
/**

View File

@@ -19,25 +19,39 @@ package com.android.server.webkit;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.webkit.UserPackage;
import android.webkit.WebViewProviderInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TestSystemImpl implements SystemInterface {
private String mUserProvider = null;
private final WebViewProviderInfo[] mPackageConfigs;
HashMap<String, PackageInfo> mPackages = new HashMap();
List<Integer> mUsers = new ArrayList<>();
// Package -> [user, package]
Map<String, Map<Integer, PackageInfo>> mPackages = new HashMap();
private boolean mFallbackLogicEnabled;
private final int mNumRelros;
private final boolean mIsDebuggable;
private int mMultiProcessSetting;
public static final int PRIMARY_USER_ID = 0;
public TestSystemImpl(WebViewProviderInfo[] packageConfigs, boolean fallbackLogicEnabled,
int numRelros, boolean isDebuggable) {
mPackageConfigs = packageConfigs;
mFallbackLogicEnabled = fallbackLogicEnabled;
mNumRelros = numRelros;
mIsDebuggable = isDebuggable;
mUsers.add(PRIMARY_USER_ID);
}
public void addUser(int userId) {
mUsers.add(userId);
}
@Override
@@ -78,17 +92,20 @@ public class TestSystemImpl implements SystemInterface {
@Override
public void enablePackageForAllUsers(Context context, String packageName, boolean enable) {
enablePackageForUser(packageName, enable, 0);
for(int userId : mUsers) {
enablePackageForUser(packageName, enable, userId);
}
}
@Override
public void enablePackageForUser(String packageName, boolean enable, int userId) {
PackageInfo packageInfo = mPackages.get(packageName);
if (packageInfo == null) {
Map<Integer, PackageInfo> userPackages = mPackages.get(packageName);
if (userPackages == null) {
throw new IllegalArgumentException("There is no package called " + packageName);
}
PackageInfo packageInfo = userPackages.get(userId);
packageInfo.applicationInfo.enabled = enable;
setPackageInfo(packageInfo);
setPackageInfoForUser(userId, packageInfo);
}
@Override
@@ -97,23 +114,61 @@ public class TestSystemImpl implements SystemInterface {
@Override
public PackageInfo getPackageInfoForProvider(WebViewProviderInfo info) throws
NameNotFoundException {
PackageInfo ret = mPackages.get(info.packageName);
Map<Integer, PackageInfo> userPackages = mPackages.get(info.packageName);
if (userPackages == null) throw new NameNotFoundException(info.packageName);
PackageInfo ret = userPackages.get(PRIMARY_USER_ID);
if (ret == null) throw new NameNotFoundException(info.packageName);
return ret;
}
public void setPackageInfo(PackageInfo pi) {
mPackages.put(pi.packageName, pi);
@Override
public List<UserPackage> getPackageInfoForProviderAllUsers(
Context context, WebViewProviderInfo info) {
Map<Integer, PackageInfo> userPackages = mPackages.get(info.packageName);
List<UserPackage> ret = new ArrayList();
// Loop over defined users, and find the corresponding package for each user.
for (int userId : mUsers) {
ret.add(new UserPackage(createUserInfo(userId),
userPackages == null ? null : userPackages.get(userId)));
}
return ret;
}
private static UserInfo createUserInfo(int userId) {
return new UserInfo(userId, "User nr. " + userId, 0 /* flags */);
}
/**
* Set package for primary user.
*/
public void setPackageInfo(PackageInfo pi) {
setPackageInfoForUser(PRIMARY_USER_ID, pi);
}
public void setPackageInfoForUser(int userId, PackageInfo pi) {
if (!mUsers.contains(userId)) {
throw new IllegalArgumentException("User nr. " + userId + " doesn't exist");
}
if (!mPackages.containsKey(pi.packageName)) {
mPackages.put(pi.packageName, new HashMap<Integer, PackageInfo>());
}
mPackages.get(pi.packageName).put(userId, pi);
}
/**
* Removes the package {@param packageName} for the primary user.
*/
public void removePackageInfo(String packageName) {
mPackages.remove(packageName);
mPackages.get(packageName).remove(PRIMARY_USER_ID);
}
@Override
public int getFactoryPackageVersion(String packageName) throws NameNotFoundException {
PackageInfo pi = null;
pi = mPackages.get(packageName);
Map<Integer, PackageInfo> userPackages = mPackages.get(packageName);
if (userPackages == null) throw new NameNotFoundException();
pi = userPackages.get(PRIMARY_USER_ID);
if (pi != null && pi.applicationInfo.isSystemApp()) {
return pi.applicationInfo.versionCode;
}

View File

@@ -92,9 +92,15 @@ public class WebViewUpdateServiceTest {
}
private void setEnabledAndValidPackageInfos(WebViewProviderInfo[] providers) {
// Set package infos for the primary user (user 0).
setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, providers);
}
private void setEnabledAndValidPackageInfosForUser(int userId,
WebViewProviderInfo[] providers) {
for(WebViewProviderInfo wpi : providers) {
mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true /* enabled */,
true /* valid */, true /* installed */));
mTestSystemImpl.setPackageInfoForUser(userId, createPackageInfo(wpi.packageName,
true /* enabled */, true /* valid */, true /* installed */));
}
}
@@ -335,7 +341,7 @@ public class WebViewUpdateServiceTest {
setEnabledAndValidPackageInfos(packages);
mWebViewUpdateServiceImpl.packageStateChanged(singlePackage,
WebViewUpdateService.PACKAGE_ADDED, 0);
WebViewUpdateService.PACKAGE_ADDED, TestSystemImpl.PRIMARY_USER_ID);
checkPreparationPhasesForPackage(singlePackage, 1 /* number of finished preparations */);
assertEquals(singlePackage,
@@ -344,7 +350,7 @@ public class WebViewUpdateServiceTest {
// Remove the package again
mTestSystemImpl.removePackageInfo(singlePackage);
mWebViewUpdateServiceImpl.packageStateChanged(singlePackage,
WebViewUpdateService.PACKAGE_ADDED, 0);
WebViewUpdateService.PACKAGE_ADDED, TestSystemImpl.PRIMARY_USER_ID);
// Package removed - ensure our interface states that there is no package
response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
@@ -374,7 +380,7 @@ public class WebViewUpdateServiceTest {
createPackageInfo(wpi.packageName, true /* enabled */, true /* valid */,
true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(wpi.packageName,
WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID);
checkPreparationPhasesForPackage(wpi.packageName, 1);
}
@@ -429,16 +435,8 @@ public class WebViewUpdateServiceTest {
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 */, true /* installed */));
}
}
// Have all packages be enabled, so that we can change provider however we want to
setEnabledAndValidPackageInfos(packages);
CountDownLatch countdown = new CountDownLatch(1);
@@ -457,8 +455,12 @@ public class WebViewUpdateServiceTest {
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));
// Verify that we killed the first package if we performed a settings change -
// otherwise we had to disable the first package, in which case its dependents
// should have been killed by the framework.
if (settingsChange) {
Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage));
}
countdown.countDown();
}
}).start();
@@ -470,11 +472,21 @@ public class WebViewUpdateServiceTest {
if (settingsChange) {
mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
} else {
// Switch provider by enabling the second one
// Enable the second provider
mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
true /* valid */, true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(
secondPackage, WebViewUpdateService.PACKAGE_CHANGED, 0);
secondPackage, WebViewUpdateService.PACKAGE_CHANGED, TestSystemImpl.PRIMARY_USER_ID);
// Ensure we haven't changed package yet.
assertEquals(firstPackage,
mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
// Switch provider by disabling the first one
mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, false /* enabled */,
true /* valid */, true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(
firstPackage, WebViewUpdateService.PACKAGE_CHANGED, TestSystemImpl.PRIMARY_USER_ID);
}
mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
// first package done, should start on second
@@ -528,7 +540,7 @@ public class WebViewUpdateServiceTest {
mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
true /* valid */, true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(
fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED, 0);
fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED, TestSystemImpl.PRIMARY_USER_ID);
if (fallbackLogicEnabled) {
// Check that we have now disabled the fallback package twice
@@ -573,7 +585,7 @@ public class WebViewUpdateServiceTest {
createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */,
true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID);
// Verify fallback disabled, primary package used as provider, and fallback package killed
Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
@@ -583,7 +595,31 @@ public class WebViewUpdateServiceTest {
}
@Test
public void testFallbackChangesEnabledState() {
public void testFallbackChangesEnabledStateSingleUser() {
for (PackageRemovalType removalType : REMOVAL_TYPES) {
checkFallbackChangesEnabledState(false /* multiUser */, removalType);
}
}
@Test
public void testFallbackChangesEnabledStateMultiUser() {
for (PackageRemovalType removalType : REMOVAL_TYPES) {
checkFallbackChangesEnabledState(true /* multiUser */, removalType);
}
}
/**
* Represents how to remove a package during a tests (disabling it / uninstalling it / hiding
* it).
*/
private enum PackageRemovalType {
UNINSTALL, DISABLE, HIDE
}
private PackageRemovalType[] REMOVAL_TYPES = PackageRemovalType.class.getEnumConstants();
public void checkFallbackChangesEnabledState(boolean multiUser,
PackageRemovalType removalType) {
String primaryPackage = "primary";
String fallbackPackage = "fallback";
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
@@ -592,46 +628,68 @@ public class WebViewUpdateServiceTest {
new WebViewProviderInfo(
fallbackPackage, "", true /* default available */, true /* fallback */, null)};
setupWithPackages(packages, true /* fallbackLogicEnabled */);
setEnabledAndValidPackageInfos(packages);
int secondaryUserId = 10;
int userIdToChangePackageFor = multiUser ? secondaryUserId : TestSystemImpl.PRIMARY_USER_ID;
if (multiUser) {
mTestSystemImpl.addUser(secondaryUserId);
setEnabledAndValidPackageInfosForUser(secondaryUserId, packages);
}
setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, packages);
runWebViewBootPreparationOnMainSync();
// Verify fallback disabled at boot when primary package enabled
Mockito.verify(mTestSystemImpl).enablePackageForUser(
Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
Matchers.anyInt());
checkEnablePackageForUserCalled(fallbackPackage, false, multiUser
? new int[] {TestSystemImpl.PRIMARY_USER_ID, secondaryUserId}
: new int[] {TestSystemImpl.PRIMARY_USER_ID}, 1 /* numUsages */);
checkPreparationPhasesForPackage(primaryPackage, 1);
boolean enabled = !(removalType == PackageRemovalType.DISABLE);
boolean installed = !(removalType == PackageRemovalType.UNINSTALL);
boolean hidden = (removalType == PackageRemovalType.HIDE);
// Disable primary package and ensure fallback becomes enabled and used
mTestSystemImpl.setPackageInfo(
createPackageInfo(primaryPackage, false /* enabled */, true /* valid */,
true /* installed */));
mTestSystemImpl.setPackageInfoForUser(userIdToChangePackageFor,
createPackageInfo(primaryPackage, enabled /* enabled */, true /* valid */,
installed /* installed */, null /* signature */, 0 /* updateTime */,
hidden /* hidden */));
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
WebViewUpdateService.PACKAGE_CHANGED, 0);
removalType == PackageRemovalType.DISABLE
? WebViewUpdateService.PACKAGE_CHANGED : WebViewUpdateService.PACKAGE_REMOVED,
userIdToChangePackageFor); // USER ID
Mockito.verify(mTestSystemImpl).enablePackageForUser(
Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */,
Matchers.anyInt());
checkEnablePackageForUserCalled(fallbackPackage, true, multiUser
? new int[] {TestSystemImpl.PRIMARY_USER_ID, secondaryUserId}
: new int[] {TestSystemImpl.PRIMARY_USER_ID}, 1 /* numUsages */);
checkPreparationPhasesForPackage(fallbackPackage, 1);
// Again enable primary package and verify primary is used and fallback becomes disabled
mTestSystemImpl.setPackageInfo(
mTestSystemImpl.setPackageInfoForUser(userIdToChangePackageFor,
createPackageInfo(primaryPackage, true /* enabled */, true /* valid */,
true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
WebViewUpdateService.PACKAGE_CHANGED, 0);
removalType == PackageRemovalType.DISABLE
? WebViewUpdateService.PACKAGE_CHANGED : WebViewUpdateService.PACKAGE_ADDED,
userIdToChangePackageFor);
// 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());
checkEnablePackageForUserCalled(fallbackPackage, false, multiUser
? new int[] {TestSystemImpl.PRIMARY_USER_ID, secondaryUserId}
: new int[] {TestSystemImpl.PRIMARY_USER_ID}, 2 /* numUsages */);
checkPreparationPhasesForPackage(primaryPackage, 2);
}
private void checkEnablePackageForUserCalled(String packageName, boolean expectEnabled,
int[] userIds, int numUsages) {
for (int userId : userIds) {
Mockito.verify(mTestSystemImpl, Mockito.times(numUsages)).enablePackageForUser(
Mockito.eq(packageName), Mockito.eq(expectEnabled), Mockito.eq(userId));
}
}
@Test
public void testAddUserWhenFallbackLogicEnabled() {
checkAddingNewUser(true);
@@ -651,8 +709,10 @@ public class WebViewUpdateServiceTest {
new WebViewProviderInfo(
fallbackPackage, "", true /* default available */, true /* fallback */, null)};
setupWithPackages(packages, fallbackLogicEnabled);
setEnabledAndValidPackageInfos(packages);
setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, packages);
int newUser = 100;
mTestSystemImpl.addUser(newUser);
setEnabledAndValidPackageInfosForUser(newUser, packages);
mWebViewUpdateServiceImpl.handleNewUser(newUser);
if (fallbackLogicEnabled) {
// Verify fallback package becomes disabled for new user
@@ -667,6 +727,42 @@ public class WebViewUpdateServiceTest {
}
}
/**
* Ensures that adding a new user for which the current WebView package is uninstalled causes a
* change of WebView provider.
*/
@Test
public void testAddingNewUserWithUninstalledPackage() {
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 */);
setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, packages);
int newUser = 100;
mTestSystemImpl.addUser(newUser);
// Let the primary package be uninstalled for the new user
mTestSystemImpl.setPackageInfoForUser(newUser,
createPackageInfo(primaryPackage, true /* enabled */, true /* valid */,
false /* installed */));
mTestSystemImpl.setPackageInfoForUser(newUser,
createPackageInfo(fallbackPackage, false /* enabled */, true /* valid */,
true /* installed */));
mWebViewUpdateServiceImpl.handleNewUser(newUser);
// Verify fallback package doesn't become disabled for the primary user.
Mockito.verify(mTestSystemImpl, Mockito.never()).enablePackageForUser(
Mockito.anyObject(), Mockito.eq(false) /* enable */,
Mockito.eq(TestSystemImpl.PRIMARY_USER_ID) /* user */);
// Verify that we enable the fallback package for the secondary user.
Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser(
Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */,
Mockito.eq(newUser) /* user */);
checkPreparationPhasesForPackage(fallbackPackage, 1 /* numRelros */);
}
/**
* 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.
@@ -713,7 +809,7 @@ public class WebViewUpdateServiceTest {
1 /* updateTime */ ));
mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID);
// Ensure we use firstPackage
checkPreparationPhasesForPackage(firstPackage, 2 /* second preparation for this package */);
@@ -742,14 +838,14 @@ public class WebViewUpdateServiceTest {
mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
false /* valid */, true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
WebViewUpdateService.PACKAGE_ADDED, 0);
WebViewUpdateService.PACKAGE_ADDED, TestSystemImpl.PRIMARY_USER_ID);
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 */, true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
WebViewUpdateService.PACKAGE_ADDED, 0);
WebViewUpdateService.PACKAGE_ADDED, TestSystemImpl.PRIMARY_USER_ID);
checkPreparationPhasesForPackage(secondPackage, 2 /* second time for this package */);
}
@@ -820,7 +916,7 @@ public class WebViewUpdateServiceTest {
mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
} else {
mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID);
}
WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
@@ -831,7 +927,7 @@ public class WebViewUpdateServiceTest {
true /* valid */, true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID);
checkPreparationPhasesForPackage(secondPackage, 1);
@@ -863,11 +959,11 @@ public class WebViewUpdateServiceTest {
createPackageInfo(firstPackage, true /* enabled */, false /* valid */,
true /* installed */));
mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID);
} else {
mTestSystemImpl.removePackageInfo(firstPackage);
mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
WebViewUpdateService.PACKAGE_REMOVED, 0);
WebViewUpdateService.PACKAGE_REMOVED, TestSystemImpl.PRIMARY_USER_ID);
}
checkPreparationPhasesForPackage(secondPackage, 1);
@@ -1098,8 +1194,10 @@ public class WebViewUpdateServiceTest {
}
}
// Ensure that the update service uses an uninstalled package if that is the only package
// available.
/**
* Ensure that the update service does use an uninstalled package when that is the only
* package available.
*/
@Test
public void testWithSingleUninstalledPackage() {
String testPackageName = "test.package.name";
@@ -1113,21 +1211,32 @@ public class WebViewUpdateServiceTest {
runWebViewBootPreparationOnMainSync();
checkPreparationPhasesForPackage(testPackageName, 1 /* first preparation phase */);
// TODO(gsennton) change this logic to use the code below when we have created a functional
// stub.
//Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
// Matchers.anyObject());
//WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
//assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
//assertEquals(null, mWebViewUpdateServiceImpl.getCurrentWebViewPackage());
}
@Test
public void testNonhiddenPackageUserOverHidden() {
checkVisiblePackageUserOverNonVisible(false /* true == uninstalled, false == hidden */);
checkVisiblePackageUserOverNonVisible(false /* multiUser*/, PackageRemovalType.HIDE);
checkVisiblePackageUserOverNonVisible(true /* multiUser*/, PackageRemovalType.HIDE);
}
@Test
public void testInstalledPackageUsedOverUninstalled() {
checkVisiblePackageUserOverNonVisible(true /* true == uninstalled, false == hidden */);
checkVisiblePackageUserOverNonVisible(false /* multiUser*/, PackageRemovalType.UNINSTALL);
checkVisiblePackageUserOverNonVisible(true /* multiUser*/, PackageRemovalType.UNINSTALL);
}
private void checkVisiblePackageUserOverNonVisible(boolean uninstalledNotHidden) {
boolean testUninstalled = uninstalledNotHidden;
boolean testHidden = !uninstalledNotHidden;
private void checkVisiblePackageUserOverNonVisible(boolean multiUser,
PackageRemovalType removalType) {
assert removalType != PackageRemovalType.DISABLE;
boolean testUninstalled = removalType == PackageRemovalType.UNINSTALL;
boolean testHidden = removalType == PackageRemovalType.HIDE;
String installedPackage = "installedPackage";
String uninstalledPackage = "uninstalledPackage";
WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
@@ -1137,11 +1246,25 @@ public class WebViewUpdateServiceTest {
false /* fallback */, null)};
setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
true /* valid */, true /* installed */));
mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
int secondaryUserId = 5;
if (multiUser) {
mTestSystemImpl.addUser(secondaryUserId);
// Install all packages for the primary user.
setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, webviewPackages);
mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(
installedPackage, true /* enabled */, true /* valid */, true /* installed */));
// Hide or uninstall the primary package for the second user
mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
true /* valid */, (testUninstalled ? false : true) /* installed */,
null /* signatures */, 0 /* updateTime */, (testHidden ? true : false)));
} else {
mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
true /* valid */, true /* installed */));
// Hide or uninstall the primary package
mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
true /* valid */, (testUninstalled ? false : true) /* installed */,
null /* signatures */, 0 /* updateTime */, (testHidden ? true : false)));
}
runWebViewBootPreparationOnMainSync();
@@ -1160,9 +1283,7 @@ public class WebViewUpdateServiceTest {
}
/**
* Ensure that we won't prioritize an uninstalled (or hidden) package even if it is user-chosen,
* and that an uninstalled (or hidden) package is not considered valid (in the
* getValidWebViewPackages() API).
* Ensure that we won't prioritize an uninstalled (or hidden) package even if it is user-chosen.
*/
private void checkCantSwitchToNonVisiblePackage(boolean uninstalledNotHidden) {
boolean testUninstalled = uninstalledNotHidden;
@@ -1176,27 +1297,31 @@ public class WebViewUpdateServiceTest {
false /* fallback */, null)};
setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
true /* valid */, true /* installed */));
mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
true /* valid */, (testUninstalled ? false : true) /* installed */,
null /* signatures */, 0 /* updateTime */,
(testHidden ? true : false) /* hidden */));
int secondaryUserId = 412;
mTestSystemImpl.addUser(secondaryUserId);
// Let all packages be installed and enabled for the primary user.
setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, webviewPackages);
// Only uninstall the 'uninstalled package' for the secondary user.
mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(installedPackage,
true /* enabled */, true /* valid */, true /* installed */));
mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(uninstalledPackage,
true /* enabled */, true /* valid */, !testUninstalled /* installed */,
null /* signatures */, 0 /* updateTime */, testHidden /* hidden */));
runWebViewBootPreparationOnMainSync();
checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
// Ensure that only the installed package is considered valid
WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
assertEquals(1, validPackages.length);
assertEquals(installedPackage, validPackages[0].packageName);
// ensure that we don't switch to the uninstalled package (it will be used if it becomes
// installed later)
assertEquals(installedPackage,
mWebViewUpdateServiceImpl.changeProviderAndSetting(uninstalledPackage));
// Ensure both packages are considered valid.
assertEquals(2, mWebViewUpdateServiceImpl.getValidWebViewPackages().length);
// We should only have called onWebViewProviderChanged once (before calling
// changeProviderAndSetting
Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged(
@@ -1227,12 +1352,16 @@ public class WebViewUpdateServiceTest {
false /* fallback */, null)};
setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
true /* valid */, true /* installed */));
mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
true /* valid */, (testUninstalled ? false : true) /* installed */,
null /* signatures */, 0 /* updateTime */,
(testHidden ? true : false) /* hidden */));
int secondaryUserId = 4;
mTestSystemImpl.addUser(secondaryUserId);
setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, webviewPackages);
mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(installedPackage,
true /* enabled */, true /* valid */, true /* installed */));
mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(uninstalledPackage,
true /* enabled */, true /* valid */,
(testUninstalled ? false : true) /* installed */, null /* signatures */,
0 /* updateTime */, (testHidden ? true : false) /* hidden */));
// Start with the setting pointing to the uninstalled package
mTestSystemImpl.updateUserSetting(null, uninstalledPackage);
@@ -1242,12 +1371,21 @@ public class WebViewUpdateServiceTest {
checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
}
@Test
public void testFallbackEnabledIfPrimaryUninstalledSingleUser() {
checkFallbackEnabledIfPrimaryUninstalled(false /* multiUser */);
}
@Test
public void testFallbackEnabledIfPrimaryUninstalledMultiUser() {
checkFallbackEnabledIfPrimaryUninstalled(true /* multiUser */);
}
/**
* Ensures that fallback becomes enabled if the primary package is uninstalled for the current
* Ensures that fallback becomes enabled at boot if the primary package is uninstalled for some
* user.
*/
@Test
public void testFallbackEnabledIfPrimaryUninstalled() {
private void checkFallbackEnabledIfPrimaryUninstalled(boolean multiUser) {
String primaryPackage = "primary";
String fallbackPackage = "fallback";
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
@@ -1256,10 +1394,24 @@ public class WebViewUpdateServiceTest {
new WebViewProviderInfo(
fallbackPackage, "", true /* default available */, true /* fallback */, null)};
setupWithPackages(packages, true /* fallback logic enabled */);
mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
int secondaryUserId = 5;
if (multiUser) {
mTestSystemImpl.addUser(secondaryUserId);
// Install all packages for the primary user.
setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, packages);
// Only install fallback package for secondary user.
mTestSystemImpl.setPackageInfoForUser(secondaryUserId,
createPackageInfo(primaryPackage, true /* enabled */,
true /* valid */, false /* installed */));
mTestSystemImpl.setPackageInfoForUser(secondaryUserId,
createPackageInfo(fallbackPackage, false /* enabled */,
true /* valid */, true /* installed */));
} else {
mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
true /* valid */, false /* installed */));
mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, false /* enabled */,
true /* valid */, true /* installed */));
}
runWebViewBootPreparationOnMainSync();
// Verify that we enable the fallback package