正文  软件开发 > 编程综合 >

Andorid Binder进程间通信---启动ServiceManager

本文参考《Android系统源代码情景分析》,作者罗升阳。一、~/Android/frameworks/base/cmd/servicemanager -----binder...

本文参考《Android系统源代码情景分析》,作者罗升阳。

一、~/Android/frameworks/base/cmd/servicemanager

-----binder.h

-----binder.c

-----service_manager.c

~/Android//kernel/goldfish/drivers/staging/android

-----binder.c

-----binder.h


二、源码分析

1、从service_manager.c的main开始执行。

----~/Android/frameworks/base/cmd/servicemanager/service_manager.c

int main(int argc, char **argv)
{
    struct binder_state *bs;
    void *svcmgr = BINDER_SERVICE_MANAGER;

    bs = binder_open(128*1024);

    if (binder_become_context_manager(bs)) {
        LOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1; 
    }   

    svcmgr_handle = svcmgr;//注意svcmgr_handle与下面的svcmgr_handler不一样,svcmgr_handle为全局变量,目前为空的函数指针,((void*)0)
    binder_loop(bs, svcmgr_handler);//svcmgr_handler是一个函数指针,指向具体的函数
    return 0;
}
----~/Android/frameworks/base/cmd/servicemanager/binder.c

struct binder_state
{       
    int fd;
    void *mapped;
    unsigned mapsize;
};
----~/Android/frameworks/base/cmd/servicemanager/binder.h

#define BINDER_SERVICE_MANAGER ((void*) 0)
ServiceManager的启动过程由三个步骤组成:第一是调用函数binder_open打开设备文件/dev/binder,以及将它映射到本进程地址空间;第二是调用binder_become_context_manager将自己注册为Binder进程间通信机制的上下文管理者;第三步是调用函数binder_loop来循环等待和处理Client进程的通信要求。


2、打开和映射Binder设备文件

----~/Android/frameworks/base/cmd/servicemanager/binder.c

struct binder_state *binder_open(unsigned mapsize)
{       
    struct binder_state *bs;

    bs = malloc(sizeof(*bs));
    if (!bs) {
        errno = ENOMEM;
        return 0;
    }

    bs->fd = open("/dev/binder", O_RDWR);//文件描述符保存在fd中
    if (bs->fd mapsize = mapsize;//128*1024
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);//映射到本进程地址空间
    if (bs->mapped == MAP_FAILED) {
        fprintf(stderr,"binder: cannot map device (%s)\n",
                strerror(errno));
        goto fail_map;
    }

        /* TODO: check version */

    return bs;

fail_map:
    close(bs->fd);
fail_open:
    free(bs);
    return 0;
} 
其中open("/dev/binder", O_RDWR)映射到binder驱动程序binder_open方法。

binder_open方法位于~/Android/kernel/goldfish/drivers/staging/android/binder.c

