Skytoby

深入理解Binder机制5-binder驱动分析

深入理解Binder机制5-binder驱动分析

一、概述

Binder驱动是Android专用的,但底层的驱动架构与Linux驱动一样。binder驱动在以misc设备进行注册,作为虚拟字符设备,没有直接操作硬件,只是对设备内存的处理,主要是驱动设备的初始化(binder_init),打开(binder_open),映射(binder_mmap),数据操作(binder_ioctl)。

  1. 通过init(),创建/dev/binder设备节点
  2. 通过open(),获取Binder Driver的文件描述符
  3. 通过mmap(),在内核分配一块内存,用于存放数据
  4. 通过ioctl(),将IPC数据作为参数传递给Binder Driver

用户态的程序调用Kernel层驱动是需要陷入内核态,进行系统调用(syscall),比如打开Binder驱动方法的调用链是:open()->__open()->binder_open()。open()为用户空间的方法, _open()是系统调用中相应的处理方法,通过查找,对应调用到内核binder驱动的binder_open方法。

systemcall

Client进程通过RPC(Remote Procedure Call Protocol)与Server通信,可以简单的分为三层,驱动层、IPC层、业务层。demo()是client和server共同协商好的统一方法,RPC数据、code、handle、协议这四项组成了IPC的层的数据,通过IPC层进行数据传输,而真正在Client和Server两端建立通信的基础设施是Binder Driver。

binderdriver_frame

例如:当AMS的client向ServiceManger注册服务的过程中,IPC层的数据组成为:handle=0,RPC数据为AMS,code为ADD_SERVICE_TRANSACTION,binder协议为BC_TRANSACTION。

二、Binder核心方法

2.1 binder_init

[->android/binder.c]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
static int __init binder_init(void)
{
int ret;
char *device_name, *device_names;
struct binder_device *device;
struct hlist_node *tmp;
//初始化shrinker
binder_alloc_shrinker_init();

atomic_set(&binder_transaction_log.cur, ~0U);
atomic_set(&binder_transaction_log_failed.cur, ~0U);

//创建一序列文件
binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
if (binder_debugfs_dir_entry_root)
binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
binder_debugfs_dir_entry_root);

if (binder_debugfs_dir_entry_root) {
debugfs_create_file("state",
S_IRUGO,
binder_debugfs_dir_entry_root,
NULL,
&binder_state_fops);
debugfs_create_file("stats",
S_IRUGO,
binder_debugfs_dir_entry_root,
NULL,
&binder_stats_fops);
debugfs_create_file("transactions",
S_IRUGO,
binder_debugfs_dir_entry_root,
NULL,
&binder_transactions_fops);
debugfs_create_file("transaction_log",
S_IRUGO,
binder_debugfs_dir_entry_root,
&binder_transaction_log,
&binder_transaction_log_fops);
debugfs_create_file("failed_transaction_log",
S_IRUGO,
binder_debugfs_dir_entry_root,
&binder_transaction_log_failed,
&binder_transaction_log_fops);
}

/*
* Copy the module_parameter string, because we don't want to
* tokenize it in-place.
*/
//分配内存
device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL);
if (!device_names) {
ret = -ENOMEM;
goto err_alloc_device_names_failed;
}
strcpy(device_names, binder_devices_param);

while ((device_name = strsep(&device_names, ","))) {
//注册misc设置,见2.2.1
ret = init_binder_device(device_name);
if (ret)
goto err_init_binder_device_failed;
}

return ret;

err_init_binder_device_failed:
hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) {
misc_deregister(&device->miscdev);
hlist_del(&device->hlist);
kfree(device);
}
err_alloc_device_names_failed:
debugfs_remove_recursive(binder_debugfs_dir_entry_root);

return ret;
}

主要工作是注册misc设备。

debugfs_create_file是指在debugfs文件系统中创建一个目录,返回值是指向dentry的指针。当kernel禁用debugfs的话,返回值是%ENODEV,默认是禁用的。如果需要打开,在目录kernel/arch/arm64/configs下找到defconfig文件下添加一行CONFIG_DEBUG_FS=y,即可开启debugfs。

2.1.1 init_binder_device

[->android/binder.c]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
static int __init init_binder_device(const char *name)
{
int ret;
struct binder_device *binder_device;

binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);
if (!binder_device)
return -ENOMEM;
//设备的文件操作结构,这是file_operation结构
binder_device->miscdev.fops = &binder_fops;
//次设备号,动态分配
binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;
//设备名
binder_device->miscdev.name = name;

binder_device->context.binder_context_mgr_uid = INVALID_UID;
binder_device->context.name = name;
mutex_init(&binder_device->context.context_mgr_node_lock);
//注册misc设备
ret = misc_register(&binder_device->miscdev);
if (ret < 0) {
kfree(binder_device);
return ret;
}
//添加到链表头部
hlist_add_head(&binder_device->hlist, &binder_devices);

return ret;
}

2.2 binder_open

[->android/binder.c]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
static int binder_open(struct inode *nodp, struct file *filp)
{
//binder进程
struct binder_proc *proc;
//为binder_proc结构体分配kernel内存空间
struct binder_device *binder_dev;

binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d/n",
current->group_leader->pid, current->pid);

proc = kzalloc(sizeof(*proc), GFP_KERNEL);
if (proc == NULL)
return -ENOMEM;
spin_lock_init(&proc->inner_lock);
spin_lock_init(&proc->outer_lock);
get_task_struct(current->group_leader);
//将当前线程的task保存到binder进程的tsk
proc->tsk = current->group_leader;
mutex_init(&proc->files_lock);
//初始化todo队列
INIT_LIST_HEAD(&proc->todo);
//初始化进程优先级
if (binder_supported_policy(current->policy)) {
proc->default_priority.sched_policy = current->policy;
proc->default_priority.prio = current->normal_prio;
} else {
proc->default_priority.sched_policy = SCHED_NORMAL;
proc->default_priority.prio = NICE_TO_PRIO(0);
}
//binder_dev初始化
binder_dev = container_of(filp->private_data, struct binder_device,
miscdev);
//初始化context
proc->context = &binder_dev->context;

