当前位置:操作系统 > 安卓/Android >>

Android Binder IPC分析

1 .binder 通信概述
 
    binder 通信是一种client-server 的通信结构,
    1. 从表面上来看,是client 通过获得一个server 的代理接口,对server 进行直接调用;
    2. 实际上,代理接口中定义的方法与server 中定义的方法是一一对应的;
    3.client 调用某个代理接口中的方法时,代理接口的方易做图将client 传递的参数打包成为Parcel 对象;
    4. 代理接口将该Parcel 发送给内核中的binder driver.
    5.server 会读取binder driver 中的请求数据,如果是发送给自己的,解包Parcel 对象,处理并将结果返回;
    6. 整个的调用过程是一个同步过程,在server 处理的时候,client 会block 住。
 
  \  
 
2 .service manager
 
Service Manager 是一个linux 级的进程, 顾名思义,就是service 的管理器。这里的service 是什么概念呢?这里的service 的概念和init 过程中init.rc 中的service 是不同,init.rc 中的service 是都是linux 进程,但是这里的service 它并不一定是一个进程,也就是说可能一个或多个service 属于同一个linux 进程。在这篇文章中不加特殊说明均指android native 端的service 。
任何service 在被使用之前,均要向SM(Service Manager) 注册,同时客户端需要访问某个service 时,应该首先向SM 查询是否存在该服务。如果SM 存在这个service ,那么会将该service 的handle 返回给client ,handle 是每个service 的唯一标识符。
   
    SM 的入口函数在service_manager.c 中,下面是SM 的代码部分
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;
}
这个进程的主要工作如下:
    1. 初始化binder ,打开/dev/binder 设备;在内存中为binder 映射128K 字节空间;
    2. 指定SM 对应的代理binder 的handle 为0 ,当client 尝试与SM 通信时,需要创建一个handle 为0 的代理binder ,这里的代理binder 其实就是第一节中描述的那个代理接口;
3. 通知binder driver(BD) 使SM 成为BD 的context manager ;
4. 维护一个死循环,在这个死循环中,不停地去读内核中binder driver ,查看是否有可读的内容;即是否有对service 的操作要求, 如果有,则调用svcmgr_handler 回调来处理请求的操作。
5.SM 维护了一个svclist 列表来存储service 的信息。
 
 \ 
 
这里需要声明一下,当service 在向SM 注册时,该service 就是一个client ,而SM 则作为了server 。而某个进程需要与service 通信时,此时这个进程为client ,service 才作为server 。因此service 不一定为server ,有时它也是作为client 存在的。
 
由于下面几节会介绍一些与binder 通信相关的几个概念,所以将SM 的功能介绍放在了后面的部分来讲。
 
应用和service 之间的通信会涉及到2 次 binder 通信。
 
1. 应用向SM 查询service 是否存在,如果存在获得该service 的代理binder ,此为一次binder 通信;
2. 应用通过代理binder 调用service 的方法,此为第二次binder 通信。
 
3 .ProcessState
 
ProcessState 是以单例模式设计的。每个进程在使用binder 机制通信时,均需要维护一个ProcessState 实例来描述当前进程在binder 通信时的binder 状态。
    ProcessState 有如下2 个主要功能:
    1. 创建一个thread, 该线程负责与内核中的binder 模块进行通信,称该线程为Pool thread ;
    2. 为指定的handle 创建一个BpBinder 对象,并管理该进程中所有的BpBinder 对象。
 
3.1 Pool thread
 
            在Binder IPC 中,所有进程均会启动一个thread 来负责与BD 来直接通信,也就是不停的读写BD ,这个线程的实现主体是一个IPCThreadState 对象,下面会介绍这个类型。
            下面是Pool thread 的启动方式:
ProcessState::self()->startThreadPool();
3.2 BpBinder 获取
 
BpBinder 主要功能是负责client 向BD 发送调用请求的数据。它是client 端binder 通信的核心对象,通过调用transact 函数向BD 发送调用请求的数据,它的构造函数如下:
BpBinder(int32_t handle);
    通过BpBinder 的构造函数发现,BpBinder 会将当前通信中server 的handle 记录下来,当有数据发送时,会通知BD 数据的发送目标。
ProcessState 通过如下方式来获取BpBinder 对象:
ProcessState::self()->getContextObject(handle);
在这个过程中,ProcessState 会维护一个BpBinder 的vector mHandleToObject ,每当ProcessState 创建一个BpBinder 的实例时,回去查询mHandleToObject ,如果对应的handle 已经有binder 指针,那么不再创建,否则创建binder 并插入到mHandleToObject 中。
    ProcessState 创建的BpBinder 实例,一般情况下会作为参数构建一个client 端的代理接口,这个代理接口的形式为BpINTERFACE , 例如在与SM 通信时,client 会创建一个代理接口BpServiceManager .
     
  
4 .IPCThreadState
 
IPCThreadState 也是以单例模式设计的。由于每个进程只维护了一个ProcessState 实例,同时ProcessState 只启动一个Pool thread ,也就是说每一个进程只会启动一个Pool thread ,因此每个进程则只需要一个IPCThreadState 即可。
    Pool thread 的实际内容则为:
    IPCThreadState::self()->joinThreadPool();
 
ProcessState 中有2 个Parcel 成员,mIn 和mOut ,Pool thread 会不停的查询BD 中是否有数据可读,如果有将其读出并保存到mIn ,同时不停的检查mOut 是否有数据需要向BD 发送,如果有,则将其内容写入到BD 中,总而言之,从BD 中读出的数据保存到mIn ,待写入到BD 中的数据保存在了mOut 中。
ProcessState 中生成的BpBinder 实例通过调用IPCThreadState 的transact 函数来向mOut 中写入数据,这样的话这个binder IPC 过程的client 端的调用请求的发送过程就明了了 。
 
IPCThreadState 有两个重要的函数,talkWithDriver 函数负责从BD 读写数据,executeCommand 函数负责解析并执行mIn 中的数据。
 
5. 主要基类
 
5.1 基类IInte易做图ce
为server 端提供接口,它的子类声明了service 能够实现的所有的方法;
 
5.2 基类IBinder
    BBinder 与BpBinder 均为IBinder 的子类,因此可以看出IBinder 定义了binder IPC 的通信协议,BBinder 与BpBinder 在这个协议框架内进行的收和发操作,构建了基本的binder IPC 机制。
5.3 基类BpRefBase
    client 端在查询SM 获得所需的的BpBinder 后,BpRefBase 负责管理当前获得的BpBinder 实例。
 
 
6. 两个接口类
 
6.1 BpINTERFACE
 
如果client 想要使用binder IPC 来通信,那么首先会从SM 出查询并获得server 端service 的BpBinder ,在client 端,这个对象被认为是server 端的远程代理。为了能够使client 能够想本地调用一样调用一个远程server ,server 端需要向client 提供一个接口,client 在在这个接口的基础上创建一个BpINTERFACE ,使用这个对象,client 的应用能够想本地调用一样直接调用server 端的方法。而不用去关心具体的binder IPC 实现。
下面看一下BpINTERFACE 的原型:
    class BpINTERFACE : public BpInte易做图ce<IINTERFACE>
 
    顺着继承关系再往上看
    template<typename INTE
补充:移动开发 , Android ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,