Home | History | Annotate | Download | only in app
      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