最近在拜读任主席的Android开发艺术探索,现在看了一半,再回头看前面的,感觉跟没有看一样,所以还是把知识点总结一下吧,这一节咱们来讲一下IPC中的Binder
直观来说,Binder是Android中的一个实现了IBinder接口的类;从IPC角度来看,Binder是Android中一个跨进程通信的方式;从Android FrameWork角度来说,Binder是ServiceManager连接各种Manager和相应ManagerService的桥梁;从Android应用层来说,Binder是客户端和服务端进行通信的媒介。
Android开发中Binder主要用在Service中,包括AIDL和Messenger,普通的Service中的Binder不涉及进程间通信,所以较为简单,而Messenger的底层其实是AIDL,所以选择AIDL来分析Binder工作机制。
在使用AIDL的时候,Android编译器会根据我们定义的aidl文件,自动生成对应的java文件,这个java类继承了IInterface接口, 根据aidl文件中声明的方法实现了对应的方法,同时声明了几个整形的id分别用于标识我们声明的方法,这个几个id用于标识在transact过程中客户端所请求的到底是哪个方法。声明了一个内部类Stub,其实就是一个Binder类,只有当客户端和服务端不位于同一个进程时,方法调用才会走transact过程,这个逻辑有Stub类的内部代理类Proxy来完成,所以这个类的核心就是Stub类和Stub的内部代理类Proxy,下面来介绍一下这两个类中每个方法的含义:
- DESCRIPTOR:Binder的唯一标识,一般用于当前Binder的类名标识
- asInterface(android.os.IBinder obj):用于将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象,如果客户端和服务端不在同意进程,那么这个方法返回的就是系统封装后的Stub.proxy对象,否则返回服务端的Stub对象本身。
- asBinder:此方法用于返回当前Binder对象
- onTransact:这个方法运行在服务端中的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理。
这个方法的原型是public Boolean onTransact(int code, Parcelable data, Parcelable reply, int flags)
服务端通过code可以知道客户端请求的目标方法,接着从data中取出所需的参数,然后执行目标方法,执行完毕之后,将结果写入到reply中。如果此方法返回false,说明客户端的请求失败,利用这个特性可以做权限验证(即验证是否有权限调用该服务)。 - Proxy#[method]:代理类中的接口方法,这些方法运行在客户端,当客户端远程调用此方法时,它的内部实现是:首先创建该方法所需要的参数,然后把方法的参数信息写入到_data中,接着调用transact方法来发起RPC请求,同时当前线程挂起;然后服务端的onTransact方法会被调用,直到RPC过程返回后,当前线程继续执行,并从_reply中取出RPC过程的返回结果,最后返回_reply中的数据。
- Binder的两个重要方法linkToDeath和unlinkToDeath
Binder运行在服务端,如果服务端进程异常终止,客户端应该得到通知,这个时候我们可以通过这两个方法来得到通知以及做出相应的操作。首先声明一个DeathRecipient对象,这个对象是一个接口,内部只有一个binderDied方法,放Binder死亡的时候,系统会回调BinderDied方法
private IBinder.DeathPecipient mDeath = new IBinder.DeathPecipient(){
@Override
public void binderDied(){
if(mBookManager == null) return;
mBookManager.asBinder().unlinkToDeath(mDeath, 0);
mBookManager = null;
//重新绑定远程Service
}
//客户端代码
mService = IMessageBoxManager.Stub.asInterface(binder);
binder.linkToDeath(mDeath, 0);
这样当Binder死亡的时候我们就可以收到通知了。