Android之binder驱动个人学习小结
前言:
Read the 易做图ing Source Code.
这段时间,大概花了两个星期(期间还偷懒了好几天),深入学习了一下Android的Binder驱动。话说上半年在看Mediaplay的源码时,就遇到过很多的IPC,当时也没有深入的去了解这块内容。这次为了对Android有一个系统级别的了解,所以较为深入的学习了一番。主要参考的内容包括:csdn的android 红人老罗,以及手里的一本杨丰盛的Android技术内幕(系统卷),作为主要的学习资料。当然我所小结的内容,也没有他们那么的详细,只是理清了整个思路而已。
注释:
SM:ServiceManager
MS:MediaPlayerService
xxx:指的是某种服务,入HelloService。
一.Binder驱动的整体架构
单从C++层宏观上看来,binder驱动的主要组成部分是:client(客户端),server(服务端),一个Service Manager和binder底层驱动。
整体的框图如下(摘自老罗的图):
其实从图中可以清晰的发现,在Android的应用层中Client和Server所谓的IPC,其实真正的工作均由底层的Binder驱动来完成。也就是说binder驱动可以完成进程间通信,这也是Android特点之一。Service Manager做为一个守护进程,主要来处理客户端的服务请求,管理所有的服务项。
二.binder底层驱动核心内容。
说到底,binder底层的驱动架构和通用的linux驱动没有区别,核心的内容包括binder_init,binder_open,binder_mmap,binder_ioctl.
binder驱动在Android系统中以miscdevice完成设备的注册,作为抽象设备,他没有直接操作硬件,只是完成了内存的拷贝处理。如果要深入理解这块机制,请参考老罗的android之旅。在这里对binder_ioctl做一定的分析:
2.1 驱动核心的操作数据结构:
binder_proc和binder_thread:
每open一个binder驱动(系统允许多个进程打开binder驱动),都会有一个专门的binder_proc管理当前进程的信息,包括进程的ID,当前进程由mmap所映射出的buffer信息,以及当前进程所允许的最大线程量。同时这个binder_proc会加入到系统的全局链表binder_procs中去,方便在不同进程之间可以查找信息。
binder_thread:在当前进程下存在多线程,因此binder驱动使用binder_thread来管理对应的线程信息,主要包括线程所属的binder_proc、当前状态looper以及一个transaction_stack(我的理解是负责着实际进程间通信交互的源头和目的地)。
binder_write_read :
[plain]
struct binder_write_read {
signed long write_size; /* bytes to write */
signed long write_consumed; /* bytes consumed by driver */
unsigned long write_buffer;
signed long read_size; /* bytes to read */
signed long read_consumed; /* bytes consumed by driver */
unsigned long read_buffer;
};
在binder驱动中,以该结构体作为信息封装的中转(可以理解为内核和用户的连接)。在驱动中为根据write_size和read_size的大小来进行处理(见ioctl的解析部分),在write_buffer和read_buffer都代表着用户空间的buffer地址。在write_buffer中,由一个cmd和binder_transaction_data组成,cmd主要告知驱动当前所要处理的内容。
binder_transaction_data:
[plain]
struct binder_transaction_data {
/* The first two are only used for bcTRANSACTION and brTRANSACTION,
* identifying the target and contents of the transaction.
*/
union {
size_t handle; /* target descriptor of command transaction */
void *ptr; /* target descriptor of return transaction */
} target;
void *cookie; /* target object cookie */
unsigned int code; /* transaction command */
/* General information about the transaction. */
unsigned int flags;
pid_t sender_pid;
uid_t sender_euid;
size_t data_size; /* number of bytes of data */
size_t offsets_size; /* number of bytes of offsets */
/* If this transaction is inline, the data immediately
* follows here; otherwise, it ends with a pointer to
* the data buffer.
*/
union {
struct {
/* transaction data */
const void *buffer;
/* offsets from buffer to flat_binder_object structs */
const void *offsets;
} ptr;
uint8_t buf[8];
} data;
};
在这里,buffer和offsets分别代表传输内容的数据量以及Binder实体的偏移量(会遇到多个Binder实体)。
binder_transaction:该结构体主要C/S即请求进程和服务进程的相关信息,方便进程间通信,以及信息的调用
binder_work:理解为binder驱动中,进程所要处理的工作项。
binder_transactionbinder_transactionbinder_transactionbinder_transaction
2.2 binder驱动之ioctl解析:
和常用的ioctl相类似,在这里我们关注BINDER_WRITE_READ命令项的内容。
binder_thread_write和binder_thread_read会根据用户传入的write_size和read_size的有无来进行处理。在这里以Mediaplayservice和ServiceManager的通信来分析,调用的cmd如下:
MS首先传入cmd=BC_TRANSACTION:
调用binder_transaction:
[plain]
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
...else {//client请求service
if (tr->target.handle) {//SM时为target.handle=0
struct binder_ref *ref;
ref = binder_get_ref(proc, tr->target.handle);
if (ref == NULL) {
binder_user_error("binder: %d:%d got "
"transaction to invalid handle\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_invalid_target_handle;
}
target_node = ref->node;
补充:移动开发 , Android ,