Anciroid的IPC机制-Binder原理

Binder驱动的原理和实现
通过上一节的介绍,大家应该对Binder有了基本的认识了。任何上层应用程序接口和用户操作都需要底层硬件设备驱动的支持,并为其提供各种操作接口。本节首先从Binder的驱动实现人手,分析其原理和它提供给用户层使用的接口。
Binder驱动的原理
为了完成进程间通信,Binder采用了AIDL(Android Interface Definition Language)来描述进程间的接口。在实际的实现中,IBinder是作为一个特殊的字符型设备而存在的,设备节点为
/dev/binder,其实现遵循Linux设备驱动模型,实现代码主要涉及以下文伴:
(1)kemel/drivers/staging/binder.h
(2)kernel/drivers/staging/binder.c
在其驱动的实现过程中,主要通过bjnder ioctl函数与用户空间的进程交换数据。BINDER WRITE.- READ用来读写数据,数据包中有一个cmd域用于区分不同的请求。binder thread_ write函数用于发送请求或返回结果,而binder thread read函数则用于读取结果。

在binder thread—write函数中调用binder transaction函数来转发请求并返回结果。当收到请求时,binder transaction函数会通过对象的handle找到对象所在的进程,如果handle为空,就认为对象是context__ mgr,把请求发给context_mgr所在的进程。请求中所有的Binder对象全部放到一个RB树中,最后把请求放到目标进程的队列中,等待目标进程读取。数据的解析工作放在binder_parser中实现;关于如何生成context__ mgr,内核中提供了BINDER。SET_ CONTEXTMGR命令来完成此项功能。下面我们就来看看Binder驱动究竟是如何实现的。
3.2.2 Blnder驱动的实现
上面我们已经对Binder驱动的原理进行了分析,在开始分析驱动的实现之前,我们还是通过一个例子来说明Binder在实际应用中应该如何运用,以及它能帮我们解决什么样的问题。这样会更容易帮助大家理解Binder驱动的实现。比如,A进程如果要使用B进程的服务,B进程首先要注题此服务,A进程通过Binder荻取该服务的hanlde,通过这个handle,A进程就可以使用该服务了。此外,你可以把handle理解成地址。A进程使用B进程的服务还意味着二者遵循相同的协议,这个协议反映在代码上就是二者要实现IBinder接口。
1.“对象”与“引用”
Binder不仅是Android系统中的一个完善的IPC机制,它也可以被当作Android系统的一种RPC(远程过程调用)机制,因为Binder的功能就是在本地“执行”其他进程的功能。因此,进程在通过Binder获取将要调用的进程服务时,可以是一个本地对象,也可以是一个远程服务的“引用”。这一点可能比较难以理解,稍候就会为大家分析,这里就先记住Binder不仅可以与本地进程通信,还可以与远程进程通信;这里的本地进程就是我们所说的本地对象,而远程进程则是我们所说的远程服务的一个“引用”。Binder的实质就是要把对象从一个进程映射到另一个进程中,而不管这个对象是本地的还
是远程的。如果是本地对象,更好理解;如果是远程对象,就按照我们上面所讲的来理解,即将远程对象的“引用”从一个进程映射到另一个进程中,于是当使用这个远程对象时,实际上
就是使用远裎对象在本地的一个“引用”,类似于把这个远程对象当作一个本地对象在使用。这也就是Binder与其他IPC机制不同的地方。
这个本地“对象”与远程对象的“引用”有什么不同呢?本地“对象”表示本地进程的地址空间的一个地址,而远程对象的“引用”则是一个抽象的32位句柄。它们之间是互斥的:
所有的进程本地对象都是本地进程的一个地址( address、ptr、binder),所有的远程进程的对象的“引用”都是一个句柄。对于发送者进程来说,不管是“对象”还是“引用”,它都会认为被发送的Binder对象是一个远程对象的句柄(即远程对象的“引用”)。但是,当Binder对象的数据被发送至日远端接收进程时,远端接收进程则会认为该Binder对象是一个本地对象地址(即本地对象)。正如我们之前说的,当Binder对象被接收进程接收后,不管该Binder对象是
 “引用”这个词并不是官方所描述的,而是笔者为了方便大家理解,将其称为引用,或许你有更好的描述。

