// Copyright (c) 2010 The Chromium Embedded Framework Authors. // Portions copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "libcef/cef_process_ui_thread.h" #include #include "include/cef_version.h" #include "libcef/browser_devtools_scheme_handler.h" #include "libcef/browser_webkit_glue.h" #include "libcef/browser_webkit_init.h" #include "libcef/cef_context.h" #include "libcef/scheme_registrar_impl.h" #include "libcef/v8_impl.h" #include "base/bind.h" #include "base/command_line.h" #include "base/i18n/icu_util.h" #include "base/metrics/stats_table.h" #include "base/rand_util.h" #include "base/string_number_conversions.h" #include "base/stringprintf.h" #include "build/build_config.h" #include "net/base/net_module.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebNetworkStateNotifier.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptController.h" #include "ui/base/ui_base_paths.h" #include "ui/gl/gl_implementation.h" #include "webkit/glue/webkit_glue.h" #include "webkit/plugins/npapi/plugin_list.h" #include "webkit/user_agent/user_agent.h" #include "webkit/user_agent/user_agent_util.h" #if defined(OS_WIN) #include // NOLINT(build/include_order) #include // NOLINT(build/include_order) #endif namespace { static const char* kStatsFilePrefix = "libcef_"; static int kStatsFileThreads = 20; static int kStatsFileCounters = 200; base::StringPiece ResourceProvider(int resource_id) { return _Context->GetDataResource(resource_id); } } // namespace CefProcessUIThread::CefProcessUIThread() : CefThread(CefThread::UI), statstable_(NULL), webkit_init_(NULL) {} CefProcessUIThread::CefProcessUIThread(base::MessageLoop* message_loop) : CefThread(CefThread::UI, message_loop), statstable_(NULL), webkit_init_(NULL) {} CefProcessUIThread::~CefProcessUIThread() { // We cannot rely on our base class to stop the thread since we want our // CleanUp function to run. Stop(); } void CefProcessUIThread::Init() { // Initialize the global CommandLine object. CommandLine::Init(0, NULL); // Create the blocking I/O pool before other threads. CefThread::CreateThreadPool(); const CefSettings& settings = _Context->settings(); // Initialize logging. logging::LoggingDestination logging_dest; if (settings.log_severity == LOGSEVERITY_DISABLE) { logging_dest = logging::LOG_NONE; } else { logging_dest = logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG; logging::SetMinLogLevel(settings.log_severity); } base::FilePath log_file = base::FilePath(CefString(&settings.log_file)); logging::DcheckState dcheck_state = logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS; if (settings.release_dcheck_enabled) dcheck_state = logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS; logging::InitLogging(log_file.value().c_str(), logging_dest, logging::DONT_LOCK_LOG_FILE, logging::APPEND_TO_OLD_LOG_FILE, dcheck_state); CefRefPtr schemeRegistrar( new CefSchemeRegistrarImpl()); CefRefPtr app = _Context->application(); if (app.get()) app->OnRegisterCustomSchemes(schemeRegistrar.get()); // Add built-in schemes. schemeRegistrar->AddCustomScheme(kChromeDevToolsScheme, true, false, true); // No references to the registar should be kept. schemeRegistrar->Detach(); DCHECK(schemeRegistrar->VerifyRefCount()); // Load ICU data tables. bool ret = icu_util::Initialize(); if (!ret) { #if defined(OS_WIN) MessageBox(NULL, L"Failed to load the required icudt library", L"CEF Initialization Error", MB_ICONERROR | MB_OK); #endif return; } // Provides path resolution required for locating locale pack files. ui::RegisterPathProvider(); _Context->InitializeResourceBundle(); PlatformInit(); // Initialize the blocking pool. blocking_pool_ = new base::SequencedWorkerPool(3, "BrowserBlocking"); _Context->set_blocking_pool(blocking_pool_.get()); // Initialize WebKit. webkit_init_ = new BrowserWebKitInit(); // Initialize WebKit encodings webkit_glue::InitializeTextEncoding(); // Register custom schemes with WebKit. schemeRegistrar->RegisterWithWebKit(); // Config the network module so it has access to a limited set of resources. net::NetModule::SetResourceProvider(ResourceProvider); // Load and initialize the stats table. Attempt to construct a somewhat // unique name to isolate separate instances from each other. statstable_ = new base::StatsTable( kStatsFilePrefix + base::Uint64ToString(base::RandUint64()), kStatsFileThreads, kStatsFileCounters); base::StatsTable::set_current(statstable_); if (settings.javascript_flags.length > 0) { // Pass the JavaScript flags to V8. webkit_glue::SetJavaScriptFlags(CefString(&settings.javascript_flags)); } if (settings.uncaught_exception_stack_size > 0) { v8::V8::AddMessageListener(&CefV8MessageHandler); v8::V8::SetCaptureStackTraceForUncaughtExceptions(true, settings.uncaught_exception_stack_size, v8::StackTrace::kDetailed); } #if defined(OS_WIN) if (settings.graphics_implementation == ANGLE_IN_PROCESS || settings.graphics_implementation == ANGLE_IN_PROCESS_COMMAND_BUFFER) { gfx::InitializeGLBindings(gfx::kGLImplementationEGLGLES2); } else { gfx::InitializeGLBindings(gfx::kGLImplementationDesktopGL); } #else gfx::InitializeGLBindings(gfx::kGLImplementationDesktopGL); #endif if (settings.user_agent.length > 0) { webkit_glue::SetUserAgent(CefString(&settings.user_agent), false); } else { std::string product_version; if (settings.product_version.length > 0) { product_version = CefString(&settings.product_version).ToString(); } else { product_version = base::StringPrintf("Chrome/%d.%d.%d.%d", CHROME_VERSION_MAJOR, CHROME_VERSION_MINOR, CHROME_VERSION_BUILD, CHROME_VERSION_PATCH); } webkit_glue::SetUserAgent( webkit_glue::BuildUserAgentFromProduct(product_version), false); } if (settings.extra_plugin_paths) { cef_string_t str; memset(&str, 0, sizeof(str)); base::FilePath path; int size = cef_string_list_size(settings.extra_plugin_paths); for (int i = 0; i < size; ++i) { if (!cef_string_list_value(settings.extra_plugin_paths, i, &str)) continue; path = base::FilePath(CefString(&str)); webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(path); } } // Create a network change notifier before starting the IO & File threads. network_change_notifier_.reset(net::NetworkChangeNotifier::Create()); // Add a listener for OnConnectionTypeChanged to notify WebKit of changes. net::NetworkChangeNotifier::AddConnectionTypeObserver(this); // Initialize WebKit with the current state. WebKit::WebNetworkStateNotifier::setOnLine( !net::NetworkChangeNotifier::IsOffline()); } void CefProcessUIThread::CleanUp() { // Flush any remaining messages. This ensures that any accumulated // Task objects get destroyed before we exit, which avoids noise in // purify leak-test results. base::MessageLoop::current()->RunUntilIdle(); // Tear down the shared StatsTable. base::StatsTable::set_current(NULL); delete statstable_; statstable_ = NULL; // Shut down WebKit. delete webkit_init_; webkit_init_ = NULL; // Release the network change notifier after all other threads end. net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); network_change_notifier_.reset(); // Shut down the blocking pool. _Context->set_blocking_pool(NULL); blocking_pool_->Shutdown(); blocking_pool_ = NULL; PlatformCleanUp(); _Context->CleanupResourceBundle(); // Close the blocking I/O pool after the other threads. Other threads such // as the I/O thread may need to schedule work like closing files or flushing // data during shutdown, so the blocking pool needs to be available. There // may also be slow operations pending that will blcok shutdown, so closing // it here (which will block until required operations are complete) gives // more head start for those operations to finish. CefThread::ShutdownThreadPool(); } void CefProcessUIThread::OnConnectionTypeChanged( net::NetworkChangeNotifier::ConnectionType type) { DCHECK(CefThread::CurrentlyOn(CefThread::UI)); WebKit::WebNetworkStateNotifier::setOnLine( type != net::NetworkChangeNotifier::CONNECTION_NONE); }