Service Manager如何启动的啊?
为什么要讲Service Manager 和 mediaserver的启动呢? 因为后面我们在讲Camera流程
的时候,会用到相关知识点。综合文章结构组织及阅读体验考虑,决定将这两部分独立出来,
针对性做个剖析。关于Binder部分,个人只是根据自己的理解写的分析,并未通过实战抓log
的方式予以确认,在相关流程里该怎么加log,还请高手们不吝赐教!!
前面我讲init.rc中的service是如何启动的,并以zygote为例做了说明。详情请参考
《深入理解Android 卷1》读书笔记 (一)—— Android Init
浅析
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; }
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)));
终于水落石出了,原来init_module时调用的就是这个binder_init啊。OK,追根溯源结束了,我们回过头来
看看那个binder_ioctl里针对BINDER_SET_CONTEXT_MGR到底做了啥。
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,传入的ptr和cookie
均为NULL。然后创建此code的work.entry和async_todo链表。对此片段更详细的解读,还是需要大神指点。
#ifdef BINDER_MONITOR strcpy(binder_context_mgr_node->name, "servicemanager"); #endif
这句就是关键了,我们明确知道了这个binder_context_mgr_node就是Service Manager。这个全局变量
binder_context_mgr_node“代表”的就是service manager,今后看到此变量时得多多留意哦!!!
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_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
此时应该为FALSE。(关于return_error,thread->todo,请参考binder_get_thread,这个在
binder_ioctl里面会调用到)
wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);
上面这个应该是设置binder reply的状态信息。
thread->looper |= BINDER_LOOPER_STATE_WAITING; ... ... binder_unlock(__func__);
之所以这里直接用了binder_unlock,是因为之前在binder_ioctl 已经调用了binder_lock。
if (non_block) { if (!binder_has_thread_work(thread)) ret = -EAGAIN; }
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); }
为了确认函数binder_has_thread_work的返回值的真假,我们需要逐个判断函数里面 “||"的几个条件:
(1)list_empty(&thread->todo)
这个thread->todo是在binder_get_thread里面被赋值的。
INIT_LIST_HEAD(&thread->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条件。
(2)关于return_error和thread->looper在binder_get_thread里的赋值
thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; thread->return_error = BR_OK; thread->return_error2 = BR_OK;
由于相关地方并未清除或者改变已经设置的状态位,所以,thread->return_error != BR_OK
判断结果为FALSE,而(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)判断
结果为TRUE,于是函数返回TRUE。
binder_lock(__func__); thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
清除了之前设置的WAITING状态。 那我们继续往下看,会看到while(1)循环,相关内容如下:
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) w = list_first_entry(&proc->todo, struct binder_work, entry); else { if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */ goto retry; break; }
首先,list_empty判断为TRUE。接着,else if里面的wait_for_proc_work判断为FALSE,所以
也不会被执行。else里面的那个thread->looper & BINDER_LOOPER_STATE_NEED_RETURN
为TRUE,所以goto retry不会被执行,下面的break会被执行,while(1)循环退出。
done: *consumed = ptr - buffer; if (proc->requested_threads + proc->ready_threads == 0 && 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_debug(BINDER_DEBUG_THREADS, "binder: %d:%d BR_SPAWN_LOOPER\n", proc->pid, thread->pid); if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) return -EFAULT; binder_stat_br(proc, thread, BR_SPAWN_LOOPER); } return 0;requested_threads,ready_threads,requested_threads_started均为0(未见其赋值),
max_threads在binder_ioctl中的case BINDER_SET_MAX_THREADS 被设置。
frameworks/native/libs/binder/ProcessState.cpp中的open_driver函数用来打开binder设备,其中有句:
size_t maxThreads = 15; result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
也就是说max_threads为15。
另外,由于thread->looper的状态包含BINDER_LOOPER_STATE_ENTERED,所以此处判断条件为TRUE。
将会把BR_SPAWN_LOOPER传到用户空间,然后设置binder reply的相关状态为BR_SPAWN_LOOPER。
OK,到此binder_ioctl这边走完了,对应的就是binder_loop中的ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
执行完毕了,那么返回到binder_loop中,由于binder_ioctl返回值为0,接下来执行的是binder_parse。
先看看binder_parse传入的参数:
(1)从bwr.read_buffer = (unsigned) readbuf; 可知,readbuf对应的是read_buffer,它会在ioctl调用
过程中被改变。
binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed
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;
if (put_user(BR_NOOP, (uint32_t __user *)ptr))
那个read_buffer对应于binder_thread_read利民的buffer(注意指针类型为void __user *),指针ptr也是
指向这块buffer,那上面的put_user就是改变里面的内容。可是问题来了,后面不是也有句
(put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) 么? 由于函数进来时,ptr 等于buffer,
那么,这个就会改掉之前写入的BR_NOOP,但这样做的话,binder_parse中执行的将是:
default: ALOGE("parse: OOPS %d\n", cmd); return -1;
会导致binder_loop里面的for循环退出。在这里,我不得不忽悠下,上面对于binder_thread_read里面
done标号语句的分析可能有误。其中,”requested_threads,ready_threads,requested_threads_started
均为0(未见其赋值)“的判断可能不正确,这里不能执行if下的语句。还望高人指点!!
(2) bwr.read_consumed 为多少? 下面两句会被执行,所以read_consumed为sizeof(uint32_t) 。
ptr += sizeof(uint32_t); *consumed = ptr - buffer;
(3)传入的binder_handler函数是? 就是 svcmgr_handler !!
int r = 1; uint32_t *end = ptr + (size / 4); case BR_NOOP: break; return r;
分析: 上面那个size / 4 结果为1,所以while 循环只有一次,只会处理一个binder reply —— BR_NOOP 。
binder_parse返回1后,回到binder_loop里的for循环,然后继续ioctl, binder_parse。
也就是说,在没有命令到来的时候,这边处理的REPLY就是BR_NOOP 。
如需转载,请注明出处: http://blog.csdn.net/happy08god/article/category/1881463