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