1 // Copyright (c) 2012 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. 4 5 #include "content/browser/browser_main_loop.h" 6 7 #include "base/bind.h" 8 #include "base/command_line.h" 9 #include "base/debug/trace_event.h" 10 #include "base/file_util.h" 11 #include "base/logging.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/metrics/field_trial.h" 14 #include "base/metrics/histogram.h" 15 #include "base/path_service.h" 16 #include "base/pending_task.h" 17 #include "base/power_monitor/power_monitor.h" 18 #include "base/power_monitor/power_monitor_device_source.h" 19 #include "base/process/process_metrics.h" 20 #include "base/run_loop.h" 21 #include "base/strings/string_number_conversions.h" 22 #include "base/system_monitor/system_monitor.h" 23 #include "base/threading/thread_restrictions.h" 24 #include "base/timer/hi_res_timer_manager.h" 25 #include "content/browser/browser_thread_impl.h" 26 #include "content/browser/device_orientation/device_motion_service.h" 27 #include "content/browser/download/save_file_manager.h" 28 #include "content/browser/gamepad/gamepad_service.h" 29 #include "content/browser/gpu/browser_gpu_channel_host_factory.h" 30 #include "content/browser/gpu/gpu_data_manager_impl.h" 31 #include "content/browser/gpu/gpu_process_host.h" 32 #include "content/browser/gpu/gpu_process_host_ui_shim.h" 33 #include "content/browser/histogram_synchronizer.h" 34 #include "content/browser/loader/resource_dispatcher_host_impl.h" 35 #include "content/browser/net/browser_online_state_observer.h" 36 #include "content/browser/plugin_service_impl.h" 37 #include "content/browser/renderer_host/media/audio_mirroring_manager.h" 38 #include "content/browser/renderer_host/media/media_stream_manager.h" 39 #include "content/browser/speech/speech_recognition_manager_impl.h" 40 #include "content/browser/startup_task_runner.h" 41 #include "content/browser/tracing/trace_controller_impl.h" 42 #include "content/browser/webui/content_web_ui_controller_factory.h" 43 #include "content/browser/webui/url_data_manager.h" 44 #include "content/public/browser/browser_main_parts.h" 45 #include "content/public/browser/browser_shutdown.h" 46 #include "content/public/browser/compositor_util.h" 47 #include "content/public/browser/content_browser_client.h" 48 #include "content/public/browser/render_process_host.h" 49 #include "content/public/common/content_switches.h" 50 #include "content/public/common/main_function_params.h" 51 #include "content/public/common/result_codes.h" 52 #include "crypto/nss_util.h" 53 #include "media/audio/audio_manager.h" 54 #include "media/base/media.h" 55 #include "media/midi/midi_manager.h" 56 #include "net/base/network_change_notifier.h" 57 #include "net/socket/client_socket_factory.h" 58 #include "net/ssl/ssl_config_service.h" 59 #include "ui/base/clipboard/clipboard.h" 60 61 #if defined(USE_AURA) 62 #include "content/browser/aura/image_transport_factory.h" 63 #endif 64 65 #if defined(OS_ANDROID) 66 #include "base/android/jni_android.h" 67 #include "content/browser/android/browser_startup_config.h" 68 #include "content/browser/android/surface_texture_peer_browser_impl.h" 69 #endif 70 71 #if defined(OS_WIN) 72 #include <windows.h> 73 #include <commctrl.h> 74 #include <shellapi.h> 75 76 #include "base/win/text_services_message_filter.h" 77 #include "content/browser/system_message_window_win.h" 78 #include "content/common/sandbox_win.h" 79 #include "net/base/winsock_init.h" 80 #include "ui/base/l10n/l10n_util_win.h" 81 #endif 82 83 #if defined(OS_LINUX) || defined(OS_OPENBSD) 84 #include <glib-object.h> 85 #endif 86 87 #if defined(OS_LINUX) 88 #include "content/browser/device_monitor_linux.h" 89 #elif defined(OS_MACOSX) && !defined(OS_IOS) 90 #include "content/browser/device_monitor_mac.h" 91 #endif 92 93 #if defined(TOOLKIT_GTK) 94 #include "ui/gfx/gtk_util.h" 95 #endif 96 97 #if defined(OS_POSIX) && !defined(OS_MACOSX) 98 #include <sys/stat.h> 99 100 #include "content/browser/renderer_host/render_sandbox_host_linux.h" 101 #include "content/browser/zygote_host/zygote_host_impl_linux.h" 102 #endif 103 104 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) 105 #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" 106 #endif 107 108 #if defined(USE_X11) 109 #include <X11/Xlib.h> 110 #endif 111 112 // One of the linux specific headers defines this as a macro. 113 #ifdef DestroyAll 114 #undef DestroyAll 115 #endif 116 117 namespace content { 118 namespace { 119 120 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 121 void SetupSandbox(const CommandLine& parsed_command_line) { 122 TRACE_EVENT0("startup", "SetupSandbox"); 123 // TODO(evanm): move this into SandboxWrapper; I'm just trying to move this 124 // code en masse out of chrome_main for now. 125 base::FilePath sandbox_binary; 126 bool env_chrome_devel_sandbox_set = false; 127 struct stat st; 128 129 const bool want_setuid_sandbox = 130 !parsed_command_line.HasSwitch(switches::kNoSandbox) && 131 !parsed_command_line.HasSwitch(switches::kDisableSetuidSandbox); 132 133 if (want_setuid_sandbox) { 134 base::FilePath exe_dir; 135 if (PathService::Get(base::DIR_EXE, &exe_dir)) { 136 base::FilePath sandbox_candidate = exe_dir.AppendASCII("chrome-sandbox"); 137 if (base::PathExists(sandbox_candidate)) 138 sandbox_binary = sandbox_candidate; 139 } 140 141 // In user-managed builds, including development builds, an environment 142 // variable is required to enable the sandbox. See 143 // http://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment 144 if (sandbox_binary.empty() && 145 stat(base::kProcSelfExe, &st) == 0 && st.st_uid == getuid()) { 146 const char* devel_sandbox_path = getenv("CHROME_DEVEL_SANDBOX"); 147 if (devel_sandbox_path) { 148 env_chrome_devel_sandbox_set = true; 149 sandbox_binary = base::FilePath(devel_sandbox_path); 150 } 151 } 152 153 static const char no_suid_error[] = "Running without the SUID sandbox! See " 154 "https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment " 155 "for more information on developing with the sandbox on."; 156 if (sandbox_binary.empty()) { 157 if (!env_chrome_devel_sandbox_set) { 158 // This needs to be fatal. Talk to security (at) chromium.org if you feel 159 // otherwise. 160 LOG(FATAL) << no_suid_error; 161 } 162 163 // TODO(jln): an empty CHROME_DEVEL_SANDBOX environment variable (as 164 // opposed to a non existing one) is not fatal yet. This is needed 165 // because of existing bots and scripts. Fix it (crbug.com/245376). 166 LOG(ERROR) << no_suid_error; 167 } 168 } 169 170 // Tickle the sandbox host and zygote host so they fork now. 171 RenderSandboxHostLinux::GetInstance()->Init(sandbox_binary.value()); 172 ZygoteHostImpl::GetInstance()->Init(sandbox_binary.value()); 173 } 174 #endif 175 176 #if defined(OS_LINUX) || defined(OS_OPENBSD) 177 static void GLibLogHandler(const gchar* log_domain, 178 GLogLevelFlags log_level, 179 const gchar* message, 180 gpointer userdata) { 181 if (!log_domain) 182 log_domain = "<unknown>"; 183 if (!message) 184 message = "<no message>"; 185 186 if (strstr(message, "Loading IM context type") || 187 strstr(message, "wrong ELF class: ELFCLASS64")) { 188 // http://crbug.com/9643 189 // Until we have a real 64-bit build or all of these 32-bit package issues 190 // are sorted out, don't fatal on ELF 32/64-bit mismatch warnings and don't 191 // spam the user with more than one of them. 192 static bool alerted = false; 193 if (!alerted) { 194 LOG(ERROR) << "Bug 9643: " << log_domain << ": " << message; 195 alerted = true; 196 } 197 } else if (strstr(message, "Unable to retrieve the file info for")) { 198 LOG(ERROR) << "GTK File code error: " << message; 199 } else if (strstr(message, "Could not find the icon") && 200 strstr(log_domain, "Gtk")) { 201 LOG(ERROR) << "GTK icon error: " << message; 202 } else if (strstr(message, "Theme file for default has no") || 203 strstr(message, "Theme directory") || 204 strstr(message, "theme pixmap") || 205 strstr(message, "locate theme engine")) { 206 LOG(ERROR) << "GTK theme error: " << message; 207 } else if (strstr(message, "Unable to create Ubuntu Menu Proxy") && 208 strstr(log_domain, "<unknown>")) { 209 LOG(ERROR) << "GTK menu proxy create failed"; 210 } else if (strstr(message, "gtk_drag_dest_leave: assertion")) { 211 LOG(ERROR) << "Drag destination deleted: http://crbug.com/18557"; 212 } else if (strstr(message, "Out of memory") && 213 strstr(log_domain, "<unknown>")) { 214 LOG(ERROR) << "DBus call timeout or out of memory: " 215 << "http://crosbug.com/15496"; 216 } else if (strstr(message, "Could not connect: Connection refused") && 217 strstr(log_domain, "<unknown>")) { 218 LOG(ERROR) << "DConf settings backend could not connect to session bus: " 219 << "http://crbug.com/179797"; 220 } else if (strstr(message, "XDG_RUNTIME_DIR variable not set")) { 221 LOG(ERROR) << message << " (http://bugs.chromium.org/97293)"; 222 } else if (strstr(message, "Attempting to store changes into") || 223 strstr(message, "Attempting to set the permissions of")) { 224 LOG(ERROR) << message << " (http://bugs.chromium.org/161366)"; 225 } else { 226 LOG(DFATAL) << log_domain << ": " << message; 227 } 228 } 229 230 static void SetUpGLibLogHandler() { 231 // Register GLib-handled assertions to go through our logging system. 232 const char* kLogDomains[] = { NULL, "Gtk", "Gdk", "GLib", "GLib-GObject" }; 233 for (size_t i = 0; i < arraysize(kLogDomains); i++) { 234 g_log_set_handler(kLogDomains[i], 235 static_cast<GLogLevelFlags>(G_LOG_FLAG_RECURSION | 236 G_LOG_FLAG_FATAL | 237 G_LOG_LEVEL_ERROR | 238 G_LOG_LEVEL_CRITICAL | 239 G_LOG_LEVEL_WARNING), 240 GLibLogHandler, 241 NULL); 242 } 243 } 244 #endif 245 246 } // namespace 247 248 // The currently-running BrowserMainLoop. There can be one or zero. 249 BrowserMainLoop* g_current_browser_main_loop = NULL; 250 251 // This is just to be able to keep ShutdownThreadsAndCleanUp out of 252 // the public interface of BrowserMainLoop. 253 class BrowserShutdownImpl { 254 public: 255 static void ImmediateShutdownAndExitProcess() { 256 DCHECK(g_current_browser_main_loop); 257 g_current_browser_main_loop->ShutdownThreadsAndCleanUp(); 258 259 #if defined(OS_WIN) 260 // At this point the message loop is still running yet we've shut everything 261 // down. If any messages are processed we'll likely crash. Exit now. 262 ExitProcess(RESULT_CODE_NORMAL_EXIT); 263 #elif defined(OS_POSIX) && !defined(OS_MACOSX) 264 _exit(RESULT_CODE_NORMAL_EXIT); 265 #else 266 NOTIMPLEMENTED(); 267 #endif 268 } 269 }; 270 271 void ImmediateShutdownAndExitProcess() { 272 BrowserShutdownImpl::ImmediateShutdownAndExitProcess(); 273 } 274 275 // For measuring memory usage after each task. Behind a command line flag. 276 class BrowserMainLoop::MemoryObserver : public base::MessageLoop::TaskObserver { 277 public: 278 MemoryObserver() {} 279 virtual ~MemoryObserver() {} 280 281 virtual void WillProcessTask(const base::PendingTask& pending_task) OVERRIDE { 282 } 283 284 virtual void DidProcessTask(const base::PendingTask& pending_task) OVERRIDE { 285 #if !defined(OS_IOS) // No ProcessMetrics on IOS. 286 scoped_ptr<base::ProcessMetrics> process_metrics( 287 base::ProcessMetrics::CreateProcessMetrics( 288 #if defined(OS_MACOSX) 289 base::GetCurrentProcessHandle(), NULL)); 290 #else 291 base::GetCurrentProcessHandle())); 292 #endif 293 size_t private_bytes; 294 process_metrics->GetMemoryBytes(&private_bytes, NULL); 295 HISTOGRAM_MEMORY_KB("Memory.BrowserUsed", private_bytes >> 10); 296 #endif 297 } 298 private: 299 DISALLOW_COPY_AND_ASSIGN(MemoryObserver); 300 }; 301 302 303 // BrowserMainLoop construction / destruction ============================= 304 305 BrowserMainLoop* BrowserMainLoop::GetInstance() { 306 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 307 return g_current_browser_main_loop; 308 } 309 310 BrowserMainLoop::BrowserMainLoop(const MainFunctionParams& parameters) 311 : parameters_(parameters), 312 parsed_command_line_(parameters.command_line), 313 result_code_(RESULT_CODE_NORMAL_EXIT), 314 created_threads_(false) { 315 DCHECK(!g_current_browser_main_loop); 316 g_current_browser_main_loop = this; 317 } 318 319 BrowserMainLoop::~BrowserMainLoop() { 320 DCHECK_EQ(this, g_current_browser_main_loop); 321 #if !defined(OS_IOS) 322 ui::Clipboard::DestroyClipboardForCurrentThread(); 323 #endif // !defined(OS_IOS) 324 g_current_browser_main_loop = NULL; 325 } 326 327 void BrowserMainLoop::Init() { 328 TRACE_EVENT0("startup", "BrowserMainLoop::Init") 329 parts_.reset( 330 GetContentClient()->browser()->CreateBrowserMainParts(parameters_)); 331 } 332 333 // BrowserMainLoop stages ================================================== 334 335 void BrowserMainLoop::EarlyInitialization() { 336 TRACE_EVENT0("startup", "BrowserMainLoop::EarlyInitialization"); 337 #if defined(USE_X11) 338 if (parsed_command_line_.HasSwitch(switches::kSingleProcess) || 339 parsed_command_line_.HasSwitch(switches::kInProcessGPU)) { 340 if (!XInitThreads()) { 341 LOG(ERROR) << "Failed to put Xlib into threaded mode."; 342 } 343 } 344 #endif 345 346 if (parts_) 347 parts_->PreEarlyInitialization(); 348 349 #if defined(OS_WIN) 350 net::EnsureWinsockInit(); 351 #endif 352 353 #if !defined(USE_OPENSSL) 354 // We want to be sure to init NSPR on the main thread. 355 crypto::EnsureNSPRInit(); 356 #endif // !defined(USE_OPENSSL) 357 358 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 359 SetupSandbox(parsed_command_line_); 360 #endif 361 362 if (parsed_command_line_.HasSwitch(switches::kEnableSSLCachedInfo)) 363 net::SSLConfigService::EnableCachedInfo(); 364 365 #if !defined(OS_IOS) 366 if (parsed_command_line_.HasSwitch(switches::kRendererProcessLimit)) { 367 std::string limit_string = parsed_command_line_.GetSwitchValueASCII( 368 switches::kRendererProcessLimit); 369 size_t process_limit; 370 if (base::StringToSizeT(limit_string, &process_limit)) { 371 RenderProcessHost::SetMaxRendererProcessCount(process_limit); 372 } 373 } 374 #endif // !defined(OS_IOS) 375 376 if (parts_) 377 parts_->PostEarlyInitialization(); 378 } 379 380 void BrowserMainLoop::MainMessageLoopStart() { 381 TRACE_EVENT0("startup", "BrowserMainLoop::MainMessageLoopStart") 382 if (parts_) { 383 TRACE_EVENT0("startup", 384 "BrowserMainLoop::MainMessageLoopStart:PreMainMessageLoopStart"); 385 parts_->PreMainMessageLoopStart(); 386 } 387 388 #if defined(OS_WIN) 389 // If we're running tests (ui_task is non-null), then the ResourceBundle 390 // has already been initialized. 391 if (!parameters_.ui_task) { 392 // Override the configured locale with the user's preferred UI language. 393 l10n_util::OverrideLocaleWithUILanguageList(); 394 } 395 #endif 396 397 // Create a MessageLoop if one does not already exist for the current thread. 398 if (!base::MessageLoop::current()) 399 main_message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_UI)); 400 401 InitializeMainThread(); 402 403 { 404 TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:SystemMonitor") 405 system_monitor_.reset(new base::SystemMonitor); 406 } 407 { 408 TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:PowerMonitor") 409 scoped_ptr<base::PowerMonitorSource> power_monitor_source( 410 new base::PowerMonitorDeviceSource()); 411 power_monitor_.reset(new base::PowerMonitor(power_monitor_source.Pass())); 412 } 413 { 414 TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:HighResTimerManager") 415 hi_res_timer_manager_.reset(new base::HighResolutionTimerManager); 416 } 417 { 418 TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:NetworkChangeNotifier") 419 network_change_notifier_.reset(net::NetworkChangeNotifier::Create()); 420 } 421 422 { 423 TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:MediaFeatures") 424 media::InitializeCPUSpecificMediaFeatures(); 425 } 426 { 427 TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:AudioMan") 428 audio_manager_.reset(media::AudioManager::Create()); 429 } 430 { 431 TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:MIDIManager") 432 midi_manager_.reset(media::MIDIManager::Create()); 433 } 434 435 #if !defined(OS_IOS) 436 { 437 TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:ContentWebUIController") 438 WebUIControllerFactory::RegisterFactory( 439 ContentWebUIControllerFactory::GetInstance()); 440 } 441 442 { 443 TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:AudioMirroringManager") 444 audio_mirroring_manager_.reset(new AudioMirroringManager()); 445 } 446 447 // Start tracing to a file if needed. 448 if (base::debug::TraceLog::GetInstance()->IsEnabled()) { 449 TRACE_EVENT0("startup", "BrowserMainLoop::InitStartupTracing") 450 TraceControllerImpl::GetInstance()->InitStartupTracing( 451 parsed_command_line_); 452 } 453 454 { 455 TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:OnlineStateObserver") 456 online_state_observer_.reset(new BrowserOnlineStateObserver); 457 } 458 #endif // !defined(OS_IOS) 459 460 #if defined(OS_WIN) 461 system_message_window_.reset(new SystemMessageWindowWin); 462 463 if (base::win::IsTSFAwareRequired()) { 464 // Create a TSF message filter for the message loop. MessageLoop takes 465 // ownership of the filter. 466 scoped_ptr<base::win::TextServicesMessageFilter> tsf_message_filter( 467 new base::win::TextServicesMessageFilter); 468 if (tsf_message_filter->Init()) { 469 base::MessageLoopForUI::current()->SetMessageFilter( 470 tsf_message_filter.PassAs<base::MessageLoopForUI::MessageFilter>()); 471 } 472 } 473 #endif 474 475 if (parts_) 476 parts_->PostMainMessageLoopStart(); 477 478 #if defined(OS_ANDROID) 479 { 480 TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:SurfaceTexturePeer") 481 SurfaceTexturePeer::InitInstance(new SurfaceTexturePeerBrowserImpl()); 482 } 483 #endif 484 485 if (parsed_command_line_.HasSwitch(switches::kMemoryMetrics)) { 486 TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:MemoryObserver") 487 memory_observer_.reset(new MemoryObserver()); 488 base::MessageLoop::current()->AddTaskObserver(memory_observer_.get()); 489 } 490 491 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) 492 trace_memory_controller_.reset(new base::debug::TraceMemoryController( 493 base::MessageLoop::current()->message_loop_proxy(), 494 ::HeapProfilerWithPseudoStackStart, 495 ::HeapProfilerStop, 496 ::GetHeapProfile)); 497 #endif 498 } 499 500 int BrowserMainLoop::PreCreateThreads() { 501 502 if (parts_) { 503 TRACE_EVENT0("startup", 504 "BrowserMainLoop::CreateThreads:PreCreateThreads"); 505 result_code_ = parts_->PreCreateThreads(); 506 } 507 508 #if defined(ENABLE_PLUGINS) 509 // Prior to any processing happening on the io thread, we create the 510 // plugin service as it is predominantly used from the io thread, 511 // but must be created on the main thread. The service ctor is 512 // inexpensive and does not invoke the io_thread() accessor. 513 { 514 TRACE_EVENT0("startup", "BrowserMainLoop::CreateThreads:PluginService") 515 PluginService::GetInstance()->Init(); 516 } 517 #endif 518 519 #if !defined(OS_IOS) && (!defined(GOOGLE_CHROME_BUILD) || defined(OS_ANDROID)) 520 // Single-process is an unsupported and not fully tested mode, so 521 // don't enable it for official Chrome builds (except on Android). 522 if (parsed_command_line_.HasSwitch(switches::kSingleProcess)) 523 RenderProcessHost::SetRunRendererInProcess(true); 524 #endif 525 return result_code_; 526 } 527 528 void BrowserMainLoop::CreateStartupTasks() { 529 TRACE_EVENT0("startup", "BrowserMainLoop::CreateStartupTasks") 530 531 #if defined(OS_ANDROID) 532 scoped_refptr<StartupTaskRunner> task_runner = 533 new StartupTaskRunner(BrowserMayStartAsynchronously(), 534 base::Bind(&BrowserStartupComplete), 535 base::MessageLoop::current()->message_loop_proxy()); 536 #else 537 scoped_refptr<StartupTaskRunner> task_runner = 538 new StartupTaskRunner(false, 539 base::Callback<void(int)>(), 540 base::MessageLoop::current()->message_loop_proxy()); 541 #endif 542 StartupTask pre_create_threads = 543 base::Bind(&BrowserMainLoop::PreCreateThreads, base::Unretained(this)); 544 task_runner->AddTask(pre_create_threads); 545 546 StartupTask create_threads = 547 base::Bind(&BrowserMainLoop::CreateThreads, base::Unretained(this)); 548 task_runner->AddTask(create_threads); 549 550 StartupTask browser_thread_started = base::Bind( 551 &BrowserMainLoop::BrowserThreadsStarted, base::Unretained(this)); 552 task_runner->AddTask(browser_thread_started); 553 554 StartupTask pre_main_message_loop_run = base::Bind( 555 &BrowserMainLoop::PreMainMessageLoopRun, base::Unretained(this)); 556 task_runner->AddTask(pre_main_message_loop_run); 557 558 task_runner->StartRunningTasks(); 559 } 560 561 int BrowserMainLoop::CreateThreads() { 562 TRACE_EVENT0("startup", "BrowserMainLoop::CreateThreads"); 563 564 base::Thread::Options default_options; 565 base::Thread::Options io_message_loop_options; 566 io_message_loop_options.message_loop_type = base::MessageLoop::TYPE_IO; 567 base::Thread::Options ui_message_loop_options; 568 ui_message_loop_options.message_loop_type = base::MessageLoop::TYPE_UI; 569 570 // Start threads in the order they occur in the BrowserThread::ID 571 // enumeration, except for BrowserThread::UI which is the main 572 // thread. 573 // 574 // Must be size_t so we can increment it. 575 for (size_t thread_id = BrowserThread::UI + 1; 576 thread_id < BrowserThread::ID_COUNT; 577 ++thread_id) { 578 scoped_ptr<BrowserProcessSubThread>* thread_to_start = NULL; 579 base::Thread::Options* options = &default_options; 580 581 switch (thread_id) { 582 case BrowserThread::DB: 583 TRACE_EVENT_BEGIN1("startup", 584 "BrowserMainLoop::CreateThreads:start", 585 "Thread", "BrowserThread::DB"); 586 thread_to_start = &db_thread_; 587 break; 588 case BrowserThread::FILE_USER_BLOCKING: 589 TRACE_EVENT_BEGIN1("startup", 590 "BrowserMainLoop::CreateThreads:start", 591 "Thread", "BrowserThread::FILE_USER_BLOCKING"); 592 thread_to_start = &file_user_blocking_thread_; 593 break; 594 case BrowserThread::FILE: 595 TRACE_EVENT_BEGIN1("startup", 596 "BrowserMainLoop::CreateThreads:start", 597 "Thread", "BrowserThread::FILE"); 598 thread_to_start = &file_thread_; 599 #if defined(OS_WIN) 600 // On Windows, the FILE thread needs to be have a UI message loop 601 // which pumps messages in such a way that Google Update can 602 // communicate back to us. 603 options = &ui_message_loop_options; 604 #else 605 options = &io_message_loop_options; 606 #endif 607 break; 608 case BrowserThread::PROCESS_LAUNCHER: 609 TRACE_EVENT_BEGIN1("startup", 610 "BrowserMainLoop::CreateThreads:start", 611 "Thread", "BrowserThread::PROCESS_LAUNCHER"); 612 thread_to_start = &process_launcher_thread_; 613 break; 614 case BrowserThread::CACHE: 615 TRACE_EVENT_BEGIN1("startup", 616 "BrowserMainLoop::CreateThreads:start", 617 "Thread", "BrowserThread::CACHE"); 618 thread_to_start = &cache_thread_; 619 options = &io_message_loop_options; 620 break; 621 case BrowserThread::IO: 622 TRACE_EVENT_BEGIN1("startup", 623 "BrowserMainLoop::CreateThreads:start", 624 "Thread", "BrowserThread::IO"); 625 thread_to_start = &io_thread_; 626 options = &io_message_loop_options; 627 break; 628 case BrowserThread::UI: 629 case BrowserThread::ID_COUNT: 630 default: 631 NOTREACHED(); 632 break; 633 } 634 635 BrowserThread::ID id = static_cast<BrowserThread::ID>(thread_id); 636 637 if (thread_to_start) { 638 (*thread_to_start).reset(new BrowserProcessSubThread(id)); 639 (*thread_to_start)->StartWithOptions(*options); 640 } else { 641 NOTREACHED(); 642 } 643 644 TRACE_EVENT_END0("startup", "BrowserMainLoop::CreateThreads:start"); 645 646 } 647 created_threads_ = true; 648 return result_code_; 649 } 650 651 int BrowserMainLoop::PreMainMessageLoopRun() { 652 if (parts_) { 653 TRACE_EVENT0("startup", 654 "BrowserMainLoop::CreateThreads:PreMainMessageLoopRun"); 655 parts_->PreMainMessageLoopRun(); 656 } 657 658 // If the UI thread blocks, the whole UI is unresponsive. 659 // Do not allow disk IO from the UI thread. 660 base::ThreadRestrictions::SetIOAllowed(false); 661 base::ThreadRestrictions::DisallowWaiting(); 662 return result_code_; 663 } 664 665 void BrowserMainLoop::RunMainMessageLoopParts() { 666 TRACE_EVENT_BEGIN_ETW("BrowserMain:MESSAGE_LOOP", 0, ""); 667 668 bool ran_main_loop = false; 669 if (parts_) 670 ran_main_loop = parts_->MainMessageLoopRun(&result_code_); 671 672 if (!ran_main_loop) 673 MainMessageLoopRun(); 674 675 TRACE_EVENT_END_ETW("BrowserMain:MESSAGE_LOOP", 0, ""); 676 } 677 678 void BrowserMainLoop::ShutdownThreadsAndCleanUp() { 679 680 if (!created_threads_) { 681 // Called early, nothing to do 682 return; 683 } 684 // Teardown may start in PostMainMessageLoopRun, and during teardown we 685 // need to be able to perform IO. 686 base::ThreadRestrictions::SetIOAllowed(true); 687 BrowserThread::PostTask( 688 BrowserThread::IO, FROM_HERE, 689 base::Bind(base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed), 690 true)); 691 692 if (parts_) 693 parts_->PostMainMessageLoopRun(); 694 695 trace_memory_controller_.reset(); 696 697 #if !defined(OS_IOS) 698 // Destroying the GpuProcessHostUIShims on the UI thread posts a task to 699 // delete related objects on the GPU thread. This must be done before 700 // stopping the GPU thread. The GPU thread will close IPC channels to renderer 701 // processes so this has to happen before stopping the IO thread. 702 GpuProcessHostUIShim::DestroyAll(); 703 704 // Cancel pending requests and prevent new requests. 705 if (resource_dispatcher_host_) 706 resource_dispatcher_host_.get()->Shutdown(); 707 708 #if defined(USE_AURA) 709 ImageTransportFactory::Terminate(); 710 #endif 711 712 // The device monitors are using |system_monitor_| as dependency, so delete 713 // them before |system_monitor_| goes away. 714 // On Mac and windows, the monitor needs to be destroyed on the same thread 715 // as they were created. On Linux, the monitor will be deleted when IO thread 716 // goes away. 717 #if defined(OS_WIN) 718 system_message_window_.reset(); 719 #elif defined(OS_MACOSX) 720 device_monitor_mac_.reset(); 721 #endif 722 #endif // !defined(OS_IOS) 723 724 // Must be size_t so we can subtract from it. 725 for (size_t thread_id = BrowserThread::ID_COUNT - 1; 726 thread_id >= (BrowserThread::UI + 1); 727 --thread_id) { 728 // Find the thread object we want to stop. Looping over all valid 729 // BrowserThread IDs and DCHECKing on a missing case in the switch 730 // statement helps avoid a mismatch between this code and the 731 // BrowserThread::ID enumeration. 732 // 733 // The destruction order is the reverse order of occurrence in the 734 // BrowserThread::ID list. The rationale for the order is as 735 // follows (need to be filled in a bit): 736 // 737 // 738 // - The IO thread is the only user of the CACHE thread. 739 // 740 // - The PROCESS_LAUNCHER thread must be stopped after IO in case 741 // the IO thread posted a task to terminate a process on the 742 // process launcher thread. 743 // 744 // - (Not sure why DB stops last.) 745 switch (thread_id) { 746 case BrowserThread::DB: 747 db_thread_.reset(); 748 break; 749 case BrowserThread::FILE_USER_BLOCKING: 750 file_user_blocking_thread_.reset(); 751 break; 752 case BrowserThread::FILE: 753 #if !defined(OS_IOS) 754 // Clean up state that lives on or uses the file_thread_ before 755 // it goes away. 756 if (resource_dispatcher_host_) 757 resource_dispatcher_host_.get()->save_file_manager()->Shutdown(); 758 #endif // !defined(OS_IOS) 759 file_thread_.reset(); 760 break; 761 case BrowserThread::PROCESS_LAUNCHER: 762 process_launcher_thread_.reset(); 763 break; 764 case BrowserThread::CACHE: 765 cache_thread_.reset(); 766 break; 767 case BrowserThread::IO: 768 io_thread_.reset(); 769 break; 770 case BrowserThread::UI: 771 case BrowserThread::ID_COUNT: 772 default: 773 NOTREACHED(); 774 break; 775 } 776 } 777 778 #if !defined(OS_IOS) 779 indexed_db_thread_.reset(); 780 #endif 781 782 // Close the blocking I/O pool after the other threads. Other threads such 783 // as the I/O thread may need to schedule work like closing files or flushing 784 // data during shutdown, so the blocking pool needs to be available. There 785 // may also be slow operations pending that will blcok shutdown, so closing 786 // it here (which will block until required operations are complete) gives 787 // more head start for those operations to finish. 788 BrowserThreadImpl::ShutdownThreadPool(); 789 790 #if !defined(OS_IOS) 791 // Must happen after the IO thread is shutdown since this may be accessed from 792 // it. 793 BrowserGpuChannelHostFactory::Terminate(); 794 795 // Must happen after the I/O thread is shutdown since this class lives on the 796 // I/O thread and isn't threadsafe. 797 GamepadService::GetInstance()->Terminate(); 798 DeviceMotionService::GetInstance()->Shutdown(); 799 800 URLDataManager::DeleteDataSources(); 801 #endif // !defined(OS_IOS) 802 803 if (parts_) 804 parts_->PostDestroyThreads(); 805 } 806 807 void BrowserMainLoop::InitializeMainThread() { 808 TRACE_EVENT0("startup", "BrowserMainLoop::InitializeMainThread") 809 const char* kThreadName = "CrBrowserMain"; 810 base::PlatformThread::SetName(kThreadName); 811 if (main_message_loop_) 812 main_message_loop_->set_thread_name(kThreadName); 813 814 // Register the main thread by instantiating it, but don't call any methods. 815 main_thread_.reset( 816 new BrowserThreadImpl(BrowserThread::UI, base::MessageLoop::current())); 817 } 818 819 int BrowserMainLoop::BrowserThreadsStarted() { 820 TRACE_EVENT0("startup", "BrowserMainLoop::BrowserThreadsStarted") 821 822 #if !defined(OS_IOS) 823 indexed_db_thread_.reset(new base::Thread("IndexedDB")); 824 indexed_db_thread_->Start(); 825 #endif 826 827 #if defined(OS_ANDROID) 828 // Up the priority of anything that touches with display tasks 829 // (this thread is UI thread, and io_thread_ is for IPCs). 830 io_thread_->SetPriority(base::kThreadPriority_Display); 831 base::PlatformThread::SetThreadPriority( 832 base::PlatformThread::CurrentHandle(), 833 base::kThreadPriority_Display); 834 #endif 835 836 #if !defined(OS_IOS) 837 HistogramSynchronizer::GetInstance(); 838 839 BrowserGpuChannelHostFactory::Initialize(); 840 #if defined(USE_AURA) 841 ImageTransportFactory::Initialize(); 842 #endif 843 844 #if defined(OS_LINUX) 845 device_monitor_linux_.reset(new DeviceMonitorLinux()); 846 #elif defined(OS_MACOSX) 847 device_monitor_mac_.reset(new DeviceMonitorMac()); 848 #endif 849 850 // RDH needs the IO thread to be created 851 { 852 TRACE_EVENT0("startup", 853 "BrowserMainLoop::BrowserThreadsStarted:InitResourceDispatcherHost"); 854 resource_dispatcher_host_.reset(new ResourceDispatcherHostImpl()); 855 } 856 857 // MediaStreamManager needs the IO thread to be created. 858 { 859 TRACE_EVENT0("startup", 860 "BrowserMainLoop::BrowserThreadsStarted:InitMediaStreamManager"); 861 media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get())); 862 } 863 864 // Initialize the GpuDataManager before we set up the MessageLoops because 865 // otherwise we'll trigger the assertion about doing IO on the UI thread. 866 GpuDataManagerImpl::GetInstance()->Initialize(); 867 868 { 869 TRACE_EVENT0("startup", 870 "BrowserMainLoop::BrowserThreadsStarted:InitSpeechRecognition"); 871 speech_recognition_manager_.reset(new SpeechRecognitionManagerImpl( 872 audio_manager_.get(), media_stream_manager_.get())); 873 } 874 875 // Alert the clipboard class to which threads are allowed to access the 876 // clipboard: 877 std::vector<base::PlatformThreadId> allowed_clipboard_threads; 878 // The current thread is the UI thread. 879 allowed_clipboard_threads.push_back(base::PlatformThread::CurrentId()); 880 #if defined(OS_WIN) 881 // On Windows, clipboards are also used on the File or IO threads. 882 allowed_clipboard_threads.push_back(file_thread_->thread_id()); 883 allowed_clipboard_threads.push_back(io_thread_->thread_id()); 884 #endif 885 ui::Clipboard::SetAllowedThreads(allowed_clipboard_threads); 886 887 // When running the GPU thread in-process, avoid optimistically starting it 888 // since creating the GPU thread races against creation of the one-and-only 889 // ChildProcess instance which is created by the renderer thread. 890 if (GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(NULL) && 891 IsForceCompositingModeEnabled() && 892 !parsed_command_line_.HasSwitch(switches::kDisableGpuProcessPrelaunch) && 893 !parsed_command_line_.HasSwitch(switches::kSingleProcess) && 894 !parsed_command_line_.HasSwitch(switches::kInProcessGPU)) { 895 TRACE_EVENT_INSTANT0("gpu", "Post task to launch GPU process", 896 TRACE_EVENT_SCOPE_THREAD); 897 BrowserThread::PostTask( 898 BrowserThread::IO, FROM_HERE, base::Bind( 899 base::IgnoreResult(&GpuProcessHost::Get), 900 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, 901 CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP)); 902 } 903 #endif // !defined(OS_IOS) 904 return result_code_; 905 } 906 907 void BrowserMainLoop::InitializeToolkit() { 908 TRACE_EVENT0("startup", "BrowserMainLoop::InitializeToolkit") 909 // TODO(evan): this function is rather subtle, due to the variety 910 // of intersecting ifdefs we have. To keep it easy to follow, there 911 // are no #else branches on any #ifs. 912 // TODO(stevenjb): Move platform specific code into platform specific Parts 913 // (Need to add InitializeToolkit stage to BrowserParts). 914 #if defined(OS_LINUX) || defined(OS_OPENBSD) 915 // g_type_init will be deprecated in 2.36. 2.35 is the development 916 // version for 2.36, hence do not call g_type_init starting 2.35. 917 // http://developer.gnome.org/gobject/unstable/gobject-Type-Information.html#g-type-init 918 #if !GLIB_CHECK_VERSION(2, 35, 0) 919 // Glib type system initialization. Needed at least for gconf, 920 // used in net/proxy/proxy_config_service_linux.cc. Most likely 921 // this is superfluous as gtk_init() ought to do this. It's 922 // definitely harmless, so retained as a reminder of this 923 // requirement for gconf. 924 g_type_init(); 925 #endif 926 927 #if !defined(USE_AURA) 928 gfx::GtkInitFromCommandLine(parsed_command_line_); 929 #endif 930 931 SetUpGLibLogHandler(); 932 #endif 933 934 #if defined(TOOLKIT_GTK) 935 // It is important for this to happen before the first run dialog, as it 936 // styles the dialog as well. 937 gfx::InitRCStyles(); 938 #endif 939 940 #if defined(OS_WIN) 941 // Init common control sex. 942 INITCOMMONCONTROLSEX config; 943 config.dwSize = sizeof(config); 944 config.dwICC = ICC_WIN95_CLASSES; 945 if (!InitCommonControlsEx(&config)) 946 LOG_GETLASTERROR(FATAL); 947 #endif 948 949 if (parts_) 950 parts_->ToolkitInitialized(); 951 } 952 953 void BrowserMainLoop::MainMessageLoopRun() { 954 #if defined(OS_ANDROID) 955 // Android's main message loop is the Java message loop. 956 NOTREACHED(); 957 #else 958 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); 959 if (parameters_.ui_task) 960 base::MessageLoopForUI::current()->PostTask(FROM_HERE, 961 *parameters_.ui_task); 962 963 base::RunLoop run_loop; 964 run_loop.Run(); 965 #endif 966 } 967 968 } // namespace content 969