static int binder_open(struct inode *nodp, struct file *filp)
{
        struct binder_proc *proc;      

        if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)
                printk(KERN_INFO "binder_open: %d:%d\n", current->group_leader->pid, current->pid);

        proc = kzalloc(sizeof(*proc), GFP_KERNEL);//创建binder_proc结构体
        if (proc == NULL)     
                return -ENOMEM;                
        get_task_struct(current);      
        proc->tsk = current;  //初始化各个参数
        INIT_LIST_HEAD(&proc->todo);   
        init_waitqueue_head(&proc->wait);
        proc->default_priority = task_nice(current);
        mutex_lock(&binder_lock);      
        binder_stats.obj_created[BINDER_STAT_PROC]++;
        hlist_add_head(&proc->proc_node, &binder_procs);//将binder_proc结构体proc加入到一个全局hash队列binder_procs中
        proc->pid = current->group_leader->pid;
        INIT_LIST_HEAD(&proc->delivered_death);
        filp->private_data = proc;//将binder_proc结构体proc保存在参数filp的成员变量private_data中  
        mutex_unlock(&binder_lock);    

        if (binder_proc_dir_entry_proc) {//如果存在/proc/binder/proc目录
                char strbuf[11];
                snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
                remove_proc_entry(strbuf, binder_proc_dir_entry_proc);
                create_proc_read_entry(strbuf, S_IRUGO, binder_proc_dir_entry_proc, binder_read_proc_proc, proc);//在/proc/binder/proc目录下创建一个以进程ID为名称的只读文件
        }

        return 0;
}
创建了binder_proc结构体,分别初始化各个参数,将binder_proc结构体proc加入到一个全局hash队列binder_procs中。Binder驱动程序将所有打开了设备文件/dev/binder的进程都加入全局hash队列binder_procs中,因此,通过遍历这个hash队列就知道系统当前有多少进程在使用Binder进程间通信机制。然后将binder_proc结构体proc保存在参数filp的成员变量private_data中。最后在/proc/binder/proc目录下创建一个以进程ID为名称的只读文件,并且以函数binder_read_proc_proc作为它的文件内容读取函数。通过读取文件/proc/binder/proc/的内容,我们就可以获得进程的Binder线程池,Binder实体对象,Binder引用对象,以及内核缓冲区等信息。

其中mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0)映射到binder驱动程序binder_mmap方法,暂时先不分析。


3、注册为Binder上下文管理者

---~/Android/frameworks/base/cmd/servicemanager/binder.c

int binder_become_context_manager(struct binder_state *bs)
{   
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
ioctl方法映射到binder驱动程序binder_ioctl方法。

binder_ioctl位于~/Android/kernel/goldfish/drivers/staging/android/binder.c

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	int ret;
	struct binder_proc *proc = filp->private_data;//获取刚刚在open中创建的binder_proc结构体
	struct binder_thread *thread;
	unsigned int size = _IOC_SIZE(cmd);//命令的大小
	void __user *ubuf = (void __user *)arg;//参数地址

	.........

	mutex_lock(&binder_lock);
	thread = binder_get_thread(proc);//获取或者创建一个binder_thread结构体
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}

	switch (cmd) {
	............
	case BINDER_SET_CONTEXT_MGR:
		if (binder_context_mgr_node != NULL) {
			.........
		}
		if (binder_context_mgr_uid != -1) {
			.........
		} else
			binder_context_mgr_uid = current->cred->euid;//初始化进程有效用户ID
		binder_context_mgr_node = binder_new_node(proc, NULL, NULL);//初始化一个Binder实体对象
		if (binder_context_mgr_node == NULL) {
			ret = -ENOMEM;
			goto err;
		}
		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;
		break;
	.............
	}
	ret = 0;
err:
	if (thread)
		thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
	mutex_unlock(&binder_lock);
	.............
	return ret;
}
binder_get_thread实现如下:

~/Android/kernel/goldfish/drivers/staging/android/binder.c

static struct binder_thread *binder_get_thread(struct binder_proc *proc)
{
	struct binder_thread *thread = NULL;
	struct rb_node *parent = NULL;
	struct rb_node **p = &proc->threads.rb_node;

	while (*p) {//根据当前主线程pid,来查找是否已经分配了binder_thread结构体
		parent = *p;
		thread = rb_entry(parent, struct binder_thread, rb_node);

		if (current->pid pid)
			p = &(*p)->rb_left;
		else if (current->pid > thread->pid)
			p = &(*p)->rb_right;
		else
			break;
	}
	if (*p == NULL) {//如果没有找到
		thread = kzalloc(sizeof(*thread), GFP_KERNEL);//分配binder_thread结构体
		if (thread == NULL)
			return NULL;
		binder_stats.obj_created[BINDER_STAT_THREAD]++;
		thread->proc = proc;//初始化各个变量
		thread->pid = current->pid;
		init_waitqueue_head(&thread->wait);
		INIT_LIST_HEAD(&thread->todo);
		rb_link_node(&thread->rb_node, parent, p);//根据pid将thread->rb_node插入到proc->threads维护的红黑树中
		rb_insert_color(&thread->rb_node, &proc->threads);
		thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;
		thread->return_error = BR_OK;
		thread->return_error2 = BR_OK;
	}
	return thread;
}
一个进程会有很多线程,所以thread->rb_node为proc->threads维护的红黑数中的一个节点。thread按照pid大小将rb_node插入到proc->threads维护的红黑树的对应节点处。所以首先根据当前主线程pid,来查找是否已经分配了binder_thread结构体。如果没有那么分配binder_thread结构体,初始化各个变量,根据pid将thread->rb_node插入到proc->threads维护的红黑树中。将looper状态设备为BINDER_LOOPER_STATE_NEED_RETURN,表示该线程在完成当前操作之后,需要马上返回到用户空间,而不可以去处理进程间的通信请求。

