Enable preloading of the appropriate WebView.

Allow the appropriate WebView to be preloaded in the zygote by
constructing the currently selected WebViewFactoryProvider when the
WebViewFactory is preloaded. At runtime, if the preloaded provider is
still the current selection, the preloaded instance is used, otherwise
the provider is loaded at that time.

This change also removes "graceful" fallback from the experimental
WebView to the classic implementation: if the option to use the
experimental WebView is selected and it could not be loaded
successfully at the time a WebView is created, an exception will be
thrown, rather than allowing execution to continue with the classic
implementation, as the fallback may mislead developers who do not
examine logcat output in detail.

Change-Id: I0cd01c784d7048abeac55ab5863ca16b8fd9ecf2
This commit is contained in:
Torne (Richard Coles)
2013-06-12 16:02:03 +01:00
parent 4b77dbb206
commit 03ce9b3e69
3 changed files with 59 additions and 37 deletions

View File

@@ -66,6 +66,7 @@ import android.text.Editable;
import android.text.InputType;
import android.text.Selection;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -1293,6 +1294,19 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
// WebViewProvider bindings
static class Factory implements WebViewFactoryProvider, WebViewFactoryProvider.Statics {
Factory() {
// Touch JniUtil and WebViewCore in case this is being called from
// WebViewFactory.Preloader, to ensure that the JNI libraries that they use are
// preloaded in the zygote.
try {
Class.forName("android.webkit.JniUtil");
Class.forName("android.webkit.WebViewCore");
} catch (ClassNotFoundException e) {
Log.e(LOGTAG, "failed to load JNI libraries");
throw new AndroidRuntimeException(e);
}
}
@Override
public String findAddress(String addr) {
return WebViewClassic.findAddress(addr);

View File

@@ -19,10 +19,9 @@ package android.webkit;
import android.os.Build;
import android.os.StrictMode;
import android.os.SystemProperties;
import android.util.AndroidRuntimeException;
import android.util.Log;
import dalvik.system.PathClassLoader;
/**
* Top level factory, used creating all the main WebView implementation classes.
*
@@ -45,6 +44,17 @@ public final class WebViewFactory {
private static final boolean DEBUG = false;
private static class Preloader {
static WebViewFactoryProvider sPreloadedProvider;
static {
try {
sPreloadedProvider = getFactoryClass().newInstance();
} catch (Exception e) {
Log.w(LOGTAG, "error preloading provider", e);
}
}
}
// Cache the factory both for efficiency, and ensure any one process gets all webviews from the
// same provider.
private static WebViewFactoryProvider sProviderInstance;
@@ -67,32 +77,39 @@ public final class WebViewFactory {
// us honest and minimize usage of WebViewClassic internals when binding the proxy.
if (sProviderInstance != null) return sProviderInstance;
if (isExperimentalWebViewEnabled()) {
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
sProviderInstance = getFactoryByName(CHROMIUM_WEBVIEW_FACTORY);
if (DEBUG) Log.v(LOGTAG, "Loaded Chromium provider: " + sProviderInstance);
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
Class<WebViewFactoryProvider> providerClass;
try {
providerClass = getFactoryClass();
} catch (ClassNotFoundException e) {
Log.e(LOGTAG, "error loading provider", e);
throw new AndroidRuntimeException(e);
}
if (sProviderInstance == null) {
if (DEBUG) Log.v(LOGTAG, "Falling back to default provider: "
+ DEFAULT_WEBVIEW_FACTORY);
sProviderInstance = getFactoryByName(DEFAULT_WEBVIEW_FACTORY);
if (sProviderInstance == null) {
if (DEBUG) Log.v(LOGTAG, "Falling back to explicit linkage");
sProviderInstance = new WebViewClassic.Factory();
}
// This implicitly loads Preloader even if it wasn't preloaded at boot.
if (Preloader.sPreloadedProvider != null &&
Preloader.sPreloadedProvider.getClass() == providerClass) {
sProviderInstance = Preloader.sPreloadedProvider;
if (DEBUG) Log.v(LOGTAG, "Using preloaded provider: " + sProviderInstance);
return sProviderInstance;
}
// The preloaded provider isn't the one we wanted; construct our own.
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
sProviderInstance = providerClass.newInstance();
if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
return sProviderInstance;
} catch (Exception e) {
Log.e(LOGTAG, "error instantiating provider", e);
throw new AndroidRuntimeException(e);
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
return sProviderInstance;
}
}
// For debug builds, we allow a system property to specify that we should use the
// experimtanl Chromium powered WebView. This enables us to switch between
// implementations at runtime. For user (release) builds, don't allow this.
// We allow a system property to specify that we should use the experimental Chromium powered
// WebView. This enables us to switch between implementations at runtime.
private static boolean isExperimentalWebViewEnabled() {
if (!isExperimentalWebViewAvailable()) return false;
boolean use_experimental_webview = SystemProperties.getBoolean(
@@ -108,19 +125,11 @@ public final class WebViewFactory {
return use_experimental_webview;
}
private static WebViewFactoryProvider getFactoryByName(String providerName) {
try {
if (DEBUG) Log.v(LOGTAG, "attempt to load class " + providerName);
Class<?> c = Class.forName(providerName);
if (DEBUG) Log.v(LOGTAG, "instantiating factory");
return (WebViewFactoryProvider) c.newInstance();
} catch (ClassNotFoundException e) {
Log.e(LOGTAG, "error loading " + providerName, e);
} catch (IllegalAccessException e) {
Log.e(LOGTAG, "error loading " + providerName, e);
} catch (InstantiationException e) {
Log.e(LOGTAG, "error loading " + providerName, e);
private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException {
if (isExperimentalWebViewEnabled()) {
return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY);
} else {
return (Class<WebViewFactoryProvider>) Class.forName(DEFAULT_WEBVIEW_FACTORY);
}
return null;
}
}

View File

@@ -1220,7 +1220,6 @@ android.webkit.HTML5Audio
android.webkit.HTML5VideoViewProxy
android.webkit.JWebCoreJavaBridge
android.webkit.JavascriptInterface
android.webkit.JniUtil
android.webkit.L10nUtils
android.webkit.MockGeolocation
android.webkit.OverScrollGlow
@@ -1269,7 +1268,6 @@ android.webkit.WebViewClassic$TitleBarDelegate
android.webkit.WebViewClassic$TrustStorageListener
android.webkit.WebViewClassic$ViewSizeData
android.webkit.WebViewClient
android.webkit.WebViewCore
android.webkit.WebViewCore$AutoFillData
android.webkit.WebViewCore$DrawData
android.webkit.WebViewCore$EventHub
@@ -1283,6 +1281,7 @@ android.webkit.WebViewDatabase
android.webkit.WebViewDatabaseClassic
android.webkit.WebViewDatabaseClassic$1
android.webkit.WebViewFactory
android.webkit.WebViewFactory$Preloader
android.webkit.WebViewFactoryProvider
android.webkit.WebViewFactoryProvider$Statics
android.webkit.WebViewInputDispatcher