binder-服务的注册流程

驱动服务的流程就不做代码讲解了,我整理了一个流程图

用户态的程序调用Kernel层驱动是需要陷入内核态,进行系统调用(syscall),比如打开Binder驱动方法的调用链为: open-> __open() -> binder_open(),像ioctl就会调用到binder_ioctl,它们的通信是通过 syscall实现的,感兴趣的可以去了解,笔者不做分析

接下来开始分析服务注册过程

先介绍一下binder中的一些概念 Binder 协议

Binder协议基本格式是(命令+数据),使用ioctl(fd, cmd, arg)函数实现交互。命令由参数cmd承载,数据由参数arg承载,随cmd不同而不同

命令 含义
BINDER_WRITE_READ 该命令向Binder写入或读取数据。参数分为两段:写部分和读部分。如果write_size不为0就先将write_buffer里的数据写入Binder;如果read_size不为0再从Binder中读取数据存入read_buffer中。write_consumed和read_consumed表示操作完成时Binder驱动实际写入或读出的数据个数
BINDER_SET_MAX_THREADS 该命令告知Binder驱动接收方(通常是Server端)线程池中最大的线程数。由于Client是并发向Server端发送请求的,Server端必须开辟线程池为这些并发请求提供服务。告知驱动线程池的最大值是为了让驱动发现线程数达到该值时不要再命令接收端启动新的线程。
BINDER_SET_CONTEXT_MGR 将当前进程注册为SMgr。系统中同时只能存在一个SMgr。只要当前的SMgr没有调用close()关闭Binder驱动就不能有别的进程可以成为SMgr。
BINDER_THREAD_EXIT 通知Binder驱动当前线程退出了。Binder会为所有参与Binder通信的线程(包括Server线程池中的线程和Client发出请求的线程)建立相应的数据结构。这些线程在退出时必须通知驱动释放相应的数据结构。
BINDER_VERSION 获得Binder驱动的版本号

上面是在使用 ioctl 用到的命令,最常用的是 BINDER_WRITE_READ,在 binder中写操作,也会用到 cmd
命令很多,具体可以取 https://blog.csdn.net/universus/article/details/6211589 查看

只要记住,BR_TRANSACTION ,BR_REPLY,BC_TRANSACTION ,BC_REPLY这四个涉及到两个进程,其他所有的cmd都是应用程序和驱动的交互,改变状态等

先放上总体的流程结构图

从 service_manager.c 文件的 main 函数入手

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int main(int argc, char** argv)
{
struct binder_state *bs;
union selinux_callback cb;
char *driver;
if (argc > 1) {
driver = argv[1];
} else {
driver = "/dev/binder";
}
bs = binder_open(driver, 128*1024);
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
selinux_status_open(true);
binder_loop(bs, svcmgr_handler);
return 0;
}

首先是打开驱动 binder_open(driver, 128*1024),来获取驱动的信息
binder_open中调用了 ioctl,传入的 cmd 是 BINDER_VERSION

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
struct binder_state *bs;
struct binder_version vers;
bs = malloc(sizeof(*bs));
bs->fd = open(driver, 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);
if (bs->mapped == MAP_FAILED) {
goto fail_map;
}

return bs;
}

调用 binder_become_context_manager ,它同样也会调用 ioctl,它传入的 cmd 是 BINDER_SET_CONTEXT_MGR

1
2
3
4
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}

因为在linux层的代码和在binder层的各个函数之间相对应,所以函数 binder_open 的 ioctl 最终会调用到 linux层的 binder_open

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static int binder_open(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc;
struct binder_device *binder_dev;
//分配一个 proc,这是之前讲数据结构的时候出现的,代表进程的结构体
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
if (proc == NULL)
return -ENOMEM;
......
//task等于当前进程
proc->tsk = current->group_leader;
......
//进程的父ID
proc->pid = current->group_leader->pid;
......
return 0;
}

新创建的binder_proc会被记录在参数filp的private_data域中,以后每次执行binder_ioctl(),都会从filp->private_data域重新读取binder_proc的

下面就是最为核心的 ioctl,找到linux层的对应代码 binder_ioctl

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
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;

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;

//实例化线程 初始化一些线程信息,以及进程的信息存放在线程的结构体中
//从进程proc中的 threads.rb_node 红黑树中查找线程 struct rb_node **p = &proc->threads.rb_node;
thread = binder_get_thread(proc);
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
//一大堆的命令处理 case ... case ...
}
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;
}

