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