2022-05-23 08:38:01 -04:00
|
|
|
// Copyright (c) 2022 The Chromium Authors and Alex313031. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "content/shell/app/shell_main_delegate.h"
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <tuple>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
#include "base/base_paths.h"
|
|
|
|
#include "base/base_switches.h"
|
|
|
|
#include "base/command_line.h"
|
|
|
|
#include "base/cpu.h"
|
|
|
|
#include "base/files/file.h"
|
|
|
|
#include "base/files/file_path.h"
|
|
|
|
#include "base/lazy_instance.h"
|
|
|
|
#include "base/logging.h"
|
|
|
|
#include "base/path_service.h"
|
|
|
|
#include "base/trace_event/trace_log.h"
|
|
|
|
#include "build/build_config.h"
|
|
|
|
#include "components/crash/core/common/crash_key.h"
|
|
|
|
#include "content/common/content_constants_internal.h"
|
|
|
|
#include "content/public/browser/browser_main_runner.h"
|
|
|
|
#include "content/public/common/content_switches.h"
|
|
|
|
#include "content/public/common/main_function_params.h"
|
|
|
|
#include "content/public/common/url_constants.h"
|
|
|
|
#include "content/shell/app/shell_crash_reporter_client.h"
|
|
|
|
#include "content/shell/browser/shell_content_browser_client.h"
|
|
|
|
#include "content/shell/browser/shell_paths.h"
|
|
|
|
#include "content/shell/common/shell_content_client.h"
|
|
|
|
#include "content/shell/common/shell_switches.h"
|
|
|
|
#include "content/shell/gpu/shell_content_gpu_client.h"
|
|
|
|
#include "content/shell/renderer/shell_content_renderer_client.h"
|
|
|
|
#include "content/shell/utility/shell_content_utility_client.h"
|
|
|
|
#include "ipc/ipc_buildflags.h"
|
|
|
|
#include "net/cookies/cookie_monster.h"
|
|
|
|
#include "ui/base/resource/resource_bundle.h"
|
|
|
|
|
|
|
|
#if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
|
|
|
|
#define IPC_MESSAGE_MACROS_LOG_ENABLED
|
|
|
|
#include "content/public/common/content_ipc_logging.h"
|
|
|
|
#define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) \
|
|
|
|
content::RegisterIPCLogger(msg_id, logger)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !BUILDFLAG(IS_ANDROID)
|
|
|
|
#include "content/web_test/browser/web_test_browser_main_runner.h" // nogncheck
|
|
|
|
#include "content/web_test/browser/web_test_content_browser_client.h" // nogncheck
|
|
|
|
#include "content/web_test/renderer/web_test_content_renderer_client.h" // nogncheck
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BUILDFLAG(IS_ANDROID)
|
|
|
|
#include "base/android/apk_assets.h"
|
|
|
|
#include "base/posix/global_descriptors.h"
|
|
|
|
#include "content/public/browser/android/compositor.h"
|
|
|
|
#include "content/shell/android/shell_descriptors.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !BUILDFLAG(IS_FUCHSIA)
|
|
|
|
#include "components/crash/core/app/crashpad.h" // nogncheck
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BUILDFLAG(IS_MAC)
|
|
|
|
#include "content/shell/app/paths_mac.h"
|
|
|
|
#include "content/shell/app/shell_main_delegate_mac.h"
|
|
|
|
#endif // BUILDFLAG(IS_MAC)
|
|
|
|
|
|
|
|
#if BUILDFLAG(IS_WIN)
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
|
|
#include <initguid.h>
|
|
|
|
#include "base/logging_win.h"
|
|
|
|
#include "content/shell/common/v8_crashpad_support_win.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_ANDROID)
|
|
|
|
#include "v8/include/v8-wasm-trap-handler-posix.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
#if !BUILDFLAG(IS_FUCHSIA)
|
|
|
|
base::LazyInstance<content::ShellCrashReporterClient>::Leaky
|
|
|
|
g_shell_crash_client = LAZY_INSTANCE_INITIALIZER;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BUILDFLAG(IS_WIN)
|
|
|
|
// If "Content Shell" doesn't show up in your list of trace providers in
|
|
|
|
// Sawbuck, add these registry entries to your machine (NOTE the optional
|
|
|
|
// Wow6432Node key for x64 machines):
|
|
|
|
// 1. Find: HKLM\SOFTWARE\[Wow6432Node\]Google\Sawbuck\Providers
|
|
|
|
// 2. Add a subkey with the name "{6A3E50A4-7E15-4099-8413-EC94D8C2A4B6}"
|
|
|
|
// 3. Add these values:
|
|
|
|
// "default_flags"=dword:00000001
|
|
|
|
// "default_level"=dword:00000004
|
|
|
|
// @="Content Shell"
|
|
|
|
|
|
|
|
// {6A3E50A4-7E15-4099-8413-EC94D8C2A4B6}
|
|
|
|
const GUID kContentShellProviderName = {
|
|
|
|
0x6a3e50a4, 0x7e15, 0x4099,
|
|
|
|
{ 0x84, 0x13, 0xec, 0x94, 0xd8, 0xc2, 0xa4, 0xb6 } };
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void InitLogging(const base::CommandLine& command_line) {
|
|
|
|
base::FilePath log_filename =
|
|
|
|
command_line.GetSwitchValuePath(switches::kLogFile);
|
|
|
|
if (log_filename.empty()) {
|
|
|
|
#if BUILDFLAG(IS_FUCHSIA)
|
|
|
|
base::PathService::Get(base::DIR_TEMP, &log_filename);
|
|
|
|
#else
|
|
|
|
base::PathService::Get(base::DIR_EXE, &log_filename);
|
|
|
|
#endif
|
|
|
|
log_filename = log_filename.AppendASCII("thorium_shell.log");
|
|
|
|
}
|
|
|
|
|
|
|
|
logging::LoggingSettings settings;
|
|
|
|
settings.logging_dest = logging::LOG_TO_ALL;
|
|
|
|
settings.log_file_path = log_filename.value().c_str();
|
|
|
|
settings.delete_old = logging::DELETE_OLD_LOG_FILE;
|
|
|
|
logging::InitLogging(settings);
|
|
|
|
logging::SetLogItems(true /* Process ID */, true /* Thread ID */,
|
|
|
|
true /* Timestamp */, false /* Tick count */);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace content {
|
|
|
|
|
|
|
|
ShellMainDelegate::ShellMainDelegate(bool is_content_browsertests)
|
|
|
|
: is_content_browsertests_(is_content_browsertests) {}
|
|
|
|
|
|
|
|
ShellMainDelegate::~ShellMainDelegate() {
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ShellMainDelegate::BasicStartupComplete(int* exit_code) {
|
|
|
|
int dummy;
|
|
|
|
if (!exit_code)
|
|
|
|
exit_code = &dummy;
|
|
|
|
|
|
|
|
base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
|
|
|
|
if (command_line.HasSwitch("run-layout-test")) {
|
|
|
|
std::cerr << std::string(79, '*') << "\n"
|
|
|
|
<< "* The flag --run-layout-test is obsolete. Please use --"
|
|
|
|
<< switches::kRunWebTests << " instead. *\n"
|
|
|
|
<< std::string(79, '*') << "\n";
|
|
|
|
command_line.AppendSwitch(switches::kRunWebTests);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if BUILDFLAG(IS_ANDROID)
|
|
|
|
Compositor::Initialize();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BUILDFLAG(IS_WIN)
|
|
|
|
// Enable trace control and transport through event tracing for Windows.
|
|
|
|
logging::LogEventProvider::Initialize(kContentShellProviderName);
|
|
|
|
|
|
|
|
v8_crashpad_support::SetUp();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BUILDFLAG(IS_MAC)
|
|
|
|
// Needs to happen before InitializeResourceBundle().
|
|
|
|
OverrideFrameworkBundlePath();
|
|
|
|
OverrideOuterBundlePath();
|
|
|
|
OverrideChildProcessPath();
|
|
|
|
OverrideSourceRootPath();
|
|
|
|
EnsureCorrectResolutionSettings();
|
|
|
|
OverrideBundleID();
|
|
|
|
#endif // BUILDFLAG(IS_MAC)
|
|
|
|
|
|
|
|
InitLogging(command_line);
|
|
|
|
|
|
|
|
#if !BUILDFLAG(IS_ANDROID)
|
|
|
|
if (switches::IsRunWebTestsSwitchPresent()) {
|
|
|
|
const bool browser_process =
|
|
|
|
command_line.GetSwitchValueASCII(switches::kProcessType).empty();
|
|
|
|
if (browser_process) {
|
|
|
|
web_test_runner_ = std::make_unique<WebTestBrowserMainRunner>();
|
|
|
|
web_test_runner_->Initialize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
RegisterShellPathProvider();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-04 02:08:56 -04:00
|
|
|
bool ShellMainDelegate::ShouldCreateFeatureList(InvokedIn invoked_in) {
|
|
|
|
return invoked_in == InvokedIn::kChildProcess;
|
2022-05-23 08:38:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void ShellMainDelegate::PreSandboxStartup() {
|
|
|
|
#if defined(ARCH_CPU_ARM_FAMILY) && \
|
|
|
|
(BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
|
|
|
|
// Create an instance of the CPU class to parse /proc/cpuinfo and cache
|
|
|
|
// cpu_brand info.
|
|
|
|
base::CPU cpu_info;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Disable platform crash handling and initialize the crash reporter, if
|
|
|
|
// requested.
|
|
|
|
// TODO(crbug.com/1226159): Implement crash reporter integration for Fuchsia.
|
|
|
|
#if !BUILDFLAG(IS_FUCHSIA)
|
|
|
|
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
|
|
|
switches::kEnableCrashReporter)) {
|
|
|
|
std::string process_type =
|
|
|
|
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
|
|
|
|
switches::kProcessType);
|
|
|
|
crash_reporter::SetCrashReporterClient(g_shell_crash_client.Pointer());
|
|
|
|
// Reporting for sub-processes will be initialized in ZygoteForked.
|
|
|
|
if (process_type != switches::kZygoteProcess) {
|
|
|
|
crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
|
|
|
|
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
|
|
|
|
crash_reporter::SetFirstChanceExceptionHandler(
|
|
|
|
v8::TryHandleWebAssemblyTrapPosix);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // !BUILDFLAG(IS_FUCHSIA)
|
|
|
|
|
|
|
|
crash_reporter::InitializeCrashKeys();
|
|
|
|
|
|
|
|
InitializeResourceBundle();
|
|
|
|
}
|
|
|
|
|
|
|
|
absl::variant<int, MainFunctionParams> ShellMainDelegate::RunProcess(
|
|
|
|
const std::string& process_type,
|
|
|
|
MainFunctionParams main_function_params) {
|
|
|
|
// For non-browser process, return and have the caller run the main loop.
|
|
|
|
if (!process_type.empty())
|
|
|
|
return std::move(main_function_params);
|
|
|
|
|
|
|
|
base::trace_event::TraceLog::GetInstance()->set_process_name("Browser");
|
|
|
|
base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex(
|
|
|
|
kTraceEventBrowserProcessSortIndex);
|
|
|
|
|
|
|
|
#if !BUILDFLAG(IS_ANDROID)
|
|
|
|
if (switches::IsRunWebTestsSwitchPresent()) {
|
|
|
|
// Web tests implement their own BrowserMain() replacement.
|
|
|
|
web_test_runner_->RunBrowserMain(std::move(main_function_params));
|
|
|
|
web_test_runner_.reset();
|
|
|
|
// Returning 0 to indicate that we have replaced BrowserMain() and the
|
|
|
|
// caller should not call BrowserMain() itself. Web tests do not ever
|
|
|
|
// return an error.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// On non-Android, we can return the |main_function_params| back and have the
|
|
|
|
// caller run BrowserMain() normally.
|
|
|
|
return std::move(main_function_params);
|
|
|
|
#else
|
|
|
|
// On Android, we defer to the system message loop when the stack unwinds.
|
|
|
|
// So here we only create (and leak) a BrowserMainRunner. The shutdown
|
|
|
|
// of BrowserMainRunner doesn't happen in Chrome Android and doesn't work
|
|
|
|
// properly on Android at all.
|
|
|
|
std::unique_ptr<BrowserMainRunner> main_runner = BrowserMainRunner::Create();
|
|
|
|
// In browser tests, the |main_function_params| contains a |ui_task| which
|
|
|
|
// will execute the testing. The task will be executed synchronously inside
|
|
|
|
// Initialize() so we don't depend on the BrowserMainRunner being Run().
|
|
|
|
int initialize_exit_code =
|
|
|
|
main_runner->Initialize(std::move(main_function_params));
|
|
|
|
DCHECK_LT(initialize_exit_code, 0)
|
|
|
|
<< "BrowserMainRunner::Initialize failed in ShellMainDelegate";
|
|
|
|
std::ignore = main_runner.release();
|
|
|
|
// Return 0 as BrowserMain() should not be called after this, bounce up to
|
|
|
|
// the system message loop for ContentShell, and we're already done thanks
|
|
|
|
// to the |ui_task| for browser tests.
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
|
|
|
|
void ShellMainDelegate::ZygoteForked() {
|
|
|
|
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
|
|
|
switches::kEnableCrashReporter)) {
|
|
|
|
std::string process_type =
|
|
|
|
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
|
|
|
|
switches::kProcessType);
|
|
|
|
crash_reporter::InitializeCrashpad(false, process_type);
|
|
|
|
crash_reporter::SetFirstChanceExceptionHandler(
|
|
|
|
v8::TryHandleWebAssemblyTrapPosix);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
|
|
|
|
|
|
|
|
void ShellMainDelegate::InitializeResourceBundle() {
|
|
|
|
#if BUILDFLAG(IS_ANDROID)
|
|
|
|
// On Android, the renderer runs with a different UID and can never access
|
|
|
|
// the file system. Use the file descriptor passed in at launch time.
|
|
|
|
auto* global_descriptors = base::GlobalDescriptors::GetInstance();
|
|
|
|
int pak_fd = global_descriptors->MaybeGet(kShellPakDescriptor);
|
|
|
|
base::MemoryMappedFile::Region pak_region;
|
|
|
|
if (pak_fd >= 0) {
|
|
|
|
pak_region = global_descriptors->GetRegion(kShellPakDescriptor);
|
|
|
|
} else {
|
|
|
|
pak_fd =
|
|
|
|
base::android::OpenApkAsset("assets/content_shell.pak", &pak_region);
|
|
|
|
// Loaded from disk for browsertests.
|
|
|
|
if (pak_fd < 0) {
|
|
|
|
base::FilePath pak_file;
|
|
|
|
bool r = base::PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_file);
|
|
|
|
DCHECK(r);
|
|
|
|
pak_file = pak_file.Append(FILE_PATH_LITERAL("paks"));
|
|
|
|
pak_file = pak_file.Append(FILE_PATH_LITERAL("content_shell.pak"));
|
|
|
|
int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
|
|
|
|
pak_fd = base::File(pak_file, flags).TakePlatformFile();
|
|
|
|
pak_region = base::MemoryMappedFile::Region::kWholeFile;
|
|
|
|
}
|
|
|
|
global_descriptors->Set(kShellPakDescriptor, pak_fd, pak_region);
|
|
|
|
}
|
|
|
|
DCHECK_GE(pak_fd, 0);
|
|
|
|
// TODO(crbug.com/330930): A better way to prevent fdsan error from a double
|
|
|
|
// close is to refactor GlobalDescriptors.{Get,MaybeGet} to return
|
|
|
|
// "const base::File&" rather than fd itself.
|
|
|
|
base::File android_pak_file(pak_fd);
|
|
|
|
ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(
|
|
|
|
android_pak_file.Duplicate(), pak_region);
|
|
|
|
ui::ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion(
|
|
|
|
std::move(android_pak_file), pak_region, ui::k100Percent);
|
|
|
|
#elif BUILDFLAG(IS_MAC)
|
|
|
|
ui::ResourceBundle::InitSharedInstanceWithPakPath(GetResourcesPakFilePath());
|
|
|
|
#else
|
|
|
|
base::FilePath pak_file;
|
|
|
|
bool r = base::PathService::Get(base::DIR_ASSETS, &pak_file);
|
|
|
|
DCHECK(r);
|
|
|
|
pak_file = pak_file.Append(FILE_PATH_LITERAL("content_shell.pak"));
|
|
|
|
ui::ResourceBundle::InitSharedInstanceWithPakPath(pak_file);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShellMainDelegate::PreBrowserMain() {
|
|
|
|
#if BUILDFLAG(IS_MAC)
|
|
|
|
RegisterShellCrApp();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-06-04 02:08:56 -04:00
|
|
|
void ShellMainDelegate::PostEarlyInitialization(InvokedIn invoked_in) {
|
|
|
|
if (!ShouldCreateFeatureList(invoked_in)) {
|
|
|
|
// Apply field trial testing configuration since content did not.
|
|
|
|
browser_client_->CreateFeatureListAndFieldTrials();
|
|
|
|
}
|
2022-05-23 08:38:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ContentClient* ShellMainDelegate::CreateContentClient() {
|
|
|
|
content_client_ = std::make_unique<ShellContentClient>();
|
|
|
|
return content_client_.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentBrowserClient* ShellMainDelegate::CreateContentBrowserClient() {
|
|
|
|
#if !BUILDFLAG(IS_ANDROID)
|
|
|
|
if (switches::IsRunWebTestsSwitchPresent()) {
|
|
|
|
browser_client_ = std::make_unique<WebTestContentBrowserClient>();
|
|
|
|
return browser_client_.get();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
browser_client_ = std::make_unique<ShellContentBrowserClient>();
|
|
|
|
return browser_client_.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentGpuClient* ShellMainDelegate::CreateContentGpuClient() {
|
|
|
|
gpu_client_ = std::make_unique<ShellContentGpuClient>();
|
|
|
|
return gpu_client_.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentRendererClient* ShellMainDelegate::CreateContentRendererClient() {
|
|
|
|
#if !BUILDFLAG(IS_ANDROID)
|
|
|
|
if (switches::IsRunWebTestsSwitchPresent()) {
|
|
|
|
renderer_client_ = std::make_unique<WebTestContentRendererClient>();
|
|
|
|
return renderer_client_.get();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
renderer_client_ = std::make_unique<ShellContentRendererClient>();
|
|
|
|
return renderer_client_.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentUtilityClient* ShellMainDelegate::CreateContentUtilityClient() {
|
|
|
|
utility_client_ =
|
|
|
|
std::make_unique<ShellContentUtilityClient>(is_content_browsertests_);
|
|
|
|
return utility_client_.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace content
|