在main函数中的 binder_loop 中会调用 binder_write, binder_write 调用linux 层的 binder_thread_write,找到该函数中 BC_ENTER_LOOPER 语句节点是

1
2
3
4
5
6
case BC_ENTER_LOOPER:
if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {
thread->looper |= BINDER_LOOPER_STATE_INVALID;
}
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;

就像之前说的,除了那四个 cmd ,其他都是做状态的更改等,这就是一个例子

继续分析 binder_loop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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));
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;

res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
}
}

在binder_loop 中,它的写操作数据为 0 ,所以它应该是一个读操作

进入linux 内核代码,前面代码可以看到,cmd是 BINDER_WRITE_READ 的时候,调用的是 binder_ioctl_write_read

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
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 (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 (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}

由于 bwr.read_size > 0 ,进入 binder_thread_read 函数

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
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;

//在应用层的代码中设置为 0 所以第一次肯定是 0
/**bwr.read_size = sizeof(readbuf);
* bwr.read_consumed = 0;
* bwr.read_buffer = (uintptr_t) readbuf;
* res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
*/
if (*consumed == 0) {
//
if (put_user(BR_NOOP, (uint32_t __user *)ptr))
return -EFAULT;
//进行指针的位置移动
ptr += sizeof(uint32_t);
}
......
}

从上面的代码可以得出一个结论,对于所有的读操作,数据头都是 BR_NOOP

同时我们还可以大致画出 bwr中readbuff真实数据的结构

继续看下面的代码

假设没有数据,那么它就会休眠,调用 wait_event_interruptible binder_wait_for_work

1
2
3
4
5
6
if (non_block) {
if (!binder_has_work(thread, wait_for_proc_work))
ret = -EAGAIN;
} else {
ret = binder_wait_for_work(thread, wait_for_proc_work);
}

休眠的时候,就会等待server来注册服务

根据我们之前写的 test_server的代码,可以知道它是如何注册服务的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr)
{
int status;
unsigned iodata[512/4];
struct binder_io msg, reply;

bio_init(&msg, iodata, sizeof(iodata), 4);
bio_put_uint32(&msg, 0); // strict mode header
bio_put_string16_x(&msg, SVC_MGR_NAME);
bio_put_string16_x(&msg, name);
bio_put_obj(&msg, ptr);

if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
return -1;

status = bio_get_uint32(&reply);

binder_done(bs, &msg, &reply);

return status;
}

我们会着重分析这部分的代码

先给大家奉上它的内存结构图

首先是 bio_init,开辟出内存空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void bio_init(struct binder_io *bio, void *data,
size_t maxdata, size_t maxoffs)
{
// 4*4 16个字节
size_t n = maxoffs * sizeof(size_t);

if (n > maxdata) {
bio->flags = BIO_F_OVERFLOW;
bio->data_avail = 0;
bio->offs_avail = 0;
return;
}
//前面16个字节 后面放入 data 数据 data0指向 16个字节+data数据大小
bio->data = bio->data0 = (char *) data + n;
//从第16个字节开始
bio->offs = bio->offs0 = data;
//可用的大小 针对于flat_binder_object
//512/4 = 128个字节
bio->data_avail = maxdata - n;
// 4个字节
bio->offs_avail = maxoffs;
bio->flags = 0;
}

然后是 bio_put_uint32(&msg, 0); 追加数据 放入4个字节的0
uint32是无符号32位整型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void bio_put_uint32(struct binder_io *bio, uint32_t n)
{
uint32_t *ptr = bio_alloc(bio, sizeof(n));
if (ptr)
//指向 n 变量的这个地址 也就是把指针位置移动到 n 部分
*ptr = n;
}

static void *bio_alloc(struct binder_io *bio, size_t size)
{
size = (size + 3) & (~3);
//可用大小每次都会减少
if (size > bio->data_avail) {
bio->flags |= BIO_F_OVERFLOW;
return NULL;
} else {
void *ptr = bio->data;
//往 data 的后面追加数据
bio->data += size;
bio->data_avail -= size;
return ptr;
}
}

接下来看 bio_put_string16_x(&msg, SVC_MGR_NAME);

string16是用16位来表示一个字符,也就是2个字节,当然它这只是名字上这样理解,实际的存放不是只有2个字节的

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
void bio_put_string16_x(struct binder_io *bio, const char *_str)
{
unsigned char *str = (unsigned char*) _str;
size_t len;
uint16_t *ptr;

if (!str) {
//为空就直接放入 0xffffffff
bio_put_uint32(bio, 0xffffffff);
return;
}

len = strlen(_str);

if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) {
bio_put_uint32(bio, 0xffffffff);
return;
}

