原理
Binder概述
- 什么是Binder
Binder最开始是IPC工具,起源于OpenBinder项目,发展于Android项目,现在已经和入LinuxKernel,目前演变成RPC工具,可以使当前进程调用另一个进程的函数向自身函数一样简单。
Binder是解决进程间通讯问题的框架
- Binder能干什么
OpenHarmony里的对应层次就是:
- 驱动:kernel/linux/linux-xxx/drivers/android/binderXXX
- 服务:foundation/communication/ipc
- 框架:各种NAPI里面和对应的服务接口:如foundation/communication/xxx/frameworks/js/napi/xxx和foundation/communication/xxx/services/bluetooth/service/xxx
在OpenHarmony上表现的功能是:
- 提供客户端-服务器(Client-Server)模型,服务请求方(Client)可获取提供服务提供方(Server)的代理 (Proxy),并通过此代理读写数据来实现进程间的数据通信。通常,系统能力(System Ability)Server侧会先注册到系统能力管理者(System Ability Manager,缩写SAMgr)中,SAMgr负责管理这些SA并向Client提供相关的接口。Client要和某个具体的SA通信,必须先从SAMgr中获取该SA的代理,然后使用代理和SA通信。三方应用可以使用FA提供的接口绑定服务提供方的Ability,获取代理,进行通信。
在OpenHarmony里的限制是:
- 单个设备上跨进程通信时,传输的数据量最大约为1MB,过大的数据量请使用匿名共享内存。
- 不支持把跨设备的Proxy对象传递回该Proxy对象所指向的Stub对象所在的设备。
- Binder原理是什么
Binder是C/S架构的进程间通讯机制。特点如下:
- 用户空间运行:Client,Service和Service Manager;内核空间运行:Binder Driver
- Client,Server和Service Manager通过系统调用open,mmap和ioctl来访问设备文件/dev/binder。从而实现进程间通信
- 功能详细如下:
- 对应文件如下
- Binder通信过程介绍
- Service使用 BINDER_SET_CONTEXT_MGR命令通过Ioctl将自己注册成为ServiceMannager
- Client向Binder驱动发起获取服务的请求,Binder驱动通过Client需要获取服务的名称,从ServiceManager中获取对Binder实体的引用,通过获得到的引用就能实现和Server进程的通信
- IPC通信过程介绍
- 首先Binder驱动在内核空间创建一个数据接收缓存区
- 接着在内核空间开辟一块内核缓存区,建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区和接收进程用户空间地址的映射关系
- Client通过系统调用copy_from_user()将数据拷贝到内核中的内核缓存区,由于内核缓存区和Service的用户空间存在内存映射,所以Service进程的用户空间也有了此数据,这就完成一次跨进程通信
角色说明
- Client进程:使用服务的进程
- Server进程:提供服务的进程
- Service Manager进程:管理Service注册与查询(将字符形式的Binder名字转化成Client中对该Binder的引用)
- Binder驱动:虚拟设备驱动,是连接Service进程,Client进程和Service Manager的桥梁,具体作用为:1.传递进程间的数据,通过内存映射。2.实现线程控制:采用Binder的线程池,并由Binder驱动自身进行管理。
- Binder怎么用
JS侧依赖
Native侧编译依赖
sdk依赖:
此外, IPC/RPC依赖的refbase实现在公共基础库下,请增加对utils的依赖:
JS侧实现跨进程通信基本步骤:
获取代理
使用ohos.ability.featureAbility提供的connectAbility方法绑定Ability,在参数里指定要绑定的Ability所在应用的包名、组件名,如果是跨设备的情况,还需要指定所在设备的NetworkId。用户需要在服务端的onConnect方法里返回一个继承自ohos.rpc.RemoteObject的对象,此对象会在其onRemoteMessageRequest方法里接收到请求。
发送请求
客户端在connectAbility参数指定的回调函数接收到代理对象后,使用ohos.rpc模块提供的方法完成RPC通信,其中MessageParcel提供了读写各种类型数据的方法,IRemoteObject提供了发送请求的方法,RemoteObject提供了处理请求的方法onRemoteRequest,用户需要重写。
Native侧实现跨进程通信的基本步骤:
定义接口类
接口类继承IRemoteBroker,定义描述符、业务函数和消息码。
实现服务提供端(Stub)
Stub继承IRemoteStub(Native),除了接口类中未实现方法外,还需要实现AsObject方法及OnRemoteRequest方法。
实现服务请求端(Proxy)
Proxy继承IRemoteProxy(Native),封装业务函数,调用SendRequest将请求发送到Stub。
注册SA
服务提供方所在进程启动后,申请SA的唯一标识,将Stub注册到SAMgr。
通过SA的标识和设备NetworkId,从SAMgr获取Proxy,通过Proxy实现与Stub的跨进程通信。