Android Binder设计与实现设计篇Word下载.docx
- 文档编号:18209717
- 上传时间:2022-12-14
- 格式:DOCX
- 页数:26
- 大小:257.31KB
Android Binder设计与实现设计篇Word下载.docx
《Android Binder设计与实现设计篇Word下载.docx》由会员分享,可在线阅读,更多相关《Android Binder设计与实现设计篇Word下载.docx(26页珍藏版)》请在冰豆网上搜索。
1
Socket/管道/消息队列
2
还有一点是出于安全性考虑。
Android作为一个开放式,拥有众多开发者的的平台,应用程序的来源广泛,确保智能终端的安全是非常重要的。
终端用户不希望从网上下载的程序在不知情的情况下偷窥隐私数据,连接无线网络,长期操作底层设备导致电池很快耗尽等等。
传统IPC没有任何安全措施,完全依赖上层协议来确保。
首先传统IPC的接收方无法获得对方进程可靠的UID/PID(用户ID/进程ID),从而无法鉴别对方身份。
Android为每个安装好的应用程序分配了自己的UID,故进程的UID是鉴别进程身份的重要标志。
使用传统IPC只能由用户在数据包里填入UID/PID,但这样不可靠,容易被恶意程序利用。
可靠的身份标记只有由IPC机制本身在内核中添加。
其次传统IPC访问接入点是开放的,无法建立私有通道。
比如命名管道的名称,systemV的键值,socket的ip地址或文件名都是开放的,只要知道这些接入点的程序都可以和对端建立连接,不管怎样都无法阻止恶意程序通过猜测接收方地址获得连接。
基于以上原因,Android需要建立一套新的IPC机制来满足系统对通信方式,传输性能和安全性的要求,这就是Binder。
Binder基于Client-Server通信模式,传输过程只需一次拷贝,为发送发添加UID/PID身份,既支持实名Binder也支持匿名Binder,安全性高。
2面向对象的
BinderIPC
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也可以看作是ServerBinder的‘代理’,在本地代表远端Server为Client提供服务。
本文中会使用‘引用’或‘句柄’这个两广泛使用的术语。
面向对象思想的引入将进程间通信转化为通过对某个Binder对象的引用调用该对象的方法,而其独特之处在于Binder对象是一个可以跨进程引用的对象,它的实体位于一个进程中,而它的引用却遍布于系统的各个进程之中。
最诱人的是,这个引用和java里引用一样既可以是强类型,也可以是弱类型,而且可以从一个进程传给其它进程,让大家都能访问同一Server,就象将一个对象或引用赋值给另一个引用一样。
Binder模糊了进程边界,淡化了进程间通信过程,整个系统仿佛运行于同一个面向对象的程序之中。
形形色色的Binder对象以及星罗棋布的引用仿佛粘接各个应用程序的胶水,这也是Binder在英文里的原意。
当然面向对象只是针对应用程序而言,对于Binder驱动和内核其它模块一样使用C语言实现,没有类和对象的概念。
Binder驱动为面向对象的进程间通信提供底层支持。
3Binder
通信模型
Binder框架定义了四个角色:
Server,Client,ServiceManager(以后简称SMgr)以及Binder驱动。
其中Server,Client,SMgr运行于用户空间,驱动运行于内核空间。
这四个角色的关系和互联网类似:
Server是服务器,Client是客户终端,SMgr是域名服务器(DNS),驱动是路由器。
3.1Binder
和路由器一样,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.2ServiceManager
与实名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.3Client
获得实名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都需要注册给SMgr广而告之的。
Server端可以通过已经建立的Binder连接将创建的Binder实体传给Client,当然这条已经建立的Binder连接必须是通过实名Binder实现。
由于这个Binder没有向SMgr注册名字,所以是个匿名Binder。
Client将会收到这个匿名Binder的引用,通过这个引用向位于Server中的实体发送请求。
匿名Binder为通信双方建立一条私密通道,只要Server没有把匿名Binder发给别的进程,别的进程就无法通过穷举或猜测等任何方式获得该Binder的引用,向该Binder发送请求。
下图展示了参与Binder通信的所有角色,将在以后章节中一一提到。
图1Binder通信示例
4Binder
协议
Binder协议基本格式是(命令+数据),使用ioctl(fd,cmd,arg)函数实现交互。
命令由参数cmd承载,数据由参数arg承载,随cmd不同而不同。
下表列举了所有命令及其所对应的数据:
表2Binder通信命令字
命令
含义
arg
BINDER_WRITE_READ
该命令向Binder写入或读取数据。
参数分为两段:
写部分和读部分。
如果write_size不为0就先将write_buffer里的数据写入Binder;
如果read_size不为0再从Binder中读取数据存入read_buffer中。
write_consumed和read_consumed表示操作完成时Binder驱动实际写入或读出的数据个数。
structbinder_write_read{
signedlongwrite_size;
signedlongwrite_consumed;
unsignedlongwrite_buffer;
signedlongread_size;
signedlongread_consumed;
unsignedlongread_buffer;
};
BINDER_SET_MAX_THREADS
该命令告知Binder驱动接收方(通常是Server端)线程池中最大的线程数。
由于Client是并发向Server端发送请求的,Server端必须开辟线程池为这些并发请求提供服务。
告知驱动线程池的最大值是为了让驱动发现线程数达到该值时不要再命令接收端启动新的线程。
intmax_threads;
BINDER_SET_CONTEXT_MGR
将当前进程注册为SMgr。
系统中同时只能存在一个SMgr。
只要当前的SMgr没有调用close()关闭Binder驱动就不能有别的进程可以成为SMgr。
---
BINDER_THREAD_EXIT
通知Binder驱动当前线程退出了。
Binder会为所有参与Binder通信的线程(包括Server线程池中的线程和Client发出请求的线程)建立相应的数据结构。
这些线程在退出时必须通知驱动释放相应的数据结构。
BINDER_VERSION
获得Binder驱动的版本号。
这其中最常用的命令是BINDER_WRITE_READ。
该命令的参数包括两部分数据:
一部分是向Binder写入的数据,一部分是要从Binder读出的数据,驱动程序先处理写部分再处理读部分。
这样安排的好处是应用程序可以很灵活地处理命令的同步或异步。
例如若要发送异步命令可以只填入写部分而将read_size置成0;
若要只从Binder获得数据可以将写部分置空即write_size置成0;
若要发送请求并同步等待返回数据可以将两部分都置上。
4.1BINDER_WRITE_READ
之写操作
Binder写操作的数据时格式同样也是(命令+数据)。
这时候命令和数据都存放在binder_write_read结构write_buffer域指向的内存空间里,多条命令可以连续存放。
数据紧接着存放在命令后面,格式根据命令不同而不同。
下表列举了Binder写操作支持的命令:
表3Binder写操作命令字
cmd
BC_TRANSACTION
BC_REPLY
BC_TRANSACTION用于Client向Server发送请求数据;
BC_REPLY用于Server向Client发送回复(应答)数据。
其后面紧接着一个binder_transaction_data结构体表明要写入的数据。
structbinder_transaction_data
BC_ACQUIRE_RESULT
BC_ATTEMPT_ACQUIRE
暂未实现
BC_FREE_BUFFER
释放一块映射的内存。
Binder接收方通过mmap()映射一块较大的内存空间,Binder驱动基于这片内存采用最佳匹配算法实现接收数据缓存的动态分配和释放,满足并发请求对接收缓存区的需求。
应用程序处理完这片数据后必须尽快使用该命令释放缓存区,否则会因为缓存区耗尽而无法接收新数据。
指向需要释放的缓存区的指针;
该指针位于收到的Binder数据包中
BC_INCREFS
BC_ACQUIRE
BC_RELEASE
BC_DECREFS
这组命令增加或减少Binder的引用计数,用以实现强指针或弱指针的功能。
32位Binder引用号
BC_INCREFS_DONE
BC_ACQUIRE_DONE
第一次增加Binder实体引用计数时,驱动向Binder实体所在的进程发送BR_INCREFS,BR_ACQUIRE消息;
Binder实体所在的进程处理完毕回馈BC_INCREFS_DONE,BC_ACQUIRE_DONE
void*ptr:
Binder实体在用户空间中的指针
void*cookie:
与该实体相关的附加数据
BC_REGISTER_LOOPER
BC_ENTER_LOOPER
BC_EXIT_LOOPER
这组命令同BINDER_SET_MAX_THREADS一道实现Binder驱动对接收方线程池管理。
BC_REGISTER_LOOPER通知驱动线程池中一个线程已经创建了;
BC_ENTER_LOOPER通知驱动该线程已经进入主循环,可以接收数据;
BC_EXIT_LOOPER通知驱动该线程退出主循环,不再接收数据。
BC_REQUEST_DEATH_NOTIFICATION
获得Binder引用的进程通过该命令要求驱动在Binder实体销毁得到通知。
虽说强指针可以确保只要有引用就不会销毁实体,但这毕竟是个跨进程的引用,谁也无法保证实体由于所在的Server关闭Binder驱动或异常退出而消失,引用者能做的是要求Server在此刻给出通知。
uint32*ptr;
需要得到死亡通知的Binder引用
void**cookie:
与死亡通知相关的信息,驱动会在发出死亡通知时返回给发出请求的进程。
BC_DEAD_BINDER_DONE
收到实体死亡通知书的进程在删除引用后用本命令告知驱动。
void**cookie
在这些命令中,最常用的是BC_TRANSACTION/BC_REPLY命令对,Binder请求和应答数据就是通过这对命令发送给接收方。
这对命令所承载的数据包由结构体structbinder_transaction_data定义。
Binder交互有同步和异步之分,利用binder_transaction_data中flag域区分。
如果flag域的TF_ONE_WAY位为1则为异步交互,即Client端发送完请求交互即结束,Server端不再返回BC_REPLY数据包;
否则Server会返回BC_REPLY数据包,Client端必须等待接收完该数据包方才完成一次交互。
4.2BINDER_WRITE_READ
:
从Binder读出数据
从Binder里读出的数据格式和向Binder中写入的数据格式一样,采用(消息ID+数据)形式,并且多条消息可以连续存放。
下表列举了从Binder读出的命令字及其相应的参数:
表4Binder读操作消息ID
消息
参数
BR_ERROR
发生内部错误(如内存分配失败)
BR_OK
BR_NOOP
操作完成
BR_SPAWN_LOOPER
该消息用于接收方线程池管理。
当驱动发现接收方所有线程都处于忙碌状态且线程池里的线程总数没有超过BINDER_SET_MAX_THREADS设置的最大线程数时,向接收方发送该命令要求创建更多线程以备接收数据。
BR_TRANSACTION
BR_REPLY
这两条消息分别对应发送方的BC_TRANSACTION和BC_REPLY,表示当前接收的数据是请求还是回复。
binder_transaction_data
BR_ACQUIRE_RESULT
BR_ATTEMPT_ACQUIRE
BR_FINISHED
尚未实现
BR_DEAD_REPLY
交互过程中如果发现对方进程或线程已经死亡则返回该消息
BR_TRANSACTION_COMPLETE
发送方通过BC_TRANSACTION或BC_REPLY发送完一个数据包后,都能收到该消息做为成功发送的反馈。
这和BR_REPLY不一样,是驱动告知发送方已经发送成功,而不是Server端返回请求数据。
所以不管同步还是异步交互接收方都能获得本消息。
BR_INCREFS
BR_ACQUIRE
BR_RELEASE
BR_DECREFS
这一组消息用于管理强/弱指针的引用计数。
只有提供Binder实体的进程才能收到这组消息。
BR_DEAD_BINDER
BR_CLEAR_DEATH_NOTIFICATION_DONE
向获得Binder引用的进程发送Binder实体死亡通知书;
收到死亡通知书的进程接下来会返回BC_DEAD_BINDER_DONE做确认。
void**cookie:
在使用BC_REQUEST_DEATH_NOTIFICATION注册死亡通知时的附加参数。
BR_FAILED_REPLY
如果发送非法引用号则返回该消息
和写数据一样,其中最重要的消息是BR_TRANSACTION或BR_REPLY,表明收到了一个格式为binder_transaction_data的请求数据包(BR_TRANSACTION)或返回数据包(BR_REPLY)。
4.3structbinder_transaction_data
收发数据包结构
该结构是Binder接收/发送数据包的标准格式,每个成员定义如下:
表5Binder收发数据包结构:
成员
union{
size_thandle;
void*ptr;
}target;
对于发送数据包的一方,该成员指明发送目的地。
由于目的是在远端,所以这里填入的是对Binder实体的引用,存放在target.handle中。
如前述,Binder的引用在代码中也叫句柄(handle)。
当数据包到达接收方时,驱动已将该成员修改成Binder实体,即指向Binder对象内存的指针,使用target.ptr来获得。
该指针是接收方在将Binder实体传输给其它进程时提交给驱动的,驱动程序能够自动将发送方填入的引用转换成接收方Binder对象的指针,故接收方可以直接将其当做对象指针来使用(通常是将其reinterpret_cast成相应类)。
void*cookie;
发送方忽略该成员;
接收方收到数据包时,该成员存放的是创建Binder实体时由该接收方自定义的任意数值,做为与
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android Binder设计与实现 设计篇 Binder 设计 实现