WebViewProviderInfo[] getValidWebViewPackages();
/**
+ * Fetch all packages that could potentially implement WebView.
+ */
+ WebViewProviderInfo[] getAllWebViewPackages();
+
+ /**
* Used by DevelopmentSetting to get the name of the WebView provider currently in use.
*/
String getCurrentWebViewPackageName();
public MissingWebViewPackageException(Exception e) { super(e); }
}
- private static String TAG_START = "webviewproviders";
- private static String TAG_WEBVIEW_PROVIDER = "webviewprovider";
- private static String TAG_PACKAGE_NAME = "packageName";
- private static String TAG_DESCRIPTION = "description";
- // Whether or not the provider must be explicitly chosen by the user to be used.
- private static String TAG_AVAILABILITY = "availableByDefault";
- private static String TAG_SIGNATURE = "signature";
- private static String TAG_FALLBACK = "isFallback";
-
- /**
- * Reads all signatures at the current depth (within the current provider) from the XML parser.
- */
- private static String[] readSignatures(XmlResourceParser parser) throws IOException,
- XmlPullParserException {
- List<String> signatures = new ArrayList<String>();
- int outerDepth = parser.getDepth();
- while(XmlUtils.nextElementWithin(parser, outerDepth)) {
- if (parser.getName().equals(TAG_SIGNATURE)) {
- // Parse the value within the signature tag
- String signature = parser.nextText();
- signatures.add(signature);
- } else {
- Log.e(LOGTAG, "Found an element in a webview provider that is not a signature");
- }
- }
- return signatures.toArray(new String[signatures.size()]);
- }
-
- /**
- * Returns all packages declared in the framework resources as potential WebView providers.
- * @hide
- * */
- public static WebViewProviderInfo[] getWebViewPackages() {
- int numFallbackPackages = 0;
- XmlResourceParser parser = null;
- List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
- try {
- parser = AppGlobals.getInitialApplication().getResources().getXml(
- com.android.internal.R.xml.config_webview_packages);
- XmlUtils.beginDocument(parser, TAG_START);
- while(true) {
- XmlUtils.nextElement(parser);
- String element = parser.getName();
- if (element == null) {
- break;
- }
- if (element.equals(TAG_WEBVIEW_PROVIDER)) {
- String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME);
- if (packageName == null) {
- throw new MissingWebViewPackageException(
- "WebView provider in framework resources missing package name");
- }
- String description = parser.getAttributeValue(null, TAG_DESCRIPTION);
- if (description == null) {
- throw new MissingWebViewPackageException(
- "WebView provider in framework resources missing description");
- }
- boolean availableByDefault = "true".equals(
- parser.getAttributeValue(null, TAG_AVAILABILITY));
- boolean isFallback = "true".equals(
- parser.getAttributeValue(null, TAG_FALLBACK));
- WebViewProviderInfo currentProvider =
- new WebViewProviderInfo(packageName, description, availableByDefault,
- isFallback, readSignatures(parser));
- if (currentProvider.isFallbackPackage()) {
- numFallbackPackages++;
- if (numFallbackPackages > 1) {
- throw new AndroidRuntimeException(
- "There can be at most one webview fallback package.");
- }
- }
- webViewProviders.add(currentProvider);
- }
- else {
- Log.e(LOGTAG, "Found an element that is not a webview provider");
- }
- }
- } catch(XmlPullParserException e) {
- throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
- } catch(IOException e) {
- throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
- } finally {
- if (parser != null) parser.close();
- }
- return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
- }
-
-
// TODO (gsennton) remove when committing webview xts test change
public static String getWebViewPackageName() {
- WebViewProviderInfo[] providers = getWebViewPackages();
- return providers[0].packageName;
+ return null;
}
/**
private WebViewProviderInfo(Parcel in) {
packageName = in.readString();
description = in.readString();
+ availableByDefault = (in.readInt() > 0);
+ isFallback = (in.readInt() > 0);
signatures = in.createStringArray();
packageInfo = null;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(packageName);
out.writeString(description);
+ out.writeInt(availableByDefault ? 1 : 0);
+ out.writeInt(isFallback ? 1 : 0);
out.writeStringArray(signatures);
}
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.UserManager;
-import android.provider.Settings;
import android.provider.Settings.Global;
+import android.provider.Settings;
import android.util.AndroidRuntimeException;
import android.util.Slog;
import android.webkit.IWebViewUpdateService;
+import android.webkit.WebViewFactory;
import android.webkit.WebViewProviderInfo;
import android.webkit.WebViewProviderResponse;
-import android.webkit.WebViewFactory;
import com.android.server.SystemService;
private WebViewProviderInfo[] mCurrentValidWebViewPackages = null;
private BroadcastReceiver mWebViewUpdatedReceiver;
+ private WebViewUtilityInterface mWebViewUtility;
public WebViewUpdateService(Context context) {
super(context);
+ mWebViewUtility = new WebViewUtilityImpl();
}
@Override
updateFallbackState(context, intent);
- for (WebViewProviderInfo provider : WebViewFactory.getWebViewPackages()) {
+ for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
String webviewPackage = "package:" + provider.packageName;
if (webviewPackage.equals(intent.getDataString())) {
// 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.
- try {
- ActivityManagerNative.getDefault().killPackageDependents(
- oldProviderName, UserHandle.USER_ALL);
- } catch (RemoteException e) {
- }
+ mWebViewUtility.killPackageDependents(oldProviderName);
}
return;
}
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 : WebViewFactory.getWebViewPackages()) {
+ for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
}
getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
void handleNewUser(int userId) {
if (!isFallbackLogicEnabled()) return;
- WebViewProviderInfo[] webviewProviders = WebViewFactory.getWebViewPackages();
+ WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
if (fallbackProvider == null) return;
boolean existsValidNonFallbackProvider =
void updateFallbackState(final Context context, final Intent intent) {
if (!isFallbackLogicEnabled()) return;
- WebViewProviderInfo[] webviewProviders = WebViewFactory.getWebViewPackages();
+ WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
|| intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) {
return false;
}
- private static boolean isFallbackPackage(String packageName) {
+ private boolean isFallbackPackage(String packageName) {
if (packageName == null || !isFallbackLogicEnabled()) return false;
- WebViewProviderInfo[] webviewPackages = WebViewFactory.getWebViewPackages();
+ WebViewProviderInfo[] webviewPackages = mWebViewUtility.getWebViewPackages();
WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
return (fallbackProvider != null
&& packageName.equals(fallbackProvider.packageName));
PackageInfo newPackage = null;
synchronized(this) {
oldPackage = mCurrentWebViewPackage;
- updateUserSetting(newProviderName);
+ mWebViewUtility.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.
- updateUserSetting(newPackage.packageName);
+ mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
return newPackage.packageName;
}
} catch (WebViewFactory.MissingWebViewPackageException e) {
onWebViewProviderChanged(newPackage);
}
// Kill apps using the old provider
- try {
- if (oldPackage != null) {
- ActivityManagerNative.getDefault().killPackageDependents(
- oldPackage.packageName, UserHandle.USER_ALL);
- }
- } catch (RemoteException e) {
+ if (oldPackage != null) {
+ mWebViewUtility.killPackageDependents(oldPackage.packageName);
}
return newPackage.packageName;
}
mCurrentProviderBeingReplaced = false;
if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
mCurrentWebViewPackage = newPackage;
- updateUserSetting(newPackage.packageName);
+ mWebViewUtility.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 = WebViewFactory.onWebViewProviderChanged(newPackage);
+ mNumRelroCreationsStarted = mWebViewUtility.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();
* */
private void updateValidWebViewPackages() {
List<WebViewProviderInfo> webViewProviders =
- new ArrayList<WebViewProviderInfo>(Arrays.asList(WebViewFactory.getWebViewPackages()));
+ new ArrayList<WebViewProviderInfo>(Arrays.asList(mWebViewUtility.getWebViewPackages()));
Iterator<WebViewProviderInfo> it = webViewProviders.iterator();
// remove non-valid packages
while(it.hasNext()) {
}
}
- private static String getUserChosenWebViewProvider() {
- return Settings.Global.getString(AppGlobals.getInitialApplication().getContentResolver(),
- Settings.Global.WEBVIEW_PROVIDER);
- }
-
- private void updateUserSetting(String newProviderName) {
- Settings.Global.putString(getContext().getContentResolver(),
- Settings.Global.WEBVIEW_PROVIDER,
- newProviderName == null ? "" : newProviderName);
- }
-
/**
* Returns either the package info of the WebView provider determined in the following way:
* If the user has chosen a provider then use that if it is valid,
private PackageInfo findPreferredWebViewPackage() {
WebViewProviderInfo[] providers = mCurrentValidWebViewPackages;
- String userChosenProvider = getUserChosenWebViewProvider();
+ String userChosenProvider = mWebViewUtility.getUserChosenWebViewProvider(getContext());
// If the user has chosen provider, use that
for (WebViewProviderInfo provider : providers) {
}
@Override // Binder call
+ public WebViewProviderInfo[] getAllWebViewPackages() {
+ return WebViewUpdateService.this.mWebViewUtility.getWebViewPackages();
+ }
+
+ @Override // Binder call
public String getCurrentWebViewPackageName() {
synchronized(WebViewUpdateService.this) {
if (WebViewUpdateService.this.mCurrentWebViewPackage == null)
@Override // Binder call
public boolean isFallbackPackage(String packageName) {
- return WebViewUpdateService.isFallbackPackage(packageName);
+ return WebViewUpdateService.this.isFallbackPackage(packageName);
}
@Override // Binder call
--- /dev/null
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.webkit;
+
+import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.res.XmlResourceParser;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.AndroidRuntimeException;
+import android.util.Log;
+import android.webkit.WebViewFactory;
+import android.webkit.WebViewFactory.MissingWebViewPackageException;
+import android.webkit.WebViewProviderInfo;
+
+import com.android.internal.util.XmlUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+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();
+ private static final String TAG_START = "webviewproviders";
+ private static final String TAG_WEBVIEW_PROVIDER = "webviewprovider";
+ private static final String TAG_PACKAGE_NAME = "packageName";
+ private static final String TAG_DESCRIPTION = "description";
+ // Whether or not the provider must be explicitly chosen by the user to be used.
+ private static final String TAG_AVAILABILITY = "availableByDefault";
+ private static final String TAG_SIGNATURE = "signature";
+ private static final String TAG_FALLBACK = "isFallback";
+
+ /**
+ * Returns all packages declared in the framework resources as potential WebView providers.
+ * @hide
+ * */
+ @Override
+ public WebViewProviderInfo[] getWebViewPackages() {
+ int numFallbackPackages = 0;
+ XmlResourceParser parser = null;
+ List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
+ try {
+ parser = AppGlobals.getInitialApplication().getResources().getXml(
+ com.android.internal.R.xml.config_webview_packages);
+ XmlUtils.beginDocument(parser, TAG_START);
+ while(true) {
+ XmlUtils.nextElement(parser);
+ String element = parser.getName();
+ if (element == null) {
+ break;
+ }
+ if (element.equals(TAG_WEBVIEW_PROVIDER)) {
+ String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME);
+ if (packageName == null) {
+ throw new MissingWebViewPackageException(
+ "WebView provider in framework resources missing package name");
+ }
+ String description = parser.getAttributeValue(null, TAG_DESCRIPTION);
+ if (description == null) {
+ throw new MissingWebViewPackageException(
+ "WebView provider in framework resources missing description");
+ }
+ boolean availableByDefault = "true".equals(
+ parser.getAttributeValue(null, TAG_AVAILABILITY));
+ boolean isFallback = "true".equals(
+ parser.getAttributeValue(null, TAG_FALLBACK));
+ WebViewProviderInfo currentProvider =
+ new WebViewProviderInfo(packageName, description, availableByDefault,
+ isFallback, readSignatures(parser));
+ if (currentProvider.isFallbackPackage()) {
+ numFallbackPackages++;
+ if (numFallbackPackages > 1) {
+ throw new AndroidRuntimeException(
+ "There can be at most one webview fallback package.");
+ }
+ }
+ webViewProviders.add(currentProvider);
+ }
+ else {
+ Log.e(TAG, "Found an element that is not a webview provider");
+ }
+ }
+ } catch(XmlPullParserException e) {
+ throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
+ } catch(IOException e) {
+ throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
+ } finally {
+ if (parser != null) parser.close();
+ }
+ return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+ }
+
+ /**
+ * Reads all signatures at the current depth (within the current provider) from the XML parser.
+ */
+ private static String[] readSignatures(XmlResourceParser parser) throws IOException,
+ XmlPullParserException {
+ List<String> signatures = new ArrayList<String>();
+ int outerDepth = parser.getDepth();
+ while(XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (parser.getName().equals(TAG_SIGNATURE)) {
+ // Parse the value within the signature tag
+ String signature = parser.nextText();
+ signatures.add(signature);
+ } else {
+ Log.e(TAG, "Found an element in a webview provider that is not a signature");
+ }
+ }
+ return signatures.toArray(new String[signatures.size()]);
+ }
+
+ @Override
+ public int onWebViewProviderChanged(PackageInfo packageInfo) {
+ return WebViewFactory.onWebViewProviderChanged(packageInfo);
+ }
+
+ @Override
+ public String getUserChosenWebViewProvider(Context context) {
+ return Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.WEBVIEW_PROVIDER);
+ }
+
+ @Override
+ public void updateUserSetting(Context context, String newProviderName) {
+ Settings.Global.putString(context.getContentResolver(),
+ Settings.Global.WEBVIEW_PROVIDER,
+ newProviderName == null ? "" : newProviderName);
+ }
+
+ @Override
+ public void killPackageDependents(String packageName) {
+ try {
+ ActivityManagerNative.getDefault().killPackageDependents(packageName,
+ UserHandle.USER_ALL);
+ } catch (RemoteException e) {
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.webkit;
+
+import android.webkit.WebViewProviderInfo;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+
+/**
+ * Utility 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 WebViewProviderInfo[] getWebViewPackages();
+ public int onWebViewProviderChanged(PackageInfo packageInfo);
+
+ public String getUserChosenWebViewProvider(Context context);
+ public void updateUserSetting(Context context, String newProviderName);
+ public void killPackageDependents(String packageName);
+}