Android10.0 Binder通信原理(十一)-Binder总结

摘要:本节主要来讲解Android10.0 Binder的通信原理总结

阅读本文大约需要花费17分钟。

文章首发微信公众号:IngresGe

专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢!

[Android取经之路] 的源码都基于Android-Q(10.0) 进行分析

[Android取经之路] 系列文章:

《系统启动篇》

  1. Android系统架构
  2. Android是怎么启动的
  3. Android 10.0系统启动之init进程
  4. Android10.0系统启动之Zygote进程
  5. Android 10.0 系统启动之SystemServer进程
  6. Android 10.0 系统服务之ActivityMnagerService
  7. Android10.0系统启动之Launcher(桌面)启动流程
  8. Android10.0应用进程创建过程以及Zygote的fork流程
  9. Android 10.0 PackageManagerService(一)工作原理及启动流程
  10. Android 10.0 PackageManagerService(二)权限扫描
  11. Android 10.0 PackageManagerService(三)APK扫描
  12. Android 10.0 PackageManagerService(四)APK安装流程

《日志系统篇》

  1. Android10.0 日志系统分析(一)-logd、logcat 指令说明、分类和属性
  2. Android10.0 日志系统分析(二)-logd、logcat架构分析及日志系统初始化
  3. Android10.0 日志系统分析(三)-logd、logcat读写日志源码分析
  4. Android10.0 日志系统分析(四)-selinux、kernel日志在logd中的实现​

《Binder通信原理》

  1. Android10.0 Binder通信原理(一)Binder、HwBinder、VndBinder概要
  2. Android10.0 Binder通信原理(二)-Binder入门篇
  3. Android10.0 Binder通信原理(三)-ServiceManager篇
  4. Android10.0 Binder通信原理(四)-Native-C\C++实例分析
  5. Android10.0 Binder通信原理(五)-Binder驱动分析
  6. Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击
  7. Android10.0 Binder通信原理(七)-Framework binder示例
  8. Android10.0 Binder通信原理(八)-Framework层分析
  9. Android10.0 Binder通信原理(九)-AIDL Binder示例
  10. Android10.0 Binder通信原理(十)-AIDL原理分析-Proxy-Stub设计模式

1.概述

 Binder的通信原理基本上都已经说完,这一节我们做一个简单的概要总结。

2.Binder通信模型

下图中涉及到Binder模型的4类角色:Binder驱动,ServiceManager,Server和Client。Binder机制的目的是实现IPC(Inter-Process Communication),即Client和Server之间的通信。

其中Server,Client,ServiceManager运行于用户空间,Binder驱动运行于内核空间。这四个角色的关系和互联网类似:Server是服务器,Client是客户终端,ServiceManager是域名服务器(DNS),驱动是路由器。

 

3.Binder的架构

 

4.Binder的通信原理

Binder 通信采用 C/S 架构,从组件视角来说,包含 Client、 Server、 ServiceManager 以及 Binder 驱动,其中 ServiceManager 用于管理系统中的各种服务。

Binder 在 framework 层进行了封装,通过 JNI 技术调用 Native(C/C++)层的 Binder 架构。

Binder 在 Native 层以 ioctl 的方式与 Binder 驱动通讯。

       

Binder通信流程如下

  1. 首先服务端需要向ServiceManager进行服务注册,ServiceManager有一个全局的service列表svcinfo,用来缓存所有服务的handler和name。
  2. 客户端与服务端通信,需要拿到服务端的对象,由于进程隔离,客户端拿到的其实是服务端的代理,也可以理解为引用。客户端通过ServiceManager从svcinfo中查找服务,ServiceManager返回服务的代理。
  3. 拿到服务对象后,我们需要向服务发送请求,实现我们需要的功能。通过 BinderProxy 将我们的请求参数发送给 内核,通过共享内存的方式使用内核方法 copy_from_user() 将我们的参数先拷贝到内核空间,这时我们的客户端进入等待状态。然后 Binder 驱动向服务端的 todo 队列里面插入一条事务,执行完之后把执行结果通过 copy_to_user() 将内核的结果拷贝到用户空间(这里只是执行了拷贝命令,并没有拷贝数据,binder只进行一次拷贝),唤醒等待的客户端并把结果响应回来,这样就完成了一次通讯。

在这里其实会存在一个问题,Client和Server之间通信是称为进程间通信,使用了Binder机制,那么Server和ServiceManager之间通信也叫进程间通信,Client和Server之间还会用到ServiceManager,也就是说Binder进程间通信通过Binder进程间通信来完成,这就好比是 孵出鸡前提却是要找只鸡来孵蛋,这是怎么实现的呢?