本地的还是远程的,它都会被当作一个本地进程来处理。因此,从第三方的角度来说,尽管名称不同,对于一次完整的Binder调用,都将指向同一个对象,Binder驱动则负责两种不同名称的对象的正确映射,这样殖能把数据发送给正确的进程进行通信。这个映射关系也是进程间引用对象的基础,对一个对象的引用,在远程是句柄,在本地则是地址(即本地对象的地址)。下面我们先介绍分析该机制中所使用的数据结构体,然后再对整个流程进行分析。
2.loincier Work
首先来看一个最简单也是最基础的结构体binder work,其定义如代码清单3-1所示。
代码清单3-1 binder vork定义
struct /oinder_work {
struct list head entry;
enum {
BINDER_WORK_TRANSACT工ON = l,
BINDER _WORK_TRANSACTION_COMPLETE ,
B工NDER_WORK_NODE ,
BINDER_WORK_DEAD_BINDER,
BINDER_WORK_DEAD_BINDER_AN D_CLEAR r
BINDER WORK CLEAR DEATH NOTIFICATION,
} type;
萁中entry被定义为list head,用来实现一个双向链表,存储所有binder work的队列;此外,还包含一个enum类型的type,表示binder work的类型,后文会对这些类型进行详细分析,
大家就会觉得它更像是一个用来表示状态的enum。
3.Binder的类型
Binder的类型是使用定义在binder.h头文件中的一个enum来表示的,定义如代码清单3-2
所示。
代码清单3-2 Binder类型
#define B_PACK_CHARS (cl, c2, c3, c4) \
#define B TYPE LARGE Ox85
enum {
BINDER TYPE BINDER =B PACK_CHARS(’s’, ’b’, ’’,B_TYPE_LARGE),
BINDER TYPE WEAK BINDER =B PACK CHARS( 'W', 'b', ’’,B_TYPE_lARGE),
BINDER TYPE HANDLE =B PACK_CHARS(’s’, 'h', ’’, B_TYPE_LARGE),
BINDER TYPE WEAK HANDLE =B PACK CHARS( 'W', 'h!, ’’, B_TYPE_LARGE),
BINDER TYPE FD =B PACK_CFiARS(7f’, ’d’, ’’,B_TYPE_LARGE),
};
从上面的代码可以看出,Binder被分成了5个不同的类型,但是仔细一看却是3个不同的大类,它们分别是:本地对象(BINDER TYPE BINDER. BINDER TYPE l;VEAK BINDER).

远程对象的“引用”( BINDEIL TYPE HANIDLE、BINDER TYPE WEAK HANDLE)的文件
( BINDER—TYPE FD)。前面两种都是我们刚刚分析过的,下面主要分析最后一种——文件(BINDER_ TYPE FD)。如果传递的是BINDER TYPE FD类型,其实还是会将文件映射到句
柄上,根据此fd找到对应的文件,然后在目标进程中分配一个fd,最后把这个fd赋值给返回的句柄。
4。Binder对象
我们把进程之间传递的数据称之为Binder对象(Binder Object),它在对应源码中使用
flat binder_object结构体(位于binder.h文件中)来表示,其定义如代码清单3-3所示。
代码清单3-3 flat_binder_object定义
struct flat_ binder_object {
unsigned long type;
unsigned long flags;
union t
void *obinder ;
signed long handle;
};
void *cookie;
该结构体中的type字段描述的是Binder的粪型,传输的数据是一个复用数据联合体。对于Binder类型,数据就是一个Binder本地对象;HANDLE类型,就是一个远程的handle句柄。
本地Binder对象和远程handle句柄比较难以理解,这里我们再次举例说明:假如A有个对象O,对于A来说,O就是一个本地的Binder对象;如果B想访问A的O对象,对于B来说,O就是一个handle。因此,从根本上来说,handle和Binder都指向O。如果是本地对象,Binder还可以带有额外的数据,这些数据将被保存到cookie字段中。flags字段表示传输方式,比如同步和异步等,其值同样使用一个enum来表示,定义如代码清单3-4所示。其中TF ONEWAY表示单向传递,是异步的,不需要返回;TFROOT OBJECT表面;内容是一个组建的根对象,对应类型为本地对象Binder; TF STATUS CODE表示内容是一个32位的状态码,将对应类型为远程对象的“引用”(即句柄handle); TF ACCEPT FDS表面;可以接收一个文件描述符,对应的类型为文件(BIND嚣R TYPE FD),即handle中存储的为文件描述符。

5. lobinder transaction ciata
其实我们并没有从flat binder_object结构体中看到Binder对象所传递的实际内容,因为Binder对象所传递的实际内容是通过另外一个结构体binder transaction data来表示的,其定义如代码清单3-5所示。
代码清单3-5 binder_transaction—data定义
structbinder—transaction_data {
union{
size—t handle;
void xptr;
) target;
void *cookie;
unsigned int code;
unsigned int flags;
pid_t sender_pid;
uid—t sender—euid;
size—t data—size;
size—t offsets—size;
union f
struct f
const void *buffer;
const void *offsets;
} ptr;
uint8一t buf[8];
} data;
}j
该结构体是理解Binder驱动实现的关键,下面将详细地对一个重要的数据进行分析。其中target字段又足一个复合联合体对象,target字段中的handle是要处理此事件的目标对象的句柄,根据此handle,Binder驱动可以找到应该由哪个进程处理此事件,并且把此事件的任务分发给一个线程,而那个线程也正在执行ioctl的BINDER- WRITE_ READ操作,即正在等待一个请求(见3.1节和3.2.1节),处理方法将稍候分析。target的ptr字段与handle对应,对于请求方,使用handle来指出远程对象;对于响应方,使用ptr来寻址,以便找到需要处理此事件的对象。所以handle和ptr是一个事物的两种表达(正如前面所说的本地对象和远程对象的“引用”),handle和ptr之间的翻译(解析)关系正是Binder驱动需要维护的(在binder_ transaction函数中,稍候分析)。
另外,该结构体中的cookie字段表示target对象所附加的额外数据;code是一个命令,它描述了请求Binder对象执行的操作;flags字段描述了传输的方式与flat binder_object中的flags字段对应;sender_pid和sender_ euid表示该进程的pid和uid;data size裹示数据的大小字节数;offsets_ size表示数据的偏移量字节数;最后一个union数据data表示真正的数据,其中ptr表看;与target->ptr对应的对象的数据,buf表示与handle对象对应的数据,data中的ptr中的buffer

