chrome_main_delegate.cc revision 010d83a9304c5a91596085d917d248abff47903a
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 "chrome/app/chrome_main_delegate.h" 6 7#include "base/command_line.h" 8#include "base/cpu.h" 9#include "base/files/file_path.h" 10#include "base/i18n/rtl.h" 11#include "base/lazy_instance.h" 12#include "base/message_loop/message_loop.h" 13#include "base/metrics/statistics_recorder.h" 14#include "base/metrics/stats_counters.h" 15#include "base/path_service.h" 16#include "base/process/memory.h" 17#include "base/process/process_handle.h" 18#include "base/strings/string_util.h" 19#include "build/build_config.h" 20#include "chrome/browser/chrome_content_browser_client.h" 21#include "chrome/browser/defaults.h" 22#include "chrome/common/chrome_constants.h" 23#include "chrome/common/chrome_content_client.h" 24#include "chrome/common/chrome_paths.h" 25#include "chrome/common/chrome_paths_internal.h" 26#include "chrome/common/chrome_switches.h" 27#include "chrome/common/chrome_version_info.h" 28#include "chrome/common/crash_keys.h" 29#include "chrome/common/logging_chrome.h" 30#include "chrome/common/profiling.h" 31#include "chrome/common/switch_utils.h" 32#include "chrome/common/url_constants.h" 33#include "chrome/plugin/chrome_content_plugin_client.h" 34#include "chrome/renderer/chrome_content_renderer_client.h" 35#include "chrome/utility/chrome_content_utility_client.h" 36#include "components/nacl/common/nacl_switches.h" 37#include "components/startup_metric_utils/startup_metric_utils.h" 38#include "content/public/common/content_client.h" 39#include "content/public/common/content_paths.h" 40#include "ui/base/ui_base_switches.h" 41 42#if defined(OS_WIN) 43#include <atlbase.h> 44#include <malloc.h> 45#include <algorithm> 46#include "base/strings/string_util.h" 47#include "chrome/common/child_process_logging.h" 48#include "sandbox/win/src/sandbox.h" 49#include "tools/memory_watcher/memory_watcher.h" 50#include "ui/base/resource/resource_bundle_win.h" 51#endif 52 53#if defined(OS_MACOSX) 54#include "base/mac/mac_util.h" 55#include "base/mac/os_crash_dumps.h" 56#include "chrome/app/chrome_main_mac.h" 57#include "chrome/browser/mac/relauncher.h" 58#include "chrome/common/chrome_paths_internal.h" 59#include "chrome/common/mac/cfbundle_blocker.h" 60#include "chrome/common/mac/objc_zombie.h" 61#include "components/breakpad/app/breakpad_mac.h" 62#include "grit/chromium_strings.h" 63#include "ui/base/l10n/l10n_util_mac.h" 64#endif 65 66#if defined(OS_POSIX) 67#include <locale.h> 68#include <signal.h> 69#include "chrome/app/chrome_breakpad_client.h" 70#include "components/breakpad/app/breakpad_client.h" 71#endif 72 73#if !defined(DISABLE_NACL) && defined(OS_LINUX) 74#include "components/nacl/common/nacl_paths.h" 75#include "components/nacl/zygote/nacl_fork_delegate_linux.h" 76#endif 77 78#if defined(OS_CHROMEOS) 79#include "base/sys_info.h" 80#include "chrome/browser/chromeos/boot_times_loader.h" 81#include "chromeos/chromeos_paths.h" 82#include "chromeos/chromeos_switches.h" 83#endif 84 85#if defined(OS_ANDROID) 86#include "chrome/common/descriptors_android.h" 87#else 88// Diagnostics is only available on non-android platforms. 89#include "chrome/browser/diagnostics/diagnostics_controller.h" 90#include "chrome/browser/diagnostics/diagnostics_writer.h" 91#endif 92 93#if defined(USE_X11) 94#include <stdlib.h> 95#include <string.h> 96#include "ui/base/x/x11_util.h" 97#endif 98 99#if defined(OS_POSIX) && !defined(OS_MACOSX) 100#include "components/breakpad/app/breakpad_linux.h" 101#endif 102 103#if defined(OS_LINUX) 104#include "base/environment.h" 105#endif 106 107#if defined(OS_MACOSX) || defined(OS_WIN) 108#include "chrome/browser/policy/policy_path_parser.h" 109#endif 110 111#if !defined(CHROME_MULTIPLE_DLL_CHILD) 112base::LazyInstance<chrome::ChromeContentBrowserClient> 113 g_chrome_content_browser_client = LAZY_INSTANCE_INITIALIZER; 114#endif 115 116#if !defined(CHROME_MULTIPLE_DLL_BROWSER) 117base::LazyInstance<ChromeContentRendererClient> 118 g_chrome_content_renderer_client = LAZY_INSTANCE_INITIALIZER; 119base::LazyInstance<chrome::ChromeContentUtilityClient> 120 g_chrome_content_utility_client = LAZY_INSTANCE_INITIALIZER; 121base::LazyInstance<chrome::ChromeContentPluginClient> 122 g_chrome_content_plugin_client = LAZY_INSTANCE_INITIALIZER; 123#endif 124 125#if defined(OS_POSIX) 126base::LazyInstance<chrome::ChromeBreakpadClient>::Leaky 127 g_chrome_breakpad_client = LAZY_INSTANCE_INITIALIZER; 128#endif 129 130extern int NaClMain(const content::MainFunctionParams&); 131extern int ServiceProcessMain(const content::MainFunctionParams&); 132 133namespace { 134 135#if defined(OS_WIN) 136const wchar_t kProfilingDll[] = L"memory_watcher.dll"; 137 138// Load the memory profiling DLL. All it needs to be activated 139// is to be loaded. Return true on success, false otherwise. 140bool LoadMemoryProfiler() { 141 HMODULE prof_module = LoadLibrary(kProfilingDll); 142 return prof_module != NULL; 143} 144 145// Early versions of Chrome incorrectly registered a chromehtml: URL handler, 146// which gives us nothing but trouble. Avoid launching chrome this way since 147// some apps fail to properly escape arguments. 148bool HasDeprecatedArguments(const std::wstring& command_line) { 149 const wchar_t kChromeHtml[] = L"chromehtml:"; 150 std::wstring command_line_lower = command_line; 151 // We are only searching for ASCII characters so this is OK. 152 StringToLowerASCII(&command_line_lower); 153 std::wstring::size_type pos = command_line_lower.find(kChromeHtml); 154 return (pos != std::wstring::npos); 155} 156 157// If we try to access a path that is not currently available, we want the call 158// to fail rather than show an error dialog. 159void SuppressWindowsErrorDialogs() { 160 UINT new_flags = SEM_FAILCRITICALERRORS | 161 SEM_NOOPENFILEERRORBOX; 162 163 // Preserve existing error mode. 164 UINT existing_flags = SetErrorMode(new_flags); 165 SetErrorMode(existing_flags | new_flags); 166} 167 168#endif // defined(OS_WIN) 169 170#if defined(OS_LINUX) 171static void AdjustLinuxOOMScore(const std::string& process_type) { 172 // Browsers and zygotes should still be killable, but killed last. 173 const int kZygoteScore = 0; 174 // The minimum amount to bump a score by. This is large enough that 175 // even if it's translated into the old values, it will still go up 176 // by at least one. 177 const int kScoreBump = 100; 178 // This is the lowest score that renderers and extensions start with 179 // in the OomPriorityManager. 180 const int kRendererScore = chrome::kLowestRendererOomScore; 181 // For "miscellaneous" things, we want them after renderers, 182 // but before plugins. 183 const int kMiscScore = kRendererScore - kScoreBump; 184 // We want plugins to die after the renderers. 185 const int kPluginScore = kMiscScore - kScoreBump; 186 int score = -1; 187 188 DCHECK(kMiscScore > 0); 189 DCHECK(kPluginScore > 0); 190 191 if (process_type == switches::kPluginProcess || 192 process_type == switches::kPpapiPluginProcess) { 193 score = kPluginScore; 194 } else if (process_type == switches::kPpapiBrokerProcess) { 195 // The broker should be killed before the PPAPI plugin. 196 score = kPluginScore + kScoreBump; 197 } else if (process_type == switches::kUtilityProcess || 198 process_type == switches::kWorkerProcess || 199 process_type == switches::kGpuProcess || 200 process_type == switches::kServiceProcess) { 201 score = kMiscScore; 202#ifndef DISABLE_NACL 203 } else if (process_type == switches::kNaClLoaderProcess || 204 process_type == switches::kNaClLoaderNonSfiProcess) { 205 score = kPluginScore; 206#endif 207 } else if (process_type == switches::kZygoteProcess || 208 process_type.empty()) { 209 // For zygotes and unlabeled process types, we want to still make 210 // them killable by the OOM killer. 211 score = kZygoteScore; 212 } else if (process_type == switches::kRendererProcess) { 213 LOG(WARNING) << "process type 'renderer' " 214 << "should be created through the zygote."; 215 // When debugging, this process type can end up being run directly, but 216 // this isn't the typical path for assigning the OOM score for it. Still, 217 // we want to assign a score that is somewhat representative for debugging. 218 score = kRendererScore; 219 } else { 220 NOTREACHED() << "Unknown process type"; 221 } 222 if (score > -1) 223 base::AdjustOOMScore(base::GetCurrentProcId(), score); 224} 225#endif // defined(OS_LINUX) 226 227// Enable the heap profiler if the appropriate command-line switch is 228// present, bailing out of the app we can't. 229void EnableHeapProfiler(const CommandLine& command_line) { 230#if defined(OS_WIN) 231 if (command_line.HasSwitch(switches::kMemoryProfiling)) 232 if (!LoadMemoryProfiler()) 233 exit(-1); 234#endif 235} 236 237// Returns true if this subprocess type needs the ResourceBundle initialized 238// and resources loaded. 239bool SubprocessNeedsResourceBundle(const std::string& process_type) { 240 return 241#if defined(OS_WIN) || defined(OS_MACOSX) 242 // Windows needs resources for the default/null plugin. 243 // Mac needs them for the plugin process name. 244 process_type == switches::kPluginProcess || 245 // Needed for scrollbar related images. 246 process_type == switches::kWorkerProcess || 247#endif 248#if defined(OS_POSIX) && !defined(OS_MACOSX) 249 // The zygote process opens the resources for the renderers. 250 process_type == switches::kZygoteProcess || 251#endif 252#if defined(OS_MACOSX) 253 // Mac needs them too for scrollbar related images and for sandbox 254 // profiles. 255 process_type == switches::kNaClLoaderProcess || 256 process_type == switches::kPpapiPluginProcess || 257 process_type == switches::kPpapiBrokerProcess || 258 process_type == switches::kGpuProcess || 259#endif 260 process_type == switches::kRendererProcess || 261 process_type == switches::kUtilityProcess; 262} 263 264#if defined(OS_POSIX) 265// Check for --version and --product-version; return true if we encountered 266// one of these switches and should exit now. 267bool HandleVersionSwitches(const CommandLine& command_line) { 268 const chrome::VersionInfo version_info; 269 270#if !defined(OS_MACOSX) 271 if (command_line.HasSwitch(switches::kProductVersion)) { 272 printf("%s\n", version_info.Version().c_str()); 273 return true; 274 } 275#endif 276 277 if (command_line.HasSwitch(switches::kVersion)) { 278 printf("%s %s %s\n", 279 version_info.Name().c_str(), 280 version_info.Version().c_str(), 281 chrome::VersionInfo::GetVersionStringModifier().c_str()); 282 return true; 283 } 284 285 return false; 286} 287 288#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) 289// Show the man page if --help or -h is on the command line. 290void HandleHelpSwitches(const CommandLine& command_line) { 291 if (command_line.HasSwitch(switches::kHelp) || 292 command_line.HasSwitch(switches::kHelpShort)) { 293 base::FilePath binary(command_line.argv()[0]); 294 execlp("man", "man", binary.BaseName().value().c_str(), NULL); 295 PLOG(FATAL) << "execlp failed"; 296 } 297} 298#endif 299 300#if !defined(OS_MACOSX) && !defined(OS_ANDROID) 301void SIGTERMProfilingShutdown(int signal) { 302 Profiling::Stop(); 303 struct sigaction sigact; 304 memset(&sigact, 0, sizeof(sigact)); 305 sigact.sa_handler = SIG_DFL; 306 CHECK(sigaction(SIGTERM, &sigact, NULL) == 0); 307 raise(signal); 308} 309 310void SetUpProfilingShutdownHandler() { 311 struct sigaction sigact; 312 sigact.sa_handler = SIGTERMProfilingShutdown; 313 sigact.sa_flags = SA_RESETHAND; 314 sigemptyset(&sigact.sa_mask); 315 CHECK(sigaction(SIGTERM, &sigact, NULL) == 0); 316} 317#endif // !defined(OS_MACOSX) && !defined(OS_ANDROID) 318 319#endif // OS_POSIX 320 321struct MainFunction { 322 const char* name; 323 int (*function)(const content::MainFunctionParams&); 324}; 325 326// Initializes the user data dir. Must be called before InitializeLocalState(). 327void InitializeUserDataDir() { 328 CommandLine* command_line = CommandLine::ForCurrentProcess(); 329 base::FilePath user_data_dir = 330 command_line->GetSwitchValuePath(switches::kUserDataDir); 331 std::string process_type = 332 command_line->GetSwitchValueASCII(switches::kProcessType); 333 334#if defined(OS_LINUX) 335 // On Linux, Chrome does not support running multiple copies under different 336 // DISPLAYs, so the profile directory can be specified in the environment to 337 // support the virtual desktop use-case. 338 if (user_data_dir.empty()) { 339 std::string user_data_dir_string; 340 scoped_ptr<base::Environment> environment(base::Environment::Create()); 341 if (environment->GetVar("CHROME_USER_DATA_DIR", &user_data_dir_string) && 342 base::IsStringUTF8(user_data_dir_string)) { 343 user_data_dir = base::FilePath::FromUTF8Unsafe(user_data_dir_string); 344 } 345 } 346#endif 347#if defined(OS_MACOSX) || defined(OS_WIN) 348 policy::path_parser::CheckUserDataDirPolicy(&user_data_dir); 349#endif 350 351 const bool specified_directory_was_invalid = !user_data_dir.empty() && 352 !PathService::OverrideAndCreateIfNeeded(chrome::DIR_USER_DATA, 353 user_data_dir, false, true); 354 // Save inaccessible or invalid paths so the user may be prompted later. 355 if (specified_directory_was_invalid) 356 chrome::SetInvalidSpecifiedUserDataDir(user_data_dir); 357 358 // Warn and fail early if the process fails to get a user data directory. 359 if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) { 360 // If an invalid command-line or policy override was specified, the user 361 // will be given an error with that value. Otherwise, use the directory 362 // returned by PathService (or the fallback default directory) in the error. 363 if (!specified_directory_was_invalid) { 364 // PathService::Get() returns false and yields an empty path if it fails 365 // to create DIR_USER_DATA. Retrieve the default value manually to display 366 // a more meaningful error to the user in that case. 367 if (user_data_dir.empty()) 368 chrome::GetDefaultUserDataDirectory(&user_data_dir); 369 chrome::SetInvalidSpecifiedUserDataDir(user_data_dir); 370 } 371 372 // The browser process (which is identified by an empty |process_type|) will 373 // handle the error later; other processes that need the dir crash here. 374 CHECK(process_type.empty()) << "Unable to get the user data directory " 375 << "for process type: " << process_type; 376 } 377 378 // Append the fallback user data directory to the commandline. Otherwise, 379 // child or service processes will attempt to use the invalid directory. 380 if (specified_directory_was_invalid) 381 command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir); 382} 383 384} // namespace 385 386ChromeMainDelegate::ChromeMainDelegate() { 387#if defined(OS_ANDROID) 388// On Android the main entry point time is the time when the Java code starts. 389// This happens before the shared library containing this code is even loaded. 390// The Java startup code has recorded that time, but the C++ code can't fetch it 391// from the Java side until it has initialized the JNI. See 392// ChromeMainDelegateAndroid. 393#else 394 startup_metric_utils::RecordMainEntryPointTime(); 395#endif 396} 397 398ChromeMainDelegate::~ChromeMainDelegate() { 399} 400 401bool ChromeMainDelegate::BasicStartupComplete(int* exit_code) { 402#if defined(OS_CHROMEOS) 403 chromeos::BootTimesLoader::Get()->SaveChromeMainStats(); 404#endif 405 406 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 407 408#if defined(OS_MACOSX) 409 // Give the browser process a longer treadmill, since crashes 410 // there have more impact. 411 const bool is_browser = !command_line.HasSwitch(switches::kProcessType); 412 ObjcEvilDoers::ZombieEnable(true, is_browser ? 10000 : 1000); 413 414 SetUpBundleOverrides(); 415 chrome::common::mac::EnableCFBundleBlocker(); 416#endif 417 418 Profiling::ProcessStarted(); 419 420#if defined(OS_POSIX) 421 if (HandleVersionSwitches(command_line)) { 422 *exit_code = 0; 423 return true; // Got a --version switch; exit with a success error code. 424 } 425#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) 426 // This will directly exit if the user asked for help. 427 HandleHelpSwitches(command_line); 428#endif 429#endif // OS_POSIX 430 431#if defined(OS_WIN) 432 // Must do this before any other usage of command line! 433 if (HasDeprecatedArguments(command_line.GetCommandLineString())) { 434 *exit_code = 1; 435 return true; 436 } 437#endif 438 439 chrome::RegisterPathProvider(); 440#if defined(OS_CHROMEOS) 441 chromeos::RegisterPathProvider(); 442#endif 443#if !defined(DISABLE_NACL) && defined(OS_LINUX) 444 nacl::RegisterPathProvider(); 445#endif 446 447// No support for ANDROID yet as DiagnosticsController needs wchar support. 448// TODO(gspencer): That's not true anymore, or at least there are no w-string 449// references anymore. Not sure if that means this can be enabled on Android or 450// not though. As there is no easily accessible command line on Android, I'm 451// not sure this is a big deal. 452#if !defined(OS_ANDROID) && !defined(CHROME_MULTIPLE_DLL_CHILD) 453 // If we are in diagnostics mode this is the end of the line: after the 454 // diagnostics are run the process will invariably exit. 455 if (command_line.HasSwitch(switches::kDiagnostics)) { 456 diagnostics::DiagnosticsWriter::FormatType format = 457 diagnostics::DiagnosticsWriter::HUMAN; 458 if (command_line.HasSwitch(switches::kDiagnosticsFormat)) { 459 std::string format_str = 460 command_line.GetSwitchValueASCII(switches::kDiagnosticsFormat); 461 if (format_str == "machine") { 462 format = diagnostics::DiagnosticsWriter::MACHINE; 463 } else if (format_str == "log") { 464 format = diagnostics::DiagnosticsWriter::LOG; 465 } else { 466 DCHECK_EQ("human", format_str); 467 } 468 } 469 470 diagnostics::DiagnosticsWriter writer(format); 471 *exit_code = diagnostics::DiagnosticsController::GetInstance()->Run( 472 command_line, &writer); 473 diagnostics::DiagnosticsController::GetInstance()->ClearResults(); 474 return true; 475 } 476#endif 477 478#if defined(OS_CHROMEOS) 479 // If we are recovering from a crash on ChromeOS, then we will do some 480 // recovery using the diagnostics module, and then continue on. We fake up a 481 // command line to tell it that we want it to recover, and to preserve the 482 // original command line. 483 if (command_line.HasSwitch(chromeos::switches::kLoginUser) || 484 command_line.HasSwitch(switches::kDiagnosticsRecovery)) { 485 486 // The statistics subsystem needs get initialized soon enough for the 487 // statistics to be collected. It's safe to call this more than once. 488 base::StatisticsRecorder::Initialize(); 489 490 CommandLine interim_command_line(command_line.GetProgram()); 491 const char* kSwitchNames[] = {switches::kUserDataDir, }; 492 interim_command_line.CopySwitchesFrom( 493 command_line, kSwitchNames, arraysize(kSwitchNames)); 494 interim_command_line.AppendSwitch(switches::kDiagnostics); 495 interim_command_line.AppendSwitch(switches::kDiagnosticsRecovery); 496 497 diagnostics::DiagnosticsWriter::FormatType format = 498 diagnostics::DiagnosticsWriter::LOG; 499 if (command_line.HasSwitch(switches::kDiagnosticsFormat)) { 500 std::string format_str = 501 command_line.GetSwitchValueASCII(switches::kDiagnosticsFormat); 502 if (format_str == "machine") { 503 format = diagnostics::DiagnosticsWriter::MACHINE; 504 } else if (format_str == "human") { 505 format = diagnostics::DiagnosticsWriter::HUMAN; 506 } else { 507 DCHECK_EQ("log", format_str); 508 } 509 } 510 511 diagnostics::DiagnosticsWriter writer(format); 512 int diagnostics_exit_code = 513 diagnostics::DiagnosticsController::GetInstance()->Run(command_line, 514 &writer); 515 if (diagnostics_exit_code) { 516 // Diagnostics has failed somehow, so we exit. 517 *exit_code = diagnostics_exit_code; 518 return true; 519 } 520 521 // Now we run the actual recovery tasks. 522 int recovery_exit_code = 523 diagnostics::DiagnosticsController::GetInstance()->RunRecovery( 524 command_line, &writer); 525 526 if (recovery_exit_code) { 527 // Recovery has failed somehow, so we exit. 528 *exit_code = recovery_exit_code; 529 return true; 530 } 531 } else { // Not running diagnostics or recovery. 532 diagnostics::DiagnosticsController::GetInstance()->RecordRegularStartup(); 533 } 534#endif 535 536 content::SetContentClient(&chrome_content_client_); 537 538 return false; 539} 540 541#if defined(OS_MACOSX) 542void ChromeMainDelegate::InitMacCrashReporter( 543 const base::CommandLine& command_line, 544 const std::string& process_type) { 545 // TODO(mark): Right now, InitCrashReporter() needs to be called after 546 // CommandLine::Init() and chrome::RegisterPathProvider(). Ideally, 547 // Breakpad initialization could occur sooner, preferably even before the 548 // framework dylib is even loaded, to catch potential early crashes. 549 breakpad::InitCrashReporter(process_type); 550 551#if defined(NDEBUG) 552 bool is_debug_build = false; 553#else 554 bool is_debug_build = true; 555#endif 556 557 // Details on when we enable Apple's Crash reporter. 558 // 559 // Motivation: 560 // In debug mode it takes Apple's crash reporter eons to generate a crash 561 // dump. 562 // 563 // What we do: 564 // * We only pass crashes for foreground processes to Apple's Crash 565 // reporter. At the time of this writing, that means just the Browser 566 // process. 567 // * If Breakpad is enabled, it will pass browser crashes to Crash Reporter 568 // itself. 569 // * If Breakpad is disabled, we only turn on Crash Reporter for the 570 // Browser process in release mode. 571 if (!command_line.HasSwitch(switches::kDisableBreakpad)) { 572 bool disable_apple_crash_reporter = is_debug_build || 573 base::mac::IsBackgroundOnlyProcess(); 574 if (!breakpad::IsCrashReporterEnabled() && disable_apple_crash_reporter) { 575 base::mac::DisableOSCrashDumps(); 576 } 577 } 578 579 // Mac Chrome is packaged with a main app bundle and a helper app bundle. 580 // The main app bundle should only be used for the browser process, so it 581 // should never see a --type switch (switches::kProcessType). Likewise, 582 // the helper should always have a --type switch. 583 // 584 // This check is done this late so there is already a call to 585 // base::mac::IsBackgroundOnlyProcess(), so there is no change in 586 // startup/initialization order. 587 588 // The helper's Info.plist marks it as a background only app. 589 if (base::mac::IsBackgroundOnlyProcess()) { 590 CHECK(command_line.HasSwitch(switches::kProcessType) && 591 !process_type.empty()) 592 << "Helper application requires --type."; 593 594 // In addition, some helper flavors only work with certain process types. 595 base::FilePath executable; 596 if (PathService::Get(base::FILE_EXE, &executable) && 597 executable.value().size() >= 3) { 598 std::string last_three = 599 executable.value().substr(executable.value().size() - 3); 600 601 if (last_three == " EH") { 602 CHECK(process_type == switches::kPluginProcess || 603 process_type == switches::kUtilityProcess) 604 << "Executable-heap process requires --type=" 605 << switches::kPluginProcess << " or " 606 << switches::kUtilityProcess << ", saw " << process_type; 607 } else if (last_three == " NP") { 608 CHECK_EQ(switches::kNaClLoaderProcess, process_type) 609 << "Non-PIE process requires --type=" 610 << switches::kNaClLoaderProcess << ", saw " << process_type; 611 } else { 612 CHECK(process_type != switches::kPluginProcess && 613 process_type != switches::kNaClLoaderProcess) 614 << "Non-executable-heap PIE process is intolerant of --type=" 615 << switches::kPluginProcess << " and " 616 << switches::kNaClLoaderProcess << ", saw " << process_type; 617 } 618 } 619 } else { 620 CHECK(!command_line.HasSwitch(switches::kProcessType) && 621 process_type.empty()) 622 << "Main application forbids --type, saw " << process_type; 623 } 624 625 if (breakpad::IsCrashReporterEnabled()) 626 breakpad::InitCrashProcessInfo(process_type); 627} 628#endif // defined(OS_MACOSX) 629 630void ChromeMainDelegate::PreSandboxStartup() { 631 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 632 std::string process_type = 633 command_line.GetSwitchValueASCII(switches::kProcessType); 634 635#if defined(OS_POSIX) 636 breakpad::SetBreakpadClient(g_chrome_breakpad_client.Pointer()); 637#endif 638 639#if defined(OS_MACOSX) 640 // On the Mac, the child executable lives at a predefined location within 641 // the app bundle's versioned directory. 642 PathService::Override(content::CHILD_PROCESS_EXE, 643 chrome::GetVersionedDirectory(). 644 Append(chrome::kHelperProcessExecutablePath)); 645 646 InitMacCrashReporter(command_line, process_type); 647#endif 648 649#if defined(OS_WIN) 650 child_process_logging::Init(); 651#endif 652#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) 653 // Create an instance of the CPU class to parse /proc/cpuinfo and cache 654 // cpu_brand info. 655 base::CPU cpu_info; 656#endif 657 658 // Initialize the user data dir for any process type that needs it. 659 if (chrome::ProcessNeedsProfileDir(process_type)) 660 InitializeUserDataDir(); 661 662 stats_counter_timer_.reset(new base::StatsCounterTimer("Chrome.Init")); 663 startup_timer_.reset(new base::StatsScope<base::StatsCounterTimer> 664 (*stats_counter_timer_)); 665 666 // Enable the heap profiler as early as possible! 667 EnableHeapProfiler(command_line); 668 669 // Enable Message Loop related state asap. 670 if (command_line.HasSwitch(switches::kMessageLoopHistogrammer)) 671 base::MessageLoop::EnableHistogrammer(true); 672 673#if !defined(OS_ANDROID) 674 // Android does InitLogging when library is loaded. Skip here. 675 logging::OldFileDeletionState file_state = 676 logging::APPEND_TO_OLD_LOG_FILE; 677 if (process_type.empty()) { 678 file_state = logging::DELETE_OLD_LOG_FILE; 679 } 680 logging::InitChromeLogging(command_line, file_state); 681#endif 682 683#if defined(OS_WIN) 684 // TODO(zturner): Throbber icons are still stored in chrome.dll, this can be 685 // killed once those are merged into resources.pak. See 686 // GlassBrowserFrameView::InitThrobberIcons() and http://crbug.com/368327. 687 ui::SetResourcesDataDLL(_AtlBaseModule.GetResourceInstance()); 688#endif 689 690 if (SubprocessNeedsResourceBundle(process_type)) { 691 // Initialize ResourceBundle which handles files loaded from external 692 // sources. The language should have been passed in to us from the 693 // browser process as a command line flag. 694#if defined(DISABLE_NACL) 695 DCHECK(command_line.HasSwitch(switches::kLang) || 696 process_type == switches::kZygoteProcess || 697 process_type == switches::kGpuProcess || 698 process_type == switches::kPpapiBrokerProcess || 699 process_type == switches::kPpapiPluginProcess); 700#else 701 DCHECK(command_line.HasSwitch(switches::kLang) || 702 process_type == switches::kZygoteProcess || 703 process_type == switches::kGpuProcess || 704 process_type == switches::kNaClLoaderProcess || 705 process_type == switches::kPpapiBrokerProcess || 706 process_type == switches::kPpapiPluginProcess); 707#endif 708 709 // TODO(markusheintz): The command line flag --lang is actually processed 710 // by the CommandLinePrefStore, and made available through the PrefService 711 // via the preference prefs::kApplicationLocale. The browser process uses 712 // the --lang flag to pass the value of the PrefService in here. Maybe 713 // this value could be passed in a different way. 714 const std::string locale = 715 command_line.GetSwitchValueASCII(switches::kLang); 716#if defined(OS_ANDROID) 717 // The renderer sandbox prevents us from accessing our .pak files directly. 718 // Therefore file descriptors to the .pak files that we need are passed in 719 // at process creation time. 720 int locale_pak_fd = base::GlobalDescriptors::GetInstance()->MaybeGet( 721 kAndroidLocalePakDescriptor); 722 CHECK(locale_pak_fd != -1); 723 ResourceBundle::InitSharedInstanceWithPakFile(base::File(locale_pak_fd), 724 false); 725 726 int extra_pak_keys[] = { 727 kAndroidChrome100PercentPakDescriptor, 728 kAndroidUIResourcesPakDescriptor, 729 }; 730 for (size_t i = 0; i < arraysize(extra_pak_keys); ++i) { 731 int pak_fd = 732 base::GlobalDescriptors::GetInstance()->MaybeGet(extra_pak_keys[i]); 733 CHECK(pak_fd != -1); 734 ResourceBundle::GetSharedInstance().AddDataPackFromFile( 735 base::File(pak_fd), ui::SCALE_FACTOR_100P); 736 } 737 738 base::i18n::SetICUDefaultLocale(locale); 739 const std::string loaded_locale = locale; 740#else 741 const std::string loaded_locale = 742 ResourceBundle::InitSharedInstanceWithLocale(locale, NULL); 743 744 base::FilePath resources_pack_path; 745 PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path); 746 ResourceBundle::GetSharedInstance().AddDataPackFromPath( 747 resources_pack_path, ui::SCALE_FACTOR_NONE); 748#endif 749 CHECK(!loaded_locale.empty()) << "Locale could not be found for " << 750 locale; 751 752#if !defined(CHROME_MULTIPLE_DLL_BROWSER) 753 if (process_type == switches::kUtilityProcess || 754 process_type == switches::kZygoteProcess) { 755 chrome::ChromeContentUtilityClient::PreSandboxStartup(); 756 } 757#endif 758 } 759 760#if defined(OS_POSIX) && !defined(OS_MACOSX) 761 // Zygote needs to call InitCrashReporter() in RunZygote(). 762 if (process_type != switches::kZygoteProcess) { 763#if defined(OS_ANDROID) 764 if (process_type.empty()) 765 breakpad::InitCrashReporter(process_type); 766 else 767 breakpad::InitNonBrowserCrashReporterForAndroid(process_type); 768#else // !defined(OS_ANDROID) 769 breakpad::InitCrashReporter(process_type); 770#endif // defined(OS_ANDROID) 771 } 772#endif // defined(OS_POSIX) && !defined(OS_MACOSX) 773 774 // After all the platform Breakpads have been initialized, store the command 775 // line for crash reporting. 776 crash_keys::SetSwitchesFromCommandLine(&command_line); 777} 778 779void ChromeMainDelegate::SandboxInitialized(const std::string& process_type) { 780 startup_timer_->Stop(); // End of Startup Time Measurement. 781 782 // Note: If you are adding a new process type below, be sure to adjust the 783 // AdjustLinuxOOMScore function too. 784#if defined(OS_LINUX) 785 AdjustLinuxOOMScore(process_type); 786#endif 787#if defined(OS_WIN) 788 SuppressWindowsErrorDialogs(); 789#endif 790} 791 792int ChromeMainDelegate::RunProcess( 793 const std::string& process_type, 794 const content::MainFunctionParams& main_function_params) { 795 // ANDROID doesn't support "service", so no ServiceProcessMain, and arraysize 796 // doesn't support empty array. So we comment out the block for Android. 797#if !defined(OS_ANDROID) 798 static const MainFunction kMainFunctions[] = { 799#if defined(ENABLE_FULL_PRINTING) && !defined(CHROME_MULTIPLE_DLL_CHILD) 800 { switches::kServiceProcess, ServiceProcessMain }, 801#endif 802 803#if defined(OS_MACOSX) 804 { switches::kRelauncherProcess, 805 mac_relauncher::internal::RelauncherMain }, 806#endif 807 808 // This entry is not needed on Linux, where the NaCl loader 809 // process is launched via nacl_helper instead. 810#if !defined(DISABLE_NACL) && !defined(CHROME_MULTIPLE_DLL_BROWSER) && \ 811 !defined(OS_LINUX) 812 { switches::kNaClLoaderProcess, NaClMain }, 813#else 814 { "<invalid>", NULL }, // To avoid constant array of size 0 815 // when DISABLE_NACL and CHROME_MULTIPLE_DLL_CHILD 816#endif // DISABLE_NACL 817 }; 818 819 for (size_t i = 0; i < arraysize(kMainFunctions); ++i) { 820 if (process_type == kMainFunctions[i].name) 821 return kMainFunctions[i].function(main_function_params); 822 } 823#endif 824 825 return -1; 826} 827 828void ChromeMainDelegate::ProcessExiting(const std::string& process_type) { 829 if (SubprocessNeedsResourceBundle(process_type)) 830 ResourceBundle::CleanupSharedInstance(); 831#if !defined(OS_ANDROID) 832 logging::CleanupChromeLogging(); 833#else 834 // Android doesn't use InitChromeLogging, so we close the log file manually. 835 logging::CloseLogFile(); 836#endif // !defined(OS_ANDROID) 837} 838 839#if defined(OS_MACOSX) 840bool ChromeMainDelegate::ProcessRegistersWithSystemProcess( 841 const std::string& process_type) { 842 return process_type == switches::kNaClLoaderProcess; 843} 844 845bool ChromeMainDelegate::ShouldSendMachPort(const std::string& process_type) { 846 return process_type != switches::kRelauncherProcess && 847 process_type != switches::kServiceProcess; 848} 849 850bool ChromeMainDelegate::DelaySandboxInitialization( 851 const std::string& process_type) { 852 // NaClLoader does this in NaClMainPlatformDelegate::EnableSandbox(). 853 // No sandbox needed for relauncher. 854 return process_type == switches::kNaClLoaderProcess || 855 process_type == switches::kRelauncherProcess; 856} 857#elif defined(OS_POSIX) && !defined(OS_ANDROID) 858content::ZygoteForkDelegate* ChromeMainDelegate::ZygoteStarting() { 859#if defined(DISABLE_NACL) 860 return NULL; 861#else 862 return new NaClForkDelegate(); 863#endif 864} 865 866void ChromeMainDelegate::ZygoteForked() { 867 Profiling::ProcessStarted(); 868 if (Profiling::BeingProfiled()) { 869 base::debug::RestartProfilingAfterFork(); 870 SetUpProfilingShutdownHandler(); 871 } 872 873 // Needs to be called after we have chrome::DIR_USER_DATA. BrowserMain sets 874 // this up for the browser process in a different manner. 875 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 876 std::string process_type = 877 command_line->GetSwitchValueASCII(switches::kProcessType); 878 breakpad::InitCrashReporter(process_type); 879 880 // Reset the command line for the newly spawned process. 881 crash_keys::SetSwitchesFromCommandLine(command_line); 882} 883 884#endif // OS_MACOSX 885 886content::ContentBrowserClient* 887ChromeMainDelegate::CreateContentBrowserClient() { 888#if defined(CHROME_MULTIPLE_DLL_CHILD) 889 return NULL; 890#else 891 return g_chrome_content_browser_client.Pointer(); 892#endif 893} 894 895content::ContentPluginClient* ChromeMainDelegate::CreateContentPluginClient() { 896#if defined(CHROME_MULTIPLE_DLL_BROWSER) 897 return NULL; 898#else 899 return g_chrome_content_plugin_client.Pointer(); 900#endif 901} 902 903content::ContentRendererClient* 904ChromeMainDelegate::CreateContentRendererClient() { 905#if defined(CHROME_MULTIPLE_DLL_BROWSER) 906 return NULL; 907#else 908 return g_chrome_content_renderer_client.Pointer(); 909#endif 910} 911 912content::ContentUtilityClient* 913ChromeMainDelegate::CreateContentUtilityClient() { 914#if defined(CHROME_MULTIPLE_DLL_BROWSER) 915 return NULL; 916#else 917 return g_chrome_content_utility_client.Pointer(); 918#endif 919} 920