Mojo IPC 是 Chromium 的底层进程间通信(IPC)框架 。Electron 基于 Chromium 构建,所以 Electron 的 IPC 在底层确实会经过 Chromium 的通信机制,但 Electron 暴露给开发者的是
ipcMain/ipcRenderer这样的高层 JavaScript API,而 Mojo 是 C++ 层面的底层基础设施。
一、Mojo IPC 是什么
Mojo 是 Chromium 团队开发的跨平台 IPC 框架,用于替代 Chromium 早期基于 C++ 宏实现的 Legacy IPC 系统。
Chromium 采用多进程架构(Browser 进程、Renderer 进程、GPU 进程、Utility 进程等),这些进程之间需要大量通信。Mojo 就是支撑这种通信的"神经系统"。
为什么需要 Mojo?
Chromium 团队希望将浏览器拆分为更多、更小的独立服务,同时解决以下问题:
- 服务解耦:让各个组件可以独立演进,减少编译时依赖
- 安全隔离:不同权限的进程通过严格定义的接口通信
- 性能提升:Mojo 比旧版 IPC 快约 3 倍,上下文切换减少约 1/3
- 类型安全:通过接口定义语言(IDL)生成强类型绑定,避免旧 IPC 中常见的消息格式错误
二、Mojo 的核心架构
Mojo 是一个分层架构,从下往上大致分为:
| 层级 | 职责 |
|---|---|
| Mojo Core | 最底层,负责建立 IPC 网络、消息路由、跨平台抽象(Windows 命名管道、Unix Domain Socket 等) |
| System API | 对 Core 的轻量封装,提供 C API |
| Language Bindings | 高层语言绑定,Chromium 主要使用 C++ Bindings,也支持 Java、JavaScript |
核心概念
| 概念 | 说明 |
|---|---|
| Mojom 文件 | 接口定义文件(IDL),用类似 C++ 的语法描述进程间可调用的接口和方法。编译时生成对应语言的绑定代码。 |
| Message Pipe | 消息管道,一对端点(Endpoint)。管道一端发送的消息,另一端按顺序接收。管道端点可以通过其他管道传递给任意进程。 |
| Remote | 接口的调用端,用于向远端发送消息(类似 RPC 的客户端 Stub)。 |
| Receiver | 接口的实现端,用于接收并处理 Remote 发来的消息(类似 RPC 的服务端 Stub)。 |
| PendingRemote / PendingReceiver | 类型安全的"待连接"容器,持有管道的一端但尚未绑定到具体实现,常用于跨进程传递接口能力。 |
| AssociatedRemote / AssociatedReceiver | 在单个 Message Pipe 上复用多个接口,同时保证消息顺序(兼容旧 Legacy IPC 的排序语义)。 |
工作流程:
- 开发者在
.mojom文件中定义接口(例如interface DatabaseService { void Query(string sql) => (array<Row> results); }) - 编译时,Mojo 绑定生成器自动生成 C++ 的 Remote/Receiver 类
- Browser 进程实现
DatabaseService并绑定到 Receiver - Renderer 进程通过 Remote 调用
Query(),Mojo 自动完成序列化、跨进程传输、反序列化和回调
三、Mojo 与 Electron IPC 的关系
Electron IPC 的本质
Electron 的 ipcMain / ipcRenderer 模块是 Electron 团队在 Chromium 之上封装出的 JavaScript API。
当 Electron 的 Renderer 进程调用 ipcRenderer.invoke('dialog:openFile') 时,底层路径大致是:
Renderer JS → V8 → Chromium Renderer C++ → [Mojo IPC] → Chromium Browser C++ → Electron C++ 绑定 → Node.js → 你的 ipcMain.handle() 回调
也就是说,Mojo 在底层承担了实际的跨进程消息传输,但 Electron 开发者完全不需要直接接触 Mojo。
关键区别
| 维度 | Mojo (Chromium 底层) | Electron IPC (应用层) |
|---|---|---|
| 使用语言 | C++(也支持 Java/JS 绑定) | JavaScript / TypeScript |
| 接口定义 | .mojom 文件,编译期生成强类型绑定 |
字符串通道名(如 'dialog:openFile'),运行时约定 |
| 类型安全 | 强类型,参数和返回值在编译期检查 | 弱类型,参数是任意对象,错误只能在运行时发现 |
| 使用方 | Chromium 内部开发、浏览器内核定制 | Electron 应用开发者 |
| 能力范围 | 任意进程间通信(Browser↔Renderer↔GPU↔Utility↔Network Service) | 主要是 Main 进程 ↔ Renderer 进程 |
一个形象的区分
- Mojo 是 Chromium 的"内部血管系统",负责所有进程间的消息传递,包括浏览器自己都不暴露给网页开发者的部分。
- Electron IPC 是 Electron 在血管系统上搭的一座"桥",只连接 Main 进程和 Renderer 进程,并且用 JavaScript 友好的方式暴露出来。
四、Mojo 的安全设计
Mojo 在 Chromium 安全模型中扮演关键角色。Chromium 官方安全文档明确指出:
- Browser 进程是最受信任的,必须对所有来自低权限进程的输入保持最大怀疑
- Renderer 和 ARC++ 进程是最不可信的,它们运行在沙箱中
- 消息处理程序不能假设偏移量有效、计算不会溢出------所有来自 Renderer 的数据都应视为恶意输入
Mojo 的设计支持这种安全模型:
- 能力(Capability)由特权进程持有和分发
- 非特权进程只能请求能力,不能绕过权限直接访问资源
- 接口的强类型定义减少了因消息格式错误导致的安全漏洞
2025 年甚至出现过针对 Mojo 的沙箱绕过漏洞(CVE-2025-2783),说明 Mojo 作为安全边界的重要性。
五、总结
| 问题 | 答案 |
|---|---|
| Mojo 是 Electron 的通信库吗? | 不是。Mojo 是 Chromium 的底层 C++ IPC 框架。 |
| Electron 的 IPC 和 Mojo 有关系吗? | 有 。Electron 的 ipcMain/ipcRenderer 在底层依赖 Chromium 的 IPC 机制,而 Chromium 的 IPC 目前已主要由 Mojo 承载。 |
| 普通 Electron 开发者需要学 Mojo 吗? | 不需要。除非你打算修改 Electron 源码或深度定制 Chromium 内核。 |
| 什么情况下需要接触 Mojo? | 开发 Chromium 内核、编写 Chromium 扩展(如新的内置服务)、或者给 Electron 提交涉及进程通信的底层 Patch 时。 |