Android IPC之Binder机制分析

原文连接: —Android IPC之Binder机制分析—java

更多精彩请点击:
AIDL实现IPC详解——AIDL实现IPC详解android

1、 Android IPC方式选择

1.1 IPC释意

IPC:Inter-Process Communication,进程间的通讯或跨进程通讯。由于不一样的进程是不能共享内存块的,因此进程之间的通讯须要使用特别的方式。进程中的线程是能够共享内存的,就是多个线程能够操做或者能够同时操做同一个文件,当多个线程同时访问同一个文件时须要作线程同步,防止读到脏数据。Android每个应用都会有一个本身的Dalvik/ART虚拟机 实例,每个应用都有一个或者多个进程,每个进程都有一个或者多个线程!
Android进程之间的通讯有六种方式,每种方式都有本身的优缺点,其中AIDL和Messenger都是基于Binder的。web

1.2 IPC方式对比


这里写图片描述

根据本身项目的实际状况选一种合适的IPC方式,处理好多进程和多线程同步就好!
其中,AIDL基于Binder,Messenger基于AIDL,因此Android中经常使用的ICP方式都是基于Binder。使用AIDL时须要写对应的.aidl文件,在编译代码的时候Android Studio会根据.aidl生成基于Binder通讯的.java文件,.aidl文件只是Google预设了一种操做Binder的java代码生成规则。Messenger是基于AIDL封装的,使用Messenger不须要写.aidl文件。多线程


2、 Binder IPC通讯交互和数据传递

Binder通讯机制是有C/S模式加代理的方式实现的。是基于C/S模式的那么就会存在客户端服务端代理模式就会存在真实对象代理对象!我前面有文章说明:Android IPC之代理模式并发

2.1 Binder框架定义了四个角色:Server,Client,ServiceManager(之后简称SMgr)以及Binder驱动交互过程:


这里写图片描述

四步交互过程描述: 参考:binder学习指南框架

  1. 首先,Server进程要向SM注册;告诉本身是谁,本身有什么能力;在这个场景就是Server告诉SM,它叫zhangsan,它有一个object对象,能够执行add
    操做;因而SM创建了一张表:zhangsan这个名字对应进程Server;svg

  2. 而后Client向SM查询:我须要联系一个名字叫作zhangsan的进程里面的object对象;这时候关键来了:进程之间通讯的数据都会通过运行在内核空间里面的驱动,驱动在数据流过的时候作了一点手脚,它并不会给Client进程返回一个真正的object对象,而是返回一个看起来跟object如出一辙的代理对象objectProxy,这个objectProxy也有一个add方法,可是这个add方法没有Server进程里面object对象的add方法那个能力;objectProxy的add只是一个傀儡,它惟一作的事情就是把参数包装而后交给驱动。(这里咱们简化了SM的流程,见下文)学习

  3. 可是Client进程并不知道驱动返回给它的对象动过手脚,毕竟假装的太像了,如假包换。Client开开心心地拿着objectProxy对象而后调用add方法;咱们说过,这个add什么也不作,直接把参数作一些包装而后直接转发给Binder驱动。ui

  4. 驱动收到这个消息,发现是这个objectProxy;一查表就明白了:我以前用objectProxy替换了object发送给Client了,它真正应该要访问的是object对象的add方法;因而Binder驱动通知Server进程,调用你的object对象的add方法,而后把结果发给我,Sever进程收到这个消息,照作以后将结果返回驱动,驱动而后把结果返回给Client进程;因而整个过程就完成了。.net

因为驱动返回的objectProxy与Server进程里面原始的object是如此类似,给人感受好像是直接把Server进程里面的对象object传递到了Client进程;所以,咱们能够说Binder对象是能够进行跨进程传递的对象

但事实上咱们知道,Binder跨进程传输并非真的把一个对象传输到了另一个进程;传输过程好像是Binder跨进程穿越的时候,它在一个进程留下了一个真身,在另一个进程幻化出一个影子(这个影子能够不少个);Client进程的操做实际上是对于影子的操做,影子利用Binder驱动最终让真身完成操做。因此咱们在写AIDL实现IPC的时候并没感受是在跨进程,因为影子的存在,给咱们的感受好像是在同一进程内直接通讯!

