博客
关于我
android10Binder(一)servicemanager启动流程
阅读量:419 次
发布时间:2019-03-06

本文共 25897 字,大约阅读时间需要 86 分钟。

servicemanager启动流程

目录

前言

serviceMmanager是第一个使用binder驱动的进程(一般情况),由init进程解析init.rc后启动。他被赋予类似dns服务器的职责:管理实名binder的注册、查询。本文从init进程出发,走一遍SM的启动流程。

代码版本:android-10.0.0_r36、kernel/msm-wahoo-4.4。摘取的代码片段有删减,仅关注主要流程。

一、从init进程开始

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()

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。

2.1 binder_open(driver, 128*1024)

前几天看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函数。

2.1.1 open(driver, O_RDWR | O_CLOEXEC)

关于驱动

这个用户空间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 };

结束,我们返回用户空间继续执行。

2.1.2 ioctl(bs->fd, BINDER_VERSION, &vers)

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

2.1.3 mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0)

用户空间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世界的神。

2.2 binder_become_context_manager(bs)

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权限的相关代码,我们先忽略它。

2.3 binder_loop(bs, svcmgr_handler)

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行。

2.3.1 binder_write(bs, readbuf, sizeof(uint32_t))

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 *datareadbuf[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     }

2.3.3 for (;😉 {读驱动-->解析}

现在我们回到了用户空间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/

你可能感兴趣的文章
go等待N个线程完成操作总结
查看>>
ReactJs入门教程-精华版
查看>>
Python 之网络式编程
查看>>
MySql5.5安装步骤及MySql_Front视图配置
查看>>
mybatis绑定错误-- Invalid bound statement (not found)
查看>>
python去除字符串中的特殊字符(爬虫存储数据时会遇到不能作为文件名的字符串)
查看>>
SpringCloud微服务(03):Hystrix组件,实现服务熔断
查看>>
云计算之路-阿里云上:0:25~0:40网络存储故障造成网站不能正常访问
查看>>
网站故障公告1:使用阿里云RDS之后一个让人欲哭无泪的下午
查看>>
上周热点回顾(8.12-8.18)
查看>>
蹒跚来迟:新版博客后台上线公测
查看>>
[网站公告]又拍云API故障造成图片无法上传(已恢复)
查看>>
上周热点回顾(6.9-6.15)
查看>>
.NET跨平台之旅:借助ASP.NET 5 Beta5的新特性显示CLR与操作系统信息
查看>>
上周热点回顾(7.27-8.2)
查看>>
上周热点回顾(5.9-5.15)
查看>>
上周热点回顾(1.16-1.22)
查看>>
上周热点回顾(1.23-1.29)
查看>>
云计算之路-阿里云上:14:20-14:55博客后台2台服务器都CPU 100%引发的故障
查看>>
【故障公告】10:30-10:45 左右 docker swarm 集群节点问题引发故障
查看>>