/* Note: The payload will carry 32bit size instead of size_t */
//刚才分析过,占4个字节 这里的长度是固定的 SVC_MGR_NAME = android.os.IServiceManager = 26个字符
//也就是用4个字节放值为26的 uint32_t 26的十六进制为 1A
bio_put_uint32(bio, len);
// 申请(26+1) * 2 = 54 字节 的空间 一个字符两个字节 最后两个直接放结尾符
// a 的 16进制是 61 n 16进制是 6e
ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t));
if (!ptr)
return;

while (*str)
*ptr++ = *str++;
*ptr++ = 0;
}

同理,bio_put_string16_x(&msg, name);和上一步的存放规则一样

然后看 bio_put_obj(&msg, ptr);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void bio_put_obj(struct binder_io *bio, void *ptr)
{
struct flat_binder_object *obj;

obj = bio_alloc_obj(bio);
if (!obj)
return;

obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
obj->hdr.type = BINDER_TYPE_BINDER;
//自己编写server时我们实现的 hello_handler
obj->binder = (uintptr_t)ptr;
obj->cookie = 0;
}

发现了一个很重要的结构体 flat_binder_object

flat_binder_object的声明在内核中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct flat_binder_object {
struct binder_object_header hdr;
__u32 flags;

/* 8 bytes of data. */
//联合体 只占一个位置 两者共用
union {
binder_uintptr_t binder; /* local object */
__u32 handle; /* remote object */
};

/* extra data associated with local object */
binder_uintptr_t cookie;
};

可以在flat_binder_object中搜索到 BINDER_TYPE_BINDER

