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函數,來到了消息循環的主體,到此由於篇幅過長,那么下面單獨寫一章來看消息處理的具體流程。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM