Android系统进程间通讯之Binder机制(一)

Android系统进程间通讯之Binder机制(一)

                                                                  

                                                                   ----理论篇


 

    首先我们知道Android是基于Linux内核的,而Linux内核继承和兼容了丰富的Unix系统进程间通讯(IPC:Internet Process Connection),其中包括:

        1、Pipe:管道

        2、Signal:信号

        3、Trace:跟踪

    以上是传统的通讯手段,并且只能用与父进程与子进程之间的通讯,或者兄弟之间的通讯。

        4、Message:报文队列

        5、Share Memory:共享内存

        6、Semaphore:信号量

    以上三种是在AT&T的Unix系统V中,又增加了三种称为“SystemV IPC”的进程间通信机制。

        7、Socket:插口

     其中,Socket是BSD Unix对“System VIPC”机制进行了重要的扩充。

     想对以上几种通讯方式详细了解可参考《Linux内核源代码情景分析》一书

 

     而在Android中采用的是Binder机制实现进程间的通讯。

     Binder是一种进程间通信机制,它是一种类似于COMCORBA分布式组件架构,通俗一点,其实是提供远程过程调用(RPC)功能。使用Client-Server通信方式:一个进程作为Server提供诸如视频/音频解码,视频捕获,地址本查询,网络连接等服务;一个或者多个进程作为ClientServer发起服务请求,获得所需要的服务。

     在AndroidBinder机制中,包含四个角色,分别是:ServerClientServiceManageBinder驱动。关系如下图:

 

   其中:

    Binder驱动:运行于内核空间,Binder机制的核心组件,提供设备文件/dev/binder与用户空间交互。

    ServerClientServiceManage:运行于用户空间,Service Manager提供了辅助管理的功能,ClientServerBinder驱动和Service Manager提供的基础设施上,进行Client-Server之间的通信。

    Service ManagerBinder驱动已经在Android平台中实现好,开发者只要按照规范实现自己的ClientServer组件就可以了,具体实现可见下篇:Android系统进程间通讯之Binder机制(二) - 实践篇。


    下面就AndroidBinder所会涉及的情景具体分析。


Service Manage

    Service Manager是一个linux级的进程,实现对Service的管理。同样的,任何service在被使用之前,均要向Service Manager注册(addService函数实现);同时客户端需要访问某个service时,应该首先向Service Manager查询是否存在该服务,并获取到这个ServergetService函数实现)。

    Service Manager的入口函数在service_manager.c中,下面是 Service Manager的代码部分:

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.指定Service Manager对应的代理binderhandle0,当client尝试与Service Manager通信时,需要创建一个handle0的代理binder,这里的代理binder其实就是第一节中描述的那个代理接口;

       3.通知binder driver(BD)使Service Manager成为BDcontextmanager
       4.
维护一个死循环,在这个死循环中,不停地去读内核中binder driver,查看是否有可读的内容;即是否有对service的操作要求,如果有,则调用svcmgr_handler回调来处理请求的操作。

       5. Service Manager维护了一个svclist列表来存储service的信息。

 注意:

    1、 service在向SM注册时,该service就是一个client,而SM则作为了server。而某个进程需要与service通信时,此时这个进程为clientservice才作为server。因此service不一定为server,有时它也是作为client存在的。

    2、 应用和service之间的通信会涉及到2binder通信:

        a)      应用向SM查询service是否存在,如果存在获得该service的代理binder,此为一次binder通信;

        b)     应用通过代理binder调用service的方法,此为第二次binder通信。


Server

    首先,ServerClient的实现都是Service Manager实现的,对Server启动而言:Server通过defaultServiceManager函数获得Service Manager远程接口,然后将自己的Service添加到Service Manager中去,接着把自己启动起来,等待Client的请求。下面将通过分析源代码了解Server的实现和启动过程是怎么样的。

    假设我们需要定义一个ServerExampleService

    首先,我们需要定义一个IExampleService(继承了IInterface类),然后定义BnExampleService(继承了IExampleServiceBBinder类)。其中BBinder类继承了IBinder类,IInterfaceIBinder类又同时继承了RefBase类。

