你真的了解 Binder 吗

在前一篇博客ActivityManagerService,我针对ActivityManagerService(AMS)的源码进行了分析,并且主要针对ActivityManagerService和ActivityManager之间的远程通信的原理进行了描述。在Android系统中,每个应用程序都是由一些Activity和Service构成的,他们有可能运行在同一进程中或者不同进程中。那么他们之间是如何解决通信问题的呢,这也是这篇博客将要进行分析的–Binder。由于我的分析方向只是针对于应用层的Java代码,不涉及底层的C/C++代码,因此我的目的也只是带领大家了解Binder在Android系统中的重要性以及工作原理。

Binder是Android系统提供的一种进程间通信机制,它提供远程过程调用功能(RPC)。而这个机制形成,是通过一些系统组件构成的,分别是Client、Server、ServiceManager和Binder Driver。Binder Driver是Binder驱动程序,运行在Linux内核空间;Client,Server和Service Manager运行在用户空间。

《你真的了解 Binder 吗》

Binder进程间通信机制

Binder的C/S模型原理

既然关于Binder机制的组成知道了,那么就有必要了解一下这块的原理了。

1. Framework层

在Framework层,ServiceManager提供了对于系统中大大小小的Manager类的服务管理,比如ActivityManager,WindowManager等。这些Manager相应的服务通过与ServiceManager远程通信将他们注册在ServiceManager里。

《你真的了解 Binder 吗》

Binder的C/S模型图

当Client发出向Server的请求时,ServerManager会通过Client发出的请求命令判断由哪个ManagerService进行处理,ServiceManager会将相应的Service取出,Client获取到Service的引用,通过这个引用即可向远程Server发送请求数据,Server处理完成之后会给Client一个返回响应。这样就完成了一个C/S的请求/响应的过程。

《你真的了解 Binder 吗》

Client从ServiceManager获得Service的远程接口

2. Android应用层

在Android应用层,用户会自行编写自己的业务Service类,如果要实现远程通信的话需要继承Binder。如此操作,Client在调用了bindService()之后,Server会返回一个包含自己业务逻辑的IBinder对象给Client。Client通过这个对象即可获取Server中的数据,达成与Server之间的通信。

其实,不管是Framework层还是Android应用层,实现通信的原理正是依靠Binder建立Client和Server之间的联系,然后通过Binder驱动完成Client和Server之间的数据交互。

Binder的工作机制

接下来聊聊Binder的工作机制。

《你真的了解 Binder 吗》

Binder工作机制

通过上图,我们可以看出binder的工作流程是这样实现的:(1)Client发送请求给Server,在Server未返回结果前,Client处于阻塞状态。请求的数据和相应操作交给Client的Proxy处理。(2)Proxy代理将数据封装后,交给Binder驱动程序进行数据的传输调度。(transact())(3)Binder驱动程序将数据发送个Server,Server对数据进行解析,并根据相应的操作标识进行相应的操作处理。(4)Server操作完成之后,将执行之后结果数据封装。然后将数据交给Binder驱动程序调度。(onTransact())(5)Binder驱动程序将结果数据交给Client的Proxy代理,Proxy代理将数据解析后将最终结果返回给Client。

(6)Client接收到数据之后,结束阻塞状态。

Client和Server之间如何实现数据共享

在了解了关于Binder的模型和工作机制之后,接下来讨论一下关于数据共享的问题。由于进程之间是不能直接进行数据共享的,那么Client和Server之间的通信是怎么做到的呢?

《你真的了解 Binder 吗》

关于C/S模型中的数据共享问题

1. 共享的数据

通过上图我们可以看出:(1)数据的发送和接收是通过Binder驱动程序调度完成的。(2)Binder驱动处理完发送方请求操作之后,会把数据写入到缓存区。该缓存区域对于接收方来说是“读缓冲区”(binder_write_read.write_buffer)(3)接收方会读取缓存区中的数据,在未读取到数据之前,接收方一直处于阻塞状态。

(4)接收方在接收到数据之后,会把返回结果用binder_transaction_data结构体封装,写入缓冲区。

总结:数据的共享是发送方和接收方通过互相获取对方缓冲区里的数据完成的。这样做的优点是通过建立公共的缓存区,发送方和接收方均可操作这块内存空间的数据,不需要再申请其他内存。

2. Binder实体和引用问题

我们可以思考一个问题,在Binder的工作机制中,我们是依赖binder驱动程序去执行数据的调度,发送方依赖binder打包数据,接收方依赖binder回传数据。那么双方使用的binder真正意义上是什么?带着这个问题,我们可以看看下面的图。

《你真的了解 Binder 吗》

Server向ServiceManager注册服务

注册流程是这样的:(1)Server在自己的进程中向Binder驱动程序申请创建一个作为自己Service的Binder实体。(2)Binder驱动程序为这个Service创建位于内核中binder实体节点和binder引用,然后将Service的名称和binder的引用传给ServiceManager,通知ServiceManager注册相应的Service服务。

(3)ServiceManager接收到数据之后,根据Service的名称和binder引用填写入一张表中。

《你真的了解 Binder 吗》

Client从SericeManager获取Service的远程接口

如果这时Client向Server发送申请该Service服务请求时,ServiceManager就会通过该服务的名称,查找表获取相应服务的binder引用,返回给Client。

总结:作为数据发送方,它持有Binder的实体;作为数据接收方,它持有Binder的引用。

小结

在本次博客,重点针对Binder的工作机制以及Binder如何实现数据共享进行了详细描述。由于binder这部分知识体系过于庞大,因此还未涉及到C/C++的底层代码,因此这也是我本人在未来学习道路上要攻克的难题。对于不了解这部分知识的同学,建议通过阅读我的第一篇Framework文章《Framework源码分析(一):ActivityManagerService》来帮助你理解本篇文章。

    原文作者:Android源码分析
    原文地址: https://juejin.im/entry/58257bd28ac247004f3a5129
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