//binder_alloc初始化
binder_alloc_init(&proc->alloc);
//BINDER_PROC对象创建数加1
binder_stats_created(BINDER_STAT_PROC);
proc->pid = current->group_leader->pid;
INIT_LIST_HEAD(&proc->delivered_death);
INIT_LIST_HEAD(&proc->waiting_threads);
//file文件指针的private_data变量指向binder_proc数据
filp->private_data = proc;

mutex_lock(&binder_procs_lock);
//proc节点添加到头部
hlist_add_head(&proc->proc_node, &binder_procs);
mutex_unlock(&binder_procs_lock);

if (binder_debugfs_dir_entry_proc) {
char strbuf[11];

snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
/*
* proc debug entries are shared between contexts, so
* this will fail if the process tries to open the driver
* again with a different context. The priting code will
* anyway print all contexts that a given PID has, so this
* is not a problem.
*/
proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,
binder_debugfs_dir_entry_proc,
(void *)(unsigned long)proc->pid,
&binder_proc_fops);
}

return 0;
}

创建binder_proc对象,并把当前进程等信息保存到binder_proc对象,该对象管理IPC所需要的各种信息并拥有其他结构体的根结构体;再把binder_proc对象保存到文件指针filp中,并且把binder_proc加入到全局链表binder_procs。

Binder驱动中 HLIST_HEAD创建全局的哈希链表binder_procs,用于保存所有的binder_proc队列,每次新创建的binder_proc都会加入到binder_procs链表中。

2.3 binder_mmap

[->android/binder.c]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret;
struct binder_proc *proc = filp->private_data;
const char *failure_string;

if (proc->tsk != current->group_leader)
return -EINVAL;

if ((vma->vm_end - vma->vm_start) > SZ_4M)
vma->vm_end = vma->vm_start + SZ_4M; //保证映射内存大小不超过4M

binder_debug(BINDER_DEBUG_OPEN_CLOSE,
"%s: %d %lx-%lx (%ld K) vma %lx pagep %lx/n",
__func__, proc->pid, vma->vm_start, vma->vm_end,
(vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
(unsigned long)pgprot_val(vma->vm_page_prot));

if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {
ret = -EPERM;
failure_string = "bad vm_flags";
goto err_bad_arg;
}
vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;
vma->vm_ops = &binder_vm_ops;
vma->vm_private_data = proc;

ret = binder_alloc_mmap_handler(&proc->alloc, vma);
if (ret)
return ret;
mutex_lock(&proc->files_lock);
proc->files = get_files_struct(current);
mutex_unlock(&proc->files_lock);
return 0;

err_bad_arg:
pr_err("binder_mmap: %d %lx-%lx %s failed %d/n",
proc->pid, vma->vm_start, vma->vm_end, failure_string, ret);
return ret;
}

mmap的主要功能:首先在内核虚拟地址空间,申请一块与用户虚拟空间相同大小的内存,然后再申请一个page大小的物理内存,再将同一块物理内存分别映射到内核虚拟地址空间和用户虚拟空间,从而实现了用户空间的buffer和内核空间的buffer同步操作的功能。

2.3.1 binder_alloc_mmap_handler

[->android/binder.c]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
int binder_alloc_mmap_handler(struct binder_alloc *alloc,
struct vm_area_struct *vma)
{
int ret;
struct vm_struct *area;
const char *failure_string;
struct binder_buffer *buffer;
//加锁
mutex_lock(&binder_alloc_mmap_lock);
if (alloc->buffer) {
ret = -EBUSY;
failure_string = "already mapped";
goto err_already_mapped;
}
//采用IOREMAP方式,分配一个连续的内核虚拟空间,与进程虚拟空间大小一致
area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
if (area == NULL) {
ret = -ENOMEM;
failure_string = "get_vm_area";
goto err_get_vm_area_failed;
}
//指向内核虚拟空间地址
alloc->buffer = area->addr;
//地址偏移量 = 用户虚拟地址空间-内核虚拟地址空间
alloc->user_buffer_offset =
vma->vm_start - (uintptr_t)alloc->buffer;
//释放锁
mutex_unlock(&binder_alloc_mmap_lock);

#ifdef CONFIG_CPU_CACHE_VIPT
if (cache_is_vipt_aliasing()) {
while (CACHE_COLOUR(
(vma->vm_start ^ (uint32_t)alloc->buffer))) {
pr_info("%s: %d %lx-%lx maps %pK bad alignment\n",
__func__, alloc->pid, vma->vm_start,
vma->vm_end, alloc->buffer);
vma->vm_start += PAGE_SIZE;
}
}
#endif
//分配物理页的指针数组,数组大小为vma的等效page个数
alloc->pages = kzalloc(sizeof(alloc->pages[0]) *
((vma->vm_end - vma->vm_start) / PAGE_SIZE),
GFP_KERNEL);
if (alloc->pages == NULL) {
ret = -ENOMEM;
failure_string = "alloc page array";
goto err_alloc_pages_failed;
}
alloc->buffer_size = vma->vm_end - vma->vm_start;

//为buffer分配物理内存
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer) {
ret = -ENOMEM;
failure_string = "alloc buffer struct";
goto err_alloc_buf_struct_failed;
}
//物理内存binder->data指向虚拟内存alloc->buffer
buffer->data = alloc->buffer;
//将binder_buffer地址,加入到所属进程的buffers队列
list_add(&buffer->entry, &alloc->buffers);
buffer->free = 1;
//将空间buffer放入proc->free_buffers中
binder_insert_free_buffer(alloc, buffer);
//异步可用空间大小为buffer总大小的一半
alloc->free_async_space = alloc->buffer_size / 2;
barrier();
alloc->vma = vma;
alloc->vma_vm_mm = vma->vm_mm;
/* Same as mmgrab() in later kernel versions */
atomic_inc(&alloc->vma_vm_mm->mm_count);

return 0;

