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

 123人阅读 评论(0) 收藏 举报

Service Manager是所有服务的管理器,因此,所有Server(System Server)都要向它注册,应用程序则向Service Manager查询相应的服务。其实现位于"frameworks/base/cmds/servicemanager\service_manager.c"文件中。

[cpp] view plaincopy
  1. int main(int argc, char **argv)  
  2. {  
  3.     struct binder_state *bs;  
  4.     void *svcmgr = BINDER_SERVICE_MANAGER;  
  5.   
  6.     bs = binder_open(128*1024);  
  7.   
  8.     if (binder_become_context_manager(bs)) {  
  9.         LOGE("cannot become context manager (%s)\n", strerror(errno));  
  10.         return -1;  
  11.     }  
  12.   
  13.     svcmgr_handle = svcmgr;  
  14.     binder_loop(bs, svcmgr_handler);  
  15.     return 0;  
  16. }  

首先调用binder_open打开binder设备/dev/binder,参数mapsize指定了需要映射的内存大小,为什么要进行映射呢,什么地方会用到映射地址bs->mapped呢?

[cpp] view plaincopy
  1. struct binder_state *binder_open(unsigned mapsize)  
  2. {         
  3.     struct binder_state *bs;  
  4.   
  5.     bs = malloc(sizeof(*bs));  
  6.     if (!bs) {  
  7.         errno = ENOMEM;  
  8.         return 0;  
  9.     }  
  10.   
  11.     bs->fd = open("/dev/binder", O_RDWR);  
  12.     if (bs->fd < 0) {  
  13.         fprintf(stderr,"binder: cannot open device (%s)\n",  
  14.                 strerror(errno));  
  15.         goto fail_open;  
  16.     }  
  17.           
  18.     bs->mapsize = mapsize;  
  19.     bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);  
  20.     if (bs->mapped == MAP_FAILED) {  
  21.         fprintf(stderr,"binder: cannot map device (%s)\n",  
  22.                 strerror(errno));  
  23.         goto fail_map;  
  24.     }  
  25.   
  26.         /* TODO: check version */  
  27.   
  28.     return bs;  
  29.   
  30. fail_map:  
  31.     close(bs->fd);  
  32. fail_open:  
  33.     free(bs);  
  34.     return 0;  
  35. }  

然后调用binder_become_context_manager使得它称为context manager,也就是Service manager,这个特殊的服务用来管理其他的所有服务。

[cpp] view plaincopy
  1. int binder_become_context_manager(struct binder_state *bs)  
  2. {         
  3.     return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);  
  4. }  

Service Manager监听请求

Service Manager通过ioctl BINDER_SET_CONTEXT_MGR向Binder驱动声明自己是服务管理器,作为服务管理器有两个最重要的工作,接收其他server的服务注册; 为客户端提供查询和获取服务。因此Service最后会进入一个监听循环,等待用户的请求,并使用srcmgr_handler回调函数处理用户请求。

[cpp] view plaincopy
  1. void binder_loop(struct binder_state *bs, binder_handler func)  
  2. {         
  3.     int res;  
  4.     struct binder_write_read bwr;  
  5.     unsigned readbuf[32];   
  6.       
  7.     bwr.write_size = 0;  
  8.     bwr.write_consumed = 0;  
  9.     bwr.write_buffer = 0;  
  10.    
  11.     readbuf[0] = BC_ENTER_LOOPER;  
  12.     binder_write(bs, readbuf, sizeof(unsigned));  
  13.   
  14.     for (;;) {  
  15.         bwr.read_size = sizeof(readbuf);  
  16.         bwr.read_consumed = 0;  
  17.         bwr.read_buffer = (unsigned) readbuf;  
  18.           
  19.         res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);  
  20.   
  21.         if (res < 0) {  
  22.             LOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));  
  23.             break;  
  24.         }  
  25.   
  26.         res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);  
  27.         if (res == 0) {  
  28.             LOGE("binder_loop: unexpected reply?!\n");  
  29.             break;  
  30.         }  
  31.         if (res < 0) {  
  32.             LOGE("binder_loop: io error %d %s\n", res, strerror(errno));  
  33.             break;  
  34.         }  
  35.     }  
  36. }  

在Service Manager能够服务Server和client的请求之前,要设置bind proc为 LOOPER_ENTER状态,然后调用ioctl BINDER_WRITE_READ等待来自Server和Client的请求,这个ioctl是个阻塞的操作,直到有请求进入,才会返回

binder_parse分析@readbuf中的请求,bwr.read_consumed是请求的长度,@func是请求处理函数


ServiceManager数据结构

[cpp] view plaincopy
  1. 90 struct svcinfo  
  2. 91 {  
  3. 92     struct svcinfo *next;  
  4. 93     void *ptr;  
  5. 94     struct binder_death death;  
  6. 95     unsigned len;  
  7. 96     uint16_t name[0];  
  8. 97 };  

每一个svcinfo代表一个注册的service

@next,所有的service通过next链接到全局变量svclist

@ptr,虽然从命名上是一个pointer,但是存储的是一个handle,一般来说从0x01开始,0x00保留给service manager自身。

@len,name的长度

@name,是service名字,client端要通过这个名字找到匹配的服务。


[cpp] view plaincopy
  1. struct binder_io  
  2. {  
  3.     char *data;            /* pointer to read/write from */  
  4.     uint32_t *offs;        /* array of offsets */  
  5.     uint32_t data_avail;   /* bytes available in data buffer */  
  6.     uint32_t offs_avail;   /* entries available in offsets array */  
  7.   
  8.     char *data0;           /* start of data buffer */  
  9.     uint32_t *offs0;       /* start of offsets buffer */  
  10.     uint32_t flags;  
  11.     uint32_t unused;  
  12. };  

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的偏移位置


 

原创粉丝点击