WebViewFactory.java revision a7eaa8ee222611c28f050158db4b68c4d893a8a9
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.webkit; 18 19import android.os.Build; 20import android.os.StrictMode; 21import android.os.SystemProperties; 22import android.util.AndroidRuntimeException; 23import android.util.Log; 24 25/** 26 * Top level factory, used creating all the main WebView implementation classes. 27 * 28 * @hide 29 */ 30public final class WebViewFactory { 31 private static final boolean DEFAULT_TO_EXPERIMENTAL_WEBVIEW = false; 32 private static final String EXPERIMENTAL_PROPERTY_DEFAULT_OFF = "persist.sys.webview.exp"; 33 private static final String EXPERIMENTAL_PROPERTY_DEFAULT_ON = "persist.sys.webview.exp_on"; 34 35 // Modify the persisted property name when the experiment is on-by-default, so that any user 36 // setting override lives in a different property namespace. 37 private static final String WEBVIEW_EXPERIMENTAL_PROPERTY = DEFAULT_TO_EXPERIMENTAL_WEBVIEW ? 38 EXPERIMENTAL_PROPERTY_DEFAULT_ON : EXPERIMENTAL_PROPERTY_DEFAULT_OFF; 39 40 private static final String FORCE_PROVIDER_PROPERTY = "webview.force_provider"; 41 private static final String FORCE_PROVIDER_PROPERTY_VALUE_CHROMIUM = "chromium"; 42 private static final String FORCE_PROVIDER_PROPERTY_VALUE_CLASSIC = "classic"; 43 44 // Default Provider factory class name. 45 // TODO: When the Chromium powered WebView is ready, it should be the default factory class. 46 private static final String DEFAULT_WEBVIEW_FACTORY = "android.webkit.WebViewClassic$Factory"; 47 private static final String CHROMIUM_WEBVIEW_FACTORY = 48 "com.android.webview.chromium.WebViewChromiumFactoryProvider"; 49 50 private static final String LOGTAG = "WebViewFactory"; 51 52 private static final boolean DEBUG = false; 53 54 private static class Preloader { 55 static WebViewFactoryProvider sPreloadedProvider; 56 static { 57 try { 58 sPreloadedProvider = getFactoryClass().newInstance(); 59 } catch (Exception e) { 60 Log.w(LOGTAG, "error preloading provider", e); 61 } 62 } 63 } 64 65 // Cache the factory both for efficiency, and ensure any one process gets all webviews from the 66 // same provider. 67 private static WebViewFactoryProvider sProviderInstance; 68 private static final Object sProviderLock = new Object(); 69 70 public static boolean isExperimentalWebViewAvailable() { 71 try { 72 // Pass false so we don't initialize the class at this point, as this will be wasted if 73 // it's not enabled. 74 Class.forName(CHROMIUM_WEBVIEW_FACTORY, false, WebViewFactory.class.getClassLoader()); 75 return true; 76 } catch (ClassNotFoundException e) { 77 return false; 78 } 79 } 80 81 /** @hide */ 82 public static void setUseExperimentalWebView(boolean enable) { 83 SystemProperties.set(WebViewFactory.WEBVIEW_EXPERIMENTAL_PROPERTY, 84 enable ? "true" : "false"); 85 } 86 87 /** @hide */ 88 public static boolean useExperimentalWebView() { 89 return SystemProperties.getBoolean(WEBVIEW_EXPERIMENTAL_PROPERTY, 90 DEFAULT_TO_EXPERIMENTAL_WEBVIEW); 91 } 92 93 static WebViewFactoryProvider getProvider() { 94 synchronized (sProviderLock) { 95 // For now the main purpose of this function (and the factory abstraction) is to keep 96 // us honest and minimize usage of WebViewClassic internals when binding the proxy. 97 if (sProviderInstance != null) return sProviderInstance; 98 99 Class<WebViewFactoryProvider> providerClass; 100 try { 101 providerClass = getFactoryClass(); 102 } catch (ClassNotFoundException e) { 103 Log.e(LOGTAG, "error loading provider", e); 104 throw new AndroidRuntimeException(e); 105 } 106 107 // This implicitly loads Preloader even if it wasn't preloaded at boot. 108 if (Preloader.sPreloadedProvider != null && 109 Preloader.sPreloadedProvider.getClass() == providerClass) { 110 sProviderInstance = Preloader.sPreloadedProvider; 111 if (DEBUG) Log.v(LOGTAG, "Using preloaded provider: " + sProviderInstance); 112 return sProviderInstance; 113 } 114 115 // The preloaded provider isn't the one we wanted; construct our own. 116 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); 117 try { 118 sProviderInstance = providerClass.newInstance(); 119 if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance); 120 return sProviderInstance; 121 } catch (Exception e) { 122 Log.e(LOGTAG, "error instantiating provider", e); 123 throw new AndroidRuntimeException(e); 124 } finally { 125 StrictMode.setThreadPolicy(oldPolicy); 126 } 127 } 128 } 129 130 // We allow a system property to specify that we should use the experimental Chromium powered 131 // WebView. This enables us to switch between implementations at runtime. 132 private static boolean isExperimentalWebViewEnabled() { 133 if (!isExperimentalWebViewAvailable()) return false; 134 String forceProviderName = SystemProperties.get(FORCE_PROVIDER_PROPERTY); 135 if (forceProviderName.isEmpty()) return useExperimentalWebView(); 136 137 Log.i(LOGTAG, String.format("Provider overridden by property: %s=%s", 138 FORCE_PROVIDER_PROPERTY, forceProviderName)); 139 if (forceProviderName.equals(FORCE_PROVIDER_PROPERTY_VALUE_CHROMIUM)) return true; 140 if (forceProviderName.equals(FORCE_PROVIDER_PROPERTY_VALUE_CLASSIC)) return false; 141 Log.e(LOGTAG, String.format("Unrecognized provider: %s", forceProviderName)); 142 return useExperimentalWebView(); 143 } 144 145 private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException { 146 if (isExperimentalWebViewEnabled()) { 147 return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY); 148 } else { 149 return (Class<WebViewFactoryProvider>) Class.forName(DEFAULT_WEBVIEW_FACTORY); 150 } 151 } 152} 153