全局变量binder_context_mgr_node用来描述一个Binder实体对象,如果它的值不为NULL,说明已经注册了Binder进程间通信上下文管理者了。全局变量binder_context_mgr_uid用来描述进程有效用户ID,如果它的值不等于-1,说明已经注册了Binder进程间通信上下文管理者了。目前没有Binder进程间通信上下文管理者,所以binder_context_mgr_uid和binder_context_mgr_node都要初始化。


binder_context_mgr_node实现如下:

-----~/Android/kernel/goldfish/drivers/staging/android/binder.c

static struct binder_node *
binder_new_node(struct binder_proc *proc, void __user *ptr, void __user *cookie)
{
	struct rb_node **p = &proc->nodes.rb_node;
	struct rb_node *parent = NULL;
	struct binder_node *node;

	while (*p) {//根据node的ptr,来查找是否已经分配了binder_node结构体
		parent = *p;
		node = rb_entry(parent, struct binder_node, rb_node);

		if (ptr ptr)
			p = &(*p)->rb_left;
		else if (ptr > node->ptr)
			p = &(*p)->rb_right;
		else
			return NULL;
	}

	node = kzalloc(sizeof(*node), GFP_KERNEL);//如果没有找到,分配binder_node结构体
	if (node == NULL)
		return NULL;
	binder_stats.obj_created[BINDER_STAT_NODE]++;
	rb_link_node(&node->rb_node, parent, p);//根据ptr将node->rb_node插入proc->nodes中
	rb_insert_color(&node->rb_node, &proc->nodes);
	node->debug_id = ++binder_last_id;//初始化各个变量
	node->proc = proc;
	node->ptr = ptr;//NULL
	node->cookie = cookie;//NULL
	node->work.type = BINDER_WORK_NODE;
	INIT_LIST_HEAD(&node->work.entry);
	INIT_LIST_HEAD(&node->async_todo);
	if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS)
		printk(KERN_INFO "binder: %d:%d node %d u%p c%p created\n",
		       proc->pid, current->pid, node->debug_id,
		       node->ptr, node->cookie);
	return node;
}
一个进程会有很多实体对象,所以node->rb_node为proc->nodes维护的红黑数中的一个节点。node按照ptr地址大小将rb_node插入到proc->threads维护的红黑树的对应节点处。所以首先根据当前node的ptr,来查找是否已经分配了binder_node结构体。如果没有那么分配binder_node结构体,初始化各个变量,根据ptr将thread->rb_node插入到proc->threads维护的红黑树中。

然后返回binder_ioctl中,会将thread->looper状态位BINDER_LOOPER_STATE_NEED_RETURN清零。


4、循环等待Client进程请求

返回用户空间,main函数开始执行binder_loop,实现如下:

---~/Android/frameworks/base/cmd/servicemanager/binder.c

