Chromium 命名规范

Chromium 代码中的文件数不胜数,读懂文件名可以帮我们快速定位某个文件的用途。好的文件命名方式应该是自解释的,能够实现 “望文生义” 的效果。不过 Chromium 只对代码风格做了指引,并未对名称的遣词做统一规定,所以文件的命名更多是所在目录的约定俗成,受 Owner 的文化背景影响,比如有 Mac 或 iOS 开发背景的 Owner 更有可能将一个类的回调对象命名为 Delegate,而非此背景下的开发者则有可能命名为 Client。

*_{platform}.{ext}

Chromium 代码支持多个平台,由于各个平台有不同的系统 API ,通常需要将这些 API 进行封装,并只在对应的平台上进行编译。 Chromium 在文件名层面区分不同的平台的方式是命名为 *_{platform}.{ext} ,例如 ,该文件就只在 android 平台进行编译。Chromium 的两个编译系统, gyp 原生支持在编译时过滤非对应平台的源文件, gn 则需要手动声明 sources_assignment_filter 才能过滤。

目前 Chromium 常用的的平台标识符如下:

  • android
  • chromeos
  • freebsd
  • fuchsia
  • ios
  • linux
  • mac
  • openbsd
  • posix
  • win

其中 fuchsia 是 Google 最新开发的操作系统,能够同时支持 PC 和嵌入式设备。

*_impl.{ext}

Chromium 代码中随处可见 *_impl.{ext} 文件,涵义并不完全相同。

cc/ 目录下的部分 *_impl.{ext} 文件表示该类运行在 impl-side painting 的 impl 线程,比如 cc/trees/layer_tree_host_impl.h。

除此之外的 {clazz}_impl.{ext} 文件基本上都是抽象接口 Clazz 类的具体实现类。

web_*_impl.{ext} 通常表示该类是 WebKit 的平台实现(PlatformImpl),比如 content/child/web_url_loader_impl.h 即为 WebKit 的 WebURLLoader 在 Chromium 平台下的实现。

定义抽象接口类与具体实现 Impl 类的方法做到了接口与实现的分离,保证了接口类的相对稳定,也对上层模块隐藏了实现细节;同时抽象接口类允许我们实现 Mock 类,方便进行单元测试,特别是考虑到 content/ 目录下很多类都需要进行 IPC 通信,初始化、建立管道等操作相对於单元测试来说太过于繁琐。

*_host.{ext}

Host 在 Chromium 代码中的语义也不尽相同,在 Chromium 代码中有一类 *_host.{ext} 文件标识了多进程架构下的通信关系,通常总是有一个 {clazz}.{ext} 文件与 {clazz}_host.{ext} 对应,比如 content/public/browser/render_view_host.h 与 content/public/renderer/render_view.h 。

RenderViewHost 与 RenderView 通过 IPC 消息进行通信,很大程度上可以认为 RenderViewHost 是 RenderView 在 Browser 端的代理(Proxy),几乎所有 Browser 端对 RenderViewHost 的操作都需要通过 IPC 消息传给 RenderView 进行实际操作,而 RenderView 也需要通过 IPC 消息传递到 RenderViewHost 回调和通知 Browser 端的上层。

以下列出了几个使用 Host 这种用法的重要的文件:

  • content/browser/frame_host/render_frame_host_impl.h 与 content/renderer/render_frame_impl.h
  • content/browser/renderer_host/render_view_host_impl.h 与 content/renderer/render_view_impl.h
  • content/browser/loader/resource_dispatcher_host_impl.h 与 content/child/resource_dispatcher.h
  • gpu/ipc/client/gpu_channel_host.h 与 gpu/ipc/service/gpu_channel.h

IPC 消息三剑客

IPC 是 Chromium 多进程架构下进程间通信的机制,通过命名管道(Linux 和 OS X 下是 socketpair)在进程间传递二进制数据,该二进制数据是由用于进程间通信的数据结构序列化而来,所以在 IPC 消息的接收端还要反序列化回来。

  • *_messages.{ext}

*_messages.{ext} 通过 Chromium 提供的一套 IPC 消息生成宏(参见 ipc_message_macros.h)定义 IPC 消息及其参数。我们只需要声明 IPC 消息的类型以及参数列表,对复合型的参数声明其数据结构中需要序列化的字段,上述消息宏会自动帮我们生成 IPC 消息序列化和反序列化的实现。

  • *_traits.{ext}

有些复合型参数,不能简单的通过序列化和反序列化数据结构中的字段来传递数据,而需要做一些额外的操作。 *_traits.{ext} 文件就是用于自定义这类参数的序列化和反序列化实现。

  • *_message_filter.{ext}

IPC 消息的实际 I/O 操作在当前进程的 IO 线程上,监听处理逻辑(IPC::Listener)运行在当前进程的主线程(Browser 端是 UI 线程,Renderer 端是 Renderer 线程)上, MessageFilter 提供了一个机会可以在 IO 线程上直接拦截 IPC 消息,通常用于将拦截到的 IPC 消息转发到非主线程。

*.mojom

mojom 是 mojo 的模板文件,在前一篇 《Chromium代码文化系列之二:目录结构》中我们提到, mojo 类似于 Android 的 AIDL ,提供了跨语言(C++ / Java / JavaScript)的进程间对象(Object)通信机制, mojom 文件也类似于 aidl 文件,会生成进程间通信对象的抽象接口以及其底层的 IPC 实现。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章