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