Android Service Manager源码剖析

         



Service Manager如何启动的啊?    


      为什么要讲Service Manager 和 mediaserver的启动呢? 因为后面我们在讲Camera流程的时候,

会用到相关知识点。综合文章结构组织及阅读体验考虑,决定将这两部分独立出来,针对性做个剖析。

关于Binder部分,个人只是根据自己的理解写的分析,并未通过实战抓log的方式予以确认,在相关流程

里该怎么加log,还请高手们不吝赐教!!


    前面我讲init.rc中的service是如何启动的,并以zygote为例做了说明。详情请参考《深入理解Android 卷1》读书笔记 (一)—— Android Init 浅析之从Main开始到service start

    Service Manager也是按照同样的方式被启动的。我们先看看init.rc中的相关片段:

service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm

    好了,我们重点是第一句: service servicemanager /system/bin/servicemanager


代码在哪里啊,入口在哪里? 


    那这个servicemanager程序对于的源码位于哪里呢? 找Makefile!!怎么找?搜索servicemanager

找目录,文件?确实,就这么找到了。看看frameworks/base/cmds/servicemanager/Android.mk怎么写

的吧?


include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := service_manager.c binder.c
LOCAL_MODULE := servicemanager
include $(BUILD_EXECUTABLE)


    太感动了,从LOCAL_MODULE为servicemanager,我们知道要找的东东就是它了!! 涉及到此目录

下的service_manager.c和binder.c两个源文件(和binder.h一个头文件)。


    接下来的第一步就是找程序的入口函数——main函数啦。 哇塞,我找到了,太激动了有莫有。。。

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)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    svcmgr_handle = svcmgr;
    binder_loop(bs, svcmgr_handler);
    return 0;
}

    变量赋值神马的,暂时不管,我们先看看调用的函数做了些啥。


细说binder_open

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);
    if (bs->fd < 0) {
        fprintf(stderr,"binder: cannot open device (%s)\n",
                strerror(errno));
        goto fail_open;
    }

    bs->mapsize = mapsize;
    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;
}

    就是打开/dev/binder设备,调用mmap将设备映射到大小为(128*1024)字节的内存里。

但这边open,mmap,其实会调用binder驱动注册的open和mmap函数。 以open为例,

对应的就是kernel/drivers/staging/android/binder.c中的binder_open函数。

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

	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;
	get_task_struct(current);
	proc->tsk = current;
	INIT_LIST_HEAD(&proc->todo);
	init_waitqueue_head(&proc->wait);
	proc->default_priority = task_nice(current);
#ifdef RT_PRIO_INHERIT
	proc->default_rt_prio = current->rt_priority;
	proc->default_policy = current->policy;
#endif

	binder_lock(__func__);

	binder_stats_created(BINDER_STAT_PROC);
	hlist_add_head(&proc->proc_node, &binder_procs);
	proc->pid = current->group_leader->pid;
	INIT_LIST_HEAD(&proc->delivered_death);
	filp->private_data = proc;

	binder_unlock(__func__);

	if (binder_debugfs_dir_entry_proc) {
		char strbuf[11];
		snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
		proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,
			binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);
	}

	return 0;
}


    注意几个变量的赋值,如todo list,wait queue的初始化(为空链),flip->private_data 此处特别要

留意,binder_ioctl中有struct binder_proc *proc = filp->private_data; 而这个proc是我们后面经常用的变量。

proc->tsk = current;
INIT_LIST_HEAD(&proc->todo);
init_waitqueue_head(&proc->wait);

proc->pid = current->group_leader->pid;
INIT_LIST_HEAD(&proc->delivered_death);
filp->private_data = proc;

binder_become_context_manager初探

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

    原来是通过ioctl,发送了BINDER_SET_CONTEXT_MGR的命令给/dev/binder设备。有点Linux Driver

基础知识的人都知道,如果设备的驱动程序注册的file operation函数指针数组里面如有指定ioctl函数,

那么此处调用的ioctl函数将是那个对应的注册函数。

    

    关于binder相关的代码,位于kernel/drivers/staging/android目录下。在此目录的Binder.c中,我们看到了

binder_ioctl函数,初步猜测这个就是我们要找的binder设备的ioctl函数。代码中是如何印证这一点的呢?

 在该文件中搜索binder_ioctl,我们可以看到:


