Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / android_webview / glue / java / src / com / android / webview / chromium / WebViewChromiumFactoryProvider.java
blobd608ac92a43326d5f6959ca3e48defde7782bdd1
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package com.android.webview.chromium;
7 import android.app.ActivityManager;
8 import android.content.ComponentCallbacks2;
9 import android.content.Context;
10 import android.content.Intent;
11 import android.content.SharedPreferences;
12 import android.content.pm.PackageInfo;
13 import android.net.Uri;
14 import android.os.Build;
15 import android.os.Looper;
16 import android.os.StrictMode;
17 import android.util.Log;
18 import android.webkit.CookieManager;
19 import android.webkit.GeolocationPermissions;
20 import android.webkit.WebStorage;
21 import android.webkit.WebView;
22 import android.webkit.WebViewDatabase;
23 import android.webkit.WebViewFactory;
24 import android.webkit.WebViewFactoryProvider;
25 import android.webkit.WebViewProvider;
27 import com.android.webview.chromium.WebViewDelegateFactory.WebViewDelegate;
29 import org.chromium.android_webview.AwBrowserContext;
30 import org.chromium.android_webview.AwBrowserProcess;
31 import org.chromium.android_webview.AwContents;
32 import org.chromium.android_webview.AwContentsClient;
33 import org.chromium.android_webview.AwContentsStatics;
34 import org.chromium.android_webview.AwCookieManager;
35 import org.chromium.android_webview.AwDataReductionProxyManager;
36 import org.chromium.android_webview.AwDevToolsServer;
37 import org.chromium.android_webview.AwQuotaManagerBridge;
38 import org.chromium.android_webview.AwResource;
39 import org.chromium.android_webview.AwSettings;
40 import org.chromium.base.CommandLine;
41 import org.chromium.base.MemoryPressureListener;
42 import org.chromium.base.PathService;
43 import org.chromium.base.PathUtils;
44 import org.chromium.base.ResourceExtractor;
45 import org.chromium.base.ThreadUtils;
46 import org.chromium.base.TraceEvent;
47 import org.chromium.base.library_loader.LibraryLoader;
48 import org.chromium.base.library_loader.LibraryProcessType;
49 import org.chromium.base.library_loader.ProcessInitException;
50 import org.chromium.content.app.ContentMain;
51 import org.chromium.content.browser.ContentViewStatics;
53 import java.io.File;
54 import java.lang.ref.WeakReference;
55 import java.util.ArrayList;
57 /**
58 * Entry point to the WebView. The system framework talks to this class to get instances of the
59 * implementation classes.
61 @SuppressWarnings("deprecation")
62 public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
63 private static final String TAG = "WebViewChromiumFactoryProvider";
65 private static final String CHROMIUM_PREFS_NAME = "WebViewChromiumPrefs";
66 private static final String VERSION_CODE_PREF = "lastVersionCodeUsed";
67 private static final String COMMAND_LINE_FILE = "/data/local/tmp/webview-command-line";
69 // Guards accees to the other members, and is notifyAll() signalled on the UI thread
70 // when the chromium process has been started.
71 private final Object mLock = new Object();
73 // Initialization guarded by mLock.
74 private AwBrowserContext mBrowserContext;
75 private Statics mStaticMethods;
76 private GeolocationPermissionsAdapter mGeolocationPermissions;
77 private CookieManagerAdapter mCookieManager;
78 private WebIconDatabaseAdapter mWebIconDatabase;
79 private WebStorageAdapter mWebStorage;
80 private WebViewDatabaseAdapter mWebViewDatabase;
81 private AwDevToolsServer mDevToolsServer;
82 private Context mWrappedAppContext;
84 private ArrayList<WeakReference<WebViewChromium>> mWebViewsToStart =
85 new ArrayList<WeakReference<WebViewChromium>>();
87 // Read/write protected by mLock.
88 private boolean mStarted;
89 private AwDataReductionProxyManager mProxyManager;
91 private SharedPreferences mWebViewPrefs;
92 private WebViewDelegate mWebViewDelegate;
94 /**
95 * Constructor called by the API 21 version of {@link WebViewFactory} and earlier.
97 public WebViewChromiumFactoryProvider() {
98 initialize(WebViewDelegateFactory.createApi21CompatibilityDelegate());
102 * Constructor called by the API 22 version of {@link WebViewFactory} and later.
104 public WebViewChromiumFactoryProvider(android.webkit.WebViewDelegate delegate) {
105 initialize(WebViewDelegateFactory.createProxyDelegate(delegate));
108 private void initialize(WebViewDelegate webViewDelegate) {
109 mWebViewDelegate = webViewDelegate;
110 if (isBuildDebuggable()) {
111 // Suppress the StrictMode violation as this codepath is only hit on debugglable builds.
112 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
113 CommandLine.initFromFile(COMMAND_LINE_FILE);
114 StrictMode.setThreadPolicy(oldPolicy);
115 } else {
116 CommandLine.init(null);
119 CommandLine cl = CommandLine.getInstance();
120 // TODO: currently in a relase build the DCHECKs only log. We either need to insall
121 // a report handler with SetLogReportHandler to make them assert, or else compile
122 // them out of the build altogether (b/8284203). Either way, so long they're
123 // compiled in, we may as unconditionally enable them here.
124 cl.appendSwitch("enable-dcheck");
126 ThreadUtils.setWillOverrideUiThread();
127 // Load chromium library.
128 AwBrowserProcess.loadLibrary(getWrappedCurrentApplicationContext());
130 final PackageInfo packageInfo = WebViewFactory.getLoadedPackageInfo();
132 // Register the handler that will append the WebView version to logcat in case of a crash.
133 AwContentsStatics.registerCrashHandler(
134 "Version " + packageInfo.versionName + " (code " + packageInfo.versionCode + ")");
136 // Load glue-layer support library.
137 System.loadLibrary("webviewchromium_plat_support");
139 // Use shared preference to check for package downgrade.
140 mWebViewPrefs = mWebViewDelegate.getApplication().getSharedPreferences(
141 CHROMIUM_PREFS_NAME, Context.MODE_PRIVATE);
142 int lastVersion = mWebViewPrefs.getInt(VERSION_CODE_PREF, 0);
143 int currentVersion = packageInfo.versionCode;
144 if (lastVersion > currentVersion) {
145 // The WebView package has been downgraded since we last ran in this application.
146 // Delete the WebView data directory's contents.
147 String dataDir = PathUtils.getDataDirectory(mWebViewDelegate.getApplication());
148 Log.i(TAG, "WebView package downgraded from " + lastVersion + " to " + currentVersion
149 + "; deleting contents of " + dataDir);
150 deleteContents(new File(dataDir));
152 if (lastVersion != currentVersion) {
153 mWebViewPrefs.edit().putInt(VERSION_CODE_PREF, currentVersion).apply();
155 // Now safe to use WebView data directory.
158 private static boolean isBuildDebuggable() {
159 return !Build.TYPE.equals("user");
162 private static void deleteContents(File dir) {
163 File[] files = dir.listFiles();
164 if (files != null) {
165 for (File file : files) {
166 if (file.isDirectory()) {
167 deleteContents(file);
169 if (!file.delete()) {
170 Log.w(TAG, "Failed to delete " + file);
176 private void initPlatSupportLibrary() {
177 DrawGLFunctor.setChromiumAwDrawGLFunction(AwContents.getAwDrawGLFunction());
178 AwContents.setAwDrawSWFunctionTable(GraphicsUtils.getDrawSWFunctionTable());
179 AwContents.setAwDrawGLFunctionTable(GraphicsUtils.getDrawGLFunctionTable());
182 private void ensureChromiumStartedLocked(boolean onMainThread) {
183 assert Thread.holdsLock(mLock);
185 if (mStarted) { // Early-out for the common case.
186 return;
189 Looper looper = !onMainThread ? Looper.myLooper() : Looper.getMainLooper();
190 Log.v(TAG, "Binding Chromium to "
191 + (Looper.getMainLooper().equals(looper) ? "main" : "background")
192 + " looper " + looper);
193 ThreadUtils.setUiThread(looper);
195 if (ThreadUtils.runningOnUiThread()) {
196 startChromiumLocked();
197 return;
200 // We must post to the UI thread to cover the case that the user has invoked Chromium
201 // startup by using the (thread-safe) CookieManager rather than creating a WebView.
202 ThreadUtils.postOnUiThread(new Runnable() {
203 @Override
204 public void run() {
205 synchronized (mLock) {
206 startChromiumLocked();
210 while (!mStarted) {
211 try {
212 // Important: wait() releases |mLock| the UI thread can take it :-)
213 mLock.wait();
214 } catch (InterruptedException e) {
215 // Keep trying... eventually the UI thread will process the task we sent it.
220 // TODO: DIR_RESOURCE_PAKS_ANDROID needs to live somewhere sensible,
221 // inlined here for simplicity setting up the HTMLViewer demo. Unfortunately
222 // it can't go into base.PathService, as the native constant it refers to
223 // lives in the ui/ layer. See ui/base/ui_base_paths.h
224 private static final int DIR_RESOURCE_PAKS_ANDROID = 3003;
226 private void startChromiumLocked() {
227 assert Thread.holdsLock(mLock) && ThreadUtils.runningOnUiThread();
229 // The post-condition of this method is everything is ready, so notify now to cover all
230 // return paths. (Other threads will not wake-up until we release |mLock|, whatever).
231 mLock.notifyAll();
233 if (mStarted) {
234 return;
237 // We don't need to extract any paks because for WebView, they are
238 // in the system image.
239 ResourceExtractor.setMandatoryPaksToExtract("");
241 try {
242 LibraryLoader.get(LibraryProcessType.PROCESS_WEBVIEW).ensureInitialized();
243 } catch (ProcessInitException e) {
244 throw new RuntimeException("Error initializing WebView library", e);
247 PathService.override(PathService.DIR_MODULE, "/system/lib/");
248 PathService.override(DIR_RESOURCE_PAKS_ANDROID, "/system/framework/webview/paks");
250 // Make sure that ResourceProvider is initialized before starting the browser process.
251 Context context = getWrappedCurrentApplicationContext();
252 setUpResources(context);
253 initPlatSupportLibrary();
254 AwBrowserProcess.start(context);
256 if (isBuildDebuggable()) {
257 setWebContentsDebuggingEnabled(true);
260 TraceEvent.setATraceEnabled(mWebViewDelegate.isTraceTagEnabled());
261 mWebViewDelegate.setOnTraceEnabledChangeListener(
262 new WebViewDelegate.OnTraceEnabledChangeListener() {
263 @Override
264 public void onTraceEnabledChange(boolean enabled) {
265 TraceEvent.setATraceEnabled(enabled);
268 mStarted = true;
270 for (WeakReference<WebViewChromium> wvc : mWebViewsToStart) {
271 WebViewChromium w = wvc.get();
272 if (w != null) {
273 w.startYourEngine();
276 mWebViewsToStart.clear();
277 mWebViewsToStart = null;
279 // Start listening for data reduction proxy setting changes.
280 mProxyManager = new AwDataReductionProxyManager();
281 mProxyManager.start(mWebViewDelegate.getApplication());
284 boolean hasStarted() {
285 return mStarted;
288 void startYourEngines(boolean onMainThread) {
289 synchronized (mLock) {
290 ensureChromiumStartedLocked(onMainThread);
294 private Context getWrappedCurrentApplicationContext() {
295 if (mWrappedAppContext == null) {
296 mWrappedAppContext = ResourcesContextWrapperFactory.get(
297 mWebViewDelegate.getApplication());
299 return mWrappedAppContext;
302 AwBrowserContext getBrowserContext() {
303 synchronized (mLock) {
304 return getBrowserContextLocked();
308 private AwBrowserContext getBrowserContextLocked() {
309 assert Thread.holdsLock(mLock);
310 assert mStarted;
311 if (mBrowserContext == null) {
312 mBrowserContext = new AwBrowserContext(mWebViewPrefs);
314 return mBrowserContext;
317 private void setWebContentsDebuggingEnabled(boolean enable) {
318 if (Looper.myLooper() != ThreadUtils.getUiThreadLooper()) {
319 throw new RuntimeException(
320 "Toggling of Web Contents Debugging must be done on the UI thread");
322 if (mDevToolsServer == null) {
323 if (!enable) return;
324 mDevToolsServer = new AwDevToolsServer();
326 mDevToolsServer.setRemoteDebuggingEnabled(enable);
329 private void setUpResources(Context context) {
330 final String packageName = WebViewFactory.getLoadedPackageInfo().packageName;
331 ResourceRewriter.rewriteRValues(
332 mWebViewDelegate.getPackageId(context.getResources(), packageName));
334 AwResource.setResources(context.getResources());
335 AwResource.setErrorPageResources(android.R.raw.loaderror, android.R.raw.nodomain);
336 AwResource.setConfigKeySystemUuidMapping(android.R.array.config_keySystemUuidMapping);
339 @Override
340 public Statics getStatics() {
341 synchronized (mLock) {
342 if (mStaticMethods == null) {
343 // TODO: Optimization potential: most these methods only need the native library
344 // loaded and initialized, not the entire browser process started.
345 // See also http://b/7009882
346 ensureChromiumStartedLocked(true);
347 mStaticMethods = new WebViewFactoryProvider.Statics() {
348 @Override
349 public String findAddress(String addr) {
350 return ContentViewStatics.findAddress(addr);
353 @Override
354 public String getDefaultUserAgent(Context context) {
355 return AwSettings.getDefaultUserAgent();
358 @Override
359 public void setWebContentsDebuggingEnabled(boolean enable) {
360 // Web Contents debugging is always enabled on debug builds.
361 if (!isBuildDebuggable()) {
362 WebViewChromiumFactoryProvider.this.setWebContentsDebuggingEnabled(
363 enable);
367 // TODO enable after L release to AOSP
368 //@Override
369 public void clearClientCertPreferences(Runnable onCleared) {
370 AwContentsStatics.clearClientCertPreferences(onCleared);
373 @Override
374 public void freeMemoryForTests() {
375 if (ActivityManager.isRunningInTestHarness()) {
376 MemoryPressureListener.maybeNotifyMemoryPresure(
377 ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
381 // TODO: Add @Override.
382 public void enableSlowWholeDocumentDraw() {
383 WebViewChromium.enableSlowWholeDocumentDraw();
386 @Override
387 public Uri[] parseFileChooserResult(int resultCode, Intent intent) {
388 return AwContentsClient.parseFileChooserResult(resultCode, intent);
393 return mStaticMethods;
396 @Override
397 public WebViewProvider createWebView(WebView webView, WebView.PrivateAccess privateAccess) {
398 WebViewChromium wvc = new WebViewChromium(this, webView, privateAccess);
400 synchronized (mLock) {
401 if (mWebViewsToStart != null) {
402 mWebViewsToStart.add(new WeakReference<WebViewChromium>(wvc));
406 return wvc;
409 @Override
410 public GeolocationPermissions getGeolocationPermissions() {
411 synchronized (mLock) {
412 if (mGeolocationPermissions == null) {
413 ensureChromiumStartedLocked(true);
414 mGeolocationPermissions = new GeolocationPermissionsAdapter(
415 getBrowserContextLocked().getGeolocationPermissions());
418 return mGeolocationPermissions;
421 @Override
422 public CookieManager getCookieManager() {
423 synchronized (mLock) {
424 if (mCookieManager == null) {
425 if (!mStarted) {
426 // We can use CookieManager without starting Chromium; the native code
427 // will bring up just the parts it needs to make this work on a temporary
428 // basis until Chromium is started for real. The temporary cookie manager
429 // needs the application context to have been set.
430 ContentMain.initApplicationContext(getWrappedCurrentApplicationContext());
432 mCookieManager = new CookieManagerAdapter(new AwCookieManager());
435 return mCookieManager;
438 @Override
439 public android.webkit.WebIconDatabase getWebIconDatabase() {
440 synchronized (mLock) {
441 if (mWebIconDatabase == null) {
442 ensureChromiumStartedLocked(true);
443 mWebIconDatabase = new WebIconDatabaseAdapter();
446 return mWebIconDatabase;
449 @Override
450 public WebStorage getWebStorage() {
451 synchronized (mLock) {
452 if (mWebStorage == null) {
453 ensureChromiumStartedLocked(true);
454 mWebStorage = new WebStorageAdapter(AwQuotaManagerBridge.getInstance());
457 return mWebStorage;
460 @Override
461 public WebViewDatabase getWebViewDatabase(Context context) {
462 synchronized (mLock) {
463 if (mWebViewDatabase == null) {
464 ensureChromiumStartedLocked(true);
465 AwBrowserContext browserContext = getBrowserContextLocked();
466 mWebViewDatabase = new WebViewDatabaseAdapter(browserContext.getFormDatabase(),
467 browserContext.getHttpAuthDatabase(context));
470 return mWebViewDatabase;
473 WebViewDelegate getWebViewDelegate() {
474 return mWebViewDelegate;