WebViewFactory.java revision cb64bb4b1692fba231bf970f19210aefa024cfba
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 public 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 public 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 Log.i(LOGTAG, "Use Experimental WebView changed: " 86 + SystemProperties.get(WebViewFactory.WEBVIEW_EXPERIMENTAL_PROPERTY, "")); 87 } 88 89 /** @hide */ 90 public static boolean useExperimentalWebView() { 91 return SystemProperties.getBoolean(WEBVIEW_EXPERIMENTAL_PROPERTY, 92 DEFAULT_TO_EXPERIMENTAL_WEBVIEW); 93 } 94 95 static WebViewFactoryProvider getProvider() { 96 synchronized (sProviderLock) { 97 // For now the main purpose of this function (and the factory abstraction) is to keep 98 // us honest and minimize usage of WebViewClassic internals when binding the proxy. 99 if (sProviderInstance != null) return sProviderInstance; 100 101 Class<WebViewFactoryProvider> providerClass; 102 try { 103 providerClass = getFactoryClass(); 104 } catch (ClassNotFoundException e) { 105 Log.e(LOGTAG, "error loading provider", e); 106 throw new AndroidRuntimeException(e); 107 } 108 109 // This implicitly loads Preloader even if it wasn't preloaded at boot. 110 if (Preloader.sPreloadedProvider != null && 111 Preloader.sPreloadedProvider.getClass() == providerClass) { 112 sProviderInstance = Preloader.sPreloadedProvider; 113 if (DEBUG) Log.v(LOGTAG, "Using preloaded provider: " + sProviderInstance); 114 return sProviderInstance; 115 } 116 117 // The preloaded provider isn't the one we wanted; construct our own. 118 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); 119 try { 120 sProviderInstance = providerClass.newInstance(); 121 if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance); 122 return sProviderInstance; 123 } catch (Exception e) { 124 Log.e(LOGTAG, "error instantiating provider", e); 125 throw new AndroidRuntimeException(e); 126 } finally { 127 StrictMode.setThreadPolicy(oldPolicy); 128 } 129 } 130 } 131 132 // We allow a system property to specify that we should use the experimental Chromium powered 133 // WebView. This enables us to switch between implementations at runtime. 134 private static boolean isExperimentalWebViewEnabled() { 135 if (!isExperimentalWebViewAvailable()) return false; 136 String forceProviderName = SystemProperties.get(FORCE_PROVIDER_PROPERTY); 137 if (forceProviderName.isEmpty()) return useExperimentalWebView(); 138 139 Log.i(LOGTAG, String.format("Provider overridden by property: %s=%s", 140 FORCE_PROVIDER_PROPERTY, forceProviderName)); 141 if (forceProviderName.equals(FORCE_PROVIDER_PROPERTY_VALUE_CHROMIUM)) return true; 142 if (forceProviderName.equals(FORCE_PROVIDER_PROPERTY_VALUE_CLASSIC)) return false; 143 Log.e(LOGTAG, String.format("Unrecognized provider: %s", forceProviderName)); 144 return useExperimentalWebView(); 145 } 146 147 private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException { 148 if (isExperimentalWebViewEnabled()) { 149 return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY); 150 } else { 151 return (Class<WebViewFactoryProvider>) Class.forName(DEFAULT_WEBVIEW_FACTORY); 152 } 153 } 154} 155