一、Binder 类比 TCP/IP
我们知道,同一个程序中的两个函数之间能直接调用的根本原因是出于相同的内存空间中。反之,两个不同的进程,它们是没有办法直接通过内存地址来访问到对方内部的函数或者变量的,那有没有“间接”的方法呢?这就是Binder所要做的工作。
Binder是Android中使用的最广泛的IPC机制。Binder通信的组成元素有如下几个:
Binder驱动
Service Manager
Binder Client
Binder Server
如果你熟悉TCP/IP网络的话,你会发现这两者有很多相似之处,
Binder驱动 -- 路由器Router
Service Manager -- NDS
Binder Client -- 客户端
Binder Server -- 服务端
TCP/IP中一个典型的服务连接过程如下:
1)Client向DNS查询Google.com的IP地址
显然,Client一定得先知道DNS的IP地址,才有可能向它发起查询。DNS的IP设置是在客户端接入网络前就完成了的。当然,如果Client已经知晓了Server的IP,那么完全可以跨越这一步而直接与Server连接。比如Windows操作系统就提供了一个hosts文件,用于查询常用网址域名与其IP地址的对应关系。当用户需要访问某个网址时,系统会先从这个文件中判断是否已经存有这个域名的对应IP。如果有就不需要再大费周折地向DNS查询了,从而加快访问速度。
2)DNS将查询结果返回Client
3)Client发起连接
在这个过程中,我们可以知道:
1)IP地址是他们彼此沟通的凭证;
2)上述过程并没有特别提及Router的作用,因为Router是构建一个通信网络的基础,它可以根据用户填写
的目标IP正确地把数据包发送到位。
3)NDS角色并不是必须的,它的出现是为了帮助人们使复杂难记的IP地址与可读性更强的域名建立关联,并提供查询功能。而客户端能使用DNS的前提是它已经配置了DNS服务器的IP地址。
清楚了网络通信中各个功能模块所扮演的角色,我们将它和Binder做一个对比。
进程1(客户端)与进程2(服务端)进行通信,因为它们之间是跨进程的,
所以必须借助于Binder驱动(路由器)来把请求正确投递到对方所在进程中。
而参与通信的进程们需要持有Binder颁发的唯一标识(IP地址),
这个标志从Service Manager(DNS)获取。
既然Service Manager是DNS,那么它的“IP地址”是什么呢?Binder机制对此做了特别规定:
Service Manager在Binder通信过程中的唯一标志永远都是0
二、Binder通信过程(transact和onTransact)
任何service在被使用之前,均要向SM(Service Manager)注册。
SM的主要工作是初始化 Binder ,打开 /dev/binder 设备;在内存中为 Binder 映射 128K 字节空间。
里面维护一个死循环,在这个死循环中,不停地去读内核中 Binder Driver ,查看是否有可读的内容,即是否有对 service 的操作请求 , 如果有,则调用 svcmgr_handler 回调来处理请求的操作。
客户端和 服务端之间的通信会涉及到 2 次Binder 通信。
1)客户端向 SM 查询 service 是否存在,如果存在获得该 service 的代理 Binder (唯一标识),此为一次 Binder 通信;
2)客户端通过代理 binder 调用 service 的方法,此为第二次 Binder 通信。
比如我要和AMS通信,先得到AMS服务对象的唯一标志:
IBinder b = ServiceManager.getService(“activity”);
返回一个IBinder对象,这个对象就是上面我们所讲的Binder颁发的唯一标识(IP地址)。
IBinder是一个接口,里面主要API是transact(),