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.
5 #include "chrome/app/chrome_main_delegate.h"
11 #include "base/base_paths.h"
12 #include "base/check.h"
13 #include "base/command_line.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"
104 #if BUILDFLAG(IS_WIN)
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"
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"
140 #if BUILDFLAG(IS_POSIX)
144 #include "chrome/app/chrome_crash_reporter_client.h"
145 #include "components/about_ui/credit_utils.h"
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"
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
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
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"
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"
192 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
193 #include "base/environment.h"
196 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
197 #include "base/message_loop/message_pump_libevent.h"
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"
206 #if BUILDFLAG(ENABLE_EXTENSIONS)
207 #include "chrome/browser/extensions/startup_helper.h"
208 #include "extensions/common/constants.h"
211 #if BUILDFLAG(ENABLE_NACL)
212 #include "components/nacl/common/nacl_switches.h"
213 #include "components/nacl/renderer/plugin/ppapi_entrypoints.h"
216 #if BUILDFLAG(ENABLE_PDF)
217 #include "chrome/child/pdf_child_init.h"
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)
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"
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;
250 extern int NaClMain(content::MainFunctionParams);
252 const char* const ChromeMainDelegate::kNonWildcardDomainNonPortSchemes[] = {
253 #if BUILDFLAG(ENABLE_EXTENSIONS)
254 extensions::kExtensionScheme,
256 chrome::kChromeSearchScheme, chrome::kIsolatedAppScheme,
257 content::kChromeDevToolsScheme, content::kChromeUIScheme,
258 content::kChromeUIUntrustedScheme,
260 const size_t ChromeMainDelegate::kNonWildcardDomainNonPortSchemesSize =
261 std::size(kNonWildcardDomainNonPortSchemes);
265 #if BUILDFLAG(IS_CHROMEOS_LACROS)
266 const base::FilePath::CharType kUserHomeDirPrefix[] =
267 FILE_PATH_LITERAL("/home/user");
268 #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
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);
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;
286 // Preserve existing error mode.
287 UINT existing_flags = SetErrorMode(new_flags);
288 SetErrorMode(existing_flags | new_flags);
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();
299 #endif // BUILDFLAG(IS_WIN)
301 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
302 void AdjustLinuxOOMScore(const std::string& process_type) {
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;
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;
326 NOTREACHED() << "Unknown process type";
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.
332 base::AdjustOOMScore(base::GetCurrentProcId(), score);
334 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
336 // Returns true if this subprocess type needs the ResourceBundle initialized
337 // and resources loaded.
338 bool SubprocessNeedsResourceBundle(const std::string& process_type) {
340 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
341 // The zygote process opens the resources for the renderers.
342 process_type == switches::kZygoteProcess ||
344 #if BUILDFLAG(IS_MAC)
345 // Mac needs them too for scrollbar related images and for sandbox
347 #if BUILDFLAG(ENABLE_NACL)
348 process_type == switches::kNaClLoaderProcess ||
350 process_type == switches::kGpuProcess ||
352 process_type == switches::kPpapiPluginProcess ||
353 process_type == switches::kRendererProcess ||
354 process_type == switches::kUtilityProcess;
357 #if BUILDFLAG(IS_POSIX)
358 bool HandleCreditsSwitch(const base::CommandLine& command_line) {
359 if (!command_line.HasSwitch(switches::kCredits))
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);
368 // Ensure there is an instance of ResourceBundle that is initialized for
369 // localized string resource accesses.
370 ui::ScopedStartupResourceBundle ensure_startup_resource_bundle;
372 base::FilePath resources_pak =
373 resource_dir.Append(FILE_PATH_LITERAL("resources.pak"));
375 #if BUILDFLAG(IS_MAC) && !defined(COMPONENT_BUILD)
376 // In non-component builds, check if a fallback in Resources/ folder is
378 if (!base::PathExists(resources_pak)) {
380 resource_dir.Append(FILE_PATH_LITERAL("Resources/resources.pak"));
384 ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
385 resources_pak, ui::kScaleFactorNone);
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
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.");
398 printf("%s\n", credits.c_str());
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());
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());
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";
435 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
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);
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);
453 // Redirect Zygote and future children's logs.
455 content::ZygoteHost::GetInstance()->ReinitializeLogging(logging_dest,
461 void AddFeatureFlagsToCommandLine(
462 const chromeos::BrowserParamsProxy& init_params) {
463 base::ScopedAddFeatureFlags flags(base::CommandLine::ForCurrentProcess());
465 if (init_params.IsVariableRefreshRateAlwaysOn()) {
466 flags.EnableIfNotSet(features::kEnableVariableRefreshRateAlwaysOn);
469 if (init_params.IsPdfOcrEnabled()) {
470 flags.EnableIfNotSet(features::kPdfOcr);
473 #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
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);
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);
492 #endif // !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_ANDROID)
494 #endif // BUILDFLAG(IS_POSIX)
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;
504 // Ensure there is an instance of ResourceBundle that is initialized for
505 // localized string resource accesses.
506 ui::ScopedStartupResourceBundle ensure_startup_resource_bundle;
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();
514 return chrome::RESULT_CODE_PACK_EXTENSION_ERROR;
517 return chrome::RESULT_CODE_NORMAL_EXIT_PACK_EXTENSION_SUCCESS;
519 #endif // !BUILDFLAG(ENABLE_EXTENSIONS)
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);
530 ProcessSingleton::NotifyResult notify_result =
531 ChromeProcessSingleton::GetInstance()->NotifyOtherProcessOrCreate();
532 UMA_HISTOGRAM_ENUMERATION("Chrome.ProcessSingleton.NotifyResult",
533 notify_result, ProcessSingleton::kNumNotifyResults);
535 switch (notify_result) {
536 case ProcessSingleton::PROCESS_NONE:
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)))
547 return chrome::RESULT_CODE_NORMAL_EXIT_PROCESS_NOTIFIED;
550 case ProcessSingleton::PROFILE_IN_USE:
551 return chrome::RESULT_CODE_PROFILE_IN_USE;
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;
562 return absl::nullopt;
566 struct MainFunction {
568 int (*function)(content::MainFunctionParams);
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();
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];
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);
594 CHECK(base::PathService::OverrideAndCreateIfNeeded(
595 chrome::DIR_USER_DATA, user_data_dir, false, true));
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);
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);
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)
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);
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);
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;
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)
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;
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)";
671 #endif // !BUILDFLAG(IS_ANDROID)
673 void RecordMainStartupMetrics(base::TimeTicks application_start_time) {
674 const base::TimeTicks now = base::TimeTicks::Now();
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.
687 // On other platforms, |application_start_time| == |now| since the application
688 // starts with ChromeMain().
689 startup_metric_utils::GetCommon().RecordApplicationStartTime(now);
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());
700 startup_metric_utils::GetCommon().RecordChromeMainEntryTime(now);
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);
720 base::Process::TerminateCurrentProcessImmediately(
721 chrome::RESULT_CODE_SYSTEM_RESOURCE_EXHAUSTED);
723 #endif // !BUILDFLAG(IS_WIN)
727 ChromeMainDelegate::ChromeMainDelegate()
728 : ChromeMainDelegate(base::TimeTicks()) {}
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);
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();
748 ChromeMainDelegate::~ChromeMainDelegate() = default;
749 #endif // !BUILDFLAG(IS_ANDROID)
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
764 ui::EnsureIntelMediaCompressionEnvVarIsSet();
765 #endif // BUILDFLAG(IS_CHROMEOS)
766 CommonEarlyInitialization(invoked_in);
767 return absl::nullopt;
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);
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);
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());
798 return process_singleton_result;
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();
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();
820 base::FilePath metrics_dir;
821 if (immediate_histogram_cleanup &&
822 base::PathService::Get(chrome::DIR_USER_DATA, &metrics_dir)) {
823 PersistentHistogramsCleanup(metrics_dir);
825 #endif // !BUILDFLAG(IS_FUCHSIA)
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();
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
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();
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());
850 // Must be added before feature list is created otherwise the added flag won't
852 AddFeatureFlagsToCommandLine(init_params);
853 #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
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();
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)
871 content::InitializeMojoCore();
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
879 lacros_service_ = std::make_unique<chromeos::LacrosService>();
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);
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()) {
898 case crosapi::mojom::BuildFlag::kUnknown:
900 case crosapi::mojom::BuildFlag::kEnablePlatformEncryptedHevc:
901 // This was deprecated.
903 case crosapi::mojom::BuildFlag::kEnablePlatformHevc:
904 base::CommandLine::ForCurrentProcess()->AppendSwitch(
905 switches::kLacrosEnablePlatformHevc);
907 case crosapi::mojom::BuildFlag::kUseChromeosProtectedMedia:
908 base::CommandLine::ForCurrentProcess()->AppendSwitch(
909 switches::kLacrosUseChromeosProtectedMedia);
911 case crosapi::mojom::BuildFlag::kUseChromeosProtectedAv1:
912 base::CommandLine::ForCurrentProcess()->AppendSwitch(
913 switches::kLacrosUseChromeosProtectedAv1);
919 if (init_params.EnableCpuMappableNativeGpuMemoryBuffers()) {
920 base::CommandLine::ForCurrentProcess()->AppendSwitch(
921 switches::kEnableNativeGpuMemoryBuffers);
924 #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
926 CommonEarlyInitialization(invoked_in);
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();
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();
941 #if BUILDFLAG(IS_ANDROID)
942 chrome_content_browser_client_->startup_data()->CreateProfilePrefService();
943 net::NetworkChangeNotifier::SetFactory(
944 new net::NetworkChangeNotifierFactoryAndroid());
947 if (base::FeatureList::IsEnabled(
948 features::kWriteBasicSystemProfileToPersistentHistogramsFile)) {
950 #if BUILDFLAG(IS_ANDROID)
952 base::FeatureList::IsEnabled(chrome::android::kUmaBackgroundSessions);
955 chrome_content_browser_client_->startup_data()->RecordCoreSystemProfile();
958 #if BUILDFLAG(IS_ANDROID)
959 UmaSessionStats::OnStartup();
962 #if BUILDFLAG(IS_MAC)
963 chrome::CacheChannelInfo();
966 // TODO(https://crbug.com/1360376): Consider deferring this to run after
968 RequestUnwindPrerequisitesInstallation(chrome::GetChannel());
970 return absl::nullopt;
973 bool ChromeMainDelegate::ShouldCreateFeatureList(InvokedIn invoked_in) {
974 // In the browser process Chrome creates the FeatureList, so content should
976 return absl::holds_alternative<InvokedInChildProcess>(invoked_in);
979 bool ChromeMainDelegate::ShouldInitializeMojo(InvokedIn invoked_in) {
980 return ShouldCreateFeatureList(invoked_in);
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();
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();
995 // Similarly, enable network state partitioning by default.
996 net::NetworkAnonymizationKey::PartitionByDefault();
998 #if BUILDFLAG(IS_CHROMEOS)
999 // Threading features.
1000 base::PlatformThread::InitFeaturesPostFieldTrial();
1003 // Start memory observation as early as possible so it can start recording
1004 // memory allocations. This includes heap profiling.
1005 InitializeMemorySystem();
1007 if (is_browser_process) {
1008 #if BUILDFLAG(IS_CHROMEOS_ASH)
1009 ash::InitializeMGLRU();
1013 #if BUILDFLAG(IS_WIN)
1014 base::sequence_manager::internal::ThreadControllerPowerMonitor::
1015 InitializeOnMainThread();
1016 base::InitializePlatformThreadFeatures();
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;
1031 hang_watcher_process_type = base::HangWatcher::ProcessType::kUnknownProcess;
1033 bool is_zygote_child = absl::visit(
1034 base::Overloaded{[](const InvokedInBrowserProcess& invoked_in_browser) {
1037 [](const InvokedInChildProcess& invoked_in_child) {
1038 return invoked_in_child.is_zygote_child;
1041 base::HangWatcher::InitializeOnMainThread(
1042 hang_watcher_process_type, /*is_zygote_child=*/is_zygote_child);
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();
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.
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();
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) {
1080 #endif // #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
1082 // We pass in CreateCoreUnwindersFactory here since it lives in the chrome/
1083 // layer while TracingSamplerProfiler is outside of chrome/.
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
1088 base::RepeatingCallback tracing_factory =
1089 #if BUILDFLAG(IS_ANDROID)
1090 base::BindRepeating(&CreateCoreUnwindersFactory,
1091 /*is_java_name_hashing_enabled=*/false);
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;
1109 tracing_sampler_profiler_ =
1110 tracing::TracingSamplerProfiler::CreateOnMainThread(
1111 std::move(tracing_factory), unwinder_type);
1114 absl::optional<int> ChromeMainDelegate::BasicStartupComplete() {
1115 #if BUILDFLAG(IS_CHROMEOS_ASH)
1116 ash::BootTimesRecorder::Get()->SaveChromeMainStats();
1119 const base::CommandLine& command_line =
1120 *base::CommandLine::ForCurrentProcess();
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.
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);
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);
1152 const bool pipes_are_specified_explicitly = false;
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;
1162 #if BUILDFLAG(IS_WIN)
1163 // Browser should not be sandboxed.
1164 if (is_browser && IsSandboxedProcess())
1165 return chrome::RESULT_CODE_INVALID_SANDBOX_STATE;
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);
1174 content::Profiling::ProcessStarted();
1176 // Setup tracing sampler profiler as early as possible at startup if needed.
1179 #if BUILDFLAG(IS_WIN)
1180 v8_crashpad_support::SetUp();
1183 #if BUILDFLAG(IS_CHROMEOS)
1184 if (!crash_reporter::IsCrashpadEnabled()) {
1185 breakpad::SetFirstChanceExceptionHandler(v8::TryHandleWebAssemblyTrapPosix);
1189 #if BUILDFLAG(IS_POSIX)
1190 if (HandleVersionSwitches(command_line)) {
1191 return 0; // Got a --version switch; exit with a success error code.
1193 if (HandleCreditsSwitch(command_line)) {
1194 return 0; // Got a --credits switch; exit with a success error code.
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);
1203 #endif // BUILDFLAG(IS_POSIX)
1205 #if BUILDFLAG(IS_WIN)
1206 // Must do this before any other usage of command line!
1207 if (HasDeprecatedArguments(command_line.GetCommandLineString())) {
1211 // HandleVerifier detects and reports incorrect handle manipulations. It
1212 // tracks handle operations on builds that support DCHECK only.
1214 base::win::DisableHandleVerifier();
1217 #endif // BUILDFLAG(IS_WIN)
1219 chrome::RegisterPathProvider();
1220 #if BUILDFLAG(IS_CHROMEOS_ASH)
1221 ash::RegisterPathProvider();
1223 #if BUILDFLAG(IS_CHROMEOS_LACROS)
1224 chromeos::lacros_paths::RegisterPathProvider();
1226 #if BUILDFLAG(IS_CHROMEOS)
1227 chromeos::dbus_paths::RegisterPathProvider();
1229 #if BUILDFLAG(ENABLE_NACL) && (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
1230 nacl::RegisterPathProvider();
1233 ContentSettingsPattern::SetNonWildcardDomainNonPortSchemes(
1234 kNonWildcardDomainNonPortSchemes, kNonWildcardDomainNonPortSchemesSize);
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;
1255 DCHECK_EQ("human", format_str);
1259 diagnostics::DiagnosticsWriter writer(format);
1260 int exit_code = diagnostics::DiagnosticsController::GetInstance()->Run(
1261 command_line, &writer);
1262 diagnostics::DiagnosticsController::GetInstance()->ClearResults();
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,
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,
1289 interim_command_line.CopySwitchesFrom(command_line, kSwitchNames);
1290 interim_command_line.AppendSwitch(switches::kDiagnostics);
1291 interim_command_line.AppendSwitch(switches::kDiagnosticsRecovery);
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;
1303 DCHECK_EQ("log", format_str);
1307 diagnostics::DiagnosticsWriter writer(format);
1308 int diagnostics_exit_code =
1309 diagnostics::DiagnosticsController::GetInstance()->Run(command_line,
1311 if (diagnostics_exit_code) {
1312 // Diagnostics has failed somehow, so we exit.
1313 return diagnostics_exit_code;
1316 // Now we run the actual recovery tasks.
1317 int recovery_exit_code =
1318 diagnostics::DiagnosticsController::GetInstance()->RunRecovery(
1319 command_line, &writer);
1321 if (recovery_exit_code) {
1322 // Recovery has failed somehow, so we exit.
1323 return recovery_exit_code;
1325 } else { // Not running diagnostics or recovery.
1326 diagnostics::DiagnosticsController::GetInstance()->RecordRegularStartup();
1330 return absl::nullopt;
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.
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);
1347 const bool initial_client =
1348 browser_process || install_from_dmg_relauncher_process;
1350 crash_reporter::InitializeCrashpad(initial_client, process_type);
1352 if (!browser_process) {
1353 std::string metrics_client_id =
1354 command_line.GetSwitchValueASCII(switches::kMetricsClientID);
1355 crash_keys::SetMetricsClientIdFromGUID(metrics_client_id);
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.
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.
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;
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);
1386 crash_reporter::SetUploadConsent(uma_setting);
1387 if (default_browser_setting)
1388 shell_integration::SetAsDefaultBrowser();
1390 #endif // BUILDFLAG(IS_MAC)
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);
1398 crash_reporter::InitializeCrashKeys();
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.
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();
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());
1415 // Redirect logs from system directory to cryptohome.
1416 RedirectLacrosLogging();
1420 #if BUILDFLAG(IS_POSIX)
1421 ChromeCrashReporterClient::Create();
1424 #if BUILDFLAG(IS_MAC)
1425 InitMacCrashReporter(command_line, process_type);
1426 SetUpInstallerPreferences(command_line);
1429 #if BUILDFLAG(IS_WIN)
1430 child_process_logging::Init();
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
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();
1447 if (initialize_user_data_dir) {
1448 InitializeUserDataDir(base::CommandLine::ForCurrentProcess());
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.
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,
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),
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),
1497 #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
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;
1505 chrome::DIR_INTERNAL_PLUGINS;
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);
1514 chrome::DIR_USER_DATA;
1517 component_updater::RegisterPathProvider(chrome::DIR_COMPONENTS,
1518 alt_preinstalled_components_dir,
1519 updated_components_dir);
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);
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());
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);
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);
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();
1565 ui::ResourceBundle::SetLottieParsingFunctions(
1566 &lottie::ParseLottieAsStillImage,
1567 &lottie::ParseLottieAsThemedStillImage);
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),
1580 // Load secondary locale .pak file if it exists.
1581 pak_fd = global_descriptors->MaybeGet(kAndroidSecondaryLocalePakDescriptor);
1584 global_descriptors->GetRegion(kAndroidSecondaryLocalePakDescriptor);
1585 ui::ResourceBundle::GetSharedInstance()
1586 .LoadSecondaryLocaleDataWithPakFileRegion(base::File(pak_fd),
1590 int extra_pak_keys[] = {
1591 kAndroidChrome100PercentPakDescriptor,
1592 kAndroidUIResourcesPakDescriptor,
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);
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.
1605 base::i18n::SetICUDefaultLocale(locale);
1606 const std::string loaded_locale = locale;
1608 const std::string loaded_locale =
1609 ui::ResourceBundle::InitSharedInstanceWithLocale(
1610 locale, nullptr, ui::ResourceBundle::LOAD_COMMON_RESOURCES);
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);
1629 ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
1630 resources_pack_path, ui::kScaleFactorNone);
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;
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();
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();
1656 base::android::InitJavaExceptionReporterForChildProcess();
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);
1664 breakpad::InitCrashReporter(process_type);
1667 crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
1668 crash_reporter::SetFirstChanceExceptionHandler(
1669 v8::TryHandleWebAssemblyTrapPosix);
1670 #endif // BUILDFLAG(IS_ANDROID)
1672 #endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
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)
1680 // After all the platform Breakpads have been initialized, store the command
1681 // line for crash reporting.
1682 crash_keys::SetCrashKeysFromCommandLine(command_line);
1684 #if BUILDFLAG(ENABLE_PDF)
1685 MaybePatchGdiGetFontData();
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);
1695 #if BUILDFLAG(IS_WIN)
1696 InitLogging(process_type);
1697 SuppressWindowsErrorDialogs();
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();
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(
1721 /*persistent_histograms_enabled=*/true,
1722 /*storage=*/kPersistentHistogramStorageMappedFile);
1727 #endif // !BUILDFLAG(IS_FUCHSIA)
1729 #if BUILDFLAG(ENABLE_NACL)
1730 ChromeContentClient::SetNaClEntryFunctions(nacl_plugin::PPP_GetInterface,
1731 nacl_plugin::PPP_InitializeModule,
1732 nacl_plugin::PPP_ShutdownModule);
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.
1742 static const MainFunction kMainFunctions[] = {
1743 #if BUILDFLAG(IS_MAC)
1744 {switches::kRelauncherProcess, mac_relauncher::internal::RelauncherMain},
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},
1752 {"<invalid>", nullptr}, // To avoid constant array of size 0
1753 // when NaCl disabled
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));
1761 #endif // !BUILDFLAG(IS_ANDROID)
1763 return std::move(main_function_params);
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);
1776 #if BUILDFLAG(ENABLE_PROCESS_SINGLETON)
1777 ChromeProcessSingleton::DeleteInstance();
1778 #endif // BUILDFLAG(ENABLE_PROCESS_SINGLETON)
1780 if (SubprocessNeedsResourceBundle(process_type))
1781 ui::ResourceBundle::CleanupSharedInstance();
1782 #if !BUILDFLAG(IS_ANDROID)
1783 logging::CleanupChromeLogging();
1785 // Android doesn't use InitChromeLogging, so we close the log file manually.
1786 logging::CloseLogFile();
1787 #endif // !BUILDFLAG(IS_ANDROID)
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);
1798 void ChromeMainDelegate::ZygoteForked() {
1799 // Set up tracing for processes forked off a zygote.
1802 content::Profiling::ProcessStarted();
1803 if (content::Profiling::BeingProfiled()) {
1804 base::debug::RestartProfilingAfterFork();
1805 SetUpProfilingShutdownHandler();
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);
1820 breakpad::InitCrashReporter(process_type);
1823 crash_reporter::InitializeCrashpad(false, process_type);
1824 crash_reporter::SetFirstChanceExceptionHandler(
1825 v8::TryHandleWebAssemblyTrapPosix);
1828 // Reset the command line for the newly spawned process.
1829 crash_keys::SetCrashKeysFromCommandLine(*command_line);
1832 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
1834 content::ContentClient* ChromeMainDelegate::CreateContentClient() {
1835 return &chrome_content_client_;
1838 content::ContentBrowserClient*
1839 ChromeMainDelegate::CreateContentBrowserClient() {
1840 chrome_content_browser_client_ =
1841 std::make_unique<ChromeContentBrowserClient>();
1842 return chrome_content_browser_client_.get();
1845 content::ContentGpuClient* ChromeMainDelegate::CreateContentGpuClient() {
1846 return g_chrome_content_gpu_client.Pointer();
1849 content::ContentRendererClient*
1850 ChromeMainDelegate::CreateContentRendererClient() {
1851 return g_chrome_content_renderer_client.Pointer();
1854 content::ContentUtilityClient*
1855 ChromeMainDelegate::CreateContentUtilityClient() {
1856 chrome_content_utility_client_ =
1857 std::make_unique<ChromeContentUtilityClient>();
1858 return chrome_content_utility_client_.get();
1861 absl::optional<int> ChromeMainDelegate::PreBrowserMain() {
1862 absl::optional<int> exit_code =
1863 content::ContentMainDelegate::PreBrowserMain();
1864 if (exit_code.has_value())
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.
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
1885 // Initialize NSApplication using the custom subclass.
1886 chrome_browser_application_mac::RegisterBrowserCrApp();
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();
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();
1905 #if BUILDFLAG(IS_WIN)
1906 // Register callback to handle resource exhaustion.
1907 base::win::SetOnResourceExhaustedFunction(&OnResourceExhausted);
1909 if (IsExtensionPointDisableSet()) {
1910 sandbox::SandboxFactory::GetBrokerServices()->SetStartingMitigations(
1911 sandbox::MITIGATION_EXTENSION_POINT_DISABLE);
1915 // Do not interrupt startup.
1916 return absl::nullopt;
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;
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,
1939 .Initialize(memory_system_);