From 12f64daddc1627d1d225081ceb36171b1426e843 Mon Sep 17 00:00:00 2001 From: "Torne (Richard Coles)" Date: Tue, 24 Oct 2017 14:59:07 -0400 Subject: [PATCH] Make WebView data directory configurable. Add WebView.setDataDirectory(String suffix) and WebView.disableWebView() interfaces. These will enable applications to better control the use of WebView when running multiple processes, since it's not safe for more than one process in an app to use the same data directory. disableWebView is completely implemented in this change; setDataDirectory will require WebView-side implementation changes to be functional. Bug: 63748219 Test: cts android.webkit.cts.WebViewDataDirTest Change-Id: Ieff225dc99b6b3ca5f223c35f7a854f0c53692df --- api/current.txt | 2 + api/system-current.txt | 1 + core/java/android/webkit/WebView.java | 42 +++++++++++++++++ core/java/android/webkit/WebViewDelegate.java | 7 +++ core/java/android/webkit/WebViewFactory.java | 47 +++++++++++++++++++ 5 files changed, 99 insertions(+) diff --git a/api/current.txt b/api/current.txt index 2702af6fe29c8..c46d0460fcecc 100644 --- a/api/current.txt +++ b/api/current.txt @@ -49791,6 +49791,7 @@ package android.webkit { method public android.print.PrintDocumentAdapter createPrintDocumentAdapter(java.lang.String); method public android.webkit.WebMessagePort[] createWebMessageChannel(); method public void destroy(); + method public static void disableWebView(); method public void documentHasImages(android.os.Message); method public static void enableSlowWholeDocumentDraw(); method public void evaluateJavascript(java.lang.String, android.webkit.ValueCallback); @@ -49851,6 +49852,7 @@ package android.webkit { method public void saveWebArchive(java.lang.String); method public void saveWebArchive(java.lang.String, boolean, android.webkit.ValueCallback); method public deprecated void setCertificate(android.net.http.SslCertificate); + method public static void setDataDirectorySuffix(java.lang.String); method public void setDownloadListener(android.webkit.DownloadListener); method public void setFindListener(android.webkit.WebView.FindListener); method public deprecated void setHorizontalScrollbarOverlay(boolean); diff --git a/api/system-current.txt b/api/system-current.txt index 50a8ea4717cb5..1f9c85e7146a5 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4538,6 +4538,7 @@ package android.webkit { method public boolean canInvokeDrawGlFunctor(android.view.View); method public void detachDrawGlFunctor(android.view.View, long); method public android.app.Application getApplication(); + method public java.lang.String getDataDirectorySuffix(); method public java.lang.String getErrorString(android.content.Context, int); method public int getPackageId(android.content.res.Resources, java.lang.String); method public void invokeDrawGlFunctor(android.view.View, long, boolean); diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 6f9925480a22d..0b1fb92e95f72 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -2074,6 +2074,48 @@ public class WebView extends AbsoluteLayout return new PluginList(); } + /** + * Define the directory used to store WebView data for the current process. + * The provided suffix will be used when constructing data and cache + * directory paths. If this API is not called, no suffix will be used. + * Each directory can be used by only one process in the application. If more + * than one process in an app wishes to use WebView, only one process can use + * the default directory, and other processes must call this API to define + * a unique suffix. + *

+ * This API must be called before any instances of WebView are created in + * this process and before any other methods in the android.webkit package + * are called by this process. + * + * @param suffix The directory name suffix to be used for the current + * process. Must not contain a path separator. + * @throws IllegalStateException if WebView has already been initialized + * in the current process. + * @throws IllegalArgumentException if the suffix contains a path separator. + */ + public static void setDataDirectorySuffix(String suffix) { + WebViewFactory.setDataDirectorySuffix(suffix); + } + + /** + * Indicate that the current process does not intend to use WebView, and + * that an exception should be thrown if a WebView is created or any other + * methods in the android.webkit package are used. + *

+ * Applications with multiple processes may wish to call this in processes + * which are not intended to use WebView to prevent potential data directory + * conflicts (see {@link #setDataDirectorySuffix}) and to avoid accidentally + * incurring the memory usage of initializing WebView in long-lived + * processes which have no need for it. + * + * @throws IllegalStateException if WebView has already been initialized + * in the current process. + */ + public static void disableWebView() { + WebViewFactory.disableWebView(); + } + + /** * @deprecated This was used for Gears, which has been deprecated. * @hide diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java index 73399313cbb50..f0670914558ed 100644 --- a/core/java/android/webkit/WebViewDelegate.java +++ b/core/java/android/webkit/WebViewDelegate.java @@ -218,4 +218,11 @@ public final class WebViewDelegate { throw e.rethrowFromSystemServer(); } } + + /** + * Returns the data directory suffix to use, or null for none. + */ + public String getDataDirectorySuffix() { + return WebViewFactory.getDataDirectorySuffix(); + } } diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index 797bdfb705cbb..ab447f8a9e517 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -33,6 +33,7 @@ import android.util.AndroidRuntimeException; import android.util.ArraySet; import android.util.Log; +import java.io.File; import java.lang.reflect.Method; /** @@ -63,6 +64,8 @@ public final class WebViewFactory { private static final Object sProviderLock = new Object(); private static PackageInfo sPackageInfo; private static Boolean sWebViewSupported; + private static boolean sWebViewDisabled; + private static String sDataDirectorySuffix; // stored here so it can be set without loading WV // Error codes for loadWebViewNativeLibraryFromPackage public static final int LIBLOAD_SUCCESS = 0; @@ -112,6 +115,45 @@ public final class WebViewFactory { return sWebViewSupported; } + /** + * @hide + */ + static void disableWebView() { + synchronized (sProviderLock) { + if (sProviderInstance != null) { + throw new IllegalStateException( + "Can't disable WebView: WebView already initialized"); + } + sWebViewDisabled = true; + } + } + + /** + * @hide + */ + static void setDataDirectorySuffix(String suffix) { + synchronized (sProviderLock) { + if (sProviderInstance != null) { + throw new IllegalStateException( + "Can't set data directory suffix: WebView already initialized"); + } + if (suffix.indexOf(File.separatorChar) >= 0) { + throw new IllegalArgumentException("Suffix " + suffix + + " contains a path separator"); + } + sDataDirectorySuffix = suffix; + } + } + + /** + * @hide + */ + static String getDataDirectorySuffix() { + synchronized (sProviderLock) { + return sDataDirectorySuffix; + } + } + /** * @hide */ @@ -204,6 +246,11 @@ public final class WebViewFactory { throw new UnsupportedOperationException(); } + if (sWebViewDisabled) { + throw new IllegalStateException( + "WebView.disableWebView() was called: WebView is disabled"); + } + StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()"); try {