Binder是Android的一种特色的跨进程的通信方式
和AIDL的关系
AIDL是封装了Binder的一种框架,使使用Binder,进行跨进程更加方便。
为什么要学习Binder
例如startActivity,网络硬件各种服务,都使用到了跨进程的通讯,在系统层,Binder无处不在。
Binder的例子
Binder相当于网络通讯中的路由器,只不过Binder是一个虚拟的设备
Binder的由来
Linux内核以具备很多跨进程通讯方案
1.管道,耗费性能
2.共享内存,使多个进程可以访问同一块内存空间,管理混乱
3.Socket适合于网络通讯,但对于进程间通讯,显然不适合
…
那为什么还要用Binder?
- 考虑安全性,本身就支持对通讯的双方进行身份的校验
- 性能,效率比较高
Binder四个重要角色
- Server
- Client
- ServiceManager
- Binder驱动 (默认最大数是16,超过会阻塞,等待)
Binder四个重要角色
- IBinder:接口,代表了跨进程通讯的能力
- IInterface:代表Server端具备什么样的功能,什么样的能力,能提供哪些方法,对应的就是AIDL定义的接口
- Binder:继承自IBinder,是java实现类,在跨进程的时候,BInder驱动会自动进行Binder和BInderProxy的转换。
- Stub:AIDL会自动生成一个Stub类,继承自Binder,实现IInterface接口,是一个抽象类,具体的IInterface相关实现,需要开发者自己实现
Binder的优点
Binder驱动
Binder原理图
Binder通信机制完整流程
Binder流程
- 打开Binder设备
- buffer创建 (用于进程间数据传递)
- 开辟内存映射 (128K)
- ServiceManager启动
- 打包Parcel中,数据写入Binder设备,copy_from_user
- 服务注册,添加到链表svclist中
- 定义主线程中的线程池
- 循环从mIn和mOut中取出读写请求,发到Binder设备中
来看下源码
frameworks/native/cmds/servicemanager.c
打开binder设备文件,返回文件描述符
然后在/frameworks/native/cmds/servicemanager/binder.c
打开binder设备驱动的时候,通过mmap
开启内存的映射128K
那什么时候调用了mmap
呢 ? (开辟内存映射)
在device google cuttlefish_kernel 4.4-x86_64/System.map
中
Android9.0在25306行,可以找到binder_mmap
即,System.map启动的时候,开启了binder的mmap,开辟了内存映射然后来看ServiceManager的启动
在/system/core/rootdir/init.rc
然后来看打包Parcel中
在frameworks native libs binder IServiceManager.cpp
会将service的信息打包到Parcel中,然后通过remote->transact
往下一步进行传输然后数据怎么写入Binder设备?
来看/frameworks /ative/libs/binder/IPCThreadState.cpp
writeTransactionData:将Parcel中的信息封装成结构体写入
waitForResponse:将设备写入到Binder当中,并且等待返回的结果服务是如何注册的?
在frameworks/native/cmds/servicemanager.c
svc_can_register:做了权限的检查,是否有注册service的权限
find_svc:在svclist这个链表里去查找,看是否已被注册过
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
:没有注册过,那么就分配一个服务管理的结构svcinfo,并将其添加到svclist中
si->next = svclist;
:将代表该服务的结构插入到链表中来
binder_acquire(bs, handle);
:增加Binder的应用技术
binder_link_to_death(bs, handle, &si->death);
:如果该服务退出之后,那么就要通知ServiceManager
定义主线程中的线程池
frameworks/native/libs/binder/IPCThreadState.cpp
定义主线程中的线程池,来进行不停地写不停地读的过程
循环从mIn和mOut中取出读写请求,发到Binder设备中
pthread_setspecific:将对象设为当前线程的私有
mIn.setDataCapacity(256);mOut.setDataCapacity(256);: 输入输出各分配256字节,不断从mIn,mOut中来进行一些读写,然后发送到binder中来