zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    漫谈:机器学习中距离和相似性度量方法
    逻辑回归Logistic Regression 之基础知识准备
    从随机过程到马尔科夫链蒙特卡洛方法
    ICLR 2016
    [转]Wireshark抓包工具--TCP数据包seq ack等解读
    网络学习资源
    Data obtained from ping: is it round trip or one way?
    【转】 一张图看懂开源许可协议,开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别
    How To Configure a Redis Cluster on Ubuntu 14.04
    redis connetced refused remote
  • 原文地址:https://www.cnblogs.com/manuosex/p/3590052.html
Copyright © 2011-2022 走看看