Merge "Change WebView fallback mechanism to consider all users' package states."
This commit is contained in:
committed by
Android (Google) Code Review
commit
eeb4e1d219
94
core/java/android/webkit/UserPackage.java
Normal file
94
core/java/android/webkit/UserPackage.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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(),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user