最近在研讀chromium源碼,通過一段懵懂期,查閱了官網和網上的技術文章,是時候本身總結一下了,首先從Browser進程啓動以及IPC message loop開始吧,這是每一個主線程必須有的一個IPC消息輪訓主體,相似以前的quagga裏thread。chrome
首先來看看chromium的多進程模型:shell
圖1 多進程模型瀏覽器
圖1描述了chromium裏 browser進程,(隱含了zygote進程),render進程以及 WebKit的關係,Webkit是網頁渲染引擎,這裏我就不發散開了。ide
瀏覽器進程有 browser進程,render進程,還有GPU進程,plugin進程等等,首先啓動確定是browser進程。函數
那麼咱們先從browser進程開始, 如下是Browser進程主函數, 在chromium//src/content/browser/browser_main.cc 33行:oop
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()起來就完成了全部的工做。ui
那麼,事情確定沒這麼簡單,BrowserMainRunner就是browser進程執行主體實現,包攬了全部的事情,那麼接着來看 在 chromium//src/content/browser/browser_main_runner.cc 239行。this
1 // static 2 BrowserMainRunner* BrowserMainRunner::Create() { 3 return new BrowserMainRunnerImpl(); 4 }
原來BrowserMainRunner只是定義了接口,是由它的子類BrowserMainRunnerImpl來實現,經過Impl模式來隱藏細節,那麼看main_runner的initialize和Run函數是如何實現的spa
在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函數,來到了消息循環的主體,到此因爲篇幅過長,那麼下面單獨寫一章來看消息處理的具體流程。