Home | History | Annotate | Download | only in webkit
      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