err_alloc_buf_struct_failed:
kfree(alloc->pages);
alloc->pages = NULL;
err_alloc_pages_failed:
mutex_lock(&binder_alloc_mmap_lock);
vfree(alloc->buffer);
alloc->buffer = NULL;
err_get_vm_area_failed:
err_already_mapped:
mutex_unlock(&binder_alloc_mmap_lock);
pr_err("%s: %d %lx-%lx %s failed %d\n", __func__,
alloc->pid, vma->vm_start, vma->vm_end, failure_string, ret);
return ret;
}

binder_mmap通过加锁,保证一次只有一个进程分配内存,保证多进程间的并发访问。user_buffer_offset是虚拟进程地址与虚拟内核地址的差值,该值为负值。

2.4 binder_ioctl

[->android/binder.c]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
//binder线程
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;

/*pr_info("binder_ioctl: %d:%d %x %lx/n",
proc->pid, current->pid, cmd, arg);*/

binder_selftest_alloc(&proc->alloc);

trace_binder_ioctl(cmd, arg);
//进入休眠状态,直到中断唤醒
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret)
goto err_unlocked;
//获取binder_thead,见2.4.1小节
thread = binder_get_thread(proc);
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}

switch (cmd) {
//对binder进行读写操作
case BINDER_WRITE_READ:
//见2.4.2小节
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
//设置binder最大支持的线程数
case BINDER_SET_MAX_THREADS: {
int max_threads;

if (copy_from_user(&max_threads, ubuf,
sizeof(max_threads))) {
ret = -EINVAL;
goto err;
}
binder_inner_proc_lock(proc);
proc->max_threads = max_threads;
binder_inner_proc_unlock(proc);
break;
}
//成为binder的上下文管理者,也就是ServiceManager成为守护进程
case BINDER_SET_CONTEXT_MGR:
ret = binder_ioctl_set_ctx_mgr(filp);
if (ret)
goto err;
break;
//当binder线程退出,释放binder线程
case BINDER_THREAD_EXIT:
binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit/n",
proc->pid, thread->pid);
binder_thread_release(proc, thread);
thread = NULL;
break;
//获取binder的版本号
case BINDER_VERSION: {
struct binder_version __user *ver = ubuf;

if (size != sizeof(struct binder_version)) {
ret = -EINVAL;
goto err;
}
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
&ver->protocol_version)) {
ret = -EINVAL;
goto err;
}
break;
}
//获取节点的debug信息
case BINDER_GET_NODE_DEBUG_INFO: {
struct binder_node_debug_info info;

if (copy_from_user(&info, ubuf, sizeof(info))) {
ret = -EFAULT;
goto err;
}

ret = binder_ioctl_get_node_debug_info(proc, &info);
if (ret < 0)
goto err;

if (copy_to_user(ubuf, &info, sizeof(info))) {
ret = -EFAULT;
goto err;
}
break;
}
default:
ret = -EINVAL;
goto err;
}
ret = 0;
err:
if (thread)
thread->looper_need_return = false;
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
pr_info("%d:%d ioctl %x %lx returned %d/n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}

2.4.1 binder_get_thread

[->android/binder.c]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static struct binder_thread *binder_get_thread(struct binder_proc *proc)
{
struct binder_thread *thread;
struct binder_thread *new_thread;

binder_inner_proc_lock(proc);
//根据当前进行的pid,从binder_proc中查找对应的binder_thread
thread = binder_get_thread_ilocked(proc, NULL);
binder_inner_proc_unlock(proc);
//如果不存在
if (!thread) {
//新建binder_thread结构体
new_thread = kzalloc(sizeof(*thread), GFP_KERNEL);
if (new_thread == NULL)
return NULL;
binder_inner_proc_lock(proc);
thread = binder_get_thread_ilocked(proc, new_thread);
binder_inner_proc_unlock(proc);
if (thread != new_thread)
kfree(new_thread);
}
return thread;
}

2.4.2 binder_ioctl_write_read

[->android/binder.c]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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;
}
//把用户空间的数据ubuf写到bwr
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"%d:%d write %lld at %016llx, read %lld at %016llx\n",
proc->pid, thread->pid,
(u64)bwr.write_size, (u64)bwr.write_buffer,
(u64)bwr.read_size, (u64)bwr.read_buffer);

if (bwr.write_size > 0) {
//当写缓存中有数据,则执行binder写操作
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
trace_binder_write_done(ret);
//当写失败,在将bwr数据写回到用户空间并返回
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
if (bwr.read_size > 0) {
//当读缓存中有数据,则执行binder读操作
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
trace_binder_read_done(ret);
binder_inner_proc_lock(proc);
if (!binder_worklist_empty_ilocked(&proc->todo))
//唤醒等待状态的线程
binder_wakeup_proc_ilocked(proc);
binder_inner_proc_unlock(proc);
//当读失败,再将bwr数据写回到用户空间并返回
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"%d:%d wrote %lld of %lld, read return %lld of %lld\n",
proc->pid, thread->pid,
(u64)bwr.write_consumed, (u64)bwr.write_size,
(u64)bwr.read_consumed, (u64)bwr.read_size);
//将内核数据bwr拷贝到用户空间ubuf
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}

binder_ioctl_write_read主要流程如下:

1.把用户空间ubuf拷贝到内核空间bwr;

2.当bwr写缓存有数据,则执行binder_thread_write;当写失败时则将bwr数据写回到用户空间并退出;

3.当bwr读缓存有数据,则执行binder_thread_read;当读失败时则将bwr数据写回到用户空间并退出;

4.把内核数据bwr拷贝到用户空间ubuf。

binder_thread_write、binder_thread_read作为两个核心方法,在第三节中详细介绍。

2.5 小结

binder_init:初始化字符设备,注册misc设备;

binder_open:打开驱动设备,初始化binder_proc;

binder_mmap:申请内核空间,将用户空间和内核空间映射到同一块物理内存;

binder_ioctl:执行相应的ioctl操作,主要进行读写操作。

下面看下binder通信的具体协议。

三、Binder通信协议

3.1 通信模型

一次完整的Binder通信过程如下(非oneway):

bindermodel

Binder协议包含在IPC数据中,分为两类:

1.BINDER_COMMAND_PROTOCOL:binder请求码,以BC_开头,简称BC码,用于从IPC层传递到Binder Driver层;

