#include "content/app/content_main_runner_impl.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <array>
#include <memory>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <variant>
#include <vector>
#include "arkweb/build/features/features.h"
#include "base/allocator/allocator_check.h"
#include "base/allocator/partition_alloc_support.h"
#include "base/at_exit.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug/debugger.h"
#include "base/debug/leak_annotations.h"
#include "base/debug/stack_trace.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/i18n/icu_util.h"
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/shared_memory_hooks.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_base.h"
#include "base/path_service.h"
#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_source.h"
#include "base/process/launch.h"
#include "base/process/memory.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/thread_pool/environment_config.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/threading/hang_watcher.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "components/discardable_memory/service/discardable_shared_memory_manager.h"
#include "components/download/public/common/download_task_runner.h"
#include "components/power_monitor/make_power_monitor_device_source.h"
#include "components/variations/net/variations_command_line.h"
#include "components/variations/variations_ids_provider.h"
#include "content/app/mojo_ipc_support.h"
#include "content/browser/browser_main.h"
#include "content/browser/browser_process_io_thread.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/first_party_sets/first_party_sets_handler_impl.h"
#include "content/browser/gpu/gpu_main_thread_factory.h"
#include "content/browser/memory_coordinator/browser_memory_consumer_registry.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/scheduler/browser_task_executor.h"
#include "content/browser/service_host/utility_process_host.h"
#include "content/browser/startup_data_impl.h"
#include "content/browser/startup_helper.h"
#include "content/browser/tracing/memory_instrumentation_util.h"
#include "content/child/field_trial.h"
#include "content/child/memory_coordinator/child_memory_consumer_registry.h"
#include "content/common/content_constants_internal.h"
#include "content/common/process_visibility_tracker.h"
#include "content/common/url_schemes.h"
#include "content/gpu/in_process_gpu_thread.h"
#include "content/public/app/content_main_delegate.h"
#include "content/public/app/initialize_mojo_core.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/network_service_util.h"
#include "content/public/browser/tracing_delegate.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_descriptor_keys.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/main_function_params.h"
#include "content/public/common/zygote/zygote_buildflags.h"
#include "content/public/gpu/content_gpu_client.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/public/utility/content_utility_client.h"
#include "content/renderer/in_process_renderer_thread.h"
#include "content/utility/in_process_utility_thread.h"
#include "gin/thread_isolation.h"
#include "gin/v8_initializer.h"
#include "media/base/media.h"
#include "media/media_buildflags.h"
#include "mojo/core/embedder/embedder.h"
#include "mojo/public/cpp/base/shared_memory_utils.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/invitation.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "net/first_party_sets/local_set_declaration.h"
#include "sandbox/policy/linux/landlock_util.h"
#include "sandbox/policy/sandbox.h"
#include "sandbox/policy/sandbox_type.h"
#include "sandbox/policy/switches.h"
#include "services/network/public/cpp/features.h"
#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
#include "services/tracing/public/cpp/trace_startup.h"
#include "services/tracing/public/cpp/tracing_features.h"
#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
#include "third_party/tflite/buildflags.h"
#include "tools/v8_context_snapshot/buildflags.h"
#include "ui/base/ui_base_paths.h"
#include "ui/base/ui_base_switches.h"
#include "ui/display/display_switches.h"
#include "ui/gfx/switches.h"
#if BUILDFLAG(IS_WIN)
#include <malloc.h>
#include <cstring>
#include "ui/base/l10n/l10n_util_win.h"
#include "ui/display/win/dpi.h"
#elif BUILDFLAG(IS_MAC)
#include "sandbox/mac/seatbelt.h"
#include "sandbox/mac/seatbelt_exec.h"
#endif
#if BUILDFLAG(IS_IOS)
#include "base/threading/thread_restrictions.h"
#if !BUILDFLAG(IS_IOS_TVOS)
#include "content/app/ios/appex/child_process_sandbox.h"
#endif
#endif
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
#include <signal.h>
#include "base/file_descriptor_store.h"
#include "base/posix/global_descriptors.h"
#include "content/browser/posix_file_descriptor_info_impl.h"
#include "content/public/common/content_descriptors.h"
#if !BUILDFLAG(IS_MAC)
#include "content/public/common/zygote/zygote_fork_delegate_linux.h"
#endif
#endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "base/files/file_path_watcher_inotify.h"
#include "base/native_library.h"
#include "base/rand_util.h"
#include "content/public/common/zygote/sandbox_support_linux.h"
#include "sandbox/policy/linux/sandbox_linux.h"
#include "third_party/boringssl/src/include/openssl/crypto.h"
#include "third_party/webrtc_overrides/init_webrtc.h"
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
#include "content/public/common/cdm_info.h"
#include "content/public/common/content_client.h"
#endif
#endif
#if BUILDFLAG(USE_ZYGOTE)
#include "base/stack_canary_linux.h"
#include "content/browser/sandbox_host_linux.h"
#include "content/browser/zygote_host/zygote_host_impl_linux.h"
#include "content/common/shared_file_util.h"
#include "content/common/zygote/zygote_communication_linux.h"
#include "content/common/zygote/zygote_handle_impl_linux.h"
#include "content/public/common/zygote/sandbox_support_linux.h"
#include "content/public/common/zygote/zygote_handle.h"
#include "content/zygote/zygote_main.h"
#include "media/base/media_switches.h"
#endif
#if BUILDFLAG(IS_ANDROID)
#include "base/android/background_thread_pool_field_trial.h"
#include "base/system/sys_info.h"
#include "content/browser/android/battery_metrics.h"
#include "content/browser/android/browser_startup_controller.h"
#include "content/common/android/cpu_time_metrics.h"
#endif
#if BUILDFLAG(IS_FUCHSIA)
#include "base/fuchsia/system_info.h"
#endif
#if BUILDFLAG(BUILD_TFLITE_WITH_XNNPACK)
#include "third_party/cpuinfo/src/include/cpuinfo.h"
#endif
#if defined(ADDRESS_SANITIZER)
#include "base/debug/asan_service.h"
#endif
#if BUILDFLAG(IS_ARKWEB)
#include "content/renderer/render_remote_proxy_ohos.h"
#endif
namespace content {
extern int GpuMain(MainFunctionParams);
extern int RendererMain(MainFunctionParams);
extern int UtilityMain(MainFunctionParams);
}
namespace content {
namespace {
using ::sandbox::policy::IsUnsandboxedSandboxType;
using ::sandbox::policy::SandboxTypeFromCommandLine;
#if defined(V8_USE_EXTERNAL_STARTUP_DATA) && BUILDFLAG(IS_ANDROID)
#if defined __LP64__
#define kV8SnapshotDataDescriptor kV8Snapshot64DataDescriptor
#define kV8ContextSnapshotDataDescriptor kV8ContextSnapshot64DataDescriptor
#else
#define kV8SnapshotDataDescriptor kV8Snapshot32DataDescriptor
#define kV8ContextSnapshotDataDescriptor kV8ContextSnapshot32DataDescriptor
#endif
#endif
#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
gin::V8SnapshotFileType GetSnapshotType(const base::CommandLine& command_line) {
#if BUILDFLAG(IS_ANDROID) && BUILDFLAG(INCLUDE_BOTH_V8_SNAPSHOTS)
if (command_line.HasSwitch(switches::kUseContextSnapshotSwitch)) {
return gin::V8SnapshotFileType::kWithAdditionalContext;
}
return gin::V8SnapshotFileType::kDefault;
#elif BUILDFLAG(USE_V8_CONTEXT_SNAPSHOT)
return gin::V8SnapshotFileType::kWithAdditionalContext;
#else
return gin::V8SnapshotFileType::kDefault;
#endif
}
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
std::string GetSnapshotDataDescriptor(const base::CommandLine& command_line) {
#if BUILDFLAG(IS_ANDROID) && BUILDFLAG(INCLUDE_BOTH_V8_SNAPSHOTS)
if (command_line.HasSwitch(switches::kUseContextSnapshotSwitch)) {
return kV8ContextSnapshotDataDescriptor;
}
return kV8SnapshotDataDescriptor;
#elif BUILDFLAG(USE_V8_CONTEXT_SNAPSHOT)
return kV8ContextSnapshotDataDescriptor;
#else
return kV8SnapshotDataDescriptor;
#endif
}
#endif
#if defined(ADDRESS_SANITIZER)
NO_SANITIZE("address")
void AsanProcessInfoCB(const char*, bool*) {
auto* cmd_line = base::CommandLine::ForCurrentProcess();
#if BUILDFLAG(IS_WIN)
std::string cmd_string = base::WideToUTF8(cmd_line->GetCommandLineString());
#else
std::string cmd_string = cmd_line->GetCommandLineString();
#endif
base::debug::AsanService::GetInstance()->Log("\nCommand line: `%s`\n",
cmd_string.c_str());
}
#endif
void LoadV8SnapshotFile(const base::CommandLine& command_line) {
const gin::V8SnapshotFileType snapshot_type = GetSnapshotType(command_line);
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
base::FileDescriptorStore& file_descriptor_store =
base::FileDescriptorStore::GetInstance();
base::MemoryMappedFile::Region region;
base::ScopedFD fd = file_descriptor_store.MaybeTakeFD(
GetSnapshotDataDescriptor(command_line), ®ion);
if (fd.is_valid()) {
base::File file(std::move(fd));
gin::V8Initializer::LoadV8SnapshotFromFile(std::move(file), ®ion,
snapshot_type);
return;
}
#endif
gin::V8Initializer::LoadV8Snapshot(snapshot_type);
}
bool ShouldLoadV8Snapshot(const base::CommandLine& command_line,
const std::string& process_type) {
if (process_type == switches::kGpuProcess ||
(process_type.empty() &&
!command_line.HasSwitch(switches::kSingleProcess))) {
return false;
}
return true;
}
#endif
void LoadV8SnapshotIfNeeded(const base::CommandLine& command_line,
const std::string& process_type) {
#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
if (ShouldLoadV8Snapshot(command_line, process_type))
LoadV8SnapshotFile(command_line);
#endif
}
#if BUILDFLAG(USE_ZYGOTE)
pid_t LaunchZygoteHelper(base::CommandLine* cmd_line,
base::ScopedFD* control_fd) {
static const char* const kForwardSwitches[] = {
switches::kAllowCommandLinePlugins,
switches::kClearKeyCdmPathForTesting,
switches::kEnableLogging,
switches::kHeadless,
switches::kForceDeviceScaleFactor,
switches::kLoggingLevel,
switches::kV,
switches::kVModule,
};
cmd_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
kForwardSwitches);
GetContentClient()->browser()->AppendExtraCommandLineSwitches(cmd_line, -1);
std::unique_ptr<PosixFileDescriptorInfo> additional_remapped_fds(
PosixFileDescriptorInfoImpl::Create());
additional_remapped_fds->Share(
GetSandboxFD(), SandboxHostLinux::GetInstance()->GetChildSocket());
return ZygoteHostImpl::GetInstance()->LaunchZygote(
cmd_line, control_fd, additional_remapped_fds->GetMapping());
}
void InitializeZygoteSandboxForBrowserProcess(
const base::CommandLine& parsed_command_line) {
TRACE_EVENT0("startup", "SetupSandbox");
SandboxHostLinux::GetInstance()->Init();
if (parsed_command_line.HasSwitch(switches::kNoZygote)) {
if (!parsed_command_line.HasSwitch(sandbox::policy::switches::kNoSandbox)) {
LOG(ERROR) << "Zygote cannot be disabled if sandbox is enabled."
<< " Use --no-zygote together with --no-sandbox";
exit(EXIT_FAILURE);
}
return;
}
ZygoteHostImpl::GetInstance()->Init(parsed_command_line);
if (!parsed_command_line.HasSwitch(switches::kNoUnsandboxedZygote)) {
CreateUnsandboxedZygote(base::BindOnce(LaunchZygoteHelper));
}
ZygoteCommunication* generic_zygote =
CreateGenericZygote(base::BindOnce(LaunchZygoteHelper));
ZygoteHostImpl::GetInstance()->SetRendererSandboxStatus(
generic_zygote->GetSandboxStatus());
}
#endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
void PreloadLibraryCdms() {
std::vector<CdmInfo> cdms;
GetContentClient()->AddContentDecryptionModules(&cdms, nullptr);
for (const auto& cdm : cdms) {
base::NativeLibraryLoadError error;
base::NativeLibrary library = base::LoadNativeLibrary(cdm.path, &error);
LOG_IF(ERROR, !library) << "Unable to load CDM " << cdm.path.value()
<< " (error: " << error.ToString() << ")";
}
}
#endif
void PreSandboxInit() {
base::GetUrandomFD();
base::SysInfo::AmountOfPhysicalMemory();
base::SysInfo::NumberOfProcessors();
base::SysInfo::NumberOfEfficientProcessors();
CRYPTO_pre_sandbox_init();
base::GetMaxNumberOfInotifyWatches();
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
PreloadLibraryCdms();
#endif
InitializeWebRtcModuleBeforeSandbox();
#if BUILDFLAG(BUILD_TFLITE_WITH_XNNPACK)
if (!cpuinfo_initialize()) {
LOG(ERROR) << "Failed to initialize cpuinfo";
}
#endif
base::internal::CanUseBackgroundThreadTypeForWorkerThread();
base::internal::CanUseUtilityThreadTypeForWorkerThread();
}
#endif
mojo::ScopedMessagePipeHandle MaybeAcceptMojoInvitation() {
const auto& command_line = *base::CommandLine::ForCurrentProcess();
if (!mojo::PlatformChannel::CommandLineHasPassedEndpoint(command_line))
return {};
mojo::PlatformChannelEndpoint endpoint =
mojo::PlatformChannel::RecoverPassedEndpointFromCommandLine(command_line);
auto invitation = mojo::IncomingInvitation::Accept(std::move(endpoint));
return invitation.ExtractMessagePipe(0);
}
#if BUILDFLAG(IS_WIN)
void HandleConsoleControlEventOnBrowserUiThread(DWORD control_type) {
GetContentClient()->browser()->SessionEnding(control_type);
}
BOOL WINAPI BrowserConsoleControlHandler(DWORD control_type) {
BrowserTaskExecutor::GetUIThreadTaskRunner(
{base::TaskPriority::USER_BLOCKING})
->PostTask(FROM_HERE,
base::BindOnce(&HandleConsoleControlEventOnBrowserUiThread,
control_type));
base::PlatformThread::Sleep(base::Hours(1));
return TRUE;
}
BOOL WINAPI OtherConsoleControlHandler(DWORD control_type) {
base::PlatformThread::Sleep(base::Hours(1));
return TRUE;
}
void InstallConsoleControlHandler(bool is_browser_process) {
if (!::SetConsoleCtrlHandler(is_browser_process
? &BrowserConsoleControlHandler
: &OtherConsoleControlHandler,
TRUE)) {
DPLOG(ERROR) << "Failed to set console hook function";
}
}
#endif
bool ShouldAllowSystemTracingConsumer() {
#if BUILDFLAG(IS_CHROMEOS)
return GetContentClient()->browser()->IsSystemWideTracingEnabled();
#else
return false;
#endif
}
void CreateChildThreadPool(const std::string& process_type) {
DCHECK(!base::ThreadPoolInstance::Get());
std::string_view thread_pool_name;
if (process_type == switches::kGpuProcess)
thread_pool_name = "GPU";
else if (process_type == switches::kRendererProcess)
thread_pool_name = "Renderer";
else
thread_pool_name = "ContentChild";
base::ThreadPoolInstance::Create(thread_pool_name);
}
}
class ContentClientCreator {
public:
static void Create(ContentMainDelegate* delegate) {
ContentClient* client = delegate->CreateContentClient();
DCHECK(client);
SetContentClient(client);
}
};
class ContentClientInitializer {
public:
static void Set(const std::string& process_type,
ContentMainDelegate* delegate) {
ContentClient* content_client = GetContentClient();
#if !BUILDFLAG(ARKWEB_DFX_TRACING)
if (process_type == switches::kUtilityProcess ||
cmd->HasSwitch(switches::kSingleProcess))
#endif
content_client->utility_ = delegate->CreateContentUtilityClient();
if (process_type.empty())
content_client->browser_ = delegate->CreateContentBrowserClient();
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
if (process_type == switches::kGpuProcess ||
cmd->HasSwitch(switches::kSingleProcess) ||
(process_type.empty() && cmd->HasSwitch(switches::kInProcessGPU)))
content_client->gpu_ = delegate->CreateContentGpuClient();
if (process_type == switches::kRendererProcess ||
cmd->HasSwitch(switches::kSingleProcess))
content_client->renderer_ = delegate->CreateContentRendererClient();
}
};
struct MainFunction {
const char* name;
int (*function)(MainFunctionParams);
};
#if BUILDFLAG(USE_ZYGOTE)
NO_STACK_PROTECTOR int RunZygote(ContentMainDelegate* delegate) {
static const MainFunction kMainFunctions[] = {
{switches::kGpuProcess, GpuMain},
{switches::kRendererProcess, RendererMain},
{switches::kUtilityProcess, UtilityMain},
};
std::vector<std::unique_ptr<ZygoteForkDelegate>> zygote_fork_delegates;
delegate->ZygoteStarting(&zygote_fork_delegates);
if (!ZygoteMain(std::move(zygote_fork_delegates))) {
return 1;
}
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
std::string process_type =
command_line->GetSwitchValueASCII(switches::kProcessType);
CreateChildThreadPool(process_type);
base::ScopedClosureRunner stack_canary_debug_message;
if (command_line->GetSwitchValueASCII(switches::kChangeStackGuardOnFork) ==
switches::kChangeStackGuardOnForkEnabled) {
base::ResetStackCanaryIfPossible();
stack_canary_debug_message.ReplaceClosure(
base::BindOnce(&base::SetStackSmashingEmitsDebugMessage));
}
base::ReseedSharedMetricsSubsampler();
PopulateFileDescriptorStoreFromGlobalDescriptors();
delegate->ZygoteForked();
base::allocator::PartitionAllocSupport::Get()->ReconfigureAfterZygoteFork(
process_type);
ContentClientInitializer::Set(process_type, delegate);
const ContentMainDelegate::InvokedInChildProcess invoked_in_child;
if (delegate->ShouldCreateFeatureList(invoked_in_child)) {
InitializeFieldTrialAndFeatureList();
}
if (delegate->ShouldInitializeMojo(invoked_in_child)) {
InitializeMojoCore();
}
delegate->PostEarlyInitialization(invoked_in_child);
base::allocator::PartitionAllocSupport::Get()
->ReconfigureAfterFeatureListInit(process_type);
media::InitializeMediaLibrary();
MainFunctionParams main_params(command_line);
main_params.zygote_child = true;
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
if (process_type == switches::kGpuProcess) {
tracing::InitTracingPostFeatureList(false,
true);
} else {
main_params.needs_startup_tracing_after_sandbox_init = true;
}
#else
tracing::InitTracingPostFeatureList(false,
false);
#endif
base::ScopedClosureRunner unregister_thread_closure;
if (base::HangWatcher::IsEnabled()) {
base::HangWatcher::CreateHangWatcherInstance();
unregister_thread_closure = base::HangWatcher::RegisterThread(
base::HangWatcher::ThreadType::kMainThread);
if (IsUnsandboxedSandboxType(SandboxTypeFromCommandLine(*command_line))) {
base::HangWatcher::GetInstance()->Start();
} else {
main_params.hang_watcher_not_started_time = base::TimeTicks::Now();
}
}
for (const MainFunction& main_function : kMainFunctions) {
if (process_type == main_function.name) {
return main_function.function(std::move(main_params));
}
}
auto exit_code = delegate->RunProcess(process_type, std::move(main_params));
DCHECK(std::holds_alternative<int>(exit_code));
DCHECK_GE(std::get<int>(exit_code), 0);
return std::get<int>(exit_code);
}
#endif
static void RegisterMainThreadFactories() {
UtilityProcessHost::RegisterUtilityMainThreadFactory(
CreateInProcessUtilityThread);
RenderProcessHostImpl::RegisterRendererMainThreadFactory(
CreateInProcessRendererThread);
content::RegisterGpuMainThreadFactory(CreateInProcessGpuThread);
}
int RunBrowserProcessMain(MainFunctionParams main_function_params,
ContentMainDelegate* delegate) {
#if BUILDFLAG(IS_WIN)
if (delegate->ShouldHandleConsoleControlEvents())
InstallConsoleControlHandler(true);
#endif
auto exit_code = delegate->RunProcess("", std::move(main_function_params));
if (std::holds_alternative<int>(exit_code)) {
DCHECK_GE(std::get<int>(exit_code), 0);
return std::get<int>(exit_code);
}
return BrowserMain(std::move(std::get<MainFunctionParams>(exit_code)));
}
NO_STACK_PROTECTOR int RunOtherNamedProcessTypeMain(
const std::string& process_type,
MainFunctionParams main_function_params,
ContentMainDelegate* delegate) {
#if BUILDFLAG(IS_MAC)
base::Process::SetCurrentTaskDefaultRole();
#endif
#if BUILDFLAG(IS_WIN)
if (delegate->ShouldHandleConsoleControlEvents())
InstallConsoleControlHandler(false);
#endif
static const auto kMainFunctions = std::to_array<MainFunction>({
{switches::kUtilityProcess, UtilityMain},
{switches::kRendererProcess, RendererMain},
{switches::kGpuProcess, GpuMain},
});
base::ScopedMemoryConsumerRegistry<ChildMemoryConsumerRegistry>
child_memory_consumer_registry;
base::ScopedClosureRunner unregister_thread_closure;
if (base::HangWatcher::IsEnabled()) {
base::HangWatcher::CreateHangWatcherInstance();
unregister_thread_closure = base::HangWatcher::RegisterThread(
base::HangWatcher::ThreadType::kMainThread);
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
const bool start_hang_watcher_now = IsUnsandboxedSandboxType(
SandboxTypeFromCommandLine(*main_function_params.command_line));
#else
const bool start_hang_watcher_now = true;
#endif
if (start_hang_watcher_now) {
base::HangWatcher::GetInstance()->Start();
} else {
main_function_params.hang_watcher_not_started_time =
base::TimeTicks::Now();
}
}
for (const MainFunction& main_function : kMainFunctions) {
if (process_type == main_function.name) {
auto exit_code =
delegate->RunProcess(process_type, std::move(main_function_params));
if (std::holds_alternative<int>(exit_code)) {
DCHECK_GE(std::get<int>(exit_code), 0);
return std::get<int>(exit_code);
}
return main_function.function(
std::move(std::get<MainFunctionParams>(exit_code)));
}
}
#if BUILDFLAG(USE_ZYGOTE)
if (process_type == switches::kZygoteProcess)
return RunZygote(delegate);
#endif
auto exit_code =
delegate->RunProcess(process_type, std::move(main_function_params));
DCHECK(std::holds_alternative<int>(exit_code));
DCHECK_GE(std::get<int>(exit_code), 0);
return std::get<int>(exit_code);
}
std::unique_ptr<ContentMainRunnerImpl> ContentMainRunnerImpl::Create() {
return std::make_unique<ContentMainRunnerImpl>();
}
ContentMainRunnerImpl::ContentMainRunnerImpl() = default;
ContentMainRunnerImpl::~ContentMainRunnerImpl() {
if (is_initialized_ && !is_shutdown_)
Shutdown();
}
int ContentMainRunnerImpl::TerminateForFatalInitializationError() {
return delegate_->TerminateForFatalInitializationError();
}
int ContentMainRunnerImpl::Initialize(ContentMainParams params) {
delegate_ = std::exchange(params.delegate, nullptr);
content_main_params_.emplace(std::move(params));
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
std::string process_type =
command_line.GetSwitchValueASCII(switches::kProcessType);
#if BUILDFLAG(IS_ANDROID)
base::android::BackgroundThreadPoolFieldTrial::Initialize();
#endif
if (!process_type.empty()) {
if (process_type != switches::kZygoteProcess) {
CreateChildThreadPool(process_type);
}
} else {
delegate_->CreateThreadPool("Browser");
DCHECK_NE(base::ThreadPoolInstance::Get(), nullptr);
}
#if !BUILDFLAG(IS_WIN)
[[maybe_unused]] base::GlobalDescriptors* g_fds =
base::GlobalDescriptors::GetInstance();
#if (!BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_OHOS))
g_fds->Set(kMojoIPCChannel,
kMojoIPCChannel + base::GlobalDescriptors::kBaseDescriptor);
g_fds->Set(kFieldTrialDescriptor,
kFieldTrialDescriptor + base::GlobalDescriptors::kBaseDescriptor);
g_fds->Set(kHistogramSharedMemoryDescriptor,
kHistogramSharedMemoryDescriptor +
base::GlobalDescriptors::kBaseDescriptor);
g_fds->Set(kTraceConfigSharedMemoryDescriptor,
kTraceConfigSharedMemoryDescriptor +
base::GlobalDescriptors::kBaseDescriptor);
g_fds->Set(kTraceOutputSharedMemoryDescriptor,
kTraceOutputSharedMemoryDescriptor +
base::GlobalDescriptors::kBaseDescriptor);
#endif
#if BUILDFLAG(IS_OHOS)
g_fds->Set(kTraceConfigSharedMemoryDescriptor,
kTraceConfigSharedMemoryDescriptor +
base::GlobalDescriptors::kBaseDescriptor);
LOG(INFO) << "ContentMainRunnerImpl::Initialize::kTraceConfigSharedMemoryDescriptor is registered.";
#endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_OPENBSD)
g_fds->Set(kCrashDumpSignal,
kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor);
#endif
#endif
is_initialized_ = true;
TRACE_EVENT0("startup,benchmark,rail", "ContentMainRunnerImpl::Initialize");
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
if (!content_main_params_->ui_task) {
exit_manager_ = std::make_unique<base::AtExitManager>();
}
#endif
#if BUILDFLAG(IS_FUCHSIA)
if (!base::FetchAndCacheSystemInfo()) {
return TerminateForFatalInitializationError();
}
#endif
if (!GetContentClient())
ContentClientCreator::Create(delegate_);
std::optional<int> basic_startup_exit_code =
delegate_->BasicStartupComplete();
if (basic_startup_exit_code.has_value())
return basic_startup_exit_code.value();
base::allocator::PartitionAllocSupport::Get()->ReconfigureEarlyish(
process_type);
#if BUILDFLAG(IS_WIN)
if (command_line.HasSwitch(switches::kDeviceScaleFactor)) {
std::string scale_factor_string =
command_line.GetSwitchValueASCII(switches::kDeviceScaleFactor);
double scale_factor = 0;
if (base::StringToDouble(scale_factor_string, &scale_factor))
display::win::SetDefaultDeviceScaleFactor(scale_factor);
}
#endif
RegisterContentSchemes(delegate_->ShouldLockSchemeRegistry());
ContentClientInitializer::Set(process_type, delegate_);
CHECK(base::allocator::IsAllocatorInitialized());
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
if (!process_type.empty()) {
if (!base::debug::BeingDebugged())
signal(SIGINT, SIG_IGN);
}
#endif
RegisterPathProvider();
#if BUILDFLAG(IS_ANDROID) && (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
if (!process_type.empty()) {
int icu_data_fd = g_fds->MaybeGet(kAndroidICUDataDescriptor);
if (icu_data_fd == -1) {
return TerminateForFatalInitializationError();
}
auto icu_data_region = g_fds->GetRegion(kAndroidICUDataDescriptor);
if (!base::i18n::InitializeICUWithFileDescriptor(icu_data_fd,
icu_data_region)) {
return TerminateForFatalInitializationError();
}
}
#else
if (!base::i18n::InitializeICU())
return TerminateForFatalInitializationError();
#endif
LoadV8SnapshotIfNeeded(command_line, process_type);
blink::TrialTokenValidator::SetOriginTrialPolicyGetter(
base::BindRepeating([]() -> blink::OriginTrialPolicy* {
if (auto* client = GetContentClient())
return client->GetOriginTrialPolicy();
return nullptr;
}));
#if !defined(OFFICIAL_BUILD) || BUILDFLAG(CHROME_FOR_TESTING)
if (!command_line.HasSwitch(switches::kDisableInProcessStackTraces)) {
base::debug::EnableInProcessStackDumping();
}
base::debug::VerifyDebugger();
#endif
delegate_->PreSandboxStartup();
#if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
if (process_type == switches::kRendererProcess ||
process_type == switches::kZygoteProcess) {
gin::GetThreadIsolationData().InitializeBeforeThreadCreation();
}
#endif
#if BUILDFLAG(IS_POSIX)
base::CheckPThreadStackMinIsSafe();
#endif
#if BUILDFLAG(IS_WIN)
if (!sandbox::policy::Sandbox::Initialize(
SandboxTypeFromCommandLine(command_line),
content_main_params_->sandbox_info)) {
return TerminateForFatalInitializationError();
}
#elif BUILDFLAG(IS_MAC)
if (!IsUnsandboxedSandboxType(SandboxTypeFromCommandLine(command_line))) {
CHECK(sandbox::Seatbelt::IsSandboxed());
}
#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
if (!IsUnsandboxedSandboxType(SandboxTypeFromCommandLine(command_line)) ||
process_type == switches::kZygoteProcess) {
PreSandboxInit();
}
#elif BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_TVOS)
ChildProcessEnterSandbox();
#endif
delegate_->SandboxInitialized(process_type);
#if BUILDFLAG(USE_ZYGOTE)
if (process_type.empty()) {
InitializeZygoteSandboxForBrowserProcess(
*base::CommandLine::ForCurrentProcess());
}
#endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
if (process_type.empty()) {
sandbox::policy::ReportLandlockStatus();
}
#endif
return -1;
}
void ContentMainRunnerImpl::ReInitializeParams(ContentMainParams new_params) {
DCHECK(!content_main_params_);
DCHECK_EQ(delegate_, new_params.delegate);
new_params.delegate = nullptr;
content_main_params_.emplace(std::move(new_params));
}
NO_STACK_PROTECTOR int ContentMainRunnerImpl::Run() {
DCHECK(is_initialized_);
DCHECK(content_main_params_);
DCHECK(!is_shutdown_);
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
std::string process_type =
command_line->GetSwitchValueASCII(switches::kProcessType);
#if defined(ADDRESS_SANITIZER)
base::debug::AsanService::GetInstance()->Initialize();
base::debug::AsanService::GetInstance()->AddErrorCallback(AsanProcessInfoCB);
#endif
bool needs_startup_tracing_after_sandbox_init = false;
if (!process_type.empty()) {
if (process_type != switches::kZygoteProcess) {
#if BUILDFLAG(IS_ARKWEB)
if (!RunRenderRemoteProxy(*command_line)) {
return -1;
}
#endif
if (delegate_->ShouldCreateFeatureList(
ContentMainDelegate::InvokedInChildProcess())) {
InitializeFieldTrialAndFeatureList();
}
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
if (process_type == switches::kGpuProcess) {
tracing::InitTracingPostFeatureList(false,
true);
} else {
needs_startup_tracing_after_sandbox_init = true;
}
#else
tracing::InitTracingPostFeatureList(false,
false);
#endif
if (delegate_->ShouldInitializeMojo(
ContentMainDelegate::InvokedInChildProcess())) {
InitializeMojoCore();
}
delegate_->PostEarlyInitialization(
ContentMainDelegate::InvokedInChildProcess());
base::allocator::PartitionAllocSupport::Get()
->ReconfigureAfterFeatureListInit(process_type);
}
}
MainFunctionParams main_params(command_line);
main_params.ui_task = std::move(content_main_params_->ui_task);
main_params.created_main_parts_closure =
std::move(content_main_params_->created_main_parts_closure);
main_params.needs_startup_tracing_after_sandbox_init =
needs_startup_tracing_after_sandbox_init;
#if BUILDFLAG(IS_WIN)
main_params.sandbox_info = content_main_params_->sandbox_info;
#elif BUILDFLAG(IS_MAC)
main_params.autorelease_pool = content_main_params_->autorelease_pool;
#endif
const bool start_minimal_browser = content_main_params_->minimal_browser_mode;
content_main_params_.reset();
RegisterMainThreadFactories();
if (process_type.empty())
return RunBrowser(std::move(main_params), start_minimal_browser);
return RunOtherNamedProcessTypeMain(process_type, std::move(main_params),
delegate_);
}
int ContentMainRunnerImpl::RunBrowser(MainFunctionParams main_params,
bool start_minimal_browser) {
TRACE_EVENT_INSTANT0("startup", "ContentMainRunnerImpl::RunBrowser(begin)",
TRACE_EVENT_SCOPE_THREAD);
if (is_browser_main_loop_started_)
return -1;
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess)) {
mojo::SyncCallRestrictions::DisableSyncCallInterrupts();
}
variations::MaybeUnpackVariationsStateFile();
if (!mojo_ipc_support_) {
const ContentMainDelegate::InvokedInBrowserProcess invoked_in_browser{
.is_running_test = !main_params.ui_task.is_null()};
if (delegate_->ShouldCreateFeatureList(invoked_in_browser)) {
base::FieldTrialList* leaked_field_trial_list =
SetUpFieldTrialsAndFeatureList().release();
ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list);
std::ignore = leaked_field_trial_list;
}
if (delegate_->ShouldInitializeMojo(invoked_in_browser)) {
InitializeMojoCore();
}
browser_memory_consumer_registry_ = std::make_unique<
base::ScopedMemoryConsumerRegistry<BrowserMemoryConsumerRegistry>>();
std::optional<int> pre_browser_main_exit_code = delegate_->PreBrowserMain();
if (pre_browser_main_exit_code.has_value())
return pre_browser_main_exit_code.value();
#if BUILDFLAG(IS_WIN)
if (l10n_util::GetLocaleOverrides().empty()) {
l10n_util::OverrideLocaleWithUILanguageList();
}
#endif
BrowserTaskExecutor::Create();
auto* provider = delegate_->CreateVariationsIdsProvider();
if (!provider) {
variations::VariationsIdsProvider::CreateInstance(
variations::VariationsIdsProvider::Mode::kUseSignedInState,
std::make_unique<base::DefaultClock>());
}
std::optional<int> post_early_initialization_exit_code =
delegate_->PostEarlyInitialization(invoked_in_browser);
if (post_early_initialization_exit_code.has_value())
return post_early_initialization_exit_code.value();
if (base::HangWatcher::IsEnabled()) {
base::HangWatcher::CreateHangWatcherInstance();
base::ScopedClosureRunner unregister_thread_closure(
base::HangWatcher::RegisterThread(
base::HangWatcher::ThreadType::kMainThread));
std::ignore = unregister_thread_closure.Release();
base::HangWatcher::GetInstance()->Start();
}
#if BUILDFLAG(IS_ANDROID)
if (delegate_->ShouldInitializePerfetto(invoked_in_browser)) {
tracing::InitTracingPostFeatureList(
true, false,
base::BindRepeating(&ShouldAllowSystemTracingConsumer));
}
#else
tracing::InitTracingPostFeatureList(
true, false,
base::BindRepeating(&ShouldAllowSystemTracingConsumer));
#endif
StartBrowserThreadPool();
BrowserTaskExecutor::
InstallPartitionAllocSchedulerLoopQuarantineTaskObserver();
base::PowerMonitor::GetInstance()->Initialize(
MakePowerMonitorDeviceSource(), true);
ProcessVisibilityTracker::GetInstance();
#if BUILDFLAG(IS_ANDROID)
SetupCpuTimeMetrics();
AndroidBatteryMetrics::CreateInstance();
#endif
GetContentClient()->browser()->SetIsMinimalMode(start_minimal_browser);
if (start_minimal_browser) {
ForceInProcessNetworkService();
content::FirstPartySetsHandlerImpl::GetInstance()->Init(
base::FilePath(), net::LocalSetDeclaration());
}
discardable_shared_memory_manager_ =
std::make_unique<discardable_memory::DiscardableSharedMemoryManager>();
mojo_ipc_support_ =
std::make_unique<MojoIpcSupport>(BrowserTaskExecutor::CreateIOThread());
GetContentClient()->browser()->BindBrowserControlInterface(
MaybeAcceptMojoInvitation());
download::SetIOTaskRunner(mojo_ipc_support_->io_thread()->task_runner());
InitializeBrowserMemoryInstrumentationClient();
#if BUILDFLAG(IS_ANDROID)
if (start_minimal_browser) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&MinimalBrowserStartupComplete));
}
#endif
}
base::allocator::PartitionAllocSupport::Get()
->ReconfigureAfterFeatureListInit("");
base::allocator::PartitionAllocSupport::Get()->ReconfigureAfterTaskRunnerInit(
"");
BrowserTaskExecutor::GetIOThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
->PostTask(FROM_HERE, base::BindOnce([] {
base::allocator::ReconfigureSchedulerLoopQuarantineBranch(
base::allocator::SchedulerLoopQuarantineBranchType::kIO);
}));
if (start_minimal_browser) {
DVLOG(0) << "Chrome is running in minimal browser mode.";
return -1;
}
is_browser_main_loop_started_ = true;
main_params.startup_data = mojo_ipc_support_->CreateBrowserStartupData();
return RunBrowserProcessMain(std::move(main_params), delegate_);
}
#if BUILDFLAG(IS_ARKWEB)
bool ContentMainRunnerImpl::RunRenderRemoteProxy(
const base::CommandLine& command_line) {
std::string process_type =
command_line.GetSwitchValueASCII(switches::kProcessType);
if (process_type != switches::kRendererProcess &&
process_type != switches::kGpuProcess) {
return true;
}
RenderRemoteProxy::CreateAndRegist(command_line, process_type);
if (process_type == switches::kGpuProcess ||
!RenderRemoteProxy::IsFdsChannelReady()) {
return RenderRemoteProxy::WaitForBrowserFd();
}
return true;
}
#endif
void ContentMainRunnerImpl::Shutdown() {
DCHECK(is_initialized_);
DCHECK(!is_shutdown_);
#if BUILDFLAG(IS_IOS)
base::PermanentThreadAllowance::AllowBaseSyncPrimitives();
base::PermanentThreadAllowance::AllowBlocking();
#endif
mojo_ipc_support_.reset();
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
std::string process_type =
command_line.GetSwitchValueASCII(switches::kProcessType);
delegate_->ProcessExiting(process_type);
BrowserTaskExecutor::Shutdown();
#if BUILDFLAG(IS_WIN)
#ifdef _CRTDBG_MAP_ALLOC
_CrtDumpMemoryLeaks();
#endif
#endif
exit_manager_.reset(nullptr);
delegate_ = nullptr;
is_shutdown_ = true;
}
void ContentMainRunnerImpl::ShutdownOnUIThread() {
base::ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
discardable_shared_memory_manager_.reset();
browser_memory_consumer_registry_.reset();
}
std::unique_ptr<ContentMainRunner> ContentMainRunner::Create() {
return ContentMainRunnerImpl::Create();
}
}