1
2
3
4
5
6
7
8
#define B_PACK_CHARS(c1, c2, c3, c4) \
((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
#define B_TYPE_LARGE 0x85

enum {
BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
......
};

B_PACK_CHARS 是一个宏,B_TYPE_LARGE 是一个字节 8位,前面3个都是进行位操作,所以总共 4 个字节

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
static struct flat_binder_object *bio_alloc_obj(struct binder_io *bio)
{
struct flat_binder_object *obj;

obj = bio_alloc(bio, sizeof(*obj));

//检查位操作 如果位置到了 offs_avail 的大小位置
if (obj && bio->offs_avail) {
bio->offs_avail--;
/**
*
* //前面16个字节 后面放入 data 数据 data0指向 16个字节+data数据大小的末尾
* bio->data = bio->data0 = (char *) data + n;
* //从第16个字节开始
* bio->offs = bio->offs0 = data;
* //maxdata = 512/4 = 128个字节
* bio->data_avail = maxdata - n;
* // 4个字节
* bio->offs_avail = maxoffs;
*
* /
*bio->offs++ = ((char*) obj) - ((char*) bio->data0);
return obj;
}

bio->flags |= BIO_F_OVERFLOW;
return NULL;
}

那么当我们把数据发送给驱动的时候,驱动是如何找到这些 flat_binder_object 的

bio_alloc_obj的代码中我们可以看到之前用过的 offs,但是前面那16个字节,他是每4个字节放一个指向 flat_binder_object 的指针, flat_binder_object 的实际数据还是追加在 data 的后面,前面16个字节,最多只能放 4 个 flat_binder_object,所以最多只能传 4 个 flat_binder_object 给binder驱动

现在再回头来看看结构图,是否更加容易理解了

数据封装好后,就是调用 binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)

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
int binder_call(struct binder_state *bs,
struct binder_io *msg, struct binder_io *reply,
uint32_t target, uint32_t code)
{
int res;
//根据 binder_io 构造 binder_write_read,会直接传给驱动程序
struct binder_write_read bwr;
struct {
// 命令
uint32_t cmd;
//指向具体数据
struct binder_transaction_data txn;
} __attribute__((packed)) writebuf;
unsigned readbuf[32];

if (msg->flags & BIO_F_OVERFLOW) {
fprintf(stderr,"binder: txn buffer overflow\n");
goto fail;
}

// 这个 BC_TRANSACTION 就是之前提到的那四个重要的 cmd
writebuf.cmd = BC_TRANSACTION;
writebuf.txn.target.handle = target;
// 调用srever_manager中的哪个函数
writebuf.txn.code = code;
writebuf.txn.flags = 0;
//data的实际大小 出了前面那16个字节
writebuf.txn.data_size = msg->data - msg->data0;
// 传入的flat_binder_object大小,我们传一个,就是4字节
writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0);
//指向data的首地址
writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0;
//指向 offs 首地址 ,也是data的首地址,最开始的那部分
writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0;

bwr.write_size = sizeof(writebuf);
bwr.write_consumed = 0;
bwr.write_buffer = (uintptr_t) &writebuf;

hexdump(msg->data0, msg->data - msg->data0);
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;

res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

if (res < 0) {
fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno));
goto fail;
}

res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0);
if (res == 0) return 0;
if (res < 0) goto fail;
}
}

ioctl就会进入驱动层,也就是内核态,进入linux的 binder_ioctl,它的主要功能就是把数据放入目的进程的todo链表并唤醒该进程

  • 根据handle找到目的进程(我们这里分析的目的进程是 servicemanager)
  • 把数据通过copy_from_user复制到mmap空间
  • 唤醒目的进程

我们又要回到那个复杂的 binder_ioctl 了,前面的文章我们也分析过ioctl了

应用层传的cmd是 BINDER_WRITE_READ ,所以我们只关心 BINDER_WRITE_READ

1
2
3
4
5
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
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
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 (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}

//我们要发数据 所以他要写数据 bwr.write_size = sizeof(writebuf);
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
//这里是前面分析过的 读数据
......
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}

进入 binder_thread_write

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
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)
{
//这里我们只关心 cmd=BC_TRANSACTION
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;

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_TRANSACTION:
case BC_REPLY: {
// 该结构体存放真实数据
struct binder_transaction_data tr;
// 把数据拷贝到 ptr中
if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr,
cmd == BC_REPLY, 0);
break;
}
}
*consumed = ptr - buffer;
}
return 0;
}

然后进入函数 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
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
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
struct binder_transaction *t;
......

if (reply) {
//我们传过来的 reply是 0 ,所以这里不需要关心
} else {
//如果传进来的handle不是 0
//注意这边要区分 target,它代表目的进程
if (tr->target.handle) {
struct binder_ref *ref;
//从当前进程中去根据传过来的handle去找binder_ref ,是一个红黑树查找
// 在 proc->refs_by_desc.rb_node 中查找
ref = binder_get_ref(proc, tr->target.handle);
......
// 找到 binder_ref 就能够找到 node
target_node = ref->node;
} else {
// 传进来的 handle 是0 ,代表他是 serviceManager
//会把目标进程的 node 直接赋值
// binder_context_mgr_node 是在 BINDER_SET_CONTEXT_MGR 时设置的,并且会创建node(表示服务的结构体)
target_node = binder_context_mgr_node;
if (target_node == NULL) {
return_error = BR_DEAD_REPLY;
goto err_no_context_mgr_node;
}
}
e->to_node = target_node->debug_id;
//之后就可以获取到目的进程的 proc 结构体 很关键
// 找到目的进程后 就需要把数据拷贝给目的进程所映射的mmap空间里
target_proc = target_node->proc;
......
}
......
// 重点在这 把目的进程所映射的空间分配出一个内存给buffer
// 那么之后操作这个buffer 就是操作目的进程的空间数据
t->buffer = binder_alloc_buf(target_proc, tr->data_size,
tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
......

offp = (binder_size_t *)(t->buffer->data +
ALIGN(tr->data_size, sizeof(void *)));

//拷贝数据的 data 部分 t 这时候已经指向了目的进程的空间
if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
tr->data.ptr.buffer, tr->data_size)) {
binder_user_error("%d:%d got transaction with invalid data ptr\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
// 拷贝数据的 offs 部分,前面那 16 个字节
if (copy_from_user(offp, (const void __user *)(uintptr_t)
tr->data.ptr.offsets, tr->offsets_size)) {
binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) {
binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n",
proc->pid, thread->pid, (u64)tr->offsets_size);
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
off_end = (void *)offp + tr->offsets_size;
// offp 就是指我们的 flat_binder_object 因为最多可能有 4 个 ,所以循环处理每一个
for (; offp < off_end; offp++) {
//这部分代码下面分析
}
......
t->work.type = BINDER_WORK_TRANSACTION;
// 放到目的进程的todo链表 target_list 是一个 thread.todo
list_add_tail(&t->work.entry, target_list);
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);
if (target_wait)
wake_up_interruptible(target_wait);
return;
}

分析如何处理 flat_binder_object

首先需要清楚 flat_binder_object 的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct flat_binder_object {
//里面就一个 __u32 type
/**
* BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
* BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
* BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
* BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
* BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
* /
struct binder_object_header hdr;
__u32 flags;

// 要么是一个引用 要么就是一个 handle 整型值
//binder 只能是server可以传递,它代表本地对象,其他只能传handle
//handle 代表远程对象,是一个引用,它是一个整型值
union {
binder_uintptr_t binder; /* local object */
__u32 handle; /* remote object */
};
binder_uintptr_t cookie;
};

当type 是 BINDER_TYPE_BINDER时,放的是 binder,否则放的是 handle
这里的binder就是我们之前写的test_server代码中,我们自己的处理函数,它的地址

接下来看源码

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
for (; offp < off_end; offp++) {
struct flat_binder_object *fp;

if (*offp > t->buffer->data_size - sizeof(*fp) ||
t->buffer->data_size < sizeof(*fp) ||
!IS_ALIGNED(*offp, sizeof(u32))) {
binder_user_error("%d:%d got transaction with invalid offset, %lld\n",
proc->pid, thread->pid, (u64)*offp);
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
//这里的 fp 是目的进程的空间
// 这里再次确认,当前进程是我们的 server ,目的进程是 service_manager
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
switch (fp->type) {
//如果它是实体的话 也就是 binder
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
struct binder_ref *ref;
struct binder_node *node = binder_get_node(proc, fp->binder);

if (node == NULL) {
//给当前进程创建 node
node = binder_new_node(proc, fp->binder, fp->cookie);
if (node == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_new_node_failed;
}
node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
}
if (fp->cookie != node->cookie) {
binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n",
proc->pid, thread->pid,
(u64)fp->binder, node->debug_id,
(u64)fp->cookie, (u64)node->cookie);
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
if (security_binder_transfer_binder(proc->tsk,
target_proc->tsk)) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
// 给目的进程创建 ref
ref = binder_get_ref_for_node(target_proc, node);
if (ref == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
//对于当前线程而言,目的进程就是远程对象,因此它只能存放 handle
if (fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
//看这里 把ref中的desc赋值hanlde
fp->handle = ref->desc;
// 引用计数器
binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
&thread->todo);

trace_binder_transaction_node_to_ref(t, node, ref);
} break;
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
/**
* 和上面的逻辑类似 简单说下
* client获取服务的时候,servicemanager在查询到服务后,要把handle传给client,所以需要先传给驱动程序
* 它只能传引用(因为获取过来的就是引用),因此,type就是 BINDER_TYPE_HANDLE
* 讲获取服务的时候会详细讲解到
**/
......
} break;
}
}
......

现在分析完了数据发送的流程,它就会唤醒目的进程,也就是service_manager

1
2
if (target_wait)
wake_up_interruptible(target_wait);

被唤醒之后,回到之前被休眠的地方,也就是 binder_thread_read 的代码,继续执行下面的代码,在被唤醒后,它还是一个循环读取

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
if (wait_for_proc_work)
proc->ready_threads--;
thread->looper &= ~BINDER_LOOPER_STATE_WAITING;

if (ret)
return ret;

while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
//取出todo链表
if (!list_empty(&thread->todo)) {
w = list_first_entry(&thread->todo, struct binder_work,
entry);
} else if (!list_empty(&proc->todo) && wait_for_proc_work) {
//thread中没有 就从进程 proc 中取出链表
w = list_first_entry(&proc->todo, struct binder_work,
entry);
} else {
if (ptr - buffer == 4 &&
!(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
goto retry;
break;
}

if (end - ptr < sizeof(tr) + 4)
break;

......
}

下面的代码中,会根据cmd命令来选择,前面的源码中有设置过cmd,放入链表中的时候

1
2
3
4
t->work.type = BINDER_WORK_TRANSACTION;
list_add_tail(&t->work.entry, target_list);
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);
1
2
3
4
5
6
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
//得到一个 binder_transaction
t = container_of(w, struct binder_transaction, work);
} break;
}