2.BINDER_RETURN_PROTOCOL:binder响应码,以BR_开头,简称BR码,用于从Binder Driver层传递到IPC层。

Binder IPC通信至少是两个进程的交互

  • client进程执行binder_thread_write,根据BC_xx命令,生成相应的binder_work;

  • server进程执行binder_thread_read,根据binder_work_type类型,生成BR_xx,发送到用户空间处理。

3.2 binder_thread_write

请求过程是通过binder_thread_write方法,该方法用于处理Binder协议中的请求码,当binder_buffer存在数据,binder线程的写操作循环执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
uint32_t cmd;
struct binder_context *context = proc->context;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;

while (ptr < end && thread->return_error.cmd == BR_OK) {
int ret;
//获取IPC数据中的Binder协议
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
atomic_inc(&binder_stats.bc[_IOC_NR(cmd)]);
atomic_inc(&proc->stats.bc[_IOC_NR(cmd)]);
atomic_inc(&thread->stats.bc[_IOC_NR(cmd)]);
}
switch (cmd) {
case BC_INCREFS:
case BC_ACQUIRE:
case BC_RELEASE:
case BC_DECREFS: ...
case BC_INCREFS_DONE:
case BC_ACQUIRE_DONE:...
case BC_ATTEMPT_ACQUIRE:
case BC_ACQUIRE_RESULT:...
case BC_FREE_BUFFER:...
case BC_TRANSACTION_SG:
case BC_REPLY_SG: ...
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
//拷贝用户空间tr到内核
if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
//见3.2.1小节
binder_transaction(proc, thread, &tr,
cmd == BC_REPLY, 0);
break;
}
case BC_REGISTER_LOOPER:...
case BC_ENTER_LOOPER:...
case BC_EXIT_LOOPER:...
case BC_REQUEST_DEATH_NOTIFICATION:
case BC_CLEAR_DEATH_NOTIFICATION: ...
case BC_DEAD_BINDER_DONE:...
default:...
}
return 0;
}

对于BC_TRANSACTION、BC_REPLY的请求码,回执行binder_transaction方法,这是最为频繁的操作,对于其他命令则不同。

3.2.1 binder_transaction

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply,
binder_size_t extra_buffers_size)
{
int ret;
//传进来的binder_transaction
struct binder_transaction *t;
struct binder_work *tcomplete;
binder_size_t *offp, *off_end, *off_start;
binder_size_t off_min;
u8 *sg_bufp, *sg_buf_end;
//根据各种判断获取一下信息:
//目标进程
struct binder_proc *target_proc = NULL;
//目标线程
struct binder_thread *target_thread = NULL;
//目标binder结点
struct binder_node *target_node = NULL;
//回复的binder_transaction
struct binder_transaction *in_reply_to = NULL;
...
/* TODO: reuse incoming transaction for reply */
t = kzalloc(sizeof(*t), GFP_KERNEL);
...
//为target_proc分配一块buffer
t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
tr->offsets_size, extra_buffers_size,
!reply && (t->flags & TF_ONE_WAY));
for (; offp < off_end; offp++) {
...
hdr = (struct binder_object_header *)(t->buffer->data + *offp);
off_min = *offp + object_size;
switch (hdr->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: ...
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: ...
case BINDER_TYPE_FD: ...
case BINDER_TYPE_FDA: ...
case BINDER_TYPE_PTR: ...
default:
}
}
//当前线程的type
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
//向目标进程的work_type
t->work.type = BINDER_WORK_TRANSACTION;
//后面会将这些事务添加到相应的队列
...
}

3.2.2 BC_PROTOCOL

Binder的请求码是在binder_driver_command_protocol中定义的,用于应用程序向binder驱动设备发送请求消息,应用程序包含Client和Server端,以BC_开头,总共19条。

请求码 参数类型 作用
BC_TRANSACTION binder_transaction_data Client向Binder驱动发送的请求数据
BC_REPLY binder_transaction_data Server向Binder驱动发送的回复数据
BC_ACQUIRE_RESULT __s32 暂时不支持
BC_FREE_BUFFER binder_uintptr_t 释放内存
BC_INCREFS __u32 binder_ref弱引用加1操作
BC_ACQUIRE __u32 binder_ref弱引用减1操作
BC_RELEASE __u32 binder_ref强引用加1操作
BC_DECREFS __u32 binder_ref强引用减1操作
BC_INCREFS_DONE binder_ptr_cookie binder_node强引用减1操作
BC_ACQUIRE_DONE binder_ptr_cookie binder_node弱引用减1操作
BC_ATTEMPT_ACQUIRE binder_pri_desc 暂时不支持
BC_REGISTER_LOOPER 无参数 创建新的Looper线程
BC_ENTER_LOOPER 无参数 应用线程进入Looper
BC_EXIT_LOOPER 无参数 应用线程退出Looper
BC_REQUEST_DEATH_NOTIFICATION binder_handle_cookie 注册死亡通知
BC_CLEAR_DEATH_NOTIFICATION binder_handle_cookie 取消注册的死亡通知
BC_DEAD_BINDER_DONE binder_uintptr_t 已经完成的死亡通知
BC_TRANSACTION_SG binder_transaction_data_sg Client向Binder驱动发送的Command
BC_REPLY_SG binder_transaction_data_sg Server向Binder驱动发送的Command

BC_FREE_BUFFER

  • 通过mmap映射内存,其中ServiceManager映射的空间大小为128K,其他Binder应用进程映射的内存大小为1M-8k;

  • Binder驱动基于这种映射的内存采用最佳匹配来动态分配和释放,通过bind_buffer结构体中的free字段来表示相应的buffer是空闲还是已分配状态。对于已分配的buffers加入到binder_proc中的allocated_buffers红黑树,对于空闲的buffer加入到free_buffers红黑树;

  • 当应用程序需要内存时,根据所需内存大小从free_buffers中找到最合适的内存,并放入allocated_buffers树中,当应用程序处理完成后必须尽快使用BC_FREE_BUFFER命令来释放该buffer,从而添加回到free_buffers树。

