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