美文网首页LinuxLinux学习之路
Android系列-Binder机制

Android系列-Binder机制

作者: QuietHeart | 来源:发表于2020-05-06 13:24 被阅读0次

Binder 通信架构简介

Binder 采用 C/S 架构,是 Android 提供的一种通信机制,通过 ServiceManager 集中管理系统中的有名服务。

使用服务的大致过程:

  1. Server 端首先向 ServiceManager 注册服务以便 Client 可以使用(此时 ServerClient 端, ServiceManager 是服务端)
  2. ClientServiceManager 请求它要使用的服务(此时 ClientClient 端, ServiceManager 是服务端)。
  3. Client 根据得到的 Service 信息,和 Server 进行通信(此时 ClientClient 端, Server 是服务端)。

以上三步均通过 Binder 通信机制实现,只是封装的层次可能有所不同,理解其中任意即可知道其它。

如图:

binder_arch.png

通信过程

这里先以 MediaServerServiceManager 注册 MediaPlayerService 服务为例,进行其流程的大致描述,每步后面都会对其中一些难以理解的地方进一步说明。

注: MediaPlayerService 只是 MediaServerserviceManager 注册的众多服务之一。

serviceManager 启动

注册服务前首先要启动好 serviceManager 服务程序,该程序是掌管服务的服总控管理服务程序,比较特殊,它的启动没有使用 Android 的封装机制而是直接和 binder 交互。

大致过程就是:

  1. 设置自己的 handle ,该 handle 为宏值 BINDER_SERVICE_MANAGER ,用来标示 serviceManager 服务程序,也就是其它程序请求服务时的目的端。
  2. 打开 binder 设备映射 binder 所需缓存
  3. 通过 binderioctl 命令设置自身为 serviceManager ,整个系统中只有一个 serviceManager
  4. 进入消息循环,根据 handle 判断消息目标,如果是自身的 handle ,则处理接收到的消息。

注:其它服务程序的启动一般使用 android 的封装机制,后面讲述服务启动的时候会讲述利用 android 封装机制如何启动一个普通的服务。

MediaServerserviceManager 注册 MediaPlayerService 服务

1、业务层实现

打包数据,即将标示“注册服务”的 AddService 关键字打包,至此业务层内容完毕,余下的交由通信层处理。

注: Android 将通信和处理过程通过其封装机制,划分为“业务层”和“通信层”两个部分(这点至关重要!)。

  • “业务层”专注对业务流程的处理,依据不同的应用功能而不同;
  • “通信层”专注对消息通信的处理,采用 Binder 机制实现,这也意味着也可用其它的通信机制实现此部分的功能例如“socket”、“管道”等。

2、通信层实现层次1- BpBinder 代理类的处理

通信层可借助 BpBinder 这个工具类来实现,通过 BpBinderTransact 函数最终传递数据给 ServerManager 处理。 BpBinder 通过“人手一份”的 IPCThreadState ,以线程局部变量的方式,将 BpBinder 自身、 BBinder 对应的 handler 与数据等信息交由其 transact 函数处理。

注: BpBinderBBinder 都是 Android 中与 binder 通信的代表,它们都继承自 IBinder 类。 BpBinder 是客户端和服务端交互的代理类, pproxy 的意思; BBinder 则是与 BpBinder 相对的一端,是 proxy 的目的端。两者一个是客户端,一个是服务端,并且一一对应,和 BpBinder 对应的 BBbinder 用一个 Bpbinderhandler 成员( mHandler )来索引到。

3、通信层实现层次2- 和驱动的交互

IPCThreadState 对象包含:

  • mIn ,包含用于接收数据的缓存和操作。
  • mOut ,包含用于发送数据的缓存和操作。
  • mProcess ,包含 binder 通信所需的具体文件描述符内存

IPCThreadStatetransact 函数首先将数据发送至其 mOut 成员中,然后通过 talkWithDriver 函数与 binder 驱动交互(即发送请求到 binder 设备并接收回复到 mIn 中)后,从 mIn 中取出相应的回复信息,并调用 executeCommand 函数进行进一步的处理。

