Chromium新的进程间通信系统Mojo与Servicification

Chromium m50版本之前所使用的进程间通信系统非常类似MFC/WTL那套的消息映射机制,通过宏来定义和处理消息,具体可以看我之前写的博客的介绍http://blog.gclxry.com/chromium-inter-process-communication/。 如今这套系统已经不再建议使用了,准备用的新的IPC系统Mojo来代替。目前还是处于老的IPC系统和新的IPC系统Mojo共存的状态,逐渐向Mojo迁移,并不再允许增加老的IPC消息。删除老的IPC系统的大致时间是2019年中期,差不多是Chromium m75版本的时候。

老的IPC系统,是基于在两个进程之间的一个大的命名管道(IPC::Channel)实现的。进程间所有的IPC消息都是通过这一个管道根据先进先出的顺序去传递,这隐含着一个副作用:不同的IPC消息之间有先后次序的依赖。这也是用Mojo取代老IPC系统的重要原因之一。

Mojo则为每一个接口创建了一个独立的消息管道,确保不同接口的IPC是独立的。为接口的创建独立的消息管道的代价也并不昂贵,文档里介绍创建消息管道本质上是生成两个随机数并放到一个hash表里面,只需分配少量的堆内存。所以只要你愿意,你可以创建几千个消息管道。

相比之前的IPC系统,Mojo的实现思想给我的感觉是有点类似protobuf,就是IPC通信的接口用IDL(Interface description language)去定义,然后用生成器生成不同语言的绑定代码。Mojo整体的架构如下图所示:

最底层是Mojo EDK(Embedder Development Kit)。每个使用Mojo进行进程间通信的进程被称之为Mojo embedder,这个进程需要链接EDK代码。EDK针对不同的系统实现具体IPC通信机制,比如在类UNIX系统上通过sokcet,Windows系统通过命名管道。Mojo embedder不需要关心Mojo EDK是具体是如何进行进程间通信的。

当EDK被使用的进程初始化后,可以使用一组C语言接口的基础API。通常我们并不直接调用这些API,它是绑定其他语言的基础。我们真正在代码中使用的是生成器针对某种特定语言生成的绑定代码。

在使用Mojo进行进程间通信的时候,就好像代码在调用一个函数接口。发送方主动调用这个函数接口并传入参数,接收方就是具体实现这个函数的功能,并可以通过回调函数返回结果。并且Mojo是跨语言的,IPC的双方不用在意对方是在什么进程里,用什么编程语言实现。

看起来这仅仅是一个简单的IPC系统的升级,实际上我认为Mojo是Chromium最近几年来架构上最大的变革。Chromium通过Mojo在架构上重新设计了一个面向Service的模型,达到代码的复用和解耦的目的。

如下图所示,之前Application层的Chrome依赖Platform层的Content,这里面包括File、Network、UI等模块,而Content又依赖Framework层的Blink渲染网页。

重新设计的架构是Framework与Platform之间的依赖关系完全倒置了。现在是Blink依赖Foundation层的File、Network、UI等services。这种变化就是Mojo带来的,通过Mojo把原来Platform层的File、Network、UI等模块变成Foundation层File、Network、UI等services。

之前是从代码层面去解决跨平台的问题,现在是从架构的层面把基础功能Service化,不仅为了解决跨平台问题,还把Blink从最底层变成一个中间层的模块,网页渲染仅仅是其中一个功能,让Chromium进化的更像一个操作系统。有趣的是Google另外一个操作系统项目Fuchsia的应用程序框架也是基于Mojo之上。

参考:

  • https://chromium.googlesource.com/chromium/src/+/lkgr/mojo
  • https://docs.google.com/document/d/15I7sQyQo6zsqXVNAlVd520tdGaS8FCicZHrN0yRu-oU/edit#heading=h.p37l9e7o0io5

发表评论

电子邮件地址不会被公开。 必填项已用*标注