原文链接: ---Android IPC之Binder机制分析---
更多精彩请点击:
AIDL实现IPC详解------AIDL实现IPC详解
一、 Android IPC方式选择
1.1 IPC释意
IPC:Inter-Process Communication,进程间的通信或跨进程通信。因为不同的进程是不能共享内存块的,所以进程之间的通信需要使用特别的方式。进程中的线程是可以共享内存的,就是多个线程可以操作或者可以同时操作同一个文件,当多个线程同时访问同一个文件时需要做线程同步,防止读到脏数据。Android每一个应用都会有一个自己的Dalvik/ART虚拟机 实例,每一个应用都有一个或者多个进程,每一个进程都有一个或者多个线程!
Android进程之间的通信有六种方式,每种方式都有自己的优缺点,其中AIDL和Messenger都是基于Binder的。
1.2 IPC方式对比
这里写图片描述根据自己项目的实际情况选一种合适的IPC方式,处理好多进程和多线程同步就好!
其中,AIDL基于Binder,Messenger基于AIDL,所以Android中常用的ICP方式都是基于Binder。使用AIDL时需要写对应的.aidl文件,在编译代码的时候Android Studio会根据.aidl生成基于Binder通信的.java文件,.aidl文件只是Google预设了一种操作Binder的java代码生成规则。Messenger是基于AIDL封装的,使用Messenger不需要写.aidl文件。
二、 Binder IPC通信交互和数据传递
Binder通信机制是有C/S模式加代理的方式实现的。是基于C/S模式的那么就会存在客户端和服务端,代理模式就会存在真实对象和代理对象!我前面有文章说明:Android IPC之代理模式
2.1 Binder框架定义了四个角色:Server,Client,ServiceManager(以后简称SMgr)以及Binder驱动交互过程:
这里写图片描述四步交互过程描述: 参考:binder学习指南
-
首先,Server进程要向SM注册;告诉自己是谁,自己有什么能力;在这个场景就是Server告诉SM,它叫zhangsan,它有一个object对象,可以执行add
操作;于是SM建立了一张表:zhangsan这个名字对应进程Server; -
然后Client向SM查询:我需要联系一个名字叫做zhangsan的进程里面的object对象;这时候关键来了:进程之间通信的数据都会经过运行在内核空间里面的驱动,驱动在数据流过的时候做了一点手脚,它并不会给Client进程返回一个真正的object对象,而是返回一个看起来跟object一模一样的代理对象objectProxy,这个objectProxy也有一个add方法,但是这个add方法没有Server进程里面object对象的add方法那个能力;objectProxy的add只是一个傀儡,它唯一做的事情就是把参数包装然后交给驱动。(这里我们简化了SM的流程,见下文)
-
但是Client进程并不知道驱动返回给它的对象动过手脚,毕竟伪装的太像了,如假包换。Client开开心心地拿着objectProxy对象然后调用add方法;我们说过,这个add什么也不做,直接把参数做一些包装然后直接转发给Binder驱动。
-
驱动收到这个消息,发现是这个objectProxy;一查表就明白了:我之前用objectProxy替换了object发送给Client了,它真正应该要访问的是object对象的add方法;于是Binder驱动通知Server进程,调用你的object对象的add方法,然后把结果发给我,Sever进程收到这个消息,照做之后将结果返回驱动,驱动然后把结果返回给Client进程;于是整个过程就完成了。
由于驱动返回的objectProxy与Server进程里面原始的object是如此相似,给人感觉好像是直接把Server进程里面的对象object传递到了Client进程;因此,我们可以说Binder对象是可以进行跨进程传递的对象
但事实上我们知道,Binder跨进程传输并不是真的把一个对象传输到了另外一个进程;传输过程好像是Binder跨进程穿越的时候,它在一个进程留下了一个真身,在另外一个进程幻化出一个影子(这个影子可以很多个);Client进程的操作其实是对于影子的操作,影子利用Binder驱动最终让真身完成操作。所以我们在写AIDL实现IPC的时候并没感觉是在跨进程,由于影子的存在,给我们的感觉好像是在同一进程内直接通信!
理解这一点非常重要;务必仔细体会。另外,Android系统实现这种机制使用的是代理模式,
对于Binder的访问,如果是在同一个进程(不需要跨进程),那么直接返回原始的Binder实体;如果在不同进程,那么就给他一个代理对象(影子);我们在系统源码以及AIDL的生成代码里面可以看到很多这种实现。
Server服务端可能会同时处理多个Client客户端的请求,服务端为了高效率处理服务端的请求,所以在Server服务端会开一个线程池来处理客户端的并发请求。
一句话总结就是:Client进程只不过是持有了Server端的代理;代理对象协助驱动完成了跨进程通信。
2.2 Server端和Client端数据交换过程
这里写图片描述2.1中描述客户端和服务端互相是怎么认识和找到的,描述了大概的交互流程。下面介绍数据交换流程!
Binder IPC通信就是指客户端和服务端互相交互数据,客户端通过SM找到和认识服务端,二者建立联系,然后客户端调用Binder代理对象的方法,并传入参数,并把数据发给Binder驱动,驱动再把数据发送给服务端,这时候服务端知道了客户端调用了自己的方法,服务端执行方法,执行完成后通过Binder把数据发给Binder驱动,Binder驱动再把数据交给客户端。
有了影子和真身的说法,那么AIDL文件其实就是指定了真身和影子长什么样子,具备什么功能。影子在客户端,真身在服务端。客户端操作AIDL制定影子和真身的功能,通过Binder和Binder驱动把操作映射到真身上,让真身完成真正的操作,真身完成操作后,通过Binder和Binder驱动把数据返回给客户端。
三、 Binder到底是什么?
写AIDL文件生成的java代码中可以看出来,Binder是一个java类,实现了IBinder接口。服务端的Binder对象就是Binder new出来的实例,真身Binder有血有肉有功能,但是客户端的影子Binder只是实现了IBinder接口,而且不管是服务端真身Binder还是客户端影子Binder,都实现了.aidl文件中的接口,这就可以实现影子Binder执行真身Binder的功能,真身Binder才是真正执行者,这么一描述大家是否可以知道了Binder是什么了,英文翻译Binder就是 粘合剂,
Binder存在于客户端、服务端、Binder驱动和SM四个地方,在每个地方都有自己不同的职能。当然,只有客户端的Binder才是真正的Binder,客户端的是代理,其他的地方是引用。
-
服务端 Binder
服务端的Binder是一个真实的Binder对象,具备AIDL接口文件中需要的所有功能,同时用与Binder驱动交互的功能,是Binder机制中一个比较核心的位置! -
客户端 Binder
客户端Binder只是一个代理,实现了AIDL文件接口但是不具备真实的功能,只是告诉你服务端用的真正功能,但是客户端Binder具备去Binder驱动交互的功能。 -
Binder驱动 中的Binder
Binder驱动真管理Binder的地方,通过Binder的引用来管理Binder,记录Binder引用->实体之间多对一的关系;为引用找到对应的实体;在某个进程中为实体创建或查找到对应的引用;记录Binder的归属地(位于哪个进程中);通过管理Binder的强/弱引用创建/销毁Binder实体等等。驱动中的Binder是为了管理生死存亡。 -
ServiceManager 中的Binder
ServiceManager跟DNS类似,客户端的binder跟服务端的binder是否认识由ServiceManager断定,作用是将字符形式的Binder名字转化成Client中对该Binder的引用,使得Client能够通过Binder名字获得对Server中Binder实体的引用。注册了名字的Binder叫实名Binder。ServiceManager中会有一张表来存放写关系。ServiceManager中的Binder是为了确定关系。
四、Client端和Server端线程模型
Server服务端可能会同时处理多个Client客户端的请求,服务端为了高效率处理服务端的请求,所以在Server服务端会开一个线程池来处理客户端的并发请求。
client 调用 server的方法a,client本身是会挂起的, 会一直等待server的方法a的执行结果。同时这个方法a 是运行在binder线程池中,所以server的方法 可以执行耗时操作。只不过 client调用的server方法时,注意不要在ui线程里调用,不然会anr的。同时如果你的业务是 一个server 多种client ,那你的server端 方法 要支持同步,不然会数据错乱的!
在上面的数据交互图也可以看到client在调用Server端方法时会挂起,在Server执行完成返回结果时会唤醒client的线程。
参考文章:
网友评论