Remove EWK_BRINGUPS for M120 #3
[platform/framework/web/chromium-efl.git] / chrome / app / chrome_main_delegate.cc
1 // Copyright 2012 The Chromium Authors
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 <stddef.h>
8
9 #include <string>
10
11 #include "base/base_paths.h"
12 #include "base/check.h"
13 #include "base/command_line.h"
14 #include "base/cpu.h"
15 #include "base/cpu_reduction_experiment.h"
16 #include "base/dcheck_is_on.h"
17 #include "base/files/file_path.h"
18 #include "base/files/file_util.h"
19 #include "base/functional/bind.h"
20 #include "base/functional/overloaded.h"
21 #include "base/i18n/rtl.h"
22 #include "base/immediate_crash.h"
23 #include "base/lazy_instance.h"
24 #include "base/metrics/histogram_macros.h"
25 #include "base/notreached.h"
26 #include "base/path_service.h"
27 #include "base/process/memory.h"
28 #include "base/process/process.h"
29 #include "base/process/process_handle.h"
30 #include "base/strings/string_util.h"
31 #include "base/strings/sys_string_conversions.h"
32 #include "base/strings/utf_string_conversions.h"
33 #include "base/task/sequence_manager/sequence_manager_impl.h"
34 #include "base/task/sequence_manager/thread_controller.h"
35 #include "base/task/sequence_manager/thread_controller_power_monitor.h"
36 #include "base/task/thread_pool/thread_pool_instance.h"
37 #include "base/threading/hang_watcher.h"
38 #include "base/threading/platform_thread.h"
39 #include "base/time/time.h"
40 #include "base/timer/timer.h"
41 #include "base/trace_event/trace_event_impl.h"
42 #include "build/build_config.h"
43 #include "build/chromeos_buildflags.h"
44 #include "chrome/browser/buildflags.h"
45 #include "chrome/browser/chrome_content_browser_client.h"
46 #include "chrome/browser/chrome_resource_bundle_helper.h"
47 #include "chrome/browser/defaults.h"
48 #include "chrome/browser/lifetime/browser_shutdown.h"
49 #include "chrome/browser/metrics/chrome_feature_list_creator.h"
50 #include "chrome/browser/startup_data.h"
51 #include "chrome/common/buildflags.h"
52 #include "chrome/common/channel_info.h"
53 #include "chrome/common/chrome_constants.h"
54 #include "chrome/common/chrome_content_client.h"
55 #include "chrome/common/chrome_features.h"
56 #include "chrome/common/chrome_paths.h"
57 #include "chrome/common/chrome_paths_internal.h"
58 #include "chrome/common/chrome_result_codes.h"
59 #include "chrome/common/chrome_switches.h"
60 #include "chrome/common/crash_keys.h"
61 #include "chrome/common/logging_chrome.h"
62 #include "chrome/common/profiler/process_type.h"
63 #include "chrome/common/profiler/unwind_util.h"
64 #include "chrome/common/url_constants.h"
65 #include "chrome/gpu/chrome_content_gpu_client.h"
66 #include "chrome/grit/generated_resources.h"
67 #include "chrome/renderer/chrome_content_renderer_client.h"
68 #include "chrome/utility/chrome_content_utility_client.h"
69 #include "components/component_updater/component_updater_paths.h"
70 #include "components/content_settings/core/common/content_settings_pattern.h"
71 #include "components/crash/core/app/crash_reporter_client.h"
72 #include "components/crash/core/common/crash_key.h"
73 #include "components/crash/core/common/crash_keys.h"
74 #include "components/devtools/devtools_pipe/devtools_pipe.h"
75 #include "components/memory_system/initializer.h"
76 #include "components/memory_system/parameters.h"
77 #include "components/metrics/persistent_histograms.h"
78 #include "components/nacl/common/buildflags.h"
79 #include "components/startup_metric_utils/common/startup_metric_utils.h"
80 #include "components/version_info/channel.h"
81 #include "components/version_info/version_info.h"
82 #include "content/public/app/initialize_mojo_core.h"
83 #include "content/public/common/content_client.h"
84 #include "content/public/common/content_constants.h"
85 #include "content/public/common/content_paths.h"
86 #include "content/public/common/content_switches.h"
87 #include "content/public/common/main_function_params.h"
88 #include "content/public/common/profiling.h"
89 #include "content/public/common/url_constants.h"
90 #include "extensions/buildflags/buildflags.h"
91 #include "net/http/http_cache.h"
92 #include "net/url_request/url_request.h"
93 #include "pdf/buildflags.h"
94 #include "ppapi/buildflags/buildflags.h"
95 #include "printing/buildflags/buildflags.h"
96 #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
97 #include "third_party/abseil-cpp/absl/types/variant.h"
98 #include "third_party/blink/public/common/features.h"
99 #include "ui/base/l10n/l10n_util.h"
100 #include "ui/base/resource/resource_bundle.h"
101 #include "ui/base/resource/scoped_startup_resource_bundle.h"
102 #include "ui/base/ui_base_switches.h"
103
104 #if BUILDFLAG(IS_WIN)
105 #include <malloc.h>
106
107 #include <algorithm>
108
109 #include "base/base_switches.h"
110 #include "base/files/important_file_writer_cleaner.h"
111 #include "base/threading/platform_thread_win.h"
112 #include "base/win/atl.h"
113 #include "base/win/resource_exhaustion.h"
114 #include "chrome/browser/chrome_browser_main_win.h"
115 #include "chrome/browser/win/browser_util.h"
116 #include "chrome/child/v8_crashpad_support_win.h"
117 #include "chrome/chrome_elf/chrome_elf_main.h"
118 #include "chrome/common/child_process_logging.h"
119 #include "chrome/common/chrome_version.h"
120 #include "sandbox/win/src/sandbox.h"
121 #include "sandbox/win/src/sandbox_factory.h"
122 #include "ui/base/resource/resource_bundle_win.h"
123 #endif
124
125 #if BUILDFLAG(IS_MAC)
126 #include "base/apple/foundation_util.h"
127 #include "base/message_loop/message_pump_apple.h"
128 #include "base/message_loop/message_pump_default.h"
129 #include "base/message_loop/message_pump_kqueue.h"
130 #include "base/synchronization/condition_variable.h"
131 #include "chrome/app/chrome_main_mac.h"
132 #include "chrome/browser/chrome_browser_application_mac.h"
133 #include "chrome/browser/headless/headless_mode_util.h"
134 #include "chrome/browser/mac/relauncher.h"
135 #include "chrome/browser/shell_integration.h"
136 #include "components/crash/core/common/objc_zombie.h"
137 #include "ui/base/l10n/l10n_util_mac.h"
138 #endif
139
140 #if BUILDFLAG(IS_POSIX)
141 #include <locale.h>
142 #include <signal.h>
143
144 #include "chrome/app/chrome_crash_reporter_client.h"
145 #include "components/about_ui/credit_utils.h"
146 #endif
147
148 #if BUILDFLAG(ENABLE_NACL) && (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
149 #include "components/nacl/common/nacl_paths.h"
150 #include "components/nacl/zygote/nacl_fork_delegate_linux.h"
151 #endif
152
153 #if BUILDFLAG(IS_CHROMEOS)
154 #include "chromeos/dbus/constants/dbus_paths.h"
155 #include "components/crash/core/app/breakpad_linux.h"
156 #include "ui/gfx/linux/gbm_util.h"  // nogncheck
157 #endif
158
159 #if BUILDFLAG(IS_CHROMEOS_ASH)
160 #include "ash/components/arc/arc_util.h"
161 #include "ash/constants/ash_paths.h"
162 #include "ash/constants/ash_switches.h"
163 #include "base/system/sys_info.h"
164 #include "chrome/browser/ash/boot_times_recorder.h"
165 #include "chrome/browser/ash/dbus/ash_dbus_helper.h"
166 #include "chrome/browser/ash/startup_settings_cache.h"
167 #include "chromeos/ash/components/memory/memory.h"
168 #include "chromeos/ash/components/memory/mglru.h"
169 #include "ui/lottie/resource.h"  // nogncheck
170 #endif
171
172 #if BUILDFLAG(IS_ANDROID)
173 #include "base/android/java_exception_reporter.h"
174 #include "base/android/library_loader/library_loader_hooks.h"
175 #include "chrome/browser/android/flags/chrome_cached_flags.h"
176 #include "chrome/browser/android/metrics/uma_session_stats.h"
177 #include "chrome/browser/flags/android/chrome_feature_list.h"
178 #include "chrome/common/chrome_descriptors.h"
179 #include "components/crash/android/pure_java_exception_handler.h"
180 #include "net/android/network_change_notifier_factory_android.h"
181 #else  // BUILDFLAG(IS_ANDROID)
182 // Diagnostics is only available on non-android platforms.
183 #include "chrome/browser/diagnostics/diagnostics_controller.h"
184 #include "chrome/browser/diagnostics/diagnostics_writer.h"
185 #endif
186
187 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_ANDROID)
188 #include "v8/include/v8-wasm-trap-handler-posix.h"
189 #include "v8/include/v8.h"
190 #endif
191
192 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
193 #include "base/environment.h"
194 #endif
195
196 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
197 #include "base/message_loop/message_pump_libevent.h"
198 #endif
199
200 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || \
201     BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
202 #include "chrome/browser/policy/policy_path_parser.h"
203 #include "components/crash/core/app/crashpad.h"
204 #endif
205
206 #if BUILDFLAG(ENABLE_EXTENSIONS)
207 #include "chrome/browser/extensions/startup_helper.h"
208 #include "extensions/common/constants.h"
209 #endif
210
211 #if BUILDFLAG(ENABLE_NACL)
212 #include "components/nacl/common/nacl_switches.h"
213 #include "components/nacl/renderer/plugin/ppapi_entrypoints.h"
214 #endif
215
216 #if BUILDFLAG(ENABLE_PDF)
217 #include "chrome/child/pdf_child_init.h"
218 #endif
219
220 #if BUILDFLAG(ENABLE_PROCESS_SINGLETON)
221 #include "chrome/browser/chrome_process_singleton.h"
222 #include "chrome/browser/process_singleton.h"
223 #endif  // BUILDFLAG(ENABLE_PROCESS_SINGLETON)
224
225 #if BUILDFLAG(IS_CHROMEOS_LACROS)
226 #include "base/scoped_add_feature_flags.h"
227 #include "chrome/common/chrome_paths_lacros.h"
228 #include "chromeos/crosapi/cpp/crosapi_constants.h"  // nogncheck
229 #include "chromeos/crosapi/mojom/crosapi.mojom.h"    // nogncheck
230 #include "chromeos/lacros/dbus/lacros_dbus_helper.h"
231 #include "chromeos/lacros/lacros_paths.h"
232 #include "chromeos/lacros/lacros_service.h"
233 #include "chromeos/startup/browser_params_proxy.h"      // nogncheck
234 #include "chromeos/startup/browser_postlogin_params.h"  // nogncheck
235 #include "chromeos/startup/startup.h"                   // nogncheck
236 #include "chromeos/startup/startup_switches.h"          // nogncheck
237 #include "content/public/browser/zygote_host/zygote_host_linux.h"
238 #include "media/base/media_switches.h"
239 #include "ui/accessibility/accessibility_features.h"
240 #include "ui/base/resource/data_pack_with_resource_sharing_lacros.h"
241 #include "ui/base/ui_base_features.h"
242 #include "ui/gfx/switches.h"
243 #endif
244
245 base::LazyInstance<ChromeContentGpuClient>::DestructorAtExit
246     g_chrome_content_gpu_client = LAZY_INSTANCE_INITIALIZER;
247 base::LazyInstance<ChromeContentRendererClient>::DestructorAtExit
248     g_chrome_content_renderer_client = LAZY_INSTANCE_INITIALIZER;
249
250 extern int NaClMain(content::MainFunctionParams);
251
252 const char* const ChromeMainDelegate::kNonWildcardDomainNonPortSchemes[] = {
253 #if BUILDFLAG(ENABLE_EXTENSIONS)
254     extensions::kExtensionScheme,
255 #endif
256     chrome::kChromeSearchScheme,       chrome::kIsolatedAppScheme,
257     content::kChromeDevToolsScheme,    content::kChromeUIScheme,
258     content::kChromeUIUntrustedScheme,
259 };
260 const size_t ChromeMainDelegate::kNonWildcardDomainNonPortSchemesSize =
261     std::size(kNonWildcardDomainNonPortSchemes);
262
263 namespace {
264
265 #if BUILDFLAG(IS_CHROMEOS_LACROS)
266 const base::FilePath::CharType kUserHomeDirPrefix[] =
267     FILE_PATH_LITERAL("/home/user");
268 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
269
270 #if BUILDFLAG(IS_WIN)
271 // Early versions of Chrome incorrectly registered a chromehtml: URL handler,
272 // which gives us nothing but trouble. Avoid launching chrome this way since
273 // some apps fail to properly escape arguments.
274 bool HasDeprecatedArguments(const std::wstring& command_line) {
275   const wchar_t kChromeHtml[] = L"chromehtml:";
276   std::wstring command_line_lower = base::ToLowerASCII(command_line);
277   // We are only searching for ASCII characters so this is OK.
278   return (command_line_lower.find(kChromeHtml) != std::wstring::npos);
279 }
280
281 // If we try to access a path that is not currently available, we want the call
282 // to fail rather than show an error dialog.
283 void SuppressWindowsErrorDialogs() {
284   UINT new_flags = SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX;
285
286   // Preserve existing error mode.
287   UINT existing_flags = SetErrorMode(new_flags);
288   SetErrorMode(existing_flags | new_flags);
289 }
290
291 bool IsSandboxedProcess() {
292   typedef bool (*IsSandboxedProcessFunc)();
293   IsSandboxedProcessFunc is_sandboxed_process_func =
294       reinterpret_cast<IsSandboxedProcessFunc>(
295           GetProcAddress(GetModuleHandle(NULL), "IsSandboxedProcess"));
296   return is_sandboxed_process_func && is_sandboxed_process_func();
297 }
298
299 #endif  // BUILDFLAG(IS_WIN)
300
301 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
302 void AdjustLinuxOOMScore(const std::string& process_type) {
303   int score = -1;
304
305   if (process_type == switches::kPpapiPluginProcess) {
306     score = content::kPluginOomScore;
307   } else if (process_type == switches::kUtilityProcess ||
308              process_type == switches::kGpuProcess) {
309     score = content::kMiscOomScore;
310 #if BUILDFLAG(ENABLE_NACL)
311   } else if (process_type == switches::kNaClLoaderProcess) {
312     score = content::kPluginOomScore;
313 #endif
314   } else if (process_type == switches::kZygoteProcess || process_type.empty()) {
315     // For zygotes and unlabeled process types, we want to still make
316     // them killable by the OOM killer.
317     score = content::kZygoteOomScore;
318   } else if (process_type == switches::kRendererProcess) {
319     LOG(WARNING) << "process type 'renderer' "
320                  << "should be created through the zygote.";
321     // When debugging, this process type can end up being run directly, but
322     // this isn't the typical path for assigning the OOM score for it.  Still,
323     // we want to assign a score that is somewhat representative for debugging.
324     score = content::kLowestRendererOomScore;
325   } else {
326     NOTREACHED() << "Unknown process type";
327   }
328   // In the case of a 0 score, still try to adjust it. Most likely the score is
329   // 0 already, but it may not be if this process inherited a higher score from
330   // its parent process.
331   if (score > -1)
332     base::AdjustOOMScore(base::GetCurrentProcId(), score);
333 }
334 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
335
336 // Returns true if this subprocess type needs the ResourceBundle initialized
337 // and resources loaded.
338 bool SubprocessNeedsResourceBundle(const std::string& process_type) {
339   return
340 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
341       // The zygote process opens the resources for the renderers.
342       process_type == switches::kZygoteProcess ||
343 #endif
344 #if BUILDFLAG(IS_MAC)
345   // Mac needs them too for scrollbar related images and for sandbox
346   // profiles.
347 #if BUILDFLAG(ENABLE_NACL)
348       process_type == switches::kNaClLoaderProcess ||
349 #endif
350       process_type == switches::kGpuProcess ||
351 #endif
352       process_type == switches::kPpapiPluginProcess ||
353       process_type == switches::kRendererProcess ||
354       process_type == switches::kUtilityProcess;
355 }
356
357 #if BUILDFLAG(IS_POSIX)
358 bool HandleCreditsSwitch(const base::CommandLine& command_line) {
359   if (!command_line.HasSwitch(switches::kCredits))
360     return false;
361
362   // Load resources: about_credits.html is in component_resources.pak that is
363   // re-packed into resources.pak.
364   base::FilePath resource_dir;
365   bool result = base::PathService::Get(base::DIR_ASSETS, &resource_dir);
366   DCHECK(result);
367
368   // Ensure there is an instance of ResourceBundle that is initialized for
369   // localized string resource accesses.
370   ui::ScopedStartupResourceBundle ensure_startup_resource_bundle;
371
372   base::FilePath resources_pak =
373       resource_dir.Append(FILE_PATH_LITERAL("resources.pak"));
374
375 #if BUILDFLAG(IS_MAC) && !defined(COMPONENT_BUILD)
376   // In non-component builds, check if a fallback in Resources/ folder is
377   // available.
378   if (!base::PathExists(resources_pak)) {
379     resources_pak =
380         resource_dir.Append(FILE_PATH_LITERAL("Resources/resources.pak"));
381   }
382 #endif
383
384   ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
385       resources_pak, ui::kScaleFactorNone);
386
387   auto credits = about_ui::GetCredits(/**include_scripts=*/false);
388   // If resources failed to load, about_ui::GetCredits returns
389   // a malformed HTML doc containing `</body>\n</html>`.
390   // When the resources loaded successfully, we get a huge document
391   // (~8 MiB) instead.
392   // We use a threshold of 100 characters to see if the resources
393   // were loaded successfully.
394   size_t resource_loading_threshold = 100;
395   if (credits.size() < resource_loading_threshold)
396     printf("%s\n", "Failed to load credits.");
397   else
398     printf("%s\n", credits.c_str());
399
400   return true;
401 }
402
403 // Check for --version and --product-version; return true if we encountered
404 // one of these switches and should exit now.
405 bool HandleVersionSwitches(const base::CommandLine& command_line) {
406 #if !BUILDFLAG(IS_MAC)
407   if (command_line.HasSwitch(switches::kProductVersion)) {
408     printf("%s\n", version_info::GetVersionNumber().data());
409     return true;
410   }
411 #endif
412
413   if (command_line.HasSwitch(switches::kVersion)) {
414     printf("%s %s %s\n", version_info::GetProductName().data(),
415            version_info::GetVersionNumber().data(),
416            chrome::GetChannelName(chrome::WithExtendedStable(true)).c_str());
417     return true;
418   }
419
420   return false;
421 }
422
423 // TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
424 // of lacros-chrome is complete.
425 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
426 // Show the man page if --help or -h is on the command line.
427 void HandleHelpSwitches(const base::CommandLine& command_line) {
428   if (command_line.HasSwitch(switches::kHelp) ||
429       command_line.HasSwitch(switches::kHelpShort)) {
430     base::FilePath binary(command_line.argv()[0]);
431     execlp("man", "man", binary.BaseName().value().c_str(), NULL);
432     PLOG(FATAL) << "execlp failed";
433   }
434 }
435 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
436
437 #if BUILDFLAG(IS_CHROMEOS_LACROS)
438 // BrowserManager launches Lacros redirecting its stderr to a log file.
439 // This function redirects stderr a second time, to another log file, after
440 // user login has happened (e.g. to the cryptohome).
441 // Only useful when pre-launching Lacros at login screen.
442 void RedirectLacrosLogging() {
443   const base::CommandLine& cmdline = *base::CommandLine::ForCurrentProcess();
444   uint32_t logging_dest = logging::DetermineLoggingDestination(cmdline);
445   base::FilePath log_file =
446       cmdline.GetSwitchValuePath(chromeos::switches::kCrosPostLoginLogFile);
447
448   if (!log_file.empty() && (logging_dest & logging::LOG_TO_STDERR)) {
449     log_file = logging::SetUpLogFile(log_file, /*new_log=*/true);
450     FILE* result = freopen(log_file.value().c_str(), "a", stderr);
451     DPCHECK(result != nullptr);
452
453     // Redirect Zygote and future children's logs.
454     if (result) {
455       content::ZygoteHost::GetInstance()->ReinitializeLogging(logging_dest,
456                                                               STDERR_FILENO);
457     }
458   }
459 }
460
461 void AddFeatureFlagsToCommandLine(
462     const chromeos::BrowserParamsProxy& init_params) {
463   base::ScopedAddFeatureFlags flags(base::CommandLine::ForCurrentProcess());
464
465   if (init_params.IsVariableRefreshRateAlwaysOn()) {
466     flags.EnableIfNotSet(features::kEnableVariableRefreshRateAlwaysOn);
467   }
468
469   if (init_params.IsPdfOcrEnabled()) {
470     flags.EnableIfNotSet(features::kPdfOcr);
471   }
472 }
473 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
474
475 #if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_ANDROID)
476 void SIGTERMProfilingShutdown(int signal) {
477   content::Profiling::Stop();
478   struct sigaction sigact;
479   memset(&sigact, 0, sizeof(sigact));
480   sigact.sa_handler = SIG_DFL;
481   CHECK_EQ(sigaction(SIGTERM, &sigact, nullptr), 0);
482   raise(signal);
483 }
484
485 void SetUpProfilingShutdownHandler() {
486   struct sigaction sigact;
487   sigact.sa_handler = SIGTERMProfilingShutdown;
488   sigact.sa_flags = SA_RESETHAND;
489   sigemptyset(&sigact.sa_mask);
490   CHECK_EQ(sigaction(SIGTERM, &sigact, nullptr), 0);
491 }
492 #endif  // !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_ANDROID)
493
494 #endif  // BUILDFLAG(IS_POSIX)
495
496 #if BUILDFLAG(ENABLE_EXTENSIONS)
497 absl::optional<int> HandlePackExtensionSwitches(
498     const base::CommandLine& command_line) {
499   // If the command line specifies --pack-extension, attempt the pack extension
500   // startup action and exit.
501   if (!command_line.HasSwitch(switches::kPackExtension))
502     return absl::nullopt;
503
504   // Ensure there is an instance of ResourceBundle that is initialized for
505   // localized string resource accesses.
506   ui::ScopedStartupResourceBundle ensure_startup_resource_bundle;
507
508   extensions::StartupHelper extension_startup_helper;
509   std::string error_message;
510   if (!extension_startup_helper.PackExtension(command_line, &error_message)) {
511     if (!error_message.empty()) {
512       LOG(ERROR) << error_message.c_str();
513     }
514     return chrome::RESULT_CODE_PACK_EXTENSION_ERROR;
515   }
516
517   return chrome::RESULT_CODE_NORMAL_EXIT_PACK_EXTENSION_SUCCESS;
518 }
519 #endif  // !BUILDFLAG(ENABLE_EXTENSIONS)
520
521 #if BUILDFLAG(ENABLE_PROCESS_SINGLETON)
522 absl::optional<int> AcquireProcessSingleton(
523     const base::FilePath& user_data_dir) {
524   // Take the Chrome process singleton lock. The process can become the
525   // Browser process if it succeed to take the lock. Otherwise, the
526   // command-line is sent to the actual Browser process and the current
527   // process can be exited.
528   ChromeProcessSingleton::CreateInstance(user_data_dir);
529
530   ProcessSingleton::NotifyResult notify_result =
531       ChromeProcessSingleton::GetInstance()->NotifyOtherProcessOrCreate();
532   UMA_HISTOGRAM_ENUMERATION("Chrome.ProcessSingleton.NotifyResult",
533                             notify_result, ProcessSingleton::kNumNotifyResults);
534
535   switch (notify_result) {
536     case ProcessSingleton::PROCESS_NONE:
537       break;
538
539     case ProcessSingleton::PROCESS_NOTIFIED: {
540       // Ensure there is an instance of ResourceBundle that is initialized for
541       // localized string resource accesses.
542       ui::ScopedStartupResourceBundle startup_resource_bundle;
543       printf("%s\n", base::SysWideToNativeMB(
544                          base::UTF16ToWide(l10n_util::GetStringUTF16(
545                              IDS_USED_EXISTING_BROWSER)))
546                          .c_str());
547       return chrome::RESULT_CODE_NORMAL_EXIT_PROCESS_NOTIFIED;
548     }
549
550     case ProcessSingleton::PROFILE_IN_USE:
551       return chrome::RESULT_CODE_PROFILE_IN_USE;
552
553     case ProcessSingleton::LOCK_ERROR:
554       LOG(ERROR) << "Failed to create a ProcessSingleton for your profile "
555                     "directory. This means that running multiple instances "
556                     "would start multiple browser processes rather than "
557                     "opening a new window in the existing process. Aborting "
558                     "now to avoid profile corruption.";
559       return chrome::RESULT_CODE_PROFILE_IN_USE;
560   }
561
562   return absl::nullopt;
563 }
564 #endif
565
566 struct MainFunction {
567   const char* name;
568   int (*function)(content::MainFunctionParams);
569 };
570
571 // Initializes the user data dir. Must be called before InitializeLocalState().
572 void InitializeUserDataDir(base::CommandLine* command_line) {
573 #if BUILDFLAG(IS_CHROMEOS_LACROS) && DCHECK_IS_ON()
574   // In debug builds of Lacros, we keep track of when the user data dir
575   // is initialized, to ensure the cryptohome is not accessed before login
576   // when prelaunching at login screen.
577   chromeos::lacros_paths::SetInitializedUserDataDir();
578 #endif
579 #if BUILDFLAG(IS_WIN)
580   // Reach out to chrome_elf for the truth on the user data directory.
581   // Note that in tests, this links to chrome_elf_test_stubs.
582   wchar_t user_data_dir_buf[MAX_PATH], invalid_user_data_dir_buf[MAX_PATH];
583
584   // In tests this may return false, implying the user data dir should be unset.
585   if (GetUserDataDirectoryThunk(user_data_dir_buf, std::size(user_data_dir_buf),
586                                 invalid_user_data_dir_buf,
587                                 std::size(invalid_user_data_dir_buf))) {
588     base::FilePath user_data_dir(user_data_dir_buf);
589     if (invalid_user_data_dir_buf[0] != 0) {
590       chrome::SetInvalidSpecifiedUserDataDir(
591           base::FilePath(invalid_user_data_dir_buf));
592       command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
593     }
594     CHECK(base::PathService::OverrideAndCreateIfNeeded(
595         chrome::DIR_USER_DATA, user_data_dir, false, true));
596   }
597 #else  // BUILDFLAG(IS_WIN)
598   base::FilePath user_data_dir =
599       command_line->GetSwitchValuePath(switches::kUserDataDir);
600   std::string process_type =
601       command_line->GetSwitchValueASCII(switches::kProcessType);
602
603 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
604   // On Linux, Chrome does not support running multiple copies under different
605   // DISPLAYs, so the profile directory can be specified in the environment to
606   // support the virtual desktop use-case.
607   if (user_data_dir.empty()) {
608     std::string user_data_dir_string;
609     std::unique_ptr<base::Environment> environment(base::Environment::Create());
610     if (environment->GetVar("CHROME_USER_DATA_DIR", &user_data_dir_string) &&
611         base::IsStringUTF8(user_data_dir_string)) {
612       user_data_dir = base::FilePath::FromUTF8Unsafe(user_data_dir_string);
613     }
614   }
615 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
616 #if BUILDFLAG(IS_MAC)
617   policy::path_parser::CheckUserDataDirPolicy(&user_data_dir);
618 #endif  // BUILDFLAG(IS_MAC)
619
620   const bool specified_directory_was_invalid =
621       !user_data_dir.empty() &&
622       !base::PathService::OverrideAndCreateIfNeeded(chrome::DIR_USER_DATA,
623                                                     user_data_dir, false, true);
624   // Save inaccessible or invalid paths so the user may be prompted later.
625   if (specified_directory_was_invalid)
626     chrome::SetInvalidSpecifiedUserDataDir(user_data_dir);
627
628   // Warn and fail early if the process fails to get a user data directory.
629   if (!base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
630     // If an invalid command-line or policy override was specified, the user
631     // will be given an error with that value. Otherwise, use the directory
632     // returned by PathService (or the fallback default directory) in the error.
633     if (!specified_directory_was_invalid) {
634       // base::PathService::Get() returns false and yields an empty path if it
635       // fails to create DIR_USER_DATA. Retrieve the default value manually to
636       // display a more meaningful error to the user in that case.
637       if (user_data_dir.empty())
638         chrome::GetDefaultUserDataDirectory(&user_data_dir);
639       chrome::SetInvalidSpecifiedUserDataDir(user_data_dir);
640     }
641
642     // The browser process (which is identified by an empty |process_type|) will
643     // handle the error later; other processes that need the dir crash here.
644     CHECK(process_type.empty()) << "Unable to get the user data directory "
645                                 << "for process type: " << process_type;
646   }
647
648   // Append the fallback user data directory to the commandline. Otherwise,
649   // child or service processes will attempt to use the invalid directory.
650   if (specified_directory_was_invalid)
651     command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
652 #endif  // BUILDFLAG(IS_WIN)
653 }
654
655 #if !BUILDFLAG(IS_ANDROID)
656 void InitLogging(const std::string& process_type) {
657   logging::OldFileDeletionState file_state = logging::APPEND_TO_OLD_LOG_FILE;
658   if (process_type.empty()) {
659     file_state = logging::DELETE_OLD_LOG_FILE;
660   }
661   const base::CommandLine& command_line =
662       *base::CommandLine::ForCurrentProcess();
663   logging::InitChromeLogging(command_line, file_state);
664   // Log the Chrome version for information. Do so at WARNING level as that's
665   // the min level on ChromeOS.
666   if (process_type.empty()) {
667     LOG(WARNING) << "This is Chrome version " << chrome::kChromeVersion
668                  << " (not a warning)";
669   }
670 }
671 #endif  // !BUILDFLAG(IS_ANDROID)
672
673 void RecordMainStartupMetrics(base::TimeTicks application_start_time) {
674   const base::TimeTicks now = base::TimeTicks::Now();
675
676 #if BUILDFLAG(IS_WIN)
677   DCHECK(!application_start_time.is_null());
678   startup_metric_utils::GetCommon().RecordApplicationStartTime(
679       application_start_time);
680 #elif BUILDFLAG(IS_ANDROID)
681   // On Android the main entry point time is the time when the Java code starts.
682   // This happens before the shared library containing this code is even loaded.
683   // The Java startup code has recorded that time, but the C++ code can't fetch
684   // it from the Java side until it has initialized the JNI. See
685   // ChromeMainDelegateAndroid.
686 #else
687   // On other platforms, |application_start_time| == |now| since the application
688   // starts with ChromeMain().
689   startup_metric_utils::GetCommon().RecordApplicationStartTime(now);
690 #endif
691
692 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || \
693     BUILDFLAG(IS_CHROMEOS)
694   // Record the startup process creation time on supported platforms. On Android
695   // this is recorded in ChromeMainDelegateAndroid.
696   startup_metric_utils::GetCommon().RecordStartupProcessCreationTime(
697       base::Process::Current().CreationTime());
698 #endif
699
700   startup_metric_utils::GetCommon().RecordChromeMainEntryTime(now);
701 }
702
703 #if BUILDFLAG(IS_WIN)
704 void OnResourceExhausted() {
705   // RegisterClassEx will fail if the session's pool of ATOMs is exhausted. This
706   // appears to happen most often when the browser is being driven by automation
707   // tools, though the underlying reason for this remains a mystery
708   // (https://crbug.com/1470483). There is nothing that Chrome can do to
709   // meaningfully run until the user restarts their session by signing out of
710   // Windows or restarting their computer.
711   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
712           switches::kNoErrorDialogs)) {
713     static constexpr wchar_t kMessageBoxTitle[] = L"System resource exhausted";
714     static constexpr wchar_t kMessage[] =
715         L"Your computer has run out of resources and cannot start "
716         PRODUCT_SHORTNAME_STRING
717         L". Sign out of Windows or restart your computer and try again.";
718     ::MessageBox(nullptr, kMessage, kMessageBoxTitle, MB_OK);
719   }
720   base::Process::TerminateCurrentProcessImmediately(
721       chrome::RESULT_CODE_SYSTEM_RESOURCE_EXHAUSTED);
722 }
723 #endif  // !BUILDFLAG(IS_WIN)
724
725 }  // namespace
726
727 ChromeMainDelegate::ChromeMainDelegate()
728     : ChromeMainDelegate(base::TimeTicks()) {}
729
730 ChromeMainDelegate::ChromeMainDelegate(base::TimeTicks exe_entry_point_ticks) {
731   // Record startup metrics in the browser process. For component builds, there
732   // is no way to know the type of process (process command line is not yet
733   // initialized), so the function below will also be called in renderers.
734   // This doesn't matter as it simply sets global variables.
735   RecordMainStartupMetrics(exe_entry_point_ticks);
736 }
737
738 #if !BUILDFLAG(IS_ANDROID)
739 ChromeMainDelegate::~ChromeMainDelegate() {
740   std::string process_type =
741       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
742           switches::kProcessType);
743   const bool is_browser_process = process_type.empty();
744   if (is_browser_process)
745     browser_shutdown::RecordShutdownMetrics();
746 }
747 #else
748 ChromeMainDelegate::~ChromeMainDelegate() = default;
749 #endif  // !BUILDFLAG(IS_ANDROID)
750
751 absl::optional<int> ChromeMainDelegate::PostEarlyInitialization(
752     InvokedIn invoked_in) {
753   DCHECK(base::ThreadPoolInstance::Get());
754   const auto* invoked_in_browser =
755       absl::get_if<InvokedInBrowserProcess>(&invoked_in);
756   if (!invoked_in_browser) {
757 #if BUILDFLAG(IS_CHROMEOS)
758     // At this point, the base::FeatureList has been initialized and the process
759     // should still be single threaded. Additionally, minigbm shouldn't have
760     // been used yet by this process. Therefore, it's a good time to ensure the
761     // Intel media compression environment flag for minigbm is correctly set
762     // (it's possible this environment variable wasn't inherited from the
763     // browser process).
764     ui::EnsureIntelMediaCompressionEnvVarIsSet();
765 #endif  // BUILDFLAG(IS_CHROMEOS)
766     CommonEarlyInitialization(invoked_in);
767     return absl::nullopt;
768   }
769
770 #if BUILDFLAG(ENABLE_PROCESS_SINGLETON)
771   // The User Data dir is guaranteed to be valid as per InitializeUserDataDir.
772   base::FilePath user_data_dir =
773       base::PathService::CheckedGet(chrome::DIR_USER_DATA);
774
775   // On platforms that support the process rendezvous, acquire the process
776   // singleton. In case of failure, it means there is already a running browser
777   // instance that handled the command-line.
778   if (auto process_singleton_result = AcquireProcessSingleton(user_data_dir);
779       process_singleton_result.has_value()) {
780     // To ensure that the histograms emitted in this process are reported in
781     // case of early exit, report the metrics accumulated this session with a
782     // future session's metrics.
783     DeferBrowserMetrics(user_data_dir);
784
785 #if BUILDFLAG(IS_WIN)
786     // In the case the process is not the singleton process, the uninstall tasks
787     // need to be executed here. A window will be displayed asking to close all
788     // running instances.
789     if (base::CommandLine::ForCurrentProcess()->HasSwitch(
790             switches::kUninstall)) {
791       // Ensure there is an instance of ResourceBundle that is initialized
792       // for localized string resource accesses.
793       ui::ScopedStartupResourceBundle startup_resource_bundle;
794       return DoUninstallTasks(browser_util::IsBrowserAlreadyRunning());
795     }
796 #endif
797
798     return process_singleton_result;
799   }
800 #endif
801
802 #if BUILDFLAG(IS_WIN)
803   // Initialize the cleaner of left-behind tmp files now that the main thread
804   // has its SequencedTaskRunner; see https://crbug.com/1075917.
805   base::ImportantFileWriterCleaner::GetInstance().Initialize();
806 #endif
807
808 #if !BUILDFLAG(IS_FUCHSIA)
809   // Schedule the cleanup of persistent histogram files. These tasks must only
810   // be scheduled in the main browser after taking the process singleton. They
811   // cannot be scheduled immediately after InstantiatePersistentHistograms()
812   // because ThreadPool is not ready at that time yet.
813   bool immediate_histogram_cleanup = true;
814 #if BUILDFLAG(IS_CHROMEOS_LACROS)
815   // When prelaunching Lacros at login screen, we want to postpone the
816   // cleanup of persistent histograms to when the user has logged in
817   // and the cryptohome is accessible.
818   immediate_histogram_cleanup = !chromeos::IsLaunchedWithPostLoginParams();
819 #endif
820   base::FilePath metrics_dir;
821   if (immediate_histogram_cleanup &&
822       base::PathService::Get(chrome::DIR_USER_DATA, &metrics_dir)) {
823     PersistentHistogramsCleanup(metrics_dir);
824   }
825 #endif  // !BUILDFLAG(IS_FUCHSIA)
826
827   // Chrome disallows cookies by default. All code paths that want to use
828   // cookies need to go through one of Chrome's URLRequestContexts which have
829   // a ChromeNetworkDelegate attached that selectively allows cookies again.
830   net::URLRequest::SetDefaultCookiePolicyToBlock();
831
832   // On Chrome OS, IPC (D-Bus, Crosapi) is required to create the FeatureList,
833   // which depends on policy from an OS service. So, initialize it at this
834   // timing.
835 #if BUILDFLAG(IS_CHROMEOS_ASH)
836   // The feature list depends on BrowserPolicyConnectorAsh which depends
837   // on DBus, so initialize it here. Some D-Bus clients may depend on feature
838   // list, so initialize them separately later at the end of this function.
839   ash::InitializeDBus();
840 #elif BUILDFLAG(IS_CHROMEOS_LACROS)
841   // Initialize D-Bus for Lacros.
842   chromeos::LacrosInitializeDBus();
843 #endif
844
845 #if BUILDFLAG(IS_CHROMEOS_LACROS)
846   // Set Lacros's default paths.
847   const auto& init_params = *chromeos::BrowserParamsProxy::Get();
848   chrome::SetLacrosDefaultPathsFromInitParams(init_params.DefaultPaths().get());
849
850   // Must be added before feature list is created otherwise the added flag won't
851   // be picked up.
852   AddFeatureFlagsToCommandLine(init_params);
853 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
854
855   // The DBus initialization above is needed for FeatureList creation here;
856   // features are needed for Mojo initialization; and Mojo initialization is
857   // needed for LacrosService initialization below.
858   ChromeFeatureListCreator* chrome_feature_list_creator =
859       chrome_content_browser_client_->startup_data()
860           ->chrome_feature_list_creator();
861   chrome_feature_list_creator->CreateFeatureList();
862
863 #if BUILDFLAG(IS_CHROMEOS)
864   // At this point, the base::FeatureList has been initialized and the process
865   // should still be single threaded. Additionally, minigbm shouldn't have been
866   // used yet by this process. Therefore, it's a good time to ensure the Intel
867   // media compression environment flag for minigbm is correctly set.
868   ui::EnsureIntelMediaCompressionEnvVarIsSet();
869 #endif  // BUILDFLAG(IS_CHROMEOS)
870
871   content::InitializeMojoCore();
872
873 #if BUILDFLAG(IS_CHROMEOS_LACROS)
874   // LacrosService instance needs the sequence of the main thread,
875   // and needs to be created earlier than incoming Mojo invitation handling.
876   // This also needs ThreadPool sequences to post some tasks internally.
877   // However, the tasks can be suspended until actual start of the ThreadPool
878   // sequences later.
879   lacros_service_ = std::make_unique<chromeos::LacrosService>();
880   {
881     // Override the login user DIR_HOME path for the Lacros browser process.
882     if (init_params.CrosUserIdHash().has_value()) {
883       base::FilePath homedir(kUserHomeDirPrefix);
884       homedir = homedir.Append(init_params.CrosUserIdHash().value());
885       base::PathService::OverrideAndCreateIfNeeded(
886           base::DIR_HOME, homedir, /*is_absolute=*/true, /*create=*/false);
887     }
888
889     // This lives here rather than in ChromeBrowserMainExtraPartsLacros due to
890     // timing constraints. If we relocate it, then the flags aren't propagated
891     // to the GPU process.
892     // All the flags in the block below relate to HW protected content, which
893     // require OOP video decoding as well.
894     if (init_params.BuildFlags().has_value() &&
895         init_params.OopVideoDecodingEnabled()) {
896       for (auto flag : init_params.BuildFlags().value()) {
897         switch (flag) {
898           case crosapi::mojom::BuildFlag::kUnknown:
899             break;
900           case crosapi::mojom::BuildFlag::kEnablePlatformEncryptedHevc:
901             // This was deprecated.
902             break;
903           case crosapi::mojom::BuildFlag::kEnablePlatformHevc:
904             base::CommandLine::ForCurrentProcess()->AppendSwitch(
905                 switches::kLacrosEnablePlatformHevc);
906             break;
907           case crosapi::mojom::BuildFlag::kUseChromeosProtectedMedia:
908             base::CommandLine::ForCurrentProcess()->AppendSwitch(
909                 switches::kLacrosUseChromeosProtectedMedia);
910             break;
911           case crosapi::mojom::BuildFlag::kUseChromeosProtectedAv1:
912             base::CommandLine::ForCurrentProcess()->AppendSwitch(
913                 switches::kLacrosUseChromeosProtectedAv1);
914             break;
915         }
916       }
917     }
918
919     if (init_params.EnableCpuMappableNativeGpuMemoryBuffers()) {
920       base::CommandLine::ForCurrentProcess()->AppendSwitch(
921           switches::kEnableNativeGpuMemoryBuffers);
922     }
923   }
924 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
925
926   CommonEarlyInitialization(invoked_in);
927
928   // Initializes the resource bundle and determines the locale.
929   std::string actual_locale = LoadLocalState(
930       chrome_feature_list_creator, invoked_in_browser->is_running_test);
931   chrome_feature_list_creator->SetApplicationLocale(actual_locale);
932   chrome_feature_list_creator->OverrideCachedUIStrings();
933
934   // On Chrome OS, initialize D-Bus clients that depend on feature list.
935 #if BUILDFLAG(IS_CHROMEOS_ASH)
936   ash::InitializeFeatureListDependentDBus();
937 #elif BUILDFLAG(IS_CHROMEOS_LACROS)
938   chromeos::LacrosInitializeFeatureListDependentDBus();
939 #endif
940
941 #if BUILDFLAG(IS_ANDROID)
942   chrome_content_browser_client_->startup_data()->CreateProfilePrefService();
943   net::NetworkChangeNotifier::SetFactory(
944       new net::NetworkChangeNotifierFactoryAndroid());
945 #endif
946
947   if (base::FeatureList::IsEnabled(
948           features::kWriteBasicSystemProfileToPersistentHistogramsFile)) {
949     bool record = true;
950 #if BUILDFLAG(IS_ANDROID)
951     record =
952         base::FeatureList::IsEnabled(chrome::android::kUmaBackgroundSessions);
953 #endif
954     if (record)
955       chrome_content_browser_client_->startup_data()->RecordCoreSystemProfile();
956   }
957
958 #if BUILDFLAG(IS_ANDROID)
959   UmaSessionStats::OnStartup();
960 #endif
961
962 #if BUILDFLAG(IS_MAC)
963   chrome::CacheChannelInfo();
964 #endif
965
966   // TODO(https://crbug.com/1360376): Consider deferring this to run after
967   // startup.
968   RequestUnwindPrerequisitesInstallation(chrome::GetChannel());
969
970   return absl::nullopt;
971 }
972
973 bool ChromeMainDelegate::ShouldCreateFeatureList(InvokedIn invoked_in) {
974   // In the browser process Chrome creates the FeatureList, so content should
975   // not.
976   return absl::holds_alternative<InvokedInChildProcess>(invoked_in);
977 }
978
979 bool ChromeMainDelegate::ShouldInitializeMojo(InvokedIn invoked_in) {
980   return ShouldCreateFeatureList(invoked_in);
981 }
982
983 void ChromeMainDelegate::CommonEarlyInitialization(InvokedIn invoked_in) {
984   const base::CommandLine* const command_line =
985       base::CommandLine::ForCurrentProcess();
986   std::string process_type =
987       command_line->GetSwitchValueASCII(switches::kProcessType);
988   bool is_browser_process = process_type.empty();
989
990   // Enable Split cache by default here and not in content/ so as to not
991   // impact non-Chrome embedders like WebView, Cronet etc. This only enables
992   // it if not already overridden by command line, field trial etc.
993   net::HttpCache::SplitCacheFeatureEnableByDefault();
994
995   // Similarly, enable network state partitioning by default.
996   net::NetworkAnonymizationKey::PartitionByDefault();
997
998 #if BUILDFLAG(IS_CHROMEOS)
999   // Threading features.
1000   base::PlatformThread::InitFeaturesPostFieldTrial();
1001 #endif
1002
1003   // Start memory observation as early as possible so it can start recording
1004   // memory allocations. This includes heap profiling.
1005   InitializeMemorySystem();
1006
1007   if (is_browser_process) {
1008 #if BUILDFLAG(IS_CHROMEOS_ASH)
1009     ash::InitializeMGLRU();
1010 #endif
1011   }
1012
1013 #if BUILDFLAG(IS_WIN)
1014   base::sequence_manager::internal::ThreadControllerPowerMonitor::
1015       InitializeOnMainThread();
1016   base::InitializePlatformThreadFeatures();
1017 #endif
1018
1019   // Initialize the HangWatcher.
1020   base::HangWatcher::ProcessType hang_watcher_process_type;
1021   if (process_type.empty()) {
1022     hang_watcher_process_type = base::HangWatcher::ProcessType::kBrowserProcess;
1023   } else if (process_type == switches::kGpuProcess) {
1024     hang_watcher_process_type = base::HangWatcher::ProcessType::kGPUProcess;
1025   } else if (process_type == switches::kRendererProcess) {
1026     hang_watcher_process_type =
1027         base::HangWatcher::ProcessType::kRendererProcess;
1028   } else if (process_type == switches::kUtilityProcess) {
1029     hang_watcher_process_type = base::HangWatcher::ProcessType::kUtilityProcess;
1030   } else {
1031     hang_watcher_process_type = base::HangWatcher::ProcessType::kUnknownProcess;
1032   }
1033   bool is_zygote_child = absl::visit(
1034       base::Overloaded{[](const InvokedInBrowserProcess& invoked_in_browser) {
1035                          return false;
1036                        },
1037                        [](const InvokedInChildProcess& invoked_in_child) {
1038                          return invoked_in_child.is_zygote_child;
1039                        }},
1040       invoked_in);
1041   base::HangWatcher::InitializeOnMainThread(
1042       hang_watcher_process_type, /*is_zygote_child=*/is_zygote_child);
1043
1044   base::InitializeCpuReductionExperiment();
1045   base::sequence_manager::internal::SequenceManagerImpl::InitializeFeatures();
1046   base::sequence_manager::internal::ThreadController::InitializeFeatures();
1047 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
1048   base::MessagePumpLibevent::InitializeFeatures();
1049 #elif BUILDFLAG(IS_MAC)
1050   base::PlatformThread::InitFeaturesPostFieldTrial();
1051   base::MessagePumpCFRunLoopBase::InitializeFeatures();
1052   base::MessagePumpKqueue::InitializeFeatures();
1053   base::ConditionVariable::InitializeFeatures();
1054 #endif
1055 }
1056
1057 #if BUILDFLAG(IS_WIN)
1058 bool ChromeMainDelegate::ShouldHandleConsoleControlEvents() {
1059   // Handle console control events so that orderly shutdown can be performed by
1060   // ChromeContentBrowserClient's override of SessionEnding.
1061   return true;
1062 }
1063 #endif
1064
1065 void ChromeMainDelegate::SetupTracing() {
1066   // It is necessary to reset the unique_ptr before assigning a new value to it.
1067   // This is to ensure that g_main_thread_instance inside
1068   // tracing_sampler_profiler.cc comes out correctly -- the old
1069   // TracingSamplerProfiler must destruct and clear g_main_thread_instance
1070   // before CreateOnMainThread() runs.
1071   tracing_sampler_profiler_.reset();
1072
1073 #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
1074   // Don't set up tracing in zygotes. Zygotes don't do much, and the tracing
1075   // system won't work after a fork because all the thread IDs will change.
1076   if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
1077           switches::kProcessType) == switches::kZygoteProcess) {
1078     return;
1079   }
1080 #endif  // #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
1081
1082   // We pass in CreateCoreUnwindersFactory here since it lives in the chrome/
1083   // layer while TracingSamplerProfiler is outside of chrome/.
1084   //
1085   // When we're the browser on android, use only libunwindstack for the tracing
1086   // sampler profiler because it can support java frames which is essential for
1087   // the main thread.
1088   base::RepeatingCallback tracing_factory =
1089 #if BUILDFLAG(IS_ANDROID)
1090       base::BindRepeating(&CreateCoreUnwindersFactory,
1091                           /*is_java_name_hashing_enabled=*/false);
1092 #else
1093       base::BindRepeating(&CreateCoreUnwindersFactory);
1094 #endif  // BUILDFLAG(IS_ANDROID)
1095   tracing::TracingSamplerProfiler::UnwinderType unwinder_type =
1096       tracing::TracingSamplerProfiler::UnwinderType::kCustomAndroid;
1097 #if BUILDFLAG(IS_ANDROID)
1098   // If we are the browser process (missing process type), then use the
1099   // experimental libunwindstack unwinder.
1100   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1101           switches::kProcessType) &&
1102       chrome::android::IsJavaDrivenFeatureEnabled(
1103           chrome::android::kUseLibunwindstackNativeUnwinderAndroid)) {
1104     tracing_factory = base::BindRepeating(&CreateLibunwindstackUnwinderFactory);
1105     unwinder_type = tracing::TracingSamplerProfiler::UnwinderType::
1106         kLibunwindstackUnwinderAndroid;
1107   }
1108 #endif
1109   tracing_sampler_profiler_ =
1110       tracing::TracingSamplerProfiler::CreateOnMainThread(
1111           std::move(tracing_factory), unwinder_type);
1112 }
1113
1114 absl::optional<int> ChromeMainDelegate::BasicStartupComplete() {
1115 #if BUILDFLAG(IS_CHROMEOS_ASH)
1116   ash::BootTimesRecorder::Get()->SaveChromeMainStats();
1117 #endif
1118
1119   const base::CommandLine& command_line =
1120       *base::CommandLine::ForCurrentProcess();
1121
1122   // Only allow disabling web security via the command-line flag if the user has
1123   // specified a distinct profile directory. This still enables tests to disable
1124   // web security by setting the kWebKitWebSecurityEnabled pref directly.
1125   //
1126   // Note that this is done in ChromeMainDelegate::BasicStartupComplete()
1127   // because this is the earliest callback. Many places in Chromium gate
1128   // security features around kDisableWebSecurity, and it is unreasonable to
1129   // expect them all to properly also check for kUserDataDir.
1130   if (command_line.HasSwitch(switches::kDisableWebSecurity)) {
1131     base::FilePath default_user_data_dir;
1132     chrome::GetDefaultUserDataDirectory(&default_user_data_dir);
1133     const base::FilePath specified_user_data_dir =
1134         command_line.GetSwitchValuePath(switches::kUserDataDir)
1135             .StripTrailingSeparators();
1136     if (specified_user_data_dir.empty() ||
1137         specified_user_data_dir == default_user_data_dir) {
1138       LOG(ERROR) << "Web security may only be disabled if '--user-data-dir' is "
1139                     "also specified with a non-default value.";
1140       base::CommandLine::ForCurrentProcess()->RemoveSwitch(
1141           switches::kDisableWebSecurity);
1142     }
1143   }
1144
1145   // The DevTools remote debugging pipe file descriptors need to be checked
1146   // before any other files are opened, see https://crbug.com/1423048.
1147   const bool is_browser = !command_line.HasSwitch(switches::kProcessType);
1148 #if BUILDFLAG(IS_WIN)
1149   const bool pipes_are_specified_explicitly =
1150       command_line.HasSwitch(::switches::kRemoteDebuggingIoPipes);
1151 #else
1152   const bool pipes_are_specified_explicitly = false;
1153 #endif
1154
1155   if (is_browser && command_line.HasSwitch(::switches::kRemoteDebuggingPipe) &&
1156       !pipes_are_specified_explicitly &&
1157       !devtools_pipe::AreFileDescriptorsOpen()) {
1158     LOG(ERROR) << "Remote debugging pipe file descriptors are not open.";
1159     return chrome::RESULT_CODE_UNSUPPORTED_PARAM;
1160   }
1161
1162 #if BUILDFLAG(IS_WIN)
1163   // Browser should not be sandboxed.
1164   if (is_browser && IsSandboxedProcess())
1165     return chrome::RESULT_CODE_INVALID_SANDBOX_STATE;
1166 #endif
1167
1168 #if BUILDFLAG(IS_MAC)
1169   // Give the browser process a longer treadmill, since crashes
1170   // there have more impact.
1171   ObjcEvilDoers::ZombieEnable(true, is_browser ? 10000 : 1000);
1172 #endif
1173
1174   content::Profiling::ProcessStarted();
1175
1176   // Setup tracing sampler profiler as early as possible at startup if needed.
1177   SetupTracing();
1178
1179 #if BUILDFLAG(IS_WIN)
1180   v8_crashpad_support::SetUp();
1181 #endif
1182
1183 #if BUILDFLAG(IS_CHROMEOS)
1184   if (!crash_reporter::IsCrashpadEnabled()) {
1185     breakpad::SetFirstChanceExceptionHandler(v8::TryHandleWebAssemblyTrapPosix);
1186   }
1187 #endif
1188
1189 #if BUILDFLAG(IS_POSIX)
1190   if (HandleVersionSwitches(command_line)) {
1191     return 0;  // Got a --version switch; exit with a success error code.
1192   }
1193   if (HandleCreditsSwitch(command_line)) {
1194     return 0;  // Got a --credits switch; exit with a success error code.
1195   }
1196
1197   // TODO(crbug.com/1052397): Revisit the macro expression once build flag
1198   // switch of lacros-chrome is complete.
1199 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
1200   // This will directly exit if the user asked for help.
1201   HandleHelpSwitches(command_line);
1202 #endif
1203 #endif  // BUILDFLAG(IS_POSIX)
1204
1205 #if BUILDFLAG(IS_WIN)
1206   // Must do this before any other usage of command line!
1207   if (HasDeprecatedArguments(command_line.GetCommandLineString())) {
1208     return 1;
1209   }
1210
1211   // HandleVerifier detects and reports incorrect handle manipulations. It
1212   // tracks handle operations on builds that support DCHECK only.
1213 #if !DCHECK_IS_ON()
1214   base::win::DisableHandleVerifier();
1215 #endif
1216
1217 #endif  // BUILDFLAG(IS_WIN)
1218
1219   chrome::RegisterPathProvider();
1220 #if BUILDFLAG(IS_CHROMEOS_ASH)
1221   ash::RegisterPathProvider();
1222 #endif
1223 #if BUILDFLAG(IS_CHROMEOS_LACROS)
1224   chromeos::lacros_paths::RegisterPathProvider();
1225 #endif
1226 #if BUILDFLAG(IS_CHROMEOS)
1227   chromeos::dbus_paths::RegisterPathProvider();
1228 #endif
1229 #if BUILDFLAG(ENABLE_NACL) && (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
1230   nacl::RegisterPathProvider();
1231 #endif
1232
1233   ContentSettingsPattern::SetNonWildcardDomainNonPortSchemes(
1234       kNonWildcardDomainNonPortSchemes, kNonWildcardDomainNonPortSchemesSize);
1235
1236 // No support for ANDROID yet as DiagnosticsController needs wchar support.
1237 // TODO(gspencer): That's not true anymore, or at least there are no w-string
1238 // references anymore. Not sure if that means this can be enabled on Android or
1239 // not though.  As there is no easily accessible command line on Android, I'm
1240 // not sure this is a big deal.
1241 #if !BUILDFLAG(IS_ANDROID)
1242   // If we are in diagnostics mode this is the end of the line: after the
1243   // diagnostics are run the process will invariably exit.
1244   if (command_line.HasSwitch(switches::kDiagnostics)) {
1245     diagnostics::DiagnosticsWriter::FormatType format =
1246         diagnostics::DiagnosticsWriter::HUMAN;
1247     if (command_line.HasSwitch(switches::kDiagnosticsFormat)) {
1248       std::string format_str =
1249           command_line.GetSwitchValueASCII(switches::kDiagnosticsFormat);
1250       if (format_str == "machine") {
1251         format = diagnostics::DiagnosticsWriter::MACHINE;
1252       } else if (format_str == "log") {
1253         format = diagnostics::DiagnosticsWriter::LOG;
1254       } else {
1255         DCHECK_EQ("human", format_str);
1256       }
1257     }
1258
1259     diagnostics::DiagnosticsWriter writer(format);
1260     int exit_code = diagnostics::DiagnosticsController::GetInstance()->Run(
1261         command_line, &writer);
1262     diagnostics::DiagnosticsController::GetInstance()->ClearResults();
1263     return exit_code;
1264   }
1265 #endif
1266
1267 #if BUILDFLAG(IS_CHROMEOS_ASH)
1268   // Initialize primary user homedir (in multi-profile session) as it may be
1269   // passed as a command line switch.
1270   base::FilePath homedir;
1271   if (command_line.HasSwitch(ash::switches::kHomedir)) {
1272     homedir = base::FilePath(
1273         command_line.GetSwitchValueASCII(ash::switches::kHomedir));
1274     base::PathService::OverrideAndCreateIfNeeded(base::DIR_HOME, homedir, true,
1275                                                  false);
1276   }
1277
1278   // If we are recovering from a crash on a ChromeOS device, then we will do
1279   // some recovery using the diagnostics module, and then continue on. We fake
1280   // up a command line to tell it that we want it to recover, and to preserve
1281   // the original command line. Note: logging at this point is to /var/log/ui.
1282   if ((base::SysInfo::IsRunningOnChromeOS() &&
1283        command_line.HasSwitch(ash::switches::kLoginUser)) ||
1284       command_line.HasSwitch(switches::kDiagnosticsRecovery)) {
1285     base::CommandLine interim_command_line(command_line.GetProgram());
1286     const char* const kSwitchNames[] = {
1287         switches::kUserDataDir,
1288     };
1289     interim_command_line.CopySwitchesFrom(command_line, kSwitchNames);
1290     interim_command_line.AppendSwitch(switches::kDiagnostics);
1291     interim_command_line.AppendSwitch(switches::kDiagnosticsRecovery);
1292
1293     diagnostics::DiagnosticsWriter::FormatType format =
1294         diagnostics::DiagnosticsWriter::LOG;
1295     if (command_line.HasSwitch(switches::kDiagnosticsFormat)) {
1296       std::string format_str =
1297           command_line.GetSwitchValueASCII(switches::kDiagnosticsFormat);
1298       if (format_str == "machine") {
1299         format = diagnostics::DiagnosticsWriter::MACHINE;
1300       } else if (format_str == "human") {
1301         format = diagnostics::DiagnosticsWriter::HUMAN;
1302       } else {
1303         DCHECK_EQ("log", format_str);
1304       }
1305     }
1306
1307     diagnostics::DiagnosticsWriter writer(format);
1308     int diagnostics_exit_code =
1309         diagnostics::DiagnosticsController::GetInstance()->Run(command_line,
1310                                                                &writer);
1311     if (diagnostics_exit_code) {
1312       // Diagnostics has failed somehow, so we exit.
1313       return diagnostics_exit_code;
1314     }
1315
1316     // Now we run the actual recovery tasks.
1317     int recovery_exit_code =
1318         diagnostics::DiagnosticsController::GetInstance()->RunRecovery(
1319             command_line, &writer);
1320
1321     if (recovery_exit_code) {
1322       // Recovery has failed somehow, so we exit.
1323       return recovery_exit_code;
1324     }
1325   } else {  // Not running diagnostics or recovery.
1326     diagnostics::DiagnosticsController::GetInstance()->RecordRegularStartup();
1327   }
1328 #endif
1329
1330   return absl::nullopt;
1331 }
1332
1333 #if BUILDFLAG(IS_MAC)
1334 void ChromeMainDelegate::InitMacCrashReporter(
1335     const base::CommandLine& command_line,
1336     const std::string& process_type) {
1337   // TODO(mark): Right now, InitializeCrashpad() needs to be called after
1338   // CommandLine::Init() and chrome::RegisterPathProvider().  Ideally, Crashpad
1339   // initialization could occur sooner, preferably even before the framework
1340   // dylib is even loaded, to catch potential early crashes.
1341
1342   const bool browser_process = process_type.empty();
1343   const bool install_from_dmg_relauncher_process =
1344       process_type == switches::kRelauncherProcess &&
1345       command_line.HasSwitch(switches::kRelauncherProcessDMGDevice);
1346
1347   const bool initial_client =
1348       browser_process || install_from_dmg_relauncher_process;
1349
1350   crash_reporter::InitializeCrashpad(initial_client, process_type);
1351
1352   if (!browser_process) {
1353     std::string metrics_client_id =
1354         command_line.GetSwitchValueASCII(switches::kMetricsClientID);
1355     crash_keys::SetMetricsClientIdFromGUID(metrics_client_id);
1356   }
1357
1358   // Mac Chrome is packaged with a main app bundle and a helper app bundle.
1359   // The main app bundle should only be used for the browser process, so it
1360   // should never see a --type switch (switches::kProcessType).  Likewise,
1361   // the helper should always have a --type switch.
1362   //
1363   // This check is done this late so there is already a call to
1364   // base::apple::IsBackgroundOnlyProcess(), so there is no change in
1365   // startup/initialization order.
1366
1367   // The helper's Info.plist marks it as a background only app.
1368   if (base::apple::IsBackgroundOnlyProcess()) {
1369     CHECK(command_line.HasSwitch(switches::kProcessType) &&
1370           !process_type.empty())
1371         << "Helper application requires --type.";
1372   } else if (base::apple::AmIBundled()) {
1373     CHECK(!command_line.HasSwitch(switches::kProcessType) &&
1374           process_type.empty())
1375         << "Main application forbids --type, saw " << process_type;
1376   }
1377 }
1378
1379 void ChromeMainDelegate::SetUpInstallerPreferences(
1380     const base::CommandLine& command_line) {
1381   const bool uma_setting = command_line.HasSwitch(switches::kEnableUserMetrics);
1382   const bool default_browser_setting =
1383       command_line.HasSwitch(switches::kMakeChromeDefault);
1384
1385   if (uma_setting)
1386     crash_reporter::SetUploadConsent(uma_setting);
1387   if (default_browser_setting)
1388     shell_integration::SetAsDefaultBrowser();
1389 }
1390 #endif  // BUILDFLAG(IS_MAC)
1391
1392 void ChromeMainDelegate::PreSandboxStartup() {
1393   const base::CommandLine& command_line =
1394       *base::CommandLine::ForCurrentProcess();
1395   std::string process_type =
1396       command_line.GetSwitchValueASCII(switches::kProcessType);
1397
1398   crash_reporter::InitializeCrashKeys();
1399
1400 #if BUILDFLAG(IS_CHROMEOS_LACROS)
1401   if (process_type.empty() && chromeos::IsLaunchedWithPostLoginParams()) {
1402     // NOTE: When prelaunching Lacros, this is as far as Lacros's initialization
1403     // will go at the login screen. The browser process will block here.
1404     //
1405     // IMPORTANT NOTE: If your code requires access to post-login parameters
1406     // (which are only known after login), please place them *after* this call.
1407     chromeos::BrowserParamsProxy::WaitForLogin();
1408
1409     // NOTE: When launching Lacros at login screen, after this point,
1410     // the user should have logged in. The cryptohome is now accessible.
1411     if (chrome::ProcessNeedsProfileDir(process_type)) {
1412       InitializeUserDataDir(base::CommandLine::ForCurrentProcess());
1413     }
1414
1415     // Redirect logs from system directory to cryptohome.
1416     RedirectLacrosLogging();
1417   }
1418 #endif
1419
1420 #if BUILDFLAG(IS_POSIX)
1421   ChromeCrashReporterClient::Create();
1422 #endif
1423
1424 #if BUILDFLAG(IS_MAC)
1425   InitMacCrashReporter(command_line, process_type);
1426   SetUpInstallerPreferences(command_line);
1427 #endif
1428
1429 #if BUILDFLAG(IS_WIN)
1430   child_process_logging::Init();
1431 #endif
1432 #if defined(ARCH_CPU_ARM_FAMILY) && \
1433     (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
1434   // Create an instance of the CPU class to parse /proc/cpuinfo and cache
1435   // cpu_brand info.
1436   base::CPU cpu_info;
1437 #endif
1438
1439   // Initialize the user data dir for any process type that needs it.
1440   bool initialize_user_data_dir = chrome::ProcessNeedsProfileDir(process_type);
1441 #if BUILDFLAG(IS_CHROMEOS_LACROS)
1442   // In Lacros, when prelaunching at login screen, we postpone the
1443   // initialization of the user data directory.
1444   // We verify that no access happens before login via DCHECKs.
1445   initialize_user_data_dir &= !chromeos::IsLaunchedWithPostLoginParams();
1446 #endif
1447   if (initialize_user_data_dir) {
1448     InitializeUserDataDir(base::CommandLine::ForCurrentProcess());
1449   }
1450
1451 #if BUILDFLAG(IS_CHROMEOS_LACROS)
1452   // Generate shared resource file only on browser process. This is to avoid
1453   // generating a file in different processes again.
1454   // Also generate only when resource file sharing feature is enabled.
1455   if (command_line.HasSwitch(switches::kEnableResourcesFileSharing) &&
1456       process_type.empty()) {
1457     // Initialize BrowserInitParams before generating and loading shared
1458     // resource file since the path required for the feature is set by
1459     // BrowserInitParams initialization.
1460     const chromeos::BrowserParamsProxy* init_params =
1461         chromeos::BrowserParamsProxy::Get();
1462     chrome::SetLacrosDefaultPathsFromInitParams(
1463         init_params->DefaultPaths().get());
1464     // TODO(crbug.com/1357874): Currently, when launching Lacros at login
1465     // screen, and if resource file sharing is also enabled, Lacros will block
1466     // here waiting for login. That's before the Zygote process is forked, so we
1467     // can't take full advantage of the pre-launching optimization. Investigate
1468     // if we can make these two features fully compatible.
1469
1470     base::FilePath ash_resources_dir;
1471     base::FilePath lacros_resources_dir;
1472     base::FilePath user_data_dir;
1473     if (base::PathService::Get(chromeos::lacros_paths::ASH_RESOURCES_DIR,
1474                                &ash_resources_dir) &&
1475         base::PathService::Get(base::DIR_ASSETS, &lacros_resources_dir) &&
1476         base::PathService::Get(chromeos::lacros_paths::USER_DATA_DIR,
1477                                &user_data_dir)) {
1478       ui::DataPackWithResourceSharing::MaybeGenerateFallbackAndMapping(
1479           ash_resources_dir.Append(FILE_PATH_LITERAL("resources.pak")),
1480           lacros_resources_dir.Append(FILE_PATH_LITERAL("resources.pak")),
1481           user_data_dir.Append(crosapi::kSharedResourcesPackName),
1482           ui::kScaleFactorNone);
1483       ui::DataPackWithResourceSharing::MaybeGenerateFallbackAndMapping(
1484           ash_resources_dir.Append(FILE_PATH_LITERAL("chrome_100_percent.pak")),
1485           lacros_resources_dir.Append(
1486               FILE_PATH_LITERAL("chrome_100_percent.pak")),
1487           user_data_dir.Append(crosapi::kSharedChrome100PercentPackName),
1488           ui::k100Percent);
1489       ui::DataPackWithResourceSharing::MaybeGenerateFallbackAndMapping(
1490           ash_resources_dir.Append(FILE_PATH_LITERAL("chrome_200_percent.pak")),
1491           lacros_resources_dir.Append(
1492               FILE_PATH_LITERAL("chrome_200_percent.pak")),
1493           user_data_dir.Append(crosapi::kSharedChrome200PercentPackName),
1494           ui::k200Percent);
1495     }
1496   }
1497 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
1498
1499   // Register component_updater PathProvider after DIR_USER_DATA overridden by
1500   // command line flags. Maybe move the chrome PathProvider down here also?
1501   int alt_preinstalled_components_dir =
1502 #if BUILDFLAG(IS_CHROMEOS_ASH)
1503       ash::DIR_PREINSTALLED_COMPONENTS;
1504 #else
1505       chrome::DIR_INTERNAL_PLUGINS;
1506 #endif
1507
1508   int updated_components_dir =
1509 #if BUILDFLAG(IS_CHROMEOS_LACROS)
1510       command_line.HasSwitch(switches::kEnableLacrosSharedComponentsDir)
1511           ? static_cast<int>(chromeos::lacros_paths::LACROS_SHARED_DIR)
1512           : static_cast<int>(chrome::DIR_USER_DATA);
1513 #else
1514       chrome::DIR_USER_DATA;
1515 #endif
1516
1517   component_updater::RegisterPathProvider(chrome::DIR_COMPONENTS,
1518                                           alt_preinstalled_components_dir,
1519                                           updated_components_dir);
1520
1521 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_WIN)
1522   // Android does InitLogging when library is loaded. Skip here.
1523   // For windows we call InitLogging when the sandbox is initialized.
1524   InitLogging(process_type);
1525 #endif
1526
1527 #if BUILDFLAG(IS_WIN)
1528   // TODO(zturner): Throbber icons and cursors are still stored in chrome.dll,
1529   // this can be killed once those are merged into resources.pak. See
1530   // BrowserFrameViewWin::InitThrobberIcons(), https://crbug.com/368327 and
1531   // https://crbug.com/1178117.
1532   ui::SetResourcesDataDLL(_AtlBaseModule.GetResourceInstance());
1533 #endif
1534
1535   if (SubprocessNeedsResourceBundle(process_type)) {
1536     // Initialize ResourceBundle which handles files loaded from external
1537     // sources.  The language should have been passed in to us from the
1538     // browser process as a command line flag.
1539 #if !BUILDFLAG(ENABLE_NACL)
1540     DCHECK(command_line.HasSwitch(switches::kLang) ||
1541            process_type == switches::kZygoteProcess ||
1542            process_type == switches::kGpuProcess ||
1543            process_type == switches::kPpapiPluginProcess);
1544 #else
1545     DCHECK(command_line.HasSwitch(switches::kLang) ||
1546            process_type == switches::kZygoteProcess ||
1547            process_type == switches::kGpuProcess ||
1548            process_type == switches::kNaClLoaderProcess ||
1549            process_type == switches::kPpapiPluginProcess);
1550 #endif
1551
1552     // TODO(markusheintz): The command line flag --lang is actually processed
1553     // by the CommandLinePrefStore, and made available through the PrefService
1554     // via the preference prefs::kApplicationLocale. The browser process uses
1555     // the --lang flag to pass the value of the PrefService in here. Maybe
1556     // this value could be passed in a different way.
1557     std::string locale = command_line.GetSwitchValueASCII(switches::kLang);
1558 #if BUILDFLAG(IS_CHROMEOS_ASH)
1559     if (process_type == switches::kZygoteProcess) {
1560       DCHECK(locale.empty());
1561       // See comment at ReadAppLocale() for why we do this.
1562       locale = ash::startup_settings_cache::ReadAppLocale();
1563     }
1564
1565     ui::ResourceBundle::SetLottieParsingFunctions(
1566         &lottie::ParseLottieAsStillImage,
1567         &lottie::ParseLottieAsThemedStillImage);
1568 #endif
1569 #if BUILDFLAG(IS_ANDROID)
1570     // The renderer sandbox prevents us from accessing our .pak files directly.
1571     // Therefore file descriptors to the .pak files that we need are passed in
1572     // at process creation time.
1573     auto* global_descriptors = base::GlobalDescriptors::GetInstance();
1574     int pak_fd = global_descriptors->Get(kAndroidLocalePakDescriptor);
1575     base::MemoryMappedFile::Region pak_region =
1576         global_descriptors->GetRegion(kAndroidLocalePakDescriptor);
1577     ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(base::File(pak_fd),
1578                                                             pak_region);
1579
1580     // Load secondary locale .pak file if it exists.
1581     pak_fd = global_descriptors->MaybeGet(kAndroidSecondaryLocalePakDescriptor);
1582     if (pak_fd != -1) {
1583       pak_region =
1584           global_descriptors->GetRegion(kAndroidSecondaryLocalePakDescriptor);
1585       ui::ResourceBundle::GetSharedInstance()
1586           .LoadSecondaryLocaleDataWithPakFileRegion(base::File(pak_fd),
1587                                                     pak_region);
1588     }
1589
1590     int extra_pak_keys[] = {
1591         kAndroidChrome100PercentPakDescriptor,
1592         kAndroidUIResourcesPakDescriptor,
1593     };
1594     for (int extra_pak_key : extra_pak_keys) {
1595       pak_fd = global_descriptors->Get(extra_pak_key);
1596       pak_region = global_descriptors->GetRegion(extra_pak_key);
1597       ui::ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion(
1598           base::File(pak_fd), pak_region, ui::k100Percent);
1599     }
1600
1601     // For Android: Native resources for DFMs should only be used by the browser
1602     // process. Their file descriptors and memory mapped file region are not
1603     // passed to child processes, and are therefore not loaded here.
1604
1605     base::i18n::SetICUDefaultLocale(locale);
1606     const std::string loaded_locale = locale;
1607 #else
1608     const std::string loaded_locale =
1609         ui::ResourceBundle::InitSharedInstanceWithLocale(
1610             locale, nullptr, ui::ResourceBundle::LOAD_COMMON_RESOURCES);
1611
1612     base::FilePath resources_pack_path;
1613     base::PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path);
1614 #if BUILDFLAG(IS_CHROMEOS_LACROS)
1615     if (command_line.HasSwitch(switches::kEnableResourcesFileSharing)) {
1616       // If LacrosResourcesFileSharing feature is enabled, Lacros refers to ash
1617       // resources pak file.
1618       base::FilePath ash_resources_pack_path;
1619       base::PathService::Get(chrome::FILE_ASH_RESOURCES_PACK,
1620                              &ash_resources_pack_path);
1621       base::FilePath shared_resources_pack_path;
1622       base::PathService::Get(chrome::FILE_RESOURCES_FOR_SHARING_PACK,
1623                              &shared_resources_pack_path);
1624       ui::ResourceBundle::GetSharedInstance()
1625           .AddDataPackFromPathWithAshResources(
1626               shared_resources_pack_path, ash_resources_pack_path,
1627               resources_pack_path, ui::kScaleFactorNone);
1628     } else {
1629       ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
1630           resources_pack_path, ui::kScaleFactorNone);
1631     }
1632 #else
1633     ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
1634         resources_pack_path, ui::kScaleFactorNone);
1635 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
1636 #endif  // BUILDFLAG(IS_ANDROID)
1637     CHECK(!loaded_locale.empty()) << "Locale could not be found for " << locale;
1638   }
1639
1640 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
1641   // Zygote needs to call InitCrashReporter() in RunZygote().
1642   if (process_type != switches::kZygoteProcess) {
1643     if (command_line.HasSwitch(switches::kPreCrashpadCrashTest)) {
1644       // Crash for the purposes of testing the handling of crashes that happen
1645       // before crashpad is initialized. Please leave this check immediately
1646       // before the crashpad initialization; the amount of memory used at this
1647       // point is important to the test.
1648       base::ImmediateCrash();
1649     }
1650 #if BUILDFLAG(IS_ANDROID)
1651     crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
1652     if (process_type.empty()) {
1653       base::android::InitJavaExceptionReporter();
1654       UninstallPureJavaExceptionHandler();
1655     } else {
1656       base::android::InitJavaExceptionReporterForChildProcess();
1657     }
1658 #elif BUILDFLAG(IS_CHROMEOS)
1659     if (crash_reporter::IsCrashpadEnabled()) {
1660       crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
1661       crash_reporter::SetFirstChanceExceptionHandler(
1662           v8::TryHandleWebAssemblyTrapPosix);
1663     } else {
1664       breakpad::InitCrashReporter(process_type);
1665     }
1666 #else
1667     crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
1668     crash_reporter::SetFirstChanceExceptionHandler(
1669         v8::TryHandleWebAssemblyTrapPosix);
1670 #endif  // BUILDFLAG(IS_ANDROID)
1671   }
1672 #endif  // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
1673
1674 #if BUILDFLAG(IS_ANDROID)
1675   CHECK_EQ(base::android::GetLibraryProcessType(),
1676            process_type.empty() ? base::android::PROCESS_BROWSER
1677                                 : base::android::PROCESS_CHILD);
1678 #endif  // BUILDFLAG(IS_ANDROID)
1679
1680   // After all the platform Breakpads have been initialized, store the command
1681   // line for crash reporting.
1682   crash_keys::SetCrashKeysFromCommandLine(command_line);
1683
1684 #if BUILDFLAG(ENABLE_PDF)
1685   MaybePatchGdiGetFontData();
1686 #endif
1687 }
1688
1689 void ChromeMainDelegate::SandboxInitialized(const std::string& process_type) {
1690   // Note: If you are adding a new process type below, be sure to adjust the
1691   // AdjustLinuxOOMScore function too.
1692 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
1693   AdjustLinuxOOMScore(process_type);
1694 #endif
1695 #if BUILDFLAG(IS_WIN)
1696   InitLogging(process_type);
1697   SuppressWindowsErrorDialogs();
1698 #endif
1699
1700 #if !BUILDFLAG(IS_FUCHSIA)
1701   // If this is a browser process, initialize the persistent histograms system.
1702   // This is done as soon as possible to ensure metrics collection coverage.
1703   // For Fuchsia, persistent histogram initialization is done after field trial
1704   // initialization (so that it can be controlled from the serverside and
1705   // experimented with).
1706   // Note: this is done before field trial initialization, so the values of
1707   // `kPersistentHistogramsFeature` and `kPersistentHistogramsStorage` will
1708   // not be used. Persist histograms to a memory-mapped file.
1709   bool immediate_histogram_init = true;
1710 #if BUILDFLAG(IS_CHROMEOS_LACROS)
1711   // For Lacros, when prelaunching at login screen, we want to postpone the
1712   // instantiation of persistent histograms to when the user has logged in
1713   // and the cryptohome is accessible.
1714   immediate_histogram_init = !chromeos::IsLaunchedWithPostLoginParams();
1715 #endif
1716   if (immediate_histogram_init && process_type.empty()) {
1717     base::FilePath metrics_dir;
1718     if (base::PathService::Get(chrome::DIR_USER_DATA, &metrics_dir)) {
1719       InstantiatePersistentHistograms(
1720           metrics_dir,
1721           /*persistent_histograms_enabled=*/true,
1722           /*storage=*/kPersistentHistogramStorageMappedFile);
1723     } else {
1724       NOTREACHED();
1725     }
1726   }
1727 #endif  // !BUILDFLAG(IS_FUCHSIA)
1728
1729 #if BUILDFLAG(ENABLE_NACL)
1730   ChromeContentClient::SetNaClEntryFunctions(nacl_plugin::PPP_GetInterface,
1731                                              nacl_plugin::PPP_InitializeModule,
1732                                              nacl_plugin::PPP_ShutdownModule);
1733 #endif
1734 }
1735
1736 absl::variant<int, content::MainFunctionParams> ChromeMainDelegate::RunProcess(
1737     const std::string& process_type,
1738     content::MainFunctionParams main_function_params) {
1739 #if BUILDFLAG(IS_ANDROID)
1740   NOTREACHED();  // Android provides a subclass and shares no code here.
1741 #else
1742   static const MainFunction kMainFunctions[] = {
1743 #if BUILDFLAG(IS_MAC)
1744     {switches::kRelauncherProcess, mac_relauncher::internal::RelauncherMain},
1745 #endif
1746
1747   // This entry is not needed on Linux, where the NaCl loader
1748   // process is launched via nacl_helper instead.
1749 #if BUILDFLAG(ENABLE_NACL) && !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
1750     {switches::kNaClLoaderProcess, NaClMain},
1751 #else
1752     {"<invalid>", nullptr},  // To avoid constant array of size 0
1753                              // when NaCl disabled
1754 #endif
1755   };
1756
1757   for (size_t i = 0; i < std::size(kMainFunctions); ++i) {
1758     if (process_type == kMainFunctions[i].name)
1759       return kMainFunctions[i].function(std::move(main_function_params));
1760   }
1761 #endif  // !BUILDFLAG(IS_ANDROID)
1762
1763   return std::move(main_function_params);
1764 }
1765
1766 void ChromeMainDelegate::ProcessExiting(const std::string& process_type) {
1767   // If not already set, set the shutdown type to be a clean process exit
1768   // |kProcessExit|. These browser process shutdowns are clean shutdowns and
1769   // their shutdown type must differ from |kNotValid|. If the shutdown type was
1770   // already set (a.k.a closing window, end-session), this statement is a no-op.
1771   if (process_type.empty()) {
1772     browser_shutdown::OnShutdownStarting(
1773         browser_shutdown::ShutdownType::kOtherExit);
1774   }
1775
1776 #if BUILDFLAG(ENABLE_PROCESS_SINGLETON)
1777   ChromeProcessSingleton::DeleteInstance();
1778 #endif  // BUILDFLAG(ENABLE_PROCESS_SINGLETON)
1779
1780   if (SubprocessNeedsResourceBundle(process_type))
1781     ui::ResourceBundle::CleanupSharedInstance();
1782 #if !BUILDFLAG(IS_ANDROID)
1783   logging::CleanupChromeLogging();
1784 #else
1785   // Android doesn't use InitChromeLogging, so we close the log file manually.
1786   logging::CloseLogFile();
1787 #endif  // !BUILDFLAG(IS_ANDROID)
1788 }
1789
1790 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
1791 void ChromeMainDelegate::ZygoteStarting(
1792     std::vector<std::unique_ptr<content::ZygoteForkDelegate>>* delegates) {
1793 #if BUILDFLAG(ENABLE_NACL)
1794   nacl::AddNaClZygoteForkDelegates(delegates);
1795 #endif
1796 }
1797
1798 void ChromeMainDelegate::ZygoteForked() {
1799   // Set up tracing for processes forked off a zygote.
1800   SetupTracing();
1801
1802   content::Profiling::ProcessStarted();
1803   if (content::Profiling::BeingProfiled()) {
1804     base::debug::RestartProfilingAfterFork();
1805     SetUpProfilingShutdownHandler();
1806   }
1807
1808   // Needs to be called after we have chrome::DIR_USER_DATA.  BrowserMain sets
1809   // this up for the browser process in a different manner.
1810   const base::CommandLine* command_line =
1811       base::CommandLine::ForCurrentProcess();
1812   std::string process_type =
1813       command_line->GetSwitchValueASCII(switches::kProcessType);
1814 #if BUILDFLAG(IS_CHROMEOS)
1815   if (crash_reporter::IsCrashpadEnabled()) {
1816     crash_reporter::InitializeCrashpad(false, process_type);
1817     crash_reporter::SetFirstChanceExceptionHandler(
1818         v8::TryHandleWebAssemblyTrapPosix);
1819   } else {
1820     breakpad::InitCrashReporter(process_type);
1821   }
1822 #else
1823   crash_reporter::InitializeCrashpad(false, process_type);
1824   crash_reporter::SetFirstChanceExceptionHandler(
1825       v8::TryHandleWebAssemblyTrapPosix);
1826 #endif
1827
1828   // Reset the command line for the newly spawned process.
1829   crash_keys::SetCrashKeysFromCommandLine(*command_line);
1830 }
1831
1832 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
1833
1834 content::ContentClient* ChromeMainDelegate::CreateContentClient() {
1835   return &chrome_content_client_;
1836 }
1837
1838 content::ContentBrowserClient*
1839 ChromeMainDelegate::CreateContentBrowserClient() {
1840   chrome_content_browser_client_ =
1841       std::make_unique<ChromeContentBrowserClient>();
1842   return chrome_content_browser_client_.get();
1843 }
1844
1845 content::ContentGpuClient* ChromeMainDelegate::CreateContentGpuClient() {
1846   return g_chrome_content_gpu_client.Pointer();
1847 }
1848
1849 content::ContentRendererClient*
1850 ChromeMainDelegate::CreateContentRendererClient() {
1851   return g_chrome_content_renderer_client.Pointer();
1852 }
1853
1854 content::ContentUtilityClient*
1855 ChromeMainDelegate::CreateContentUtilityClient() {
1856   chrome_content_utility_client_ =
1857       std::make_unique<ChromeContentUtilityClient>();
1858   return chrome_content_utility_client_.get();
1859 }
1860
1861 absl::optional<int> ChromeMainDelegate::PreBrowserMain() {
1862   absl::optional<int> exit_code =
1863       content::ContentMainDelegate::PreBrowserMain();
1864   if (exit_code.has_value())
1865     return exit_code;
1866
1867 #if BUILDFLAG(ENABLE_EXTENSIONS)
1868   const base::CommandLine& command_line =
1869       *base::CommandLine::ForCurrentProcess();
1870   absl::optional<int> pack_extension_exit_code =
1871       HandlePackExtensionSwitches(command_line);
1872   if (pack_extension_exit_code.has_value())
1873     return pack_extension_exit_code;  // Got a --pack-extension switch; exit.
1874 #endif
1875
1876 #if BUILDFLAG(IS_MAC)
1877   // Tell Cocoa to finish its initialization, which we want to do manually
1878   // instead of calling NSApplicationMain(). The primary reason is that NSAM()
1879   // never returns, which would leave all the objects currently on the stack
1880   // in scoped_ptrs hanging and never cleaned up. We then load the main nib
1881   // directly. The main event loop is run from common code using the
1882   // MessageLoop API, which works out ok for us because it's a wrapper around
1883   // CFRunLoop.
1884
1885   // Initialize NSApplication using the custom subclass.
1886   chrome_browser_application_mac::RegisterBrowserCrApp();
1887
1888   // Perform additional initialization when running in headless mode: hide
1889   // dock icon and menu bar.
1890   if (headless::IsHeadlessMode()) {
1891     chrome_browser_application_mac::InitializeHeadlessMode();
1892   }
1893
1894   if (l10n_util::GetLocaleOverride().empty()) {
1895     // The browser process only wants to support the language Cocoa will use,
1896     // so force the app locale to be overridden with that value. This must
1897     // happen before the ResourceBundle is loaded, which happens in
1898     // ChromeBrowserMainParts::PreEarlyInitialization().
1899     // Don't do this if the locale is already set, which is done by integration
1900     // tests to ensure tests always run with the same locale.
1901     l10n_util::OverrideLocaleWithCocoaLocale();
1902   }
1903 #endif
1904
1905 #if BUILDFLAG(IS_WIN)
1906   // Register callback to handle resource exhaustion.
1907   base::win::SetOnResourceExhaustedFunction(&OnResourceExhausted);
1908
1909   if (IsExtensionPointDisableSet()) {
1910     sandbox::SandboxFactory::GetBrokerServices()->SetStartingMitigations(
1911         sandbox::MITIGATION_EXTENSION_POINT_DISABLE);
1912   }
1913 #endif
1914
1915   // Do not interrupt startup.
1916   return absl::nullopt;
1917 }
1918
1919 void ChromeMainDelegate::InitializeMemorySystem() {
1920   const base::CommandLine* const command_line =
1921       base::CommandLine::ForCurrentProcess();
1922   const std::string process_type =
1923       command_line->GetSwitchValueASCII(switches::kProcessType);
1924   const bool is_browser_process = process_type.empty();
1925   const version_info::Channel channel = chrome::GetChannel();
1926   const bool is_canary_dev = (channel == version_info::Channel::CANARY ||
1927                               channel == version_info::Channel::DEV);
1928   const bool gwp_asan_boost_sampling = is_canary_dev || is_browser_process;
1929
1930   memory_system::Initializer()
1931       .SetGwpAsanParameters(gwp_asan_boost_sampling, process_type)
1932       .SetProfilingClientParameters(channel,
1933                                     GetProfileParamsProcess(*command_line))
1934       .SetDispatcherParameters(memory_system::DispatcherParameters::
1935                                    PoissonAllocationSamplerInclusion::kEnforce,
1936                                memory_system::DispatcherParameters::
1937                                    AllocationTraceRecorderInclusion::kDynamic,
1938                                process_type)
1939       .Initialize(memory_system_);
1940 }