void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    unsigned readbuf[32];

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;
    
    readbuf[0] = BC_ENTER_LOOPER;//首先将BC_ENTER_LOOPER协议写入缓冲区readbuf中
    binder_write(bs, readbuf, sizeof(unsigned));//调用binder_write将它发送到Binder驱动程序中

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (unsigned) readbuf;

        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//bwr.write_size为0,bwr.read_size不为0

        if (res         首先将BC_ENTER_LOOPER协议写入缓冲区readbuf中,接着调用binder_write将它发送到Binder驱动程序中。函数binder_write的实现如下:

---~/Android/frameworks/base/cmd/servicemanager/binder.c

int binder_write(struct binder_state *bs, void *data, unsigned len)
{
    struct binder_write_read bwr;
    int res;
    bwr.write_size = len;
    bwr.write_consumed = 0;
    bwr.write_buffer = (unsigned) data;
    bwr.read_size = 0;
    bwr.read_consumed = 0;
    bwr.read_buffer = 0;
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//bwr的write_size不为0,read_size为0
    if (res       ioctl方法同样映射到binder驱动程序binder_ioctl方法。 
binder_ioctl位于~/Android/kernel/goldfish/drivers/staging/android/binder.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;

	.........

	mutex_lock(&binder_lock);
	thread = binder_get_thread(proc);//上次获取的thread,looper为0
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}

	switch (cmd) {//cmd为上面传递过来的BINDER_WRITE_READ
	case BINDER_WRITE_READ: {
		struct binder_write_read bwr;
		if (size != sizeof(struct binder_write_read)) {
			ret = -EINVAL;
			goto err;
		}
		if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//从用户空间传进来的一个binder_write_read结构体拷贝出来,并且保存在变量bwr中
			ret = -EFAULT;
			goto err;
		}
                .........
		if (bwr.write_size > 0) {//bwr.write_size大于0,执行这里
			ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
			if (ret  0) {//bwr.read_size等于0,不执行这里
			ret = binder_thread_read(proc, thread, (void __user *)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 (ret looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;//looper为BINDER_LOOPER_STATE_ENTERED,由于对应位已经为0,此时执行此句无效果
	mutex_unlock(&binder_lock);
        ...........
	return ret;
}
由于bwr.write_size大于0,开始执行binder_thread_write,实现如下:

binder_ioctl位于~/Android/kernel/goldfish/drivers/staging/android/binder.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;//结束位置

	while (ptr return_error == BR_OK) {
		if (get_user(cmd, (uint32_t __user *)ptr))//cmd为BC_ENTER_LOOPER
			return -EFAULT;
		ptr += sizeof(uint32_t);//由于只有一个cmd,此时ptr已经等于end
		............
		switch (cmd) {
		...........
		case BC_ENTER_LOOPER:
		        ..............
			if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {//此时looper为0,不会执行这里
				thread->looper |= BINDER_LOOPER_STATE_INVALID;
				binder_user_error("binder: %d:%d ERROR:"
					" BC_ENTER_LOOPER called after "
					"BC_REGISTER_LOOPER\n",
					proc->pid, thread->pid);
			}
			thread->looper |= BINDER_LOOPER_STATE_ENTERED;//执行本次写操作,最终的目的居然是looper设置成BINDER_LOOPER_STATE_ENTERED
			break;
		.........
		*consumed = ptr - buffer;//由于只有一个cmd,consumed为size
	}
	return 0;
}
返回binder_ioctl,bwr.read_size等于0,不会执行,最后将结果返回用户空间bwr。

返回用户空间,接着执行binder_loop,从上面我们看出来,驱动程序是否执行读、写操作,取决于用户空间write_size,read_size的大小。此时write_size为0,read_size不为0, ioctl方法同样映射到binder驱动程序binder_ioctl方法。
binder_ioctl位于~/Android/kernel/goldfish/drivers/staging/android/binder.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;

	.........

	mutex_lock(&binder_lock);
	thread = binder_get_thread(proc);//上次获取的thread,looper为BINDER_LOOPER_STATE_ENTERED
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}

	switch (cmd) {//cmd为上面传递过来的BINDER_WRITE_READ
	case BINDER_WRITE_READ: {
		struct binder_write_read bwr;
		if (size != sizeof(struct binder_write_read)) {
			ret = -EINVAL;
			goto err;
		}
		if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//从用户空间传进来的一个binder_write_read结构体拷贝出来,并且保存在变量bwr中
			ret = -EFAULT;
			goto err;
		}
                .........
		if (bwr.write_size > 0) {//bwr.write_size等于0,不执行这里
			ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
			if (ret  0) {//bwr.read_size大于0,执行这里
			ret = binder_thread_read(proc, thread, (void __user *)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 (ret looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
	mutex_unlock(&binder_lock);
        ...........
	return ret;
}

由于bwr.read_size大于0,开始执行binder_thread_read,实现如下:

binder_ioctl位于~/Android/kernel/goldfish/drivers/staging/android/binder.c

static int
binder_thread_read(struct binder_proc *proc, struct binder_thread *thread,
	void  __user *buffer, int size, signed long *consumed, int non_block)
{
	void __user *ptr = buffer + *consumed;//起始位置
	void __user *end = buffer + size;//结束位置

	int ret = 0;
	int wait_for_proc_work;

	if (*consumed == 0) {
		if (put_user(BR_NOOP, (uint32_t __user *)ptr))//BR_NOOP存入刚才的局部变量中
			return -EFAULT;
		ptr += sizeof(uint32_t);
	}

retry:
	wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);//wait_for_proc_work目前为1,表示线程没有要处理的任务

	if (thread->return_error != BR_OK && ptr looper |= BINDER_LOOPER_STATE_WAITING;//looper为BINDER_LOOPER_STATE_ENTERED,BINDER_LOOPER_STATE_WAITING
	if (wait_for_proc_work)//为1
		proc->ready_threads++;//ready_threads为1,进程多了一个空闲线程
	mutex_unlock(&binder_lock);
	if (wait_for_proc_work) {//为1
		if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
					BINDER_LOOPER_STATE_ENTERED))) {     // 此时为false
		      ...............
		}
		binder_set_nice(proc->default_priority);//把当前线程的优先级设置为它所属进程的优先级
		if (non_block) {//非阻塞要立刻返回处理结果
			if (!binder_has_proc_work(proc, thread))//有任务就接着往下执行,没有任务就返回
				ret = -EAGAIN;
		} else
			ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread));//睡眠等待直到其所属的进程有新的未处理项为止
	} else {
		if (non_block) {//非阻塞要立刻返回处理结果
			if (!binder_has_thread_work(thread))有任务就接下往下执行,没有任务就返回
				ret = -EAGAIN;
		} else
			ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));//睡眠等待直到线程有新的未处理项为止
	}
	mutex_lock(&binder_lock);
	if (wait_for_proc_work)//为1
		proc->ready_threads--;//ready_thread为0
	thread->looper &= ~BINDER_LOOPER_STATE_WAITING;//looper为BINDER_LOOPER_STATE_ENTERED

	if (ret)
		return ret;

	while (1) {
		........
	}

done:

	*consumed = ptr - buffer;
	..........
	return 0;
}

static int
binder_has_proc_work(struct binder_proc *proc, struct binder_thread *thread)
{
	return !list_empty(&proc->todo) || (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN);
}

static int
binder_has_thread_work(struct binder_thread *thread)
{
	return !list_empty(&thread->todo) || thread->return_error != BR_OK ||
		(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN);
}
如果线程thread中没有要处理的数据,那么就处理进程proc上等待的数据。如果进程上没有数据要处理,那么睡眠等待直到其所属的进程有新的未处理项为止。

如果线程thread中有要处理的数据,那么就处理线程thread上的数据。如果线程上没有数据要处理,那么睡眠等待直到线程有新的未处理项为止。

如果是非阻塞访问,如果没有数据,就立刻返回,不会睡眠等待。如果有数据,就继续往下执行。

目前由于线程thread没有要处理的数据,进程上也没有要处理的数据,那么睡眠等待直到其所属的进程有新的未处理项为止。