这篇文章,是建立在大家对binder已经有了一定认识的基数上,因此对于一些具体概念不再衍述!

对于binder,主要可以分为实名binder和匿名binder,那么何为实名,何为匿名?

1.实名binder

其实实名binder大家应该都很熟悉,每当我们需要和一个系统服务交互的时候其实就会利用实名binder和系统服务建立IPC通信。
比如我们需要获取windowmanager的服务,我们可以直接通过下面代码获取:

  1. WindowManager wm = context.getSystemService(WINDOW_SERVICE);

其实这里我们通过代码获取的就是WMS的实名binder的proxy代理,那么这个代理又是如何返回给我们的?

image.png
我们先抛开这个不谈,我们先来整理下关于Binder使用到的元素:
IBinder
Binder implements IBinder
Stub extends android.os.Binder
Proxy implements SelfInterface
IInterface
SelfInterface extends android.os.IInterface
现在,我们先不考虑Binder驱动中的工作和Binder的注册,单从上面的元素调用来分析C/S的IPC通信:
image.png

Client端

无论是何种通信,首先都要约定通信的内容,因此我们先定义一个接口来约定通信内容:

  1. public interface SelfInterface{
  2. void callback(Object obj);
  3. }

这里我们约定了一个带参数的回调方法callback(Object obj)来和Server端进行通信。
约定了通信内容之后,我们需要一个载体来进行通信操作,就好比你寄快递,把要寄的东西打包好之后,需要填写一个快递单,并先把包裹存放在快递的寄件代理处,等快递小哥来接收,在这里,大家可以把BinderProxy看作是寄件代理处,而把IBinder看作是快递小哥:

image.png
image.png

大家不要急,待我一步步给大家分析:

1.收揽快递(Proxy -> IBinder):

我们进行进程间通信之前,首先需要一个IBinder的代理,它可以告诉Binder驱动把邮件寄给哪个Server端,并告诉Server端需要做些什么,Proxy就好比是存放在代理寄件处的包裹,上面标注了需要取件的快递小哥(mRemotes), 以及里面装载了邮寄的物件(实现的SelfInterface接口),当我们调用了Proxy的复写的SelfInterface中的方法后,就会通知快递小哥把包裹送往邮局(Binder Driver)。

  1. private static class Proxy implements SelfInterface {
  2. private android.os.IBinder mRemote;
  3. Proxy(android.os.IBinder remote) {
  4. mRemote = remote;
  5. }
  6. @Override
  7. public android.os.IBinder asBinder() {
  8. return mRemote;
  9. }
  10. public java.lang.String getInterfaceDescriptor() {
  11. return DESCRIPTOR;
  12. }
  13. @Override
  14. public void callback(Object obj) throws android.os.RemoteException {
  15. android.os.Parcel _data = android.os.Parcel.obtain();
  16. android.os.Parcel _reply = android.os.Parcel.obtain();
  17. int[] _result;
  18. try {
  19. _data.writeInterfaceToken(DESCRIPTOR);
  20. mRemote.transact(Stub.TRANSACTION_loginTFCard, _data, _reply, 0);
  21. _reply.readException();
  22. _result = _reply.createIntArray();
  23. } finally {
  24. _reply.recycle();
  25. _data.recycle();
  26. }
  27. return _result;
  28. }
  29. }

Proxy中,我们通过构造函数会传入远端注册的IBinder mRemotes,我们可以通过Stub.asInterface()去获取对应IBinder的代理,我们当然也可以在代理中通过asBinder()来获取这个IBinder。
我们重点来分析以下在Proxy中复写的来自于SelfInterface接口定义的方法。

  1. @Override
  2. public void callback(Object obj) throws android.os.RemoteException {
  3. android.os.Parcel _data = android.os.Parcel.obtain();
  4. android.os.Parcel _reply = android.os.Parcel.obtain();
  5. int[] _result;
  6. try {
  7. _data.writeInterfaceToken(DESCRIPTOR);
  8. mRemote.transact(Stub.TRANSACTION_loginTFCard, _data, _reply, 0);
  9. _reply.readException();
  10. _result = _reply.createIntArray();
  11. } finally {
  12. _reply.recycle();
  13. _data.recycle();
  14. }
  15. return _result;
  16. }

这里首先会对我们的数据进行序列化,这一块涉及到数据的传输,我们不过多叙述,主要关注mRemote.transact(Stub.TRANSACTION_loginTFCard, _data, _reply, 0),在这里调用了IBinder中的transact(args..)方法来把通信内容交由Binder驱动处理,在这个过程中会阻塞下一步的执行,只有等Binder.onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)方法相应并且处理了客户端传来的通信内容并成功写入到reply后,才会继续执行下面的代码来获取服务端处理的结果:

  1. _reply.readException();
  2. _result = _reply.createIntArray();

