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