图文助你理解Binder

概述

本文尽量屏蔽不影响理解的底层细节,因为太过深入的底层细节会让人深陷其中无法自拔,造成不能很好地从整体上对Binder进行把握。

The What

Android是基于Linux系统进行开发的,采用了进程隔离机制,每个进程都有自己独立的地址空间即虚拟地址,每个进程似乎都可以占满所有的内存运行,而实际上却访问的是不同的物理内存。也就是说各个进程之间数据相互独立,互不影响,一个进程崩溃并不会影响到其他进程。当不同的进程之间需要合作的时候,就涉及到在不同的独立的地址空间中传递数据的问题,IPC的方式有很多,共享内存、信号量、管道、Socket、消息队列等等,Android平台上特有Binder这种进程间通信方式。

从Java语言层面上来说,Binder是一个实现了IBinder接口的抽象类。

从IPC角度来说,Binder是一种通信机制的名称。对于FrameWork层,ServiceManager使用Binder机制和AMS、WMS等进行通信和管理。对于应用层,一来用户可以用Binder机制和ServiceManager通信,获取所需系统服务的代理,并进一步利用Binder机制和系统服务通信;二来可以用Binder机制和基于AIDL的Service(非本进程)进行通信。

The Why

为什么要使用Binder的问题比较系统而又细节,我不好做评述,只能参考网上找了两点能接受的理论作为原因。

性能方面,用户空间和内核空间是互相隔离的,客户端和服务端在用户空间,而在内核空间中,常见的方式是通过 copy_from_user 和 copy_to_user 两个系统调用来完成,但 Android Framework 考虑到这种方式涉及到两次内存拷贝,在嵌入式系统中不是很合适,于是通过 Binder Framework 通过 ioctl 系统调用,直接在内核态进行了相关的操作,节省了宝贵的空间。

安全性方面,传统的进程通信方式对于通信双方的身份并没有做出严格的验证,比如Socket通信ip地址是客户端手动填入,很容易进行伪造,而Binder机制从协议本身就支持对通信双方做身份校检,因而大大提升了安全性。

The How

Android每一个进程都是一个虚拟机,在用户空间中,并且具有自己独立的地址空间,那么不同的进程之间的通信又是怎么靠Binder机制做到的呢 ?

从进程的角度,我理解的是通过 系统调用和共享内存

以客户端调用系统服务功能为例,客户端(进程1)和服务端(进程2)之间并没有实际进行“函数调用”(也是不可能的),Binder驱动程序存在于内核进程中,我们在客户端通过一个引用调用了服务端的函数,其实是陷入内核后交给Binder驱动去找到对应进程的对应函数并执行,这里就相当于系统帮我们屏蔽了底层的过程细节,看起来好像直接调用了远端的函数。但实际上所有基于Binder机制的通信的进程都是要先和内核进程交互。Binder驱动类似于一个中转站,提供的功能也就是让各进程使用内核空间。(Binder驱动还是实现线程控制(通过中断等待队列实现线程的等待/唤醒),以及UID/PID等安全机制的保证)

整体上看起来是下图中这样的模式,虚线并不是真正的过程,实线才是真正过程:

这里写图片描述

然后再说到共享内存,传统的 IPC 传递数据,至少需要2次拷贝,一次为进程1到内核,一次为内核到进程2,而Binder只需要一次。

无论是客户端、ServiceManager还是服务端进程,Binder驱动都会为其在用户空间中分配一块虚拟地址,同时内核进程中也分配一块虚拟地址,这两块虚拟地址对应映射到同一物理地址,从而达到了用户进程和内核进程共享内存的效果。随后用户空间就可以直接访问到内核空间中的内容。

当进行数据拷贝的时候,Binder驱动是知道客户端需要通信的服务端进程的,数据会直接拷贝到服务端分配的内核空间中。

所以一次完整的方法调用中数据流动的过程是这样的,当客户端线程通过一个引用调用服务端的方法时,所需数据通过系统调用写进服务端在内核进程的共享内存中,Binder驱动程序找到需要执行的线程,远程线程从共享内存中获取数据并执行方法,把执行结果通过系统调用再写入客户端所在内核进程的共享内存中,这时候客户端线程就能从共享内存中获取返回的结果了。很像是一种“交叉”写入的方式。

共享内存看起来像是下面这样:
这里写图片描述

更进一步,为了实现跨进程的通讯,内核空间必须要能够依赖和维护某些信息,准确的找到发起通讯的源进程要去到的目的进程,实际上Binder驱动会记录:客户端Binder引用与内核中Binder引用的映射关系,内核中Binder引用与内核中Binder实体的映射关系,内核中Binder实体与服务端Binder实体的映射关系。

他们看起来是这样的:
这里写图片描述

ServiceManager的一点理解

SM在系统中充当一个守护进程,它管理了所有的服务,它类似于Internet中的DNS的作用,客户端根据一个字符串可以查询并获取到具体Binder对象的代理,客户端不应该知道远程服务的调用地址,如果知道了这势必会很不安全。每一个Binder需要将自己的名字和Binder 引用交给Service Manager,客户端只需要知道服务的名字就可以。
这里写图片描述

实际中的工作过程

假设客户端已经获取了远程服务的Binder的代理(无论是系统服务还是AIDL服务),并且调用了一个对应的函数。那么整个执行流程是下面这个样子的:
这里写图片描述

client通过Binder代理引用调用远程方法后:发送系统调用和数据,Binder驱动处理数据,唤醒服务端目标线程,并通过系统调用让服务端用户空间执行相应函数,服务端用户空间处理完请求后,再通过系统调用把结果数据交给Binder驱动,Binder驱动处理数据,唤醒client线程,客户端就可以收到函数调用的结果了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值