Android开发Android开发经验谈程序员

Android IPC之Binder机制分析

2017-09-14  本文已影响216人  生椰拿铁锤

原文链接: ---Android IPC之Binder机制分析---

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

一、 Android IPC方式选择

1.1 IPC释意

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

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文件。


二、 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;

  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驱动。

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

由于驱动返回的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驱动把数据返回给客户端。


三、 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是为了确定关系。

四、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学习指南

上一篇下一篇

猜你喜欢

热点阅读