对于现代开发者而言,Chromium 不仅是一个浏览器,更是一座蕴含丰富系统编程思想的技术宝库。它采用多进程架构,包含浏览器进程、渲染进程、GPU进程等。理解其核心——浏览器进程的启动过程,是深入探究 Chromium 底层工作原理的绝佳起点。本文将以 Electron(一个基于 Chromium 的应用框架)的源码为例,带你一步步剖析这个复杂的启动流程。
让我们从 Electron 的入口函数开始。Electron 的 main 函数是应用启动的起点。
int main(int argc, char* argv[]) {
return ElectronMain(argc, argv);
}
int main(int argc, char* argv[]) {
// 初始化命令行参数
argv = uv_setup_args(argc, argv);
base::CommandLine::Init(argc, argv);
electron::ElectronCommandLine::Init(argc, argv);
// 定义 delegate,参与 Chromium 的处理逻辑。
electron::ElectronMainDelegate delegate;
// content 模块是 Chromium 上层的模块
return content::ContentMain(content::ContentMainParams{&delegate});
}
这里的 content::ContentMain 函数是进入 Chromium 世界的正式入口。它的参数是一个 ContentMainParams 对象,其中最重要的字段是 delegate。这个 delegate 是 content::ContentMainDelegate 类型,它提供了一系列钩子函数,允许上层(如 Electron)参与并定制 Chromium 的内部逻辑。ContentMainParams 的简化定义如下:
struct ContentMainParams {
explicit ContentMainParams(ContentMainDelegate* delegate);
/*
class ContentMainDelegate {
public:
// ...
protected:
// 子类实现
virtual ContentClient* CreateContentClient();
virtual ContentBrowserClient* CreateContentBrowserClient();
virtual ContentGpuClient* CreateContentGpuClient();
virtual ContentRendererClient* CreateContentRendererClient();
virtual ContentUtilityClient* CreateContentUtilityClient();
};
*/
raw_ptr<ContentMainDelegate> delegate;
};
接下来,我们进入 ContentMain 函数的内部。
int ContentMain(ContentMainParams params) {
/*
class ContentMainRunnerImpl : public ContentMainRunner {
public:
int Initialize(ContentMainParams params) override;
int Run() override;
private:
raw_ptr<ContentMainDelegate> delegate_ = nullptr;
std::optional<ContentMainParams> content_main_params_;
};
*/
auto runner = ContentMainRunner::Create();
return RunContentProcess(std::move(params), runner.get());
}
ContentMain 内部创建了一个 ContentMainRunnerImpl 对象,然后将 ContentMainParams 和这个 runner 一起传递给 RunContentProcess 函数。
int RunContentProcess(
ContentMainParams params,
ContentMainRunner* content_main_runner) {
// 初始化参数
int argc = 0;
const char** argv = nullptr;
argc = params.argc;
argv = params.argv;
base::CommandLine::Init(argc, argv);
// 设置进程 title
base::SetProcessTitleFromCommandLine(argv);
// 执行 ContentMainRunnerImpl 的 Initialize、Run 等函数
content_main_runner->Initialize(std::move(params));
content_main_runner->Run();
content_main_runner->Shutdown();
}
RunContentProcess 的核心逻辑是依次调用 runner 的 Initialize、Run 和 Shutdown 方法。我们首先聚焦于 Initialize 阶段,这里完成了大量前置准备工作。
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();
// 进程类型,如浏览器进程、渲染进程,浏览器进程的 process_type 为空字符串
std::string process_type = command_line.GetSwitchValueASCII(switches::kProcessType);
// 根据进程类型执行不同逻辑
if (!process_type.empty()) {
// 不是种子进程则创建线程池
if (process_type != switches::kZygoteProcess) {
CreateChildThreadPool(process_type);
}
} else {
// 浏览器进程创建线程池,和 CreateChildThreadPool 类似
delegate_->CreateThreadPool("Browser");
}
// 注册进程 IPC 相关的信息,创建子进程的时候使用,如渲染进程
g_fds->Set(kMojoIPCChannel,
kMojoIPCChannel + base::GlobalDescriptors::kBaseDescriptor);
// ...
// 创建 content 模块的 client,用于参与 content 模块的处理流程
if (!GetContentClient())
/*
static void Create(ContentMainDelegate* delegate) {
ContentClient* client = delegate->CreateContentClient();
// 设置到全局变量中
SetContentClient(client);
}
*/
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();
/*
class ContentClientInitializer {
public:
static void Set(const std::string& process_type,
ContentMainDelegate* delegate) {
ContentClient* content_client = GetContentClient();
// 创建参与浏览器进程的对象,该对象实现了各自钩子函数,在浏览器进程执行的过程中被回调
if (process_type.empty())
content_client->browser_ = delegate->CreateContentBrowserClient();
// 命令行参数
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
// GPU 进程
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();
// 工具进程
if (process_type == switches::kUtilityProcess ||
cmd->HasSwitch(switches::kSingleProcess))
content_client->utility_ = delegate->CreateContentUtilityClient();
}
};
*/
ContentClientInitializer::Set(process_type, delegate_);
RegisterPathProvider();
delegate_->PreSandboxStartup();
// sandbox 初始化相关
delegate_->SandboxInitialized(process_type);
// 浏览器进程
if (process_type.empty()) {
// 创建种子沙盒进程,用于限制子进程的能力和加速启动
InitializeZygoteSandboxForBrowserProcess(
*base::CommandLine::ForCurrentProcess());
}
// Return -1 to indicate no early termination.
return -1;
}
Initialize 方法完成了几个关键步骤:根据进程类型创建线程池、注册 IPC 通道、通过 delegate 创建各类进程(浏览器、GPU、渲染器等)的客户端对象,并进行沙盒初始化。注意,浏览器进程的 process_type 是空字符串,这是一个重要的判断依据。
初始化完成后,真正的启动流程在 Run 方法中展开。
int ContentMainRunnerImpl::Run() {
const base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
std::string process_type = command_line->GetSwitchValueASCII(switches::kProcessType);
MainFunctionParams main_params(command_line);
main_params.ui_task = std::move(content_main_params_->ui_task);
// ...
const bool start_minimal_browser = content_main_params_->minimal_browser_mode;
// 浏览器进程
if (process_type.empty())
return RunBrowser(std::move(main_params), start_minimal_browser);
// 其他类型的子进程,如渲染进程
return RunOtherNamedProcessTypeMain(process_type, std::move(main_params),
delegate_);
}
Run 方法根据进程类型进行分发。对于浏览器进程,它将调用 RunBrowser 函数,这也是我们分析的重点。
int ContentMainRunnerImpl::RunBrowser(MainFunctionParams main_params,
bool start_minimal_browser) {
if (!mojo_ipc_support_) {
const ContentMainDelegate::InvokedInBrowserProcess invoked_in_browser{
.is_running_test = !main_params.ui_task.is_null()};
// 初始化 IPC 相关
if (delegate_->ShouldInitializeMojo(invoked_in_browser)) {
InitializeMojoCore();
}
// 执行钩子函数
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();
// 创建 UI 线程和 IO 线程相关的数据结构
BrowserTaskExecutor::Create();
// 执行钩子函数,Electron 在这钩子函数执行和 Node.js 相关的初始化逻辑
delegate_->PostEarlyInitialization(invoked_in_browser);
// 启动线程池
StartBrowserThreadPool();
mojo_ipc_support_ =
std::make_unique<MojoIpcSupport>(BrowserTaskExecutor::CreateIOThread());
// 执行钩子函数
GetContentClient()->browser()->BindBrowserControlInterface(
MaybeAcceptMojoInvitation());
download::SetIOTaskRunner(mojo_ipc_support_->io_thread()->task_runner());
}
is_browser_main_loop_started_ = true;
main_params.startup_data = mojo_ipc_support_->CreateBrowserStartupData();
// 继续启动
return RunBrowserProcessMain(std::move(main_params), delegate_);
}
RunBrowser 中一个至关重要的步骤是调用 BrowserTaskExecutor::Create()。这个方法负责创建 UI 线程和 IO 线程的核心调度器,这是浏览器多线程模型的基础。如果你对 C/C++ 中的对象生命周期和资源管理感兴趣,这里的实现细节值得深入研究。
void BrowserTaskExecutor::Create() {
CreateInternal(std::make_unique<BrowserUIThreadScheduler>(),
std::make_unique<BrowserIOThreadDelegate>());
}
BrowserUIThreadScheduler::BrowserUIThreadScheduler()
// 任务管理器
: owned_sequence_manager_(
base::sequence_manager::CreateUnboundSequenceManager(
base::sequence_manager::SequenceManager::Settings::Builder()
.SetMessagePumpType(base::MessagePumpType::UI)
.SetIsMainThread(true)
.Build())),
task_queues_(BrowserThread::UI, owned_sequence_manager_.get()),
handle_(task_queues_.GetHandle()) {
task_queues_.SetOnTaskCompletedHandler(base::BindRepeating(
&BrowserUIThreadScheduler::OnTaskCompleted, base::Unretained(this)));
CommonSequenceManagerSetup(owned_sequence_manager_.get());
owned_sequence_manager_->SetDefaultTaskRunner(handle_->GetDefaultTaskRunner());
// 注册事件循环依赖的 delegate
owned_sequence_manager_->BindToMessagePump(
// 创建事件循环对象
base::MessagePump::Create(base::MessagePumpType::UI));
g_browser_ui_thread_scheduler = this;
}
BrowserUIThreadScheduler 的构造函数创建了序列管理器(SequenceManager)和消息泵(MessagePump),它们共同构成了 UI 线程事件循环的核心。之后,流程进入 RunBrowserProcessMain。
int RunBrowserProcessMain(MainFunctionParams main_function_params,
ContentMainDelegate* delegate) {
auto exit_code = delegate->RunProcess("", std::move(main_function_params));
return BrowserMain(std::move(std::get<MainFunctionParams>(exit_code)));
}
int BrowserMain(MainFunctionParams parameters) {
base::CurrentProcess::GetInstance().SetProcessType(
base::CurrentProcessType::PROCESS_BROWSER);
std::unique_ptr<BrowserMainRunnerImpl> main_runner(
BrowserMainRunnerImpl::Create());
int exit_code = main_runner->Initialize(std::move(parameters));
if (exit_code >= 0)
return exit_code;
exit_code = main_runner->Run();
main_runner->Shutdown();
return exit_code;
}
RunBrowserProcessMain 创建了 BrowserMainRunnerImpl 对象,并依次执行其 Initialize 和 Run 方法。在 Initialize 中,创建了 BrowserMainLoop 并执行了一系列启动任务。
int BrowserMainRunnerImpl::Initialize(MainFunctionParams parameters) {
main_loop_ = std::make_unique<BrowserMainLoop>(std::move(parameters), ...);
// 创建 BrowserMainPart
// parts_ = GetContentClient()->browser()->CreateBrowserMainParts(...);
main_loop_->Init();
// 执行上层各种钩子函数
main_loop_->PreCreateMainMessageLoop();
main_loop_->CreateMainMessageLoop();
main_loop_->PostCreateMainMessageLoop();
}
main_loop_->CreateStartupTasks();
main_loop_->GetResultCode();
// Return -1 to indicate no early termination.
return -1;
}
PostCreateMainMessageLoop 方法创建了一系列系统监控相关的对象。
void BrowserMainLoop::PostCreateMainMessageLoop() {
// 创建各种对象
{
TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:SystemMonitor");
system_monitor_ = std::make_unique<base::SystemMonitor>();
}
{
network_change_notifier_ = net::NetworkChangeNotifier::CreateIfNeeded();
}
{
TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:ScreenlockMonitor");
std::unique_ptr<ScreenlockMonitorSource> screenlock_monitor_source =
std::make_unique<ScreenlockMonitorDeviceSource>();
screenlock_monitor_ = std::make_unique<ScreenlockMonitor>(
std::move(screenlock_monitor_source));
}
// ...
if (parts_)
parts_->PostCreateMainMessageLoop();
}
而 CreateStartupTasks 则编排了关键的启动任务序列,包括创建线程。
void BrowserMainLoop::CreateStartupTasks() {
startup_task_runner_ = std::make_unique<StartupTaskRunner>(
base::OnceCallback<void(int, base::TimeDelta, base::TimeDelta)>(),
base::SingleThreadTaskRunner::GetCurrentDefault());
StartupTask pre_create_threads = base::BindOnce(
&BrowserMainLoop::PreCreateThreads, base::Unretained(this));
startup_task_runner_->AddTask(std::move(pre_create_threads));
// 创建 IO 线程,使用了前面创建的 IO 线程相关的数据结构
/*
int BrowserMainLoop::CreateThreads() {
if (!io_thread_) {
io_thread_ = BrowserTaskExecutor::CreateIOThread();
}
io_thread_->RegisterAsBrowserThread();
BrowserTaskExecutor::InitializeIOThread();
}
*/
StartupTask create_threads =
base::BindOnce(&BrowserMainLoop::CreateThreads, base::Unretained(this));
startup_task_runner_->AddTask(std::move(create_threads));
// ...
// 执行上面创建的任务
startup_task_runner_->RunAllTasksNow(false);
}
所有初始化工作就绪后,BrowserMainRunnerImpl::Run 启动了主消息循环。
int BrowserMainRunnerImpl::Run() {
main_loop_->RunMainMessageLoop();
return main_loop_->GetResultCode();
}
void BrowserMainLoop::RunMainMessageLoop() {
// 创建事件循环
auto main_run_loop = std::make_unique<base::RunLoop>();
// 执行钩子函数
if (parts_)
parts_->WillRunMainMessageLoop(main_run_loop);
main_run_loop->Run();
}
// 执行事件循环
void RunLoop::Run(const Location& location) {
if (!BeforeRun()) {
return;
}
// 执行 delegate_ 的 Run (执行 SequenceManagerImpl::BindToMessagePump 时设置)
delegate_->Run(application_tasks_allowed, TimeDelta::Max());
AfterRun();
}
delegate_ 是在之前创建 UI 线程调度器时设置的 ThreadControllerWithMessagePumpImpl 对象。
void ThreadControllerWithMessagePumpImpl::Run(bool application_tasks_allowed,
TimeDelta timeout) {
pump_->Run(this);
}
最终,ThreadControllerWithMessagePumpImpl::Run 调用了消息泵(pump_)的 Run 方法。我们以 Linux 下常见的 MessagePumpEpoll 为例,看看事件循环的最终形态。
void MessagePumpEpoll::Run(Delegate* delegate) {
// 事件循环
for (;;) {
if (run_state.should_quit) {
break;
}
delegate->DoIdleWork();
TimeDelta timeout = 最长等待时间;
delegate->BeforeWait();
// 等待事件
WaitForEpollEvents(timeout);
}
}
bool MessagePumpEpoll::WaitForEpollEvents(TimeDelta timeout) {
const int epoll_timeout =
timeout.is_max() ? -1
: saturated_cast<int>(timeout.InMillisecondsRoundedUp());
epoll_event epoll_events[16];
std::vector<epoll_event> poll_events;
span<epoll_event> ready_events;
// 等待事件
const int epoll_result = epoll_wait(epoll_.get(), epoll_events,
std::size(epoll_events), epoll_timeout);
ready_events =
span(epoll_events).first(base::checked_cast<size_t>(epoll_result));
// 处理就绪事件
for (epoll_event& e : ready_events) {
auto& entry = EpollEventEntry::FromEpollEvent(e);
DCHECK(!entry.active_event);
EpollEventEntry::FromEpollEvent(e).active_event = &e;
}
// 执行回调
for (auto& e : ready_events) {
if (e.data.ptr) {
auto& entry = EpollEventEntry::FromEpollEvent(e);
entry.active_event = nullptr;
OnEpollEvent(entry, e.events);
}
}
return true;
}
至此,Chromium 浏览器进程完成了从入口函数到事件循环的完整启动。这个过程涵盖了多线程模型、IPC通信、沙盒安全、模块化设计等多个核心领域。通过对 开源实战 项目如 Electron 的源码进行分析,我们能更直观地理解这些复杂系统是如何协同工作的。希望这次对 Chromium 浏览器进程启动的剖析,能为你打开一扇深入理解现代浏览器与桌面应用框架的大门。