理解这一点很是重要;务必仔细体会。另外,Android系统实现这种机制使用的是代理模式,
对于Binder的访问,若是是在同一个进程(不须要跨进程),那么直接返回原始的Binder实体;若是在不一样进程,那么就给他一个代理对象(影子);咱们在系统源码以及AIDL的生成代码里面能够看到不少这种实现。

Server服务端可能会同时处理多个Client客户端的请求,服务端为了高效率处理服务端的请求,因此在Server服务端会开一个线程池来处理客户端的并发请求。

一句话总结就是:Client进程只不过是持有了Server端的代理;代理对象协助驱动完成了跨进程通讯。

2.2 Server端和Client端数据交换过程


这里写图片描述

2.1中描述客户端和服务端互相是怎么认识和找到的,描述了大概的交互流程。下面介绍数据交换流程!

Binder IPC通讯就是指客户端和服务端互相交互数据,客户端经过SM找到和认识服务端,两者创建联系,而后客户端调用Binder代理对象的方法,并传入参数,并把数据发给Binder驱动,驱动再把数据发送给服务端,这时候服务端知道了客户端调用了本身的方法,服务端执行方法,执行完成后经过Binder把数据发给Binder驱动,Binder驱动再把数据交给客户端。

有了影子和真身的说法,那么AIDL文件其实就是指定了真身和影子长什么样子,具有什么功能。影子在客户端,真身在服务端。客户端操做AIDL制定影子和真身的功能,经过Binder和Binder驱动把操做映射到真身上,让真身完成真正的操做,真身完成操做后,经过Binder和Binder驱动把数据返回给客户端。


3、 Binder究竟是什么?

写AIDL文件生成的java代码中能够看出来,Binder是一个java类,实现了IBinder接口。服务端的Binder对象就是Binder new出来的实例,真身Binder有血有肉有功能,可是客户端的影子Binder只是实现了IBinder接口,并且不论是服务端真身Binder仍是客户端影子Binder,都实现了.aidl文件中的接口,这就能够实现影子Binder执行真身Binder的功能,真身Binder才是真正执行者,这么一描述你们是否能够知道了Binder是什么了,英文翻译Binder就是 粘合剂

Binder存在于客户端、服务端、Binder驱动和SM四个地方,在每一个地方都有本身不一样的职能。固然,只有客户端的Binder才是真正的Binder,客户端的是代理,其余的地方是引用。

  1. 服务端 Binder
    服务端的Binder是一个真实的Binder对象,具有AIDL接口文件中须要的全部功能,同时用与Binder驱动交互的功能,是Binder机制中一个比较核心的位置!

  2. 客户端 Binder
    客户端Binder只是一个代理,实现了AIDL文件接口可是不具有真实的功能,只是告诉你服务端用的真正功能,可是客户端Binder具有去Binder驱动交互的功能。

  3. Binder驱动 中的Binder
    Binder驱动真管理Binder的地方,经过Binder的引用来管理Binder,记录Binder引用->实体之间多对一的关系;为引用找到对应的实体;在某个进程中为实体建立或查找到对应的引用;记录Binder的归属地(位于哪一个进程中);经过管理Binder的强/弱引用建立/销毁Binder实体等等。驱动中的Binder是为了管理生死存亡。

  4. ServiceManager 中的Binder
    ServiceManager跟DNS相似,客户端的binder跟服务端的binder是否定识由ServiceManager判定,做用是将字符形式的Binder名字转化成Client中对该Binder的引用,使得Client可以经过Binder名字得到对Server中Binder实体的引用。注册了名字的Binder叫实名Binder。ServiceManager中会有一张表来存放写关系。ServiceManager中的Binder是为了肯定关系。

4、Client端和Server端线程模型

Server服务端可能会同时处理多个Client客户端的请求,服务端为了高效率处理服务端的请求,因此在Server服务端会开一个线程池来处理客户端的并发请求。

client 调用 server的方法a,client自己是会挂起的, 会一直等待server的方法a的执行结果。同时这个方法a 是运行在binder线程池中,因此server的方法 能够执行耗时操做。只不过 client调用的server方法时,注意不要在ui线程里调用,否则会anr的。同时若是你的业务是 一个server 多种client ,那你的server端 方法 要支持同步,否则会数据错乱的!

在上面的数据交互图也能够看到client在调用Server端方法时会挂起,在Server执行完成返回结果时会唤醒client的线程。

参考文章:

Android Bander设计与实现 - 设计篇
Binder学习指南