学安卓Binder应该是必须了解的东西。花了几天时间阅读Google前3页的binder文章。
其中主要阅读了Gityuan的Binder系列文章http://gityuan.com/2015/10/31/binder-prepare/
很给力,一看还是我大小米的系统工程师,膜拜膜拜。
Binder是什么?
Binder是Android的一个类,继承IBinder接口
Binder是一种进程间通信方法,因为种种优点被Android大量使用
Binder可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder
为什么Android要使用Binder,尤其是在Linux拥有好几个传统进程间通信方法的情况下还要开发出Binder?
这个问题就是等于问Linux传统进程间通信方法有什么缺点,然后Binder怎么把缺点补齐的。
先列下传统方法。有管道、消息队列、共享内存、socket、信号量
然后分几方面讲
1.性能角度
Binder数据拷贝只需要拷贝一次(Service端拷贝到内核,Client端是则是获取内核中Binder引用,无需拷贝直接使用)。
而管道、消息队列、socket都需要2次。共享内存无需拷贝,但是操作复杂,需要考虑并发问题。
2.稳定性和架构设计角度
Binder基于Client-Service架构设计,降低耦合,相对独立,稳定性好,方便android程序之间相互通信。
共享内存这种就没有C/S区分。
3.安全性角度
传统的进程间通信不需要报出自己的身份,或者自己的身份自己填写。这样的方式放在android上肯定是不合适的。
意味着随意一个进程都可以要随意访问或者伪造身份访问联系人,短信,通话记录。
所以android开发的Binder机制,设计成Binder强制为进程填写UID/PID,并且在Binder通信时会根据UID/PID进行有效性检测。这样就约束了每个进程对权限的使用。
Servicemanager是干什么的
ServiceManager也是一个Service端,只不过它的作用是Service端的管家。
很容易理解,如果只有Service和Client,如果client要找到某个Service,是很费力的。所以需要一个服务管理者的角色存在。
Android系统中需要公开的服务,在完成创建后,都将把自己注册到ServiceManager里面。相当于路由表。
后面的Client想要访问某个服务功能,就需要先到ServiceManager中查找和获取。
那么问题来了,Server向ServerManager注册时,也算是进程间通信,当时没有“这个路由表”,怎么实现的。
答案是ServiceManager作为用户控件的一个守护进程,启动时会告诉Binder驱动它是服务管理者。
Binder驱动会新建ServiceManager对应的Binder对象,并将Binder实体设为全局变量。
其他文章有讲,ServiceManager被赋予一个特殊的句柄——0句柄。其他Service进程通过0句柄与ServiceManager通信。
Server向ServiceManager注册的细节
1.首先,XXXServer(XXX代表某个)在自己的进程中向Binder驱动申请创建一个XXXService的Binder的实体,
2.Binder驱动为这个XXXService创建位于内核中的Binder实体节点以及Binder的引用,注意,是将名字和新建的引用打包传递给SM(实体没有传给SM),通知SM注册一个名叫XXX的Service。
3.SM收到数据包后,从中取出XXXService名字和引用,填入一张查找表中。
Client获取远程服务细节
Client发送请求(服务名)到Binder驱动, Binder驱动转发给ServiceManager进程
ServiceManager也是通过Binder驱动把 Server对应的Binder实体的Binder引用信息(XXXBpBinder)反馈给Client
Client收到之后,创建出一个Server对应的远程服务,这个远程服务就是Server的代理.
所以通信流向大概是Client —— Server远程服务的接口 —— Binder驱动 —— Server
关于Binder实体和Binder引用
Binder实体 : 是各个Server以及ServiceManager在内核(Binder驱动)中的存在形式
Binder引用 : 是Client在内核(Binder驱动)中保存的一个Binder实体的引用
一个Binder实体 可以对应 多个Binder引用
关于IBinder接口和Binder类
Binder 类实现 IBinder 接口。IBinder 有个关键方法 transact(),是客服端向服务端发出调用(方法)请求。当然这个抽象的,具体实现还是在Binder里面。
Binder 有个关键方法 onTransact(),是服务端接收客服端的请求,作出响应并返回。
这一系列操作是同步的,所以代码中 transact() 方法里执行 onTransact(),会等待 onTransact() 执行完成,返回后者的执行结果。
onTransact 接收目标方法ID、方法参数、返回结果,最终会分发到真正执行业务的目标方法中。
public final boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}