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)
100base::LazyInstance<chrome::ChromeContentBrowserClient>
101    g_chrome_content_browser_client = LAZY_INSTANCE_INITIALIZER;
102#endif
103
104#if !defined(CHROME_MULTIPLE_DLL_BROWSER)
105base::LazyInstance<chrome::ChromeContentRendererClient>
106    g_chrome_content_renderer_client = LAZY_INSTANCE_INITIALIZER;
107base::LazyInstance<chrome::ChromeContentUtilityClient>
108    g_chrome_content_utility_client = LAZY_INSTANCE_INITIALIZER;
109base::LazyInstance<chrome::ChromeContentPluginClient>
110    g_chrome_content_plugin_client = LAZY_INSTANCE_INITIALIZER;
111#endif
112
113#if defined(OS_POSIX)
114base::LazyInstance<chrome::ChromeBreakpadClient>::Leaky
115    g_chrome_breakpad_client = LAZY_INSTANCE_INITIALIZER;
116#endif
117
118extern int NaClMain(const content::MainFunctionParams&);
119extern int ServiceProcessMain(const content::MainFunctionParams&);
120
121namespace {
122
123#if defined(OS_WIN)
124const 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.
128bool 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.
136bool 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.
147void 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)
159static 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.
216void 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.
226bool 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.
253void 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.
279bool 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.
302void 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)
313void 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
322void 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
333struct MainFunction {
334  const char* name;
335  int (*function)(const content::MainFunctionParams&);
336};
337
338}  // namespace
339
340ChromeMainDelegate::ChromeMainDelegate() {
341  startup_metric_utils::RecordMainEntryPointTime();
342}
343
344ChromeMainDelegate::~ChromeMainDelegate() {
345}
346
347bool 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)
484void 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
571void 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
724void 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
737int 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
769void 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)
781bool ChromeMainDelegate::ProcessRegistersWithSystemProcess(
782    const std::string& process_type) {
783  return process_type == switches::kNaClLoaderProcess;
784}
785
786bool ChromeMainDelegate::ShouldSendMachPort(const std::string& process_type) {
787  return process_type != switches::kRelauncherProcess &&
788      process_type != switches::kServiceProcess;
789}
790
791bool 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)
799content::ZygoteForkDelegate* ChromeMainDelegate::ZygoteStarting() {
800#if defined(DISABLE_NACL)
801  return NULL;
802#else
803  return new NaClForkDelegate();
804#endif
805}
806
807void 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
823content::ContentBrowserClient*
824ChromeMainDelegate::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
832content::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
840content::ContentRendererClient*
841ChromeMainDelegate::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
849content::ContentUtilityClient*
850ChromeMainDelegate::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