BC_INCREFS、BC_ACQUIRE、BC_RELEASE、BC_DECREFS等请求码的作用是对binder的强/弱引用的计数操作,用于实现强/弱指针的功能;

BC_REGISTER_LOOPER:Binder用于驱动层决策而创建新的binder线程,joniThreadPool过程,创建非binder主线程;

BC_ENTER_LOOPER:binder主线程(由应用层发起)的创建会向驱动发送该消息;joniThreadPool过程,创建binder主线程;

BC_EXIT_LOOPER:退出binder线程,对于binder主线程是不能退出;jointThreadPool的过程出现timeout且是非binder主线程,则会退出该binder线程。

3.3 binder_thread_read

响应处理的过程是通过binder_thread_read方法,该方法根据不同的binder_work->type已经不同的状态,生成相应的响应码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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)
{

wait_for_proc_work = binder_available_for_proc_work_ilocked(thread);
//根据wait_for_proc_work来决定wait在当前线程还是进程的等待队列
if (wait_for_proc_work) {
...
}
...
while (1) {
//当thread->todo和proc->todo为空时,goto到retry标志处,否则往下执行
if (!binder_worklist_empty_ilocked(&thread->todo))
list = &thread->todo;
else if (!binder_worklist_empty_ilocked(&proc->todo) &&
wait_for_proc_work)
list = &proc->todo;
else {
binder_inner_proc_unlock(proc);
/* no data added */
if (ptr - buffer == 4 && !thread->looper_need_return)
goto retry;
break;
}
...
switch (w->type) {
case BINDER_WORK_TRANSACTION:
case BINDER_WORK_RETURN_ERROR: ...
case BINDER_WORK_TRANSACTION_COMPLETE: ...
case BINDER_WORK_NODE: ...
case BINDER_WORK_DEAD_BINDER:
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: ...
}

done:
*consumed = ptr - buffer;
binder_inner_proc_lock(proc);
//当满足请求线程已准备线程数等于0,已启动线程数小于最大线程数15
//且looper状态为已经注册或者已进入时创建新的线程
if (proc->requested_threads == 0 &&
list_empty(&thread->proc->waiting_threads) &&
proc->requested_threads_started < proc->max_threads &&
(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
/*spawn a new thread if we leave this out */) {
proc->requested_threads++;
binder_inner_proc_unlock(proc);
binder_debug(BINDER_DEBUG_THREADS,
"%d:%d BR_SPAWN_LOOPER\n",
proc->pid, thread->pid);
//生成BR_SPAWN_LOOPER命令,用于创建新的线程
if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
return -EFAULT;
binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
} else
binder_inner_proc_unlock(proc);
return 0;
}

当transaction堆栈为空且线程todo链表为空,且non_block=false时,则意味着没有任何事物需要处理,会进入等待客户端请求的状态。当有事务需要处理时便会进入循环处理过程,并生成相应的响应码。在Binder驱动层,只有在进入binder_thread_read方法时,同时满足以下条件才会生成BR_SPAWN_LOOPER命令,当用户态进程收到该命令则会创建新的线程。

1.binder_proc的requested_threads线程数等于0;

2.binder_proc的waiting_threads的列表为空;

3.binder_proc的requested_threads_started个数小于15即最大线程个数;

4.binder_thead的looper状态为BINDER_LOOPER_STATE_REGISTERED或BINDER_LOOPER_STATE_ENTERED。

响应码的处理(文章注册Servicemanager中),在用户空间的 IPCThreadState类中的 IPCThreadState::waitForResponse和 IPCThreadState::executeCommand两个方法共同处理Binder协议中的响应码。

3.3.1 BR_PROTOCOL

Binder响应码,在binder_driver_return_protocol中定义,是binder设备向应用程序回复的消息,应用程序包括client和server端,以BR_开头,总共18条。

响应码 参数类型 作用
BR_ERROR __s32 操作发送错误
BR_OK 无参数 操作完成
BR_TRANSACTION binder_transaction_data Binder驱动向Server发送的请求数据
BR_REPLY binder_transaction_data Binder驱动向Client发送的回复数据
BR_ACQUIRE_RESULT __s32 暂时不支持
BR_DEAD_REPLY 无参数 回复失败,线程或节点为空
BR_TRANSACTION_COMPLETE 无参数 对请求发送的成功反馈
BR_INCREFS binder_ptr_cookie binder_ref弱引用加1操作
BR_ACQUIRE binder_ptr_cookie binder_ref弱引用减1操作
BR_RELEASE binder_ptr_cookie binder_ref强引用加1操作
BR_DECREFS binder_ptr_cookie binder_ref强引用减1操作
BR_ATTEMPT_ACQUIRE binder_pri_ptr_cookie 暂时不支持
BR_NOOP 无参数 不做任何事情
BR_SPAWN_LOOPER 无参数 创建新的Looper线程
BR_FINISHED 无参数 暂时不支持
BR_DEAD_BINDER binder_uintptr_t Binder驱动向client发送死亡通知
BR_CLEAR_DEATH_NOTIFICATION_DONE binder_uintptr_t 清除死亡通知
BR_FAILED_REPLY 无参数 回复失败,transaction出错导致

BR_SPAWN_LOOPER:binder驱动已经检测到进程中没有线程等待即将到来的事务,那么当一个进程接受到这条命令时,该进程必须创建一个新的服务线程并注册该线程,在接下来的响应过程会看到何时生成该响应码。

BR_TRANSACTION_COMPLETE:当Client端向Binder驱动发送BC_TRANSACTION命令后,Client会收到BR_TRANSACTION_COMPLETE命令,告知Client端请求命令发送成功;对于Server向Binder驱动发送BC_REPLY命令后,server端会收到BR_TRANSACTION_COMPLETE命令,告知Server端请求回应命令发送成功。

BR_DEAD_REPLY:当应用层向Binder驱动发送Binder调用时,若Binder应用层的另一个端已经死亡,则驱动回应BR_DEAD_REPLY命令。

BR_FAILED_REPLY:当应用层向Binder驱动发送Binder调用时,若transaction出错,比如调用的函数号不存在,则驱动回应BR_FAILED_REPLY。

3.4 协议使用场景

3.4.1 BC协议

BC协议 调用方法
BC_TRANSACTION IPC.transact()
BC_REPLY IPC.sendReply()
BC_FREE_BUFFER IPC.freeBuffer()
BC_REQUEST_DEATH_NOTIFICATION IPC.requestDeathNotification()
BC_CLEAR_DEATH_NOTIFICATION IPC.clearDeathNotification()
BC_DEAD_BINDER_DONE IPC.execute()

binder_thread_write()根据不同的BC协议而执行不同的流程。 其中BC_TRANSACTION和BC_REPLY协议,会进入binder_transaction()过程。

3.4.2 BR协议

BR协议 触发时机
BR_TRANSACTION 收到BINDER_WORK_TRANSACTION
BR_REPLY 收到BINDER_WORK_TRANSACTION
BR_TRANSACTION_COMPLETE 收到BINDER_WORK_TRANSACTION_COMPLETE
BR_DEAD_BINDER 收到BINDER_WORK_DEAD_BINDER或BINDER_WORK_DEAD_BINDER_AND_CLEAR
BR_CLEAR_DEATH_NOTIFICATION_DONE 收到BINDER_WORK_CLEAR_DEATH_NOTIFICATION

BR_DEAD_REPLY,BR_FAILED_REPLY,BR_ERROR这些都是失败或错误相关的应答协议。

3.4.3 协议转换图

以BC_TRANSACTION为例,说明协议转换过程。

  • 发起端进程:binder_transaction()过程将BC_TRANSACTION转换为BW_TRANSACTION;
  • 接收端进程:binder_thread_read()过程,将BW_TRANSACTION转换为BR_TRANSACTION;
  • 接收端进程:IPC.execute()过程,处理BR_TRANSACTION命令。

注:BINDER_WORK_xxx –> BW_xxx

binder_procol1

binder_procol2

四、Binder内存机制

binder_mmap是Binder进程间通信的高效的核心机制所在,其模型如下:

内存模型

虚拟进程地址空间(vm_area_struct)和虚拟内核地址空间(vm_struct)都映射到同一块物理内存空间。当client端与server端发送数据时,client作为数据发送端,先从自己的进程空间把IPC通信数据copy_from_user拷贝到内核空间,而server端作为数据接收端,与内核共享数据,不再需要拷贝数据,而是通过内存地址空间的偏移量获取内存地址,整个过程只发生一次内存拷贝。一般的做法,需要Client端进程空间拷贝到内核空间,再由内核空间拷贝到server进程空间,会发生两次拷贝。

binder内存转换

对于进程和内核虚拟地址映射到同一个物理内存的操作(通过地址偏移量来实现)是发生在数据接收端,而数据发送端还是需要将用户态的数据复制到内核态。为什么不直接让发送端和接收端直接映射到同一块物理空间,那样连一次复制的操作都不需要,0次复制那就和Linux标准内核的共享内存IPC没有区别了,对于共享内存虽然效率高,但是对于多进程同步的问题比较复杂,而管道/消息队列等IPC需要复制两次,效率较低。总之Android选择Binder是基于速度和安全性的考虑。

附录

下面列举Binder驱动相关的一些重要结构体

结构体列表

序号 结构体 名称 解释
1 binder_proc binder进程 每个进程调用open()打开binder驱动都会创建该结构体,用于管理IPC所需的各种信息
2 binder_thread binder线程 对应于上层的binder线程
3 binder_node binder实体 对应于BBinder对象,记录BBinder的进程、指针、引用计数等
4 binder_ref binder引用 对应于BpBinder对象,记录BpBinder的引用计数、死亡通知、BBinder指针等
5 binder_ref_death binder死亡引用 记录binder死亡的引用信息
6 binder_write_read binder读写 记录buffer中读和写的数据信息
7 binder_transaction_data binder事务数据 记录传输数据内容,比如发送方pid/uid,RPC数据
8 flat_binder_object binder扁平对象 Binder对象在两个进程间传递的扁平结构
9 binder_buffer binder内存 调用mmap()创建用于Binder传输数据的缓存区
10 binder_transaction binder事务 记录传输事务的发送方和接收方线程、进程等
11 binder_work binder工作 记录binder工作类型
12 binder_state binder状态

6~9 用于数据传输相关,其中binder_write_read,binder_transaction_data进程空间和内核空间是通用的。

BWR核心数据表

bwr

binder_write_read是整个Binder IPC过程,最为核心的数据结构之一。

1.binder_proc

binder_proc结构体:用于管理IPC所需的各种信息,拥有其他结构体的结构体。

类型 成员变量 解释
struct hlist_node proc_node 进程节点
struct rb_root threads binder_thread红黑树的根节点
struct rb_root nodes binder_node红黑树的根节点
struct rb_root refs_by_desc binder_ref红黑树的根节点(以handle为key)
struct rb_root refs_by_node binder_ref红黑树的根节点(以ptr为key)
int pid 相应进程id
struct vm_area_struct * vma 指向进程虚拟地址空间的指针
struct mm_struct * vma_vm_mm 相应进程的内存结构体
struct task_struct * tsk 相应进程的task结构体
struct files_struct * files 相应进程的文件结构体
struct hlist_node deferred_work_node
int deferred_work
void * buffer 内核空间的起始地址
ptrdiff_t user_buffer_offset 内核空间与用户空间的地址偏移量
struct list_head buffers 所有的buffer
struct rb_root free_buffers 空闲的buffer
struct rb_root allocated_buffers 已分配的buffer
size_t free_async_space 异步的可用空闲空间大小
struct page ** pages 指向物理内存页指针的指针
size_t buffer_size 映射的内核空间大小
uint32_t buffer_free 可用内存总大小
struct list_head todo 进程将要做的事
wait_queue_head_t wait 等待队列
struct binder_stats stats binder统计信息
struct list_head delivered_death 已分发的死亡通知
int max_threads 最大线程数
int requested_threads 请求的线程数
int requested_threads_started 已启动的请求线程数
int ready_threads 准备就绪的线程个数
long default_priority 默认优先级
struct dentry * debugfs_entry
  • free_buffers:记录所有空闲的buffer,记录以buffer_size为key的binder_buffer的红黑树结构
  • allocated_buffers:记录所有已分配的buffer,记录以buffer_size为key的binder_buffer的红黑树结构
  • buffers: 所有buffer(包含空闲的和已分配的buffer)的按地址由从低到高都连入到buffers链表中
  • ready_threads: 准备就绪的线程个数,往往是指进入binder_thread_read(),处于休眠等待状态的线程个数;ready_threads线程个数越多,代表系统越空闲。
  • requested_threads_started:是指系统已经启动的线程个数,在方法binder_thread_write()中,执行一次BC_REGISTER_LOOPER,则requested_threads_started++,requested_threads–;上限为max_threads.BC_REGISTER_LOOPER次数与requested_threads_started个数应该相等;
  • requested_threads:请求的线程个数,在方法binder_thread_read()中,当同时满足requested_threads_started小于最大线程数,没有ready_threads线程,且requested_threads=0,则执行requested_threads++。可见requested_threads取值要么为0,要么为1.

2.binder_thread

binder_thread结构体代表当前binder操作所在的线程

类型 成员变量 解释
struct binder_proc * proc 线程所属的进程
struct rb_node rb_node
int pid 线程pid
int looper looper的状态
struct binder_transaction * transaction_stack 线程正在处理的事务
struct list_head todo 将要处理的链表
uint32_t return_error write失败后,返回的错误码
uint32_t return_error2 write失败后,返回的错误码2
wait_queue_head_t wait 等待队列的队头
struct binder_stats stats binder线程的统计信息

looper的状态如下:

1
2
3
4
5
6
7
8
enum {
BINDER_LOOPER_STATE_REGISTERED = 0x01, // 创建注册线程BC_REGISTER_LOOPER
BINDER_LOOPER_STATE_ENTERED = 0x02, // 创建主线程BC_ENTER_LOOPER
BINDER_LOOPER_STATE_EXITED = 0x04, // 已退出
BINDER_LOOPER_STATE_INVALID = 0x08, // 非法
BINDER_LOOPER_STATE_WAITING = 0x10, // 等待中
BINDER_LOOPER_STATE_NEED_RETURN = 0x20, // 需要返回
};

binder_thread_write()过程:

  • 收到 BC_REGISTER_LOOPER,则线程状态为BINDER_LOOPER_STATE_REGISTERED;
  • 收到 BC_ENTER_LOOPER,则线程状态为 BINDER_LOOPER_STATE_ENTERED;
  • 收到 BC_EXIT_LOOPER, 则线程状态为BINDER_LOOPER_STATE_EXITED;

其他3个状态的时机:

  • BINDER_LOOPER_STATE_WAITING:
    • 当停留在binder_thread_read()的wait_event_xxx过程, 则设置该状态;
  • BINDER_LOOPER_STATE_NEED_RETURN:
    • binder_get_thread()过程, 根据binder_proc查询不到当前线程所对应的binder_thread,会新建binder_thread对象;
    • binder_deferred_flush()过程;
  • BINDER_LOOPER_STATE_INVALID:
    • 当binder_thread创建过程状态不正确时会设置.

3.binder_node

binder_node代表一个binder实体

类型 成员变量 解释
int debug_id 节点创建时分配,具有全局唯一性,用于调试使用
struct binder_work work
struct rb_node rb_node binder节点正常使用,union
struct hlist_node dead_node binder节点已销毁,union
struct binder_proc * proc binder所在的进程
struct hlist_head refs 所有指向该节点的binder引用队列
int internal_strong_refs
int local_weak_refs
int local_strong_refs
binder_uintptr_t ptr 指向用户空间binder_node的指针
binder_uintptr_t cookie 附件数据
unsigned has_strong_ref 占位1bit
unsigned pending_strong_ref 占位1bit
unsigned has_weak_ref 占位1bit
unsigned pending_weak_ref 占位1bit
unsigned has_async_transaction 占位1bit
unsigned accept_fds 占位1bit
unsigned min_priority 占位8bit,最小优先级
struct list_head async_todo 异步todo队列

binder_node有一个联合类型:

1
2
3
4
union {
struct rb_node rb_node;
struct hlist_node dead_node;
};

当Binder对象已销毁,但还存在该Binder节点引用,则采用dead_node,并加入到全局列表binder_dead_nodes;否则使用rb_node节点。

另外:

  • binder_node.ptr对应于flat_binder_object.binder;
  • binder_node.cookie对应于flat_binder_object.cookie。

4.binder_ref

类型 成员变量 解释
int debug_id 用于调试使用
struct rb_node rb_node_desc 以desc为索引的红黑树
struct rb_node rb_node_node 以node为索引的红黑树
struct hlist_node node_entry
struct binder_proc * proc binder进程
struct binder_node * node binder节点
uint32_t desc handle
int strong 强引用次数
int weak 弱引用次数
struct binder_ref_death * death 当应用注册死亡通知时,此域不为空

binder引用的查询方式如下:

  • node + proc => ref (transaction)
  • desc + proc => ref (transaction, inc/dec ref)
  • node => refs + procs (proc exit)

5. binder_ref_death

1
2
3
4
struct binder_ref_death {
struct binder_work work;
binder_uintptr_t cookie;
};

cookie只是死亡通知的BpBinder代理对象的指针

6.binder_write_read

用户空间程序和Binder驱动程序交互基本都是通过BINDER_WRITE_READ命令,来进行数据的读写操作。

类型 成员变量 解释
binder_size_t write_size write_buffer的总字节数
binder_size_t write_consumed write_buffer已消费的字节数
binder_uintptr_t write_buffer 写缓冲数据的指针
binder_size_t read_size read_buffer的总字节数
binder_size_t read_consumed read_buffer已消费的字节数
binder_uintptr_t read_buffer 读缓存数据的指针
  • write_buffer变量:用于发送IPC(或IPC reply)数据,即传递经由Binder Driver的数据时使用。
  • read_buffer 变量:用于接收来自Binder Driver的数据,即Binder Driver在接收IPC(或IPC reply)数据后,保存到read_buffer,再传递到用户空间;

write_buffer和read_buffer都是包含Binder协议命令和binder_transaction_data结构体。

  • copy_from_user()将用户空间IPC数据拷贝到内核态binder_write_read结构体;
  • copy_to_user()将用内核态binder_write_read结构体数据拷贝到用户空间;

7.binder_transaction_data

当BINDER_WRITE_READ命令的目标是本地Binder node时,target使用ptr,否则使用handle。只有当这是Binder node时,cookie才有意义,表示附加数据,由进程自己解释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct binder_transaction_data {
union {
__u32 handle; //binder_ref(即handle)
binder_uintptr_t ptr; //Binder_node的内存地址
} target; //RPC目标
binder_uintptr_t cookie; //BBinder指针
__u32 code; //RPC代码,代表Client与Server双方约定的命令码

__u32 flags; //标志位,比如TF_ONE_WAY代表异步,即不等待Server端回复
pid_t sender_pid; //发送端进程的pid
uid_t sender_euid; //发送端进程的uid
binder_size_t data_size; //data数据的总大小
binder_size_t offsets_size; //IPC对象的大小

union {
struct {
binder_uintptr_t buffer; //数据区起始地址
binder_uintptr_t offsets; //数据区IPC对象偏移量
} ptr;
__u8 buf[8];
} data; //RPC数据
};
  • target: 对于BpBinder则使用handle,对于BBinder则使用ptr,故使用union数据类型来表示;
  • code: 比如注册服务过程code为ADD_SERVICE_TRANSACTION,又比如获取服务code为CHECK_SERVICE_TRANSACTION
  • data:代表整个数据区,其中data.ptr指向的是传递给Binder驱动的数据区的起始地址,data.offsets指的是数据区中IPC数据地址的偏移量。
  • cookie: 记录着BBinder指针。
  • data_size:代表本次传输的parcel数据的大小;
  • offsets_size: 代表传递的IPC对象的大小;根据这个可以推测出传递了多少个binder对象。
    • 对于64位IPC,一个IPC对象大小等于8;
    • 对于32位IPC,一个IPC对象大小等于4;

8.flat_binder_object

flat_binder_object结构体代表Binder对象在两个进程间传递的扁平结构。

类型 成员变量 解释
__u32 type 类型
__u32 flags 记录优先级、文件描述符许可
binder_uintptr_t binder (union)当传递的是binder_node时使用,指向binder_node在应用程序的地址
__u32 handle (union)当传递的是binder_ref时使用,存放Binder在进程中的引用号
binder_uintptr_t cookie 只对binder_node有效,存放binder_node的额外数据

此处的类型type的可能取值来自于enum,成员如下:

成员变量 解释
BINDER_TYPE_BINDER binder_node的强引用
BINDER_TYPE_WEAK_BINDER binder_node的弱引用
BINDER_TYPE_HANDLE binder_ref强引用
BINDER_TYPE_WEAK_HANDLE binder_ref弱引用
BINDER_TYPE_FD binder文件描述符

说明:

  • 当type等于BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER类型时, 代表Server进程向ServiceManager进程注册服务,则创建binder_node对象;
  • 当type等于BINDER_TYPE_HANDLE或BINDER_TYPE_WEAK_HEANDLE类型时, 代表Client进程向Server进程请求代理,则创建binder_ref对象;
  • 当type等于BINDER_TYPE_FD类型时, 代表进程向另一个进程发送文件描述符,只打开文件,则无需创建任何对象。

9.binder_buffer

每一次Binder传输数据时,都会先从Binder内存缓存区中分配一个binder_buffer来存储传输数据。

类型 成员变量 解释
struct list_head entry buffer实体的地址
struct rb_node rb_node buffer实体的地址
unsigned free 标记是否是空闲buffer,占位1bit
unsigned allow_user_free 是否允许用户释放,占位1bit
unsigned async_transaction 占位1bit
unsigned debug_id 占位29bit
struct binder_transaction * transaction 该缓存区的需要处理的事务
struct binder_node * target_node 该缓存区所需处理的Binder实体
size_t data_size 数据大小
size_t offsets_size 数据偏移量
uint8_t data[0] 数据地址

每一个binder_buffer分为空闲和已分配的,通过free标记来区分。空闲和已分配的binder_buffer通过各自的成员变量rb_node分别连入binder_proc的free_buffers(红黑树)和allocated_buffers(红黑树)。

10.binder_transaction

类型 成员变量 解释
int debug_id 用于调试
struct binder_work work binder工作类型
struct binder_thread * from 发送端线程
struct binder_transaction * from_parent 上一个事务
struct binder_proc * to_proc 接收端进程
struct binder_thread * to_thread 接收端线程
struct binder_transaction * to_parent 下一个事务
unsigned need_reply 是否需要回复
struct binder_buffer * buffer 数据buffer
unsigned int code 通信方法,比如startService
unsigned int flags 标志,比如是否oneway
long priority 优先级
long saved_priority 保存的优先级
kuid_t sender_euid 发送端uid

执行binder_transaction()过程创建的结构体

  • debug_id:是一个全局静态变量,每当创建一个binder_transactionbinder_nodebinder_ref对象,则++debug_id
  • from与to_thread是一对,分别是发送端线程和接收端线程;
  • from_parent与to_parent是一对,分别是上一个和下一个binder_transaction,组成一个链表。
    • 执行binder_transaction()方法过程,当非oneway的BC_TRANSACTION时,则设置当前事务t->from_parent等于当前线程的transaction_stack;
    • 执行binder_thread_read()方法过程,当非oneway的BR_TRANSACTION时,则设置当前事务t->to_parent等于当前线程的transaction_stack;

11.binder_work

1
2
3
4
5
6
7
8
9
10
11
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.type设置时机:

  • binder_transaction()
  • binder_thread_write()
  • binder_new_node()

12.binder_state

类型 成员变量 解释
int fd 文件描述符
void * mapped 映射到进程空间的起始地址
size_t mapsize 内存空间的映射大小