没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
Android Binder 设计与实现 ——设计篇
Android Binder
设计与实现
——设计篇
关键词
Binder Android IPC Linux 内核 驱动
摘要
Binder 是 Android 系统进程间通信(IPC)方式之一。Linux 已经拥有管道,system V IPC,socket 等
IPC 手段,却还要倚赖 Binder 来实现进程间通信,说明 Binder 具有无可比拟的优势。深入了解 Binder 并
将之与传统 IPC 做对比有助于我们深入领会进程间通信的实现和性能优化。本文将对 Binder 的设计细节做一
个全面的阐述,首先通过介绍 Binder 通信模型和 Binder 通信协议了解 Binder 的设计需求;然后分别阐
述 Binder 在系统不同部分的表述方式和起的作用;最后还会解释 Binder 在数据接收端的设计考虑,包括
线程池管理,内存映射和等待队列管理等。通过本文对 Binder 的详细介绍以及与其它 IPC 通信方式的对比,
读者将对 Binder 的优势和使用 Binder 作为 Android 主要 IPC 方式的原因有深入了解。
1 引言
基于 Client-Server 的通信方式广泛应用于从互联网和数据库访问到嵌入式手持设备内部通信等各个领域。
智能手机平台特别是 Android 系统中,为了向应用开发者提供丰富多样的功能,这种通信方式更是无处不在 ,
诸如媒体播放,视音频频捕获,到各种让手机更智能的传感器(加速度,方位,温度,光亮度等)都由不同的
Server 负责管理,应用程序只需做为 Client 与这些 Server 建立连接便可以使用这些服务,花很少的时间
和精力就能开发出令人眩目的功能。Client-Server 方式的广泛采用对进程间通信(IPC)机制是一个挑战。
目前 linux 支持的 IPC 包括传统的管道,System V IPC,即消息队列/共享内存/信号量,以及 socket
中只有 socket 支持 Client-Server 的通信方式。当然也可以在这些底层机制上架设一套协议来实现
Client-Server 通信,但这样增加了系统的复杂性,在手机这种条件复杂,资源稀缺的环境下可靠性也难
以保证。
另一方面是传输性能。socket 作为一款通用接口,其传输效率低,开销大,主要用在跨网络的进程间通信和
本机上进程间的低速通信。消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的
缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。共享内存虽然无需拷贝,但控制
复杂,难以使用。
表 1 各种 IPC 方式数据拷贝次数
IPC 数据拷贝次数
共享内存 0
Binder 1
Socket/管道/消息队列 2
还有一点是出于安全性考虑。Android 作为一个开放式,拥有众多开发者的的平台,应用程序的来源广泛,确
保智能终端的安全是非常重要的。终端用户不希望从网上下载的程序在不知情的情况下偷窥隐私数据,连接无
线网络,长期操作底层设备导致电池很快耗尽等等。传统 IPC 没有任何安全措施,完全依赖上层协议来确保。
首先传统 IPC 的接收方无法获得对方进程可靠的 UID/PID(用户 ID/进程 ID),从而无法鉴别对方身份 。
Android 为每个安装好的应用程序分配了自己的 UID,故进程的 UID 是鉴别进程身份的重要标志。使用传统
1
Android Binder 设计与实现 ——设计篇
IPC 只能由用户在数据包里填入 UID/PID,但这样不可靠,容易被恶意程序利用。可靠的身份标记只有由 IPC
机制本身在内核中添加。其次传统 IPC 访问接入点是开放的,无法建立私有通道。比如命名管道的名称,
system V 的键值,socket 的 ip 地址或文件名都是开放的,只要知道这些接入点的程序都可以和对端建立
连接,不管怎样都无法阻止恶意程序通过猜测接收方地址获得连接。
基于以上原因,Android 需要建立一套新的 IPC 机制来满足系统对通信方式,传输性能和安全性的要求,这
就是 Binder。Binder 基于 Client-Server 通信模式,传输过程只需一次拷贝,为发送发添加 UID/PID 身
份,既支持实名 Binder 也支持匿名 Binder,安全性高。
2 面向对象的 Binder IPC
Binder 使用 Client-Server 通信方式:一个进程作为 Server 提供诸如视频/音频解码,视频捕获,地址
本查询,网络连接等服务;多个进程作为 Client 向 Server 发起服务请求,获得所需要的服务。要想实现
Client-Server 通信据必须实现以下两点:一是 server 必须有确定的访问接入点或者说地址来接受
Client 的请求,并且 Client 可以通过某种途径获知 Server 的地址;二是制定 Command-Reply 协议来
传输数据。例如在网络通信中 Server 的访问接入点就是 Server 主机的 IP 地址+端口号,传输协议为 TCP 协
议。对 Binder 而言,Binder 可以看成 Server 提供的实现某个特定服务的访问接入点, Client 通过这个
‘ ’地址 向 Server 发送请求来使用该服务;对 Client 而言,Binder 可以看成是通向 Server 的管道入口,
要想和某个 Server 通信首先必须建立这个管道并获得管道入口。
与其它 IPC 不同,Binder 使用了面向对象的思想来描述作为访问接入点的 Binder 及其在 Client 中的入
口:Binder 是一个实体位于 Server 中的对象,该对象提供了一套方法用以实现对服务的请求,就象类的成
员函数。遍布于 client 中的入口可以看成指向这个 binder ‘ ’ ‘ ’对象的 指针 ,一旦获得了这个 指针 就可以调用
该对象的方法访问 server。在 Client 看来,通过 Binder‘ ’指针 调用其提供的方法和通过指针调用其它任何
本地对象的方法并无区别,尽管前者的实体位于远端 Server ‘ ’中,而后者实体位于本地内存中。 指针 是 C++
的术语,而更通常的说法是引用,即 Client 通过 Binder 的引用访问 Server ‘ ’。而软件领域另一个术语 句柄
也可以用来表述 Binder 在 Client 中的存在方式。从通信的角度看,Client 中的 Binder 也可以看作是
Server Binder ‘ ’的 代理 ,在本地代表远端 Server 为 Client ‘ ’ ‘ ’提供服务。本文中会使用 引用 或 句柄 这个
两广泛使用的术语。
面向对象思想的引入将进程间通信转化为通过对某个 Binder 对象的引用调用该对象的方法,而其独特之处
在于 Binder 对象是一个可以跨进程引用的对象,它的实体位于一个进程中,而它的引用却遍布于系统的各
个进程之中。最诱人的是,这个引用和 java 里引用一样既可以是强类型,也可以是弱类型,而且可以从一个
进程传给其它进程,让大家都能访问同一 Server,就象将一个对象或引用赋值给另一个引用一样。Binder
模糊了进程边界,淡化了进程间通信过程,整个系统仿佛运行于同一个面向对象的程序之中。形形色色的
Binder 对象以及星罗棋布的引用仿佛粘接各个应用程序的胶水,这也是 Binder 在英文里的原意。
当然面向对象只是针对应用程序而言,对于 Binder 驱动和内核其它模块一样使用 C 语言实现,没有类和对
象的概念。Binder 驱动为面向对象的进程间通信提供底层支持。
2
Android Binder 设计与实现 ——设计篇
3 Binder 通信模型
Binder 框架定义了四个角色:Server,Client,ServiceManager(以后简称 SMgr)以及 Binder 驱动。
其中 Server,Client,SMgr 运行于用户空间,驱动运行于内核空间。这四个角色的关系和互联网类似:
Server 是服务器,Client 是客户终端,SMgr 是域名服务器(DNS),驱动是路由器。
3.1 Binder 驱动
和路由器一样,Binder ‘ ’驱动虽然默默无闻,却是通信的核心。尽管名叫 驱动 ,实际上和硬件设备没有任何关
系,只是实现方式和设备驱动程序是一样的:它工作于内核态,提供 open(),mmap(),poll(),ioctl()
等标准文件操作,以字符驱动设备中的 misc 设备注册在设备目录/dev 下,用户通过/dev/binder 访问它。
驱动负责进程之间 Binder 通信的建立,Binder 在进程之间的传递,Binder 引用计数管理,数据包在进程
之间的传递和交互等一系列底层支持。驱动和应用程序之间定义了一套接口协议,主要功能由 ioctl()接口实
现,不提供 read(),write()接口,因为 ioctl()灵活方便,且能够一次调用实现先写后读以满足同步交
互 , 而 不 必 分 别 调 用 write() 和 read() 。 Binder 驱 动 的 代 码 位 于 linux 目 录 的
drivers/misc/binder.c 中。
3.2 ServiceManager 与实名 Binder
和 DNS 类似,SMgr 的作用是将字符形式的 Binder 名字转化成 Client 中对该 Binder 的引用,使得
Client 能够 通过 Binder 名 字获得对 Server 中 Binder 实体的引用。 注册 了名 字的 Binder 叫实名
Binder,就象每个网站除了有 IP 地址外还有自己的网址。Server 创建了 Binder 实体,为其取一个字符形
式,可读易记的名字,将这个 Binder 连同名字以数据包的形式通过 Binder 驱动发送给 SMgr,通知 SMgr
注册一个名叫张三的 Binder,它位于某个 Server 中。驱动为这个穿过进程边界的 Binder 创建位于内核中
的实体节点以及 SMgr 对实体的引用,将名字及新建的引用打包传递给 SMgr。SMgr 收数据包后,从中取出名
字和引用填入一张查找表中。
细心的读者可能会发现其中的蹊跷: SMgr 是一个进程,Server 是另一个进程,Server 向 SMgr 注册
Binder 必然会涉及进程间通信。当前实现的是进程间通信却又要用到进程间通信,这就好象蛋可以孵出鸡前
提却是要找只鸡来孵蛋。Binder 的实现比较巧妙:预先创造一只鸡来孵蛋:SMgr 和其它进程同样采用
Binder 通信,SMgr 是 Server 端,有自己的 Binder 对象(实体),其它进程都是 Client,需要通过这个
Binder 的引用来实现 Binder 的注册,查询和获取。SMgr 提供的 Binder 比较特殊,它没有名字也不需要注
册,当一个进程使用 BINDER_SET_CONTEXT_MGR 命令将自己注册成 SMgr 时 Binder 驱动会自动为它创建
Binder 实体(这就是那只预先造好的鸡)。其次这个 Binder 的引用在所有 Client 中都固定为 0 而无须通过
其它手段获得。也就是说,一个 Server 若要向 SMgr 注册自己 Binder 就必需通过 0 这个引用号和 SMgr 的
Binder 通信。类比网络通信,0 号引用就好比域名服务器的地址,你必须预先手工或动态配置好。要注意这里
说的 Client 是相对 SMgr 而言的,一个应用程序可能是个提供服务的 Server,但对 SMgr 来说它仍然是个
Client。
3
Android Binder 设计与实现 ——设计篇
3.3 Client 获得实名 Binder 的引用
Server 向 SMgr 注册了 Binder 实体及其名字后, Client 就可以通过名字获得该 Binder 的引用了 。
Client 也利用保留的 0 号引用向 SMgr 请求访问某个 Binder:我申请获得名字叫张三的 Binder 的引用 。
SMgr 收到这个连接请求,从请求数据包里获得 Binder 的名字,在查找表里找到该名字对应的条目,从条目
中取出 Binder 的引用,将该引用作为回复发送给发起请求的 Client。从面向对象的角度,这个 Binder 对
象现在有了两个引用:一个位于 SMgr 中,一个位于发起请求的 Client 中。如果接下来有更多的 Client 请
求该 Binder,系统中就会有更多的引用指向该 Binder,就象 java 里一个对象存在多个引用一样。而且类似
的这些指向 Binder 的引用是强类型,从而确保只要有引用 Binder 实体就不会被释放掉。通过以上过程可以
看出,SMgr 象个火车票代售点,收集了所有火车的车票,可以通过它购买到乘坐各趟火车的票 -得到某个
Binder 的引用。
3.4 匿名 Binder
并不是所有 Binder 都需要注册给 SMgr 广而告之的。Server 端可以通过已经建立的 Binder 连接将创建的
Binder 实体传给 Client,当然这条已经建立的 Binder 连接必须是通过实名 Binder 实现。由于这个
Binder 没有向 SMgr 注册名字,所以是个匿名 Binder。Client 将会收到这个匿名 Binder 的引用,通过这
个引用向位于 Server 中的实体发送请求。匿名 Binder 为通信双方建立一条私密通道,只要 Server 没有把
匿名 Binder 发给别的进程,别的进程就无法通过穷举或猜测等任何方式获得该 Binder 的引用,向该
Binder 发送请求。
下图展示了参与 Binder 通信的所有角色,将在以后章节中一一提到。
图 1 Binder 通信示例
4
剩余17页未读,继续阅读
Morpheus_Lee
- 粉丝: 2
- 资源: 8
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
- 1
- 2
前往页