Merge "Move more code from WebViewUpdateService to separate overridable class" into nyc-dev

This commit is contained in:
Gustav Sennton
2016-04-04 20:19:55 +00:00
committed by Android (Google) Code Review
4 changed files with 135 additions and 111 deletions

View File

@@ -21,7 +21,6 @@ import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -561,18 +560,6 @@ public final class WebViewFactory {
return result;
}
/**
* Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather
* than just one of its components).
* @hide
*/
public static boolean entirePackageChanged(Intent intent) {
String[] componentList =
intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
return Arrays.asList(componentList).contains(
intent.getDataString().substring("package:".length()));
}
private static String WEBVIEW_UPDATE_SERVICE_NAME = "webviewupdate";
/** @hide */

View File

@@ -19,15 +19,22 @@ package com.android.server.webkit;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.content.Context;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.content.res.XmlResourceParser;
import android.os.Build;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings.Global;
import android.provider.Settings;
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.webkit.WebViewFactory;
import android.webkit.WebViewFactory.MissingWebViewPackageException;
import android.webkit.WebViewFactory;
import android.webkit.WebViewProviderInfo;
import com.android.internal.util.XmlUtils;
@@ -42,8 +49,8 @@ import org.xmlpull.v1.XmlPullParserException;
* Default implementation for the WebView preparation Utility interface.
* @hide
*/
public class WebViewUtilityImpl implements WebViewUtilityInterface {
private static final String TAG = WebViewUtilityImpl.class.getSimpleName();
public class SystemImpl implements SystemInterface {
private static final String TAG = SystemImpl.class.getSimpleName();
private static final String TAG_START = "webviewproviders";
private static final String TAG_WEBVIEW_PROVIDER = "webviewprovider";
private static final String TAG_PACKAGE_NAME = "packageName";
@@ -158,4 +165,67 @@ public class WebViewUtilityImpl implements WebViewUtilityInterface {
} catch (RemoteException e) {
}
}
@Override
public boolean isFallbackLogicEnabled() {
// Note that this is enabled by default (i.e. if the setting hasn't been set).
return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
}
@Override
public void enableFallbackLogic(boolean enable) {
Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
}
@Override
public void uninstallAndDisablePackageForAllUsers(Context context, String packageName) {
context.getPackageManager().deletePackage(packageName,
new IPackageDeleteObserver.Stub() {
public void packageDeleted(String packageName, int returnCode) {
// Ignore returnCode since the deletion could fail, e.g. we might be trying
// to delete a non-updated system-package (and we should still disable the
// package)
enablePackageForAllUsers(context, packageName, false);
}
}, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
}
@Override
public void enablePackageForAllUsers(Context context, String packageName, boolean enable) {
UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE);
for(UserInfo userInfo : userManager.getUsers()) {
enablePackageForUser(packageName, enable, userInfo.id);
}
}
@Override
public void enablePackageForUser(String packageName, boolean enable, int userId) {
try {
AppGlobals.getPackageManager().setApplicationEnabledSetting(
packageName,
enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
userId, null);
} catch (RemoteException e) {
Log.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
}
}
@Override
public boolean systemIsDebuggable() {
return Build.IS_DEBUGGABLE;
}
@Override
public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
throws NameNotFoundException {
PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
return pm.getPackageInfo(configInfo.packageName, PACKAGE_FLAGS);
}
// flags declaring we want extra info from the package manager for webview providers
private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
| PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
}

View File

