Android笔记五(Binder例子)

写之前,我们要明确一点:服务端存在Binder实体BBinder,客户端只有对应的Binder代理BpBinder。在java层中,Binder实体被Stub继承,而Binder代理为Stub.Proxy。

举个栗子:
假设要执行这样的场景:应用A作为客户端,要调用服务端B中的f方法。下面进行具体分析
对于服务端B,我们需要有Binder实体这样才能进行IPC通信,AIDL文件可以帮我们生成一个接口文件(.java),里面有我们需要的Binder实体,也就是Stub
Android笔记五(Binder例子)_第1张图片

Stub中还有该Binder实体的代理Proxy,后面会用到
Android笔记五(Binder例子)_第2张图片
然后我们写个自己的Service,叫做MyService,在onBind()中返回Binder实体Stub,该实体中实现了方法f,该方法在服务端B中
对于客户端A,我们要做的事情是希望可以调用到服务端B中f方法。由于客户端不能获取到Binder实体,我们只能从Binder代理Proxy入手。事实上,客户端A通过下面这个参数获得Proxy
Android笔记五(Binder例子)_第3张图片
其中Myaidl.Stub.asInterface(service)就是去获取BinderProxy
Android笔记五(Binder例子)_第4张图片

Proxy中重写了f方法,假设我们的f方法为getSum,,如下图
Android笔记五(Binder例子)_第5张图片
在客户端,我们能执行的只有上面的内容,先不用管_data和_reply怎么得到的,我们把重点方法mRemote.transact()方法上,这个方法实际上就是跨进程操作,前面我们已经提到,Proxy中重要的两部分

  • mRemote。IBinder数据类型,也就是我们C++层说的BpBinder。
  • 实现Binder实体中的方法。在方法中进行mRemote.transact()操作

也就是说,我们的客户端是通过mRemote.transact()方法来与服务端进行数据交互的。我们的客户端执行mRemote.transact()操作,其实C++层调用的就是BpBinder中的transact()方法,该方法会执行到IPCThreadState中的transact方法中,将我们的输入数据打包到mOut包中
这里写图片描述
而且在里面会和Binder驱动打交道,这是最重要的,我们终于可以访问到除客户端A之外的内存了,因为Binder驱动对所有应用都是可见的。具体的跨进程事务操作是在talkwithDriver()中完成的,如下图
这里写图片描述
talkwithDriver完成之后,完成了数据的交互,但还没有确认我们的BBinder实体,接下来,我们再去执行excuteCommand()方法,这个里面我们会执行cookie.transact(),总算是从客户端A的transact过度到了服务端B的tractsact()。在BBinder的tractsact中,我们会执行onTransact()方法。这样,整个逻辑就清晰了。
未完,待续。这只是对Binder为什么能够从一个进程跨到另一个进程进行读写操作进行的一次简单描述。

AMS为例来说明

我们知道,Android中所有的系统服务都需要注册到ServiceManager中,然后通过获取后才能使用,整个过程分为三次Binder跨进程通信。

  1. 注册服务:首先AMS注册到ServiceManager。该过程:AMS所在进程(system_server)是客户端,ServiceManager是服务端。
  2. 获取服务:Client进程使用AMS前,须先向ServiceManager中获取AMS的代理类AMP。该过程:AMP所在进程(app process)是客户端,ServiceManager是服务端。
  3. 使用服务: app进程根据得到的代理类AMP,便可以直接与AMS所在进程交互。该过程:AMP所在进程(app process)是客户端,AMS所在进程(system_server)是服务端。

PS:ServiceManager在init.rc中启动,不属于java进程。system_server在zygote(第一个java进程)之后启动。

你可能感兴趣的:(Android笔记五(Binder例子))