在从Android 6.0源码的视点剖析Activity的发动进程一文(https://blog.csdn.net/AndrExpert/article/details/81488503)中,咱们了解到Activity的发动进程终究由体系服务ActivityManagerService完结,ActivityManagerServer是承继于Binder且运转在体系进程中,Activity的发动本质是一次依据Binder机制的跨进程通讯。除此之外,Android体系还为运用程序供给了各种体系服务,比方多媒体播映、音视频获取、读取传感器数据等,它们之间的交互都是由Binder机制完结的。那么,所谓的Binder终究是什么?实践上,Binder并不是一个切当的概念,它在不同的层次表述大不相同,比方一般含义下,Binder指Android体系中特有的一种跨进程通讯办法;从用户空间的视点来说,关于Server进程,Binder指Binder本地目标,而关于Client进程,Binder指Binder署理目标;从内核空间的视点来说,Binder指Binder驱动;从传输通讯的视点来说,Binder是能够跨进程传递的目标。
作者 | 蒋东国
责编 | 屠敏
出品 | CSDN博客
Binder基本原理
IPC与Binder简介
进程是程序的实体,它是程序的一次运转活动,一起也是操作体系资源分配和调度的基本单位。在操作体系中运转着许许多多的进程,为了保证体系的有序运转和进程间互不搅扰,操作体系引进了进程阻隔的概念来保证不同进程之间彼此独立。进程阻隔运用了虚拟地址空间技能,该技能经过为不同的进程分配不同的虚拟地址,使得关于每个进程来说都认为自己独享了整个体系,彻底不知道其他进程的存在,这样就避免了进程间过错的彼此写入数据而导致进程无法正常运转。可是,尽管进程阻隔能够保证每个进程的数据安全,不被歹意损坏,但毕竟操作体系是一个有机的的共同全体,就像人体样,尽管人体的各个器官也是彼此独立,可是若要完结某一个行为,就需求在大脑的操控下对相关器官进行分配,一起器官之间也会彼此传递信号,操作体系亦是如此。操作体系是办理核算机硬件与软件资源的核算机程序,它由内核、驱动程序、接口库及外围组成,其间,内核是操作体系的中心,具有拜访受维护的内存空间和拜访底层硬件设备的一切权限。当操作体系需求履行某个使命时,必定需求体系中相关进程在内核的操控下进行协作,既然是彼此协作,就必定牵涉到进程间的数据交互,为了完结这个意图,跨进程通讯技能开端"闪亮上台"。
IPC,跨进程通讯
跨进程通讯(IPC,Interprocess Communication)是一组编程接口,它答应在一个操作体系中不同进程之间传递或交流信息,其存储-转发办法通讯进程大致为:假定有两个运转在用户空间的进程A、B,进程A要给进程B发送数据,那么进程A会经过体系调用copy_from_user将数据copy到内核空间,然后把内核空间经过体系调用copy_to_user将对应的数据copy到进程B即完结。下图为IPC通讯模型:
用户空间和内核空间是人们从逻辑上抽离出来的概念,旨在差异操作体系中一般的运用程序和内核。内核是操作体系的中心,它具有拜访受维护内存空间和底层硬件设备的一切权限,维持着整个操作体系的正常运转。为了维护内核不受损坏,一般的运用程序被颁发有限的资源拜访权限,假如一般的运用程序需求拜访受限的资源,就需求经过体系调用经过内核来拜访这些被维护的资源。用户空间拜访内核空间经过体系调用完结,用户空间拜访用户空间则需求经过内核模块/驱动来完结。
Android体系是依据Linux内核完结的,天然支撑Linux体系中的IPC办法,这些办法包括管道、System V IPC(包括音讯行列/同享内存/信号灯)和socket。其间,管道是一种半双工的通讯办法,数据只能单向流转且只能在具有父子进程联系的进程间运用;System V IPC是Linux体系为了补偿管道在进程间通讯的缺乏所引进,它包括音讯行列、信号灯和同享内存三种进程间通讯机制,它们同享通用的认证办法,即进程在运用某种类型的IPC资源曾经,有必要经过体系调用传递一个仅有的引证标识符到内核来拜访这些资源;Socket套接字是一种通用的接口,用于跨网络的进程间通讯和本机上进程间的低速通讯,而且支撑Client-Server的通讯办法。
下表为上述5种IPC办法差异:
(1) C/S结构:Client-Server结构是一种网络架构,它把客户端与服务器差异开来。客户端发送恳求到服务器,服务器接纳并处理恳求,然后回来成果给客户端。在Android体系中,大部分体系服务都是经过这种架构为运用程序供给服务,然后让运用程序具有丰厚的功用。
(2) 存储-转发办法:数据先从发送方缓存区复制到内核拓荒的缓存区中,然后再从内核缓存区复制到接纳方缓存区,因而整个进程需求复制两次。
Binder简介
尽管Android体系是依据Linux体系完结的,但它并没有运用上述的5种办法作为体系的进程间通讯办法,首要是由这几种办法要么是开支过大,要么便是安全性低。因为Android体系作为一种嵌入式体系,设备资源相对有限,因而对相关的功用要求也十分高,过大的开支会严重影响体系的运转功用。别的,Android体系是开放式的,具有很多的开发者渠道,运用程序的来历也十分广泛,一起传统的IPC办法无法取得对方进程牢靠的UID/PID进行身份校验,这会直接影响智能设备的安全。依据此,Android体系树立了一套新的IPC机制来满意体系中对较高的传输功用和安全性通讯要求,这种Android特有的IPC机制便是Binder机制。
Binder是依据OpenBinder完结的,OpenBinder由Google公司的Dianne Hackborn开发,旨在供给一个简略的进程间相互通讯的途径。Binder机制选用C/S通讯模型,它运用Binder来作为Server服务对外的拜访接入点和Client向Server建议服务恳求的"地址",而且在进程间通讯的进程中,数据传输只需复制一次,而且Client的身份验证标志(UID/PID)只能由Binder机制在内核中增加,因而具有安全性高、传输功用好等优势。与其他IPC机制不同,Binder运用了面向目标的思维来描绘Server端的拜访接入点和Client端的服务恳求建议地址,具体来说便是Server端的拜访接入点本质是坐落Server进程中的一个Binder实体目标,该目标供给了一套办法用于向Client端供给各种服务;Client端的“地址”即为Binder实体目标的引证,Client将持有该引证向Server端建议服务恳求。下图为Binder机制的C/S模型:
虽然Binder机制的底层代码由C完结,但面向目标思维的引进将进程间通讯转化为经过对某个Binder目标的引证并调用该目标的办法,而其共同之处在于Binder目标是一个能够跨进程引证的目标,它的实体坐落一个进程中,而它的引证却遍及于体系的各个进程之中。
Binder通讯结构
依据Binder机制的进程间通讯,其通讯结构首要触及四个人物,即Server进程、Client进程、ServerManager进程以及Binder驱动,其间,Server、Client和ServerManager运转在用户空间,Binder驱动运转在内核空间。Binder驱动是Binder通讯结构的中心,它作业于内核空间,首要担任进程间Binder通讯的树立、Binder在进程之间的传递、Binder引证计数办理以及数据包在进程之间的传递和交互等一系列底层支撑;Server进程用于向Client进程供给长途服务,该进程会创立一个Binder实体(目标),并为其取一个字符串办法的姓名,当该Binder实体被Binder驱动在ServerManger进行实名注册后,咱们又称这个Binder实体为“实名Binder”,它将担负起向Client供给具体的长途服务;Client进程即为咱们的APP,它将经过长途Binder实体的引证拜访长途Server,获取相关的服务,这儿为什么不是直接经过Binder实体拜访,咱们在后面的Binder机制原理再胪陈;ServerManager是一个体系进程,它办理着一张“查询表”,该表记录了Server进程中Binder实体姓名到Client中对该Binder实体引证的对应联系,以便使Client能够经过Binder姓名取得对Server中Binder实体的引证。Binder通讯结构结构图如下:
在Binder机制通讯模型中,Server、Client、ServerManager以及Binder驱动的联系有点类似于互联网,它们别离对应于互联网中的服务器、客户端、域名服务器(DNS)以及路由器,其间,服务器用于向客户端供给服务且对外接入点为IP地址;客户端用于向服务器建议恳求服务,且建议"地址"一般为域名;域名服务器供给长途服务器的IP地址与其域名映射联系,便于客户端能够经过域名直接拜访服务器;路由器用于网络办理、数据处理等,是互联网络的纽带。Binder通讯结构流程图如下:
大致进程为:
首要,体系中某个进程向Binder驱动建议恳求为ServerManager进程,该进程将树立一张体系中相关Server进程“姓名”及其“地址”的映射表(查询表);
其次,Server进程将自己“姓名”和“地址”增加到ServerManager进程的查询表中;
终究,Client进程从ServerManager进程获取到长途Server进程的实在“地址”,即树立Binder通讯结束。
Binder机制原理
前面谈论到大部分传统的IPC都是依据存储-转发的办法完结的,即进程A经过体系调用copy_from_user将数据从用户空间复制到内核空间,然后再经过体系调用copy_to_user将数据复制从内核空间复制到进程B,整个通讯进程数据需求复制2次。可是Binder机制却不是这么做的,而是把一切的作业均交给Binder驱动来完结,而且Binder本质上仅仅一种底层通讯办法和具体服务没有联系。为了供给具体服务(或称才能),Server有必要供给一套接口函数以便Client经过长途拜访运用各种服务,这儿运用署理(Proxy)方式来完结,即**将接口函数界说在一个笼统类中,Server和Client均以该笼统类为基类完结一切的接口函数,其间Server端是真实的功用完结并为每个函数进行逐个编号以便Client精准调用,而Client端则是对这些函数长途调用恳求的包装。此外,Server端还界说了一个Binder笼统类来处理来自Client的Binder恳求数据包,其间最重要的成员函数是虚函数onTransact(),该函数将用于剖析收到的数据包,调用相应的接口函数处理恳求,并将终究的调用成果回来给Client。整个通讯进程都是在Binder驱动的操控下完结的,而且Binder在Server中的实体是经过选用承继办法以接口类和Binder笼统类为基类构建的。**接下来,咱们凭借Binder学习指南一文中的一张图来具体剖析下Binder机制通讯进程,了解Binder驱动、ServerManager(SM)在整个通讯进程中所起的效果。
为了深化了解依据Binder机制的进程间通讯原理,这儿假定Server进程中有个Object目标(即Binder实体),它供给一个add办法供长途调用,Client进程将经过Binder机制的办法拜访Server进程中Object目标的add办法,具体的通讯进程如下:
Server在SM中注册实名Binder
在Server进程中有一个Object目标(即Binder实体,下述均以Binder实体描绘),它供给一个add办法,为了Client能够找到自己并与之通讯,Server进程为Binder实体创立了一个字符办法的姓名,然后再将Binder实体及其姓名以数据包的办法经过Binder驱动发送给ServerManager进行注册,其注册进程为:
首要,Binder驱动接纳到Server发过来的数据包后,会取出数据包中的Binder实体及其姓名,并为该Binder实体创立坐落内核中的实体节点,并生成与其姓名对应的引证;
然后,Binder驱动将Binder的姓名和新建的引证打包传递给ServerManager,ServerManager收到数据包后从中取出姓名和引证填入一张查找表中,这张表就像一个“通讯录”且是体系仅有的,它记录了体系中各种Server的姓名(Binder实体字符办法姓名)和地址(Binder实体的引证),而被注册的这个Binder实体也称为实名Binder。
Client从SM取得实名Binder的引证
Client进程要想拜访Server进程的Binder实体的add办法,会即将拜访Binder实体的姓名以数据包的办法发送给Binder驱动,Binder驱动取出姓名查询ServerManager中的查询表即可取得Binder实体及其引证。可是Binder驱动并没有将真实的Binder实体回来给Client,而是“照着”Binder实体的姿态仿制一个如出一辙的目标作为署理回来给Client,这个目标又被称之为署理目标ProxyBinder,它持有Binder实体的引证,且具有与Binder实体彻底相同才能(即办法),仅仅这些才能仅仅个“空壳”,真实的具体完结仍是在Server进程的Binder实体中。因为驱动回来的署理目标(ProxyBinder)与Server进程中的Binder实体如此类似,给人的感觉好像是直接把Server进程Binder实体(目标)传递到了Client进程,因而,咱们能够说Binder目标是能够跨进程传递的目标,而实践上Binder目标并没有传递,传递的仅仅是Binder目标的引证,它将经过署理目标来承载。也便是说,Server进程中Binder目标指Binder实体(也称Binder本地目标),Client进程中Binder目标指的是Binder署理目标。在Binder目标进行跨进程传递的时分,Binder驱动会主动完结这两种类型的转化。
需求留意的是,Binder驱动回来一个Binder实体的署理目标给Client是依据Client与Server归归于不同进程而言的,假如Client和Server归归于同一个进程,Binder驱动将直接将Server进程的Binder实体回来给Client。因为本文首要是考虑Client与Server归归于不同进程状况,因而待Client取得署理目标ProxyBinder的那一刻,依据Binder机制的Client与Server长途通讯链路树立结束。
Client与Server跨进程通讯
在Binder驱动回来一个Binder的署理目标给Client进程后,Client进程就能够经过该署理目标与长途Server进程进行通讯。Binder署理目标承继了Server供给的公共接口类并完结公共函数(注:并不是真实的完结,真实的完结在Server进程的Binder实体中),是对长途函数调用的包装。接下来,咱们剖析下Client拜访Server中办法通讯进程:(1) Client进程首要会将函数参数和Binder实体的引证以数据包的办法进行打包,然后将数据包发送给Binder驱意向指定Server发送恳求,尔后Client进程进入挂起状况,以等候回来值;(2) Binder驱动收到Client进程发送过来的数据包后,取出Binder实体的引证,取得意图Server并将其唤醒,再将数据包发送给它处理。这儿需求提下的是,因为该引证原本便是Binder驱动创立并交给ServerManager注册用的,因而Binder驱动天然很简单就能够经过该引证找到能够接纳数据包的Server和取得指向Binder实体对应的内存空间;(3) Server进程收到Binder驱动发送过来的Binder恳求数据包后,Server进程会运用之前拓荒好线程池中的线程来处理该恳求,经过调用Binder实体中的onTransact()函数,对收到的数据包进行剖析,即取出数据包中恳求的函数接口编码,case-by-case地解析code值,待解析成功后,再从数据包中取出函数参数并调用相应的接口函数处理恳求,然后Server进程会将调用成果发送给Binder驱动;(4) Binder驱动收到Server进程回来的调用成果后,就会唤醒处于等候中的Client进程,并将成果回来给它,至此,一次跨进程通讯结束。
Java层Binder结构解析
在Android体系中,Binder结构由C/C++底层和Java上层构成,其间C/C++底层供给功用完结,Java上层为运用进程间的通讯供给接口。因为C/C++层底层完结极端杂乱,本文暂不触及这部分内容,本节将具体剖析Java层部分。依据Binder机制原理,Binder结构Java层部分首要包括四部分,即公共接口(IIterface)、Binder接口(IBinder)、Binder实体(或称Binder本地目标)以及Binder署理目标(BinderProxy),它们各自的效果如下:
IIterface
IIterface是Android供给的一个接口,它标明长途Server目标具有什么样的才能,可了解为Server和Client契约,Binder本地目标和Binder署理目标均需完结该接口。Interface接口中只包括一个asBinder办法,该办法用于回来与该IInterface绑定的Binder本地目标。IIterface源码如下:
IBinder
代表了一种跨进程传输的才能,完结该接口就能将这个目标进行跨进程传递,IBinder担任数据传递。在跨进程数据流经驱动的时分,驱动会辨认IBinder类型的数据,然后主动完结不同进程Binder本地目标以及Binder署理目标的转化。
Binder
Binder实体目标,坐落Server进程中,它承继了IBinder,然后具有跨进程传输的才能,但在实践通讯进程中,Binder实体目标并没有传输,传输的仅仅该目标的引证。
Binder署理目标
长途进程Binder目标的署理,坐落Client进程中,它持有IBinder引证,也能够了解具有跨进程传输的才能。
AIDL作业原理
AIDL(Android Interface Definition Language),即Android接口界说言语,是Android体系为了便于开发具有跨进程通讯的运用,专门供给的且用于主动生成Java层Binder通讯结构的技能。AIDL的运用比较简略,咱们只需求编写契合AIDL开发标准的源码文件,AS就会主动生成用于跨进程通讯的相关文件。这儿以Server端向Client供给"加法核算"服务(才能)为例,具体剖析Java层Binder通讯结构原理。
首要,咱们在工程中创立一个以".aidl"为后缀的源文件,文件命名为IComputeInterface,并供给一个add办法;
其次,"Build->make project"工程后AS就会主动在"app/build/generated/…/com/jiangdg/hellobuilder"目录生成一个名为IComputeInterface.java接口文件。代码结构大致如下:
从IComputeInterface.java源码咱们能够大致看出,它首要包括三部分,即接口IComputeInterface,静态笼统类Stub、静态类Proxy,并由此构成Java层的Binder通讯结构。接下来,咱们就来剖析它们之间有何相关以及起到的效果是什么?
(1) IComputeInterface:公共接口
IComputeInterface承继于接口IInterface,它包括一个add办法且抛出RemoteException反常,由此可知add办法应该是一个被长途拜访的办法。依据Binder机制原理,咱们天然简单理解IComputeInterface接口便是一个“契约”接口,它标明Server端能够像Client端供给哪些服务,也是Binder机制中的署理拜访的完结根底,Server中的Binder实体和Client中的Binder实体的署理均需求完结它,其间,在Binder实体中为add办法真实的完结,在Binder实体的署理目标中仅仅对add办法的长途调用恳求包装,在接下来的剖析中能够验证这一点。
(2) IComputeInterface.Stub:Binder本地目标
从 IComputeInterface的源码可知,Stub是IComputeInterface的一个静态笼统内部类,可是这不是要害的,也仅是AIDL中的生成代码的一种办法罢了,真实重要的是Stub承继了Binder类和IComputeInterface接口,而Binder又承继于IBinder。依据Binder机制原理,咱们就能够得出Stub便是坐落Server端中的Binder实体或称Binder本地目标,它的源码如下:
接下来,咱们侧重剖析下Stub类的作业原理,这儿从asInterface办法下手,该办法首要的效果是判别Binder驱动传递过来的Binder目标obj类型,来决议是否想需求回来Binder目标的署理目标Proxy,即调用obj的queryLocalInterface办法判别传入的DEscriptOR(接口描绘)是否与obj绑定的共同,假如共同,则标明Client与Server归归于同一个进程,直接将Binder本地目标回来给Client;假如不共同,则标明Client与Server不归于同一个进程,就需求将obj作为参数实例化一个Binder本地目标的署理Proxy给Client。onTransact办法用于剖析处理Binder驱动发来的恳求数据包,假如Client与Server归于同一个进程,当Client要拜访Server中的add办法时,onTransact就会被直接调用,不再阅历署理调用进程。
(3) IComputeInterface.Stub.Proxy
Proxy是Stub的一个静态内部类,相同也不是要害的,仅是AIDL中的生成代码的一种办法罢了,真实重要的是Proxy承继了IComputeInterface接口,并持有一个IBinder目标的引证。依据Binder机制原理,咱们就能够得出Proxy便是坐落Client端中的Binder本地目标的署理。从Proxy的源码可知,它不只持有长途Binder实体的引证,还重写了公共办法add,该办法将Client要拜访长途办法的参数封装在Parcel目标中,然后调用长途Binder实体的transact办法建议跨进程调用。经过检查Android源码可知,transact办法的完结坐落native层,它终究调用talkwithDriver函数将恳求参数打包交给Binder驱动,Binder驱动辨认后,终究会调用长途Server中Binder实体的onTransact办法,即Stub的onTransact办法进行处理。需求留意的是,在实践开发中,Stub中onTransact办法所调用的add办法将由咱们自己完结,待add履行结束会将成果填入Parcel中以便Binder驱动回来给Client。Proxy源码如下:
至此,关于对Binder机制的剖析将告一段落,终究,咱们选用Android Binder规划与完结中的一段原话为Binder机制造个总结:Binder含糊了进程鸿沟,淡化了进程间通讯进程,整个体系似乎运转于同一个面向目标的程序之中,五花八门的Binder目标及其漫山遍野的引证似乎粘接各个运用程序的胶水,这也是Binder在英文的本意。
版权声明:本文为 CSDN 博主「无名之辈FTER」的原创文章。