然而BnExampleService并不是直接接收到Client处发送过来的请求,而是使用了IPCThreadState接收Client处发送过来的请求,而IPCThreadState又借助了ProcessState类来与Binder驱动程序交互。IPCThreadState接收到了Client处的请求后,就会调用BBinder类的transact函数,并传入相关参数,BBinder类的transact函数最终调用BnMediaPlayerService类的onTransact函数,于是,就开始真正地处理Client的请求了。(其中有关IPCThreadStateProcessState的关系下面会有介绍)。以上便是Server的实现过程。

 

    那么对ExampleService的启动流程呢?

    首先:

sp<ProcessState> proc(ProcessState::self());

    这句代码的作用是通过ProcessState::self()调用创建一个ProcessState实例。ProcessState::self()ProcessState类的一个静态成员变量,定义在frameworks/base/libs/binder/ProcessState.cpp文件中。

    这个函数作用是返回一个全局唯一的ProcessState实例gProcess。全局唯一实例变量gProcess定义在frameworks/base/libs/binder/Static.cpp文件中。

    在ProcessState的构造函数中主要以下操作:

          1、  open_driverframeworks/base/libs/binder/ProcessState.cpp)函数打开Binder设备

文件/dev/binder,并将打开设备文件描述符保存在成员变量mDriverFD中:主要是通过open文件操作函数来打开/dev/binder设备文件,然后再调用ioctl文件控制函数来分别执行BINDER_VERSIONBINDER_SET_MAX_THREADS两个命令来和Binder驱动程序进行交互,前者用于获得当前Binder驱动程序的版本号,后者用于通知Binder驱动程序。(openBinder驱动程序中的具体实现,打开/dev/binder设备文件后,Binder驱动程序就为ExampleService进程创建了一个struct binder_proc结构体实例来维护ExampleService进程上下文相关信息)。

          2、  mmap来把设备文件/dev/binder映射到内存中。 mmap函数调用完成之后,Binder驱动程序就为当前进程预留了BINDER_VM_SIZE大小的内存空间了。

    至此,ProcessState全局唯一变量gProcess就创建完毕了。


    接下来:

       调用defaultServiceManager函数来获得Service Manager的远程接口,定义ExampleService::instantiate函数把ExampleService添加到Service Manger中去了,如下:

void ExampleService::instantiate() {
    defaultServiceManager()->addService(String16("exampleservice"));
}

    其中defaultServiceManager返回的实际是一个BpServiceManger类实例,因此,我们具体了解一下BpServiceManger::addService的实现,这个函数实现在frameworks/base/libs/binder/IServiceManager.cpp文件中。

    对addService的理解:BpServiceMangerClient的形式,将相应的一些数据通过Parcel类中各种Parcel.writexxx的方式写入Parcel,最后通过

status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);

    将data传递,实现信息交互传递(主要是Binder驱动程序之间,传输这个ExampleService)。实现ExampleService的启动过程。

    最终实现的就是就是把ExampleService这个Binder实体的引用写到一个struct svcinfo结构体中,主要是它的名称和句柄值,然后插入到链接svclist的头部去。Client来向Service Manager查询服务接口时,只要给定服务名称,Service Manger就可以返回相应的句柄值了,从而实现调用该Service

    最后

ProcessState::self()->startThreadPool();  
IPCThreadState::self()->joinThreadPool();

在一个无穷循环中等待Client的请求。


Client

    同样的,在这将简单介绍一下Client的实现流程与获取Server的流程,Client的实现流程原理跟Server如出一辙,获取Server的方式也是通过ServiceManager实现的。

    假设我们定义一个Client:ExampleService。

    首先我们需要定义一个 IExampleService (继承了IInterface类),然后定义 BpExampleService(继承了IExampleServiceBpinder类)。其中Bpinder类继承了IBinder类,IInterfaceIBinder类又同时继承了RefBase类。在BpExampleService调用remote()->transact实现数据传递。

    remote()是在BpExampleService的父类BpRefBase中实现的,返回的就是一个BpBinder.实际上调用的就是BpBindertransact,将写入到Parcel中的数据传递出去并取得返回值。

    对于Serve的启动流程主要是调用addService 实现的,对于Client获取Server的流程采用getService实现。

    声明:

sp<IServiceManager> sm = defaultServiceManager();  
sp<IBinder> binder;

    因为可能存在相对应需要获取的Server可能还没有启动起来,所以这里如果发现取回来的binder接口为NULL,就睡眠0.5秒,然后再尝试获取,这是获取Service接口的标准做法:

