Binder C/S 模式
Binder 是 Android 的通讯方式,在Android中我们所使用 Activity 、service 等组件都需要和 AMS(system_server)通讯,这种跨进程的通讯都是通过 Binder 完成;
-
机制 binder 是一种进程间通讯的机制
-
驱动 binder 是一个物理设备的驱动
-
应用层 binder 是一个能发起通讯的java 类
-
framework binder 是链接 Client、Server、 Service Manager 和 Binder 驱动程序,形成一套C/S 的通讯架构;
Binder 各个层级之间定义
两个 APP 必须有一个 server 有一个 client
-
BinderProxy
-
BpBinder
-
BBinder
-
IBinder
service 的 bindService 流程图
Binder 基于 AIDL 代理模式流程图
aidl会在gen中自动生成一个同名的 IaidlData.java 接口文件,该接口文件包含一个抽象类stub,
其继承了 android.os.Binder、实现 IaidlData 接口,我们实际需要实现的是Stub抽象类。
asInterface 也会在 aidl 中生成;
CLient端: MainActivity
Server端: Service
Service 的对外 aidl 接口如上面的案例所示
MainActivity 已经通过 BindService 拿到 Service 的 Binder 对象;
Binder 在 c/s 和 Service Manager 之间示意图
由一系列的组件组成,包括 Client、Server、ServiceManager、Binder 驱动。
-
其中 Client、Server、Service Manager 运行在用户空间,Binder 驱动运行在内核空间。
-
其中 Service Manager 和 Binder 驱动由系统提供,而 Client、Server 由应用程序来实现。
-
Client、Server 和 ServiceManager 均是通过系统调用 open、mmap 和 ioctl 来访问设备文件 /dev/binder,从而实现与 Binder 驱动的交互来间接的实现跨进程通信
Binder 的原理
mmap
内存被操作系统划分成两块:用户空间和内核空间,用户空间是用户程序代码运行的地方,内核空间是内核代码运行的地方,为了安全,他们是隔离的,用户程序崩溃了,内核空间不受影响;
Binder IPC 正是基于内存映射(mmap)来实现的, 但是 mmap() 通常是用在有物理介质的文件系统上的。
比如进程中的用户区域是不能直接和物理设备打交道的,如果想要把磁盘上的数据读取到进程的用户区域,需要两次拷贝(磁盘-->内核空间-->用户空间);通常在这种场景下 mmap() 就能发挥作用,通过在物理介质和用户空间之间建立映射,减少数据的拷贝次数,用内存读写取代I/O读写,提高文件读取效率。
而 Binder 并不存在物理介质,因此 Binder 驱动使用 mmap() 并不是为了在物理介质和用户空间之间建立映射,而是用来在内核空间创建数据接收的缓存空间。
IPCThreadState
ProcessState 多个 IPCProcessState Binder 线程池
一次完整的 Binder IPC 通信过程
- 首先 Binder 驱动在内核空间创建一个数据接收缓存区;
- 接着在内核空间开辟一块内核缓存区,建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区和接收进程用户空间地址的映射关系;
- 发送方进程通过系统调用 copyfromuser() 将数据 copy 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。
一次完成的进程间通信必然至少包含两个进程, 通常我们称通信的双方分别为客户端进程(Client) 和服务端进程(Server), 由于进程隔离机制的存在, 通信双方必然需要借助 Binder 来实现.
其他问题
Binder 同步异步传输
-
声明oneway 异步
-
不声明 同步传输
Intent 传输大小 Binder 传输大小
ProcessState
//内存映射空间大小 1M-8k
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
//最大线程数量
#define DEFAULT_MAX_BINDER_THREADS 15
//binder 驱动映射文件
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
#else
const char* kDefaultDriver = "/dev/binder";
#endif
drivers/staging/android/binder.c -> binder_mmap
mmap 时, 将异步的可用空间设置总空间大小的一半 (1024 - 8)/2 = 508