WebViewChromiumFactoryProvider.java revision d9e4aedf3d14b3494d54dbb482ece3603d0f693d
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 com.android.webview.chromium; 18 19import android.app.ActivityThread; 20import android.content.Context; 21import android.content.SharedPreferences; 22import android.os.Build; 23import android.os.Looper; 24import android.webkit.CookieManager; 25import android.webkit.GeolocationPermissions; 26import android.webkit.WebIconDatabase; 27import android.webkit.WebStorage; 28import android.webkit.WebView; 29import android.webkit.WebViewDatabase; 30import android.webkit.WebViewFactoryProvider; 31import android.webkit.WebViewProvider; 32 33import org.chromium.android_webview.AwBrowserContext; 34import org.chromium.android_webview.AwBrowserProcess; 35import org.chromium.android_webview.AwContents; 36import org.chromium.android_webview.AwCookieManager; 37import org.chromium.android_webview.AwDevToolsServer; 38import org.chromium.android_webview.AwFormDatabase; 39import org.chromium.android_webview.AwGeolocationPermissions; 40import org.chromium.android_webview.AwQuotaManagerBridge; 41import org.chromium.android_webview.AwSettings; 42import org.chromium.base.PathService; 43import org.chromium.base.ThreadUtils; 44import org.chromium.content.app.LibraryLoader; 45import org.chromium.content.browser.ContentViewStatics; 46import org.chromium.content.browser.ResourceExtractor; 47import org.chromium.content.common.CommandLine; 48import org.chromium.content.common.ProcessInitException; 49 50public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider { 51 52 private static final String CHROMIUM_PREFS_NAME = "WebViewChromiumPrefs"; 53 private static final String COMMAND_LINE_FILE = "/data/local/tmp/webview-command-line"; 54 55 // Guards accees to the other members, and is notifyAll() signalled on the UI thread 56 // when the chromium process has been started. 57 private final Object mLock = new Object(); 58 59 // Initialization guarded by mLock. 60 private AwBrowserContext mBrowserContext; 61 private Statics mStaticMethods; 62 private GeolocationPermissionsAdapter mGeolocationPermissions; 63 private CookieManagerAdapter mCookieManager; 64 private WebIconDatabaseAdapter mWebIconDatabase; 65 private WebStorageAdapter mWebStorage; 66 private WebViewDatabaseAdapter mWebViewDatabase; 67 private AwDevToolsServer mDevToolsServer; 68 69 // Read/write protected by mLock. 70 private boolean mStarted; 71 72 public WebViewChromiumFactoryProvider() { 73 // Load chromium library. 74 AwBrowserProcess.loadLibrary(); 75 // Load glue-layer support library. 76 System.loadLibrary("webviewchromium_plat_support"); 77 } 78 79 private void initPlatSupportLibrary() { 80 DrawGLFunctor.setChromiumAwDrawGLFunction(AwContents.getAwDrawGLFunction()); 81 AwContents.setAwDrawSWFunctionTable(GraphicsUtils.getDrawSWFunctionTable()); 82 AwContents.setAwDrawGLFunctionTable(GraphicsUtils.getDrawGLFunctionTable()); 83 } 84 85 private void ensureChromiumStartedLocked() { 86 assert Thread.holdsLock(mLock); 87 88 if (mStarted) { // Early-out for the common case. 89 return; 90 } 91 92 if (ThreadUtils.runningOnUiThread()) { 93 startChromiumLocked(); 94 return; 95 } 96 97 // We must post to the UI thread to cover the case that the user has invoked Chromium 98 // startup by using the (thread-safe) CookieManager rather than creating a WebView. 99 ThreadUtils.postOnUiThread(new Runnable() { 100 @Override 101 public void run() { 102 synchronized (mLock) { 103 startChromiumLocked(); 104 } 105 } 106 }); 107 while (!mStarted) { 108 try { 109 // Important: wait() releases |mLock| so the UI thread can take it :-) 110 mLock.wait(); 111 } catch (InterruptedException e) { 112 // Keep trying... eventually the UI thread will process the task we sent it. 113 } 114 } 115 } 116 117 private void startChromiumLocked() { 118 assert Thread.holdsLock(mLock) && ThreadUtils.runningOnUiThread(); 119 120 // The post-condition of this method is everything is ready, so notify now to cover all 121 // return paths. (Other threads will not wake-up until we release |mLock|, whatever). 122 mLock.notifyAll(); 123 124 if (mStarted) { 125 return; 126 } 127 128 if (Build.IS_DEBUGGABLE) { 129 CommandLine.initFromFile(COMMAND_LINE_FILE); 130 } else { 131 CommandLine.init(null); 132 } 133 134 CommandLine cl = CommandLine.getInstance(); 135 // TODO: currently in a relase build the DCHECKs only log. We either need to insall 136 // a report handler with SetLogReportHandler to make them assert, or else compile 137 // them out of the build altogether (b/8284203). Either way, so long they're 138 // compiled in, we may as unconditionally enable them here. 139 cl.appendSwitch("enable-dcheck"); 140 141 // TODO: Remove when GL is supported by default in the upstream code. 142 if (!cl.hasSwitch("disable-webview-gl-mode")) { 143 cl.appendSwitch("testing-webview-gl-mode"); 144 } 145 146 // We don't need to extract any paks because for WebView, they are 147 // in the system image. 148 ResourceExtractor.setMandatoryPaksToExtract(""); 149 150 try { 151 LibraryLoader.ensureInitialized(); 152 } catch(ProcessInitException e) { 153 throw new RuntimeException("Error initializing WebView library", e); 154 } 155 156 PathService.override(PathService.DIR_MODULE, "/system/lib/"); 157 // TODO: DIR_RESOURCE_PAKS_ANDROID needs to live somewhere sensible, 158 // inlined here for simplicity setting up the HTMLViewer demo. Unfortunately 159 // it can't go into base.PathService, as the native constant it refers to 160 // lives in the ui/ layer. See ui/base/ui_base_paths.h 161 final int DIR_RESOURCE_PAKS_ANDROID = 3003; 162 PathService.override(DIR_RESOURCE_PAKS_ANDROID, 163 "/system/framework/webview/paks"); 164 165 AwBrowserProcess.start(ActivityThread.currentApplication()); 166 initPlatSupportLibrary(); 167 168 if (Build.IS_DEBUGGABLE) { 169 setWebContentsDebuggingEnabled(true); 170 } 171 172 mStarted = true; 173 } 174 175 @Override 176 public Statics getStatics() { 177 synchronized (mLock) { 178 if (mStaticMethods == null) { 179 // TODO: Optimization potential: most these methods only need the native library 180 // loaded and initialized, not the entire browser process started. 181 // See also http://b/7009882 182 ensureChromiumStartedLocked(); 183 mStaticMethods = new WebViewFactoryProvider.Statics() { 184 @Override 185 public String findAddress(String addr) { 186 return ContentViewStatics.findAddress(addr); 187 } 188 189 @Override 190 public void setPlatformNotificationsEnabled(boolean enable) { 191 // noop 192 } 193 194 @Override 195 public String getDefaultUserAgent(Context context) { 196 return AwSettings.getDefaultUserAgent(); 197 } 198 199 @Override 200 public void setWebContentsDebuggingEnabled(boolean enable) { 201 // Web Contents debugging is always enabled on debug builds. 202 if (!Build.IS_DEBUGGABLE) { 203 WebViewChromiumFactoryProvider.this. 204 setWebContentsDebuggingEnabled(enable); 205 } 206 } 207 }; 208 } 209 } 210 return mStaticMethods; 211 } 212 213 @Override 214 public WebViewProvider createWebView(WebView webView, WebView.PrivateAccess privateAccess) { 215 assert Looper.myLooper() == Looper.getMainLooper(); 216 AwBrowserContext browserContext; 217 synchronized (mLock) { 218 ensureChromiumStartedLocked(); 219 ResourceProvider.registerResources(webView.getContext()); 220 browserContext = getBrowserContextLocked(); 221 } 222 // Make sure GeolocationPermissions is created before creating a webview 223 getGeolocationPermissions(); 224 return new WebViewChromium(webView, privateAccess, browserContext); 225 } 226 227 @Override 228 public GeolocationPermissions getGeolocationPermissions() { 229 synchronized (mLock) { 230 if (mGeolocationPermissions == null) { 231 ensureChromiumStartedLocked(); 232 mGeolocationPermissions = new GeolocationPermissionsAdapter( 233 getBrowserContextLocked().getGeolocationPermissions()); 234 } 235 } 236 return mGeolocationPermissions; 237 } 238 239 private AwBrowserContext getBrowserContextLocked() { 240 assert Thread.holdsLock(mLock); 241 assert mStarted; 242 if (mBrowserContext == null) { 243 mBrowserContext = new AwBrowserContext( 244 ActivityThread.currentApplication().getSharedPreferences( 245 CHROMIUM_PREFS_NAME, Context.MODE_PRIVATE)); 246 } 247 return mBrowserContext; 248 } 249 250 @Override 251 public CookieManager getCookieManager() { 252 synchronized (mLock) { 253 if (mCookieManager == null) { 254 ensureChromiumStartedLocked(); 255 mCookieManager = new CookieManagerAdapter(new AwCookieManager()); 256 } 257 } 258 return mCookieManager; 259 } 260 261 @Override 262 public WebIconDatabase getWebIconDatabase() { 263 synchronized (mLock) { 264 if (mWebIconDatabase == null) { 265 ensureChromiumStartedLocked(); 266 mWebIconDatabase = new WebIconDatabaseAdapter(); 267 } 268 } 269 return mWebIconDatabase; 270 } 271 272 @Override 273 public WebStorage getWebStorage() { 274 synchronized (mLock) { 275 if (mWebStorage == null) { 276 ensureChromiumStartedLocked(); 277 mWebStorage = new WebStorageAdapter(AwQuotaManagerBridge.getInstance()); 278 } 279 } 280 return mWebStorage; 281 } 282 283 @Override 284 public WebViewDatabase getWebViewDatabase(Context context) { 285 synchronized (mLock) { 286 if (mWebViewDatabase == null) { 287 ensureChromiumStartedLocked(); 288 AwBrowserContext browserContext = getBrowserContextLocked(); 289 mWebViewDatabase = new WebViewDatabaseAdapter( 290 browserContext.getFormDatabase(), 291 browserContext.getHttpAuthDatabase(context)); 292 } 293 } 294 return mWebViewDatabase; 295 } 296 297 private void setWebContentsDebuggingEnabled(boolean enable) { 298 if (Looper.myLooper() != Looper.getMainLooper()) { 299 throw new RuntimeException( 300 "Toggling of Web Contents Debugging must be done on the main thread"); 301 } 302 if (mDevToolsServer == null) { 303 if (!enable) return; 304 mDevToolsServer = new AwDevToolsServer(); 305 } 306 mDevToolsServer.setRemoteDebuggingEnabled(enable); 307 } 308} 309