diff options
6 files changed, 233 insertions, 127 deletions
diff --git a/core/java/android/webkit/IWebViewUpdateService.aidl b/core/java/android/webkit/IWebViewUpdateService.aidl index 5697dfc0188c..9434f0ccac4e 100644 --- a/core/java/android/webkit/IWebViewUpdateService.aidl +++ b/core/java/android/webkit/IWebViewUpdateService.aidl @@ -54,6 +54,11 @@ interface IWebViewUpdateService { 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(); diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index c280b81f73a3..f1bf890b3c86 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -128,98 +128,9 @@ public final class WebViewFactory { 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; } /** diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java index 64c2caa58fd5..75ccf355ecd7 100644 --- a/core/java/android/webkit/WebViewProviderInfo.java +++ b/core/java/android/webkit/WebViewProviderInfo.java @@ -150,6 +150,8 @@ public class WebViewProviderInfo implements Parcelable { private WebViewProviderInfo(Parcel in) { packageName = in.readString(); description = in.readString(); + availableByDefault = (in.readInt() > 0); + isFallback = (in.readInt() > 0); signatures = in.createStringArray(); packageInfo = null; } @@ -163,6 +165,8 @@ public class WebViewProviderInfo implements Parcelable { 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); } diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java index a4bbb515154f..50699f8ccf4a 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java @@ -35,14 +35,14 @@ import android.os.RemoteException; 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; @@ -76,9 +76,11 @@ public class WebViewUpdateService extends SystemService { private WebViewProviderInfo[] mCurrentValidWebViewPackages = null; private BroadcastReceiver mWebViewUpdatedReceiver; + private WebViewUtilityInterface mWebViewUtility; public WebViewUpdateService(Context context) { super(context); + mWebViewUtility = new WebViewUtilityImpl(); } @Override @@ -114,7 +116,7 @@ public class WebViewUpdateService extends SystemService { updateFallbackState(context, intent); - for (WebViewProviderInfo provider : WebViewFactory.getWebViewPackages()) { + for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) { String webviewPackage = "package:" + provider.packageName; if (webviewPackage.equals(intent.getDataString())) { @@ -153,11 +155,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. - try { - ActivityManagerNative.getDefault().killPackageDependents( - oldProviderName, UserHandle.USER_ALL); - } catch (RemoteException e) { - } + mWebViewUtility.killPackageDependents(oldProviderName); } return; } @@ -170,7 +168,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 : WebViewFactory.getWebViewPackages()) { + for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) { filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL); } getContext().registerReceiver(mWebViewUpdatedReceiver, filter); @@ -210,7 +208,7 @@ public class WebViewUpdateService extends SystemService { 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 = @@ -228,7 +226,7 @@ public class WebViewUpdateService extends SystemService { 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))) { @@ -319,10 +317,10 @@ public class WebViewUpdateService extends SystemService { 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)); @@ -359,13 +357,13 @@ public class WebViewUpdateService extends SystemService { 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) { @@ -378,12 +376,8 @@ public class WebViewUpdateService extends SystemService { 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; } @@ -397,14 +391,14 @@ public class WebViewUpdateService extends SystemService { mAnyWebViewInstalled = true; 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(); @@ -421,7 +415,7 @@ public class WebViewUpdateService extends SystemService { * */ 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()) { @@ -435,17 +429,6 @@ public class WebViewUpdateService extends SystemService { } } - 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, @@ -456,7 +439,7 @@ public class WebViewUpdateService extends SystemService { 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) { @@ -616,6 +599,11 @@ public class WebViewUpdateService extends SystemService { } @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) @@ -626,7 +614,7 @@ public class WebViewUpdateService extends SystemService { @Override // Binder call public boolean isFallbackPackage(String packageName) { - return WebViewUpdateService.isFallbackPackage(packageName); + return WebViewUpdateService.this.isFallbackPackage(packageName); } @Override // Binder call diff --git a/services/core/java/com/android/server/webkit/WebViewUtilityImpl.java b/services/core/java/com/android/server/webkit/WebViewUtilityImpl.java new file mode 100644 index 000000000000..4dbd02d1ede5 --- /dev/null +++ b/services/core/java/com/android/server/webkit/WebViewUtilityImpl.java @@ -0,0 +1,161 @@ +/* + * 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) { + } + } +} diff --git a/services/core/java/com/android/server/webkit/WebViewUtilityInterface.java b/services/core/java/com/android/server/webkit/WebViewUtilityInterface.java new file mode 100644 index 000000000000..1919f400c29a --- /dev/null +++ b/services/core/java/com/android/server/webkit/WebViewUtilityInterface.java @@ -0,0 +1,37 @@ +/* + * 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); +} |