#创作者激励# #跟着小白一起学鸿蒙# Binder机制剖析和使用 原创 精华
【本文正在参加2023年第一期优质创作者激励计划】
原理
1. 物理内存中开辟4096字节内存(1m-8k)
2. 物理内存与磁盘内存对应
3. mmu将mmap开辟的物理内存地址转换成虚拟地址
Binder概述
-
什么是Binder
Binder最开始是IPC工具,起源于OpenBinder项目,发展于Android项目,现在已经和入LinuxKernel,目前演变成RPC工具,可以使当前进程调用另一个进程的函数向自身函数一样简单。
OpenBinder is a system for inter-process communication. It was developed at Be Inc. and then Palm, Inc. and was the basis for the Binder framework now used in the Android operating system developed by Google. OpenBinder allows processes to present interfaces which may be called by other threads. Each process maintains a thread pool which may be used to service such requests. OpenBinder takes care of reference counting, recursion back into the original thread, and the inter-process communication itself. On the Linux version of OpenBinder, the communication is achieved using ioctls on a given file descriptor, communicating with a kernel driver. The kernel-side component of the Linux version of OpenBinder was merged into the Linux kernel mainline in kernel version 3.19, which was released on February 8, 2015.
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。从而实现进程间通信
-
功能详细如下:
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) #define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) #define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32) #define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32) #define BINDER_THREAD_EXIT _IOW('b', 8, __s32) #define BINDER_VERSION _IOWR('b', 9, struct binder_version) #define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) #define BINDER_FEATURE_SET _IOWR('b', 30, struct binder_feature_set) #define BINDER_GET_ACCESS_TOKEN _IOWR('b', 31, struct access_token)
-
对应文件如下
. ├── binder_alloc.c ├── binder_alloc.h ├── binder_alloc_selftest.c ├── binder.c ├── binder_trace.h ├── Kconfig └── Makefile
-
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侧依赖
import rpc from "@ohos.rpc" import featureAbility from "@ohos.ability.featureAbility"
Native侧编译依赖
sdk依赖:
external_deps = [ "ipc:ipc_core", ]
此外, IPC/RPC依赖的refbase实现在公共基础库下,请增加对utils的依赖:
external_deps = [ "c_utils: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的跨进程通信。
-
很详细的讲解,在哪有具体实例可以实操一下吗?
感觉这个工具对优化大型程序很有帮助
大佬有实现的样例参考一下