继续查看while循环中的后续代码

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
if (t->buffer->target_node) {
struct binder_node *target_node = t->buffer->target_node;

tr.target.ptr = target_node->ptr;
tr.cookie = target_node->cookie;
t->saved_priority = task_nice(current);
if (t->priority < target_node->min_priority &&
!(t->flags & TF_ONE_WAY))
binder_set_nice(t->priority);
else if (!(t->flags & TF_ONE_WAY) ||
t->saved_priority > target_node->min_priority)
binder_set_nice(target_node->min_priority);
//接收的是 BC_TRANSACTION 返回的是 BR_TRANSACTION
cmd = BR_TRANSACTION;
} else {
tr.target.ptr = 0;
tr.cookie = 0;
cmd = BR_REPLY;
}
tr.code = t->code;
tr.flags = t->flags;
tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);

if (t->from) {
struct task_struct *sender = t->from->proc->tsk;

tr.sender_pid = task_tgid_nr_ns(sender,
task_active_pid_ns(current));
} else {
tr.sender_pid = 0;
}
//后面的代码就是构造 binder_transaction 并返回
......

接下来就是回到之前的binder_loop了,ioctl执行后就是 binder_parse

1
2
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);

还记得驱动传给我们的cmd么, BR_TRANSACTION ,在之前的分析中,它第一次会返回 BR_NOOP,后面才会返回 BR_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
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func)
{
int r = 1;
uintptr_t end = ptr + (uintptr_t) size;

while (ptr < end) {
uint32_t cmd = *(uint32_t *) ptr;
ptr += sizeof(uint32_t);
switch(cmd) {
case BR_NOOP:
//不做处理
break;
......
case BR_TRANSACTION: {
struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
if ((end - ptr) < sizeof(*txn)) {
ALOGE("parse: txn too small!\n");
return -1;
}
binder_dump_txn(txn);
if (func) {
unsigned rdata[256/4];
struct binder_io msg;
struct binder_io reply;
int res;

bio_init(&reply, rdata, sizeof(rdata), 4);
// 根据 txn 构造 binder_io
bio_init_from_txn(&msg, txn);
//svcmgr_handler 处理函数
res = func(bs, txn, &msg, &reply);
if (txn->flags & TF_ONE_WAY) {
binder_free_buffer(bs, txn->data.ptr.buffer);
} else {
//处理结束后回复信息
binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
}
}
ptr += sizeof(*txn);
break;
}
......
}
return r;
}

在处理函数中我们简单看下它的核心函数 do_add_service ,就是服务的信息的一些设置

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
int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle,
uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) {
struct svcinfo *si;

if (!handle || (len == 0) || (len > 127))
return -1;


if (!svc_can_register(s, len, spid, uid)) {
ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
str8(s, len), handle, uid);
return -1;
}

