問題
構建一個永不崩潰或掛起的渲染引擎幾乎是不可能的,構建一個絕對安全的渲染引擎也幾乎是不可能的。
從某種程度上來說,2006 年左右的網絡瀏覽器狀態與過去單用戶、協作式多任務操作系統的狀況類似。正如在這樣的操作系統中,一個行為不端的應用程序可能導致整個系統崩潰一樣,網絡瀏覽器中一個行為不端的網頁也可能導致整個瀏覽器和所有當前正在運行的標簽頁崩潰。只需一個渲染引擎或插件錯誤,就能導致整個瀏覽器和所有當前正在運行的標簽頁崩潰。
現代操作系統更加健壯,因為它們將應用程序置于彼此隔離的獨立進程中。一個應用程序的崩潰通常不會影響其他應用程序或操作系統的完整性,并且每個用戶對其他用戶數據的訪問也受到限制。Chromium 的架構旨在實現這種更健壯的設計。
架構概述
Chromium 使用多個進程來保護整個應用程序免受渲染引擎或其他組件中的錯誤和故障的影響。它還限制每個渲染引擎進程對其他進程以及系統其余部分的訪問。從某種程度上來說,這為網頁瀏覽帶來了內存保護和訪問控制為操作系統帶來的好處。
我們將運行 UI 并管理渲染器和其他進程的主進程稱為“瀏覽器進程”或“瀏覽器”。同樣,處理 Web 內容的進程稱為“渲染器進程”或“渲染器”。渲染器使用Blink開源布局引擎來解釋和布局 HTML。
從圖中可以看到:一個渲染進程可能有多個RenderView視圖,對應瀏覽器進程中的RenderViewHost(在灰色陰影區域中標識)。兩者以瀏覽器進程中的I/O線程為橋梁,通過IPC通信。這種結構為一個渲染進程對應的RenderView創建子RenderView提供了可能,例如在cef中,創建子窗體。如果主窗體的標簽頁關閉了,子窗體也要關閉。
管理渲染器進程
每個渲染器進程都有一個全局RenderProcess對象,用于管理與父瀏覽器進程的通信并維護全局狀態。瀏覽器RenderProcessHost為每個渲染器進程維護一個對應的對象,用于管理瀏覽器狀態以及與渲染器的通信。瀏覽器和渲染器使用 Mojo或 Chromium 的傳統 IPC 系統進行通信。
管理框架和文檔
每個渲染器進程都有一個或多個RenderFrame對象,這些對象對應于包含內容的文檔所在的框架。RenderFrameHost瀏覽器進程中的相應對象管理與該文檔相關的狀態。每個對象都 RenderFrame被賦予一個路由 ID,用于區分同一渲染器中的多個文檔或框架。這些 ID 在一個渲染器內部是唯一的,但在瀏覽器內部則不同,因此識別一個框架需要同時擁有一個RenderProcessHost和路由 ID。從瀏覽器到渲染器中特定文檔的通信是通過這些RenderFrameHost 對象完成的,這些對象知道如何通過 Mojo 或傳統的進程間通信 (IPC) 發送消息。
組件和接口
在渲染器進程中:
- 處理RenderProcessMojo 設置以及瀏覽器中相應的舊式 IPC RenderProcessHost。每個渲染器進程只有一個 RenderProcess對象。
- 該RenderFrame對象與瀏覽器進程中的對應對象 RenderFrameHost(通過 Mojo)以及 Blink 層進行通信。該對象表示選項卡或子框架中一個 Web 文檔的內容。
在瀏覽器進程中:
- 該Browser對象代表頂級瀏覽器窗口。
- 該RenderProcessHost對象表示單個瀏覽器 ? 渲染器 IPC 連接的瀏覽器端。RenderProcessHost每個渲染器進程在瀏覽器進程中都有一個對應的對象。
- 該RenderFrameHost對象封裝了與的通信 RenderFrame,RenderWidgetHost處理瀏覽器中的輸入和繪畫對于RenderWidget的。
有關此嵌入如何工作的更多詳細信息,請參閱Chromium 如何顯示網頁設計文檔。(這個單獨起一篇文章)
共享渲染器進程
通常,每個新窗口或標簽頁都會在一個新進程中打開。瀏覽器會生成一個新進程,并指示其創建一個單獨的RenderFrame,這可能會在頁面中創建更多 iframe(可能在不同的進程中)。
有時,在標簽頁或窗口之間共享渲染器進程是必要的或理想的。例如,一個 Web 應用可以用來window.open創建另一個窗口,而新文檔如果屬于同一源,則必須共享同一個進程。如果進程總數過大,Chromium 也有一些策略可以將新標簽頁分配給現有進程。這些注意事項和策略在“進程模型”中進行了描述。
檢測崩潰或行為異常的渲染器
每個與瀏覽器進程的 Mojo 或 IPC 連接都會監視進程句柄。如果這些句柄收到信號,則表示渲染器進程已崩潰,受影響的標簽頁和框架會收到崩潰通知。Chromium 會顯示“糟糕的標簽頁”或“糟糕的框架”圖像,通知用戶渲染器已崩潰。您可以通過點擊“重新加載”按鈕或啟動新的導航來重新加載頁面。當這種情況發生時,Chromium 會注意到渲染器進程已不存在,并創建一個新的渲染器進程。
渲染器沙盒化
由于渲染器在單獨的進程中運行,我們可以通過