WebViewFactory.java revision eb665d66bac9aa3d7bf1834cfda6c886f721b157
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.Log;
23
24import dalvik.system.PathClassLoader;
25
26/**
27 * Top level factory, used creating all the main WebView implementation classes.
28 *
29 * @hide
30 */
31public final class WebViewFactory {
32    public static final boolean DEFAULT_TO_EXPERIMENTAL_WEBVIEW = false;
33    public static final String WEBVIEW_EXPERIMENTAL_PROPERTY = "persist.sys.webview.exp";
34    private static final String FORCE_PROVIDER_PROPERTY = "webview.force_provider";
35    private static final String FORCE_PROVIDER_PROPERTY_VALUE_CHROMIUM = "chromium";
36    private static final String FORCE_PROVIDER_PROPERTY_VALUE_CLASSIC = "classic";
37
38    // Default Provider factory class name.
39    // TODO: When the Chromium powered WebView is ready, it should be the default factory class.
40    private static final String DEFAULT_WEBVIEW_FACTORY = "android.webkit.WebViewClassic$Factory";
41    private static final String CHROMIUM_WEBVIEW_FACTORY =
42            "com.android.webview.chromium.WebViewChromiumFactoryProvider";
43
44    private static final String LOGTAG = "WebViewFactory";
45
46    private static final boolean DEBUG = false;
47
48    // Cache the factory both for efficiency, and ensure any one process gets all webviews from the
49    // same provider.
50    private static WebViewFactoryProvider sProviderInstance;
51    private static final Object sProviderLock = new Object();
52
53    public static boolean isExperimentalWebViewAvailable() {
54        try {
55            // Pass false so we don't initialize the class at this point, as this will be wasted if
56            // it's not enabled.
57            Class.forName(CHROMIUM_WEBVIEW_FACTORY, false, WebViewFactory.class.getClassLoader());
58            return true;
59        } catch (ClassNotFoundException e) {
60            return false;
61        }
62    }
63
64    static WebViewFactoryProvider getProvider() {
65        synchronized (sProviderLock) {
66            // For now the main purpose of this function (and the factory abstraction) is to keep
67            // us honest and minimize usage of WebViewClassic internals when binding the proxy.
68            if (sProviderInstance != null) return sProviderInstance;
69
70            if (isExperimentalWebViewEnabled()) {
71                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
72                try {
73                    sProviderInstance = getFactoryByName(CHROMIUM_WEBVIEW_FACTORY);
74                    if (DEBUG) Log.v(LOGTAG, "Loaded Chromium provider: " + sProviderInstance);
75                } finally {
76                    StrictMode.setThreadPolicy(oldPolicy);
77                }
78            }
79
80            if (sProviderInstance == null) {
81                if (DEBUG) Log.v(LOGTAG, "Falling back to default provider: "
82                        + DEFAULT_WEBVIEW_FACTORY);
83                sProviderInstance = getFactoryByName(DEFAULT_WEBVIEW_FACTORY);
84                if (sProviderInstance == null) {
85                    if (DEBUG) Log.v(LOGTAG, "Falling back to explicit linkage");
86                    sProviderInstance = new WebViewClassic.Factory();
87                }
88            }
89            return sProviderInstance;
90        }
91    }
92
93    // For debug builds, we allow a system property to specify that we should use the
94    // experimtanl Chromium powered WebView. This enables us to switch between
95    // implementations at runtime. For user (release) builds, don't allow this.
96    private static boolean isExperimentalWebViewEnabled() {
97        if (!isExperimentalWebViewAvailable()) return false;
98        boolean use_experimental_webview = SystemProperties.getBoolean(
99                WEBVIEW_EXPERIMENTAL_PROPERTY, DEFAULT_TO_EXPERIMENTAL_WEBVIEW);
100        String forceProviderName = SystemProperties.get(FORCE_PROVIDER_PROPERTY);
101        if (forceProviderName.isEmpty()) return use_experimental_webview;
102
103        Log.i(LOGTAG, String.format("Provider overridden by property: %s=%s",
104                FORCE_PROVIDER_PROPERTY, forceProviderName));
105        if (forceProviderName.equals(FORCE_PROVIDER_PROPERTY_VALUE_CHROMIUM)) return true;
106        if (forceProviderName.equals(FORCE_PROVIDER_PROPERTY_VALUE_CLASSIC)) return false;
107        Log.e(LOGTAG, String.format("Unrecognized provider: %s", forceProviderName));
108        return use_experimental_webview;
109    }
110
111    private static WebViewFactoryProvider getFactoryByName(String providerName) {
112        try {
113            if (DEBUG) Log.v(LOGTAG, "attempt to load class " + providerName);
114            Class<?> c = Class.forName(providerName);
115            if (DEBUG) Log.v(LOGTAG, "instantiating factory");
116            return (WebViewFactoryProvider) c.newInstance();
117        } catch (ClassNotFoundException e) {
118            Log.e(LOGTAG, "error loading " + providerName, e);
119        } catch (IllegalAccessException e) {
120            Log.e(LOGTAG, "error loading " + providerName, e);
121        } catch (InstantiationException e) {
122            Log.e(LOGTAG, "error loading " + providerName, e);
123        }
124        return null;
125    }
126}
127