文档的思路从需求决定设计开始展开Chromium主要设计特点。从来没有复杂的设计,它们都可以转换为简单的描述。期望能从学习中解开Chromium设计要点。
(文章还在完善中......)
需求的分类
Chormium将页面浏览类的应用需求分为两类(参考文中第一段说明: Content Module):
.Web Platform Features
a. 多进程下解析、渲染页面的能力。
b. HTML/HTML5/CSS3
.Application Features (对应于Chrome,即为Chrome Features)
a. Extensions
b. Autofill
c. Pre-render
d. Safe-Browsering
e. Translate
Chromium的架构分工
从Chromium项目来看,负责提供Web Platform Features的Content是其核心,在其上可以建构出一个完整的浏览器应用。上层的调用者被称为Embedder, 是一个应用层,它提供了Application Features。不同的应用,针对各自不同的用户场景,会有不同的需求。除了典型的浏览器,还有其它应用内置的页面浏览功能,如帮助,预览,甚至是游戏等。它们都会有不同的应用类需求(Application Features)。
下面展现了Chromium项目几个典型Embedder,前三个都是Google的产品。
Chromium架构的要点
Chromium架构特征除了多进程外,最明显的就是解决依赖问题,不断的发展高内聚、低耦合的层次和组件,并且使用DEPS进行保障。
以下概括Chromium架构的要点:
1. 层次化设计
目前层次化的设计是演进出来,并非一步到位。主要包括了两个阶段:
i. 第一阶段, 为了最大化的兼容WebKit, 在Chormium自有的业务逻辑与WebKit之间引入一个Glue层,用来隔离WebKit与Chromium自己实现的业务,比如多进程架构。后面改WebKit为Blink,独立演进后,Glue层又改名为Blink Public API。
ii. 第二阶段,当Chromium的业务逻辑越来越多后,为了避免引入不必要的依赖,破坏原本的设计,另外还要为第三方应用提供页面浏览的功能,Chromium将需求分为两类,并将负责Web Platform Features的功能抽离出来成为Content层。(参考Content Module)
下面就是目前Chrome完整的层次架构:
2. 多进程架构
多进程架构是由Content层实现的,它内部就会成为两个进程交互的界面:
RenderWidgetHost/RenderWidget就是分处两个进程(Browser & Renderer)代表,他们之间就是通过IPC连接。
子进程都由Browser进程创建出来,相互间以IPC&Shared memory的方式进行交互。
3. 组件化设计
组件化在四处表现最为明显:
a. Extension
b. Browser Components
它的目标是持续地对Chrome层级的代码(即Chrome Features)进行组件化,其中提取出content层就是它的一项成果。
c. Layered Component (组件化中的模块化)
算是Browser Components中的一种特别类型。这是迫于iOS限制使用第三方的浏览器内核,Chromium为了让Chrome Features使用的各种组件可以兼容iOS, 避免那部分功能的重复开发,从而引入了Layered Component的模式。其基本的思路就是将Component分为不依赖于Content层的Core (content free), 和负责与Content或者iOS下UIWebView交互的Driver。详情请参考: Layered Components Design Document。
d. Blink Componentization
为了优化其内部的依赖关系,不断提炼功能.... 详见: Core/Module Componentization.
但还不止于此,下步配合Blink完全合并到Chromium,其依赖关系还会再进一步变化。详见Blink componentization after Chromium-Blink repository merge。
4. Blink向着微内核发展
以下为Chromium的描述:
If core has too many code and too complex dependencies, it is very difficult to understand and update (including maintaining existing features, fixing bugs, adding new features and so on) core.
Blink的目标不断向着微内核的方向不断内聚,观察到的两个比较大的变化是:
. 借助Blink Platform API,抽离H5特性的实现。
. 借助Slimming Paint,将渲染中的合成事务进一步集中到Content的Chromium Compositor (cc)上处理。
这样Blink负责的都是核心的逻辑控制,排版,输出一些中间结果,再与其它模块协作做进一步的处理。
Chromium Android WebView架构的要点
层次上的差异
基于Content层的核心功能,提供一个替代Android之前使用的WebKit WebView,就是所谓的Chromium Android WebView, 简称CAW。
如下图所示, AOSP WebView是属于Android代码中的一部分,而Chromium Android WebView则属于Chromium项目。
从下至下:
android.webkit.WebView 仍然是基于WebView定义的实现。
WebView Glue是将WebView的实现桥接到Chromium Android WebView之上。这些都是Java的实现。
Chromium Android WebView提供了对Content的封装,兼有了一些Embedder的行为。
Android WebView还集成了部分Browser Components, 比如AutoFill, 甚至是PDF Exporter.
进程及渲染架构上的差异
Chromium Android WebView目标是向外提供一个WebView的能力,符合Android View的标准实现。这些也限制了它只能使用单进程架构,并且对渲染架构上做了变化。
GPU进程变为InProcGpuThread, 而Renderer进程则变为InProcRendererThread. (InProc -> In Process, 表示单进程.)
可见GPU上的变更最为明显,Chromium专为单进程架构做了两个核心的变更:
Compositor
*另外Compositor Main Thread与Impl Thread的交互中引入了SingleThreadProxy,也是为配合这个变更.
GPU
设计上的决策要点
目的是降低开发成本、提高生产力,包括:
a. 开发者对设计和代码的理解要清晰。
b. 降低变更的代价, 更好地支持功能演进及多团队合作。
c. 降低犯错的可能性。
d. 加快编译。
设计上的要点
1. 高内聚,低耦合。简化依赖,同时避免错误的依赖
Blink Componentization是典型的代表. 首先不要出现环形依赖(cyclic dependencies),然后再简化依赖关系。
Chromium特别为此引入了DEPS, 帮助团队进行管理。
2. 避免接口的膨胀
Bloating! Chromium反复强调保持精简的接口,不要轻易的去增加接口, 多使用Chromium提供的扩展机制。详情见:
如何扩展Chromium的各层接口。
3. 传递必要的数据
参照Law of Demeter,也是有利于简化依赖关系,降低耦合。所谓LoD, 就是只和必要的类做必要的交互,这样可以减少相互依赖的类,以及它们对外提供的接口。
4. 不要让一个类做太多事(SRP)
也不要让一个接口函数做太多事情。
5. 明确功能,避免曲解
一个类、一个模块、一个层次的功能职责都必须是要明确的,避免二义性。这是一个设计问题,也是一个管理问题。
6. 中间层 何时需要Wrapper
“任何一个计算机问题都可以引入一个中间层来解决。”
中间层应用很广,Bridge, Wrapper, Adaptter, Glue, Proxy, COM+都在此列。但增加一层的成本也是有的,并不是所有的场景都要增加一层来解决。比如Chromium在Layered Compontents的设计选用的适配方式是增加交互的Driver, 而没有让Content API去实现一个Wrapper进行兼容处理,可能性是有的,但现在不会做。(详见:http://www.chromium.org/developers/design-documents/layered-components-design FAQ:Will there be a wrapper API around the content API and the iOS API?)
这里有一个增加层的决策问题。层的架构设计分离不同的业务实现,降低相互间的依赖,也有利于团队对架构的理解,从而避免一些错误实现。但层的缺点是加长了执行路径,甚至可能出现不必要的数据转换。比如OSI为网络架构定义了7层协议,而真正广泛应用却是4层结构。
或许引入中间层可以解决任何问题,但代价有时是很高的。详细参考关于层的反模式讨论。
7. 面向接口
Content API就是最好的例子。为了封装内部的变化,将上层开发者的负担降低,增加接口层进行隔离。这也是中间层的一种应用。
8. 策略与能力的分离
对于Content而言,blink提供的是能力, 完成核心的业务逻辑,是一个真正的引擎。而Content则负责为其提供上下文环境(提供Blink需要的依赖的扩展能力),并进行业务决策,即做什么。而Content又是Embedder的核心,对外提供HTML页面呈现和GPU渲染的能力,Embedder则负责基于这种能力构建本身的应用。
如同下图这样一层层包裹,里面的模块向上提供能力,上面的模块驱动内部的模块做事。
9. 平衡维护成本
推荐简洁有效的方案。
持续重构
Chromium无论在Blink Componentization, Layered component cookbook, 或者Warden Project,都在体现持续重构的思想。
这是一个开发问题,也是一个管理问题。
当新功能依赖于一个功能时,或者一个功能在累积Bug时,都是重构的好时机。比如Chromium了解到Blink-Chromium合并代码仓库的规划后,已经开始规划重构Content-Blink的接口层设计.详见Blink componentization after Chromium-Blink repository merge.
转载请注明出处: http://blog.csdn.net/horkychen
参考
Blink componentization after the Chromium-Blink repository merge
Browser Components Design Document
Layered Components Cookbook