@@ -16,22 +16,35 @@
package com.android.server.webkit;
import android.webkit.WebViewProviderInfo;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.webkit.WebViewProviderInfo;
/**
* Utility interface for the WebViewUpdateService.
* System interface for the WebViewUpdateService.
* This interface provides a way to test the WebView preparation mechanism - during normal use this
* interface is implemented using calls to the Android framework, but by providing an alternative
* implementation we can test the WebView preparation logic without reaching other framework code.
*
* @hide
*/
public interface WebViewUtilityInterface {
public interface SystemInterface {
public WebViewProviderInfo[] getWebViewPackages();
public int onWebViewProviderChanged(PackageInfo packageInfo);
public String getUserChosenWebViewProvider(Context context);
public void updateUserSetting(Context context, String newProviderName);
public void killPackageDependents(String packageName);
public boolean isFallbackLogicEnabled();
public void enableFallbackLogic(boolean enable);
public void uninstallAndDisablePackageForAllUsers(Context context, String packageName);
public void enablePackageForAllUsers(Context context, String packageName, boolean enable);
public void enablePackageForUser(String packageName, boolean enable, int userId);
public boolean systemIsDebuggable();
public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
throws NameNotFoundException;
}

View File

@@ -16,30 +16,19 @@
package com.android.server.webkit;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Build;
import android.os.PatternMatcher;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings.Global;
import android.provider.Settings;
import android.util.AndroidRuntimeException;
import android.util.Base64;
import android.util.Slog;
import android.webkit.IWebViewUpdateService;
@@ -52,7 +41,6 @@ import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
@@ -77,11 +65,11 @@ public class WebViewUpdateService extends SystemService {
private PackageInfo mCurrentWebViewPackage = null;
private BroadcastReceiver mWebViewUpdatedReceiver;
private WebViewUtilityInterface mWebViewUtility;
private SystemInterface mSystemInterface;
public WebViewUpdateService(Context context) {
super(context);
mWebViewUtility = new WebViewUtilityImpl();
mSystemInterface = new SystemImpl();
}
@Override
@@ -103,7 +91,7 @@ public class WebViewUpdateService extends SystemService {
// Ensure that we only heed PACKAGE_CHANGED intents if they change an entire
// package, not just a component
if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) {
if (!WebViewFactory.entirePackageChanged(intent)) {
if (!entirePackageChanged(intent)) {
return;
}
}
@@ -117,7 +105,7 @@ public class WebViewUpdateService extends SystemService {
updateFallbackState(context, intent);
for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
String webviewPackage = "package:" + provider.packageName;
if (webviewPackage.equals(intent.getDataString())) {
@@ -155,7 +143,7 @@ public class WebViewUpdateService extends SystemService {
// package that was not the previous provider then we must kill
// packages dependent on the old package ourselves. The framework
// only kills dependents of packages that are being removed.
mWebViewUtility.killPackageDependents(oldProviderName);
mSystemInterface.killPackageDependents(oldProviderName);
}
return;
}
@@ -168,7 +156,7 @@ public class WebViewUpdateService extends SystemService {
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
// Make sure we only receive intents for WebView packages from our config file.
for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
}
getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
@@ -184,7 +172,7 @@ public class WebViewUpdateService extends SystemService {
for (WebViewProviderInfo provider : providers) {
if (provider.availableByDefault && !provider.isFallback) {
try {
PackageInfo packageInfo = getPackageInfoForProvider(provider);
PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(provider);
if (isEnabledPackage(packageInfo) && isValidProvider(provider, packageInfo)) {
return true;
}
@@ -196,29 +184,17 @@ public class WebViewUpdateService extends SystemService {
return false;
}
private static void enablePackageForUser(String packageName, boolean enable, int userId) {
try {
AppGlobals.getPackageManager().setApplicationEnabledSetting(
packageName,
enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
userId, null);
} catch (RemoteException e) {
Slog.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
}
}
/**
* Called when a new user has been added to update the state of its fallback package.
*/
void handleNewUser(int userId) {
if (!isFallbackLogicEnabled()) return;
if (!mSystemInterface.isFallbackLogicEnabled()) return;
WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
if (fallbackProvider == null) return;
enablePackageForUser(fallbackProvider.packageName,
mSystemInterface.enablePackageForUser(fallbackProvider.packageName,
!existsValidNonFallbackProvider(webviewProviders), userId);
}
@@ -228,9 +204,9 @@ public class WebViewUpdateService extends SystemService {
* otherwise, enable the fallback package.
*/
void updateFallbackState(final Context context, final Intent intent) {
if (!isFallbackLogicEnabled()) return;
if (!mSystemInterface.isFallbackLogicEnabled()) return;
WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
|| intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) {
@@ -257,7 +233,8 @@ public class WebViewUpdateService extends SystemService {
boolean isFallbackEnabled = false;
try {
isFallbackEnabled = isEnabledPackage(getPackageInfoForProvider(fallbackProvider));
isFallbackEnabled =
isEnabledPackage(mSystemInterface.getPackageInfoForProvider(fallbackProvider));
} catch (NameNotFoundException e) {
}
@@ -265,45 +242,17 @@ public class WebViewUpdateService extends SystemService {
// During an OTA the primary user's WebView state might differ from other users', so
// ignore the state of that user during boot.
&& (isFallbackEnabled || intent == null)) {
// Uninstall and disable fallback package for all users.
context.getPackageManager().deletePackage(fallbackProvider.packageName,
new IPackageDeleteObserver.Stub() {
public void packageDeleted(String packageName, int returnCode) {
// Ignore returnCode since the deletion could fail, e.g. we might be trying
// to delete a non-updated system-package (and we should still disable the
// package)
UserManager userManager =
(UserManager)context.getSystemService(Context.USER_SERVICE);
// Disable the fallback package for all users.
for(UserInfo userInfo : userManager.getUsers()) {
enablePackageForUser(packageName, false, userInfo.id);
}
}
}, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
mSystemInterface.uninstallAndDisablePackageForAllUsers(context,
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 || intent==null)) {
// Enable the fallback package for all users.
UserManager userManager =
(UserManager)context.getSystemService(Context.USER_SERVICE);
for(UserInfo userInfo : userManager.getUsers()) {
enablePackageForUser(fallbackProvider.packageName, true, userInfo.id);
}
mSystemInterface.enablePackageForAllUsers(context, fallbackProvider.packageName, true);
}
}
private static boolean isFallbackLogicEnabled() {
// Note that this is enabled by default (i.e. if the setting hasn't been set).
return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
}
private static void enableFallbackLogic(boolean enable) {
Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
}
/**
* Returns the only fallback provider, or null if there is none.
*/
@@ -317,9 +266,9 @@ public class WebViewUpdateService extends SystemService {
}
private boolean isFallbackPackage(String packageName) {
if (packageName == null || !isFallbackLogicEnabled()) return false;
if (packageName == null || !mSystemInterface.isFallbackLogicEnabled()) return false;
WebViewProviderInfo[] webviewPackages = mWebViewUtility.getWebViewPackages();
WebViewProviderInfo[] webviewPackages = mSystemInterface.getWebViewPackages();
WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
return (fallbackProvider != null
&& packageName.equals(fallbackProvider.packageName));
@@ -355,13 +304,13 @@ public class WebViewUpdateService extends SystemService {
PackageInfo newPackage = null;
synchronized(this) {
oldPackage = mCurrentWebViewPackage;
mWebViewUtility.updateUserSetting(getContext(), newProviderName);
mSystemInterface.updateUserSetting(getContext(), newProviderName);
try {
newPackage = findPreferredWebViewPackage();
if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) {
// If we don't perform the user change, revert the settings change.
mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
mSystemInterface.updateUserSetting(getContext(), newPackage.packageName);
return newPackage.packageName;
}
} catch (WebViewFactory.MissingWebViewPackageException e) {
@@ -375,7 +324,7 @@ public class WebViewUpdateService extends SystemService {
}
// Kill apps using the old provider
if (oldPackage != null) {
mWebViewUtility.killPackageDependents(oldPackage.packageName);
mSystemInterface.killPackageDependents(oldPackage.packageName);
}
return newPackage.packageName;
}
@@ -389,14 +338,14 @@ public class WebViewUpdateService extends SystemService {
mAnyWebViewInstalled = true;
if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
mCurrentWebViewPackage = newPackage;
mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
mSystemInterface.updateUserSetting(getContext(), newPackage.packageName);
// The relro creations might 'finish' (not start at all) before
// WebViewFactory.onWebViewProviderChanged which means we might not know the number
// of started creations before they finish.
mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN;
mNumRelroCreationsFinished = 0;
mNumRelroCreationsStarted = mWebViewUtility.onWebViewProviderChanged(newPackage);
mNumRelroCreationsStarted = mSystemInterface.onWebViewProviderChanged(newPackage);
// If the relro creations finish before we know the number of started creations we
// will have to do any cleanup/notifying here.
checkIfRelrosDoneLocked();
@@ -407,11 +356,12 @@ public class WebViewUpdateService extends SystemService {
}
private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos() {
WebViewProviderInfo[] allProviders = mWebViewUtility.getWebViewPackages();
WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages();
List<ProviderAndPackageInfo> providers = new ArrayList<>();
for(int n = 0; n < allProviders.length; n++) {
try {
PackageInfo packageInfo = getPackageInfoForProvider(allProviders[n]);
PackageInfo packageInfo =
mSystemInterface.getPackageInfoForProvider(allProviders[n]);
if (isValidProvider(allProviders[n], packageInfo)) {
providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
}
@@ -454,7 +404,7 @@ public class WebViewUpdateService extends SystemService {
private PackageInfo findPreferredWebViewPackage() {
ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos();
String userChosenProvider = mWebViewUtility.getUserChosenWebViewProvider(getContext());
String userChosenProvider = mSystemInterface.getUserChosenWebViewProvider(getContext());
// If the user has chosen provider, use that
for (ProviderAndPackageInfo providerAndPackage : providers) {
@@ -483,10 +433,11 @@ public class WebViewUpdateService extends SystemService {
"Could not find a loadable WebView package");
}
/**
* Returns whether this provider is valid for use as a WebView provider.
*/
private static boolean isValidProvider(WebViewProviderInfo configInfo,
public boolean isValidProvider(WebViewProviderInfo configInfo,
PackageInfo packageInfo) {
if (providerHasValidSignature(configInfo, packageInfo) &&
WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) != null) {
@@ -495,10 +446,11 @@ public class WebViewUpdateService extends SystemService {
return false;
}
private static boolean providerHasValidSignature(WebViewProviderInfo provider,
private boolean providerHasValidSignature(WebViewProviderInfo provider,
PackageInfo packageInfo) {
if (Build.IS_DEBUGGABLE)
if (mSystemInterface.systemIsDebuggable()) {
return true;
}
Signature[] packageSignatures;
// If no signature is declared, instead check whether the package is included in the
// system.
@@ -523,20 +475,22 @@ public class WebViewUpdateService extends SystemService {
* Returns whether the given package is enabled.
* This state can be changed by the user from Settings->Apps
*/
private static boolean isEnabledPackage(PackageInfo packageInfo) {
public boolean isEnabledPackage(PackageInfo packageInfo) {
return packageInfo.applicationInfo.enabled;
}
private static PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
throws NameNotFoundException {
PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
return pm.getPackageInfo(configInfo.packageName, PACKAGE_FLAGS);
/**
* Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather
* than just one of its components).
* @hide
*/
public static boolean entirePackageChanged(Intent intent) {
String[] componentList =
intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
return Arrays.asList(componentList).contains(
intent.getDataString().substring("package:".length()));
}
// flags declaring we want extra info from the package manager for webview providers
private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
| PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
/**
* Returns whether WebView is ready and is not going to go through its preparation phase again
* directly.
@@ -669,7 +623,7 @@ public class WebViewUpdateService extends SystemService {
@Override // Binder call
public WebViewProviderInfo[] getAllWebViewPackages() {
return WebViewUpdateService.this.mWebViewUtility.getWebViewPackages();
return WebViewUpdateService.this.mSystemInterface.getWebViewPackages();
}
@Override // Binder call
@@ -699,7 +653,7 @@ public class WebViewUpdateService extends SystemService {
throw new SecurityException(msg);
}
WebViewUpdateService.enableFallbackLogic(enable);
WebViewUpdateService.this.mSystemInterface.enableFallbackLogic(enable);
}
}
}