do {  
   binder = sm->getService(String16("exampleservice"));  
      if (binder != 0) {  
           break;  
         }  
      LOGW("service not published, waiting...");  
       usleep(500000); // 0.5 s  
        } while(true);

    对于BpServiceManager::getService的具体实现在这就不做详细介绍,跟ServeraddService如出一辙。

    接着,

sExampleService = interface_cast<IExampleService>(binder);

    这里的interface_cast实际上最终调用了IExampleService::asInterface函数,创建一个BpExampleService对象供我们得到。有了这个BpExampleService这个远程接口之后,Client就可以调用ExampleService的服务了。

    最后,在 BpExampleService 下定义相应的方法实现信息传递 : 定义一个 Parcel data ,将数据写入,然后调用 remote()->transact 函数将数据传递出去,在 Server 下的 onTransact 函数就能接收到相应的 read 出相应的数据。

IBinder, BBinderBpBinder

    首先BBinder(也就是BnBinder)与BpBinder均为IBinder的子类,因此可以看出IBinder定义了binder IPC的通信协议,BBinderBpBinder在这个协议框架内进行的收和发操作,构建了基本的binder IPC机制。

ProcessState, IPCThreadState

    ProcessState是以单例模式设计的。每个进程在使用binder机制通信时,均需要维护

一个ProcessState实例来描述当前进程在binder通信时的binder状态。ProcessState有如下2个主要功能:
   
 1.创建一个thread,该线程负责与内核中的binder模块进行通信,称该线程为Pool thread;(Poolthread:BinderIPC中,所有进程均会启动一个thread来负责与BD来直接通信,也就是不停的读写BD,这个线程的实现主体是一个IPCThreadState对象. Poolthread的启动方式:ProcessState::self()->startThreadPool();
   
 2.为指定的handle创建一个BpBinder对象,并管理该进程中所有的BpBinder对象。

 

    IPCThreadState也是以单例模式设计的。由于每个进程只维护了一个ProcessState实例,同时ProcessState只启动一个Pool thread,也就是说每一个进程只会启动一个Pool thread,因此每个进程则只需要一个IPCThreadState即可。

    Pool thread的实际内容则为:IPCThreadState::self()->joinThreadPool();

    IPCThreadState有两个重要的函数,talkWithDriver函数负责从BD读写数据,executeCommand函数负责解析并执行mIn中的数据。

    ProcessState&IPCThreadState&BpBinder&BinderDriver关系图:



Parcel

    ParcelbinderIPC中的最基本的通信单元,它存储C-S间函数调用的参数.但是Parcel只能存储基本的数据类型,如果是复杂的数据类型的话,在存储时,需要将其拆分为基本的数据类型来存储。Parcel类下定义了相应的writeread方法写入和读取数据。

       注:写入和读取的顺序需要一样,否则会出错。


具体的实现可参见下篇本人具体就项目采用的binder通讯机制的实现Android系统进程间通讯之Binder机制(二) - 实践篇。



  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
千里马8年Android系统及应用开发经验,曾担任过美国unokiwi公司移动端技术总监兼架构师,对系统开发,性能优化,应用高级开发有深入的研究,Android开源定制ROM Lineage的贡献者之一,国内首家线下开辟培训Android Framework课程,拥有2年的Android系统培训经验。成为腾讯课堂专业负责android framework课程分享第一人,致力于提高国内android Framework水平Android Framework领域内是国内各大手机终端科技公司需要的人才,应用开发者都对Android系统充满着好奇,其中的binder是重中之重,都说无binderAndroidbinde是Android系统的任督二脉。课程水平循序渐进,由中级再到高级,满足各个层次水平的android开发者。1、灵活使用binder进程通信,在app端对它的任何api方法等使用自如2、可以单独分析android系统源码中任何binder部分,分析再也没有难度3、掌握binder驱动本质原理,及对应binder驱动怎么进行跨进程通信,及内存等拷贝方式数据等4、对binder从上层的java app端一直到最底层的内核binder驱动,都可以顺利理通5、针对系统开发过程中遇到的binder报错等分析方法,及binder bug案例学习6、针对面试官任何的binder问题都可以对答自如7、socket这种跨进程通信实战使用8、针对android源码中使用的socket源码轻松掌握9、android系统源码中最常见的socketpair中双向跨进程通信10、使用socket实现一个可以让app执行shell命令的程序

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值