Chromium 网络栈之初始化 URLRequestContext

发布于 2021-11-02


URLRequestContext里面是网络栈的各种上下文信息,包含了各种网络栈涉及到的网络组件指针。

创建 URLRequestContext

scoped_refptr<base::SingleThreadTaskRunner> g_main_task_runner;
base::Closure g_main_quit_closure;
std::unique_ptr<base::Thread> g_network_thread;
std::unique_ptr<net::URLRequestContext> g_url_request_context;

void ShutdownOnMainThread() {
  if (g_main_quit_closure) {
    g_main_quit_closure.Run();
  }
}

void ShutdownUrlRequestContextOnNetworkThread() {
  g_url_request_context.reset();

  g_main_task_runner->PostTask(FROM_HERE, base::BindOnce(ShutdownOnMainThread));
}

void InitUrlRequestContextOnNetworkThread() {
  net::URLRequestContextBuilder context_builder;
  g_url_request_context = context_builder.Build();

  g_network_thread->task_runner()->PostDelayedTask(
      FROM_HERE, base::BindOnce(ShutdownUrlRequestContextOnNetworkThread),
      base::TimeDelta::FromSeconds(1));
}

int main(int argc, char* argv[]) {
  base::AtExitManager exit_manager;
  base::CommandLine::Init(0, 0);
  logging::LoggingSettings settings;
  settings.logging_dest = logging::LOG_TO_ALL;
  settings.delete_old = logging::DELETE_OLD_LOG_FILE;
  settings.log_file = L"learn_chromium_net_exe.log";
  logging::InitLogging(settings);

  base::ThreadPool::CreateAndStartWithDefaultParams("net");

  base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);

  base::RunLoop run_loop;
  g_main_quit_closure = run_loop.QuitClosure();

  g_main_task_runner = message_loop.task_runner();

  g_network_thread = std::make_unique<base::Thread>("network");
  base::Thread::Options options;
  options.message_loop_type = base::MessageLoop::TYPE_IO;
  g_network_thread->StartWithOptions(options);
  g_network_thread->task_runner()->PostTask(
      FROM_HERE, base::BindOnce(InitUrlRequestContextOnNetworkThread));

  run_loop.Run();

  g_network_thread.reset();
  g_main_task_runner = nullptr;

  return 0;
}

URLRequestContext需要运行在专有的网络线程里。因此我们创建一个类型为TYPE_IO的 network 线程。

URLRequestContext类里面的逻辑比较简单,它通过成员变量存放各种网络组件的指针。但是成员变量比较多,创建初始化比较复杂,因此我们通常借助URLRequestContextBuilder类来创建URLRequestContext。通过URLRequestContextBuilder的接口可以配置URLRequestContext所需要的网络组件。在InitUrlRequestContextOnNetworkThread函数里,即使我们没有创建任何网络组件传递给URLRequestContextBuilder,但是在URLRequestContextBuilder::Build里面,它也会自动创建一些基础的网络组件,比如BasicNetworkDelegate,让网络栈可以正常的运作起来。

对象生命周期的管理

URLRequestContext仅仅是存放了各种网络组件的指针,并没有管理网络组件的生命周期。理论上一个网络组件可以在多个URLRequestContext共享使用。

实际的情况是URLRequestContextBuilderURLRequestContextBuilder::Build里面创建的是URLRequestContext的子类ContainerURLRequestContextContainerURLRequestContext它通过成员变量URLRequestContextStorage来管理大部分网络组件的生命周期。如下图所示: Build URLRequestContext

Chromium 中的 URLRequestContext

在 Chromium 70 左右的版本,网络栈是运行在 browser 进程的。后来通过 Mojo 把网络能力改造成Network Service ,网络栈就运行在 Network Service 的 Utility 进程里。

整个网络栈被封装成NetworkService提供给其他浏览器进程使用。NetworkContext负责创建管理URLRequestContext

Chromium browser进程会创建多个NetworkContext:

  • SystemNetworkContextManager,用于跟某个 profile 无关的网络。它没有磁盘存储,因此每次 browser 进程退出之后丢弃所有的 cookie、cache等状态信息。
  • 每个 profile 会创建一个专用 NetworkContext,甚至包括隐身模式的 incognito profile 。
  • 每个 app 都有自己专用的 NetworkContext

参考