Binder机制是基石

一个操作系统,免不了需要提供进程间通信机制。在Linux系统中,信号、管道、报文队列,共享内存等是常用的进程间通信方式。Android系统中主要使用Binder机制,是一种C/S机制。那么Binder机制是如何运行的呢?首先看下图一个典型的C/S通信问题,如Client进程要发送数据到Server进程,因为处于不同的进程,进程与进程之间是没有共享内存的,那么Client进程需要先拷贝数据到内核进程,再通过内核进程拷贝数据到server进程,这样就产生了两次拷贝。如下图。

​​​​

18582563-82019a2f49e012d1.png

而Android的binder机制是怎样的呢?在此之前,要先了解一个知识。在操作系统中,32位的CPU可以支持4G的物理内存空间。物理内存是CPU地址线直接寻址的内存空间大小。若内存条(实际的物理内存)为1G,则CPU直接能直接寻址的地址只能在0~0x7fffffff区间,那么如果进程产生了一个不在0~0x7fffffff区间的空间地址怎么办呢?这就是涉及计算机的分页机制,有页和页帧的概念,页和页帧的地址空间是一样大的。这里记住,虚拟内存空间分页产生页,物理内存空间分页产生帧。这样问题来了,4G虚拟内存地址空间产生的页的数量肯定比物理内存空间分页(帧)产生的数量多,既多对一的关系。为了虚拟内存的页都有对应的物理内存页,那么就涉及到物理内存页帧重复利用对应虚拟内存页的问题。怎么重复利用的呢?就是把比较少用的,让这个物理内存页失效(你没什么用了),把这个页帧的数据写到磁盘,然后重新映射这个物理地址到虚拟地址。而虚拟内存页到物理内存页的映射关系,得要有记录的吧,要不然都不知道谁映射到谁,而这个记录就是页表要做的事。

理解了虚拟内存地址和物理内存的关系之后,现在在Android系统上,要进行两个进程之间的数据通信,如果像上面那样的数据拷贝,则需要拷贝两次,一次从Client进程的用户空间拷贝到内核空间,然后再从内核空间拷贝到Server的用户空间,显然性能上并没那么好。而Binder机制是怎么操作的呢?如下图,Client传输数据从用户空间到binder驱动,binder驱动拷贝数据到Server通过mmap映射的物理内存空间M,binder驱动把Server映射的物理空间对应的虚拟地址空间告知Server,Server用户空间通过binder驱动传递过来的虚拟地址空间来访问Client的数据。整个过程只是在binder驱动拷贝数据到Server通过mmap映射的物理空间发生了一次拷贝。


18582563-1e3ad000e990bef2.png

Binder机制中,涉及的几个角色有,Client、Server、ServiceManager、以及binder驱动。如下图:


18582563-d928a2cce407079d.png

ServiceManager即当爹也当妈。ServiceManager既是Android系统的进程通信binder机制守护进程,也是充当id为0的Server服务。在binder机制的服务方中,id为0为ServerManager, 其他服务统一由binder驱动服务分配,id>0。下图为ServiceManager的启动过程。打开dev/binder驱动文件、映射128k物理地址、通知binder驱动它是守护进程,进入循环等待请求到来(阻塞,避免一直循环进行,有新请求唤醒)。这里的守护进程主要在循环等待,且打开文件的方式是阻塞模式,不会直接返回。那么ServiceManager有什么作用呢?既然是守护进程,当然是提供服务。什么服务?即提供连接通信的服务能力。

Client和Service在数据通信时,都开启了循环等待数据到来。Client通过new BpServiceManaer(new BpBinder())得到远程binder代理,从而通过该远程binder代理发起远程服务,远程服务Service所在的消息循环得到Client发出的消息命令,解析之后,返回相关的数据响应。ServiceManager、Server、Client的执行流程如下三个图。其中ServiceManager的流程标记1和Server的流程标记1具有关联性,实际上也是一种binder通信,当Server的流程标记1执行XXXService.instantial的时候,向ServiceManager注册服务,因此ServiceManager的流程标记1的binder_loop消息循环就会收到相关的消息命令,从而做出加入服务列表的操作等。Service所涉及的类图和ServiceManager涉及的类图类似,如下图为ServiceManager涉及的类图:其中主要的就是BpServiceManager, 为远程binder代理对象,里面以IBinder为属性(ServiceManager为BpBinder, 如MediaService为BnBinder),该IBinder属性是处理Binder请求的关键对象,通过transact进入到IPCThreadState进行简单处理之后扔回IBinder的具体派生类的onTransact函数处理,IPCThreadState通过ProcessState获取上下文(和binder设备有关)。


18582563-4eca459ed836ec98.png
18582563-ff789654fca7b316.png
18582563-6ff2a553afd1f962.png
18582563-299ad24a28ca9ba0.png

上述的分析是基于C/C++层的,在应用开发中,我们经常遇到进程间通信相关的,接下来有必要分析下Java层开始的进程间Binder通信是怎样的。Android中,基于底层Binder机制的AIDL通信框架如下图:


18582563-4a55c4a19b659dc0.png

aidl文件对应生成的java文件就会包含一个Stub和Proxy内部静态类。其中Proxy就是本地响应Client请求的代理,而Stub就是Client请求代理到达远程服务的远程服务代理,具体的请求处理在Stub的派生类进行。

因此,通过上述的分析,我们可以把binder机制的流程思想和服务器请求进行类比,Client就相当于客户端发起请求者、Server就是响应请求的服务器、ServiceManager就相当于DNS解析,当Client发起请求的时候,它只说,我要和XXXService(如media_service)通信,于是就需要从ServiceManager查看是否存在改服务在已注册的服务列表中。服务找到了,Client正式发起消息了,经过各种路由(对应binder机制的driver),到达服务器,服务器解析相关的请求,返回相关的数据。

之所以说Binder机制是基石,是因为在Android系统中,很多的系统执行都涉及Binder通信,可见Binder机制的重要性。如果没有非常清楚Binder机制是怎样的,那么后面所有的知识将很难进行,也将会理解的很生涩。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值