Binder的实现比较巧妙:预先创造一只鸡来孵蛋:ServiceManager和其它进程同样采用Binder通信,ServiceManager是Server端,有自己的Binder对象(实体),其它进程都是Client,需要通过这个Binder的引用来实现Binder的注册,查询和获取。

ServiceManager提供的Binder比较特殊,它没有名字也不需要注册,当一个进程使用BINDER_SET_CONTEXT_MGR_EXT命令将自己注册成ServiceManager时Binder驱动会自动为它创建Binder实体(这就是那只预先造好的鸡)。

其次这个Binder的引用在所有Client中都固定为0(handle=0)而无须通过其它手段获得。也就是说,一个Server若要向ServiceManager注册自己Binder就必须通过0这个引用号和ServiceManager的Binder通信。

类比网络通信,0号引用就好比域名服务器的地址,你必须预先手工或动态配置好。要注意这里说的Client是相对ServiceManager而言的,一个应用程序可能是个提供服务的Server,但对ServiceManager来说它仍然是个Client。

图片来源csdn-jeanboydev

5 Binder传输过程

Binder-IPC机制,就是指在进程间传输数据(binder_transaction_data),一次数据的传输,称为事务(binder_transaction)。

对于多个不同进程向同一个进程发送事务时,这个同一个进程或线程的事务需要串行执行,在Binder驱动中为binder_proc和binder_thread都有todo队列。

也就是说对于进程间的通信,就是发送端把binder_transaction节点,插入到目标进程或其子线程的todo队列中,等目标进程或线程不断循环地从todo队列中取出数据并进行相应的操作。

在Binder驱动层,每个接收端进程都有一个todo队列,用于保存发送端进程发送过来的binder请求,这类请求可以由接收端进程的任意一个空闲的binder线程处理。

接收端进程存在一个或多个binder线程,在每个binder线程里都有一个todo队列,也是用于保存发送端进程发送过来的binder请求,这类请求只能由当前binder线程来处理。

binder线程在空闲时进入可中断的休眠状态,当自己的todo队列或所属进程的todo队列有新的请求到来时便会唤醒,如果是由所需进程唤醒的,那么进程会让其中一个线程处理响应的请求,其他线程再次进入休眠状态。

6 Binder协议的演变

下面展示了Binder协议码的演变过程,在Android9.0之前,当client向Binder驱动发送BC_TRANSACTION,Binder驱动唤醒Server进程时,会向client进程发送BR_TRANSACTION_COMPLETE,现在这一步被移到了 唤醒Client之后再做,减少了数据延迟。

Android9.0之前的协议码流程:

Android9.0及之后的协议码流程:

上面第5步的 BR_TRANSACTION_COMPLETE 被延迟到 第 10步 ,Android做了deferred_thread_work,延迟 TRANSACTION_COMPLETE,因此不会立即返回到用户空间;这允许目标进程立即开始处理此事务,从而减少延迟。然后,当目标回复(或出现错误)时,我们将返回TRANSACTION_COMPLETE。

7.AIDL的Proxy-Stub设计模式

AIDL的设计采用了Proxy-Stub(代理-存根) 的设计模式,Client拿到的是Proxy的Binder代理对象,Server拿到的是Stub的Binder服务实体,两者之间的数据传入通过Parcel进行扁平化传输。

Proxy将特殊性接口转换成通用性接口,Stub将通用性接口转换成特殊性接口,二者之间的数据转换通过Parcel(打包)进行的,Proxy常作为数据发送代理,通过Parcel将数据打包发送,Stub常作为数据接收桩,解包并解析Parcel Data package。

 

Client和Server交互的简单示意流程:

Binder通信的数据流转如下图所示:

AIDL的具体流程如下:

  1. Client和Server都使用同一个AIDL文件,包名相同,编译后,两边都会生成IMyService.java,其中有Stub实体和Proxy代理两个对象
  2. Server端通过AndroidManifest.xml 注册Service
  3. Client通过bindService()获得服务的代理Stub.Proxy()
  4. Client 调用AIDL的方法add(),其实调用的是IMyService.java中的Stub.Proxy.add(),最终通过BinderProxy.java的transact()向服务端发送
  5. 通过Binder驱动的流程,进入到服务端的onTransact(),根据Client发送的TRANSACTION code,解析进入相应的流程处理,进入add()
  6. MyService在被绑定时,有了实体IMyService.Stub,最终进入MyService.java的add()处理,完成接口调用,调用完成后把数据写入Parcel,通过reply发送给Client

我的微信公众号:IngresGe

发布了27 篇原创文章 · 获赞 69 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/yiranfeng/article/details/105314445
今日推荐