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