需要掌握的点
1.一个流程:servier--->binder---->servermanager ** server注册的流程图一个整体的类和方法流向**
2.重要的几个方法:open ,mmap ,iocontro。特别是mmap内存映射 (图片解析)
3.唤醒流程图,bp和br
4.binder_thread_write 和 binder_thread_read 和 copy_from_user 和copy_to_user
5.Java层,分析总的一个流程图,4个角色的关系和代理的关系。从一个activityManager开始!
6.数据流向?
- 流程总结:
[图片上传失败...(image-9fecb0-1643110660184)]
1).Binder 驱动的全局链表 binder_procs 中插入服务端的信息(binder_proc 结构体,每个 binder_proc 结构体中都有 todo 任务队列),然后向 ServiceManager 的 svcinfo 列表中缓存一下注册的服务。
2). 有了服务端,客户端就可以跟服务端通讯了,通讯之前需要先获取到服务,拿到服务的代理,也可以理解为引用
获取服务端的方式就是通过 ServiceManager 向 svcinfo 列表中查询一下返回服务端的代理,svcinfo 列表就是所有已注册服务的通讯录,保存了所有注册的服务信息。
3).有了服务端的引用我们就可以向服务端发送请求了,通过 BinderProxy 将我们的请求参数发送给 ServiceManager,通过共享内存的方式使用内核方法 copy_from_user() 将我们的参数先拷贝到内核空间,这时我们的客户端进入等待状态,然后 Binder 驱动向服务端的 todo 队列里面插入一条事务,执行完之后把执行结果通过 copy_to_user() 将内核的结果拷贝到用户空间(这里只是执行了拷贝命令,并没有拷贝数据,binder只进行一次拷贝),唤醒等待的客户端并把结果响应回来,这样就完成了一次通讯。
2.重要的几个方法:open ,mmap ,iocontro。特别是mmap内存映射
内存的拷贝次数有几次?
肯定不是 1 次,服务端把数据拷到内核再拷回去 2 次,客户端把数据拷到内核再拷回去 2 次,还有一次是客户端把数据拷到服务端映射的内存中,还有一次是从服务端的映射内存拷贝到驱动层创建的内存。6 次拷贝
[图片上传失败...(image-36616-1643110660185)]
一次拷贝的过程:
发送方进程通过系统调用 copyfromuser() 将数据 copy 到内核中的内(这一次拷贝),核缓存区,
由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。
Binder在一次拷贝中
的作用则是怎么样的?
连接 两个进程,实现了mmap()系统调用,主要负责 创建数据接收的缓存空间 & 管理数据接收缓存
3、唤醒流程图,bp和br 解析
内核层内核层的通信都是通过ioctl来进行的,client打开一个ioctl,进入到轮询队列,一直阻塞直到时间到或者有消息。
[图片上传失败...(image-f9baa9-1643110660185)]
流程:
1.开始servermanager处于等待状态
2.然后media进程发送BP_transation
3.binder收到后发送br_transation。把servermanager唤醒,同时br_transtation_complete发送给客户端
4.客户端收到指令后,客户端处于等待的状态!
5.同上serverManager收到指令后。开始执行执行完后发送br_replay给binder驱动。同时还会发送
br_transtation_complete给servermanager。binder驱动发送br_rep给客户端唤醒
问题:
.是先serverManager在进行循环等待吗?然后客户端进行请求add吗?
4.binder_thread_write 和 binder_thread_read 和 copy_from_user 和copy_to_user 关系
binder_thread_write :主要作用:
binder_thread_read :主要作用:
copy_from_user :主要作用:
copy_to_user :主要作用:
调用流程:
binder_ioctl
binder_ioctl_write_read
copy_from_user
binder_thread_write
binder_thread_read
copy_to_user
binder_thread_write里面又会调用 copy_from_user
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
return_error == BR_OK) {
switch (cmd) {
...
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
// 把数据从用户空间拷贝到内核空间 binder_transaction_data
if (copy_from_user(&tr, ptr, sizeof(tr)))
binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
break;
}
}
return 0;
binder_thread_read里面又会调用copy_to_user
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed, int non_block)
{
// 开始不断循环读取数据
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
ptr += sizeof(uint32_t);
// 把数据拷贝到用户空间
if (copy_to_user(ptr, &tr, sizeof(tr)))
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
// 从 filp 获取 binder_proc
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
// 进入休眠直到中断被唤醒
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret)
goto err_unlocked;
// 从 binder_proc 获取 binder 线程
thread = binder_get_thread(proc);
switch (cmd) {
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
int ret = 0;
// 从 filp 中获取 binder_proc
struct binder_proc *proc = filp->private_data;
// arg 是上层传下来的 binder_write_read 的结构体对象地址
struct binder_write_read bwr;
// 将用户空间的 binder_write_read 拷贝到内核空间的 bwr
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
// 进入这里不断的读取数据
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, 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 out;
}
}
// 将内核空间的 bwr 数据拷贝到用户空间的 binder_write_read
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed, int non_block)
{
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
// 如果线程事务栈和 todo 队列都为空,说明此时没有要当前线程处理的任务,将增加空闲线程的计数器(即将 wait_for_proc_work 设为1),让线程等待在**进程**的 wait 队列上
wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);
if (wait_for_proc_work)
proc->ready_threads++;
binder_unlock(__func__);
if (wait_for_proc_work) {
if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED))) {
// 线程还未进入 binder 循环,输出错误信息,并阻塞直到 binder_stop_on_user_error 小于2
wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2);
}
binder_set_nice(proc->default_priority);
// 非阻塞
if (non_block) {
...
} else{
// 如果是阻塞的读操作,则让进程阻塞在 proc 的 wait 队列上,直到 binder_has_proc_work(thread) 为 true,即进程有工作待处理
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
}
} else {
...
}
// 下面的代码目前还执行不到,需要等待 thread 线程的 todo 里面有内容
return 0;
}来源: https://www.jianshu.com/p/4472c7dabe6c
[图片上传失败...(image-c656fd-1643110660184)]
5.java层调用
[图片上传失败...(image-f837a8-1643110660184)]
但是上面还有个问题就是client和service要直接和binder driver打交道,但是实际上client和service并不想知道binder相关协议,所以进一步client通过添加proxy代理,service通过添加stub来进一步处理与binder的交互。
[图片上传失败...(image-b7ea4c-1643110660184)]
这样的好处是client和service都可以不用直接去和binder打交道。上面的图好像已经很完善了,但是Android系统更进一步封装,不让client知道Binder的存在,Android系统提供了Manager来管理client。如下图:
[图片上传失败...(image-14601e-1643110660184)]
这样client只需要交给manager来管理就好了,根本就不用关心进程通信相关的事,关于manager其实是很熟悉的,比如说activity的就是由ActivityManager来控制的,ActivityManager是通过Binder获取ActivityManagerService来控制activity的。这样就不用我们自己来使用Binder来ActivityManagerService通信了。
在service和binder之间还有一个contextManager,也就是serviceManage
总结流程:
注册服务过程:就是前面4篇文章讲的
第一步: service通过调用serviceManager中的addService方法,然后调用ServiceManagerNative
类中的addservice(name)
方法。
第二步: ServiceManagerNative
会通过Binder发送一条SVG_MGR_ADD_SERVICE的指令,然后通过svcmgr_handler()调用do_add_service()方法往svc_list中添加相应的service。
重点:所有的服务都要先注册到svc_list中才能被client调用到。svc_list以linkedlist的形式保存这些服务。
获取服务过程:
第一步:client要请求服务,比如说在activity中调用context.getSystemService()
方法,这个时候serviceManager
就会使用getService(name)
,然后就会调用到native层中的ServiceManagerNative
类中的getService(name)
方法。
第二步:ServiceManagerNative会通过Binder发送一条SVG_MGR_GET_SERVICE的指令,然后通过svcmgr_handler()调用do_find_service()方法去svc_list中查找到相关的service。
第三步:查找到相应的服务后就会通过Binder将服务传给ServiceManagerNative,然后传给serviceManager,最后client就可以使用了。
注意: 服务实在svclist中保存的,svclist是一个链表,因此客户端调用的服务必须要先注册到svclist中。