本文共 25897 字,大约阅读时间需要 86 分钟。
serviceMmanager是第一个使用binder驱动的进程(一般情况),由init进程解析init.rc后启动。他被赋予类似dns服务器的职责:管理实名binder的注册、查询。本文从init进程出发,走一遍SM的启动流程。
代码版本:android-10.0.0_r36、kernel/msm-wahoo-4.4。摘取的代码片段有删减,仅关注主要流程。
system/core/init/main.cpp
51 int main(int argc, char** argv) { 72 if (!strcmp(argv[1], "second_stage")) { 73 return SecondStageMain(argc, argv);
system/core/init/init.cpp
618 int SecondStageMain(int argc, char** argv) { 706 LoadBootScripts(am, sm);//1741 // Trigger all the boot actions to get us started.742 am.QueueEventTrigger("init");765 while (true) {776 if (!(waiting_for_prop || Service::is_exec_service_running())) {777 am.ExecuteOneCommand();//2778 }
在注释//1处,解析init.rc,拿到要启动的东西:servicemanager。在注释//2处,触发进程启动,此处不展开。
init.rc中描述的触发时机如下:
out/target/product/walleye/root/init.rc
42 on init 291 # Start logd before any other services run to ensure we capture all of their logs.292 start logd293 294 # Start essential services.295 start servicemanager 296 start hwservicemanager297 start vndservicemanager
servicemanager自己也有rc文件来规定进程的属性,明显的,能看到onrestart restart zygote
,这意味着sm进程崩溃时,Android世界会重启。
frameworks/native/cmds/servicemanager/servicemanager.rc
1 service servicemanager /system/bin/servicemanager 2 class core animation 3 user system 4 group system readproc 5 critical 6 onrestart restart healthd 7 onrestart restart zygote 8 onrestart restart audioserver 9 onrestart restart media 10 onrestart restart surfaceflinger 11 onrestart restart inputflinger 12 onrestart restart drm 13 onrestart restart cameraserver 14 onrestart restart keystore 15 onrestart restart gatekeeperd 16 onrestart restart thermalservice 17 writepid /dev/cpuset/system-background/tasks 18 shutdown critical
开始之前看下sm的Android.bp文件,认识下源文件和依赖。
frameworks/native/cmds/servicemanager/Android.bp
27 cc_binary { 28 name: "servicemanager", 29 defaults: ["servicemanager_flags"], 30 srcs: [ 31 "service_manager.c", 32 "binder.c", 33 ], 34 shared_libs: ["libcutils", "libselinux"], 35 init_rc: ["servicemanager.rc"], 36 }
main函数还是很清晰的
frameworks/native/cmds/servicemanager/service_manager.c
382 int main(int argc, char** argv)383 {384 struct binder_state *bs;386 char *driver;387 388 if (argc > 1) {389 driver = argv[1];390 } else {391 driver = "/dev/binder";392 }393 394 bs = binder_open(driver, 128*1024);406 407 if (binder_become_context_manager(bs)) {408 ALOGE("cannot become context manager (%s)\n", strerror(errno));409 return -1;410 }
删减了selinux权限控制的代码,仅关注与binder驱动交互部分。
394行见小节2.1。
407行见小节2.2。
前几天看master的代码,发现sm的初始化改的和应用进程一样,均是借助构造函数来做,mmap映射大小也与应用进程一致,1M-2页
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
在我的pixel2上,页大小为4096比特,所以BINDER_VM_SIZE为1M-8k。从此sm与其他应用进程(native或java)的初始化方式、mmap映射大小,达到了统一。
walleye:/ # getconf PAGESIZE4096
从master代码转回android10。
frameworks/native/cmds/servicemanager/service_manager.c
97 struct binder_state *binder_open(const char* driver, size_t mapsize) 98 { 99 struct binder_state *bs;100 struct binder_version vers;101 102 bs = malloc(sizeof(*bs));107 108 bs->fd = open(driver, O_RDWR | O_CLOEXEC);114 115 if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||116 (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {117 fprintf(stderr,118 "binder: kernel driver version (%d) differs from user space version (%d)\n",119 vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);120 goto fail_open;121 }122 123 bs->mapsize = mapsize;124 bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);130 131 return bs;138 }
99行,关键数据结构binder_state。关键数据结构请转到老罗的书博客或者gityuan的博客。
108行,见小节2.1.1。跳转到驱动binder_open函数。
115、116行,见小节2.1.2。跳转到驱动binder_ioctl函数。
124行,见小节2.1.3。跳转到驱动binder_mmap函数。
关于驱动
这个用户空间open函数会走入内核的binder驱动中binder_open函数,类似的后面还会有其他函数用户空间与内核空间驱动代码一一对应,截取如下。驱动的知识:
drivers/android/binder.c
static const struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, .unlocked_ioctl = binder_ioctl, .compat_ioctl = binder_ioctl, .mmap = binder_mmap, .open = binder_open, .flush = binder_flush, .release = binder_release,};
关于驱动代码版本
pixel2的驱动代码是msm-wahoo-4.4分支,参见官网文档:
Device | Binary path in AOSP tree | Repo branches |
---|---|---|
Pixel 2 (walleye) Pixel 2 XL (taimen) | device/google/wahoo-kernel | android-msm-wahoo-4.4-android10-qpr3 |
github有人传了,此处借用下
drivers/android/binder.c
4922 static int binder_open(struct inode *nodp, struct file *filp)4923 {4924 struct binder_proc *proc;4925 struct binder_device *binder_dev;4926 4930 proc = kzalloc(sizeof(*proc), GFP_KERNEL);4931 if (proc == NULL)4932 return -ENOMEM;4933 spin_lock_init(&proc->inner_lock);4934 spin_lock_init(&proc->outer_lock);4935 get_task_struct(current->group_leader);4936 proc->tsk = current->group_leader;4937 mutex_init(&proc->files_lock);4938 INIT_LIST_HEAD(&proc->todo);4939 if (binder_supported_policy(current->policy)) {4940 proc->default_priority.sched_policy = current->policy;4941 proc->default_priority.prio = current->normal_prio;4942 } else {4943 proc->default_priority.sched_policy = SCHED_NORMAL;4944 proc->default_priority.prio = NICE_TO_PRIO(0);4945 }4946 4947 binder_dev = container_of(filp->private_data, struct binder_device,4948 miscdev);4949 proc->context = &binder_dev->context;4950 binder_alloc_init(&proc->alloc);4951 4952 binder_stats_created(BINDER_STAT_PROC);4953 proc->pid = current->group_leader->pid;4954 INIT_LIST_HEAD(&proc->delivered_death);4955 INIT_LIST_HEAD(&proc->waiting_threads);4956 filp->private_data = proc;4957 4958 mutex_lock(&binder_procs_lock);4959 hlist_add_head(&proc->proc_node, &binder_procs);4960 mutex_unlock(&binder_procs_lock);4961 4979 return 0;4980 }
.open = binder_open这个方法作用是啥呢?打眼一看,有没有像一个类的构造函数,如果把驱动也比喻成一个类的话。用户空间传参来初始化出一个代表用户空间进程的“对象”变量-->4924 struct binder_proc *proc;
,然后经过初步处理对proc赋值、初始化。这个binder_proc结构体代表一个用户空间的进程,无论是client端还是server端,只要open了binder驱动,就会被驱动以一个binder_proc的形式,添加记录在内核驱动的链表数据结构,binder_procs里。4959 hlist_add_head(&proc->proc_node, &binder_procs);
4935行的current是啥:
current 指针指向当前在运行的进程. 在一个系统调用执行期间, 例如 open 或者 read, 当前进程是发出调用的进程. 内核代码可以通过使用 current 来使用进程特定的信息
了解binder_open的功能后还需要关注这其中涉及到的数据结构(这很重要),也就是binder_proc结构体及其子数据结构。
详见:、。其中有一个数据结构要重点关注,这是binder驱动拆分新产生的。较6.0里用的3.18.10kernel不同,binder_alloc,用于储存申请内存相关的数据,是binder_proc结构体成员。
drivers/android/binder_alloc.h
101 struct binder_alloc {102 struct mutex mutex;//??103 struct vm_area_struct *vma;//代表一块用户空间内存104 struct mm_struct *vma_vm_mm;//代表整个进程的虚拟地址空间105 void __user *buffer;//指向用户空间内存起始地址alloc->buffer = (void __user *)vma->vm_start;106 struct list_head buffers;//链表,存放binder_buffer结构体107 struct rb_root free_buffers;//红黑树,存放空闲binder_buffer结构体108 struct rb_root allocated_buffers;//红黑树,存放已分配binder_buffer结构体109 size_t free_async_space;//空闲异步空间110 struct binder_lru_page *pages;//映射页数111 size_t buffer_size;//映射内存大小alloc->buffer_size = vma->vm_end - vma->vm_start;112 uint32_t buffer_free;//free标志位113 int pid;//进程id114 size_t pages_high;115 };
结束,我们返回用户空间继续执行。
ioctl会走入内核驱动的binder_ioctl方法。
drivers/android/binder.c
4741 static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)4742 {4743 int ret;4744 struct binder_proc *proc = filp->private_data;4745 struct binder_thread *thread;4746 unsigned int size = _IOC_SIZE(cmd);4747 void __user *ubuf = (void __user *)arg;//用户空间的&vers4751 4752 binder_selftest_alloc(&proc->alloc);4755 4756 ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);4760 thread = binder_get_thread(proc);4765 4766 switch (cmd) {4796 case BINDER_VERSION: {4797 struct binder_version __user *ver = ubuf;4798 4799 if (size != sizeof(struct binder_version)) {4800 ret = -EINVAL;4801 goto err;4802 }4803 if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,4804 &ver->protocol_version)) {4805 ret = -EINVAL;4806 goto err;4807 }4808 break;4809 }
第一次进ioctl,很清晰的逻辑,switch传入的cmd参数,参数还有很多,此处只截取上面传入的BINDER_VERSION。
4756行涉及wait_event_interruptible的用法,可参考:
好,接下来看重点,4803行将binder驱动的版本号BINDER_CURRENT_PROTOCOL_VERSION,通过put_user方法返回给了用户空间,存入变量&ver->protocol_version,此次ioctl调用结束。
再回顾下我们的用户空间sm代码
115 if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||116 (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
116行对put_user的返回值做了校验。接下来是mmap的小节,2.1.3
用户空间mmap函数会走入内核空间binder驱动的binder_mmap方法。
drivers/android/binder.c
4879 static int binder_mmap(struct file *filp, struct vm_area_struct *vma)4880 {4881 int ret;4882 struct binder_proc *proc = filp->private_data;4883 const char *failure_string;4884 4885 if (proc->tsk != current->group_leader)4886 return -EINVAL;4887 4888 if ((vma->vm_end - vma->vm_start) > SZ_4M)4889 vma->vm_end = vma->vm_start + SZ_4M;4890 4902 vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP;4903 vma->vm_flags &= ~VM_MAYWRITE;4904 4905 vma->vm_ops = &binder_vm_ops;4906 vma->vm_private_data = proc;4907 4908 ret = binder_alloc_mmap_handler(&proc->alloc, vma);4909 if (ret)4910 return ret;4911 mutex_lock(&proc->files_lock);4912 proc->files = get_files_struct(current);4913 mutex_unlock(&proc->files_lock);4914 return 0;4920 }
binder_mmap方法较6.0有变动,申请内核空间内存的相关代码被拆分到binder_alloc.c
进入4098行,开始处理内核空间内存分配并与用户空间内存地址做映射。
drivers/android/binder_alloc.c
635 /** 636 * binder_alloc_mmap_handler() - map virtual address space for proc 637 * @alloc:| alloc structure for this proc 638 * @vma:| vma passed to mmap() 639 * 640 * Called by binder_mmap() to initialize the space specified in 641 * vma for allocating binder buffers 642 * 643 * Return: 644 * 0 = success 645 * -EBUSY = address space already mapped 646 * -ENOMEM = failed to map memory to given address space 647 */ 648 int binder_alloc_mmap_handler(struct binder_alloc *alloc, 649 struct vm_area_struct *vma) 650 { 651 int ret; 652 const char *failure_string; 653 struct binder_buffer *buffer; 654 662 alloc->buffer = (void __user *)vma->vm_start; 663 mutex_unlock(&binder_alloc_mmap_lock); 664 665 alloc->pages = kzalloc(sizeof(alloc->pages[0]) * 666 ((vma->vm_end - vma->vm_start) / PAGE_SIZE), 667 GFP_KERNEL); 673 alloc->buffer_size = vma->vm_end - vma->vm_start; 674 675 buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); 681 682 buffer->user_data = alloc->buffer; 683 list_add(&buffer->entry, &alloc->buffers); 684 buffer->free = 1; 685 binder_insert_free_buffer(alloc, buffer); 686 alloc->free_async_space = alloc->buffer_size / 2; 687 barrier(); 688 alloc->vma = vma; 689 alloc->vma_vm_mm = vma->vm_mm; 690 /* Same as mmgrab() in later kernel versions */ 691 atomic_inc(&alloc->vma_vm_mm->mm_count); 692 693 return 0; 694 706 }
注意,为方便理解请记住,入参*alloc
是内核空间这侧,*vma
代表用户空间待映射区域。
662行,获取用户空间内存块起始地址
665行,申请一块内核空间虚拟地址并为之映射物理内存。大小为待映射*vma
的页数 乘alloc->pages[0]
结构体size。这个alloc->pages
是一个数组,数组成员是binder_lru_page结构体,又其中的struct page *page_ptr;
为内存物理页指针(是一页)。见数据结构:page。
这样用户空间虚拟地址多少页,内核空间虚拟地址和其映射的物理内存就是多少页。
学习资料:
673行,获取用户空间内存块大小
675行,申请一块内核空间虚拟地址并为之映射物理内存。分配给结构体binder_buffer *buffer
。
682行,将662行拿到的用户空间起始地址再传给这个binder_buffer *buffer
存一下
683行,将这个binder_buffer *buffer
加入链表&alloc->buffers
684-691行,初始化剩下的结构体成员变量。
结束,总结一下。用户空间的mmap系统调用,并未在内核空间分配物理内存(对应*vma
的物理内存),仅仅做了用户空间vm_area_struct *vma
到内核空间binder_alloc *alloc->pages
的虚拟地址映射。
现在,返回到用户空间sm进程的binder_open方法124行,无异常则binder_open方法也调用完毕再返回上层,至sm的main函数394行。
下面2.2小节,走入contex_manager的注册流程,main函数407行。sm渡劫成功原地升天,成为实名binder世界的神。
frameworks/native/cmds/servicemanager/binder.c
147 int binder_become_context_manager(struct binder_state *bs)148 {149 struct flat_binder_object obj;150 memset(&obj, 0, sizeof(obj));151 obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX;152153 int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj);161 return result;162 }
关键数据结构struct flat_binder_object
,参考附录。
同之前2.12节请求驱动版本时的流程一致,走入binder_ioctl方法。只是switch的分支变成
drivers/android/binder.c
5058 case BINDER_SET_CONTEXT_MGR_EXT: {5059 struct flat_binder_object fbo;50605061 if (copy_from_user(&fbo, ubuf, sizeof(fbo))) {5062 ret = -EINVAL;5063 goto err;5064 }5065 ret = binder_ioctl_set_ctx_mgr(filp, &fbo);5066 if (ret)5067 goto err;5068 break;5069 }
学习资料:
5061将用户空间的flat_binder_object实例复制到内核空间的fbo。走入5065行。
drivers/android/binder.c
4906 static int binder_ioctl_set_ctx_mgr(struct file *filp,4907 struct flat_binder_object *fbo)4908 {4909 int ret = 0;4910 struct binder_proc *proc = filp->private_data;4911 struct binder_context *context = proc->context;4912 struct binder_node *new_node;4913 kuid_t curr_euid = current_euid();49144936 new_node = binder_new_node(proc, fbo);4941 binder_node_lock(new_node);4942 new_node->local_weak_refs++;4943 new_node->local_strong_refs++;4944 new_node->has_strong_ref = 1;4945 new_node->has_weak_ref = 1;4946 context->binder_context_mgr_node = new_node;4947 binder_node_unlock(new_node);4948 binder_put_node(new_node);4952 }
关键数据结构binder_node,代表一个binder服务端也叫binder实体(书上都这么叫)
4936行new出了一个binder_node,从此作为服务端的用户空间进程sm,在内核空间binder驱动的代表就产生了。
4946行将这个新的new_node注册到上下文变量context->binder_context_mgr_node
。这个变量定义在结构体binder_context中,全系统唯一。如何做到的呢?就是下面每次binder_open都会将context同步到这个新的进程proc中。关键数据结构:binder_device、binder_context。
drivers/android/binder.c
5226 static int binder_open(struct inode *nodp, struct file *filp)5227 {5252 binder_dev = container_of(filp->private_data, struct binder_device,miscdev);5254 proc->context = &binder_dev->context;
学习资料:
至此,本小节结束,返回到用户空间sm进程main函数的407行。除了下一小节的binder_loop方法外,还有selinux权限的相关代码,我们先忽略它。
frameworks/native/cmds/servicemanager/binder.c
415 void binder_loop(struct binder_state *bs, binder_handler func)416 {417 int res;418 struct binder_write_read bwr;419 uint32_t readbuf[32];420421 bwr.write_size = 0;422 bwr.write_consumed = 0;423 bwr.write_buffer = 0;424425 readbuf[0] = BC_ENTER_LOOPER;426 binder_write(bs, readbuf, sizeof(uint32_t));427428 for (;;) {429 bwr.read_size = sizeof(readbuf);430 bwr.read_consumed = 0;431 bwr.read_buffer = (uintptr_t) readbuf;432433 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);434440 res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);441 if (res == 0) {442 ALOGE("binder_loop: unexpected reply?!\n");443 break;444 }445 if (res < 0) {446 ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));447 break;448 }449 }450 }
进入binder_loop,不断读binder驱动然后处理返回信号与数据。有人可能要问了,为啥要循环读,不累吗?为啥不能驱动主动通知sm?
好问题。在andrid12上,sm已经改了。看一下426行。
164 int binder_write(struct binder_state *bs, void *data, size_t len)165 {166 struct binder_write_read bwr;167 int res;168169 bwr.write_size = len;170 bwr.write_consumed = 0;171 bwr.write_buffer = (uintptr_t) data;172 bwr.read_size = 0;173 bwr.read_consumed = 0;174 bwr.read_buffer = 0;175 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);176 if (res < 0) {177 fprintf(stderr,"binder_write: ioctl failed (%s)\n",178 strerror(errno));179 }180 return res;181 }
入参void *data
是readbuf[0] = BC_ENTER_LOOPER;
。关键数据结构:binder_write_read。
接着重点是175行的ioctl,我们已经很熟悉它了,借助该系统调用让我们再次进入内核空间binder驱动,同之前2.12节请求驱动版本时的差异为入参2和入参3。
drivers/android/binder.c
5039 switch (cmd) {5040 case BINDER_WRITE_READ:5041 ret = binder_ioctl_write_read(filp, cmd, arg, thread);5042 if (ret)5043 goto err;5044 break;
5041行跳转处理,需对入参保持关注。
cmd是BINDER_WRITE_READ
arg是&bwr,并且该结构体的成员bwr.write_buffer = (uintptr_t) data 是readbuf(这是个指针、数组的首地址),而readbuf[0] = BC_ENTER_LOOPER(这才是首地址指针内容)。
题外话。后面的copy_from_user、get_user操作让我闹了个大笑话,我一直在想,不是都copy到内核了吗,为啥还要get_user呢???最后经大佬指点才整明白。哦,原来如此简单!就是个指针及其内容的问题。吃一堑长一智,读代码要用心,别看漏了。
drivers/android/binder.c
4840 static int binder_ioctl_write_read(struct file *filp,4841 unsigned int cmd, unsigned long arg,4842 struct binder_thread *thread)4843 {4844 int ret = 0;4845 struct binder_proc *proc = filp->private_data;4846 unsigned int size = _IOC_SIZE(cmd);4847 void __user *ubuf = (void __user *)arg;4848 struct binder_write_read bwr;4854 if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {4855 ret = -EFAULT;4856 goto out;4857 }48634864 if (bwr.write_size > 0) {4865 ret = binder_thread_write(proc, thread,4866 bwr.write_buffer,4867 bwr.write_size,4868 &bwr.write_consumed);4869 trace_binder_write_done(ret);4870 if (ret < 0) {4870 if (ret < 0) {4871 bwr.read_consumed = 0;4872 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))4873 ret = -EFAULT;4874 goto out;4875 }4876 }4877 if (bwr.read_size > 0) {4878 ret = binder_thread_read(proc, thread, bwr.read_buffer,4879 bwr.read_size,4880 &bwr.read_consumed,4881 filp->f_flags & O_NONBLOCK);4882 trace_binder_read_done(ret);4883 binder_inner_proc_lock(proc);4884 if (!binder_worklist_empty_ilocked(&proc->todo))4885 binder_wakeup_proc_ilocked(proc);4886 binder_inner_proc_unlock(proc);4887 if (ret < 0) {4888 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))4889 ret = -EFAULT;4890 goto out;4891 }4892 }4898 if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {4899 ret = -EFAULT;4900 goto out;4901 }4902 out:4903 return ret;4904 }
4854行将用户空间sm的binder_write_read结构体复制到内核的bwr,需要注意此处的copy_from_user不是你通常听到的一次拷贝中的那个,同理4898行的copy_to_user也不是。那要问了,既然不是那这是啥?这里的copy_from/to是传输指令的,可以理解为通信协议,命令。还不是通信数据的传输。这里提前告诉你,别被固有印象弄蒙了,因为我就蒙过。
由于我们此次的write_size是1,因为readbuf[0] = BC_ENTER_LOOPER。所以4865行走入方法binder_thread_write
drivers/android/binder.c
3688 static int binder_thread_write(struct binder_proc *proc,3689 struct binder_thread *thread,3690 binder_uintptr_t binder_buffer, size_t size,3691 binder_size_t *consumed)3692 {3693 uint32_t cmd;3694 struct binder_context *context = proc->context;3695 void __user *buffer = (void __user *)(uintptr_t)binder_buffer;3696 void __user *ptr = buffer + *consumed;3697 void __user *end = buffer + size;36983699 while (ptr < end && thread->return_error.cmd == BR_OK) {3700 int ret;37013702 if (get_user(cmd, (uint32_t __user *)ptr))3703 return -EFAULT;3704 ptr += sizeof(uint32_t);3711 switch (cmd) {3953 case BC_ENTER_LOOPER:3957 if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {3958 thread->looper = BINDER_LOOPER_STATE_INVALID;3959 binder_user_error("%d:%d ERROR: BC_ENTER_LOOPER called after BC_REGISTER_LOOPER\n",3960 proc->pid, thread->pid);3961 }3962 thread->looper = BINDER_LOOPER_STATE_ENTERED;3963 break;4150 *consumed = ptr - buffer;4151 }4152 return 0;4153 }
3699行是个遍历,遍历了命令数组,因为我们传下来的数组只有readbuf[0] = BC_ENTER_LOOPER一个成员,所以就只跑一遍。
还记得我闹的那个笑话吗?就发生在3702行。这行我们依据用户空间传下来的地址真正的拿到了值:BC_ENTER_LOOPER。
所以走入了3953-3963行的case,在这里3962行,仅仅设置了线程结构体的looper成员的值,是一个状态位。仅此而已。
方法调用结束,返回至驱动的binder_ioctl_write_read方法4865行。然后下一步走到4898行,将此次的运行结果反馈给用户空间等待我们的sm。再次提醒下,这不是我们常听到的“一次拷贝”的copy_from/to_user。
drivers/android/binder.c
4840 static int binder_ioctl_write_read(struct file *filp,4841 unsigned int cmd, unsigned long arg,4842 struct binder_thread *thread)4843 {4898 if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {4899 ret = -EFAULT;4900 goto out;4901 }
现在我们回到了用户空间sm的binder_loop函数426行,让我们走入接下来的死循环,看下读驱动-->解析的代码。
frameworks/native/cmds/servicemanager/binder.c
415 void binder_loop(struct binder_state *bs, binder_handler func)416{426 binder_write(bs, readbuf, sizeof(uint32_t));427428 for (;;) {429 bwr.read_size = sizeof(readbuf);430 bwr.read_consumed = 0;431 bwr.read_buffer = (uintptr_t) readbuf;432433 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);434440 res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);441 if (res == 0) {442 ALOGE("binder_loop: unexpected reply?!\n");443 break;444 }445 if (res < 0) {446 ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));447 break;448 }449 }450 }
死循环第一步,读驱动。我们又陷入内核啦。binder_ioctl-->case BINDER_WRITE_READ:binder_ioctl_write_read,我们直接看binder_ioctl_write_read方法的readsize部分。因为啥呢?因为用户空间ioctl的传参bwr.read_size为1,还是readbuf[0] = BC_ENTER_LOOPER。
drivers/android/binder.c
4840 static int binder_ioctl_write_read(struct file *filp,4841 unsigned int cmd, unsigned long arg,4842 struct binder_thread *thread)4843 {4877 if (bwr.read_size > 0) {4878 ret = binder_thread_read(proc, thread, bwr.read_buffer,4879 bwr.read_size,4880 &bwr.read_consumed,4881 filp->f_flags & O_NONBLOCK);4882 trace_binder_read_done(ret);4883 binder_inner_proc_lock(proc);4884 if (!binder_worklist_empty_ilocked(&proc->todo))4885 binder_wakeup_proc_ilocked(proc);4886 binder_inner_proc_unlock(proc);4887 if (ret < 0) {4888 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))4889 ret = -EFAULT;4890 goto out;4891 }4892 }4898 if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {4899 ret = -EFAULT;4900 goto out;4901 }4902 out:4903 return ret;4904 }
需要关注的有4878、4883和4898行。我们看下binder_thread_read方法。
drivers/android/binder.c
4229 static int binder_thread_read(struct binder_proc *proc,4230 struct binder_thread *thread,4231 binder_uintptr_t binder_buffer, size_t size,4232 binder_size_t *consumed, int non_block)4233 {4234 void __user *buffer = (void __user *)(uintptr_t)binder_buffer;4235 void __user *ptr = buffer + *consumed;4236 void __user *end = buffer + size;42374238 int ret = 0;4239 int wait_for_proc_work;42404241 if (*consumed == 0) {4242 if (put_user(BR_NOOP, (uint32_t __user *)ptr))4243 return -EFAULT;4244 ptr += sizeof(uint32_t);4245 }
入参binder_size_t *consumed
还记的怎么来的吗?我们回顾下用户空间sm的代码
frameworks/native/cmds/servicemanager/binder.c
415 void binder_loop(struct binder_state *bs, binder_handler func){428 for (;;) {429 bwr.read_size = sizeof(readbuf);430 bwr.read_consumed = 0;431 bwr.read_buffer = (uintptr_t) readbuf;432433 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);440 res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
*consumed
是0,所以驱动里直接4242行反馈给用户空间一个码BR_NOOP,返回到哪里呢,返回到(void __user *)(uintptr_t)binder_buffer
也就是431行的bwr.read_buffer = (uintptr_t) readbuf
。
现在我们从内核空间拿到了反馈,开始着手处理,走入binder_loop方法的440行binder_parse。
frameworks/native/cmds/servicemanager/binder.c
229 int binder_parse(struct binder_state *bs, struct binder_io *bio,230 uintptr_t ptr, size_t size, binder_handler func)231 {232 int r = 1;233 uintptr_t end = ptr + (uintptr_t) size;234235 while (ptr < end) {236 uint32_t cmd = *(uint32_t *) ptr;237 ptr += sizeof(uint32_t);238 #if TRACE239 fprintf(stderr,"%s:\n", cmd_name(cmd));240 #endif241 switch(cmd) {242 case BR_NOOP:243 break;329 return r;330 }
由于我们从内核驱动拿到的返回码是BR_NOOP,所以走到243行break退出了,没有真正的工作让我们用户空间sm做处理。是不是觉得读驱动读了个寂寞。sm大多数情况下都很寂寞,寂寞是常态。
329行返回上层,返回值是int r = 1
。所以binder_loop的死循环会继续,如果r是≤0,那sm进程就完蛋了。
frameworks/native/cmds/servicemanager/binder.c
415 void binder_loop(struct binder_state *bs, binder_handler func){428 for (;;) {433 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);440 res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);441 if (res == 0) {//完蛋了442 ALOGE("binder_loop: unexpected reply?!\n");443 break;444 }445 if (res < 0) {//完蛋了446 ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));447 break;448 }449 }450 }
至此从init进程起的用户进程servicemanager的启动流程就结束了,启动流程很简单,并且没有涉及sm的核心业务,例如增加、查询权限管理等,但是能让我们有个印象,初步认识sm是谁,binder驱动是啥,用户空间和驱动交互的手段都是什么等。下面开始总结。
就像service_manager.c#main函数里写的那样,sm的启动流程主要是以下四部分工作。
1、binder_open
打开binder驱动,并且驱动生成binder_proc结构体将sm加入procs链表
2、bind_mmap
将该进程的虚拟地址大小同步给内核空间,记录为多少页,存在pages中
3、向驱动注册成为管理员,handle是0
4、用户空间无限循环ioctl读消息、处理消息。
转载地址:http://ccluz.baihongyu.com/