blob: 84a9622eae7df8d98d14abde16b8add4491d740c [file] [log] [blame]
[email protected]38d0b2d42012-01-18 03:37:341// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]b48c9182011-10-26 18:03:302// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/browser_main_loop.h"
6
[email protected]820de972012-01-03 18:23:047#include "base/bind.h"
[email protected]b48c9182011-10-26 18:03:308#include "base/command_line.h"
9#include "base/debug/trace_event.h"
[email protected]b3aabd342012-06-04 19:33:5610#include "base/hi_res_timer_manager.h"
[email protected]b48c9182011-10-26 18:03:3011#include "base/logging.h"
12#include "base/message_loop.h"
13#include "base/metrics/field_trial.h"
14#include "base/metrics/histogram.h"
[email protected]8e937c1e2012-06-28 22:57:3015#include "base/run_loop.h"
[email protected]a6381cb52012-02-13 22:39:3416#include "base/string_number_conversions.h"
[email protected]b48c9182011-10-26 18:03:3017#include "base/threading/thread_restrictions.h"
[email protected]c38831a12011-10-28 12:44:4918#include "content/browser/browser_thread_impl.h"
[email protected]99907362012-01-11 05:41:4019#include "content/browser/download/save_file_manager.h"
[email protected]ac671e782012-06-05 18:48:2020#include "content/browser/gamepad/gamepad_service.h"
[email protected]5b040e592012-02-10 02:56:1021#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
[email protected]7e343152012-09-20 21:49:5322#include "content/browser/gpu/gpu_data_manager_impl.h"
[email protected]99af54b2012-03-03 01:06:5023#include "content/browser/gpu/gpu_process_host.h"
[email protected]64d69de42012-02-06 00:19:5424#include "content/browser/gpu/gpu_process_host_ui_shim.h"
[email protected]c6ff6a32012-07-17 19:01:0125#include "content/browser/histogram_synchronizer.h"
[email protected]c2b77b2392011-12-02 13:00:1626#include "content/browser/in_process_webkit/webkit_thread.h"
[email protected]678c0362012-12-05 08:02:4427#include "content/browser/loader/resource_dispatcher_host_impl.h"
[email protected]bff327f2012-03-11 22:17:1928#include "content/browser/net/browser_online_state_observer.h"
[email protected]99907362012-01-11 05:41:4029#include "content/browser/plugin_service_impl.h"
[email protected]5a3097162012-07-06 12:03:0530#include "content/browser/renderer_host/media/media_stream_manager.h"
[email protected]28df14d2012-05-16 14:51:2231#include "content/browser/speech/speech_recognition_manager_impl.h"
[email protected]900e9122012-03-13 15:43:0832#include "content/browser/trace_controller_impl.h"
[email protected]b48c9182011-10-26 18:03:3033#include "content/public/browser/browser_main_parts.h"
[email protected]2e5b60a22011-11-28 15:56:4134#include "content/public/browser/browser_shutdown.h"
[email protected]3220d1b2012-12-08 04:13:3535#include "content/public/browser/compositor_util.h"
[email protected]b48c9182011-10-26 18:03:3036#include "content/public/browser/content_browser_client.h"
[email protected]a6381cb52012-02-13 22:39:3437#include "content/public/browser/render_process_host.h"
[email protected]b48c9182011-10-26 18:03:3038#include "content/public/common/content_switches.h"
[email protected]4573fbd2011-10-31 20:25:1839#include "content/public/common/main_function_params.h"
[email protected]b48c9182011-10-26 18:03:3040#include "content/public/common/result_codes.h"
41#include "crypto/nss_util.h"
[email protected]52e456b92012-02-23 17:13:1842#include "media/audio/audio_manager.h"
[email protected]b48c9182011-10-26 18:03:3043#include "net/base/network_change_notifier.h"
44#include "net/base/ssl_config_service.h"
45#include "net/socket/client_socket_factory.h"
46#include "net/socket/tcp_client_socket.h"
[email protected]2dd33552012-09-11 16:39:5547#include "ui/base/clipboard/clipboard.h"
[email protected]b48c9182011-10-26 18:03:3048
[email protected]894e8fc2012-02-24 13:29:5049#if defined(USE_AURA)
50#include "content/browser/renderer_host/image_transport_factory.h"
51#endif
52
[email protected]40bdb122012-11-10 03:02:3853#if defined(OS_ANDROID)
54#include "base/android/jni_android.h"
55#include "content/browser/android/surface_texture_peer_browser_impl.h"
56#include "content/browser/device_orientation/data_fetcher_impl_android.h"
57#endif
58
[email protected]b48c9182011-10-26 18:03:3059#if defined(OS_WIN)
60#include <windows.h>
61#include <commctrl.h>
[email protected]b48c9182011-10-26 18:03:3062#include <shellapi.h>
63
[email protected]cd1cd4c02011-11-15 01:59:4964#include "content/browser/system_message_window_win.h"
[email protected]6a7da762012-03-31 02:12:3365#include "content/common/sandbox_policy.h"
[email protected]b48c9182011-10-26 18:03:3066#include "ui/base/l10n/l10n_util_win.h"
67#include "net/base/winsock_init.h"
68#endif
69
[email protected]e60c0232011-11-11 19:56:3570#if defined(OS_LINUX) || defined(OS_OPENBSD)
[email protected]b48c9182011-10-26 18:03:3071#include <glib-object.h>
72#endif
73
[email protected]97646c92012-07-31 20:30:0874#if defined(OS_LINUX)
75#include "content/browser/device_monitor_linux.h"
[email protected]a34087bd2012-10-11 17:05:3076#elif defined(OS_MACOSX) && !defined(OS_IOS)
[email protected]14625442012-08-15 12:51:4277#include "content/browser/device_monitor_mac.h"
[email protected]97646c92012-07-31 20:30:0878#endif
79
[email protected]a13283cc2012-04-05 00:21:2280#if defined(TOOLKIT_GTK)
[email protected]b48c9182011-10-26 18:03:3081#include "ui/gfx/gtk_util.h"
82#endif
83
84#if defined(OS_POSIX) && !defined(OS_MACOSX)
85#include <sys/stat.h>
[email protected]094797b72012-09-15 10:51:0586
87#include "base/process_util.h"
[email protected]b48c9182011-10-26 18:03:3088#include "content/browser/renderer_host/render_sandbox_host_linux.h"
[email protected]13d6b3c2012-07-24 01:31:3189#include "content/browser/zygote_host/zygote_host_impl_linux.h"
[email protected]b48c9182011-10-26 18:03:3090#endif
91
[email protected]462d4a32012-01-19 00:11:0492#if defined(USE_X11)
93#include <X11/Xlib.h>
94#endif
95
[email protected]64d69de42012-02-06 00:19:5496// One of the linux specific headers defines this as a macro.
97#ifdef DestroyAll
98#undef DestroyAll
99#endif
100
[email protected]130757672012-10-24 00:26:19101namespace content {
[email protected]b48c9182011-10-26 18:03:30102namespace {
103
[email protected]a08029b42012-04-25 03:18:46104#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
[email protected]b48c9182011-10-26 18:03:30105void SetupSandbox(const CommandLine& parsed_command_line) {
106 // TODO(evanm): move this into SandboxWrapper; I'm just trying to move this
107 // code en masse out of chrome_main for now.
108 const char* sandbox_binary = NULL;
109 struct stat st;
110
111 // In Chromium branded builds, developers can set an environment variable to
112 // use the development sandbox. See
113 // http://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment
[email protected]094797b72012-09-15 10:51:05114 if (stat(base::kProcSelfExe, &st) == 0 && st.st_uid == getuid())
[email protected]b48c9182011-10-26 18:03:30115 sandbox_binary = getenv("CHROME_DEVEL_SANDBOX");
116
117#if defined(LINUX_SANDBOX_PATH)
118 if (!sandbox_binary)
119 sandbox_binary = LINUX_SANDBOX_PATH;
120#endif
121
122 std::string sandbox_cmd;
123 if (sandbox_binary && !parsed_command_line.HasSwitch(switches::kNoSandbox))
124 sandbox_cmd = sandbox_binary;
125
126 // Tickle the sandbox host and zygote host so they fork now.
[email protected]c2c68b1f2012-02-25 00:29:15127 RenderSandboxHostLinux::GetInstance()->Init(sandbox_cmd);
128 ZygoteHostImpl::GetInstance()->Init(sandbox_cmd);
[email protected]b48c9182011-10-26 18:03:30129}
130#endif
131
[email protected]e60c0232011-11-11 19:56:35132#if defined(OS_LINUX) || defined(OS_OPENBSD)
[email protected]b48c9182011-10-26 18:03:30133static void GLibLogHandler(const gchar* log_domain,
134 GLogLevelFlags log_level,
135 const gchar* message,
136 gpointer userdata) {
137 if (!log_domain)
138 log_domain = "<unknown>";
139 if (!message)
140 message = "<no message>";
141
142 if (strstr(message, "Loading IM context type") ||
143 strstr(message, "wrong ELF class: ELFCLASS64")) {
144 // http://crbug.com/9643
145 // Until we have a real 64-bit build or all of these 32-bit package issues
146 // are sorted out, don't fatal on ELF 32/64-bit mismatch warnings and don't
147 // spam the user with more than one of them.
148 static bool alerted = false;
149 if (!alerted) {
150 LOG(ERROR) << "Bug 9643: " << log_domain << ": " << message;
151 alerted = true;
152 }
[email protected]8a1ea192011-11-29 22:40:50153 } else if (strstr(message, "Unable to retrieve the file info for")) {
154 LOG(ERROR) << "GTK File code error: " << message;
[email protected]b48c9182011-10-26 18:03:30155 } else if (strstr(message, "Theme file for default has no") ||
156 strstr(message, "Theme directory") ||
[email protected]2bdaecf2011-12-15 02:44:55157 strstr(message, "theme pixmap") ||
158 strstr(message, "locate theme engine")) {
[email protected]b48c9182011-10-26 18:03:30159 LOG(ERROR) << "GTK theme error: " << message;
[email protected]45d8f472012-09-20 19:29:20160 } else if (strstr(message, "Unable to create Ubuntu Menu Proxy") &&
161 strstr(log_domain, "<unknown>")) {
162 LOG(ERROR) << "GTK menu proxy create failed";
[email protected]b48c9182011-10-26 18:03:30163 } else if (strstr(message, "gtk_drag_dest_leave: assertion")) {
164 LOG(ERROR) << "Drag destination deleted: http://crbug.com/18557";
165 } else if (strstr(message, "Out of memory") &&
166 strstr(log_domain, "<unknown>")) {
167 LOG(ERROR) << "DBus call timeout or out of memory: "
168 << "http://crosbug.com/15496";
169 } else if (strstr(message, "XDG_RUNTIME_DIR variable not set")) {
170 LOG(ERROR) << message << " (http://bugs.chromium.org/97293)";
[email protected]238d5c32012-11-20 02:27:40171 } else if (strstr(message, "Attempting to store changes into") ||
172 strstr(message, "Attempting to set the permissions of")) {
173 LOG(ERROR) << message << " (http://bugs.chromium.org/161366)";
[email protected]b48c9182011-10-26 18:03:30174 } else {
175 LOG(DFATAL) << log_domain << ": " << message;
176 }
177}
178
179static void SetUpGLibLogHandler() {
180 // Register GLib-handled assertions to go through our logging system.
181 const char* kLogDomains[] = { NULL, "Gtk", "Gdk", "GLib", "GLib-GObject" };
182 for (size_t i = 0; i < arraysize(kLogDomains); i++) {
183 g_log_set_handler(kLogDomains[i],
184 static_cast<GLogLevelFlags>(G_LOG_FLAG_RECURSION |
185 G_LOG_FLAG_FATAL |
186 G_LOG_LEVEL_ERROR |
187 G_LOG_LEVEL_CRITICAL |
188 G_LOG_LEVEL_WARNING),
189 GLibLogHandler,
190 NULL);
191 }
192}
193#endif
194
195} // namespace
196
[email protected]2e5b60a22011-11-28 15:56:41197// The currently-running BrowserMainLoop. There can be one or zero.
[email protected]52e456b92012-02-23 17:13:18198BrowserMainLoop* g_current_browser_main_loop = NULL;
[email protected]2e5b60a22011-11-28 15:56:41199
200// This is just to be able to keep ShutdownThreadsAndCleanUp out of
201// the public interface of BrowserMainLoop.
202class BrowserShutdownImpl {
203 public:
204 static void ImmediateShutdownAndExitProcess() {
[email protected]52e456b92012-02-23 17:13:18205 DCHECK(g_current_browser_main_loop);
206 g_current_browser_main_loop->ShutdownThreadsAndCleanUp();
[email protected]2e5b60a22011-11-28 15:56:41207
208#if defined(OS_WIN)
209 // At this point the message loop is still running yet we've shut everything
210 // down. If any messages are processed we'll likely crash. Exit now.
[email protected]130757672012-10-24 00:26:19211 ExitProcess(RESULT_CODE_NORMAL_EXIT);
[email protected]2e5b60a22011-11-28 15:56:41212#elif defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]130757672012-10-24 00:26:19213 _exit(RESULT_CODE_NORMAL_EXIT);
[email protected]2e5b60a22011-11-28 15:56:41214#else
215 NOTIMPLEMENTED();
216#endif
217 }
218};
219
220void ImmediateShutdownAndExitProcess() {
221 BrowserShutdownImpl::ImmediateShutdownAndExitProcess();
222}
[email protected]b48c9182011-10-26 18:03:30223
[email protected]52e456b92012-02-23 17:13:18224// static
[email protected]67dfea902012-04-03 01:49:09225media::AudioManager* BrowserMainLoop::GetAudioManager() {
[email protected]52e456b92012-02-23 17:13:18226 return g_current_browser_main_loop->audio_manager_.get();
227}
228
[email protected]5a3097162012-07-06 12:03:05229// static
[email protected]1d232b92012-10-29 17:39:07230MediaStreamManager* BrowserMainLoop::GetMediaStreamManager() {
[email protected]5a3097162012-07-06 12:03:05231 return g_current_browser_main_loop->media_stream_manager_.get();
232}
[email protected]e974ad292012-03-07 07:34:51233// BrowserMainLoop construction / destruction =============================
[email protected]b48c9182011-10-26 18:03:30234
[email protected]130757672012-10-24 00:26:19235BrowserMainLoop::BrowserMainLoop(const MainFunctionParams& parameters)
[email protected]b48c9182011-10-26 18:03:30236 : parameters_(parameters),
[email protected]badf5cf2011-10-29 03:44:44237 parsed_command_line_(parameters.command_line),
[email protected]130757672012-10-24 00:26:19238 result_code_(RESULT_CODE_NORMAL_EXIT) {
[email protected]52e456b92012-02-23 17:13:18239 DCHECK(!g_current_browser_main_loop);
240 g_current_browser_main_loop = this;
[email protected]b48c9182011-10-26 18:03:30241}
242
243BrowserMainLoop::~BrowserMainLoop() {
[email protected]52e456b92012-02-23 17:13:18244 DCHECK_EQ(this, g_current_browser_main_loop);
[email protected]a34087bd2012-10-11 17:05:30245#if !defined(OS_IOS)
[email protected]2dd33552012-09-11 16:39:55246 ui::Clipboard::DestroyClipboardForCurrentThread();
[email protected]a34087bd2012-10-11 17:05:30247#endif // !defined(OS_IOS)
[email protected]52e456b92012-02-23 17:13:18248 g_current_browser_main_loop = NULL;
[email protected]b48c9182011-10-26 18:03:30249}
250
251void BrowserMainLoop::Init() {
[email protected]50462bf02011-11-21 19:13:31252 parts_.reset(
253 GetContentClient()->browser()->CreateBrowserMainParts(parameters_));
[email protected]b48c9182011-10-26 18:03:30254}
255
256// BrowserMainLoop stages ==================================================
257
258void BrowserMainLoop::EarlyInitialization() {
[email protected]462d4a32012-01-19 00:11:04259#if defined(USE_X11)
260 if (parsed_command_line_.HasSwitch(switches::kSingleProcess) ||
261 parsed_command_line_.HasSwitch(switches::kInProcessGPU)) {
262 if (!XInitThreads()) {
263 LOG(ERROR) << "Failed to put Xlib into threaded mode.";
264 }
265 }
266#endif
267
[email protected]50462bf02011-11-21 19:13:31268 if (parts_.get())
269 parts_->PreEarlyInitialization();
[email protected]b48c9182011-10-26 18:03:30270
[email protected]b48c9182011-10-26 18:03:30271#if defined(OS_WIN)
272 net::EnsureWinsockInit();
273#endif
274
[email protected]1648b292011-11-03 23:57:39275#if !defined(USE_OPENSSL)
[email protected]b48c9182011-10-26 18:03:30276 // Use NSS for SSL by default.
277 // The default client socket factory uses NSS for SSL by default on
278 // Windows and Mac.
279 bool init_nspr = false;
280#if defined(OS_WIN) || defined(OS_MACOSX)
281 if (parsed_command_line_.HasSwitch(switches::kUseSystemSSL)) {
282 net::ClientSocketFactory::UseSystemSSL();
283 } else {
284 init_nspr = true;
285 }
[email protected]c4805102012-03-02 23:34:32286 UMA_HISTOGRAM_BOOLEAN("Chrome.CommandLineUseSystemSSL", !init_nspr);
[email protected]b48c9182011-10-26 18:03:30287#elif defined(USE_NSS)
288 init_nspr = true;
289#endif
290 if (init_nspr) {
291 // We want to be sure to init NSPR on the main thread.
292 crypto::EnsureNSPRInit();
293 }
[email protected]1648b292011-11-03 23:57:39294#endif // !defined(USE_OPENSSL)
[email protected]b48c9182011-10-26 18:03:30295
[email protected]a08029b42012-04-25 03:18:46296#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
[email protected]b48c9182011-10-26 18:03:30297 SetupSandbox(parsed_command_line_);
298#endif
299
[email protected]b48c9182011-10-26 18:03:30300 if (parsed_command_line_.HasSwitch(switches::kEnableSSLCachedInfo))
301 net::SSLConfigService::EnableCachedInfo();
[email protected]b48c9182011-10-26 18:03:30302
303 // TODO(abarth): Should this move to InitializeNetworkOptions? This doesn't
304 // seem dependent on SSL initialization().
305 if (parsed_command_line_.HasSwitch(switches::kEnableTcpFastOpen))
306 net::set_tcp_fastopen_enabled(true);
307
[email protected]759a86a2012-09-10 14:42:54308#if !defined(OS_IOS)
[email protected]a6381cb52012-02-13 22:39:34309 if (parsed_command_line_.HasSwitch(switches::kRendererProcessLimit)) {
310 std::string limit_string = parsed_command_line_.GetSwitchValueASCII(
311 switches::kRendererProcessLimit);
312 size_t process_limit;
313 if (base::StringToSizeT(limit_string, &process_limit)) {
[email protected]130757672012-10-24 00:26:19314 RenderProcessHost::SetMaxRendererProcessCount(process_limit);
[email protected]a6381cb52012-02-13 22:39:34315 }
316 }
[email protected]759a86a2012-09-10 14:42:54317#endif // !defined(OS_IOS)
[email protected]a6381cb52012-02-13 22:39:34318
[email protected]50462bf02011-11-21 19:13:31319 if (parts_.get())
320 parts_->PostEarlyInitialization();
[email protected]b48c9182011-10-26 18:03:30321}
322
323void BrowserMainLoop::MainMessageLoopStart() {
[email protected]50462bf02011-11-21 19:13:31324 if (parts_.get())
325 parts_->PreMainMessageLoopStart();
[email protected]b48c9182011-10-26 18:03:30326
327#if defined(OS_WIN)
328 // If we're running tests (ui_task is non-null), then the ResourceBundle
329 // has already been initialized.
[email protected]716476c2011-12-29 00:07:03330 if (!parameters_.ui_task) {
[email protected]b48c9182011-10-26 18:03:30331 // Override the configured locale with the user's preferred UI language.
332 l10n_util::OverrideLocaleWithUILanguageList();
333 }
334#endif
335
[email protected]de88c5e2012-04-10 23:35:23336 // Create a MessageLoop if one does not already exist for the current thread.
337 if (!MessageLoop::current())
[email protected]f573ed6b2012-02-10 15:58:52338 main_message_loop_.reset(new MessageLoop(MessageLoop::TYPE_UI));
[email protected]b48c9182011-10-26 18:03:30339
340 InitializeMainThread();
341
[email protected]759a86a2012-09-10 14:42:54342 system_monitor_.reset(new base::SystemMonitor);
343 hi_res_timer_manager_.reset(new HighResolutionTimerManager);
344 network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
345 audio_manager_.reset(media::AudioManager::Create());
346
347#if !defined(OS_IOS)
[email protected]50f38422011-11-09 19:21:33348 // Start tracing to a file if needed.
[email protected]900e9122012-03-13 15:43:08349 if (base::debug::TraceLog::GetInstance()->IsEnabled()) {
350 TraceControllerImpl::GetInstance()->InitStartupTracing(
351 parsed_command_line_);
352 }
[email protected]50f38422011-11-09 19:21:33353
[email protected]bff327f2012-03-11 22:17:19354 online_state_observer_.reset(new BrowserOnlineStateObserver);
[email protected]ebd71962012-12-20 02:56:55355#endif // !defined(OS_IOS)
[email protected]b48c9182011-10-26 18:03:30356
[email protected]ebd71962012-12-20 02:56:55357#if defined(ENABLE_PLUGINS)
[email protected]99907362012-01-11 05:41:40358 // Prior to any processing happening on the io thread, we create the
359 // plugin service as it is predominantly used from the io thread,
360 // but must be created on the main thread. The service ctor is
361 // inexpensive and does not invoke the io_thread() accessor.
362 PluginService::GetInstance()->Init();
[email protected]ebd71962012-12-20 02:56:55363#endif
[email protected]759a86a2012-09-10 14:42:54364
365#if defined(OS_WIN)
366 system_message_window_.reset(new SystemMessageWindowWin);
367#endif
[email protected]99907362012-01-11 05:41:40368
[email protected]50462bf02011-11-21 19:13:31369 if (parts_.get())
370 parts_->PostMainMessageLoopStart();
[email protected]40bdb122012-11-10 03:02:38371
372#if defined(OS_ANDROID)
373 SurfaceTexturePeer::InitInstance(new SurfaceTexturePeerBrowserImpl(
374 parameters_.command_line.HasSwitch(
375 switches::kMediaPlayerInRenderProcess)));
376 DataFetcherImplAndroid::Init(base::android::AttachCurrentThread());
377#endif
[email protected]b48c9182011-10-26 18:03:30378}
379
[email protected]f573ed6b2012-02-10 15:58:52380void BrowserMainLoop::CreateThreads() {
[email protected]50462bf02011-11-21 19:13:31381 if (parts_.get())
[email protected]69479b922012-02-02 09:56:20382 result_code_ = parts_->PreCreateThreads();
383
[email protected]dfd53652012-10-25 00:20:02384#if !defined(OS_IOS) && (!defined(GOOGLE_CHROME_BUILD) || defined(OS_ANDROID))
385 // Single-process is an unsupported and not fully tested mode, so
386 // don't enable it for official Chrome builds (except on Android).
387 if (parsed_command_line_.HasSwitch(switches::kSingleProcess))
388 RenderProcessHost::SetRunRendererInProcess(true);
389#endif
390
[email protected]69479b922012-02-02 09:56:20391 if (result_code_ > 0)
392 return;
[email protected]2e5b60a22011-11-28 15:56:41393
394 base::Thread::Options default_options;
395 base::Thread::Options io_message_loop_options;
396 io_message_loop_options.message_loop_type = MessageLoop::TYPE_IO;
397 base::Thread::Options ui_message_loop_options;
398 ui_message_loop_options.message_loop_type = MessageLoop::TYPE_UI;
399
400 // Start threads in the order they occur in the BrowserThread::ID
401 // enumeration, except for BrowserThread::UI which is the main
402 // thread.
403 //
404 // Must be size_t so we can increment it.
405 for (size_t thread_id = BrowserThread::UI + 1;
406 thread_id < BrowserThread::ID_COUNT;
407 ++thread_id) {
408 scoped_ptr<BrowserProcessSubThread>* thread_to_start = NULL;
409 base::Thread::Options* options = &default_options;
410
411 switch (thread_id) {
412 case BrowserThread::DB:
413 thread_to_start = &db_thread_;
414 break;
[email protected]e1dd5622011-12-20 12:28:58415 case BrowserThread::WEBKIT_DEPRECATED:
[email protected]c2b77b2392011-12-02 13:00:16416 // Special case as WebKitThread is a separate
417 // type. |thread_to_start| is not used in this case.
[email protected]2e5b60a22011-11-28 15:56:41418 break;
[email protected]31dbf9d2011-12-07 01:25:30419 case BrowserThread::FILE_USER_BLOCKING:
420 thread_to_start = &file_user_blocking_thread_;
421 break;
[email protected]2e5b60a22011-11-28 15:56:41422 case BrowserThread::FILE:
423 thread_to_start = &file_thread_;
424#if defined(OS_WIN)
425 // On Windows, the FILE thread needs to be have a UI message loop
426 // which pumps messages in such a way that Google Update can
427 // communicate back to us.
428 options = &ui_message_loop_options;
429#else
430 options = &io_message_loop_options;
431#endif
432 break;
433 case BrowserThread::PROCESS_LAUNCHER:
434 thread_to_start = &process_launcher_thread_;
435 break;
436 case BrowserThread::CACHE:
437 thread_to_start = &cache_thread_;
438 options = &io_message_loop_options;
439 break;
440 case BrowserThread::IO:
441 thread_to_start = &io_thread_;
442 options = &io_message_loop_options;
443 break;
[email protected]2e5b60a22011-11-28 15:56:41444 case BrowserThread::UI:
445 case BrowserThread::ID_COUNT:
446 default:
447 NOTREACHED();
448 break;
449 }
450
451 BrowserThread::ID id = static_cast<BrowserThread::ID>(thread_id);
452
[email protected]e1dd5622011-12-20 12:28:58453 if (thread_id == BrowserThread::WEBKIT_DEPRECATED) {
[email protected]759a86a2012-09-10 14:42:54454#if !defined(OS_IOS)
[email protected]c2b77b2392011-12-02 13:00:16455 webkit_thread_.reset(new WebKitThread);
456 webkit_thread_->Initialize();
[email protected]759a86a2012-09-10 14:42:54457#endif
[email protected]c2b77b2392011-12-02 13:00:16458 } else if (thread_to_start) {
[email protected]2e5b60a22011-11-28 15:56:41459 (*thread_to_start).reset(new BrowserProcessSubThread(id));
460 (*thread_to_start)->StartWithOptions(*options);
[email protected]c2b77b2392011-12-02 13:00:16461 } else {
462 NOTREACHED();
[email protected]2e5b60a22011-11-28 15:56:41463 }
[email protected]2e5b60a22011-11-28 15:56:41464 }
465
[email protected]99907362012-01-11 05:41:40466 BrowserThreadsStarted();
467
[email protected]2e5b60a22011-11-28 15:56:41468 if (parts_.get())
[email protected]50462bf02011-11-21 19:13:31469 parts_->PreMainMessageLoopRun();
[email protected]b48c9182011-10-26 18:03:30470
[email protected]b48c9182011-10-26 18:03:30471 // If the UI thread blocks, the whole UI is unresponsive.
472 // Do not allow disk IO from the UI thread.
473 base::ThreadRestrictions::SetIOAllowed(false);
[email protected]3a7b66d2012-04-26 16:34:16474 base::ThreadRestrictions::DisallowWaiting();
[email protected]f573ed6b2012-02-10 15:58:52475}
476
477void BrowserMainLoop::RunMainMessageLoopParts() {
478 TRACE_EVENT_BEGIN_ETW("BrowserMain:MESSAGE_LOOP", 0, "");
[email protected]b48c9182011-10-26 18:03:30479
[email protected]b48c9182011-10-26 18:03:30480 bool ran_main_loop = false;
[email protected]50462bf02011-11-21 19:13:31481 if (parts_.get())
482 ran_main_loop = parts_->MainMessageLoopRun(&result_code_);
483
[email protected]b48c9182011-10-26 18:03:30484 if (!ran_main_loop)
485 MainMessageLoopRun();
486
487 TRACE_EVENT_END_ETW("BrowserMain:MESSAGE_LOOP", 0, "");
[email protected]2e5b60a22011-11-28 15:56:41488}
489
490void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
491 // Teardown may start in PostMainMessageLoopRun, and during teardown we
492 // need to be able to perform IO.
493 base::ThreadRestrictions::SetIOAllowed(true);
494 BrowserThread::PostTask(
[email protected]8f5a7e492012-01-01 02:14:47495 BrowserThread::IO, FROM_HERE,
[email protected]71cb8aa2011-12-29 19:14:00496 base::Bind(base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed),
497 true));
[email protected]2e5b60a22011-11-28 15:56:41498
[email protected]50462bf02011-11-21 19:13:31499 if (parts_.get())
500 parts_->PostMainMessageLoopRun();
[email protected]2e5b60a22011-11-28 15:56:41501
[email protected]759a86a2012-09-10 14:42:54502#if !defined(OS_IOS)
[email protected]64d69de42012-02-06 00:19:54503 // Destroying the GpuProcessHostUIShims on the UI thread posts a task to
504 // delete related objects on the GPU thread. This must be done before
505 // stopping the GPU thread. The GPU thread will close IPC channels to renderer
506 // processes so this has to happen before stopping the IO thread.
507 GpuProcessHostUIShim::DestroyAll();
508
[email protected]99907362012-01-11 05:41:40509 // Cancel pending requests and prevent new requests.
510 if (resource_dispatcher_host_.get())
511 resource_dispatcher_host_.get()->Shutdown();
512
[email protected]894e8fc2012-02-24 13:29:50513#if defined(USE_AURA)
514 ImageTransportFactory::Terminate();
515#endif
[email protected]5b040e592012-02-10 02:56:10516 BrowserGpuChannelHostFactory::Terminate();
517
[email protected]14625442012-08-15 12:51:42518 // The device monitors are using |system_monitor_| as dependency, so delete
519 // them before |system_monitor_| goes away.
520 // On Mac and windows, the monitor needs to be destroyed on the same thread
521 // as they were created. On Linux, the monitor will be deleted when IO thread
522 // goes away.
523#if defined(OS_WIN)
524 system_message_window_.reset();
525#elif defined(OS_MACOSX)
526 device_monitor_mac_.reset();
527#endif
[email protected]759a86a2012-09-10 14:42:54528#endif // !defined(OS_IOS)
[email protected]14625442012-08-15 12:51:42529
[email protected]2e5b60a22011-11-28 15:56:41530 // Must be size_t so we can subtract from it.
531 for (size_t thread_id = BrowserThread::ID_COUNT - 1;
532 thread_id >= (BrowserThread::UI + 1);
533 --thread_id) {
534 // Find the thread object we want to stop. Looping over all valid
535 // BrowserThread IDs and DCHECKing on a missing case in the switch
536 // statement helps avoid a mismatch between this code and the
537 // BrowserThread::ID enumeration.
538 //
539 // The destruction order is the reverse order of occurrence in the
540 // BrowserThread::ID list. The rationale for the order is as
541 // follows (need to be filled in a bit):
542 //
[email protected]2e5b60a22011-11-28 15:56:41543 //
544 // - The IO thread is the only user of the CACHE thread.
545 //
546 // - The PROCESS_LAUNCHER thread must be stopped after IO in case
547 // the IO thread posted a task to terminate a process on the
548 // process launcher thread.
549 //
550 // - (Not sure why FILE needs to stop before WEBKIT.)
551 //
552 // - The WEBKIT thread (which currently is the responsibility of
553 // the embedder to stop, by destroying ResourceDispatcherHost
554 // before the DB thread is stopped)
555 //
556 // - (Not sure why DB stops last.)
557 scoped_ptr<BrowserProcessSubThread>* thread_to_stop = NULL;
558 switch (thread_id) {
559 case BrowserThread::DB:
560 thread_to_stop = &db_thread_;
561 break;
[email protected]e1dd5622011-12-20 12:28:58562 case BrowserThread::WEBKIT_DEPRECATED:
[email protected]c2b77b2392011-12-02 13:00:16563 // Special case as WebKitThread is a separate
564 // type. |thread_to_stop| is not used in this case.
[email protected]99907362012-01-11 05:41:40565
566 // Need to destroy ResourceDispatcherHost before PluginService
567 // and since it caches a pointer to it.
568 resource_dispatcher_host_.reset();
[email protected]2e5b60a22011-11-28 15:56:41569 break;
[email protected]31dbf9d2011-12-07 01:25:30570 case BrowserThread::FILE_USER_BLOCKING:
571 thread_to_stop = &file_user_blocking_thread_;
572 break;
[email protected]2e5b60a22011-11-28 15:56:41573 case BrowserThread::FILE:
574 thread_to_stop = &file_thread_;
[email protected]99907362012-01-11 05:41:40575
[email protected]759a86a2012-09-10 14:42:54576#if !defined(OS_IOS)
[email protected]99907362012-01-11 05:41:40577 // Clean up state that lives on or uses the file_thread_ before
578 // it goes away.
[email protected]53ac00e82012-10-18 20:59:20579 if (resource_dispatcher_host_.get())
[email protected]99907362012-01-11 05:41:40580 resource_dispatcher_host_.get()->save_file_manager()->Shutdown();
[email protected]759a86a2012-09-10 14:42:54581#endif // !defined(OS_IOS)
[email protected]2e5b60a22011-11-28 15:56:41582 break;
583 case BrowserThread::PROCESS_LAUNCHER:
584 thread_to_stop = &process_launcher_thread_;
585 break;
586 case BrowserThread::CACHE:
587 thread_to_stop = &cache_thread_;
588 break;
589 case BrowserThread::IO:
590 thread_to_stop = &io_thread_;
591 break;
[email protected]2e5b60a22011-11-28 15:56:41592 case BrowserThread::UI:
593 case BrowserThread::ID_COUNT:
594 default:
595 NOTREACHED();
596 break;
597 }
598
599 BrowserThread::ID id = static_cast<BrowserThread::ID>(thread_id);
600
[email protected]e1dd5622011-12-20 12:28:58601 if (id == BrowserThread::WEBKIT_DEPRECATED) {
[email protected]759a86a2012-09-10 14:42:54602#if !defined(OS_IOS)
[email protected]c2b77b2392011-12-02 13:00:16603 webkit_thread_.reset();
[email protected]759a86a2012-09-10 14:42:54604#endif
[email protected]c2b77b2392011-12-02 13:00:16605 } else if (thread_to_stop) {
[email protected]2e5b60a22011-11-28 15:56:41606 thread_to_stop->reset();
[email protected]c2b77b2392011-12-02 13:00:16607 } else {
608 NOTREACHED();
609 }
[email protected]2e5b60a22011-11-28 15:56:41610 }
611
[email protected]3189013e2012-01-19 04:11:57612 // Close the blocking I/O pool after the other threads. Other threads such
613 // as the I/O thread may need to schedule work like closing files or flushing
614 // data during shutdown, so the blocking pool needs to be available. There
615 // may also be slow operations pending that will blcok shutdown, so closing
616 // it here (which will block until required operations are complete) gives
617 // more head start for those operations to finish.
618 BrowserThreadImpl::ShutdownThreadPool();
619
[email protected]a34087bd2012-10-11 17:05:30620#if !defined(OS_IOS)
[email protected]00c0d042012-09-10 07:06:39621 // Must happen after the I/O thread is shutdown since this class lives on the
622 // I/O thread and isn't threadsafe.
623 GamepadService::GetInstance()->Terminate();
[email protected]a34087bd2012-10-11 17:05:30624#endif // !defined(OS_IOS)
[email protected]00c0d042012-09-10 07:06:39625
[email protected]2e5b60a22011-11-28 15:56:41626 if (parts_.get())
627 parts_->PostDestroyThreads();
[email protected]b48c9182011-10-26 18:03:30628}
629
630void BrowserMainLoop::InitializeMainThread() {
631 const char* kThreadName = "CrBrowserMain";
632 base::PlatformThread::SetName(kThreadName);
[email protected]de88c5e2012-04-10 23:35:23633 if (main_message_loop_.get())
634 main_message_loop_->set_thread_name(kThreadName);
[email protected]b48c9182011-10-26 18:03:30635
636 // Register the main thread by instantiating it, but don't call any methods.
[email protected]c38831a12011-10-28 12:44:49637 main_thread_.reset(new BrowserThreadImpl(BrowserThread::UI,
638 MessageLoop::current()));
[email protected]b48c9182011-10-26 18:03:30639}
640
[email protected]99907362012-01-11 05:41:40641
642void BrowserMainLoop::BrowserThreadsStarted() {
[email protected]759a86a2012-09-10 14:42:54643#if !defined(OS_IOS)
[email protected]c6ff6a32012-07-17 19:01:01644 HistogramSynchronizer::GetInstance();
645
[email protected]130757672012-10-24 00:26:19646 BrowserGpuChannelHostFactory::Initialize();
[email protected]c6ff6a32012-07-17 19:01:01647#if defined(USE_AURA)
648 ImageTransportFactory::Initialize();
649#endif
650
[email protected]97646c92012-07-31 20:30:08651#if defined(OS_LINUX)
652 device_monitor_linux_.reset(new DeviceMonitorLinux());
[email protected]14625442012-08-15 12:51:42653#elif defined(OS_MACOSX)
654 device_monitor_mac_.reset(new DeviceMonitorMac());
[email protected]97646c92012-07-31 20:30:08655#endif
656
[email protected]99907362012-01-11 05:41:40657 // RDH needs the IO thread to be created.
[email protected]ea114722012-03-12 01:11:25658 resource_dispatcher_host_.reset(new ResourceDispatcherHostImpl());
[email protected]b14b873b2012-05-03 03:56:09659
[email protected]89c6eaf2012-11-26 18:52:27660 // MediaStreamManager needs the IO thread to be created.
661 media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get()));
662
[email protected]7e343152012-09-20 21:49:53663 // Initialize the GpuDataManager before we set up the MessageLoops because
[email protected]b14b873b2012-05-03 03:56:09664 // otherwise we'll trigger the assertion about doing IO on the UI thread.
[email protected]7e343152012-09-20 21:49:53665 GpuDataManagerImpl::GetInstance()->Initialize();
[email protected]759a86a2012-09-10 14:42:54666#endif // !OS_IOS
667
668#if defined(ENABLE_INPUT_SPEECH)
[email protected]fcb8e0212012-10-29 11:57:18669 speech_recognition_manager_.reset(new SpeechRecognitionManagerImpl());
[email protected]759a86a2012-09-10 14:42:54670#endif
[email protected]2dd33552012-09-11 16:39:55671
[email protected]a34087bd2012-10-11 17:05:30672#if !defined(OS_IOS)
[email protected]2dd33552012-09-11 16:39:55673 // Alert the clipboard class to which threads are allowed to access the
674 // clipboard:
675 std::vector<base::PlatformThreadId> allowed_clipboard_threads;
676 // The current thread is the UI thread.
677 allowed_clipboard_threads.push_back(base::PlatformThread::CurrentId());
678#if defined(OS_WIN)
679 // On Windows, clipboards are also used on the File or IO threads.
680 allowed_clipboard_threads.push_back(file_thread_->thread_id());
681 allowed_clipboard_threads.push_back(io_thread_->thread_id());
682#endif
683 ui::Clipboard::SetAllowedThreads(allowed_clipboard_threads);
[email protected]3220d1b2012-12-08 04:13:35684
685 // When running the GPU thread in-process, avoid optimistically starting it
686 // since creating the GPU thread races against creation of the one-and-only
687 // ChildProcess instance which is created by the renderer thread.
688 if (GpuDataManagerImpl::GetInstance()->GpuAccessAllowed() &&
689 content::IsForceCompositingModeEnabled() &&
690 !parsed_command_line_.HasSwitch(switches::kDisableGpuProcessPrelaunch) &&
691 !parsed_command_line_.HasSwitch(switches::kSingleProcess) &&
692 !parsed_command_line_.HasSwitch(switches::kInProcessGPU)) {
693 TRACE_EVENT_INSTANT0("gpu", "Post task to launch GPU process");
694 BrowserThread::PostTask(
695 BrowserThread::IO, FROM_HERE, base::Bind(
696 base::IgnoreResult(&GpuProcessHost::Get),
697 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
698 CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP));
699 }
[email protected]a34087bd2012-10-11 17:05:30700#endif // !defined(OS_IOS)
[email protected]99907362012-01-11 05:41:40701}
702
[email protected]b48c9182011-10-26 18:03:30703void BrowserMainLoop::InitializeToolkit() {
704 // TODO(evan): this function is rather subtle, due to the variety
705 // of intersecting ifdefs we have. To keep it easy to follow, there
706 // are no #else branches on any #ifs.
707 // TODO(stevenjb): Move platform specific code into platform specific Parts
708 // (Need to add InitializeToolkit stage to BrowserParts).
[email protected]e60c0232011-11-11 19:56:35709#if defined(OS_LINUX) || defined(OS_OPENBSD)
[email protected]b48c9182011-10-26 18:03:30710 // Glib type system initialization. Needed at least for gconf,
711 // used in net/proxy/proxy_config_service_linux.cc. Most likely
712 // this is superfluous as gtk_init() ought to do this. It's
713 // definitely harmless, so retained as a reminder of this
714 // requirement for gconf.
715 g_type_init();
716
[email protected]b48c9182011-10-26 18:03:30717#if !defined(USE_AURA)
[email protected]38d0b2d42012-01-18 03:37:34718 gfx::GtkInitFromCommandLine(parsed_command_line_);
[email protected]b48c9182011-10-26 18:03:30719#endif
720
721 SetUpGLibLogHandler();
722#endif
723
724#if defined(TOOLKIT_GTK)
725 // It is important for this to happen before the first run dialog, as it
726 // styles the dialog as well.
727 gfx::InitRCStyles();
728#endif
729
730#if defined(OS_WIN)
731 // Init common control sex.
732 INITCOMMONCONTROLSEX config;
733 config.dwSize = sizeof(config);
734 config.dwICC = ICC_WIN95_CLASSES;
735 if (!InitCommonControlsEx(&config))
736 LOG_GETLASTERROR(FATAL);
737#endif
738
[email protected]50462bf02011-11-21 19:13:31739 if (parts_.get())
740 parts_->ToolkitInitialized();
[email protected]b48c9182011-10-26 18:03:30741}
742
743void BrowserMainLoop::MainMessageLoopRun() {
[email protected]8e937c1e2012-06-28 22:57:30744#if defined(OS_ANDROID)
[email protected]a08029b42012-04-25 03:18:46745 // Android's main message loop is the Java message loop.
746 NOTREACHED();
[email protected]b48c9182011-10-26 18:03:30747#else
[email protected]8e937c1e2012-06-28 22:57:30748 DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
749 if (parameters_.ui_task)
750 MessageLoopForUI::current()->PostTask(FROM_HERE, *parameters_.ui_task);
751
752 base::RunLoop run_loop;
753 run_loop.Run();
[email protected]b48c9182011-10-26 18:03:30754#endif
755}
756
757} // namespace content