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