文章目录
什么是Binder
binder是Android中特有的一种跨进程的实现方式,模糊了进程边界,淡化了进程通讯的过程,整个系统仿佛运行在OOP
的程序中,Binder
仿佛是粘贴各种应用程序的 “胶水”,英文中binder的意思就是"胶水"。Binder无处不在,就好比在OOP
中,调用的时候使用binder
就可以拿到其他的一些进程服务。如媒体播放,音视频捕获,手机传感器,加速度,方位,温度,亮度,甚至startActivity/Service等等,都是由不同的服务端 Server
提供一些服务,供应用程序调用,而应用程序作为客户端与提供服务的Server
建立链接,便可以方便的使用这些服务。
Binder与AIDL关系
平时项目中,如果纯粹使用Binder调动系统服务,代码量会非常大,非常复杂。而AIDL
是一种架构,为我们使用Binder的时候提供更加轻便简洁的语法就可以调用Binder,实现跨进程的通信。
AIDL
是专门为Binder设计的一种框架, 如果单纯用Binder来调用系统提供的服务,代码量会非常大、非常复杂,而AIDL是一中框架,提供给开发者更加轻便的解决跨进程方案,AIDL只是封装了。如startActivity
封装了AIDL,一行代码实现了跨进程。
Binder更贴切的比喻
如上图:
- Binder :系统提供了很多服务应用程序调用,而Binder作为了调用这些服务的
接入点
- Client :应用程序作为
client
,调用系统提供的服务,可以通过binder
,在client而言,binder可以看做通向服务管道的入口
域名发布的时候,就会告诉DNS(域名解析服务器)真实ip地址。
Binder由来
linux内核提供了很多进程间通信(IPC)的尝试方式。如下
linux提供的通讯方式 | 缺点 | 其他 |
---|---|---|
管道 | 耗费性能(是个半双工过程) | 半双工,如对讲机;全双工,如电话 |
共享内存 | 使多个进程访问同一块内存空间,管理混乱。 | |
socket | 适用于网络通讯,但对于进程间通讯大材小用。 | 适用于网络通信 |
A进程与B进程通信:
- 管道:首先A打开管道,B打开管道,A往管道中写数据,进程B从管道中读数据,不停地写不停地读,直到写完之后,进程A再关闭通道,进程B关闭通道,最后删除管道。 这个过程很 消耗性能。
- 共享内存 : 多个进程可以同时共享同一块内存空间,但是管理很混乱。
- socket :更加适用于网络通信,但对于进程间通讯大材小用。
传统的ipc过程,是 C/S架构,一个server 对应多个 client,如下图:
传统的icp,都是依赖一些协议,无法确认对方可靠的身份。而android会为每个程序分派uid,是鉴别进程身份的重要标识。
上图中,数据会进行至少2次拷贝。
Android应用程序之间,是不可以进行数据共享的,而在底层内核空间就可以。
Android 为什么用Binder进行 ipc,
- binder会对通信的应用双方进行身份校验,安全性高。验证 pid(进程id) uid(用户id)。此外,比如像socket通讯,只需要ip地址就可以进行通信了,甚至都可以伪造。
- 性能高。binder,在binder驱动的内核区域进行数据拷贝,只会拷贝一次,所以传输效率高。
- android系统会为每一个应用程序分配一个唯一的
UID
,进程的UID是鉴别进程身份的重要标识。
性能仅次于共享内存。
binder基于c/s架构(一对多)
为发送方添加了pid,uid(Android9.0源码startActivity有体现)。
跟踪startActivity执行流程,在ActivityTaskManagerService#startActivityAsUser()
发现 pid及uid的设置
int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
boolean validateIncomingUser) {
enforceNotIsolatedCaller("startActivityAsUser");
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
//...
}
为什么学binder
Binder四个重要的角色:Server , Client ,ServiceManager , Binder驱动
,前三者存在于用户空间,而Binder驱动存在于内核空间。而用户空间(client)是不可以进程通信的,内核空间可以。
ServiceManager
服务主要是作为Server
与 Client
之间的桥梁,ServiceManager
在init
进程中启动,类比于DNS服务器。Client可以通过ServiceManager拿到Server中Binder实体的引用。如有服务需要提供给client,那需要将binder的引用注册到ServiceManager中。如client想要使用该服务,需要固定的key(类比于域名www.baidu.com)及binder引用来访问该服务。从ServiceManager
的map链表提取出来,通过key拿到对应的binder引用。
Android中,很多服务都是通过Binder去和AMS进行交互的。如获取音量服务。
AudioManager audioManager = (AudioManager) getSystemService(Service.AUDIO_SERVICE);
系统提供的很多服务Server
,如手机传感器、加速度等等,都需要在ServiveManager
中进行注册,多个系统服务在ServiveManager
中进行注册。此时,ServiveManager
作为服务端,而Server
作为客户端。
// 当一个进程使用 binder.setContext
Binder驱动:负责进程之间Binder 通讯的建立,binder之间无法直接进行交互,都是+通过Binder驱动进行通讯。binder驱动中有一个线程池,因为可能存在并发,线程池由binder驱动管理。一个进程中,binder的线程池中线程数最大是16
,超过这请求就会阻塞等待空闲。
ThreadPool:多个需求方需要用个同一个服务或多个服务的时候就产生很多binder驱动的交互。
AIDL
AIDL: Android Interface Definition Language
Client 与 Server进行通信的时候,必须统一语言,否则无法进行通信。而AIDL专门为这种通信 设计的一种架构,用来binder之间通信。
Binder四个重要对象:
Binder角色 | 作用 | 说明 |
---|---|---|
IBinder | 接口,代表了跨进程通讯的能力,只要实现改接口就可以进行跨进程传输了。 | |
IInterface | 代表了Server进程对象具备哪些功能,提供哪些方法,对应了AIDL定义的接口 | |
Binder | java层的Binder类,代表了Binder的本地对象,BinderProxy是Binder内部类。 | 继承自IBinder |
Stub | AIDL的时候,idea自动生成一个stub的静态内部类,继承了Binder,实现了IInterface接口 | 具备Serve承诺给Client的一种能力 |
Binder : client访问server提供的服务的时候,并不是直接操作binder对象而是操作binder引用,并且是通过本地代理BinderProxy 去 操作binder驱动操作来访问Server,完成之后BinderProxy 就会和内核的内存映射存在共存(共享内存?有待商榷)关系。如下图:
无论Binder
还是BinderProxy
都是继承自IBinder
因而皆具备跨进程通信的能力。
Binder机制通信的流程:
总结:
架构设计:
client 代用 代理BinderProxy接口的方法时候,会将Client传递的数据打包成Parcel
Parcel Parcelable Searilable
区别