时间: 2024-12-25 03:19:15

Anciroid的IPC机制-Binder原理的相关文章

Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析_Android

        在前面一篇文章Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路中,介绍了在Android系统中Binder进程间通信机制中的Server角色是如何获得Service Manager远程接口的,即defaultServiceManager函数的实现.Server获得了Service Manager远程接口之后,就要把自己的Service添加到Service Manager中去,然后把自己启动起来,等待Cl

浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路_Android

   上一篇文章Android进程间通信(IPC)机制Binder简要介绍和学习计划简要介绍了Android系统进程间通信机制Binder的总体架构,它由Client.Server.Service Manager和驱动程序Binder四个组件构成.本文着重介绍组件Service Manager,它是整个Binder机制的守护进程,用来管理开发者创建的各种Server,并且向Client提供查询Server远程接口的功能.         既然Service Manager组件是用来管理Serve

Android进程间通信(IPC)机制Binder简要介绍

在Android系统中,每一个应用程序都是由一些Activity和Service组成的,这些Activity和Service有可能运行在同一个进程中,也有可能运行在不同的进程中.那么,不在同一个进程的Activity或者Service是如何通信的呢?这就是本文中要介绍的Binder进程间通信机制了. 我们知道,Android系统是基于Linux内核的,而Linux内核继承和兼容了丰富的Unix系统进程间通信(IPC)机制.有传统的管道(Pipe).信号(Signal)和跟踪(Trace),这三项

Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析_Android

     在上一篇文章中,我们分析了Android系统进程间通信机制Binder中的Server在启动过程使用Service Manager的addService接口把自己添加到Service Manager守护过程中接受管理.在这一篇文章中,我们将深入到Binder驱动程序源代码去分析Client是如何通过Service Manager的getService接口中来获得Server远程接口的.Client只有获得了Server的远程接口之后,才能进一步调用Server提供的服务.       

Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路_Android

        在前面一篇文章浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路中,介绍了Service Manager是如何成为Binder机制的守护进程的.既然作为守护进程,Service Manager的职责当然就是为Server和Client服务了.那么,Server和Client如何获得Service Manager接口,进而享受它提供的服务呢?本文将简要分析Server和Client获得Service Manager的过程.     

深入理解Android IPC机制之Binder机制

Binder是Android系统进程间通信(IPC)方式之一.Linux已经拥有的进程间通信IPC手段包括(Internet Process Connection): 管道(Pipe).信号(Signal)和跟踪(Trace).插口(Socket).报文队列(Message).共享内存(Share Memory)和信号量(Semaphore).本文详细介绍Binder作为Android主要IPC方式的优势. Binder机制概述: 基于Client-Server的通信方式广泛应用于从互联网和数据

Android开发艺术探索——第二章:IPC机制(中)

Android开发艺术探索--第二章:IPC机制(中) 好的,我们继续来了解IPC机制,在上篇我们可能就是把理论的知识写完了,然后现在基本上是可以实战了. 一.Android中的IPC方式 本节我们开始详细的分析各中跨进程的方式,具体方式有很多,比如可以通过在Intent中附加extras来传递消息,或者通过共享文件的方式来共享数据,还可以采用Binder方式来跨进程通信,另外,ContentProvider天生就是支持扩进程访问的,所以通过Socket也可以实现IPC,上述的各种方法都能实现I

Android开发艺术探索——第二章:IPC机制(上)

Android开发艺术探索--第二章:IPC机制(上) 本章主要讲解Android的IPC机制,首先介绍Android中的多进程概念以及多进程开发模式中常见的注意事项,接着介绍Android中的序列化机制和Binder,然后详细的介绍Bundle,文件共享,AIDL,Messenger,ContentProvider和Socker等进程间通讯的方法,为了更好的使用AIDL进行进程间通讯,本章引入了Binder连接池的概念,最后,本章讲解各种进程间通信方式的优缺点和使用场景,通过本章,可以让读者对

Android艺术开发探索——第二章:IPC机制(下)

Android艺术开发探索--第二章:IPC机制(下) 我们继续来讲IPC机制,在本篇中你将会学习到 ContentProvider Socket Binder连接池 一.使用ContentProvider ContentProvider是Android中提供的专门用来不同应用之间数据共享的方式,从这一点来看,他天生就是适合进程间通信,和Messenger一样,ContentProvider的底层实现同样也是Binder,由此可见,Binder在Android系统中是何等的重要,虽然Conten