content_main_runner.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
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/public/app/content_main_runner.h" 6 7#include <stdlib.h> 8 9#include "base/allocator/allocator_extension.h" 10#include "base/at_exit.h" 11#include "base/command_line.h" 12#include "base/debug/debugger.h" 13#include "base/debug/trace_event.h" 14#include "base/files/file_path.h" 15#include "base/i18n/icu_util.h" 16#include "base/lazy_instance.h" 17#include "base/logging.h" 18#include "base/memory/scoped_ptr.h" 19#include "base/metrics/stats_table.h" 20#include "base/path_service.h" 21#include "base/process/launch.h" 22#include "base/process/memory.h" 23#include "base/process/process_handle.h" 24#include "base/profiler/alternate_timer.h" 25#include "base/strings/string_number_conversions.h" 26#include "base/strings/string_util.h" 27#include "base/strings/stringprintf.h" 28#include "content/browser/browser_main.h" 29#include "content/browser/gpu/gpu_process_host.h" 30#include "content/common/set_process_title.h" 31#include "content/common/url_schemes.h" 32#include "content/gpu/in_process_gpu_thread.h" 33#include "content/public/app/content_main.h" 34#include "content/public/app/content_main_delegate.h" 35#include "content/public/app/startup_helper_win.h" 36#include "content/public/browser/content_browser_client.h" 37#include "content/public/browser/render_process_host.h" 38#include "content/public/browser/utility_process_host.h" 39#include "content/public/common/content_client.h" 40#include "content/public/common/content_constants.h" 41#include "content/public/common/content_paths.h" 42#include "content/public/common/content_switches.h" 43#include "content/public/common/main_function_params.h" 44#include "content/public/common/sandbox_init.h" 45#include "content/renderer/in_process_renderer_thread.h" 46#include "content/utility/in_process_utility_thread.h" 47#include "crypto/nss_util.h" 48#include "ipc/ipc_descriptors.h" 49#include "ipc/ipc_switches.h" 50#include "media/base/media.h" 51#include "sandbox/win/src/sandbox_types.h" 52#include "ui/base/ui_base_paths.h" 53#include "ui/base/ui_base_switches.h" 54#include "ui/gfx/win/dpi.h" 55 56#if defined(USE_TCMALLOC) 57#include "third_party/tcmalloc/chromium/src/gperftools/malloc_extension.h" 58#if defined(TYPE_PROFILING) 59#include "base/allocator/type_profiler.h" 60#include "base/allocator/type_profiler_tcmalloc.h" 61#endif 62#endif 63 64#if !defined(OS_IOS) 65#include "content/app/mojo/mojo_init.h" 66#include "content/public/plugin/content_plugin_client.h" 67#include "content/public/renderer/content_renderer_client.h" 68#include "content/public/utility/content_utility_client.h" 69#endif 70 71#if defined(OS_WIN) 72#include <atlbase.h> 73#include <atlapp.h> 74#include <malloc.h> 75#include <cstring> 76#elif defined(OS_MACOSX) 77#include "base/mac/scoped_nsautorelease_pool.h" 78#if !defined(OS_IOS) 79#include "base/power_monitor/power_monitor_device_source.h" 80#include "content/browser/mach_broker_mac.h" 81#include "content/common/sandbox_init_mac.h" 82#endif // !OS_IOS 83#endif // OS_WIN 84 85#if defined(OS_POSIX) 86#include <signal.h> 87 88#include "base/posix/global_descriptors.h" 89#include "content/public/common/content_descriptors.h" 90 91#if !defined(OS_MACOSX) 92#include "content/public/common/zygote_fork_delegate_linux.h" 93#endif 94#if !defined(OS_MACOSX) && !defined(OS_ANDROID) 95#include "content/zygote/zygote_main.h" 96#endif 97 98#endif // OS_POSIX 99 100#if !defined(OS_MACOSX) && defined(USE_TCMALLOC) 101extern "C" { 102int tc_set_new_mode(int mode); 103} 104#endif 105 106namespace content { 107extern int GpuMain(const content::MainFunctionParams&); 108#if defined(ENABLE_PLUGINS) 109#if !defined(OS_LINUX) 110extern int PluginMain(const content::MainFunctionParams&); 111#endif 112extern int PpapiPluginMain(const MainFunctionParams&); 113extern int PpapiBrokerMain(const MainFunctionParams&); 114#endif 115extern int RendererMain(const content::MainFunctionParams&); 116extern int UtilityMain(const MainFunctionParams&); 117extern int WorkerMain(const MainFunctionParams&); 118} // namespace content 119 120namespace { 121#if defined(OS_WIN) 122// In order to have Theme support, we need to connect to the theme service. 123// This needs to be done before we lock down the process. Officially this 124// can be done with OpenThemeData() but it fails unless you pass a valid 125// window at least the first time. Interestingly, the very act of creating a 126// window also sets the connection to the theme service. 127void EnableThemeSupportOnAllWindowStations() { 128 HDESK desktop_handle = ::OpenInputDesktop(0, FALSE, READ_CONTROL); 129 if (desktop_handle) { 130 // This means we are running in an input desktop, which implies WinSta0. 131 ::CloseDesktop(desktop_handle); 132 return; 133 } 134 135 HWINSTA current_station = ::GetProcessWindowStation(); 136 DCHECK(current_station); 137 138 HWINSTA winsta0 = ::OpenWindowStationA("WinSta0", FALSE, GENERIC_READ); 139 if (!winsta0) { 140 DVLOG(0) << "Unable to open to WinSta0, we: "<< ::GetLastError(); 141 return; 142 } 143 if (!::SetProcessWindowStation(winsta0)) { 144 // Could not set the alternate window station. There is a possibility 145 // that the theme wont be correctly initialized. 146 NOTREACHED() << "Unable to switch to WinSta0, we: "<< ::GetLastError(); 147 ::CloseWindowStation(winsta0); 148 return; 149 } 150 151 HWND window = ::CreateWindowExW(0, L"Static", L"", WS_POPUP | WS_DISABLED, 152 CW_USEDEFAULT, 0, 0, 0, HWND_MESSAGE, NULL, 153 ::GetModuleHandleA(NULL), NULL); 154 if (!window) { 155 DLOG(WARNING) << "failed to enable theme support"; 156 } else { 157 ::DestroyWindow(window); 158 window = NULL; 159 } 160 161 // Revert the window station. 162 if (!::SetProcessWindowStation(current_station)) { 163 // We failed to switch back to the secure window station. This might 164 // confuse the process enough that we should kill it now. 165 LOG(FATAL) << "Failed to restore alternate window station"; 166 } 167 168 if (!::CloseWindowStation(winsta0)) { 169 // We might be leaking a winsta0 handle. This is a security risk, but 170 // since we allow fail over to no desktop protection in low memory 171 // condition, this is not a big risk. 172 NOTREACHED(); 173 } 174} 175#endif // defined(OS_WIN) 176} // namespace 177 178namespace content { 179 180base::LazyInstance<ContentBrowserClient> 181 g_empty_content_browser_client = LAZY_INSTANCE_INITIALIZER; 182#if !defined(OS_IOS) && !defined(CHROME_MULTIPLE_DLL_BROWSER) 183base::LazyInstance<ContentPluginClient> 184 g_empty_content_plugin_client = LAZY_INSTANCE_INITIALIZER; 185base::LazyInstance<ContentRendererClient> 186 g_empty_content_renderer_client = LAZY_INSTANCE_INITIALIZER; 187base::LazyInstance<ContentUtilityClient> 188 g_empty_content_utility_client = LAZY_INSTANCE_INITIALIZER; 189#endif // !OS_IOS && !CHROME_MULTIPLE_DLL_BROWSER 190 191#if defined(OS_WIN) 192 193static CAppModule _Module; 194 195#endif // defined(OS_WIN) 196 197#if defined(OS_POSIX) && !defined(OS_IOS) 198 199// Setup signal-handling state: resanitize most signals, ignore SIGPIPE. 200void SetupSignalHandlers() { 201 // Sanitise our signal handling state. Signals that were ignored by our 202 // parent will also be ignored by us. We also inherit our parent's sigmask. 203 sigset_t empty_signal_set; 204 CHECK(0 == sigemptyset(&empty_signal_set)); 205 CHECK(0 == sigprocmask(SIG_SETMASK, &empty_signal_set, NULL)); 206 207 struct sigaction sigact; 208 memset(&sigact, 0, sizeof(sigact)); 209 sigact.sa_handler = SIG_DFL; 210 static const int signals_to_reset[] = 211 {SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV, 212 SIGALRM, SIGTERM, SIGCHLD, SIGBUS, SIGTRAP}; // SIGPIPE is set below. 213 for (unsigned i = 0; i < arraysize(signals_to_reset); i++) { 214 CHECK(0 == sigaction(signals_to_reset[i], &sigact, NULL)); 215 } 216 217 // Always ignore SIGPIPE. We check the return value of write(). 218 CHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR); 219} 220 221#endif // OS_POSIX && !OS_IOS 222 223void CommonSubprocessInit(const std::string& process_type) { 224#if defined(OS_WIN) 225 // HACK: Let Windows know that we have started. This is needed to suppress 226 // the IDC_APPSTARTING cursor from being displayed for a prolonged period 227 // while a subprocess is starting. 228 PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0); 229 MSG msg; 230 PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); 231#endif 232#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 233 // Various things break when you're using a locale where the decimal 234 // separator isn't a period. See e.g. bugs 22782 and 39964. For 235 // all processes except the browser process (where we call system 236 // APIs that may rely on the correct locale for formatting numbers 237 // when presenting them to the user), reset the locale for numeric 238 // formatting. 239 // Note that this is not correct for plugin processes -- they can 240 // surface UI -- but it's likely they get this wrong too so why not. 241 setlocale(LC_NUMERIC, "C"); 242#endif 243} 244 245// Only needed on Windows for creating stats tables. 246#if defined(OS_WIN) 247static base::ProcessId GetBrowserPid(const CommandLine& command_line) { 248 base::ProcessId browser_pid = base::GetCurrentProcId(); 249 if (command_line.HasSwitch(switches::kProcessChannelID)) { 250 std::string channel_name = 251 command_line.GetSwitchValueASCII(switches::kProcessChannelID); 252 253 int browser_pid_int; 254 base::StringToInt(channel_name, &browser_pid_int); 255 browser_pid = static_cast<base::ProcessId>(browser_pid_int); 256 DCHECK_NE(browser_pid_int, 0); 257 } 258 return browser_pid; 259} 260#endif 261 262static void InitializeStatsTable(const CommandLine& command_line) { 263 // Initialize the Stats Counters table. With this initialized, 264 // the StatsViewer can be utilized to read counters outside of 265 // Chrome. These lines can be commented out to effectively turn 266 // counters 'off'. The table is created and exists for the life 267 // of the process. It is not cleaned up. 268 if (command_line.HasSwitch(switches::kEnableStatsTable)) { 269 // NOTIMPLEMENTED: we probably need to shut this down correctly to avoid 270 // leaking shared memory regions on posix platforms. 271#if defined(OS_POSIX) 272 // Stats table is in the global file descriptors table on Posix. 273 base::GlobalDescriptors* global_descriptors = 274 base::GlobalDescriptors::GetInstance(); 275 base::FileDescriptor table_ident; 276 if (global_descriptors->MaybeGet(kStatsTableSharedMemFd) != -1) { 277 // Open the shared memory file descriptor passed by the browser process. 278 table_ident = base::FileDescriptor( 279 global_descriptors->Get(kStatsTableSharedMemFd), false); 280 } 281#elif defined(OS_WIN) 282 // Stats table is in a named segment on Windows. Use the PID to make this 283 // unique on the system. 284 std::string table_ident = 285 base::StringPrintf("%s-%u", kStatsFilename, 286 static_cast<unsigned int>(GetBrowserPid(command_line))); 287#endif 288 base::StatsTable* stats_table = 289 new base::StatsTable(table_ident, kStatsMaxThreads, kStatsMaxCounters); 290 base::StatsTable::set_current(stats_table); 291 } 292} 293 294class ContentClientInitializer { 295 public: 296 static void Set(const std::string& process_type, 297 ContentMainDelegate* delegate) { 298 ContentClient* content_client = GetContentClient(); 299 if (process_type.empty()) { 300 if (delegate) 301 content_client->browser_ = delegate->CreateContentBrowserClient(); 302 if (!content_client->browser_) 303 content_client->browser_ = &g_empty_content_browser_client.Get(); 304 } 305 306#if !defined(OS_IOS) && !defined(CHROME_MULTIPLE_DLL_BROWSER) 307 if (process_type == switches::kPluginProcess || 308 process_type == switches::kPpapiPluginProcess) { 309 if (delegate) 310 content_client->plugin_ = delegate->CreateContentPluginClient(); 311 if (!content_client->plugin_) 312 content_client->plugin_ = &g_empty_content_plugin_client.Get(); 313 // Single process not supported in split dll mode. 314 } else if (process_type == switches::kRendererProcess || 315 CommandLine::ForCurrentProcess()->HasSwitch( 316 switches::kSingleProcess)) { 317 if (delegate) 318 content_client->renderer_ = delegate->CreateContentRendererClient(); 319 if (!content_client->renderer_) 320 content_client->renderer_ = &g_empty_content_renderer_client.Get(); 321 } 322 323 if (process_type == switches::kUtilityProcess || 324 CommandLine::ForCurrentProcess()->HasSwitch( 325 switches::kSingleProcess)) { 326 if (delegate) 327 content_client->utility_ = delegate->CreateContentUtilityClient(); 328 // TODO(scottmg): http://crbug.com/237249 Should be in _child. 329 if (!content_client->utility_) 330 content_client->utility_ = &g_empty_content_utility_client.Get(); 331 } 332#endif // !OS_IOS && !CHROME_MULTIPLE_DLL_BROWSER 333 } 334}; 335 336// We dispatch to a process-type-specific FooMain() based on a command-line 337// flag. This struct is used to build a table of (flag, main function) pairs. 338struct MainFunction { 339 const char* name; 340 int (*function)(const MainFunctionParams&); 341}; 342 343#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 344// On platforms that use the zygote, we have a special subset of 345// subprocesses that are launched via the zygote. This function 346// fills in some process-launching bits around ZygoteMain(). 347// Returns the exit code of the subprocess. 348int RunZygote(const MainFunctionParams& main_function_params, 349 ContentMainDelegate* delegate) { 350 static const MainFunction kMainFunctions[] = { 351 { switches::kRendererProcess, RendererMain }, 352 { switches::kWorkerProcess, WorkerMain }, 353#if defined(ENABLE_PLUGINS) 354 { switches::kPpapiPluginProcess, PpapiPluginMain }, 355#endif 356 { switches::kUtilityProcess, UtilityMain }, 357 }; 358 359 scoped_ptr<ZygoteForkDelegate> zygote_fork_delegate; 360 if (delegate) { 361 zygote_fork_delegate.reset(delegate->ZygoteStarting()); 362 // Each Renderer we spawn will re-attempt initialization of the media 363 // libraries, at which point failure will be detected and handled, so 364 // we do not need to cope with initialization failures here. 365 base::FilePath media_path; 366 if (PathService::Get(DIR_MEDIA_LIBS, &media_path)) 367 media::InitializeMediaLibrary(media_path); 368 } 369 370 // This function call can return multiple times, once per fork(). 371 if (!ZygoteMain(main_function_params, zygote_fork_delegate.get())) 372 return 1; 373 374 if (delegate) delegate->ZygoteForked(); 375 376 // Zygote::HandleForkRequest may have reallocated the command 377 // line so update it here with the new version. 378 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 379 std::string process_type = 380 command_line.GetSwitchValueASCII(switches::kProcessType); 381 ContentClientInitializer::Set(process_type, delegate); 382 383 // The StatsTable must be initialized in each process; we already 384 // initialized for the browser process, now we need to initialize 385 // within the new processes as well. 386 InitializeStatsTable(command_line); 387 388 MainFunctionParams main_params(command_line); 389 390 for (size_t i = 0; i < arraysize(kMainFunctions); ++i) { 391 if (process_type == kMainFunctions[i].name) 392 return kMainFunctions[i].function(main_params); 393 } 394 395 if (delegate) 396 return delegate->RunProcess(process_type, main_params); 397 398 NOTREACHED() << "Unknown zygote process type: " << process_type; 399 return 1; 400} 401#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 402 403#if !defined(OS_IOS) 404static void RegisterMainThreadFactories() { 405#if !defined(CHROME_MULTIPLE_DLL_BROWSER) 406 UtilityProcessHost::RegisterUtilityMainThreadFactory( 407 CreateInProcessUtilityThread); 408 RenderProcessHost::RegisterRendererMainThreadFactory( 409 CreateInProcessRendererThread); 410 GpuProcessHost::RegisterGpuMainThreadFactory( 411 CreateInProcessGpuThread); 412#else 413 CommandLine& command_line = *CommandLine::ForCurrentProcess(); 414 if (command_line.HasSwitch(switches::kSingleProcess)) { 415 LOG(FATAL) << 416 "--single-process is not supported in chrome multiple dll browser."; 417 } 418 if (command_line.HasSwitch(switches::kInProcessGPU)) { 419 LOG(FATAL) << 420 "--in-process-gpu is not supported in chrome multiple dll browser."; 421 } 422#endif 423} 424 425// Run the FooMain() for a given process type. 426// If |process_type| is empty, runs BrowserMain(). 427// Returns the exit code for this process. 428int RunNamedProcessTypeMain( 429 const std::string& process_type, 430 const MainFunctionParams& main_function_params, 431 ContentMainDelegate* delegate) { 432 static const MainFunction kMainFunctions[] = { 433#if !defined(CHROME_MULTIPLE_DLL_CHILD) 434 { "", BrowserMain }, 435#endif 436#if !defined(CHROME_MULTIPLE_DLL_BROWSER) 437#if defined(ENABLE_PLUGINS) 438#if !defined(OS_LINUX) 439 { switches::kPluginProcess, PluginMain }, 440#endif 441 { switches::kWorkerProcess, WorkerMain }, 442 { switches::kPpapiPluginProcess, PpapiPluginMain }, 443 { switches::kPpapiBrokerProcess, PpapiBrokerMain }, 444#endif // ENABLE_PLUGINS 445 { switches::kUtilityProcess, UtilityMain }, 446 { switches::kRendererProcess, RendererMain }, 447 { switches::kGpuProcess, GpuMain }, 448#endif // !CHROME_MULTIPLE_DLL_BROWSER 449 }; 450 451 RegisterMainThreadFactories(); 452 453 for (size_t i = 0; i < arraysize(kMainFunctions); ++i) { 454 if (process_type == kMainFunctions[i].name) { 455 if (delegate) { 456 int exit_code = delegate->RunProcess(process_type, 457 main_function_params); 458#if defined(OS_ANDROID) 459 // In Android's browser process, the negative exit code doesn't mean the 460 // default behavior should be used as the UI message loop is managed by 461 // the Java and the browser process's default behavior is always 462 // overridden. 463 if (process_type.empty()) 464 return exit_code; 465#endif 466 if (exit_code >= 0) 467 return exit_code; 468 } 469 return kMainFunctions[i].function(main_function_params); 470 } 471 } 472 473#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 474 // Zygote startup is special -- see RunZygote comments above 475 // for why we don't use ZygoteMain directly. 476 if (process_type == switches::kZygoteProcess) 477 return RunZygote(main_function_params, delegate); 478#endif 479 480 // If it's a process we don't know about, the embedder should know. 481 if (delegate) 482 return delegate->RunProcess(process_type, main_function_params); 483 484 NOTREACHED() << "Unknown process type: " << process_type; 485 return 1; 486} 487#endif // !OS_IOS 488 489class ContentMainRunnerImpl : public ContentMainRunner { 490 public: 491 ContentMainRunnerImpl() 492 : is_initialized_(false), 493 is_shutdown_(false), 494 completed_basic_startup_(false), 495 delegate_(NULL), 496 ui_task_(NULL) { 497#if defined(OS_WIN) 498 memset(&sandbox_info_, 0, sizeof(sandbox_info_)); 499#endif 500 } 501 502 virtual ~ContentMainRunnerImpl() { 503 if (is_initialized_ && !is_shutdown_) 504 Shutdown(); 505 } 506 507#if defined(USE_TCMALLOC) 508 static bool GetAllocatorWasteSizeThunk(size_t* size) { 509 size_t heap_size, allocated_bytes, unmapped_bytes; 510 MallocExtension* ext = MallocExtension::instance(); 511 if (ext->GetNumericProperty("generic.heap_size", &heap_size) && 512 ext->GetNumericProperty("generic.current_allocated_bytes", 513 &allocated_bytes) && 514 ext->GetNumericProperty("tcmalloc.pageheap_unmapped_bytes", 515 &unmapped_bytes)) { 516 *size = heap_size - allocated_bytes - unmapped_bytes; 517 return true; 518 } 519 DCHECK(false); 520 return false; 521 } 522 523 static void GetStatsThunk(char* buffer, int buffer_length) { 524 MallocExtension::instance()->GetStats(buffer, buffer_length); 525 } 526 527 static void ReleaseFreeMemoryThunk() { 528 MallocExtension::instance()->ReleaseFreeMemory(); 529 } 530#endif 531 532 virtual int Initialize(const ContentMainParams& params) OVERRIDE { 533 ui_task_ = params.ui_task; 534 535#if defined(OS_WIN) 536 RegisterInvalidParamHandler(); 537 _Module.Init(NULL, static_cast<HINSTANCE>(params.instance)); 538 539 sandbox_info_ = *params.sandbox_info; 540#else // !OS_WIN 541 542#if defined(OS_ANDROID) 543 // See note at the initialization of ExitManager, below; basically, 544 // only Android builds have the ctor/dtor handlers set up to use 545 // TRACE_EVENT right away. 546 TRACE_EVENT0("startup", "ContentMainRunnerImpl::Initialize"); 547#endif // OS_ANDROID 548 549 // NOTE(willchan): One might ask why these TCMalloc-related calls are done 550 // here rather than in process_util_linux.cc with the definition of 551 // EnableTerminationOnOutOfMemory(). That's because base shouldn't have a 552 // dependency on TCMalloc. Really, we ought to have our allocator shim code 553 // implement this EnableTerminationOnOutOfMemory() function. Whateverz. 554 // This works for now. 555#if !defined(OS_MACOSX) && defined(USE_TCMALLOC) 556 557#if defined(TYPE_PROFILING) 558 base::type_profiler::InterceptFunctions::SetFunctions( 559 base::type_profiler::NewInterceptForTCMalloc, 560 base::type_profiler::DeleteInterceptForTCMalloc); 561#endif 562 563 // For tcmalloc, we need to tell it to behave like new. 564 tc_set_new_mode(1); 565 566 // On windows, we've already set these thunks up in _heap_init() 567 base::allocator::SetGetAllocatorWasteSizeFunction( 568 GetAllocatorWasteSizeThunk); 569 base::allocator::SetGetStatsFunction(GetStatsThunk); 570 base::allocator::SetReleaseFreeMemoryFunction(ReleaseFreeMemoryThunk); 571 572 // Provide optional hook for monitoring allocation quantities on a 573 // per-thread basis. Only set the hook if the environment indicates this 574 // needs to be enabled. 575 const char* profiling = getenv(tracked_objects::kAlternateProfilerTime); 576 if (profiling && 577 (atoi(profiling) == tracked_objects::TIME_SOURCE_TYPE_TCMALLOC)) { 578 tracked_objects::SetAlternateTimeSource( 579 MallocExtension::GetBytesAllocatedOnCurrentThread, 580 tracked_objects::TIME_SOURCE_TYPE_TCMALLOC); 581 } 582#endif // !OS_MACOSX && USE_TCMALLOC 583 584 // On Android, 585 // - setlocale() is not supported. 586 // - We do not override the signal handlers so that we can get 587 // stack trace when crashing. 588 // - The ipc_fd is passed through the Java service. 589 // Thus, these are all disabled. 590#if !defined(OS_ANDROID) && !defined(OS_IOS) 591 // Set C library locale to make sure CommandLine can parse argument values 592 // in correct encoding. 593 setlocale(LC_ALL, ""); 594 595 SetupSignalHandlers(); 596 597 base::GlobalDescriptors* g_fds = base::GlobalDescriptors::GetInstance(); 598 g_fds->Set(kPrimaryIPCChannel, 599 kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor); 600#endif // !OS_ANDROID && !OS_IOS 601 602#if defined(OS_LINUX) || defined(OS_OPENBSD) 603 g_fds->Set(kCrashDumpSignal, 604 kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor); 605#endif 606 607#endif // !OS_WIN 608 609 is_initialized_ = true; 610 delegate_ = params.delegate; 611 612 base::EnableTerminationOnHeapCorruption(); 613 base::EnableTerminationOnOutOfMemory(); 614 615 // The exit manager is in charge of calling the dtors of singleton objects. 616 // On Android, AtExitManager is set up when library is loaded. 617 // On iOS, it's set up in main(), which can't call directly through to here. 618 // A consequence of this is that you can't use the ctor/dtor-based 619 // TRACE_EVENT methods on Linux or iOS builds till after we set this up. 620#if !defined(OS_ANDROID) && !defined(OS_IOS) 621 if (!ui_task_) { 622 // When running browser tests, don't create a second AtExitManager as that 623 // interfers with shutdown when objects created before ContentMain is 624 // called are destructed when it returns. 625 exit_manager_.reset(new base::AtExitManager); 626 } 627#endif // !OS_ANDROID && !OS_IOS 628 629#if defined(OS_MACOSX) 630 // We need this pool for all the objects created before we get to the 631 // event loop, but we don't want to leave them hanging around until the 632 // app quits. Each "main" needs to flush this pool right before it goes into 633 // its main event loop to get rid of the cruft. 634 autorelease_pool_.reset(new base::mac::ScopedNSAutoreleasePool()); 635#endif 636 637 // On Android, the command line is initialized when library is loaded and 638 // we have already started our TRACE_EVENT0. 639#if !defined(OS_ANDROID) 640 // argc/argv are ignored on Windows and Android; see command_line.h for 641 // details. 642 int argc = 0; 643 const char** argv = NULL; 644 645#if !defined(OS_WIN) 646 argc = params.argc; 647 argv = params.argv; 648#endif 649 650 CommandLine::Init(argc, argv); 651 652#if !defined(OS_IOS) 653 SetProcessTitleFromCommandLine(argv); 654#endif 655#endif // !OS_ANDROID 656 657 int exit_code; 658 if (delegate_ && delegate_->BasicStartupComplete(&exit_code)) 659 return exit_code; 660 661 completed_basic_startup_ = true; 662 663 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 664 std::string process_type = 665 command_line.GetSwitchValueASCII(switches::kProcessType); 666 667#if !defined(OS_IOS) 668 // Initialize mojo here so that services can be registered. 669 InitializeMojo(); 670#endif 671 672 if (!GetContentClient()) 673 SetContentClient(&empty_content_client_); 674 ContentClientInitializer::Set(process_type, delegate_); 675 676#if defined(OS_WIN) 677 // Route stdio to parent console (if any) or create one. 678 if (command_line.HasSwitch(switches::kEnableLogging)) 679 base::RouteStdioToConsole(); 680#endif 681 682 // Enable startup tracing asap to avoid early TRACE_EVENT calls being 683 // ignored. 684 if (command_line.HasSwitch(switches::kTraceStartup)) { 685 base::debug::CategoryFilter category_filter( 686 command_line.GetSwitchValueASCII(switches::kTraceStartup)); 687 base::debug::TraceLog::GetInstance()->SetEnabled( 688 category_filter, 689 base::debug::TraceLog::RECORDING_MODE, 690 base::debug::TraceLog::RECORD_UNTIL_FULL); 691 } 692#if !defined(OS_ANDROID) 693 // Android tracing started at the beginning of the method. 694 // Other OSes have to wait till we get here in order for all the memory 695 // management setup to be completed. 696 TRACE_EVENT0("startup", "ContentMainRunnerImpl::Initialize"); 697#endif // !OS_ANDROID 698 699#if defined(OS_MACOSX) && !defined(OS_IOS) 700 // We need to allocate the IO Ports before the Sandbox is initialized or 701 // the first instance of PowerMonitor is created. 702 // It's important not to allocate the ports for processes which don't 703 // register with the power monitor - see crbug.com/88867. 704 if (process_type.empty() || 705 (delegate_ && 706 delegate_->ProcessRegistersWithSystemProcess(process_type))) { 707 base::PowerMonitorDeviceSource::AllocateSystemIOPorts(); 708 } 709 710 if (!process_type.empty() && 711 (!delegate_ || delegate_->ShouldSendMachPort(process_type))) { 712 MachBroker::ChildSendTaskPortToParent(); 713 } 714#elif defined(OS_WIN) 715 if (command_line.HasSwitch(switches::kEnableHighResolutionTime)) 716 base::TimeTicks::SetNowIsHighResNowIfSupported(); 717 718 // This must be done early enough since some helper functions like 719 // IsTouchEnabled, needed to load resources, may call into the theme dll. 720 EnableThemeSupportOnAllWindowStations(); 721 SetupCRT(command_line); 722#endif 723 724#if defined(OS_POSIX) 725 if (!process_type.empty()) { 726 // When you hit Ctrl-C in a terminal running the browser 727 // process, a SIGINT is delivered to the entire process group. 728 // When debugging the browser process via gdb, gdb catches the 729 // SIGINT for the browser process (and dumps you back to the gdb 730 // console) but doesn't for the child processes, killing them. 731 // The fix is to have child processes ignore SIGINT; they'll die 732 // on their own when the browser process goes away. 733 // 734 // Note that we *can't* rely on BeingDebugged to catch this case because 735 // we are the child process, which is not being debugged. 736 // TODO(evanm): move this to some shared subprocess-init function. 737 if (!base::debug::BeingDebugged()) 738 signal(SIGINT, SIG_IGN); 739 } 740#endif 741 742#if defined(USE_NSS) 743 crypto::EarlySetupForNSSInit(); 744#endif 745 746 ui::RegisterPathProvider(); 747 RegisterPathProvider(); 748 RegisterContentSchemes(true); 749 750 CHECK(base::i18n::InitializeICU()); 751 752 InitializeStatsTable(command_line); 753 754 if (delegate_) 755 delegate_->PreSandboxStartup(); 756 757 if (!process_type.empty()) 758 CommonSubprocessInit(process_type); 759 760#if defined(OS_WIN) 761 CHECK(InitializeSandbox(params.sandbox_info)); 762#elif defined(OS_MACOSX) && !defined(OS_IOS) 763 if (process_type == switches::kRendererProcess || 764 process_type == switches::kPpapiPluginProcess || 765 (delegate_ && delegate_->DelaySandboxInitialization(process_type))) { 766 // On OS X the renderer sandbox needs to be initialized later in the 767 // startup sequence in RendererMainPlatformDelegate::EnableSandbox(). 768 } else { 769 CHECK(InitializeSandbox()); 770 } 771#endif 772 773 if (delegate_) 774 delegate_->SandboxInitialized(process_type); 775 776 // Return -1 to indicate no early termination. 777 return -1; 778 } 779 780 virtual int Run() OVERRIDE { 781 DCHECK(is_initialized_); 782 DCHECK(!is_shutdown_); 783 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 784 std::string process_type = 785 command_line.GetSwitchValueASCII(switches::kProcessType); 786 787 MainFunctionParams main_params(command_line); 788 main_params.ui_task = ui_task_; 789#if defined(OS_WIN) 790 main_params.sandbox_info = &sandbox_info_; 791#elif defined(OS_MACOSX) 792 main_params.autorelease_pool = autorelease_pool_.get(); 793#endif 794 795#if !defined(OS_IOS) 796 return RunNamedProcessTypeMain(process_type, main_params, delegate_); 797#else 798 return 1; 799#endif 800 } 801 802 virtual void Shutdown() OVERRIDE { 803 DCHECK(is_initialized_); 804 DCHECK(!is_shutdown_); 805 806 if (completed_basic_startup_ && delegate_) { 807 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 808 std::string process_type = 809 command_line.GetSwitchValueASCII(switches::kProcessType); 810 811 delegate_->ProcessExiting(process_type); 812 } 813 814#if !defined(OS_IOS) 815 ShutdownMojo(); 816#endif 817 818#if defined(OS_WIN) 819#ifdef _CRTDBG_MAP_ALLOC 820 _CrtDumpMemoryLeaks(); 821#endif // _CRTDBG_MAP_ALLOC 822 823 _Module.Term(); 824#endif // OS_WIN 825 826#if defined(OS_MACOSX) 827 autorelease_pool_.reset(NULL); 828#endif 829 830 exit_manager_.reset(NULL); 831 832 delegate_ = NULL; 833 is_shutdown_ = true; 834 } 835 836 private: 837 // True if the runner has been initialized. 838 bool is_initialized_; 839 840 // True if the runner has been shut down. 841 bool is_shutdown_; 842 843 // True if basic startup was completed. 844 bool completed_basic_startup_; 845 846 // Used if the embedder doesn't set one. 847 ContentClient empty_content_client_; 848 849 // The delegate will outlive this object. 850 ContentMainDelegate* delegate_; 851 852 scoped_ptr<base::AtExitManager> exit_manager_; 853#if defined(OS_WIN) 854 sandbox::SandboxInterfaceInfo sandbox_info_; 855#elif defined(OS_MACOSX) 856 scoped_ptr<base::mac::ScopedNSAutoreleasePool> autorelease_pool_; 857#endif 858 859 base::Closure* ui_task_; 860 861 DISALLOW_COPY_AND_ASSIGN(ContentMainRunnerImpl); 862}; 863 864// static 865ContentMainRunner* ContentMainRunner::Create() { 866 return new ContentMainRunnerImpl(); 867} 868 869} // namespace content 870