//查找链表中是否有服务
si = find_svc(s, len);
if (si) {
if (si->handle) {
ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
str8(s, len), handle, uid);
svcinfo_death(bs, si);
}
si->handle = handle;
} else {
//分配 si
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
if (!si) {
ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
str8(s, len), handle, uid);
return -1;
}
si->handle = handle;
si->len = len;
memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
si->name[len] = '\0';
si->death.func = (void*) svcinfo_death;
si->death.ptr = si;
si->allow_isolated = allow_isolated;
si->dumpsys_priority = dumpsys_priority;
// 头尾链表
si->next = svclist;
//把数据放入 svclist ,它是一个链表
svclist = si;
}

//增加引用计数
binder_acquire(bs, handle);
//用于销毁通知
binder_link_to_death(bs, handle, &si->death);
return 0;
}

简单看下 binder_send_reply

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
void binder_send_reply(struct binder_state *bs,
struct binder_io *reply,
binder_uintptr_t buffer_to_free,
int status)
{
struct {
uint32_t cmd_free;
binder_uintptr_t buffer;
uint32_t cmd_reply;
struct binder_transaction_data txn;
} __attribute__((packed)) data;

data.cmd_free = BC_FREE_BUFFER;
data.buffer = buffer_to_free;
data.cmd_reply = BC_REPLY;
data.txn.target.ptr = 0;
data.txn.cookie = 0;
data.txn.code = 0;
if (status) {
data.txn.flags = TF_STATUS_CODE;
data.txn.data_size = sizeof(int);
data.txn.offsets_size = 0;
data.txn.data.ptr.buffer = (uintptr_t)&status;
data.txn.data.ptr.offsets = 0;
} else {
data.txn.flags = 0;
data.txn.data_size = reply->data - reply->data0;
data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
}
binder_write(bs, &data, sizeof(data));
}

可以看出,server处理完数据后,会封装好数据,并且调用ioctl,cmd为 BC_REPLY

当server注册服务成功之后,就是进入一个循环,等待client发送数据,过程中还会有其他的 cmd 操作,这些细节可以自己查看源码理解

再回头看看结构图