今天说说神秘又常用又多变的Binder~
- Binder是什么
- Binder通信过程和原理
- 在Android中的应用
- Binder优势
Binder是什么
先借用神书《Android开发艺术探索》中的一段话:
直观的说,Binder是一个类,实现了IBinder接口。
从IPC(Inter-Process Communication,进程间通信)角度来说,Binder是Android中一种跨进程通信方式。
还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder。
从Android FrameWork角度来说,Binder是ServiceManager连接各种Manager(ActivityManager,WindowManager等等)和响应ManagerService的桥梁。
从Android应用层来说,Binder是客户端和服务端进行通信的媒介。
挺多概念的是吧,其实就说了一件事,Binder
就是用来进程间通信的,是一种IPC
方式。后面所有的解释都是Binder
实际应用涉及到的内容。
不管是获取其他的系统服务,亦或是服务端和客户端的通信,都是源于Binder
的进程间通信能力。
Binder通信过程和原理
首先,还是看一张图,原图也是出自神书中:
首先要明确的是客户端进程是无法直接操作服务端中的类和方法的,因为不同进程直接是不共享资源的。所以客户端这边操作的只是服务端进程的一个代理对象,也就是一个服务端的类引用,也就是Binder
引用。
总体通信流程
就是:
- 客户端通过代理对象向服务器发送请求。
- 代理对象通过
Binder
驱动发送到服务器进程 - 服务器进程处理请求,并通过
Binder
驱动返回处理结果给代理对象 - 代理对象将结果返回给客户端。
再看看在我们应用中常常用到的工作模型
,上图:
这就是在应用层面我们常用的工作模型,通过ServiceManager
去获取各种系统进程服务。这里的通信过程如下(详细流程也可参考文末链接):
- 服务端跨进程的类都要继承
Binder
类,所以也就是服务端对应的Binder
实体。这个类并不是实际真实的远程Binder
对象,而是一个Binder
引用(即服务端的类引用),会在Binder
驱动里还要做一次映射。 - 客户端要调用远程对象函数时,只需要调用
Binder
引用的方法,一般是transact
函数。 - 然后Binder引用会把数据放入到Client的共享内存,
Binder
驱动从Client的共享内存中读取数据,根据这些数据找到对应的远程进程的共享内存。 - 然后把数据拷贝到远程进程的共享内存中,并通知远程进程执行onTransact()函数,这个函数也是属于
Binder
类。 - 远程进程
Binder
对象执行完成后,将得到的写入自己的共享内存中,Binder驱动再将远程进程的共享内存数据拷贝到客户端的共享内存,并唤醒客户端线程。
所以通信过程中比较重要的就是这个服务端的Binder引用
,通过它来找到服务端并与之完成通信。
看到这里可能有的人疑惑了,图中线程池
怎么没用到啊?
- 可以从第一张图中看出,
Binder线程池
位于服务端,它的主要作用就是将每个业务模块的Binder请求统一转发到远程Servie中去执行,从而避免了重复创建Service的过程。也就是服务端只有一个,但是可以处理多个不同客户端的Binder
请求。
在Android中的应用
Binder在Android中的应用除了刚才的ServiceManager
,你还想到了什么呢?
- 系统服务是用过
getSystemService
获取的服务,内部也就是通过ServiceManager
。例如四大组件的启动调度等工作,就是通过Binder机制传递给ActivityManagerService,再反馈给Zygote
。而我们自己平时应用中获取服务也是通过getSystemService(getApplication().WINDOW_SERVICE)
代码获取。 AIDL(Android Interface definition language)
。例如我们定义一个IServer.aidl文件,aidl工具会自动生成一个IServer.java的java接口类(包含Stub,Proxy等内部类)。- 前台进程通过
bindService
绑定后台服务进程时,onServiceConnected(ComponentName name, IBinder service)传回IBinder对象,并且可以通过IServer.Stub.asInterface(service)获取IServer的内部类Proxy的对象,其实现了IServer接口。
Binder优势
在Linux中,进程通信的方式肯定不止Binder这一种,还有以下这些:
管道(Pipe)
信号(Signal)
消息队列(Message)
共享内存(Share Memory)
套接字(Socket)
Binder
而Binder
在这之后主要有以下优点:
性能高,效率高
:传统的IPC(套接字、管道、消息队列)需要拷贝两次内存、Binder只需要拷贝一次内存、共享内存不需要拷贝内存。安全性好
:接收方可以从数据包中获取发送发的进程Id和用户Id,方便验证发送方的身份,其他IPC想要实验只能够主动存入,但是这有可能在发送的过程中被修改。
熟悉Zygote
的朋友可能知道,在fork()进程的时候,也就是向Zygote进程发出创建进程的消息的时候,用到的进程间通信方式就不是Binder了,而换成了Socket,这主要是因为fork不允许存在多线程,Binder
通讯偏偏就是多线程。
所以具体的情况还是要去具体选择合适的IPC方式。
参考
https://www.cnblogs.com/hustcser/p/10228843.html
拜拜
有一起学习的小伙伴可以关注下❤️我的公众号——码上积木,每天剖析一个知识点,我们一起积累知识。