轉自:Chromium學習筆記:程序啟動入口分析(Windows)
本篇筆記跟蹤記錄了Chromium的啟動過程,主要關注 Browser 進程和 Renderer 進程。根據 Chromium 項目的分層設計,我們把 Content API 稱作為 Content 層,而把調用 Content API 實現瀏覽器程序的部分稱作為 Embedder 層。在項目中,Embedder 層有 chrome、content_shell 等多種實現。
1、main() 函數
Chromium的main函數在 chrome\app\chrome_exe_main_win.cc,具體如下:
// chrome\app\chrome_exe_main_win.cc |
在main函數中,最重要的一步,就是 int rc = loader->Launch(instance, exe_entry_point_ticks); 載入 chrome.dll運行。
2、載入 chrome.dll
在這里首先調用了 MakeMainDllLoader() 函數,這是一個靜態函數,在chrome\app\main_dll_loader.cc 中,內容如下:
// chrome\app\main_dll_loader.cc |
函數創建並返回一個 ChromiumDllLoader,緊接着再調用它的 Launch 函數,內容如下:
// chrome\app\main_dll_loader.cc |
這里完成了 chrome.dll 的載入,並且執行里面的 ChromeMain 函數。
3、ChromeMain() 函數
ChromeMain 函數負責 Embedder 層的實現類創建,並傳遞給 Content 層,定義在 chrome\app\chrome_main.cc 中,內容如下:
// chrome\app\chrome_main.cc |
在ChromeMain中,最終執行到了 content::ContentMain 這個函數。
4、content::ContentMain() 函數
代碼執行到這里,進入了 Content 層,並且傳入參數 content::ContentMainParams 類型的參數 params,它是由 Embedder 層傳遞過來的重要參數,里面包含了 Embedder 層的具體實現信息,此結構體在 content\public\app\content_main.h 中定義如下:
// content\public\app\content_main.h |
其中有一個重要的成員變量 delegate,其類型為 content::ContentMainDelegate,它在 content\public\app\content_main_delegate.cc 中定義如下:
// content\public\app\content_main_delegate.cc |
可以看到,這里定義了一系列與啟動相關的操作,並且通過幾個 CreateXXX 的函數,獲取 ContentBrowserClient、ContentRendererClient 等接口具體的實現,這也是 content API 的巧妙設計,通過這種方式,將瀏覽器的實現放入了 content 中。
繼續往下看,content::ContentMain() 中調用了 content\app\content_main.cc 中的 service_manager::Main():
// content\app\content_main.cc |
在這里,使用一個 content::ContentServiceManagerMainDelegate 對象來構建了 main_params,並傳入了 service_manager::Main()。
5、service_manager::Main 函數
service_manager::Main 函數位於 services\service_manager\embedder\main.cc,接收一個 MainParams 類型的參數,具體如下:
// services\service_manager\embedder\main.cc |
這里截取的代碼比較長,也非常重要,我們主要關注這四個部分:
- 根據傳入的
delegate和command_line決定進程的類型 - 運行環境的初始化,比如
CreateATLModuleIfNeeded,SetupCRT並用is_initialized來防止重復執行 - 通過傳入的
delegate進行程序的初始化操作,delegate->Initialize(init_params) - 根據進程類型啟動相應的工作
這里的 delegate 類型為 service_manager::MainDelegate*,是在 services/service_manager/embedder/main_delegate.h 中定義的抽象類,在這里我們主要關注它的 Initialize、RunEmbedderProcess 和 ShutDownEmbedderProcess,其中 Initialize 為被聲明為純虛函數,RunEmbedderProcess 和 ShutDownEmbedderProcess 又是什么都不做的,代碼如下:
// services/service_manager/embedder/main_delegate.h |
// services/service_manager/embedder/main_delegate.cc |
回到 service_manager::Main(),我們看到第一句 MainDelegate* delegate = params.delegate; 中的 params.delegate 就是前面在 content::ContentMain 中構建 main_params 所使用的 content::ContentServiceManagerMainDelegate 對象,因此,上述的三個函數 Initialize、RunEmbedderProcess、ShutDownEmbedderProcess 是由 ContentServiceManagerMainDelegate 來最終實現的,來看代碼:
// content\app\content_service_manager_main_delegate.cc |
在這三個函數的定義中,都使用了 content_main_runner_ 這個成員變量來具體執行,它的定義為 std::unique_ptr<ContentMainRunnerImpl>。
6、整個程序的Runner,content::ContentMainRunnerImpl
這個 content::ContentMainRunnerImpl 是 content::ContentMainRunner 接口的一個實現,先來看接口的聲明:
// content\app\content_main_runner_impl.h |
再來看實現類的代碼:
// content\app\content_main_runner_impl.h |
7、ContentMainRunner::Initialize() 函數
先來看 Initialize 函數:
// content\app\content_main_runner_impl.cc |
大致看一下,在這個 Initialize 中,主要是根據 command_line 啟動了相應的 sandbox service,並在啟動前后都觸發了 delegate_->PreSandboxStartup() 和 delegate_->SandboxInitialized(process_type),這個 delegate_ 來自於傳入的 content::ContentMainParams 結構體,這個結構體是在 chrome_main.cc 中調用 content::ContentMain(params) 時所創建,所以這個 delegate_ 正是前面所提到的巧妙設計中,繼承自 content::ContentMainDelegate 的 ChromeMainDelegate 對象,通過這一系列的調用,content 層就把創建 sandbox service 前后的事件觸發了出來,具體實現者只要在 ChromeMainDelegate 中填充這兩個時間點要做的事即可。
8、進程入口,ContentMainRunner::Run() 函數
再來看 Run 函數:
// // content\app\content_main_runner_impl.cc |
此處先判斷 process_type 是否為空,為空則代表當前執行的是默認進程(一般情況下為 Browser 進程),則調用 RunServiceManager(),否則調用 RunOtherNamedProcessTypeMain 根據process_type 來執行相應的進程。先來看 RunServiceManager:
// content\app\content_main_runner_impl.cc |
同樣,這里通過 delegate_ 做了一些操作之后,最后調用了 RunBrowserProcessMain() 函數,內容如下:
// content\app\content_main_runner_impl.cc |
非常簡單明了,首先通過 delegate->RunProcess 把執行默認進程的優先權交由 Embedder 層,如果 Embedder 層成功執行了進程並最終返回了成功標志(exit_code >= 0),那么就退出函數;如果 Embedder 層對默認進程沒有定義,就繼續執行 content::BrowserMain,由此,Browser 進程開始執行。
再來看 RunOtherNamedProcessTypeMain 函數:
// content\app\content_main_runner_impl.cc |
先建立了一個進程類型和入口函數指針的對應數組,再根據進程類型去具體執行,執行的過程與 Browser 進程一樣,先通過 delegate->RunProcess 交由 Embedder 層處理,如果未處理再調用默認的進程入口函數,可以看到分別提供了 UtilityMain、RendererMain、GpuMain 這三個進程的入口,其中 RendererMain 則是我們關注的 Renderer 進程的入口函數,Renderer 進程從此處開始執行。最后一句,如果進程類型不在以上范圍內,則交由 Embedder 去處理。
9、程序結束
void ContentMainRunnerImpl::Shutdown() { |
首先通過 delegate_->ProcessExiting(process_type) 通知 Embedder 層處理,然后做了一些善后釋放的工作,最后將 is_shutdown_ 標記置為 true。
10、總結
前面分析了這么多,其實結合類圖來看一下還是很簡單明了的,主要起到作用的就是圖中標紅的三個,service_manager::Main 通過 content::ContentServiceManagerMainDelegate 的實例調用了 content::ContentMainRunnerImpl 實例中的 Initialize()、Run()、Shutdown() 函數,而在這個Runner中,又通過 content::ContentMainDelegate 接口指針調用到了由 Embedder 層創建的 ChromeMainDelegate 實例中的函數,由此完成了程序的啟動以及 Content 層對 Embedder 的交互。
