找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3014

积分

0

好友

402

主题
发表于 2 小时前 | 查看: 3| 回复: 0

对于现代开发者而言,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。这个 delegatecontent::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 的 InitializeRunShutdown 方法。我们首先聚焦于 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 对象,并依次执行其 InitializeRun 方法。在 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 浏览器进程启动的剖析,能为你打开一扇深入理解现代浏览器与桌面应用框架的大门。




上一篇:链抽象如何解决RWA的流动性割裂与跨链难题?
下一篇:Node.js HTTP 客户端内存泄露问题解析:双重响应场景的修复方案
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-15 04:27 , Processed in 0.605867 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表