HarmonyOS IPC Kit 笔记:我眼里的进程间通信(IPC/RPC)到底在干啥?
HarmonyOS IPC Kit 笔记:我眼里的进程间通信(IPC/RPC)到底在干啥?
鸿蒙第四期活动
这段时间我在把 HarmonyOS 的并发相关内都过一遍:前面看了 TaskPool、Worker、Sendable,这一块是“线程内怎么跑快”;而 IPC Kit 更多是解决“进程之间怎么说话”的问题。正好趁热把我自己理解的内容整理成一篇博客,当作之后写实战代码的铺垫。
1. 先把几个核心名词讲清楚
官方文档里先给了一个小表,其实就是这几个关键词:IPC / RPC / Client / Server / Proxy / Stub。我们直接用自己的话翻译一下。developer.huawei.com+1
- IPC(Inter Process Communication)——设备内的进程间通信
同一台设备上,不同进程之间想互相调用接口、传递一点数据,就要走 IPC。比如:一个“后台播放服务进程”和一个“UI 进程”,一个负责播歌,一个负责画界面。 - RPC(Remote Procedure Call)——设备间的进程间通信
不同设备之间要协同,就轮到 RPC 出场了。比如:手机上一个进程想远程调用平板、音箱、PC 上的某个服务进程,这就是典型 RPC 场景。底层走的是软总线。CSDN+1 - Client(客户端)
发起调用的一方。你可以理解为“用户”或者“调用者”。在代码里,它拿到的是一个 Proxy 对象,通过这个 Proxy 去调用远端的接口。 - Server(服务端)
真正提供服务的一方。里面有具体业务逻辑,比如“计算、读数据库、访问硬件”等。Server 这边有个对应的 Stub,用来接收 Proxy 传过来的请求并回包。 - Proxy(代理)
跑在 Client 进程里,长得和服务端接口一样,但本质是个“壳”。你对 Proxy 调用方法,它会把参数打包成二进制,通过 Binder/软总线发给远端,再把结果拆包给你。 - Stub(桩)
跑在 Server 进程里,是和 Proxy 对应的另一端。它负责:- 接收 Proxy 发来的二进制数据;
- 反序列化成参数;
- 调用真正的业务方法;
- 把结果再打包回去给 Proxy。
一句话总结:Client 只和 Proxy 打交道,Server 只和 Stub 打交道,真正跑远程通信的是 Binder 或软总线。博客园+1
2. IPC & RPC 在 HarmonyOS 里的定位
从系统角度看,IPC 和 RPC 的角色其实非常固定:developer.huawei.com+1
- IPC:Binder 驱动 + 单设备跨进程
- 跑在同一台设备上;
- 底层用 Binder 驱动;
- 适合“后台服务 + 前台 UI”这类经典架构。
- RPC:软总线驱动 + 跨设备跨进程
- 跑在不同设备之间;
- 底层用软总线;
- 适合多端协同:手机 + 平板 + PC + 智能音箱一起玩。
为什么一定要搞这么麻烦?因为每个进程有自己独立的虚拟内存空间,默认是互相不可见的。你没法直接“拿着另一个进程的指针去读写”,那是内存安全灾难。所以系统提供了一套正规的“过道”——也就是 IPC / RPC 通道——让你规规矩矩地传数据、调方法。
3. IPC Kit 的整体架构:从 Client 到 Server 走一圈
我自己理解的 IPC Kit 结构,可以用一个很土的类比:
SAMgr = 总服务大厅
Server = 窗口办事员
Client = 来办事的市民
Proxy = 你手里的号单
Stub = 办事员那边的受理台
结合官方接口,整个流程基本是这样的:CSDN+1
- Server 注册服务(System Ability)
- Server 进程启动后,把自己的能力注册到 System Ability Manager(SAMgr) 里;
- 对外暴露一个 ID(systemAbilityId)和一套接口协议。
- Client 通过“元能力接口”拿到 Proxy
- Client 想用某个服务,会先通过“连接服务接口”(本质就是去 SAMgr 查)拿到一个 Proxy;
- 这一步就是你平时写的:构造
Want→ 调connectAbility/ 相关连接接口 → 在回调里得到 Proxy。developer.huawei.com+1
- Client 调用 Proxy → 底层打包发给 Stub
- Client 这边正常写:
proxy.doSomething(param1, param2); - Proxy 会把方法编号 + 参数,打包进一个
MessageParcel,通过 Binder/软总线往远端丢。
- Client 这边正常写:
- Stub 解包 → 调用真实业务 → 回包
- Server 进程里的 Stub 收到请求;
- 读出方法 code + 参数;
- 调用对应的业务实现;
- 再把结果写进一个回复包发回去。
- Client 在 Proxy 侧拿到结果
- Proxy 收到 reply;
- 反序列化后返回给 Client 本地代码。
所以从上层开发者视角看,其实就两句:
- 我这边拿到的是一个“远程对象”;
- 调它的方法,像本地一样,但实际在对面进程/设备跑。
4. 典型使用场景:什么时候用 IPC,什么时候用 RPC?
4.1 IPC:单设备后台服务
这种场景特别适合 IPC:bbs.songma.com+1
- 媒体播放服务
- 播放逻辑跑在后台 Service(Server);
- UI 进程只是个前端壳(Client);
- 播放 / 暂停 / 进度更新,全靠 IPC 调接口。
- 统一数据服务
- 做一个“数据聚合服务进程”,统一对外暴露“查数据”的接口;
- 其他业务进程全是 Client,通过 IPC 调这个服务拿数据。
- 安全/权限相关服务
- 把高敏感操作放在特权进程里;
- 普通应用想用就走 IPC + 权限校验。
4.2 RPC:多端协同、多设备联动
RPC 的典型画面大概是这样:CSDN+1
- 手机控制家里的智能音箱、电视
- 手机作为 Client,通过 RPC 调用音箱/电视上的服务进程;
- 比如“播放指定歌单”“调整音量”“切换输入源”。
- 文档多端协同编辑
- 手机编辑器 = Client;
- PC/平板上的文档服务 = Server;
- 手机保存操作通过 RPC 发到 PC,那边完成真正的写文件。
- 分布式游戏/白板
- 每个设备上都是一个进程;
- 通过 RPC 同步游戏状态、画笔轨迹等。
5. 开发者视角:ArkTS 里大概怎么用 IPC Kit?
现在 HarmonyOS 提供了一个 @kit.IPCKit 模块,ArkTS 这边主要是走 rpc 模块来做进程间调用。整体步骤可以概括成几步(只说思路,不按官方文档逐句翻译):developer.huawei.com+1
5.1 Client 侧(ArkTS)
- 引入依赖
import { rpc } from '@kit.IPCKit';
import { Want, common } from '@kit.AbilityKit';
- 构造 Want,准备绑定目标 Ability
const want: Want = {
bundleName: 'com.example.demo',
abilityName: 'DemoServiceExtAbility',
// 如果是跨设备,还会带上 networkId
};
- 写 ConnectOptions,拿到 Proxy
let remote: rpc.IRemoteObject | undefined = undefined;
const connect: common.ConnectOptions = {
onConnect(elementName, proxy) {
remote = proxy;
console.log('connect success');
},
onDisconnect(elementName) {
remote = undefined;
},
onFailed(code) {
console.error('connect failed, code = ' + code);
}
};
- 在 UIAbility 里发起连接
this.context.connectAbility(want, connect);
- 通过 sendRequest 发送请求
async function callRemoteAdd(a: number, b: number): Promise<number> {
if (!remote) {
throw new Error('remote not ready');
}
const data = rpc.MessageParcel.create();
const reply = rpc.MessageParcel.create();
const option = new rpc.MessageOption();
data.writeInt(a);
data.writeInt(b);
const RESULT_CODE_ADD = 1;
await remote.sendRequest(RESULT_CODE_ADD, data, reply, option);
return reply.readInt();
}
这里的 RESULT_CODE_ADD 就是你约定好的“方法编号”,服务端会根据这个编号走到对应的业务逻辑。
5.2 Server 侧(简要)
Server 侧一般会:developer.huawei.com+1
- 定义一个接口(可以用 IDL,也可以用自定义协议);
- 写一个继承框架基类的 Stub 类,在里面重写
onRemoteRequest; - 根据收到的
code+data,解析参数、调用真实业务、写回 reply; - 把这个 Stub 注册成 System Ability,让 Client 能查到。
具体代码每个版本会有点差异,这里就不展开了,等后面写“实战篇”的时候再完整走一遍。
6. 那些容易踩坑的“约束与限制”
这一段官方文档写得比较“硬”,我自己理解了一下,用自己的话讲一下:developer.huawei.com+1
6.1 单条消息大小限制:别在 IPC 里硬怼大文件
- 文档里给了一个“单设备跨进程通信时,单次传输的数据量上限”:
- 有的地方写大约 200KB;
- 开发学习手册里给的是大约 1MB。CSDN+1
不管是 200KB 还是 1MB,传递的意思都一样:
IPC/RPC 通道适合传“小消息”,不适合直接传大文件。
如果你要传的是大块数据(比如图片二进制、视频段、长列表),建议用:
- 匿名共享内存 做大块数据;
- IPC/RPC 只传“句柄 + 控制信息”。
这样既不会卡死 Binder,也更符合系统设计。
6.2 匿名 Stub:在 RPC 场景下别指望监听死亡
“不支持在 RPC 中订阅匿名 Stub 对象(没有向 SAMgr 注册的 Stub)的死亡通知。”
翻译成人话:
- 如果你的 Stub 没有对 SAMgr 正式注册(就是“匿名 Stub”),在跨设备 RPC 场景下:
- 你没法对这个 Stub 订阅“死亡通知”;
- 换句话说,一旦远端挂了,你这边想靠死亡回调感知是不行的,只能用其它心跳/超时机制兜底。
6.3 跨设备 Proxy 不能“二次转手”
“指向远端设备 Stub 的 Proxy 对象,不能在本设备内再进行二次跨进程传递。”
这个限制很容易踩坑,比如你可能想这么干:
- 进程 A 通过 RPC 拿到远端设备 X 上某个服务的 Proxy;
- 然后 A 想把这个 Proxy,通过 IPC 传给本机另外一个进程 B,让 B 也能用这个远端服务。
**官方明确说不支持。**所以正确的姿势是:
- 每个需要访问远端服务的本机进程,都自己去连一遍 RPC;
- 不要想着“把 Proxy 当成句柄在设备内到处传”。
6.4 Stage 模型下三方应用的限制(顺带提一句)
开发学习手册里还提到一个现实:当前版本下:CSDN
- 三方应用暂时不能自己实现 ServiceExtensionAbility 做 Server;
- 但三方应用可以作为 Client,通过 Context 去连接系统提供的 ServiceExtensionAbility。
所以目前更常见的姿势是:
- 你写的是一个“客户端应用”,通过 IPC/RPC 调用系统服务 / 系统能力;
- 真正跑在后面的 Server 多半是系统应用或特权进程。
7. 我对 IPC Kit 的一个简单总结
从我目前的学习体验来说,IPC Kit 有几个很明显的特点:
- 理念一点都不陌生:
本质上还是我们熟悉的“Client–Server + Proxy–Stub + Binder/SoftBus”模型,只是 HarmonyOS 把这一套封装得比较完整。 - 统一了“设备内”和“跨设备”的心智模型:
- 设备内:IPC + Binder;
- 跨设备:RPC + 软总线;
上层开发者看的都是“拿 Proxy、发请求、收结果”,习惯之后切换场景很顺滑。
- 需要敬畏几个硬约束:
- 单次传输大小限制,别当成文件传输通道;
- 匿名 Stub 在 RPC 下做不了死亡订阅;
- 跨设备 Proxy 不要互相转手;
- Stage 模型下三方应用目前主要扮演 Client 角色。
- 和并发那一套是互补关系:
- IPC/RPC 解决的是“进程之间怎么说话”;
- TaskPool / Worker / Sendable / ConditionVariable 解决的是“进程内部多线程怎么协作”。
后面做复杂业务时,两块一定是要一起玩的。
更多推荐
所有评论(0)