zoukankan      html  css  js  c++  java
  • chromium源码阅读--Browser进程初始化

    最近在研读chromium源码,经过一段懵懂期,查阅了官网和网上的技术文章,是时候自己总结一下了,首先从Browser进程启动以及IPC message loop开始吧,这是每个主线程必须有的一个IPC消息轮训主体,类似之前的quagga里thread。

    首先来看看chromium的多进程模型:

                                                                              图1  多进程模型

    图1描述了chromium里 browser进程,(隐含了zygote进程),render进程以及 WebKit的关系,Webkit是网页渲染引擎,这里我就不发散开了。

    浏览器进程有 browser进程,render进程,还有GPU进程,plugin进程等等,首先启动肯定是browser进程。

    那么我们先从browser进程开始, 以下是Browser进程主函数, 在chromium//src/content/browser/browser_main.cc 33行:

     1 // Main routine for running as the Browser process.
     2 int BrowserMain(const MainFunctionParams& parameters) {
     3   ScopedBrowserMainEvent scoped_browser_main_event;
     4 
     5   base::trace_event::TraceLog::GetInstance()->SetProcessName("Browser");
     6   base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex(
     7       kTraceEventBrowserProcessSortIndex);
     8 
     9   std::unique_ptr<BrowserMainRunner> main_runner(BrowserMainRunner::Create());
    10 
    11   int exit_code = main_runner->Initialize(parameters);
    12   if (exit_code >= 0)
    13     return exit_code;
    14 
    15   exit_code = main_runner->Run();
    16 
    17   main_runner->Shutdown();
    18 
    19   return exit_code;
    20 

    当然,启动browser进程可以有多种方式,比如,shell模式的browser就是以ContentMain来启动的。这个函数很简单,创建了一个BrowserMainRunner对象,并且Run()起来就完成了所有的工作。

    那么,事情肯定没这么简单,BrowserMainRunner就是browser进程执行主体实现,包揽了所有的事情,那么接着来看 在 chromium//src/content/browser/browser_main_runner.cc 239行

    1 // static
    2 BrowserMainRunner* BrowserMainRunner::Create() {
    3   return new BrowserMainRunnerImpl();
    4 }

    原来BrowserMainRunner只是定义了接口,是由它的子类BrowserMainRunnerImpl来实现,通过Impl模式来隐藏细节,那么看main_runner的initialize和Run函数是如何实现的

    chromium//src/content/browser/browser_main_runner.cc 51行

    class BrowserMainRunnerImpl : public BrowserMainRunner {
    
      int Initialize(const MainFunctionParams& parameters) override {
          ......
          const base::TimeTicks start_time_step1 = base::TimeTicks::Now();
    
          SkGraphics::Init();
    
          base::StatisticsRecorder::Initialize();
    
          notification_service_.reset(new NotificationServiceImpl);
          main_loop_.reset(new BrowserMainLoop(parameters));
    
          main_loop_->Init();
    
          main_loop_->EarlyInitialization();
          ......
    
          main_loop_->PreMainMessageLoopStart();
          main_loop_->MainMessageLoopStart();
          main_loop_->PostMainMessageLoopStart();
          ui::InitializeInputMethod();
    
        const base::TimeTicks start_time_step2 = base::TimeTicks::Now();
        main_loop_->CreateStartupTasks();
        int result_code = main_loop_->GetResultCode();
        if (result_code > 0)
          return result_code;
          .....
      }
    
      int Run() override {
        DCHECK(initialization_started_);
        DCHECK(!is_shutdown_);
        main_loop_->RunMainMessageLoopParts();
        return main_loop_->GetResultCode();
      }
    }

     可以看到 main_loop_ 成员接管了所有的工作,那么它的声明是什么:

    1  std::unique_ptr<BrowserMainLoop> main_loop_;

    chromium//src/content/browser/browser_main_loop.h 里给出了 BrowserMainLoop的声明,BrowserMainLoop的初始化顺序如下:

     1 // Quick reference for initialization order:
     2   // Constructor
     3   // Init()
     4   // EarlyInitialization()
     5   // InitializeToolkit()
     6   // PreMainMessageLoopStart()
     7   // MainMessageLoopStart()
     8   //   InitializeMainThread()
     9   // PostMainMessageLoopStart()
    10   // CreateStartupTasks()
    11   //   PreCreateThreads()
    12   //   CreateThreads()
    13   //   BrowserThreadsStarted()
    14   //     InitializeMojo()
    15   //     InitStartupTracingForDuration()
    16   //   PreMainMessageLoopRun()

    这个流程已经在前面的BrowserMainRunnerImpl的实例对象的initialize已经完成,包含了大量信息,这里我就主要看主线程的IPC消息循环的部分,如下声明了IPC消息轮询对象:

    1 // Members initialized in |MainMessageLoopStart()| 
    2   std::unique_ptr<base::MessageLoop> main_message_loop_;

    chromium//src/content/browser/browser_main_loop.cc 710行,MainMessageLoopStart函数负责初始化成员变量main_message_loop_,如果当前进程没有就指向一个base::MessageLoopForUI指针.

     1 void BrowserMainLoop::MainMessageLoopStart() {
     2   // DO NOT add more code here. Use PreMainMessageLoopStart() above or
     3   // PostMainMessageLoopStart() below.
     4 
     5   TRACE_EVENT0("startup", "BrowserMainLoop::MainMessageLoopStart");
     6 
     7   // Create a MessageLoop if one does not already exist for the current thread.
     8   if (!base::MessageLoop::current())
     9     main_message_loop_.reset(new base::MessageLoopForUI);
    10 
    11   InitializeMainThread();
    12 }

    到了这里我们可以看到,base::MessageLoopForUI,顾名思义,是UI类型的IPC消息轮询,嗯,没错,Browser进程负责UI方面的IPC消息接收和转发(routing)。

    接下来,就将这个消息轮询对象加入到主线程当中:

    1 void BrowserMainLoop::InitializeMainThread() {
    2   TRACE_EVENT0("startup", "BrowserMainLoop::InitializeMainThread");
    3   base::PlatformThread::SetName("CrBrowserMain");
    4 
    5   // Register the main thread by instantiating it, but don't call any methods.
    6   main_thread_.reset(
    7       new BrowserThreadImpl(BrowserThread::UI, base::MessageLoop::current()));
    8 }

    初始化完成之后,我们返回之前main_runner_的Run()是执行RunMainMessageLoopParts()函数:

     1 void BrowserMainLoop::RunMainMessageLoopParts() {
     2   // Don't use the TRACE_EVENT0 macro because the tracing infrastructure doesn't
     3   // expect synchronous events around the main loop of a thread.
     4   TRACE_EVENT_ASYNC_BEGIN0("toplevel", "BrowserMain:MESSAGE_LOOP", this);
     5 
     6   bool ran_main_loop = false;
     7   if (parts_)
     8     ran_main_loop = parts_->MainMessageLoopRun(&result_code_);
     9 
    10   if (!ran_main_loop)
    11     MainMessageLoopRun();
    12 
    13   TRACE_EVENT_ASYNC_END0("toplevel", "BrowserMain:MESSAGE_LOOP", this);
    14 }

    这里我们需要分析一下 BrowserMainParts 这个类以及它的子类,因为它开始涉及到平台相关的内容了。

    BrowserMainParts的子类有ChromeBrowserMainParts, ChromeBrowserMainPartsAndroid,ChromeBrowserMainPartsPosix 等等,涉及chrome相关的,都没有重载MainMessageLoopRun,当然也有重载这个函数,比如ShellBrowserMainParts类。

    那么在chromium//src/content/browser/browser_main_loop.cc 1708行

     1 void BrowserMainLoop::MainMessageLoopRun() {
     2 #if defined(OS_ANDROID)
     3   // Android's main message loop is the Java message loop.
     4   NOTREACHED();
     5 #else
     6   DCHECK(base::MessageLoopForUI::IsCurrent());
     7   if (parameters_.ui_task) {
     8     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
     9                                                   *parameters_.ui_task);
    10   }
    11 
    12   base::RunLoop run_loop;
    13   run_loop.Run();
    14 #endif
    15 }

    RunLoop是一个可以处理嵌套IPC消息的辅助类,它里面声明了一个 RunLoop::Delegate类,来协助完成对IPC消息轮询嵌套层级的执行。

    这里简单解释一下消息嵌套,即当前处理的IPC消息过程中有收到了新的IPC消息。RunLoop以一种类似入栈出栈的思路来实现消息嵌套。

    我们接着看RunLoop的声明:

    1   enum class Type {
    2     kDefault,
    3     kNestableTasksAllowed,
    4   };
    5 
    6   RunLoop(Type type = Type::kDefault);

    构造函数:

     1 RunLoop::RunLoop(Type type)
     2     : delegate_(tls_delegate.Get().Get()),
     3       type_(type),
     4       origin_task_runner_(ThreadTaskRunnerHandle::Get()),
     5       weak_factory_(this) {
     6   DCHECK(delegate_) << "A RunLoop::Delegate must be bound to this thread prior "
     7                        "to using RunLoop.";
     8   DCHECK(origin_task_runner_);
     9 
    10   DCHECK(IsNestingAllowedOnCurrentThread() ||
    11          type_ != Type::kNestableTasksAllowed);
    12 }

    默认的话是不支持嵌套的,通过ThreadTaskRunnerHandle::Get()获取当前线程的IPC消息sender,并且偷偷的将从当前线程变量里的tls_delegate来初始化 RunLoop::Delegate delegate_ 成员变量,那么tls_delegate是什么呢?

    在 chromium//src/base/run_loop.cc 73行

     1 // static
     2 RunLoop::Delegate::Client* RunLoop::RegisterDelegateForCurrentThread(
     3     Delegate* delegate) {
     4   // Bind |delegate| to this thread.
     5   DCHECK(!delegate->bound_);
     6   DCHECK_CALLED_ON_VALID_THREAD(delegate->bound_thread_checker_);
     7 
     8   // There can only be one RunLoop::Delegate per thread.
     9   DCHECK(!tls_delegate.Get().Get());
    10   tls_delegate.Get().Set(delegate);
    11   delegate->bound_ = true;
    12 
    13   return &delegate->client_interface_;
    14 }
    函数RegisterDelegateForCurrentThread负责对tls_delegate进行赋值。而这个函数是在MessageLoop的BindToCurrentThread函数里调用的。
     1 void MessageLoop::BindToCurrentThread() {
     2   DCHECK(!pump_);
     3   if (!pump_factory_.is_null())
     4     pump_ = std::move(pump_factory_).Run();
     5   else
     6     pump_ = CreateMessagePumpForType(type_);
     7 
     8   DCHECK(!current()) << "should only have one message loop per thread";
     9   GetTLSMessageLoop()->Set(this);
    10 
    11   incoming_task_queue_->StartScheduling();
    12   unbound_task_runner_->BindToCurrentThread();
    13   unbound_task_runner_ = nullptr;
    14   SetThreadTaskRunnerHandle();
    15   thread_id_ = PlatformThread::CurrentId();
    16 
    17   scoped_set_sequence_local_storage_map_for_current_thread_ = std::make_unique<
    18       internal::ScopedSetSequenceLocalStorageMapForCurrentThread>(
    19       &sequence_local_storage_map_);
    20 
    21   run_loop_client_ = RunLoop::RegisterDelegateForCurrentThread(this);
    22 }
    
    

    到这里,又悄悄的把MessageLoop和RunLoop联系到了一起,RunLoop的delegate_指向一个MessageLoop指针,那么我们接下来可以看一下MessageLoop的声明了。

    1 class BASE_EXPORT MessageLoop : public MessagePump::Delegate,
    2                                 public RunLoop::Delegate {
    3   ......
    4 
    5 }

    好了,可以看到RunLoop的Run函数实际上是调用的MessageLoop的Run函数,来到了消息循环的主体,到此由于篇幅过长,那么下面单独写一章来看消息处理的具体流程。

     
  • 相关阅读:
    bower使用记录
    前端生成二维码
    删除顽固node_modules
    vue初体验:实现一个增删查改成绩单
    H5常用代码:适配方案5
    H5常用代码:适配方案4
    H5常用代码:适配方案3
    ARFA 教堂的第四次洗礼&斜率优化重学
    CSP考前总结&周二晚+周三晚模拟考总结&洛谷11月月赛 III Div.1总结
    T44253 绝美的挣扎 题解
  • 原文地址:https://www.cnblogs.com/danxi/p/7685629.html
Copyright © 2011-2022 走看看