本文主要解析两个关键点:
- ServiceManger 如何成为所有Service的管理进程
- ServiceManager 与 Binder Driver 共享 128K 内存
我们从ServiceManager的 main函数开始(service_manager.c):
int main()
{
struct binder_state *bs;
bs = binder_open(128*1024);
...
binder_become_context_manager(bs);
...
binder_loop(bs, svcmgr_handler);
return 0;
}
从其main函数可以看到,ServiceManager进程主要通过这三个函数的执行,使得其成为 Service的管理进程,我们依次来说;
1.binder_open
我们看下binder_open函数(代码在 /frameworks/native/cmds/servicemanager/binder.c), 这里摘取了函数的主要逻辑:
struct binder_state *binder_open(size_t mapsize)
{
struct binder_state *bs;
struct binder_version vers;
bs = malloc(sizeof(*bs));
...
bs->fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
...
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
goto fail_open;
}
...
bs->mapsize = mapsize;
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
...
return bs;
}
其中 bs 是一个struct:
struct binder_state
{
int fd;
void *mapped;
size_t mapsize;
};
bs->fd : 保存着打开的 binder driver节点 "/dev/binder"对应的文件描述符, 待 ServiceManager 进程与 binder driver通信时,
会使用到这个fd;
bs->mmaped : 保存着 mmap 返回的用户态虚拟地址;
bs->mapsize :128 KB
函数首先调用 malloc 给 bs分配一块内存,这个没什么可说的;
接下来 open 函数会打开 binder driver对应的字符设备节点 "/dev/binder",对于用户态来说,目的就是返回了一个 fd;
而由于 binder driver 注册,而对于这个节点的 open操作,最终经过 open 系统调用后,会调用 binder driver的 binder_open函数,binder driver的 binder_open 函数 (kernel/drivers/android/binder.c):
static int binder_open(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc; //每个要进行binder通信的进程都有一个对应的 binder_proc
...
proc = kzalloc(sizeof(*proc), GFP_KERNEL); //在kernel为调用open的进程分配binder_proc
...
get_task_struct(current);
proc->tsk = current; //设置该 binder_proc的 task指向调用 open的进程
INIT_LIST_HEAD(&proc->todo); //初始化todo list,这个list用来保存将要进行的通信工作
init_waitqueue_head(&proc->wait);//初始化 wait,即正在睡眠的 binder 线程list
proc->default_priority = task_nice(current);//进程优先级
hlist_add_head(&proc->proc_node, &binder_procs);//把 proc添加到binder_procs list中
proc->pid = current->group_leader->pid; //记录当前进程 pid
INIT_LIST_HEAD(&proc->delivered_death); //death list
filp->private_data = proc; //把 proc记录到 file的 private_data
return 0;
}
这里面的操作主要是 创建一个 binder_proc,初始化一些数据,并把 binder_proc保存到service_manager进程打开 "/dev/binder"时,
创建的 filp->private_data中。binder_proc是每个要进行 binder通信都需要的一个数据结构,与进程关系是一对一 ,其保存进程binder通信时使用到的一些数据。
下面我们看一下 binder_proc:
struct binder_proc {
// 进程打开设备文件/dev/binder时,Binder驱动会为它创建一个binder_proc结构体,并将它
// 保存在全局hash列表中,proc_node是该hash列表的节点。
struct hlist_node proc_node;
// 每个使用了Binder机制的进程都有一个Binder线程池,用来处理进程间通信请求。threads以
// 线程ID作为key来组织进程的Binder线程池。进程可以调用ioctl将线程注册到Binder驱动中
// 当没有足够的空闲线程处理进程间通信请求时,驱动可以要求进程注册更多的线程到Binder线程
// 池中
struct rb_root threads;
struct rb_root nodes; // 组织Binder实体对象,它以成员ptr作为key
struct rb_root refs_by_desc; // 组织Binder引用对象,它以成员desc作为key
struct rb_root refs_by_node; // 组织Binder引用对象,它以成员node作为key
int pid; // 指向进程组ID
struct vm_area_struct *vma; // 内核缓冲区的用户空间地址,供应用程序使用
struct mm_struct *vma_vm_mm;
struct task_struct *tsk; // 指向进程任务控制块
struct files_struct *files; // 指向进程打开文件结构体数组
// 一个hash表,保存进程可以延迟执行的工作项,这些延迟工作有三种类型
// BINDER_DEFERRED_PUT_FILES、BINDER_DEFERRED_FLUSH、BINDER_DEFERRED_RELEASE
// 驱动为进程分配内核缓冲区时,会为该缓冲区创建一个文件描述符,进程可以通过该描述符将该内
// 核缓冲区映射到自己的地址空间。当进程不再需要使用Binder机制时,就会通知驱动关闭该文件
// 描述符并释放之前所分配的内核缓冲区。由于这不是一个马上就要完成的操作,因此驱动会创建一
// 个BINDER_DEFERRED_PUT_FILES类型的工作来延迟执行;
// Binder线程池中的空闲Binder线程是睡眠在一个等待队列中的,进程可以通过调用函数flush
// 来唤醒这些线程,以便它们可以检查进程是否有新的工作项需要处理。此时驱动会创建一个
// BINDER_DEFERRED_FLUSH类型的工作项,以便延迟执行唤醒空闲Binder线程的操作;
// 当进程不再使用Binder机制时,会调用函数close关闭文件/dev/binder,此时驱动会释放之
// 前为它分配的资源,由于资源释放是个比较耗时的操作,驱动会创建一个
// BINDER_DEFERRED_RELEASE类型的事务来延迟执行
struct hlist_node deferred_work_node;
int deferred_work; // 描述该延迟工作项的具体类型
void *buffer; // 内核缓冲区的内核空间地址,供驱动程序使用
ptrdiff_t user_buffer_offset; // vma和buffer之间的差值
// buffer指向一块大的内核缓冲区,驱动程序为方便管理,将它划分成若干小块,这些小块的内核缓
// 冲区用binder_buffer描述保存在列表中,按地址从小到大排列。buffers指向该列表的头部。
struct list_head buffers;
struct rb_root free_buffers; // buffers中的小块有的正在使用,被保存在此红黑树
struct rb_root allocated_buffers; // buffers中的空闲小块被保存在此红黑树
size_t free_async_space; // 当前可用的保存异步事务数据的内核缓冲区的大小
struct page **pages; // buffer和vma都是虚拟地址,它们对应的物理页面保存在pages
// 中,这是一个数组,每个元素指向一个物理页面
size_t buffer_size; // 进程调用mmap将它映射到进程地址空间,实际上是请求驱动为它
// 分配一块内核缓冲区,缓冲区大小保存在该成员中
uint32_t buffer_free; // 空闲内核缓冲区的大小
struct list_head todo; // 当进程接收到一个进程间通信请求时,Binder驱动就将该请求封
// 装成一个工作项,并且加入到进程的待处理工作向队列中,该队列
// 使用成员变量todo来描述。
wait_queue_head_t wait; // 线程池中空闲Binder线程会睡眠在由该成员所描述的等待队列中
// 当宿主进程的待处理工作项队列增加新工作项后,驱动会唤醒这
// 些线程,以便处理新的工作项
struct binder_stats stats; // 用来统计进程数据
// 当进程所引用的Service组件死亡时,驱动会向该进程发送一个死亡通知。这个正在发出的通知被
// 封装成一个类型为BINDER_WORK_DEAD_BINDER或BINDER_WORK_DEAD_BINDER_AND_CLEAR
// 的工作项,并保存在由该成员描述的队列中删除
struct list_head delivered_death;
int max_threads; // 驱动程序最多可以主动请求进程注册的线程数
int requested_threads;
int requested_threads_started;
int ready_threads; // 进程当前的空闲Binder线程数
long default_priority; // 进程的优先级,当线程处理一个工作项时,线程优先级可能被
// 设置为宿主进程的优先级
struct dentry *debugfs_entry;
};
总结:用户进程调用open("/dev/binder"),其实做了2个工作:
- 记录一个文件描述符 fd到用户进程,以便后面与 binder driver 通信
- 内核中执行内核的 binder_open 函数,为该用户进程创建一个对应的 binder_proc,以便通信使用
接下来,ServiceManager中的 binder_open函数会依次执行 version校验 和 mmap操作,分到下面两节来说。
2.version校验
对应代码是:
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
goto fail_open;
}
就是从获取一下binder driver中的binder的版本,比较是否与 service manger使用 binder 版本匹配;
主要工作在 binder version的获取,是通过 ioctl来获取的。
ioctl(bs->fd, BINDER_VERSION, &vers);
刚才记录的 bs->fd就是用来做 ioctl通信的,发的命令是 BINDER_VERSION,得到的version记录在 vers中。
ioctl经过系统调用后,会调用到 binder driver的 binder_ioctl 函数,这里只摘录跟本次调用 相关的代码:
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//这个filp就是servicemanager进程打开 "/dev/binder"节点是对应的进程,之前把 proc记录到了其 private_data中
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd); // cmd, BINDER_VERSION
void __user *ubuf = (void __user *)arg;//对应上面的 vers
...
thread = binder_get_thread(proc);//从proc->threads.rb_node中找,找不到则创建一个,并记录
switch (cmd) {
...
case BINDER_VERSION: {
struct binder_version __user *ver = ubuf;
if (size != sizeof(struct binder_version)) {
ret = -EINVAL;
goto err;
}
if (put_user_preempt_disabled(BINDER_CURRENT_PROTOCOL_VERSION,
&ver->protocol_version)) {//把 binder driver version写入到 vers中,这样返回后,Servicemanger中 binder_open函数的局部变量 vers中就有数据了
ret = -EINVAL;
goto err;
}
break;
}
}
ret = 0;
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
return ret; //正常返回
}
完成binder dirver的vers获取,即可进行对比验证。
接下来是: bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
3.binder_mmap
service manager 的 version校验办成后,接下来就是mmap,
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
这个函数主要完成两件事情:
- 把 mmap 128KB 返回的service manager进程的用户空间地址记录到 bs->mmaped
- 在内核调用 binder driver的 binder_mmap函数,为进程在内核空间申请 128K虚拟内存,在用户空间也申请 128K虚拟内存;并先 alloc一个 PAGE的物理内存以便使用,后续需要的的时候,再真正分配物理页面
实际上,kernel空间的 128K 虚拟内存,和用户空间的 128K虚拟内存,在使用时,是会对应到相同的物理内存的。代码如下:
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret;
struct vm_struct *area;
struct binder_proc *proc = filp->private_data;
const char *failure_string;
struct binder_buffer *buffer;
...
if ((vma->vm_end - vma->vm_start) > SZ_4M)
vma->vm_end = vma->vm_start + SZ_4M;//每个进程的binder通信内存最大不能超过4M
...
area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); //分配内核虚拟内存属性
proc->buffer = area->addr; //指向内核虚拟内存起始位置
proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;//记录 offset
proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);//分配虚拟内存用以记录物理页面对应的指针
proc->buffer_size = vma->vm_end - vma->vm_start;//buffer size
vma->vm_ops = &binder_vm_ops;
vma->vm_private_data = proc;
ret = binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma); //分配一个 PAGE 的实际物理页面,并通过vma与用户空间虚拟地址绑定,通过 proc->pages与内核空间虚拟地址绑定起来
buffer = proc->buffer;
INIT_LIST_HEAD(&proc->buffers);
list_add(&buffer->entry, &proc->buffers);
buffer->free = 1;
binder_insert_free_buffer(proc, buffer);
proc->free_async_space = proc->buffer_size / 2;
barrier();
proc->files = get_files_struct(current);
proc->vma = vma;
proc->vma_vm_mm = vma->vm_mm;
return 0;
}
binder_mmap完成后,kernel 128K虚拟内存和 service manger 进程的 128K虚拟内存关系如下:
其实解释了ServiceManger 与 binder driver如何共享的 128K内存;
这样就解释了binder一次内存拷贝的原理:
当一个进程 B 想和 ServiceManger通信时,自己组织好的数据data(用户态的内存地址),调用 binder_ioctl 进入内核态,binder driver找到 service manager记录在内核中的 binder node,取出其 binder_proc, 把 data 内容拷贝到 binder_proc中记录的内核中servicemanger进程对应的128K内存首地址:binder_proc->buffer,当拷贝完成(data已经写入物理内存),由于 service manger进程用户态 128K 虚拟内存对应的也是这段物理内存,所以,此时从 servicemanager进程读取它 128K虚拟内存的数据,访问的物理内存与 kernel中是同一个,已经有data数据了,这就是binder一次拷贝的秘密 。
4.binder_become_context_manager(bs)
在 service_manager.c main函数执行完 binder_open函数后,接下来执行 binder_become_context_manager(bs)函数:
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//这个filp就是servicemanager进程打开 "/dev/binder"节点是对应的进程,之前把 proc记录到了其 private_data中
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd); // cmd, BINDER_VERSION
void __user *ubuf = (void __user *)arg;//这次的arg是0,用不到
...
thread = binder_get_thread(proc);//从proc->threads.rb_node中找,找不到则创建一个,并记录
switch (cmd) {
...
case BINDER_SET_CONTEXT_MGR:
ret = binder_ioctl_set_ctx_mgr(filp);
if (ret)
goto err;
break;
...
}
ret = 0;
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
return ret;
}
接下来调用 binder_ioctl_set_ctx_mgr(filp):
static int binder_ioctl_set_ctx_mgr(struct file *filp)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
kuid_t curr_euid = current_euid();
if (binder_context_mgr_node != NULL) { //如果已经有context mgr,则创建失败
ret = -EBUSY;
goto out;
}
if (uid_valid(binder_context_mgr_uid)) { //检查权限
if (!uid_eq(binder_context_mgr_uid, curr_euid)) {
ret = -EPERM;
goto out;
}
} else {
binder_context_mgr_uid = curr_euid;
}
binder_context_mgr_node = binder_new_node(proc, 0, 0);//创建一个新的 binder node,其中两个0代表binder node的 ptr和 cookie都是 0,proc代表这个node对应的进程
if (binder_context_mgr_node == NULL) {
ret = -ENOMEM;
goto out;
}
binder_context_mgr_node->local_weak_refs++; //记录引用计数
binder_context_mgr_node->local_strong_refs++;
binder_context_mgr_node->has_strong_ref = 1;
binder_context_mgr_node->has_weak_ref = 1;
out:
return ret;
}
看下 binder_new_node:
static struct binder_node *binder_new_node(struct binder_proc *proc,
binder_uintptr_t ptr,
binder_uintptr_t cookie)
{
struct rb_node **p = &proc->nodes.rb_node;
struct rb_node *parent = NULL;
struct binder_node *node;
while (*p) {
parent = *p;
node = rb_entry(parent, struct binder_node, rb_node);
if (ptr < node->ptr)
p = &(*p)->rb_left;
else if (ptr > node->ptr)
p = &(*p)->rb_right;
else
return NULL;
}
node = kzalloc_preempt_disabled(sizeof(*node));
if (node == NULL)
return NULL;
binder_stats_created(BINDER_STAT_NODE);
rb_link_node(&node->rb_node, parent, p);
rb_insert_color(&node->rb_node, &proc->nodes);
node->debug_id = ++binder_last_id;
node->proc = proc;//当前node的proc就是 servce mangager进程对应的binder proc
node->ptr = ptr;
node->cookie = cookie;
node->work.type = BINDER_WORK_NODE;
INIT_LIST_HEAD(&node->work.entry);
INIT_LIST_HEAD(&node->async_todo);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"%d:%d node %d u%016llx c%016llx created\n",
proc->pid, current->pid, node->debug_id,
(u64)node->ptr, (u64)node->cookie);
return node;
}
总结:所以 binder_become_context_manager(bs)这个函数调用使得 内核中 binder driver 创建了一个新的binder node,记录到 binder_context_mgr_node,这个node是唯一的,其记录这个 node对应的进程是 service manger进程。所以 service manger成为所有需要binder通信的Service的管理进程就是这么来的。
5.binder_loop
在 service_manager.c main函数执行完binder_become_context_manager(bs)函数后,就要执行函数:
binder_loop(bs, svcmgr_handler);
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
uint32_t readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
binder_write(bs, readbuf, sizeof(uint32_t));//通知binder driver进入LOOP
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//开始从128K 内存中读取数据,可能block在这
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);//读取到数据后处理数据
if (res == 0) {
ALOGE("binder_loop: unexpected reply?!\n");
break;
}
if (res < 0) {
ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
break;
}
}
}
int binder_write(struct binder_state *bs, void *data, size_t len)
{
struct binder_write_read bwr;
int res;
bwr.write_size = len;
bwr.write_consumed = 0;
bwr.write_buffer = (uintptr_t) data;
bwr.read_size = 0;
bwr.read_consumed = 0;
bwr.read_buffer = 0;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
fprintf(stderr,"binder_write: ioctl failed (%s)\n",
strerror(errno));
}
return res;
}
这里构建了一个binder_write_read 数据 bwr来进行和 driver通话,这里有必要解释以下 bwr:
struct binder_write_read {
signed long write_size; //要写入的数据大小
signed long write_consumed; //写入数据对于buffer的偏移
unsigned long write_buffer; //要写入的数据从write_buffer中获取
signed long read_size; //读取。。
signed long read_consumed;
unsigned long read_buffer; //读取的数据保存到 read_buffer
};
所以 binder_loop函数先通过 binder_write(fd, buffer, 4)组织数据到 bwr,这里 buffer中只存放了一个数据: "BC_ENTER_LOOPER",然后调用 ioctl(fd, BINDER_WRITE_READ, &bwr)与 binder driver通信。
这个 bwr和 buffer都在用户空间。我们先图示化一下要 bwr参数,方便后面解析这个参数:
这里又到了 binder_ioctl,只不过这次的cmd是 BINDER_WRITE_READ:
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//这个filp就是servicemanager进程打开 "/dev/binder"节点是对应的进程,之前把 proc记录到了其 private_data中
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd); // cmd, BINDER_VERSION
void __user *ubuf = (void __user *)arg;//这次arg对应bwr
...
thread = binder_get_thread(proc);//从proc->threads.rb_node中找,找不到则创建一个,并记录
switch (cmd) {
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);//arg原封不动传递过去
if (ret)
goto err;
break;
...
}
ret = 0;
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
return ret;
}
命令 BINDER_WRITE_READ会使得 binder driver调用 binder_ioctl_write_read(filp, cmd, arg, thread);
我么可以看到 arg(也就是上面的 bwr)被原封不动的传递过去了。我们看看binder_ioctl_write_read有没有解析 arg参数:
2625static int binder_ioctl_write_read(struct file *filp,
2626 unsigned int cmd, unsigned long arg,
2627 struct binder_thread *thread)
2628{
2629 int ret = 0;
2630 struct binder_proc *proc = filp->private_data;
2631 unsigned int size = _IOC_SIZE(cmd);//每个cmd对应参数size不同,而只有BINDER_WRITE_READ cmd会走到这个函数,其对应的size是固定的
2632 void __user *ubuf = (void __user *)arg;//arg指向 bwr(用户态地址)
2633 struct binder_write_read bwr;//这里在内核分配一个bwr用来存放传过来的参数
2634
2635 if (size != sizeof(struct binder_write_read)) {
2636 ret = -EINVAL;
2637 goto out;
2638 }
2639 if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//把传过来的bwr数据拷贝到内核中的 bwr中,注意,bwr中write_buffer仍指向用户态的那个 buffer
2640 ret = -EFAULT;
2641 goto out;
2642 }
2643 binder_debug(BINDER_DEBUG_READ_WRITE,
2644 "%d:%d write %lld at %016llx, read %lld at %016llx\n",
2645 proc->pid, thread->pid,
2646 (u64)bwr.write_size, (u64)bwr.write_buffer,
2647 (u64)bwr.read_size, (u64)bwr.read_buffer);
2648
2649 if (bwr.write_size > 0) {//如果 write_size>0,先write
2650 ret = binder_thread_write(proc, thread,
2651 bwr.write_buffer,//指向用户空间buf
2652 bwr.write_size,
2653 &bwr.write_consumed);
2654 trace_binder_write_done(ret);
2655 if (ret < 0) {//write成功时,ret是0;小于0代表失败
2656 bwr.read_consumed = 0;
2657 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
2658 ret = -EFAULT;
2659 goto out;
2660 }
2661 }
2662 if (bwr.read_size > 0) {//如果需要 read,再进行read
2663 ret = binder_thread_read(proc, thread, bwr.read_buffer,
2664 bwr.read_size,
2665 &bwr.read_consumed,
2666 filp->f_flags & O_NONBLOCK);
2667 trace_binder_read_done(ret);
2668 if (!list_empty(&proc->todo))
2669 wake_up_interruptible(&proc->wait);
2670 if (ret < 0) {//read成功时,ret是0;小于0代表失败
2671 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
2672 ret = -EFAULT;
2673 goto out;
2674 }
2675 }
2676 binder_debug(BINDER_DEBUG_READ_WRITE,
2677 "%d:%d wrote %lld of %lld, read return %lld of %lld\n",
2678 proc->pid, thread->pid,
2679 (u64)bwr.write_consumed, (u64)bwr.write_size,
2680 (u64)bwr.read_consumed, (u64)bwr.read_size);
2681 if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {//把read/write结束的数据写回user space的 buffer中
2682 ret = -EFAULT;
2683 goto out;
2684 }
2685out:
2686 return ret;
2687}
1754static int binder_thread_write(struct binder_proc *proc,
1755 struct binder_thread *thread,
1756 binder_uintptr_t binder_buffer, size_t size,
1757 binder_size_t *consumed)
1758{
1759 uint32_t cmd;
1760 void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
1761 void __user *ptr = buffer + *consumed;//ptr指向用户空间buffer位置
1762 void __user *end = buffer + size;
1763
1764 while (ptr < end && thread->return_error == BR_OK) {
1765 if (get_user(cmd, (uint32_t __user *)ptr))//从用户空间buf起始位置读取cmd,我们buf中保存的是:"BC_ENTER_LOOPER"
1766 return -EFAULT;
1767 ptr += sizeof(uint32_t);//ptr向前移动sizeof(cmd)
1768 trace_binder_command(cmd);
1769 if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
1770 binder_stats.bc[_IOC_NR(cmd)]++;
1771 proc->stats.bc[_IOC_NR(cmd)]++;
1772 thread->stats.bc[_IOC_NR(cmd)]++;
1773 }
1774 switch (cmd) {
... //函数较大,只摘取本次相关代码
1961 case BC_ENTER_LOOPER:
1962 binder_debug(BINDER_DEBUG_THREADS,
1963 "%d:%d BC_ENTER_LOOPER\n",
1964 proc->pid, thread->pid);
1965 if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {
1966 thread->looper |= BINDER_LOOPER_STATE_INVALID;
1967 binder_user_error("%d:%d ERROR: BC_ENTER_LOOPER called after BC_REGISTER_LOOPER\n",
1968 proc->pid, thread->pid);
1969 }
1970 thread->looper |= BINDER_LOOPER_STATE_ENTERED;//只是设置了一下当前 binder_thread 的状态
1971 break;
...
2107 default:
2108 pr_err("%d:%d unknown command %d\n",
2109 proc->pid, thread->pid, cmd);
2110 return -EINVAL;
2111 }
2112 *consumed = ptr - buffer;//更新bwr.write_consumed = 4,注意这个bwr是内核中的 bwr
2113 }
2114 return 0;
2115}
所以此时内核中的 bwr数据:
注意,kernel bwr数据是从用户空间拷贝过来的,而这里只把write_consumed 从 0改了4,所以上面就是 kernel bwr现在的数据了。
修改完 write_consumed后,就从 binder_thread_write函数返回到 binder_ioctl_write_read函数,由于当前不需要read,所以会继续走到如下代码:
2681 if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {//把read/write结束的数据写回user space的 buffer中
2682 ret = -EFAULT;
2683 goto out;
2684 }
int binder_write(struct binder_state *bs, void *data, size_t len)
{
struct binder_write_read bwr;
int res;
bwr.write_size = len;
bwr.write_consumed = 0;
bwr.write_buffer = (uintptr_t) data;
bwr.read_size = 0;
bwr.read_consumed = 0;
bwr.read_buffer = 0;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
fprintf(stderr,"binder_write: ioctl failed (%s)\n",
strerror(errno));
}
return res;
}
这里调用完成 ioctl返回后,并没有再使用 bwr了,我们不再关注bwr。但我们知道了 BINDER_WRITE_READ 执行完成后,会回写修改后的 bwr 数据到 user space,那么user space就可以再 ioctl(..., BINDER_WRITE_READ , &bwr)函数返回后,通过 bwr数据得到一些 driver执行的信息,比如就通过刚才那个 bwr.write_consumed 和 bwr.write_size比较,从而判断有没有把数据write完成。
到这里,binder_write函数就返回了,接下来又回到了 service manger的 binder_loop函数:
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
uint32_t readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
binder_write(bs, readbuf, sizeof(uint32_t));//通知binder driver进入LOOP
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//开始从128K 内存中读取数据,可能block在这
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);//读取到数据后处理数据
if (res == 0) {
ALOGE("binder_loop: unexpected reply?!\n");
break;
}
if (res < 0) {
ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
break;
}
}
}
可以看到 binder_write函数返回后,service manger 进程就会进入 for循环,进行反复的读取,解析binder请求的动作了。这里调用 ioctl指令是 BINDER_WRITE_READ ,为什么我么说读取,而没有写入呢?请注意这里的 bwr:
这里同样会走到 binder_ioctl_write_read函数,可以去前面看下,不同的是,这次只会走到 read分支:
2662 if (bwr.read_size > 0) {//如果需要 read,再进行read
2663 ret = binder_thread_read(proc, thread, bwr.read_buffer,
2664 bwr.read_size,
2665 &bwr.read_consumed,
2666 filp->f_flags & O_NONBLOCK);//这参数代表是否 block
....
2675 }
问:filp->f_flags时在那里设置的呢?O_NONBLOCK又时什么意思?
可以看到,传递了 bwr.read_consumed,这样后续把 bwr拷贝回用户空间时,用户空间进程就能知道本次的binder read读到了多少数据;
2141static int binder_thread_read(struct binder_proc *proc,
2142 struct binder_thread *thread,
2143 binder_uintptr_t binder_buffer, size_t size,
2144 binder_size_t *consumed, int non_block)
2145{
2146 void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
2147 void __user *ptr = buffer + *consumed;//buffer的开始使用的位置
2148 void __user *end = buffer + size;//buffer末尾
2149
2150 int ret = 0;
2151 int wait_for_proc_work;
2152
2153 if (*consumed == 0) {
2154 if (put_user(BR_NOOP, (uint32_t __user *)ptr))//写BR_LOOP占位
2155 return -EFAULT;
2156 ptr += sizeof(uint32_t);//更新 ptr
2157 }
2158
2159retry:
2160 wait_for_proc_work = thread->transaction_stack == NULL &&
2161 list_empty(&thread->todo);//如果binder thread 没有binder请求需要处理,wait_for_proc_work置为 true,代表需要等待从 binder_proc获取binder请求
2162
2163 if (thread->return_error != BR_OK && ptr < end) {//错误处理,暂时跳过
2164 if (thread->return_error2 != BR_OK) {
2165 if (put_user(thread->return_error2, (uint32_t __user *)ptr))
2166 return -EFAULT;
2167 ptr += sizeof(uint32_t);
2168 binder_stat_br(proc, thread, thread->return_error2);
2169 if (ptr == end)
2170 goto done;
2171 thread->return_error2 = BR_OK;
2172 }
2173 if (put_user(thread->return_error, (uint32_t __user *)ptr))
2174 return -EFAULT;
2175 ptr += sizeof(uint32_t);
2176 binder_stat_br(proc, thread, thread->return_error);
2177 thread->return_error = BR_OK;
2178 goto done;
2179 }
2180
2181
2182 thread->looper |= BINDER_LOOPER_STATE_WAITING;//进入waiting状态
2183 if (wait_for_proc_work)
2184 proc->ready_threads++;//可用binder_thread数+1
2185
2186 binder_unlock(__func__);
2187
2188 trace_binder_wait_for_work(wait_for_proc_work,
2189 !!thread->transaction_stack,
2190 !list_empty(&thread->todo));//trace
2191 if (wait_for_proc_work) {//如果当前binder thread 确实没有binder请求
2192 if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
2193 BINDER_LOOPER_STATE_ENTERED))) {//异常情况
2194 binder_user_error("%d:%d ERROR: Thread waiting for process work before calling BC_REGISTER_LOOPER or BC_ENTER_LOOPER (state %x)\n",
2195 proc->pid, thread->pid, thread->looper);
2196 wait_event_interruptible(binder_user_error_wait,
2197 binder_stop_on_user_error < 2);
2198 }
2199 binder_set_nice(proc->default_priority);//设置优先级
2200 if (non_block) {//如果不需要block,则查看当前进程的binder_proc中是否有binder work需要做,如果没有,那么返回值为 -EAGAIN
2201 if (!binder_has_proc_work(proc, thread))
2202 ret = -EAGAIN;
2203 } else //如果需要block(一般走这个),则wait在这里,直到当前进程对应的binder_proc中有binder work(即有binder通信请求)
2204 ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
2205 } else {//如果当前线程中存在 binder work需要做
2206 if (non_block) {
2207 if (!binder_has_thread_work(thread))
2208 ret = -EAGAIN;
2209 } else
2210 ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); //再次根据thread是否有 binder work决定是否wait
2211 }
2212
2213 binder_lock(__func__);
2214
2215 if (wait_for_proc_work) //执行到这里说明不在wait,将要执行自己的binder work了,那么 read threads数量需要 -1
2216 proc->ready_threads--;
2217 thread->looper &= ~BINDER_LOOPER_STATE_WAITING; //把 waiting状态去掉
2218
2219 if (ret) //ret != 0
2220 return ret;
2221
2222 while (1) {
2223 uint32_t cmd;
2224 struct binder_transaction_data tr;
2225 struct binder_work *w;
2226 struct binder_transaction *t = NULL;
2227
2228 if (!list_empty(&thread->todo)) {
2229 w = list_first_entry(&thread->todo, struct binder_work,
2230 entry); //取第一个binder work
2231 } else if (!list_empty(&proc->todo) && wait_for_proc_work) {
2232 w = list_first_entry(&proc->todo, struct binder_work,
2233 entry);//binder thread中没有binder work,尝试从binder proc拿一个binder work
2234 } else {
2235 /* no data added */
2236 if (ptr - buffer == 4 &&
2237 !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))//没有数据,重新尝试
2238 goto retry;
2239 break;
2240 }
2241
2242 if (end - ptr < sizeof(tr) + 4)//buffer剩余空间不足以存放一个{cmd, binder_transaction_data}数据对了
2243 break;
2244
2245 switch (w->type) {//binder work的type
2246 case BINDER_WORK_TRANSACTION: { //是个 transation
2247 t = container_of(w, struct binder_transaction, work); //获取对应 binder transation
2248 } break;
2249 case BINDER_WORK_TRANSACTION_COMPLETE: {
2250 cmd = BR_TRANSACTION_COMPLETE;
2251 if (put_user(cmd, (uint32_t __user *)ptr))//写入 cmd
2252 return -EFAULT;
2253 ptr += sizeof(uint32_t);
2254
2255 binder_stat_br(proc, thread, cmd);
2256 binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE,
2257 "%d:%d BR_TRANSACTION_COMPLETE\n",
2258 proc->pid, thread->pid);
2259
2260 list_del(&w->entry);//删除binder work
2261 kfree(w);
2262 binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
2263 } break;
2264 case BINDER_WORK_NODE: {
2265 struct binder_node *node = container_of(w, struct binder_node, work);
2266 uint32_t cmd = BR_NOOP;
2267 const char *cmd_name;
2268 int strong = node->internal_strong_refs || node->local_strong_refs;
2269 int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong;
2270
2271 if (weak && !node->has_weak_ref) {
2272 cmd = BR_INCREFS;
2273 cmd_name = "BR_INCREFS";
2274 node->has_weak_ref = 1;
2275 node->pending_weak_ref = 1;
2276 node->local_weak_refs++;
2277 } else if (strong && !node->has_strong_ref) {
2278 cmd = BR_ACQUIRE;
2279 cmd_name = "BR_ACQUIRE";
2280 node->has_strong_ref = 1;
2281 node->pending_strong_ref = 1;
2282 node->local_strong_refs++;
2283 } else if (!strong && node->has_strong_ref) {
2284 cmd = BR_RELEASE;
2285 cmd_name = "BR_RELEASE";
2286 node->has_strong_ref = 0;
2287 } else if (!weak && node->has_weak_ref) {
2288 cmd = BR_DECREFS;
2289 cmd_name = "BR_DECREFS";
2290 node->has_weak_ref = 0;
2291 }
2292 if (cmd != BR_NOOP) {
2293 if (put_user(cmd, (uint32_t __user *)ptr))
2294 return -EFAULT;
2295 ptr += sizeof(uint32_t);
2296 if (put_user(node->ptr,
2297 (binder_uintptr_t __user *)ptr))
2298 return -EFAULT;
2299 ptr += sizeof(binder_uintptr_t);
2300 if (put_user(node->cookie,
2301 (binder_uintptr_t __user *)ptr))
2302 return -EFAULT;
2303 ptr += sizeof(binder_uintptr_t);
2304
2305 binder_stat_br(proc, thread, cmd);
2306 binder_debug(BINDER_DEBUG_USER_REFS,
2307 "%d:%d %s %d u%016llx c%016llx\n",
2308 proc->pid, thread->pid, cmd_name,
2309 node->debug_id,
2310 (u64)node->ptr, (u64)node->cookie);
2311 } else {
2312 list_del_init(&w->entry);
2313 if (!weak && !strong) {
2314 binder_debug(BINDER_DEBUG_INTERNAL_REFS,
2315 "%d:%d node %d u%016llx c%016llx deleted\n",
2316 proc->pid, thread->pid,
2317 node->debug_id,
2318 (u64)node->ptr,
2319 (u64)node->cookie);
2320 rb_erase(&node->rb_node, &proc->nodes);
2321 kfree(node);
2322 binder_stats_deleted(BINDER_STAT_NODE);
2323 } else {
2324 binder_debug(BINDER_DEBUG_INTERNAL_REFS,
2325 "%d:%d node %d u%016llx c%016llx state unchanged\n",
2326 proc->pid, thread->pid,
2327 node->debug_id,
2328 (u64)node->ptr,
2329 (u64)node->cookie);
2330 }
2331 }
2332 } break;
2333 case BINDER_WORK_DEAD_BINDER:
2334 case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
2335 case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
2336 struct binder_ref_death *death;
2337 uint32_t cmd;
2338
2339 death = container_of(w, struct binder_ref_death, work);
2340 if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
2341 cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
2342 else
2343 cmd = BR_DEAD_BINDER;
2344 if (put_user(cmd, (uint32_t __user *)ptr))
2345 return -EFAULT;
2346 ptr += sizeof(uint32_t);
2347 if (put_user(death->cookie,
2348 (binder_uintptr_t __user *)ptr))
2349 return -EFAULT;
2350 ptr += sizeof(binder_uintptr_t);
2351 binder_stat_br(proc, thread, cmd);
2352 binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,
2353 "%d:%d %s %016llx\n",
2354 proc->pid, thread->pid,
2355 cmd == BR_DEAD_BINDER ?
2356 "BR_DEAD_BINDER" :
2357 "BR_CLEAR_DEATH_NOTIFICATION_DONE",
2358 (u64)death->cookie);
2359
2360 if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
2361 list_del(&w->entry);
2362 kfree(death);
2363 binder_stats_deleted(BINDER_STAT_DEATH);
2364 } else
2365 list_move(&w->entry, &proc->delivered_death);
2366 if (cmd == BR_DEAD_BINDER)
2367 goto done; /* DEAD_BINDER notifications can cause transactions */
2368 } break;
2369 }
2370
2371 if (!t)
2372 continue;
2373
2374 BUG_ON(t->buffer == NULL);
2375 if (t->buffer->target_node) {
2376 struct binder_node *target_node = t->buffer->target_node;
2377
2378 tr.target.ptr = target_node->ptr;
2379 tr.cookie = target_node->cookie;
2380 t->saved_priority = task_nice(current);
2381 if (t->priority < target_node->min_priority &&
2382 !(t->flags & TF_ONE_WAY))
2383 binder_set_nice(t->priority);
2384 else if (!(t->flags & TF_ONE_WAY) ||
2385 t->saved_priority > target_node->min_priority)
2386 binder_set_nice(target_node->min_priority);
2387 cmd = BR_TRANSACTION;
2388 } else {
2389 tr.target.ptr = 0;
2390 tr.cookie = 0;
2391 cmd = BR_REPLY;
2392 }
2393 tr.code = t->code;
2394 tr.flags = t->flags;
2395 tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);
2396
2397 if (t->from) {
2398 struct task_struct *sender = t->from->proc->tsk;
2399
2400 tr.sender_pid = task_tgid_nr_ns(sender,
2401 task_active_pid_ns(current));
2402 } else {
2403 tr.sender_pid = 0;
2404 }
2405
2406 tr.data_size = t->buffer->data_size;
2407 tr.offsets_size = t->buffer->offsets_size;
2408 tr.data.ptr.buffer = (binder_uintptr_t)(
2409 (uintptr_t)t->buffer->data +
2410 proc->user_buffer_offset);
2411 tr.data.ptr.offsets = tr.data.ptr.buffer +
2412 ALIGN(t->buffer->data_size,
2413 sizeof(void *));
2414
2415 if (put_user(cmd, (uint32_t __user *)ptr))
2416 return -EFAULT;
2417 ptr += sizeof(uint32_t);
2418 if (copy_to_user(ptr, &tr, sizeof(tr)))
2419 return -EFAULT;
2420 ptr += sizeof(tr);
2421
2422 trace_binder_transaction_received(t);
2423 binder_stat_br(proc, thread, cmd);
2424 binder_debug(BINDER_DEBUG_TRANSACTION,
2425 "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n",
2426 proc->pid, thread->pid,
2427 (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" :
2428 "BR_REPLY",
2429 t->debug_id, t->from ? t->from->proc->pid : 0,
2430 t->from ? t->from->pid : 0, cmd,
2431 t->buffer->data_size, t->buffer->offsets_size,
2432 (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets);
2433
2434 list_del(&t->work.entry);
2435 t->buffer->allow_user_free = 1;
2436 if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
2437 t->to_parent = thread->transaction_stack;
2438 t->to_thread = thread;
2439 thread->transaction_stack = t;
2440 } else {
2441 t->buffer->transaction = NULL;
2442 kfree(t);
2443 binder_stats_deleted(BINDER_STAT_TRANSACTION);
2444 }
2445 break;
2446 }
2447
2448done:
2449
2450 *consumed = ptr - buffer;
2451 if (proc->requested_threads + proc->ready_threads == 0 &&
2452 proc->requested_threads_started < proc->max_threads &&
2453 (thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
2454 BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
2455 /*spawn a new thread if we leave this out */) {
2456 proc->requested_threads++;
2457 binder_debug(BINDER_DEBUG_THREADS,
2458 "%d:%d BR_SPAWN_LOOPER\n",
2459 proc->pid, thread->pid);
2460 if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
2461 return -EFAULT;
2462 binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
2463 }
2464 return 0;
2465}
这个函数很长,但主要是因为case比较多,处理逻辑都写到这个函数了,其实可以把过长的case抽成函数的。。。
开始的时候,先往 buffer中写了一个 BR_NOOP:
237 BR_NOOP = _IO('r', 12),
238 /*
239 * No parameters. Do nothing and examine the next command. It exists
240 * primarily so that we can replace it with a BR_SPAWN_LOOPER command.
241 */
代表啥事也不干,记下来占位的,方便后续替换为 BR_SPAWN_LOOPER;
这里大体说下函数作用:
- 先尝试从 binder thread 中拿 binder work来做
- 如果binder thread中没有binder work需要做,那么尝试从 binder_proc中找 binder work来做
- 如果都找不到 binder work,那么当前线程进入等待,并基数 proc->thread_ready +1
- 找到binder work后,找到其cmd,target_node 及binder_transaction_data,然后依次拷贝到用户空间的 read buffer
- 完成后,更新 bwr.read_consumed以便用户空间知道读取到多少数据
这里有一点的还没弄清楚的是,binder work中如何记录数据的,不过没有关系,我们后续分析binder请求的创建的时候会弄明白的,现在只需要知道我们把binder请求数据已经读取到了 service manager进程的read buffer中即可。
那么读取到数据后,接下来就应该是解析数据了,再摘抄部分binder_looper代码:
406 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//此时这个函数已经返回
407
408 if (res < 0) {
409 ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
410 break;
411 }
412 //接下来将要执行 binder_parse,看到,确实用到了 bwr.read_consumed
413 res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
接下来调用 binder_parse:
216int binder_parse(struct binder_state *bs, struct binder_io *bio,
217 uintptr_t ptr, size_t size, binder_handler func)
218{
219 int r = 1;
220 uintptr_t end = ptr + (uintptr_t) size;//read buffer中有效数据末尾
221
222 while (ptr < end) {
223 uint32_t cmd = *(uint32_t *) ptr;//读取一个 cmd
224 ptr += sizeof(uint32_t);//更新 ptr
225#if TRACE
226 fprintf(stderr,"%s:\n", cmd_name(cmd));
227#endif
228 switch(cmd) {
229 case BR_NOOP:
230 break;
231 case BR_TRANSACTION_COMPLETE:
232 break;
233 case BR_INCREFS:
234 case BR_ACQUIRE:
235 case BR_RELEASE:
236 case BR_DECREFS:
237#if TRACE
238 fprintf(stderr," %p, %p\n", (void *)ptr, (void *)(ptr + sizeof(void *)));
239#endif
240 ptr += sizeof(struct binder_ptr_cookie);
241 break;
242 case BR_TRANSACTION: {//一个 transaction事物,主要是这个
243 struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
244 if ((end - ptr) < sizeof(*txn)) {//数据合法性检测
245 ALOGE("parse: txn too small!\n");
246 return -1;
247 }
248 binder_dump_txn(txn);
249 if (func) {//有处理函数,这里是 srvcmgr_handler
250 unsigned rdata[256/4];
251 struct binder_io msg;
252 struct binder_io reply;
253 int res;
254
255 bio_init(&reply, rdata, sizeof(rdata), 4);
256 bio_init_from_txn(&msg, txn);
257 res = func(bs, txn, &msg, &reply);//srvcmr_handler处理
258 if (txn->flags & TF_ONE_WAY) { //one way处理buffer
259 binder_free_buffer(bs, txn->data.ptr.buffer);
260 } else {// 非one way,要发送reply
261 binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
262 }
263 }
264 ptr += sizeof(*txn);
265 break;
266 }
267 case BR_REPLY: {
268 struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
269 if ((end - ptr) < sizeof(*txn)) {
270 ALOGE("parse: reply too small!\n");
271 return -1;
272 }
273 binder_dump_txn(txn);
274 if (bio) {
275 bio_init_from_txn(bio, txn);
276 bio = 0;
277 } else {
278 /* todo FREE BUFFER */
279 }
280 ptr += sizeof(*txn);
281 r = 0;
282 break;
283 }
284 case BR_DEAD_BINDER: {//death处理
285 struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr;
286 ptr += sizeof(binder_uintptr_t);
287 death->func(bs, death->ptr);
288 break;
289 }
290 case BR_FAILED_REPLY:
291 r = -1;
292 break;
293 case BR_DEAD_REPLY:
294 r = -1;
295 break;
296 default:
297 ALOGE("parse: OOPS %d\n", cmd);
298 return -1;
299 }
300 }
301
302 return r;
303}
这个函数里,我们主要看 BINDER_TRANSACTION 这个 cmd,这里会从 read buffer中读出一个binder_transaction_data数据 txn,txn的读取:
然后构建两个binder_io数据,跳转到 srvcmgr_handler处理这个 cmd。
这里看下 binder_io是什么:
12struct binder_io
13{
14 char *data; /* pointer to read/write from */
15 binder_size_t *offs; /* array of offsets */
16 size_t data_avail; /* bytes available in data buffer */
17 size_t offs_avail; /* entries available in offsets array */
18
19 char *data0; /* start of data buffer */
20 binder_size_t *offs0; /* start of offsets buffer */
21 uint32_t flags;
22 uint32_t unused;
23};
前面执行到这里代码:
250 unsigned rdata[256/4];
252 struct binder_io reply;
255 bio_init(&reply, rdata, sizeof(rdata), 4);
看下bio_init如何做的:
434void bio_init(struct binder_io *bio, void *data,
435 size_t maxdata, size_t maxoffs)
436{
437 size_t n = maxoffs * sizeof(size_t); // n = 4*4 =16
438
439 if (n > maxdata) {
440 bio->flags = BIO_F_OVERFLOW;
441 bio->data_avail = 0;
442 bio->offs_avail = 0;
443 return;
444 }
445
446 bio->data = bio->data0 = (char *) data + n; //rdata+4
447 bio->offs = bio->offs0 = data; //rdata
448 bio->data_avail = maxdata - n; //256-16
449 bio->offs_avail = maxoffs; // 4
450 bio->flags = 0;
451}
所以此时 reply:
243 struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
251 struct binder_io msg;
256 bio_init_from_txn(&msg, txn);
binder_transaction_data:
96struct binder_transaction_data {
97 union {
99 __u32 handle;
100 binder_uintptr_t ptr;
101 } target;
102 binder_uintptr_t cookie;
104 __u32 code;
105 __u32 flags;
106 pid_t sender_pid;
107 uid_t sender_euid;
109 binder_size_t data_size;
110 binder_size_t offsets_size;
111 union {
112 struct {
114 binder_uintptr_t buffer;
115 binder_uintptr_t offsets;
116 } ptr;
117 __u8 buf[8];
119 } data;
120};
425void bio_init_from_txn(struct binder_io *bio, struct binder_transaction_data *txn)
426{
427 bio->data = bio->data0 = (char *)(intptr_t)txn->data.ptr.buffer;
428 bio->offs = bio->offs0 = (binder_size_t *)(intptr_t)txn->data.ptr.offsets;
429 bio->data_avail = txn->data_size;
430 bio->offs_avail = txn->offsets_size / sizeof(size_t);
431 bio->flags = BIO_F_SHARED;
432}
此时的 msg:
三个参数准备好后,接下来继续执行
257 res = func(bs, txn, &msg, &reply);//srvcmr_handler处理
func就是 svcmgr_handler:
262int svcmgr_handler(struct binder_state *bs,
263 struct binder_transaction_data *txn,
264 struct binder_io *msg,
265 struct binder_io *reply)
266{
267 struct svcinfo *si;
268 uint16_t *s;
269 size_t len;
270 uint32_t handle;
271 uint32_t strict_policy;
272 int allow_isolated;
273
274 //ALOGI("target=%p code=%d pid=%d uid=%d\n",
275 // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);
276
277 if (txn->target.ptr != BINDER_SERVICE_MANAGER)
278 return -1;
279
280 if (txn->code == PING_TRANSACTION)
281 return 0;
282
283 // Equivalent to Parcel::enforceInterface(), reading the RPC
284 // header with the strict mode policy mask and the interface name.
285 // Note that we ignore the strict_policy and don't propagate it
286 // further (since we do no outbound RPCs anyway).
287 strict_policy = bio_get_uint32(msg);
288 s = bio_get_string16(msg, &len);
289 if (s == NULL) {
290 return -1;
291 }
292
293 if ((len != (sizeof(svcmgr_id) / 2)) ||
294 memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
295 fprintf(stderr,"invalid id %s\n", str8(s, len));
296 return -1;
297 }
298
299 if (sehandle && selinux_status_updated() > 0) {
300 struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
301 if (tmp_sehandle) {
302 selabel_close(sehandle);
303 sehandle = tmp_sehandle;
304 }
305 }
306
307 switch(txn->code) {
308 case SVC_MGR_GET_SERVICE:
309 case SVC_MGR_CHECK_SERVICE:
310 s = bio_get_string16(msg, &len);
311 if (s == NULL) {
312 return -1;
313 }
314 handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
315 if (!handle)
316 break;
317 bio_put_ref(reply, handle);
318 return 0;
319
320 case SVC_MGR_ADD_SERVICE:
321 s = bio_get_string16(msg, &len);
322 if (s == NULL) {
323 return -1;
324 }
325 handle = bio_get_ref(msg);
326 allow_isolated = bio_get_uint32(msg) ? 1 : 0;
327 if (do_add_service(bs, s, len, handle, txn->sender_euid,
328 allow_isolated, txn->sender_pid))
329 return -1;
330 break;
331
332 case SVC_MGR_LIST_SERVICES: {
333 uint32_t n = bio_get_uint32(msg);
334
335 if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
336 ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
337 txn->sender_euid);
338 return -1;
339 }
340 si = svclist;
341 while ((n-- > 0) && si)
342 si = si->next;
343 if (si) {
344 bio_put_string16(reply, si->name);
345 return 0;
346 }
347 return -1;
348 }
349 default:
350 ALOGE("unknown code %d\n", txn->code);
351 return -1;
352 }
353
354 bio_put_uint32(reply, 0);
355 return 0;
356}
这个时候相当于已经从 readbuf中读到请求,然后执行这些请求,比如 addService请求等。
至此,我们已经分析完成如下:
- service manager 进程如何与binder driver共享物理内存,即一次拷贝通信的基石
- service manager 如何成功所有service 管理者的
- service manager 如何读取binder请求,读取完后由 srvcmgr_handler处理
后续我们将在其他文章继续分析 service 的查找和添加的实现。