由此可见,Proxy在整个Binder IPC通信过程中相当于客户端寄存中心(代理中心),它会负责实现客户端想要实现的方法,并且利用通过Stub.asInterface(android.os.IBinder obj)中缓存的IBinder来和服务端进行Binder通信,代码中注释描述了asInterface的功能:

  1. public static jifuliya.lyl.retrofitproxy.IEcmServiceBinder asInterface(android.os.IBinder obj) {
  2. if ((obj == null)) {
  3. return null;
  4. }
  5. //查询IBinder是否是本地进程所注册,即IBinder是否属于自己
  6. android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
  7. if (((iin != null) && (iin instanceof jifuliya.lyl.retrofitproxy.IEcmServiceBinder))) {
  8. //如果属于自己则直接返回,属于进程内部通信
  9. return ((jifuliya.lyl.retrofitproxy.IEcmServiceBinder) iin);
  10. }
  11. //如果不属于自己则生成对应的代理,将远程IBinder缓存到Proxy代理中
  12. return new jifuliya.lyl.retrofitproxy.IEcmServiceBinder.Stub.Proxy(obj);
  13. }

2&3:在邮局中的那些事

通过底层BpBinder和BbBinder的通信来完成底层的数据传递,这个后面我们单独提取出来细细道来。
image.png

4:把包裹送到目的地

远端Server会持有一个Stub,它继承了Binder,我们可以通过复写onTransact()来和Binder驱动定义响应协议,Binder驱动将协议通知给BbBinder,在响应客户端的过程中按照定义的协议进行响应。这就好比我们在接收快递的时候可以选择代收或者亲自接收等,当完成了接收之后,我们会向邮局返回一个已经签收成功的订单回执,来告诉邮局我已经成功接受了包裹,并且可以附带一些信息给寄送快递的人,这个回执就是_reply,相当于Server端对处理结果的反馈。
我们来看看这个Stub到底长什么样子?

  1. public static abstract class Stub extends android.os.Binder implements jifuliya.lyl.retrofitproxy.IEcmServiceBinder {
  2. private static final java.lang.String DESCRIPTOR = "jifuliya.lyl.retrofitproxy.IEcmServiceBinder";
  3. /**
  4. * Construct the stub at attach it to the interface.
  5. */
  6. public Stub() {
  7. this.attachInterface(this, DESCRIPTOR);
  8. }
  9. /**
  10. * Cast an IBinder object into an jifuliya.lyl.retrofitproxy.IEcmServiceBinder interface,
  11. * generating a proxy if needed.
  12. */
  13. public static jifuliya.lyl.retrofitproxy.IEcmServiceBinder asInterface(android.os.IBinder obj) {
  14. if ((obj == null)) {
  15. return null;
  16. }
  17. android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
  18. if (((iin != null) && (iin instanceof jifuliya.lyl.retrofitproxy.IEcmServiceBinder))) {
  19. return ((jifuliya.lyl.retrofitproxy.IEcmServiceBinder) iin);
  20. }
  21. return new jifuliya.lyl.retrofitproxy.IEcmServiceBinder.Stub.Proxy(obj);
  22. }
  23. @Override
  24. public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
  25. java.lang.String descriptor = DESCRIPTOR;
  26. switch (code) {
  27. case INTERFACE_TRANSACTION: {
  28. reply.writeString(descriptor);
  29. return true;
  30. }
  31. case TRANSACTION_callback: {
  32. data.enforceInterface(descriptor);
  33. java.lang.String _arg0;
  34. _arg0 = data.readString();
  35. int[] _result = this.loginTFCard(_arg0);
  36. reply.writeNoException();
  37. reply.writeIntArray(_result);
  38. return true;
  39. }
  40. default: {
  41. return super.onTransact(code, data, reply, flags);
  42. }
  43. }
  44. }
  45. }

这里面的DESCRIPTOR相当于一个身份name,作为身份凭证,asInterface()在#1中我们已经分析过了,主要是为了生成改Binder的一个代理,作为客户端的通信入口,现在我们把重点放在onTransact()上:

  1. @Override
  2. public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
  3. java.lang.String descriptor = DESCRIPTOR;
  4. switch (code) {
  5. case INTERFACE_TRANSACTION: {
  6. reply.writeString(descriptor);
  7. return true;
  8. }
  9. case TRANSACTION_callback: {
  10. data.enforceInterface(descriptor);
  11. java.lang.String _arg0;
  12. _arg0 = data.readString();
  13. //this.loginTFCard(_arg0)为SelfInterface接口中的方法在服务端的具体实现
  14. int[] _result = this.loginTFCard(_arg0);
  15. reply.writeNoException();
  16. reply.writeIntArray(_result);
  17. return true;
  18. }
  19. default: {
  20. return super.onTransact(code, data, reply, flags);
  21. }
  22. }
  23. }

我们所有在客户端中定义的每一个通信内容,都会生成一个类似于TRANSACTION_callback的code,彼此之间不会重复,当我们通过Binder驱动在onTransact()拿到data后,会将data中的参数通过data.readString()读取出来,并将参数传入到自己对应的callback(param)中按照自己约定的逻辑协议处理数据,最后将结果通过reply.writeIntArray(_result)写到序列化的reply中。

5.收件回执reply

我们通过一张图来表述reply在整个Binder通信中的生命周期:
image.png
这里注意一点,transact()中执行到mRemote.transact()后会等待onTransact()成功把result写入reply并回传后才会继续下面的代码指令执行。

当1-5执行完毕后,一次进程间的Binder IPC通信就算完成了,是不是很简单?
image.png

下一章我将带大家在此基础上详细分析实名Binder的注册和通信。