Android是如何实现跨进程通讯的,你们熟悉的Binder是什么,怎么设计的,进程间的数据如何发送接收的。本文将以及解析,并对Binder驱动实现、Native层实现、Java层实现三块作一个总结分析。node
由于要实现跨进程通讯,那么,数据是如何传输的,怎么组织的。两个进程之间是如何知道对方的标识(引用)的,这一系列问题,都由Binder驱动解决,每一个进程须要为其余进程提供服务(API调用),都须要向Binder驱动注册,其余进程才能知道本身的数据传向哪里。这里你们先忽略ServiceManager的特殊身份。只讨论Binder驱动的以为定位便可。安全
这样看来,其实Binder驱动就是一个多个进程之间的中枢神经,支撑起了Android中进程间通讯,它内部的设计,与应用程序进程中的业务,不存在任何耦合关系,只负责实现进程间数据通讯。能够用以下图来理解Binder驱动与应用程序进程之间的关系。数据结构
固然,Android里的Binder架构应该还有ServiceManager这个系统服务。架构
ServiceManager下文简称SM,是一个Android操做系统提供的一个系统进程。那么为何要单独提他呢,由于这个进程里,记录了全部Binder实体(提供服务的Binder实现对象)的信息。性能
也就是说,SM是用来给应用程序查找其余应用程序的数据中心与校验中心,保障进程间通讯的安全新,合法性。学习
SM是系统服务,在系统启动后,SM便启动,并执行如下事情:操作系统
SM处理的消息类型有:设计
注册Binder实体信息到SM的时候,请求数据中须要写到Binder实体的描述信息,以后进行查询的时候就是根据描述信息来获取到对应的Binder应用编号。3d
到这里,咱们能够看出,其实整个Binder架构就是一个Client,Server,DNS的结构,固然Binder驱动就扮演了一个路由器的角色。代理
这个结构的前提,就是DNS须要提早注册。也就是说SM进程须要第一个注册到Binder驱动中,并且,Client和Server都知道SM的引用编号(0),可以直接经过SM获取其余进程提供的Binder引用编号
对于应用程序进程来讲,打开驱动和内存映射动做由Native类ProcessState完成,该类为单利,在构造方法中进行,先打开,再执行内存映射。
为何与共享内存进行对比(性能),是由于共享内存管是unix中最快的一种IPC机制。
共享内存为何快,是由于共享内存至关因而将两个进程的虚拟地址空间指向了一块物理内存,两个进程对该内存区域的修改,可以直接反应到对方进程中,也就是不须要对数据进行拷贝。
前面说到,Binder是经过mmap来实现的,理论上,mmap也可让两个进程映射到同一段物理内存区域(文件)上。可是Binder没有这样实现,若是这样的话,和共享内存就同样了。那Binder又是如何实现的呢。
首先,Binder有驱动程序,全部数据传输和接收,都是经过Binder驱动来操做的。这就带来一个问题,Binder驱动是运行在内核态的,那么数据在使用Binder驱动传输时,是须要在内核内存空间与用户内存空间进行拷贝操做的。
试想下,A进程与B进程进行通讯,A进程给B进程发送数据data,按照上面的分析,数据data须要先从A进程的用户空间拷贝到Binder驱动的内核空间,再经过Binder驱动写入到(具体实现后面说)B进程的Binder驱动内核空间,最后从Binder驱动再拷贝的B进程的用户空间。如此一来,数据进行了两次拷贝。
其实,Binder驱动内部并不须要两次数据的拷贝,缘由在于Binder将内核内存空间与用户内存空间进行了内存映射操做,具体以下图
首先,咱们从数据接收进程看,内核与用户内存空间,经过mmap映射到了同一块物理内存上。也就是说对该块物理内存的修改,将会提现到数据接收进程的用户空间和内核空间。
再看数据发送进程,左边的数据发送进程,只是将内核的内存空间映射到了物理内存上。
接着,当数据发送进程须要向数据接收进程传递数据时,数据只须要从数据发送进程的用户内存空间拷贝到数据发送进程的内核内存空间,此时,由于数据发送进程的内核内存空间与物理内存进行了映射,而数据接收进程的用户内存空间与内核内存空间同时都映射到了同一块物理内存上,因此这次拷贝,直接将数据发送进程的用户空间数据,拷贝到了数据接收进程的用户内存空间。
经过上面的分析,也就能理解,为何说Binder传输数据时须要拷贝1次数据,共享内存不须要拷贝数据
完成对Binder跨进程通讯底层IPC实现分析以后,须要思考,Android如何让两个进程创建联系(如何找到通讯进程),那就须要一个系统进程,全部应用程序都知道它,并能联系到它,从这个系统进程那边,可以查找到(经过Service名字符串)须要通信的进程。
最终,Android采用了Client、Server、ServiceManager的实现架构,其中Client须要从ServiceManager中找到Server,而后Client与Server之间便可进行通讯
那么什么进程可以在ServiceManager中注册呢,就是在Android操做系统中注册过(APP清单文件中的Service)的那部分服务才能注册,到这,也就能理解Android为何采用这种架构模式了,在安全上又进一步约束。
首先要知道Binder驱动是运行在内核态下,内核态的内存是全部进程共享的。
任务一:存储全部进程的Binder信息(引用编号,Server端的虚拟内存地址)
任务二:进程间数据传递
Binder是什么,须要从多方面解释,不一样环境中,其表明的是不同的东西。
Binder在Server中表明的是具体的实现,简称Binder实体
Binder的具体实现应该是在Server进程,也就是说Client进程是没法拿到该实现对象的地址信息的。
那么Binder在Client中表明的仅仅是一个引用(驱动给的)编号,Client可以经过该编号向远端Server发送数据。
驱动,是Binder架构在最核心的一部分,驱动须要作的事情不少
Binder实体(Server端)在驱动中的表述
Binder实体须要在驱动中进行注册,注册时,驱动须要在内核中为Binder实体建立一个结构体binder_node
该结构体中存储的主要数据为
Server端Binder实体在全部实体链表中的节点结构体
说明:每一个Server进程都对应有一个链表,用来存储全部的Binder实体节点,以Binder实体对象的内存地址为索引进行查找。
Binder引用在驱动中以binder_ref结构体的形式存在。改结构体中存储的主要数据为:
说明:每一个Client进程都对应有两个链表,一个是以Binder实体在驱动中的结构体地址为索引创建的链表,一个是以Binder实体在驱动中的引用号为索引简历的链表。
虽然Binder实体和Binder引用都在驱动中有不一样的结构体来标识,可是Client和Server在于Binder进行通讯时,并非经过传递这两个结构体来表明不一样的Binder的,而是经过另外一个统一的结构体flat_binder_object来表明本次通讯对应的Binder。
既然使用的是同一个结构体,那么这个结构体中应该有的内容:
其中Binder类型有如下几种:
那么flat_binder_object里的内容填充方式具体是怎样的呢,好比Server将Binder传递给Client,Server发送的flat_binder_object,类型应该是BINDER_TYPE_BINDER,此时,驱动将会在内核中为Server进程建立对应的binder_node结构,而且将flat_binder_object中的Binder实体的内存地址保存起来。接着驱动须要在内核中为Client进程建立一个binder_ref结构,由于Server穿过来的Binder实体的内存地址在Client进程是无效的,因此驱动须要为Client进程建立一个Binder对应的引用编号,并将此编号存入binder_ref结构中。同时,须要将flat_binder_object中的类型改为BINDER_TYPE_HANDLE,以及存储引用编号。
当Client须要使用Server传递过来的Binder的时候,向驱动传递的数据包中,就须要用到Binder的引用编号,驱动将会对引用编号进行校验,这样就能在安全性上获得保障。
当一个Server进程建立了一个Binder实体,以后,这个实体在各个环境中的表述状况为