很多BAT也不一定能懂的binder机制! 我同事从小米跳槽过来,干安卓framework层10年,是小米的专家级别 然后他把binder驱动层全部和我讲解了一遍,然后我这边做个笔记分享给大家。 因为搞懂binder需要会c,linux内核知识。看java根本就看不懂! 分4篇文字讲解: 01. Android Binder图解 小米系统专家 解析Service 的addService注册过程 (安卓12) 02. Android Binder图解 小米系统专家 解析 ServiceManager和binder通信 (安卓12) 03. Android Binder图解 小米系统专家 解析binder驱动层解析binder通信过程 (安卓12) 04. Android Binder图解 小米系统专家 从binder java层解析binder整个流程 (安卓12) 问题: binder驱动是如何和serviceManager进行通信的?数据是如何传递的? 打开驱动,然后进行读取文件 相关源码文件: ServiceManager 进程是由 init 进程通过解析 init.rc 文件而创建的。 ServiceManager 进程启动的三个阶段:
最终会通过 binder 驱动跨进程执行** ServiceMananger 的 do_add_service **方法。 servicemanager的入口函数在service_manager.c中: 是c文件哦,不是cpp。 **``` ![]() } 1. 打开 binder 驱动,具体的代码都在binder.c里面 struct binder_state *binder_open(size_t mapsize) { struct binder_state *bs; struct binder_version vers; bs = malloc(sizeof(*bs)); if (!bs) { errno = ENOMEM; return NULL; } // 打开 binder 驱动,调用的是驱动层的 binder_open bs->fd = open("/dev/binder", O_RDWR); if (bs->fd < 0) { fprintf(stderr,"binder: cannot open device (%s)\n", strerror(errno)); goto fail_open; } // 获取 binder 驱动的版本,调用的是 binder_ioctl 方法获取 if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) || (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) { fprintf(stderr, "binder: kernel driver version (%d) differs from user space version (%d)\n", vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION); goto fail_open; } // 调用的是驱动层的 binder_mmap 方法 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; } return bs; fail_map: close(bs->fd); fail_open: free(bs); return NULL; } 调用mmap函数进行内存映射 2. 成为 binder 驱动管理者 int binder_become_context_manager(struct binder_state *bs) { // 告诉驱动,当前进程成为驱动的上下文管理,也是调用的驱动层的 binder_ioctl 方法 return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); } 3. 循环等待处理 client 请求 for (;;) { bwr.read_size = sizeof(readbuf); bwr.read_consumed = 0; bwr.read_buffer = (uintptr_t) 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, (uintptr_t) 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; } } int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, uid_t uid, int allow_isolated, pid_t spid) { struct svcinfo *si; //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle, // allow_isolated ? "allow_isolated" : "!allow_isolated", uid); if (!handle || (len == 0) || (len > 127)) return -1; // 判断当前进程的 pid 是不是有权限 if (!svc_can_register(s, len, spid)) { ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", str8(s, len), handle, uid); return -1; } si = find_svc(s, len); if (si) { if (si->handle) { ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n", str8(s, len), handle, uid); svcinfo_death(bs, si); } si->handle = handle; } else { si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); if (!si) { ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n", str8(s, len), handle, uid); return -1; } si->handle = handle; si->len = len; memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); si->name[len] = '\0'; si->death.func = (void*) svcinfo_death; si->death.ptr = si; si->allow_isolated = allow_isolated; si->next = svclist; svclist = si; } // 观察这个服务所在的进程是否死了 binder_acquire(bs, handle); binder_link_to_death(bs, handle, &si->death); return 0; } struct binder_transaction_data { union { __u32 handle; //binder_ref(即 handle ) binder_uintptr_t ptr; // Binder_node 的内存地址 } target; //RPC目标 binder_uintptr_t cookie; // BBinder 指针 __u32 code; //RPC代码,代表 Client 与 Server 双方约定的命令码 __u32 flags; //标志位,比如 TF_ONE_WAY 代表异步,即不等待 Server 端回复 pid_t sender_pid; //发送端进程的 pid uid_t sender_euid; //发送端进程的 uid binder_size_t data_size; //data 数据的总大小 binder_size_t offsets_size; //IPC 对象的大小 union { struct { binder_uintptr_t buffer; //数据区起始地址 binder_uintptr_t offsets; //数据区 IPC 对象偏移量 } ptr; __u8 buf[8]; } data; //RPC数据 }; bind.c /dev/binder copy_from_user函数:里面是for循环!! servicemanager成功注册成为Binder机制的上下文管理者后,servicemanager就是Binder机制的“总管”了,它需要在系统运行期间处理client端的请求,由于client端的请求不确定何时发送,因此需要通过无限循环来实现,实现这一需求的函数就是binder_loop。 ———————————————— servicemanager是系统中的关键服务,关键服务是不会退出的,如果退出了,系统就会重启,当系统重启时就会启动用onrestart关键字修饰的进程,比如zygote、media、surfaceflinger等等。 ServiceManager本身的工作很简单:注册服务、查询服务、列出所有服务,启动一个死循环来解析Binder驱动读写动作,进行事务处理 问题:ServiceManager 是如何管理service信息的? 通过前面的一些信息,我们了解到,ServiceManager用来管理服务信息,那么它是如何进行管理的呢? 在ServiceMnager的进程里有一个全局性的svclist变量,服务信息都存在于这里 ServiceManager存在的意义 为何需要一个这样的东西呢? 原来,Android系统中Service信息都是先add到ServiceManager中,由ServiceManager来集中管理,这样就可以查询当前系统有哪些服务。而且,Android系统中某个服务例如MediaPlayerService的客户端想要和MediaPlayerService通讯的话,必须先向ServiceManager查询MediaPlayerService的信息,然后通过ServiceManager返回的东西再来和MediaPlayerService交互。 毕竟,要是MediaPlayerService身体不好,老是挂掉的话,客户的代码就麻烦了,就不知道后续新生的MediaPlayerService的信息了,所以只能这样: MediaPlayerService向SM注册 MediaPlayerClient查询当前注册在SM中的MediaPlayerService的信息 根据这个信息,MediaPlayerClient和MediaPlayerService交互 另外,ServiceManager的handle标示是0,所以只要往handle是0的服务发送消息了,最终都会被传递到ServiceManager中去。 ServiceManager的整体流程如下: 1.打开设备,mmap一个128K的内存空间,进行用户空间和内核空间的内存绑定 2.注册成为上下文的管理者--守护进程 3.陷入死循环,标注线程的looper状态为enter 4.不停的操作binder读写过程 5.解析binder数据,进行查询服务、注册服务、列出服务的核心操作 由于在进行服务注册的时候,把svcinfo_death()注册到了binder_death的中,当收到BR_DEAD_BINDER时,表明应用层向Binder驱动发送Binder调用时,Binder应用层的另一个端已经死亡,进行死亡通知操作,调用svcinfo_death(),最终调用binder_release()发送BC_RELEASE 到内核进行处理。
最后:Binder通信流程如下: 1)首先服务端需要向ServiceManager进行服务注册,ServiceManager有一个全局的service列表svcinfo,用来缓存所有服务的handler和name。 2)客户端与服务端通信,需要拿到服务端的对象,由于进程隔离,客户端拿到的其实是服务端的代理,也可以理解为引用。客户端通过ServiceManager从svcinfo中查找服务,ServiceManager返回服务的代理。 3)拿到服务对象后,我们需要向服务发送请求,实现我们需要的功能。通过 BinderProxy 将我们的请求参数发送给 内核,通过共享内存的方式使用内核方法 copy_from_user() 将我们的参数先拷贝到内核空间,这时我们的客户端进入等待状态。然后 Binder 驱动向服务端的 todo 队列里面插入一条事务,执行完之后把执行结果通过 copy_to_user() 将内核的结果拷贝到用户空间(这里只是执行了拷贝命令,并没有拷贝数据,binder只进行一次拷贝),唤醒等待的客户端并把结果响应回来,这样就完成了一次通讯 参考博客: https://blog.csdn.net/yiranfeng/article/details/105210069 作者:鹏城十八少 |
|