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