Andriod binder
来源:互联网 发布:淘宝外围活动 编辑:程序博客网 时间:2024/06/14 10:25
原文地址http://blog.csdn.net/kickxxx/article/details/9001336
Android binder简介
4 Binder
本章介绍什么是Binder以及Binder的能力。本章是从抽象的角度介绍Binder,并没有涉及到实现细节,在下一章我们会讲解实现细节。
4.1 出身
Binder最初是Be Inc公司开发的OpenBinder,后来Palm Inc收购了Be Inc,这个项目随之转到了Pam公司下。主开发人员是Dianne Hackborn。在OpenBinder的文档中声称:Openbinder是一个系统级的架构,为传统的现代操作系统服务提供一个丰富的高级抽象。
更准确的说,Binder提供了对不同执行环境的粘合能力。OpenBInder实现运行在LInux之上,扩展了现在的IPC机制。OpenBinder文档中还声称:OpenBinder已经能移植到多种平台,包括BeOS, Windows,已经PalmOS Cobalt
Android上的Binder是OpenBinder的定制。在Android's M3 release 原生的kernel包含了OpenBinder的驱动部分,但是Binder的用户空间部分和OpenBinder相比被重写了,以避免OpenBinder的License和Android's的License不相容的情况。在Android's M5 release中,驱动部分也被重写了。尽管核心概念没有改变,但是很多实现细节都改变了。
原始的OpenBinder代码不再开发了。但是从某种程度上说,Android binder可以看作是OpenBinder的一个分支,被Android开发者维护着。
4.2 Binder术语
Binder framework使用它自己的数目来命名它的功能和组件。这一节介绍几个最重要的属于,细节部分会在后面讨论。
Binder 这个术语的使用一直比较模糊,有时指整个Binder框架,有时指一个Binder接口的特定实现。
Binder Object 是一个实现Binder接口的类实例。一个Binder对象可以实现多个Binders
Binder Protocol Binder中间件使用了一个非常低级的协议,用来和Binder kernel driver通信。
IBinder interface 一个Binder interface是Binder可以实现的一组定义良好的方法,属性和事件。通常使用AIDL语言描述。
Binder Token 可以用来惟一标始一个Binder的数字。
4.3 设施
Binder framework 提供了一个简单的进程间通信系统,
从Android应用开发者的角度,最重要的改变就是可以想调用本地对象方法一样,调用远程对象方法。这是一个同步方法调用。相应的,client进程在服务器给出应答之前保持block状态。这样做的好处是避免异步调用导致client要提供一个线程方法。
AIDL的一个特色就是,在高的的层次,应用不需要知道服务试运行在一个server进程还是就在进程内部。Android's的应用概念使得在进程内还是Activity进程运行服务称为可能,这使得应用开发者可以很容易的把自己的服务export给其他的Android应用。
Android系统服务使用Binder的一个特定的通知功能,称为link to death机制。这个机制允许一个进程 获得给定进程的binder结束通知。特别是这个方法允许Android window manager建立一个link to death关联到每一个window的Binder接口,使得window被关闭时通知windwo manager。
每一个Binder是唯一标始的,这意味着它可以用做共享令牌。我们假定Binder没有通过Service Manager发布,BInder标始仅仅被通讯参与者知悉,包括远程进程和本地进程。相应的一个Binder可以被看作一个安全访问令牌。令牌可以被多个进程共享。
另外一个安全特色是:被调用进程可以通过UID和PID来标始调用进程。结合Andoird的安全模型,一个进程可以被标始。另外一个特色,是共享内存机制,通过Binder framework可以共享heap
总的来说,Binder框架的特色使得它良好的支持面向对象的进程间通信。
4.4 概念
本节描述这些设施后面的概念,由于Binder缺乏公开的文档,所以本节大部分都是基于阅读代码后的理解。
4.4.1 Communication Model
Binder framework通信是client/server模型。一个client发起通信并等待Server的响应。Client端使用一个client-side proxy来进行通信。在服务器端,一个线程池来满足client发送来的请求。在图4.2中,client端进程A包括一个proxy对象,实现和Binder kernel driver的通信。Process B是一个服务器端进程,包含多个Binder线程。Binder framework创建新的线程处理所有进入的请求,直到最大允许线程数。代理对象和Binder driver通信,Bind driver负责把消息转发给目标对象。
4.4.2 Transactions
如果一个进程发送数据给其他的进程,那么称为transaction。伴随着每一次传输payload数据被提交。这些数据称为transaction data。
数据结构如图4.3。它包含一个target成员,也就是目标binder node;cookie成员用来内部信息;sender ID成员包含安全相关的信息;data成员包含一组数据,每个数组项包含一个命令和命令参数,Binber会解析这个数组。在Binder framework之上的application可以用这些参数定义它们自己的命令。在Android源代码中我们可以看到,开发者使用target command成员作为远程服务的函数指针,并且把函数的参数序列化到argument成员中。就是实现了一个用户自定义IPC协议。Binder通信依赖于request和reply机制。这就意味着每一个请求比去于一个应答,而请求进程则必须要等待应答,在等待的过程中,请求进程处于阻塞状态。如果开发者想要实现异步的IPC协议,当然是可行的,但是需要开发者注意Binder本身并不支持异步IPC,开发者必须自己实现一个机制来管理请求应答。
因此一个transaction意味着需要两条message,transaction请求和transaction reply。特例是one way通信,一路通信仅限于death notification这种功能。
4.4.3 Parcels和Marshaling
从对象的观点来说,transaction data被称为parcel。换句话说,传输的是数据结构。任何能够传输到远端的对象,都要必须实现parcelable接口。一个实现parcelable接口的对象必须提供序如下方法,在sender端能够序列化对象数据结构,并且在接收端恢复为对象数据结构。数据结构的所有成员都被简化为简单的数据类型如Int, Float,Boolean和String,然后被序列化到一个parcel中。
创建parcel的过程称为marshaling或者对象平面化,相反,从parcel重建object的过程称为unmarshaling或者去平面化
Binder的内存共享基础设施不能被JAVA 应用使用,仅仅C++库可以访问内存中的共享对象表示。
4.4.4 Death Notification
Binder framework支持Binder object的死亡通知,这是一种观察者模式。一个本地BInder 对象如果想知道一个远程Binder对象的终结,那么就把它加到观察着列表中。如果一个发生的事件是远程Binder对象销毁,那么本地对象就会得到通知执行相应的动作。图4.4演示了这一过程
4.5 Context Manager
Context manager是Binder framework中的一个特别Binder node。他对应的Binder号是0。它是一个name system,这样就可以使用一个名称来表示一个Binder接口。这非常重要,因为Clients一般不会预先知道远程Binder的地址。如果一个client预先知道了remote binder的地址,那么Binder的安全令牌机制就不能工作了。但是如果不知道远程通信伙伴的地址,那么就无法发起通信。而context manager解决了这个问题,接口地址固定并且地址是知名的。Context manager实现是Binder framework的一部分。在Android中,context manager被称为Service manager。每一个需要提供服务的Binder都要提交他的名字和Binder令牌给Server manager。而对于client端来说,仅仅需要知道服务的名字,通过名称从service manager查询所要使用服务的Binder address。
4.6 Intents
intent也就是message,开发者在Java API这一层使用它,并通过IPC发送。它是一个要执行动作的抽象表示。抽象意味着动作的执行者并没有定义在intent中。Intent仅仅包含action和data。如4.5给出来一个intent的例子。这个intent由Binder的intent reference monitor分发。service将负责执行拨号动作,所拨拨号码就是保存在Data中
有两种形式的intents,显示的intent是指一个特定的组件。另一方面,一个隐式的intent把决定权交给Android系统。如果系统有多个部件可以处理它,那么Android 系统会选择最合适的组件运行这个intent
4.7 系统集成
Binder在Android平台上使用的相当多,无论什么时候两个进程需要通信, Binder都会介入。比如window manager通过Binder framework和它的clients交换数据。同时使用Binder的death notification功能来获得client应用的结束信息。
s所以Binder连接Android系统的各个框架,因此是非常重要的一个模块。
4.8 安全模型
Binder安全模型非常简单但是很有效。它确保进程间通信通道的安全,保证通信方的身份识别。
伴随Intent的另外一个功能是intent filter。Service和app可以声明,告诉系统哪些intents可以转发给他们执行。
5. Implementation of the Binder Framework
本章会大概分析Binder framework的实现。对于每一层,源代码文件在[10] [9]中列出来,我们讨论他们的目的。此外还有AIDL,因为它被用来生成Java code,所以也可以看作是Binder framework的一部分。
图5.1演示了Binder framework的不同层次。它有三层组成。第一层也就是最高一层是Android应用API。第二层Binder framework中间件层;第三层也就是最底层则是kernel driver
5.1 AIDL
Android interface definition language AIDL是Eclipse SDK的一部分,由Google提供。它的主要目的是简化Android 远程服务的实现。AIDL使用类Java的语法。
在AIDL文件中,开发者用远程服务的方法签名定义接口。AIDL 解析器可以从接口生成Java class,首先为client 生成访问service的代理类,其次为service实现生成一个stub类,service可以扩展这个类做为远程方法的实现。
AIDL语言支持基本数据类型。它生成的代码可以实现:写值到parcels,通过Binder IPC发送 parcels,接收parcel,读取这些值,调用服务的方法,并且发送执行结果。
AIDL文件必须由远程service/app开发者和client app开发者共享。因为AIDL生成器为client和service生成的代码保存在一个文件中,每一个应用使用和实例化的仅仅是这些生成类的一个子集。
5.2 Java API Wrapper
本节讨论Java framework,这个框架位于middleware和kernel driver之上。这些source classes和interfaces属于Java API层:
Interfaces:
• android.app.IActivityManager
• android.os.Parcable
• andorid.os.IBinder
• android.content.ServiceConnection
Classes:
• android.app.ActivityManagerNative
• android.app.ContextImpl
• android.content.Intent
• android.content.ComponentName
• android.os.Parcel
• android.os.Bundle
• android.os.Binder
• android.os.BinderProxy
• com.android.internal.os.BinderInternal
Binder framework的Java layer有两个功能。一个功能是对下层中间件的封装,使得Android应用可以参与到Binder通信当中。第二个功能,它在Binder framework中引入了intents功能。
5.2.1 JNI wrapper
Java API Layer依赖于Binder中间件。为了从Java使用C++编写的中间件,必须使用JNI。在源代码文件frameworks/base/core/jni/android_util_Binder.cpp中,实现了Java和C++函数之间的映射。
5.3 C++中间件
Binder framework在用户空间的中间件实现是C++编写的。framework提供了进程和线程控制方法以及 孵化和管理新线程所需要的数据结构。Marshalling和Unmarshalling功能也是在这里实现的,所以对象信息可以在这里转换为可提交的parcel数据。中间件提供了和Binder kernel驱动的交互以及共享内存的实现。
使用C++的Services或者apps可以直接使用Binder framework,但是必须放弃Java API提供的那些功能。
源代码保存在这些文件中:
• frameworks/base/include/utils/IInterface.h
• frameworks/base/include/utils/Binder.h
• frameworks/base/include/utils/BpBinder.h
• frameworks/base/include/utils/IBinder.h
• frameworks/base/include/utils/Parcel.h
• frameworks/base/include/utils/IPCThreadState.h
• frameworks/base/include/utils/ProcessState.h
• frameworks/base/libs/utils/Binder.cpp
• frameworks/base/libs/utils/BpBinder.cpp
• frameworks/base/libs/utils/IInterface.cpp
• frameworks/base/libs/utils/ProcessSTate.cpp
• frameworks/base/libs/utils/IPCThreadState.cpp
5.4 C kernel driver
Binder kernel driver是Binder framework的核心。在这个点上,信息的可靠性和安全交付必须得到满足。kernel driver是一个使用C语言实现的内核模块。驱动代码包含下面的源文件
• /drivers/staging/android/binder.c
• /drivers/staging/android/binder.h
Binder kernel驱动支持下面的文件操作open, mmap, release, poll和系统调用ioctl。这个操作代表着上层访问Binder驱动的接口。Binder操作open建立到Binder的连接并且把这个连接赋给file pointer,而release操作则关闭连接。mmap操作是用来映射Binder内存的。ioctl是最主要的操作,上层通过这个接口提交和接收信息。ioctl操作使用Binder driver命令码和data buffer作为参数,这些命令包括:
BINDER _WRITE_READ 是最重要的命令,它提交一串transmission data。这个数据传报含多个数据,如图4.3描述的。
BINDER_SET_MAX_THREADS 设置每个进程服务请求的最大线程数。
BINDER_SET_CONTEXT_MGR 设置context manager。context manager仅存在一个,所以这个调用只能成功一次
BINDER_THREAD_EXIT 这个命令被中间件发送,如果一个binder线程退出。
BINDER_VERSION 返回Binder的版本号
Binder驱动实现的功能将在下一节讨论。这些节使用的命令是target commands。甚至如果名字是target command,这些命令可能仅仅应用到本地binder。在OpenBinder文档中他们被称为Binder driver protocol。下面要讨论的代码使用BC_前缀表示Binder command,使用BR前缀表示Binder return
5.4.1 Binder thread support
因为kernel driver没有实现thread启动机制,它必须知道多少threads启动了。下面这些命令必须发送给Binder driver,以便Binder driver能够精确的知道looping threads数目。这些Target commands是BC_REGISTER_LOOPER, BC_ENTER_LOOPER和BC_EXIT_LOOPER。这些命令是用来进行记账的。
5.4.2 Binder Transactions
命令BC_TRANSACTION和BC_REPLY命令传输数据到其他的Binder接口。BC_REPLY命令被中间件用来回答一个接收到的RC_TRANSACTION。图5.3演示了当一个Binder发送一个 transaction然后等待接收这个transaction reply过程中,和Binder driver的交互过程。
Binder驱动负责把reply提交给等待线程,可以把这个reply看作直接响应。
Binder驱动从发送进程的用户空间拷贝transmission数据到kernel空间,Binder再把数据从内核拷贝到目标进程,这是通过copy_from_user和copy_to_user来实现的。data transaction过程如图5.4
5.4.3 Further Mechanism
Binder kernel命令BC_INCREFS,BC_RELEASE和BC_DECREFS实现Binder framework的引用计数功能。
link to death和death notification 功能也在kernel driver中实现了,kernel driver维护和管理 识别和分发Binder node结束的必要信息。命令BC_REQUEST_DEATH_NOTIFICIATION, BC_CLEAR_DEATH_NOTIFICATION, BC_DEAD_BINDER_NODE以及他们的请求码。
Android Binder - Service Manager
Service Manager是所有服务的管理器,因此,所有Server(System Server)都要向它注册,应用程序则向Service Manager查询相应的服务。其实现位于"frameworks/base/cmds/servicemanager\service_manager.c"文件中。
- int main(int argc, char **argv)
- {
- struct binder_state *bs;
- void *svcmgr = BINDER_SERVICE_MANAGER;
- bs = binder_open(128*1024);
- if (binder_become_context_manager(bs)) {
- LOGE("cannot become context manager (%s)\n", strerror(errno));
- return -1;
- }
- svcmgr_handle = svcmgr;
- binder_loop(bs, svcmgr_handler);
- return 0;
- }
首先调用binder_open打开binder设备/dev/binder,参数mapsize指定了需要映射的内存大小,为什么要进行映射呢,什么地方会用到映射地址bs->mapped呢?
- struct binder_state *binder_open(unsigned mapsize)
- {
- struct binder_state *bs;
- bs = malloc(sizeof(*bs));
- if (!bs) {
- errno = ENOMEM;
- return 0;
- }
- bs->fd = open("/dev/binder", O_RDWR);
- if (bs->fd < 0) {
- fprintf(stderr,"binder: cannot open device (%s)\n",
- strerror(errno));
- goto fail_open;
- }
- bs->mapsize = mapsize;
- bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
- if (bs->mapped == MAP_FAILED) {
- fprintf(stderr,"binder: cannot map device (%s)\n",
- strerror(errno));
- goto fail_map;
- }
- /* TODO: check version */
- return bs;
- fail_map:
- close(bs->fd);
- fail_open:
- free(bs);
- return 0;
- }
然后调用binder_become_context_manager使得它称为context manager,也就是Service manager,这个特殊的服务用来管理其他的所有服务。
- int binder_become_context_manager(struct binder_state *bs)
- {
- return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
- }
Service Manager监听请求
Service Manager通过ioctl BINDER_SET_CONTEXT_MGR向Binder驱动声明自己是服务管理器,作为服务管理器有两个最重要的工作,接收其他server的服务注册; 为客户端提供查询和获取服务。因此Service最后会进入一个监听循环,等待用户的请求,并使用srcmgr_handler回调函数处理用户请求。
- void binder_loop(struct binder_state *bs, binder_handler func)
- {
- int res;
- struct binder_write_read bwr;
- unsigned readbuf[32];
- bwr.write_size = 0;
- bwr.write_consumed = 0;
- bwr.write_buffer = 0;
- readbuf[0] = BC_ENTER_LOOPER;
- binder_write(bs, readbuf, sizeof(unsigned));
- for (;;) {
- bwr.read_size = sizeof(readbuf);
- bwr.read_consumed = 0;
- bwr.read_buffer = (unsigned) readbuf;
- res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
- if (res < 0) {
- LOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
- break;
- }
- res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
- if (res == 0) {
- LOGE("binder_loop: unexpected reply?!\n");
- break;
- }
- if (res < 0) {
- LOGE("binder_loop: io error %d %s\n", res, strerror(errno));
- break;
- }
- }
- }
在Service Manager能够服务Server和client的请求之前,要设置bind proc为 LOOPER_ENTER状态,然后调用ioctl BINDER_WRITE_READ等待来自Server和Client的请求,这个ioctl是个阻塞的操作,直到有请求进入,才会返回
binder_parse分析@readbuf中的请求,bwr.read_consumed是请求的长度,@func是请求处理函数
ServiceManager数据结构
- 90 struct svcinfo
- 91 {
- 92 struct svcinfo *next;
- 93 void *ptr;
- 94 struct binder_death death;
- 95 unsigned len;
- 96 uint16_t name[0];
- 97 };
每一个svcinfo代表一个注册的service
@next,所有的service通过next链接到全局变量svclist
@ptr,虽然从命名上是一个pointer,但是存储的是一个handle,一般来说从0x01开始,0x00保留给service manager自身。
@len,name的长度
@name,是service名字,client端要通过这个名字找到匹配的服务。
- struct binder_io
- {
- char *data; /* pointer to read/write from */
- uint32_t *offs; /* array of offsets */
- uint32_t data_avail; /* bytes available in data buffer */
- uint32_t offs_avail; /* entries available in offsets array */
- char *data0; /* start of data buffer */
- uint32_t *offs0; /* start of offsets buffer */
- uint32_t flags;
- uint32_t unused;
- };
binder_io是用来生成binder message的辅助结构
@data 是当前可用buffer位置,这个地址随着加入数据,而改变
@offs 是当前可用的offset buffer位置,可以用来存放obj相对于@data0的偏移地址,4bytes
@data_avail 当前可用的data空间大小
@offs_avail 当前空用的offsets大小
@data0 data buffer的起始位置,data0记录着binder_io数据buffer的起始位置
@offs0 offset buffer的起始位置,offs0记录着binder_io offset buffer的起始位置
从@data0 ~ @data保存着对象,@offs0 ~ @offs保存着obj的偏移位置,这个偏移位置是obj地址相对于@data0的偏移位置
- Andriod binder
- andriod Binder框架记录
- andriod binder-ServiceManager守护进程
- andriod
- andriod
- Andriod
- andriod
- andriod
- Andriod
- Andriod
- Andriod
- binder
- binder
- binder
- Binder
- binder
- binder
- Binder
- LinuxI2C子系统架构
- Linux设备驱动之——PCI 总线
- Android4.0.3 显示系统深入理解
- 除去字符串中非数字的字符&&时间转为Long型
- [桌面+Mobile+Web]重大更新!SpriteSheetViewer 精灵表动画查看器V1.0.2发布!
- Andriod binder
- Android Binder 驱动分析 - 数据结构
- Android binder系统架构
- 解决document.elementFromPoint浏览器差异问题
- Hangman Judge
- ArcGIS 为什么要以显示方式实现接口?
- Linear Cellular Automata
- - 播放器
- Tomcat内存溢出 tomcat outofmemoryerror permgen space