Android Binder是个很复杂的机制,底层是Binder Driver注册了一个模拟硬件为/dev/binder,通过内存复制的方式实现了进程间数据共享,并在这套机制上提供了ServiceManager等实现。
本文不去解读C++的那些实现,而是从Java层分析理解Binder的主要类结构,目的是使读者理解Binder涉及到的类的作用。
本文首先从AIDL涉及到的类讲起,然后参照AIDL来说明ServiceManager的结构,会发现两者是很类似的。
想实现进程通信,我们需要先定义一个aidl文件,比如ITimerServer.aidl,目的是返回服务端时间:
package cn.techtick.abp.aidl;
interface ITimeServer {
long getTime();
}
系统会帮助我们生成一个复杂的Java类,首先是ITimeServer自身,这个很容易理解:.
public interface ITimeServer extends android.os.IInterface {
public long getTime() throws android.os.RemoteException;
}
它继承了IInterface ,这个接口里只有一个asBinder方法,先忽略。
另外生成了IInterface.Stub
public static abstract class Stub extends android.os.Binder implements cn.techtick.abp.aidl.ITimeServer {
}
这个Stub继承自Binder,并实现了我们的业务接口ITimeServer
Stub一方面实现了我们的业务接口,但它是个抽象类,它没有实现getTime方法;另一方面它继承自Binder,从而具备了进程间通信的能力。
Binder中调用了系统的封装,实现了跨进程通信,详细内容可以先不看。主要关注transact和onTransact方法,可以理解为模版设计模式。transact是骨架,onTransact是算法具体实现。这两个是传输数据用的,先知道这个就够了。
我们需要实现ITimeServer业务接口,比如叫MyServer,那么让它继承ITimeServer.Stub就行。
到这里就能实现同一个进程内的通信了,使用bindService可以获得MyServer对象。
但是如果是跨进程的话,MyServer对象在另一个进程无法直接访问,这时就需要使用Proxy类。
它同样实现了我们的业务接口,其实是一个比较标准的代理设计模式,属于远程代理。
Proxy不是抽象类了,它实现了getTime方法,里面会调用到IBinder.transact,再进一步调用到MyServer.getTime。
那么Proxy具体是在哪里使用的呢?我们在客户端bindService时,使用ServiceConnection收到如下回调:
public void onServiceConnected(ComponentName name, IBinder service) {
mTimeServer = ITimeServer.Stub.asInterface(service);
}
这里使用了Stub的asInterface方法,里面会判断,如果是跨进程通信,会使用Stub.Proxy。
整体类图如下:
下一篇分析ServiceManager的代码结构。