static const struct file_operations binder_fops = {
	.owner = THIS_MODULE,
	.poll = binder_poll,
	.unlocked_ioctl = binder_ioctl,
	.mmap = binder_mmap,
	.open = binder_open,
	.flush = binder_flush,
	.release = binder_release,
};

static struct miscdevice binder_miscdev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "binder",
	.fops = &binder_fops
};

    看到这个东东,是否觉得似曾相识? 没错,在很多讲驱动程序的地方,我们会看到字符设备驱动的范例。

里面会有module_init/ module_exit。会讲到模块的插入和移除,字符设备的注册和注销,以及该module的

file operation数组。该数组里面会指定设备文件的各种操作函数,诸如open,ioctl,release等。


    这里也是那样的。还有个问题,那设备驱动程序的入口(insert module时执行的函数)在哪里呢?搜索下

上面那个binder_miscdev,看看哪个地方注册的这个设备。原来是在binder_init函数里:

ret = misc_register(&binder_miscdev);

    那谁调用的binder_init呢?


device_initcall(binder_init);

#define device_initcall(fn)		module_init(fn)


/* Each module must use one module_init(). */
#define module_init(initfn)					\
	static inline initcall_t __inittest(void)		\
	{ return initfn; }					\
	int init_module(void) __attribute__((alias(#initfn)));

    终于水落石出了,原来module_init时调用的就是这个binder_init啊。OK,追根溯源结束了,

我们回过头来看看那个binder_ioctl里针对BINDER_SET_CONTEXT_MGR到底做了啥。


    进入binder_ioctl,在进入switch 语句处理对应的case之前,我们会看到:

thread = binder_get_thread(proc);
if (thread == NULL) {
	ret = -ENOMEM;
	goto err;
}
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) {
		parent = *p;
		thread = rb_entry(parent, struct binder_thread, rb_node);

		if (current->pid < thread->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);
		if (thread == NULL)
			return NULL;
		binder_stats_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);
		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;
}

    这里把当前线程current的pid作为键值,在进程proc->threads表示的红黑树中进行查找,看是否已经

为当前线程创建过了binder_thread信息。由于当前线程是第一次进到这里,所以肯定找不到,即*p == NULL。

于是,就为当前线程创建一个线程上下文信息结构体binder_thread,并插入到proc->threads所表示的红黑树

中去,下次要使用时就可以通过proc找到了。

    所以,thread = binder_get_thread(proc); 返回的thread不为NULL。

struct binder_proc *proc = filp->private_data;
	struct binder_thread *thread;
	unsigned int size = _IOC_SIZE(cmd);
	void __user *ubuf = (void __user *)arg;

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

	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_lock(__func__);
	thread = binder_get_thread(proc);
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}

case BINDER_SET_CONTEXT_MGR:
binder_context_mgr_node = binder_new_node(proc, NULL, NULL);
		if (binder_context_mgr_node == NULL) {
			ret = -ENOMEM;
			goto err;
		}
#ifdef BINDER_MONITOR
		strcpy(binder_context_mgr_node->name, "servicemanager");
#endif
		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;

    先看看这个binder_new_node做了什么。

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) {
		parent = *p;
		node = rb_entry(parent, struct binder_node, rb_node);

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

	node = kzalloc(sizeof(*node), GFP_KERNEL);
	if (node == NULL)
		return NULL;
	binder_stats_created(BINDER_STAT_NODE);
	rb_link_node(&node->rb_node, parent, p);
	rb_insert_color(&node->rb_node, &proc->nodes);
	node->debug_id = ++binder_last_id;
	node->proc = proc;
	node->ptr = ptr;
	node->cookie = cookie;
	node->work.type = BINDER_WORK_NODE;
	INIT_LIST_HEAD(&node->work.entry);
	INIT_LIST_HEAD(&node->async_todo);
	binder_debug(BINDER_DEBUG_INTERNAL_REFS,
		     "binder: %d:%d node %d u%p c%p created\n",
		     proc->pid, current->pid, node->debug_id,
		     node->ptr, node->cookie);
	return node;
}

    从函数和变量名称来看,跟红黑树有关。先在红黑树中查找此结点,后面调用rb_link_node和

rb_insert_color将结点插入到红黑树上。这里的debug_id唯一地标识了每一个创建的binder node

(此处应该是第一次创建bindernode,而binder_last_id初始值为0,所以debug_id值为1),传入

的ptr和cookie均为NULL;work.type为BINDER_WORK_NODE。然后创建此code的work.entry和

