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 17 package android.webkit; 18 19 import android.os.Build; 20 import android.os.StrictMode; 21 import android.os.SystemProperties; 22 import android.util.Log; 23 24 import dalvik.system.PathClassLoader; 25 26 /** 27 * Top level factory, used creating all the main WebView implementation classes. 28 * 29 * @hide 30 */ 31 public final class WebViewFactory { 32 public static final String WEBVIEW_EXPERIMENTAL_PROPERTY = "persist.sys.webview.exp"; 33 private static final String DEPRECATED_CHROMIUM_PROPERTY = "webview.use_chromium"; 34 35 // Default Provider factory class name. 36 // TODO: When the Chromium powered WebView is ready, it should be the default factory class. 37 private static final String DEFAULT_WEBVIEW_FACTORY = "android.webkit.WebViewClassic$Factory"; 38 private static final String CHROMIUM_WEBVIEW_FACTORY = 39 "com.android.webview.chromium.WebViewChromiumFactoryProvider"; 40 private static final String CHROMIUM_WEBVIEW_JAR = "/system/framework/webviewchromium.jar"; 41 42 private static final String LOGTAG = "WebViewFactory"; 43 44 private static final boolean DEBUG = false; 45 46 // Cache the factory both for efficiency, and ensure any one process gets all webviews from the 47 // same provider. 48 private static WebViewFactoryProvider sProviderInstance; 49 private static final Object sProviderLock = new Object(); 50 51 public static boolean isExperimentalWebViewAvailable() { 52 return Build.IS_DEBUGGABLE && (new java.io.File(CHROMIUM_WEBVIEW_JAR).exists()); 53 } 54 55 static WebViewFactoryProvider getProvider() { 56 synchronized (sProviderLock) { 57 // For now the main purpose of this function (and the factory abstraction) is to keep 58 // us honest and minimize usage of WebViewClassic internals when binding the proxy. 59 if (sProviderInstance != null) return sProviderInstance; 60 61 if (isExperimentalWebViewEnabled()) { 62 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); 63 try { 64 sProviderInstance = loadChromiumProvider(); 65 if (DEBUG) Log.v(LOGTAG, "Loaded Chromium provider: " + sProviderInstance); 66 } finally { 67 StrictMode.setThreadPolicy(oldPolicy); 68 } 69 } 70 71 if (sProviderInstance == null) { 72 if (DEBUG) Log.v(LOGTAG, "Falling back to default provider: " 73 + DEFAULT_WEBVIEW_FACTORY); 74 sProviderInstance = getFactoryByName(DEFAULT_WEBVIEW_FACTORY, 75 WebViewFactory.class.getClassLoader()); 76 if (sProviderInstance == null) { 77 if (DEBUG) Log.v(LOGTAG, "Falling back to explicit linkage"); 78 sProviderInstance = new WebViewClassic.Factory(); 79 } 80 } 81 return sProviderInstance; 82 } 83 } 84 85 // For debug builds, we allow a system property to specify that we should use the 86 // experimtanl Chromium powered WebView. This enables us to switch between 87 // implementations at runtime. For user (release) builds, don't allow this. 88 private static boolean isExperimentalWebViewEnabled() { 89 if (!isExperimentalWebViewAvailable()) 90 return false; 91 if (SystemProperties.getBoolean(DEPRECATED_CHROMIUM_PROPERTY, false)) { 92 Log.w(LOGTAG, String.format("The property %s has been deprecated. Please use %s.", 93 DEPRECATED_CHROMIUM_PROPERTY, WEBVIEW_EXPERIMENTAL_PROPERTY)); 94 return true; 95 } 96 return SystemProperties.getBoolean(WEBVIEW_EXPERIMENTAL_PROPERTY, false); 97 } 98 99 // TODO: This allows us to have the legacy and Chromium WebView coexist for development 100 // and side-by-side testing. After transition, remove this when no longer required. 101 private static WebViewFactoryProvider loadChromiumProvider() { 102 ClassLoader clazzLoader = new PathClassLoader(CHROMIUM_WEBVIEW_JAR, null, 103 WebViewFactory.class.getClassLoader()); 104 return getFactoryByName(CHROMIUM_WEBVIEW_FACTORY, clazzLoader); 105 } 106 107 private static WebViewFactoryProvider getFactoryByName(String providerName, 108 ClassLoader loader) { 109 try { 110 if (DEBUG) Log.v(LOGTAG, "attempt to load class " + providerName); 111 Class<?> c = Class.forName(providerName, true, loader); 112 if (DEBUG) Log.v(LOGTAG, "instantiating factory"); 113 return (WebViewFactoryProvider) c.newInstance(); 114 } catch (ClassNotFoundException e) { 115 Log.e(LOGTAG, "error loading " + providerName, e); 116 } catch (IllegalAccessException e) { 117 Log.e(LOGTAG, "error loading " + providerName, e); 118 } catch (InstantiationException e) { 119 Log.e(LOGTAG, "error loading " + providerName, e); 120 } 121 return null; 122 } 123 } 124