NOTE
- 源码版本:Android 7.1.2。
- 内核版本:android-goldfish-3.4
- 内核下载:
git clone https://aosp.tuna.tsinghua.edu.cn/kernel/goldfish.git
(清华镜像站)
- 以下分析思路均来自老罗的《Android 系统源代码情景分析(修订版)》。
Binder 机制简介
- Linux 内核提供了多种进程间通讯机制:
- Pipe:管道。
- Signal:信号。
- Message:消息队列。
- Share Memory:共享内存。
- Socket:插口。
- Android 虽是基于 Linux 内核而开发的,但并没有采用这些传统通讯机制,而是自己开发了一套新的机制,即
Binder
。
Binder
优势:
- 进程间传输数据时仅执行一次拷贝操作。
- 因此提高了效率,同时节省了空间。
Binder
机制中的关键词:
- OpenBinder:
Binder
机制是在它的基础上实现的。(Wiki:OpenBinder)
- CS 通讯方式:客户端
Client
/ 服务端 Server
。
- Server 进程:提供服务
Service
的进程。
- Client 进程:访问服务的进程。
- Service 组件:同一个
Server
可以运行多个组件向 Client
提供服务,提供服务的组件即 Service
组件。
- Service 代理对象:同一个
Client
可以同时向多个 Server
请求服务,每个请求都对应有一个 Client
组件,这个组件即是 Service
代理对象。
- Binder 线程池:每个
Server
与 Client
进程都会维护一个 Binder
线程池来处理进程间通讯请求,service
的提供与访问是可并发的。
- Binder 驱动程序:向用户空间暴露一个设备文件
/dev/binder
,使应用程序进程可以间接通过它建立通信通道。
- Service Manager 组件:
Service
组件启动,就会将自己注册到一个 Service Manager
中,以便 Client
组件可以找到它。
- 可称为
Binder
机制的上下文管理者。
- 可看做一个特殊的
Service
组件。
- open:系统接口,用于打开
Binder
设备。
- mmap:系统接口,提供内存映射操作。
- ioctl:系统接口,提供内核缓冲区管理操作,可实现读、写功能。
Client
、Service
、Service Manager
与 Binder
关系:
Client
、Service
与 Service Manager
运行在用户空间。
Binder
驱动程序运行在内核空间。
- 系统提供
Service Manager
与 Binder
。
Client
与 Service
由应用程序实现。
- 通过
open
、mmap
、ioctl
与 Binder
设备交互。
Binder 基础数据结构分析
- NOTE:
- 结构体中经常能看到成员变量
debug_id
,它是用来标识 Binder
实体对象身份,帮助调试 Binder
驱动的,下面的分析中这个就忽略掉。
- 数据结构介绍的部分内容比较多,我觉得在这部分,不用一开始就一一理清楚它们的详细用处,只需要大概了解每个结构体的用处就好。等到以后分析实现机制的时候,碰到不太了解的成员变量时再回头来看,这样能理解得比较深刻。
1. binder.c
- 位置:
kernel/goldfish/drivers/staging/android/binder.c
- 该文件中的结构体都是在
Binder
驱动程序内部进行使用的。
1.1 struct binder_work
struct binder_work {
struct list_head entry;
enum {
BINDER_WORK_TRANSACTION = 1,
BINDER_WORK_TRANSACTION_COMPLETE,
BINDER_WORK_NODE,
BINDER_WORK_DEAD_BINDER,
BINDER_WORK_DEAD_BINDER_AND_CLEAR,
BINDER_WORK_CLEAR_DEATH_NOTIFICATION,
} type;
};
binder_work
结构用于描述待处理的工作项。
- 工作项有可能属于一个进程,也可能属于某个线程。
- 成员变量:
entry
:将该结构体嵌入到一个宿主结构中。
type
:描述工作项类型,可判断出该结构嵌入的宿主类型。
1.2 struct binder_node
struct binder_node {
int debug_id;
struct binder_work work;
union {
struct rb_node rb_node;
struct hlist_node dead_node;
};
struct binder_proc *proc;
struct hlist_head refs;
int internal_strong_refs;
int local_weak_refs;
int local_strong_refs;
void __user *ptr;
void __user *cookie;
unsigned has_strong_ref:1;
unsigned pending_strong_ref:1;
unsigned has_weak_ref:1;
unsigned pending_weak_ref:1;
unsigned has_async_transaction:1;
unsigned accept_fds:1;
unsigned min_priority:8;
struct list_head async_todo;
};
binder_node
结构描述一个 Binder
实体对象。
- 每个
Service
组件在驱动中都对应一个 Binder
实体,描述它在内核中的状态。
Binder
驱动通过强 (弱)引用计数技术维护实体的生命周期。
- 成员变量:
work
:即工作项。
proc
:指向一个 Binder
实体对象的宿主进程。
rb_node
:宿主进程用红黑树维护内部 Binder
实体,该变量则是红黑树中一个节点。
dead_node
:宿主进程死亡,这个 Binder
实体就通过该变量保存在全局 hash
表中。
ref
:
- 一个
Binder
实体可被多个 Client
组件引用,于是驱动用 binder_ref
结构描述这些引用关系。
- 将引用同一个
Binder
实体的所有引用保存在 hash
表中。
- 该成员变量用于描述这个
hash
表。
- 驱动通过它可知哪些
Client
组件引用了同一 Binder
实体。
internal_strong_refs
&& local_strong_refs
:描述强引用计数。
local_weak_refs
:描述弱引用计数。
has_strong_ref
&& has_weak_ref
:
- 一个
Binder
实体请求一个 Service
执行某一操作,则增加该 Service
组件的强(弱)引用计数。
- 相应地,
Binder
实体将它的这两个变量置为 1
。
pending_strong_ref
&& pending_weak_ref
:
- 为
1
时,表明正处于 Binder
实体向 Service
组件请求改变引用计数的过程。
- 为
0
时,表明上述过程结束。
ptr
&& cookie
:指向用户空间地址。
ptr
指向 Service
组件内部引用计数对象(weakref_impl 类型)地址。
cookie
指向该 Service
组件地址。
has_async_transaction
:描述 Binder
实体是否正在处理异步事务。(1 为是, 0 为否)
async_todo
:
- 异步事务队列。
- 异步事务优先级低于同步,表现为同同一时刻,一个
Binder
实体所有异步事务至多处理一个,其余等待。而同步事务无限制。
min_priority
:处理来自 Client
的请求时,所要求的处理线程(Server
中的一个线程)应具备的最小线程优先级。
accept_fds
:表示是否可接收包含文件描述符的通讯数据(1 可以,0 不可)。
1.3 struct binder_ref_death
struct binder_ref_death {
struct binder_work work;
void __user *cookie;
};
binder_ref_death
用来描述一个 Service
组件的死亡接收通知:
Service
组件所在进程可能会意外崩溃。
Client
进程需要在引用的 Service
组件死亡时得到通知,以便做出相应处理。
- 驱动决定向
Client
发送组件死亡通知时,将该结构体封装成一个工作项,并设置相应 work
值,再加入到 Client
的 todo
队列中等待处理。
- 成员变量:
work
:标志一个具体的死亡通知类型。
cookie
:保存负责接收死亡通知的对象地址。
1.4 struct binder_ref
struct binder_ref {
int debug_id;
struct rb_node rb_node_desc;
struct rb_node rb_node_node;
struct hlist_node node_entry;