async_todo链表。对此片段更详细的解读,还是需要大神指点,建议参考luoshengyang的博客


#ifdef BINDER_MONITOR
		strcpy(binder_context_mgr_node->name, "servicemanager");
#endif

    这句就是关键了,我们明确知道了这个binder_context_mgr_node就是Service Manager。这个全局

变量binder_context_mgr_node“代表”的就是service manager,今后看到此变量时得多多留意哦!!!

    小弟不才,之前分析的时候遗漏了重大信息,导致后面再分析的时候就出现了错误。就在这里:

if (thread)
    thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
        

    看见没,之前我们设置的BINDER_LOOPER_STATE_NEED_RETURN在这里被清掉了,那么

thread->looper此时为0。

binder_loop  和  svcmgr_handler

    附带说明下,svcmgr_handle 此时被赋值为NULL。

#define BINDER_SERVICE_MANAGER ((void*) 0)

void *svcmgr = BINDER_SERVICE_MANAGER;

svcmgr_handle = svcmgr;

    我们回到主题,看看这个binder_loop函数怎么写的。

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;
    
    readbuf[0] = BC_ENTER_LOOPER;
    binder_write(bs, readbuf, sizeof(unsigned));

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);
    if (res < 0) {
        fprintf(stderr,"binder_write: ioctl failed (%s)\n",
                strerror(errno));
    }
    return res;
}

    由此可见,这个binder_write其实是设置了binder_write_read结构体里面的write部分,而read

部分为空(read_size为0,read_buffer为NULL),然后通过ioctl发送BINDER_WRITE_READ命令。

case BINDER_WRITE_READ: 
...
...
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) 
{
        ret = -EFAULT;
        goto err;
}

...
...

if (bwr.write_size > 0) 
{
	ret = binder_thread_write(proc, thread, (void __user *)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 err;
	}
}

if (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);
	trace_binder_read_done(ret);
	if (!list_empty(&proc->todo))
		wake_up_interruptible(&proc->wait);
	if (ret < 0) {
		if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
			ret = -EFAULT;
			goto err;
	}
}

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


    既然是驱动,就涉及到了内核空间和用户空间数据的传递。通过copy_from_user将用户空间的数据

拷贝到内核空间(此处对应驱动程序处理数据之前),copy_to_user将内核空间的数据拷贝到用户空间

(此处对应驱动程序处理完数据后)。


    此处我们的write_size > 0, 而read_size为0。继续看binder_thread_write函数:


case BC_ENTER_LOOPER:
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
	break;

      哦,原来只是设置了binder_thread结构的looper成员的状态。果真是跟BC_ENTER_LOOPER

这个命令对应啊。继续看binder_loop的其他部分。

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

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

        if (res < 0) {
            ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
            break;
        }

        res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
        if (res == 0) {
            ALOGE("binder_loop: unexpected reply?!\n");
            break;
        }
        if (res < 0) {
            ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
            break;
        }
    }

    这个死循环只有在出错情况下才会退出。前面讲了BC_ENTER_LOOPER的前半段,就是

binder_write,去写数据(set command)。这里继续讲其后半段——读数据( Binder Reply),

这里也正是binder通信中的精髓之一 —— 与 Service Manager的通信。


    上面那个binder_write执行完了,在这里的loop中,我们看到read_size不为0,如上面所贴出的

case  BINDER_WRITE_READ,binder_thread_read函数会被执行。

