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