ServiceManager启动:
ServiceManager进程由init进程解析相应的.rc启动并进入执行入口main函数。
不同的版本具体实现有差异,但都包含这三个关键动作:
-
打开binder设备驱动,mmap映射共享内存
-
向驱动注册为服务管理者
-
进入循环不断处理请求
android 8.0:

-
binder_open 打开binder设备驱动
-
binder_become_context_manager 注册为服务管理者
-
binder_loop 进入循环等待处理请求
本文以8.0代码为例讲解:
1、打开binder设备驱动以及映射共享内存
../frameworks/native/cmd/binder.c
C++
struct binder_state *binder_open(size_t mapsize)
{
struct binder_state *bs;
struct binder_version vers;
bs = malloc(sizeof(*bs));
...
// 1
bs->fd = open("/dev/binder", O_RDWR);
...
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
...
// ERR
}
bs->mapsize = mapsize;
// 2
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
...
return bs;
...
}
Binder驱动设备注册,设置了驱动主体函数入口,包括本系列常用到的 open对应驱动binder_open,mmap对应驱动binder_mmap,ioctl对应binder_ioctl
C++
device_initcall(binder_init);
static int __init binder_init(void)
{
...
// 设备注册
ret = misc_register(&binder_miscdev);
...
}
static struct miscdevice binder_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "binder",
.fops = &binder_fops // 驱动主体函数入口指针
};
static const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
.compat_ioctl = binder_ioctl,
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
.release = binder_release,
};
1.1 open -> 驱动 binder_open
C++
static HLIST_HEAD(binder_procs);
static int binder_open(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc;
...
//binder_proc分配内存,这个是ServiceManager进程上下文的结构体
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
if (proc == NULL)
return -ENOMEM;
get_task_struct(current);
//将proc->tsk指向当前线程current
proc->tsk = current;
//proc的待处理事务列表,创建头结点
INIT_LIST_HEAD(&proc->todo);
//proc的等待队列,创建头结点
init_waitqueue_head(&proc->wait);
//设置proc的进程优先级为当前进程优先级
proc->default_priority = task_nice(current);
binder_lock(__func__);
binder_stats_created(BINDER_STAT_PROC);
//将ServiceManager的proc保存到"全局哈希表binder_procs"中
hlist_add_head(&proc->proc_node, &binder_procs);
//设置进程id
proc->pid = current->group_leader->pid;
INIT_LIST_HEAD(&proc->delivered_death);
//将proc赋给filp私有数据private_data
//这样,mmap(),ioctl()等函数都可以通过私有数据获取到proc,即该进程的上下文信息
filp->private_data = proc;
binder_unlock(__func__);
...
return 0;
}
-
创建并初始化ServiceManager的binder_proc。binder_proc是描述Binder进程的上下文信息结构体。也就是将ServiceManager的进程的信息存储到proc中。
-
将ServiceManager的binder_proc添加到全局哈希表binder_procs中。
-
将proc设为filp的private_data,使得在mmap(),ioctl()等函数中,我们都可以通过filp的private_data来获取proc信息。
1.2 mmap ->驱动 binder_mmap
C++
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret;
struct vm_struct *area;
// 1
struct binder_proc *proc = filp->private_data;
const char *failure_string;
struct binder_buffer *buffer;
// 有效性检查:映射的内存不能大于4M
if ((vma->vm_end - vma->vm_start) > SZ_4M)
vma->vm_end = vma->vm_start + SZ_4M;
...
vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;
mutex_lock(&binder_mmap_lock);
// 2 获取空闲的内核空间地址
area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
...
// 3.1 将内核空间地址赋值到proc->buffer
proc->buffer = area->addr;
// 3.2 计算 "内核空间地址" 和 "进程虚拟地址" 的偏移
proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;
mutex_unlock(&binder_mmap_lock);
// 3.3 分配内存,proc->pages为内存对象起始地址
proc->pages = kzalloc(sizeof(proc->pages[0])
* ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);
...
// 3.4 内核空间的内存大小 = 进程虚拟地址区域(用户空间)的内存大小
proc->buffer_size = vma->vm_end - vma->vm_start;
vma->vm_ops = &binder_vm_ops;
// 将 proc(进程上下文信息) 赋值给vma私有数据
vma->vm_private_data = proc;
// 4 通过调用binder_update_page_range()来分配物理页面,
// 以及将物理内存映射到内核空间以及用户空间
if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) {
goto err_alloc_small_buf_failed;
}
buffer = proc->buffer;
INIT_LIST_HEAD(&proc->buffers);
// 将物理内存添加到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(proc->tsk);
// 将用户空间地址信息保存到proc中
proc->vma = vma;
proc->vma_vm_mm = vma->vm_mm;
return 0;
...
}
-
proc = filp->private_data。该flip是在binder_open()初始化的,通过 flip获取到 binder_proc。
-
area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP)。
- get_vm_area:从内核虚拟地址中,获取指定大小的空闲地址,起始地址赋值给area。
- area:vm_struct类型。vm_struct 描述内核虚拟地址信息(vm_area_struct 是描述进程虚拟地址信息)
-
赋值:
proc->buffer(内核空间分配的虚拟内存的起始地址)
proc->user_buffer_offset(内核空间地址和进程虚拟地址的偏移值)
-
用于内核虚拟地址和进程虚拟地址相互获取
内核 + offset = 用户进程地址,已知其中一个就能获得另一个
proc->pages(内核空间所占物理页面)
- struct page 结构体
- 映射内存的page页的数组,page是描述物理内存的结构体
proc->buffer_size(内核地址空间的大小)
-
-
调用binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)。
- 分配物理内存
binder_update_page_range 的分析
C++static int binder_update_page_range(struct binder_proc *proc, int allocate, void *start, void *end, struct vm_area_struct *vma) { void *page_addr; unsigned long user_page_addr; struct page **page; struct mm_struct *mm; ... // 分配物理页面, // 并将"内核空间"和"用户空间(进程的内存区域)"指向同一块物理内存。 for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { int ret; page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; // 分配物理页面 *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); ... // 将物理页面映射到内核空间中 ret = map_kernel_range_noflush((unsigned long)page_addr, PAGE_SIZE, PAGE_KERNEL, page); flush_cache_vmap((unsigned long)page_addr, (unsigned long)page_addr + PAGE_SIZE); ... user_page_addr = (uintptr_t)page_addr + proc->user_buffer_offset; // 将物理页面映射插入到进程的虚拟内存中 ret = vm_insert_page(vma, user_page_addr, page[0]); ... } ... return 0; ... }
小结
打开/dev/binder设备驱动,Binder驱动新建并初始化描述该进程的binder_proc结构体,
获取内核虚拟地址,将其和该进程用户空间虚拟地址映射到同一物理内存。
2、注册为管理者 binder_become_context_manager
C++
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
向驱动发起注册请求
2.1 binder_ioctl
C
// 全局binder实体,准确点说是ServiceManager的binder实体
static struct binder_node *binder_context_mgr_node;
// ServiceManager守护进程的uid
static uid_t binder_context_mgr_uid = -1;
static int binder_stop_on_user_error;
...
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
// 取SM的binder_proc
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
...
binder_lock(__func__);
// 取SM的binder_thread
//在proc进程中查找该线程对应的 binder_thread;
//若查找失败,则新建一个binder_thread,并添加到proc->threads中
thread = binder_get_thread(proc);
...
switch (cmd) {
...
// *** 注册服务管理者
case BINDER_SET_CONTEXT_MGR:
ret = binder_ioctl_set_ctx_mgr(filp);
...
}
ret = 0;
err:
// 去掉thread的BINDER_LOOPER_STATE_NEED_RETURN标记
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
...
return ret;
}
-
proc = flip->private_data,获取binder_proc。flip的私有数据是在binder_open()时设置的
-
cmd的值是我们在service_manager.c调用ioctl()传入的参数 BINDER_SET_CONTEXT_MGR,调用binder_ioctl_set_ctx_mgr
-
代码最后调用 thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN
- 表示清除thread->looper的 BINDER_LOOPER_STATE_NEED_RETURN标记
- BINDER_LOOPER_STATE_NEED_RETURN标记:是在调用binder_get_thread()中创建binder_thread对象时添加的。
2.2 binder_ioctl_set_ctx_mgr
C
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 (uid_valid(binder_context_mgr_uid)) {
if (!uid_eq(binder_context_mgr_uid, curr_euid)) {
pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
from_kuid(&init_user_ns, curr_euid),
from_kuid(&init_user_ns,
binder_context_mgr_uid));
ret = -EPERM;
goto out;
}
} else {
//设置ServiceManager对应的uid
binder_context_mgr_uid = curr_euid;
}
//新建binder实体,并将proc保存到binder实体中;
//然后,将该binder实体赋值给binder_context_mgr_node,是一个全局变量。
//这个binder实体是ServiceManager对应的binder实体。
binder_context_mgr_node = binder_new_node(proc, 0, 0);
...
//设置binder实体的引用计数相关参数
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_context_mgr_uid,代表ServiceManager所对应的uid;
-
创建binder实体,并将该新建的Binder实体赋值给binder_context_mgr_node,binder_context_mgr_node是一个全局变量;
-
最后,设置binder实体的引用计数等参数。
关于binder_node结构体:
- Binder驱动为每一个 service创建一个 binder_node 代表service在驱动中的binder实体。
- 而对于ServiceManager这个服务管理者也是作为服务存在,Binder驱动创建了全局变量binder_context_mgr_node 作为其binder实体。
2.3 创建binder实体
binder_new_node(proc, 0, 0)
C++
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;
//在binder_proc的nodes红黑树中,查找是否有匹配的binder实体(通过ptr来判断)
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;
}
//如果没有找到要找的binder实体,则新建该binder实体
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (node == NULL)
return NULL;
binder_stats_created(BINDER_STAT_NODE);
// 将node链接到红黑树proc->nodes中
rb_link_node(&node->rb_node, parent, p);
rb_insert_color(&node->rb_node, &proc->nodes);
node->debug_id = ++binder_last_id;
//将进程上下文信息保存到node->proc中
node->proc = 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);
...
return node;
}
- 首先在 proc->nodes 红黑树中查找是否有binder实体(binder_node)存在。有的话,返回NULL,即不需要新建binder实体;
- 没有查找到,新建并初始化binder_node,然后将其添加到proc->nodes红黑树中。
小结
是从用户空间向驱动发起的请求,在binder驱动中主要做了如下事情:
-
新建当前线程对应的binder_thread对象,并将其添加到进程上下文信息binder_proc的threads红黑树中;
-
新建ServiceManager对应的binder实体并将其保存为全局变量binder_context_mgr_node中。
3、进入循环处理 binder_loop
C++
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;
//告诉Kernel binder驱动,我(ServiceManager进程)要进入消息循环状态了,请做好相关准备
readbuf[0] = BC_ENTER_LOOPER;
// 1 发起BC_ENTER_LOOPER
binder_write(bs, readbuf, sizeof(uint32_t));
// 2 循环
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
//向Kernel binder驱动中发送消息(消息顺序是先写后读)
//先将消息传递给Kernel binder驱动,然后再从kernel读取消息反馈
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
...
// 3 解析读取的消息反馈
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
...
}
}
-
binder_write(,BC_ENTER_LOOPER,) 准备进入消息循环状态,通知 Kernel Binder驱动做好相关准备。
-
进入消息循环后,调用ioctl(,BINDER_WRITE_READ,)
-
binder_parse 解析处理ioctl返回了的数据
3.1 发起BC_ENTER_LOOPER命令
3.1.1 binder_write
C++
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; //BC_ENTER_LOOPER
bwr.read_size = 0; //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通信中常用的数据结构体binder_write_read。
bwr.write_size>0:表示通过ServiceManager有数据(即BC_ENTER_LOOPER指令)发送给Binder驱动,
bwr.write_buffer:发送的数据(BC_ENTER_LOOPER)
bwr.write_consumed:已经被读取并处理的数据的大小。
bwr.read_XXX:保存Binder驱动即将反馈给ServiceManager的各种信息,这里都是0。
这里可以看出,binder_write 函数就是通过ioctl向binder读写数据,只写不读。
3.1.2 binder_ioctl - BINDER_WRITE_READ
binder_loop -> binder_write -> binder_ioctl
C++
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
...
// 中断等待函数。
// 1. 当binder_stop_on_user_error < 2为true时;不会进入等待状态;直接跳过。
// 2. 当binder_stop_on_user_error < 2为false时,进入等待状态。
// 当有其他进程通过wake_up_interruptible来唤醒binder_user_error_wait队列,
// 并且binder_stop_on_user_error < 2为true时;
// 则继续执行;否则,再进入等待状态。
// 1 跳过
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret)
goto err_unlocked;
binder_lock(__func__);
// 在proc进程中查找该线程对应的binder_thread;
// 若查找失败,则新建一个binder_thread,并添加到proc->threads中。
// 2 上一次已经创建过了,可以直接获取到
thread = binder_get_thread(proc);
...
switch (cmd) {
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
}
...
ret = 0;
...
return ret;
}
3.1.3 binder_ioctl_write_read
binder_loop -> binder_write -> binder_ioctl -> binder_ioctl_write_read
C
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {
ret = -EINVAL;
goto out;
}
// 3 将binder_write_read从"用户空间" 拷贝到 "内核空间"
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
...
// 4 write_size>0,进行写操作
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
...
}
// 5 read_size == 0,不进行读操作
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
...
}
...
// 6
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}
-
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2)
binder_stop_on_user_error < 2为true。因此,不进入中断等待状态而是直接跳过该函数。
-
thread = binder_get_thread(proc)。
上次调用ioctl时,已经创建了该线程对应的binder_thread对象,因此这次能在proc->threads红黑树中找到
-
copy_from_user(&bwr, ubuf, sizeof(bwr)) 作用是将用户空间的数据拷贝到内核空间。
将ServiceManager调用ioctl(bs->fd, BINDER_WRITE_READ, &bwr)时的bwr对象拷贝到Binder驱动中。
-
在binder_write()中设置的 bwr.write_size>0;所以,调用binder_thread_write()进行写操作。
-
在binder_write()中设置的bwr.read_size==0;所以,不调用binder_thread_read()进行读操作。
-
读写操作完毕之后,将bwr从内核空间再拷贝到用户空间。
3.1.4 binder_thread_write
binder_loop -> binder_write -> binder_ioctl -> binder_ioctl_write_read -> binder_thread_write
C++
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
{
uint32_t cmd;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
// 读取binder_write_read.write_buffer中的内容。
// 每次读取32bit(即4个字节)的数据
while (ptr < end && thread->return_error == BR_OK) {
// 从用户空间读取32bit到内核中,并赋值给cmd。
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
...
switch (cmd) {
...
case BC_ENTER_LOOPER:
...
// 设置线程的状态为BINDER_LOOPER_STATE_ENTERED;
// 即,进入了循环状态
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
...
}
// 更新bwr.write_consumed的值
*consumed = ptr - buffer;
}
return 0;
}
说明:
-
binder_thread_write()从brw.write_buffer中每次读取前4个字节作为cmd。
这里这4个字节就是ServiceManager传递的指令BC_ENTER_LOOPER。
-
case BC_ENTER_LOOPER:将BINDER_LOOPER_STATE_ENTERED加入到thread->looper中。告诉Binder驱动,ServiceManager进程进入了消息循环状态。
3.2 正式进入循环体
回到 binder_loop
C++
void binder_loop(struct binder_state *bs, binder_handler func)
{
...
// 2 循环
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
//向Kernel binder驱动中发送消息(消息顺序是先写后读)
//先将消息传递给Kernel binder驱动,然后再从kernel读取消息反馈
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
...
// 3 解析读取的消息并反馈
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
...
}
}
此时的 bwr 内容:
C++
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (unsigned) readbuf;
bwr.write_size=0,而bwr.read_size>0;表示只从Binder驱动读取数据,并不向Binder驱动写入数据。
可以看出循环体中的ioctl实际就是负责只读不写。(写动作在后面的binder_parse里会根据不同场景俺需调用binder_write 写)
接着调用ioctl()再次进入到Binder驱动binder_ioctl()执行 binder_ioctl_write_read:
3.2.1 binder_ioctl_write_read
binder_loop -> binder_ioctl -> binder_ioctl_write_read
C
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
...
// write_size == 0,跳过
if (bwr.write_size > 0) {
...
}
// read_size > 0
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
...
}
...
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}
binder_thread_read
C++
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed, int non_block)
{
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
int ret = 0;
int wait_for_proc_work;
// 1 如果*consumed=0,则写入BR_NOOP到用户传进来的bwr.read_buffer缓存区
if (*consumed == 0) {
if (put_user(BR_NOOP, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
}
retry:
// 2 等待proc进程的事务标记。
// 当线程的事务栈为空 并且 待处理事务列表为空时,该标记位true。
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);
...
// 设置线程为"等待状态"
thread->looper |= BINDER_LOOPER_STATE_WAITING;
if (wait_for_proc_work)
proc->ready_threads++;
...
if (wait_for_proc_work) {
...
// 设置当前线程的优先级=proc->default_priority。
//即,当前线程要处理proc的事务,所以设置优先级和proc一样
binder_set_nice(proc->default_priority);
// 4
if (non_block) {
// 非阻塞式的读取,则通过binder_has_proc_work()读取proc的事务;
// 若没有,则直接返回
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN;
} else
// 4 阻塞式的读取,则阻塞等待事务的发生。
ret = wait_event_freezable_exclusive(proc->wait,
binder_has_proc_work(proc, thread));
} else {
...
}
...
}
-
刚进来还没有消费,bwr.read_consumed=0,将BR_NOOP拷贝到用户空间的bwr.read_buffer缓存区中。
-
目前为止,并没有进程将事务添加到当前线程中;因此,线程的事务栈和待处理事务队列都是为空。于是得到wait_for_proc_work的值是true。
-
non_block表示是否阻塞式读取,这里是false,调用 wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread))。
目前ServiceManager进程中没有待处理事务,因此binder_has_proc_work(proc, thread)为false。
从而当前线程进入中断等待状态,等待其它进程将ServiceManager唤醒。
至此,ServiceManager进入了等待状态,binder_loop()就分析就告一段落了。
3.2.2 binder_parse
解析读取的消息并反馈。假如3.2.1读取到了数据,这里负责解析和处理。后续的addService getService讲解的文章会涉及到。
小结
循环体内实际分两部分,ioctl和binder_parse,ioctl负责从驱动读数据,binder_parse负责解析和处理读到的数据(binder_parse也有涉及向驱动发起请求的场景,如BR_TRANSACTION的处理,此时会调用binder_write进入驱动后仅做写处理,读取还是通过下一次循环ioctl读)。处理完毕后进入下一次循环重复该动作。
android 10.0:
安卓10 对binder通信相关内容做了重构:
- 把对binder通信的相关操做了解耦,给了ProcessState/IPCThreadState处理,与普通进程的方式一致了;
- 把自己注册为binder服务也是通过调用自己的addService把自己注册为服务;
- 把自己设置为服务管理者,也抽取到ProcessState调用处理。与普通进程的binder管理方式归一。
而最终实际要做的事情都是一致的:打开驱动,mmap映射内存,注册为管理者,进入循环等待请求。本文没有写安卓10的实现方式,如果有需要后续可以另外补充。
SM启动总结
对于ServiceManager进程而言
- 打开Binder设备文件,映射内存。
- 向Binder驱动发起将自己注册为Binder上下文管理者。
- 进入循环,等待Client请求。
对于Binder驱动而言
- 初始化ServiceManager对应的进程上下文环境(binder_proc),并将内核虚拟地址和进程虚拟地址映射到同一物理内存。
- 接到ServiceManager注册为Binder上下文管理者的请求后,建立ServiceManager对应的Binder实体binder_node,并将该Binder实体保存为全局变量binder_context_mgr_node。
- 最后,ServiceManager进入消息循环后发起binder_thread_read,如果没有事务会进入等待状态,等待其他进程发起请求将其唤醒。