1.chromium框架概述
chromium框架主要描述chromium模块、层次划分,强调各个模块之间如何协作,而不会具体到内部如何工作。
2.视图一
如下图所示的分层模型中,上面两层描述了chromium浏览器,而下面四层描述的是chromium OS。
参考:Software Architecture
Chromium OS 包含3个主要的组件:
- 基于chromium的浏览器和窗口管理器;
- 系统级的软件和用户域服务:内核、驱动程序和连接管理器等
- 固件
Chromium和窗口管理器
窗口管理器负责处理用户与多个窗口的交互。
3.视图二
下图说明了chromium浏览器不同模块的分层。
参考:Content module
一个模块可以从较低层次的模块中包含代码,然而,不能从更高层次的模块中包含代码。这些通过DEPS规则强制检查。较高层次的模块可以实现嵌入的API接口,这样较低层次的模块可以通过这些接口来访问这些模块。Webkit API和content API就是这样的例子。
chrome模块
chrome模块包含浏览器的功能列表如下:
- Extensions
- NaCl
- ChromeFrame
- SpellCheck
- Autofill
- Sync
- Prerendering
- Safe Browsering
- Translate
这些功能可以基于content模块提供的API来实现。
content模块
content模块放在src\content目录下,只包含呈现页面所需的核心代码,包括所有的网络平台功能(如HTML5)和GPU加速。
可以基于该模块来构建一个浏览器,也可以将该模块嵌入到应用中,从而实现应用内嵌的浏览器。
对于这幅图,我有几个疑问,还没有找到解答:
- 为什么这些箭头都是双向的?是否其中部分双向,部分单向更加合理?
- 从上层指向下层的箭头在chromium代码中能否找到例子?
- chrome到webkit的箭头是什么意思?为什么不是chrome到webkit_glue的箭头?
这些问题留待以后继续补充吧。
4.视图三
概念应用分层
参考:How Chromium Displays Web Pages
Webkit
在Safari,Chromium和所有其他基于WebKit的浏览器之间共享的渲染引擎。WebKit Port 是WebKit的一部分,集成了与平台相关的系统服务,如资源加载和图形等。
Glue
将WebKit类型转换为Chromium类型。
Renderer / Render host
这是Chromium的“多进程嵌入层”。它跨越进程边界代理通知和命令。
WebContents
一个可重用的组件,是Content模块的主要类。它很容易被嵌入以允许将HTML多进程渲染到视图中。
Browser
代表浏览器窗口,它包含多个WebContentses。
Tab Helpers
可以附加到WebContents的单个对象。浏览器将各种类型的Tab Helpers附加到对应的WebContents上。
5.视图四
管理Render进程
每一个Render进程有一个全局的RenderProcess对象,用来管理与父进程(Browser进程)之间的通信和维护全局状态。Browser进程为每一个Rneder进程维护了一个RenderProcessHost,用于管理Browser进程的状态和与Render进程之间的通信。Browser进程与Render进程之间使用chromium的IPC系统进行通信。
管理视图
每一个Render进程通过RenderProcess对象管理一个或者多个RenderView对象,而每一个RenderView对象与一个tab页的内容(即一个View)相关联。在Browser进程中,与每一个RenderView对象对应的是RenderViewHost对象。每一个View被分配了一个ID用于区分在同一Render进程中的多个View。这些ID在Render进程中是唯一的,但在Browser进程中却不是,因此,需要通过RenderProcessHost和一个View ID来区分一个View。Browser进程与一个特定的tab页的内容通过这些RenderViewHost对象进行通信,RenderViewHost对象知道如何通过RenderProcessHost给RenderProcess以及RenderView发送消息。
共享Render进程
通常,每一个新窗口或一个tab页会打开一个新的进程。Browser进程会创建一个新的进程并指导这个进程创建一个RenderView。
然而,有时候在多个tab页和窗口之间共享Render进程是必须的或者是合理的。例如,一个web应用通过window.open打开了一个窗口,它希望与这个窗口同步通信,在这种情况下,当我们创建一个新窗口或者是一个tab页,需要重用打开窗口的Render进程。
当Render进程的总数太多或者是用户已经打开一个进程导航到这个域名,此时,我们的策略是将这个新的tab页分配到已经存在的Render进程上。
6.视图五
在chromium中,所有网络访问在Browser进程中进行,这样做的目的一是有利于全局控制,二是能在不同进程间保持cookie等的session状态。
参考:Multi-process Resource Loading
可以看到资源加载是依赖chromium多进程架构设计的,Renderer进程的ResourceDispatcher与Browser进程的ResourceDispatcherHost通信,通过Browser完成资源加载。chromium通过重新实现webkit中的ResourceHandle来实现这一逻辑。
7.视图六
受限于沙盒,Render进程无法直接访问操作系统提供的3D API。为此,我们使用一个单独的进程来访问设备,这个进程就是GPU进程。GPU进程被专门设计用于为处于沙盒中的Render进程以及更加受限的本地客户端“监狱”提供对系统3D API的访问。
参考:GPU Accelerated Compositing in Chrome
- 客户端(运行于Render进程或者NaCl模块的代码),客户端并不是直接调用系统API,而是将调用系统API的命令序列化并放入一个环形缓冲区,这个缓冲区驻留在client与server进程之间共享的内存里。
- 服务器端(GPU进程运行在一个受限程度更低的沙盒中,拥有访问平台3D API的权限。)从共享内存中取出序列化的命令,分析这些命令并执行合适的图形接口调用。
目前,Chrome为每一个浏览器实例启用一个GPU进程,处理来自render进程和插件进程的请求。GPU进程能够在多个命令缓冲区之间复用,而每一个命令缓冲区都与渲染上下文关联。
8.小结
目前对chromium的理解还非常浅薄,所搜罗的chromium框架没有加入自己的理解,基本翻译了chromium的开发文档,随着后续对chromium理解的深入,会继续充实这篇博客。