注: talkWithDriver 中,通过 ioctl 的方式与驱动交互。这里使用 BINDER_WRITE_READ 命令将 mOut 的数据发送给 driver ,然后接收消息到 mIn 中。(这里,我们需要注意,一般在处理不同命令的分支中,发送给设备驱动的分支命令码是 BC_XXX ,设备回复的命令码是 BR_XXX

4、通信层实现层次3- BBinder 的处理

executeCommand 函数中,借助回复得到的 BBinder 这个工具类对象,调用其 transact 函数进行处理(若 server 死掉,则由 BpBinder 处理)。

注:此时客户端接收回复,相当于服务器的“服务端”,这个 BBinder 也是客户端做为服务服务端的代表,具体这个 BBinder 的处理情况,可参考后面服务端的处理过程。

5、通信层实现层次4- 服务端的工作

客户端程序发送信息后,服务端在接收消息循环中接收到消息并开始处理。这里因为是向 ServerManager 发送注册服务请求,而 ServerManager 这个服务程序比较特殊,没有使用 BBinderBnXXX 之类的封装工具接口,它是直接使用操作 binder 提供的相关接口完成这个过程的。

至此,我们分两种方式讲解此处内容:

5.1、在 ServerManager 中实际的处理

直接在其循环中调用 binderioctl 接口接收到消息,然后再进行相关处理,再通过 binderioctl 接口回复消息给请求方。

5.2、正常 Server 程序的处理

一般 Server 都至少有一个线程处于接收消息的循环中,假设其中一个线程接收到客户端发送来的消息,最终会调用到 executeCommand 函数进一步处理。
处理过程如前所述:

  1. 从接收到的消息中,取得代表自己的 BBinder 对象,
  2. 进入 BBinder::transact 函数,
  3. 再调用 onTransact 处理通信的内容,
  4. onTransact 中调用业务函数处理业务逻辑的内容。

注:这里调用的 BBinder::onTransact ,其实指向的是其子类对象的函数,即 BnXXX ;而其中调用的业务函数,也是其子类对象自己实现的函数,即 XXXService 。具体是什么子类,依据服务有所不同,以刚刚注册的 MediaPlayerService 为例,其它类似,涉及的相关类如下图:

mediaplayerservice.png

我们实现 MediaPlayerService 的业务功能(如 createMediaRecorder )时,就实现 MediaPlayerService 子类的函数。处理通信信息时(如根据不同类型的信息,调用不同的业务函数),实现 BnMediaPlayerService 子类的函数。

服务端启动

前面讲述的服务注册过程只是服务程序启动的一个阶段,这个阶段服务程序做为 serviceManager 的客户端,向 serviceManager 程序请求注册服务。当注册完服务后,服务程序本身便可做为服务端,进入自己的消息循环,接收客户端的请求,和 serviceManager 不同的是, serviceManager 启动时直接与 binder 交互,而一般服务端通过 android 封装的机制来启动。

这里还是以 MediaServer 的启动为例,介绍启动的大致过程:

1、获得 ProcessState 单实例对象

每个进程启动时,都通过单实例方式创建一个唯一的 ProcessState ,它主要打开 binder 设备文件,以及通过 mmap 映射好通信所需的内存地址,相关信息在其成员中保存。后面使用 binder 通信时,最终会用到这里的内容。

2、获得 IServiceManager 单实例对象以便和 serviceManager 进程交互

这里通过 defaultServiceManager 函数,以单实例方式进行。

  1. 首先创建 BpBinder 对象,该对象由 serviceManager 对应的 handle 初始化,完成通信层功能;
  2. 然后通过该 BpBinder ,转换生成 IServiceManager 对象(其实是子类 BpServerManager 对象),完成业务层功能;
  3. BpBinder 对象做为 IServiceManager 对象的成员存在,以这种方式将业务层和通信层相关联。

交互实现的关键

  1. 通信层、业务层、通信业务关联

    • 通信层相关内容

      根据前面, serviceManagerhandleBINDER_SERVICE_MANAGER ,一般就是0,这个为系统所周知。借助该 handle 做为成员构成的 BpBinder 代理对象,来向 serviceManager 发送消息协助完成通信层的功能。服务端会通过接受到消息中的 handle 比对,判断出是否为发送给自己的消息。

    • 业务层相关内容

      生成的 BpBinder 对象,会最终通过 interface_cast ,转换成 IServiceManager 对象,完成 serviceManager 应用程序对应的业务功能(如: getServiceaddService 等)。

    • 通信层和业务层的关联

      是利用 BpBinder 创建 BpServiceManager 对象,使用 BpBinder 是通过 BpServiceManager 对象的 mRemote 成员来做到的。

    期间所涉及的类关系如下:

iservice_manager.png
  1. 实现通信层、业务层类的关系

    对于前面的类图,我们还是从“业务层”和“通信层”两个方面来看。

    • 业务层

      BpServiceManagerBnServiceManager 都继承自 IServiceManager ,通过 IServiceManager 完成业务逻辑功能,通过其子类实现业务逻辑,其中 BnServiceManager 的功能需要又由子类 MyServiceManager 来实现。

    • 通信层

      通过 IBinder 完成通信相关逻辑,具体实现由其子类: BpBinder 完成客户代理功能, BBinder 完成服务端功能。而实现又是借助于封装的 BpServiceManagerBnServiceManager 完成的。 BnServiceManager 继承自 BBinder ;而 BpServiceManager 通过父类 BpInterface 的父类 BpRefBasemRemote 成员,与 BpBinder 对象关联。

    1. 总结

      结合前面描述“正常 server 程序的处理”中的“ MediaPlayerService 家谱”图,我们可大致理清 Android 封装机制对“业务层”和“通信层”的封装机制。而两者间的关联,正是 BnServerXXXBpServiceXXX 即能涉及业务相关的内容,也能涉及通信相关内容的原因。

bp_bn_layer.png
    服务端启动后,与客户端的交互过程,与服务程序本身做为客户端向 `serviceManager` 注册服务的过程类似,参见后面讲述“客户端和服务端交互”时的内容。这里着重讲述 `Android` 系统中,大部分服务程序是如何利用 `Android` 的封装机制实现启动,以便后续的客户端能向注册服务一般向该服务程序请求服务的。

3、向 serviceManager 注册各类服务

前面注册的 MediaPlayerService ,只是 MediaServer 的众服务之一,它使用 MediaPlayerService::instantiate 函数,调用通过 defaultServiceManager 函数返回的 IServiceManageraddService 业务接口实现。

注册期间 MediaServer 做为 serviceManager 的客户端,向 serviceManager 程序请求注册服务;其它服务的注册类似,其详细过程参考前面讲述的 “ MediaServerserviceManager 注册 MediaPlayerService 服务” 相关内容。

4、服务端进入自己的消息循环

通过 StartThreadPoolJoinThreadPool 实现。

启动的这些线程,进入消息循环统一为前面各类服务工作。如果任务不繁重,可以不用 StartThreadPool ,使用主线程即可。

客户端和服务端交互

这里,以客户端与MediaPlayerService服务的交互为例

1、客户端向 ServiceManager 查询 MediaPlayerService 服务

  1. 首先客户端通过 defaultServiceManage 函数获取到代表 serviceManageIServiceManager 接口;
  2. 然后通过 IServerManagergetService 业务接口,获取到 MediaPlayerServiceBpBinder
  3. 最后将获取的 BpBinder 通过 interface_cast 转换成 IMediaPlayerService 接口,做为获取的结果。

2、客户端向服务端发送服务请求

ImediaPlayerService 接口包含了 MediaPlayerService 可提供的各种业务接口函数供客户端使用,大致过程是:

  1. 客户端的业务层( BpMediaPlayerService 相关)打包数据递交给通信层;
  2. 客户端通信层( BpBinder 相关)将数据发送给 Binder 驱动。

这里客户端发送数据时涉及到从业务层到通信层的过程(类似数据打包),之后我们可以看到,通过 Binder 驱动,在服务端接收数据时会经历从通信层到业务层的过程(类似数据解包)。

注:这些业务接口目前还是在客户端被调用,实际调用的是子类 BpMediaPlayerService ,这是一个代理接口,客户端通过继承自 IMediaPlayerServiceBpMediaPlayerService 代理接口来调用各种业务接口请求服务端的服务,在代理接口的业务函数中将封装好的信息借助其通信层的代理 BpBinder 类发送给内核 Binder 设备的驱动,之后的过程在服务端的处理中可以看到。

3、服务端处理收到的客户端请求

这里的内容在前面讲述注册服务过程时的 “正常 Server 程序的处理” 中已经详细讲述,可参考相关内容。

大致过程是:

  1. 服务端的通信层接收到请求( BBinder 相关);
  2. 递交给服务端的业务层处理( BnMediaPlayerService 相关)。

这里,服务端通过调用同样继承自 IMediaPlayerServiceBnMediaplayerService 业务接口,来实现客户端用 BpMediaPlayerService 业务接口中的对应的各种业务接口,客户端调用时采用的是代理接口的业务函数,和服务端服务时对应的真正实现的业务函数,因为来自同一父类,一般都是相同的函数签名。

注:
Binder 驱动通过客户端通过 BpBinder 发送来的 handle 找到在驱动中对应的 Server 端通信层的 BBinder ,将数据传送到服务端的业务层,在服务端有一个和 BpMediaPlayerService 继承自同一个父类的 BnMediaPlayerservice 接口,其中的业务函数才是真正的业务实现,该业务接口的业务函数收到 BBinder 通信端传上来的信息后,调用相应的真正实现了的业务函数进行业务处理。

其他

参考资料:

  • 《深入理解Android 卷I》

相关文章

网友评论

    本文标题:Android系列-Binder机制

    本文链接:https://www.haomeiwen.com/subject/pgddghtx.html