if (*consumed == 0) {
	if (put_user(BR_NOOP, (uint32_t __user *)ptr))
		return -EFAULT;
	ptr += sizeof(uint32_t);
}


    将会把BR_NOOP (也就是Binder Reply NO OPeraterion 放到用户空间。在这里顺便说下

put_user与copy_to_user的区别,前者是将基本类型数据(1字节,2字节,4字节,8字节)

拷贝到用户空间,后者可以拷贝任意长度的数据(参数里面有长度,有数据指针)。


    此时thread_todo链表应该为空,也没有transaction吧(个人推测)?那么wait_for_proc_work

此时应该为TRUE。(关于return_error,thread->todo,请参考binder_get_thread,这个在

binder_ioctl里面会调用到)

wait_for_proc_work = thread->transaction_stack == NULL &&
				list_empty(&thread->todo);


    上面这个应该是设置binder loop的状态信息为WAITING 。

thread->looper |= BINDER_LOOPER_STATE_WAITING;
if (wait_for_proc_work)
	proc->ready_threads++;

binder_unlock(__func__);

    之所以这里直接用了binder_unlock,是因为之前在binder_ioctl 已经调用了binder_lock。

接下来的if(wait_for_proc_work)语句中,先disable内核抢占,防止这个正在被调度的

线程被“调度出去”。然后设置优先级 ( 通过调用sched_setscheduler_nocheck :

change the scheduling policy and/or RT priority of a thread from kernelspace )

#ifdef RT_PRIO_INHERIT
		/* disable preemption to prevent from schedule-out immediately */
		preempt_disable();
#endif
		binder_set_nice(proc->default_priority);
#ifdef RT_PRIO_INHERIT
		if (rt_task(current) && !binder_has_proc_work(proc, thread)) {
			/* make sure binder has no work before setting priority back*/
			struct sched_param param = {
				.sched_priority = proc->default_rt_prio,
			};

			mt_sched_setscheduler_nocheck(current,
				    proc->default_policy, & param);
		}
		preempt_enable_no_resched();
#endif

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

    上面这个non_block的判断,我暂时无法确定。如果是non_block的,那么将返回-EAGAIN(负值)。

if (ret)
    return ret;


    上面是从binder_thread_read返回到binder_ioctl,我们继续追,看看是否可能返回这个负值。


if (ret < 0) {
	if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
	ret = -EFAULT;
	goto err;
}
	return ret;


    所以binder_ioctl会返回这个负值。看看ioctl返回后binder_loop中怎么处理这个返回值的吧。

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

if (res < 0) {
    ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
    break;
}

    结果,会退出binder_loop里的循环,而外层也没有retry再进入这个循环的语句。所以我们

可以推测,上面那个non_block为FALSE,将被执行的语句是wait_event_interruptible_exclusive。


#define wait_event_interruptible_exclusive(wq, condition)		\
({									\
	int __ret = 0;							\
	if (!(condition))						\
		__wait_event_interruptible_exclusive(wq, condition, __ret);\
	__ret;								\
})

#define __wait_event_interruptible_exclusive(wq, condition, ret)	\
do {									\
	DEFINE_WAIT(__wait);						\
									\
	for (;;) {							\
		prepare_to_wait_exclusive(&wq, &__wait,			\
					TASK_INTERRUPTIBLE);		\
		if (condition) {					\
			finish_wait(&wq, &__wait);			\
			break;						\
		}							\
		if (!signal_pending(current)) {				\
			schedule();					\
			continue;					\
		}							\
		ret = -ERESTARTSYS;					\
		abort_exclusive_wait(&wq, &__wait, 			\
				TASK_INTERRUPTIBLE, NULL);		\
		break;							\
	}								\
} while (0)

    OK,不继续深入了。反正binder_loop中的那个BINDER_READ_WRITE的ioctl会睡眠阻塞

在这里等待被唤醒,唤醒条件是—— binder_has_proc_work(proc, thread) 为TRUE。


    为了确认当前binder_has_proc_work的返回值的真假,我们需要逐个判断函数里面 “||"的几个条件:

(1)list_empty(&proc->todo)

    这个proc->todo是在binder_open时调用INIT_LIST_HEAD(&proc->todo);里面被赋值的。


static inline void INIT_LIST_HEAD(struct list_head *list)
{
	list->next = list;
	list->prev = list;
}

static inline int list_empty(const struct list_head *head)
{
	return head->next == head;
}

    在插入结点到此链表之前,头结点指针为INIT_LIST_HEAD所指定,满足list_empty条件。

于是!list_empty(&proc->todo) 返回FALSE。


(2)(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)

由于thread->looper的状态为0(其中BINDER_LOOPER_STATE_NEED_RETURN在

SET_CONTEXT_MGR的ioctl的最后被清除了),所以此条件为FALSE。

 

   此部分只是重点讲述了Service Manager进入Binder loop的流程,对于Binder的通信还未进行

深入的探讨,这个任务就交给后续的文章了。


   在此总结下Binder 进入loop等待数据到来的流程:

   (1) BC_ENTER_LOOPER 流程

binder_loop -> binder_write -> ioctl -> binder_ioctl ->  binder_thread_write

    (2)无数据时binder_loop中for循环中读数据的流程

 binder_ioctl ->  binder_thread_read -> wait_event_interruptible  等待被唤醒


如需转载,请注明出处: http://blog.csdn.net/happy08god/article/category/1881463




评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值