Android进阶知识(五):IPC基本概念之Binder、Binder工作机制及其原理
Binder是一个很深入的话题——任玉刚老师如是说。就笔者的水平而言,实际上从任玉刚老师的《艺术探索》中读完从AIDL代码中去解析其工作机制,确实可以理解。但是笔者在这不会老套照搬代码,介绍其工作机制时只是必要的些许代码,不会整个代码文件上,有兴趣的读者可以阅读该书,按照书的步骤走即可。
一、Binder
什么是Binder?
从IPC角度来说,Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,其设备驱动是/dev/binder,值得一提的是该通信方式在Linux中是没有的。
从Android Framework角度来讲,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager等等)和相应ManagerService的桥梁。
从Android应用层角度来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通的服务以及基于AIDL的服务。
值得一提的是,Binder在Android开发中主要用在了Service中,包括AIDL和Messenger,而Messenger的底层其实还是AIDL。
二、Binder工作机制
上面提到了Binder的实现方式之一AIDL,这里我们以AIDL来分析一下Binder的工作机制,当然只是涉及部分代码以理解,关于AIDL的使用读者可令行学习。在AS中,创建一个IBookManager.aidl的文件(右键即可),该aidl中书写如下代码(其中需要一个Book.java的bean类以及对应的Book.aidl)。
// Declare any non-default types here with import statements
import com.fatdoge.myapplication.Book;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
AS关于AIDL实现的一个好处是能够自动的为用户实现对应的IBookManager.java以实现跨进程通信。如下为该类的核心代码。
public interface IBookManager extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.fatdoge.myapplication.IBookManager {
public static com.fatdoge.myapplication.IBookManager asInterface(android.os.IBinder obj) {
// 将服务端Binder对象转为客户端所需AIDL接口类型对象
// 客户端服务端同一进程,返回Stub本身;否则封装系统包装后的Stub.proxy对象
}
@Override public android.os.IBinder asBinder() {
// 返回当前Binder对象
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
// 运行在Binder线程池中,服务端根据code确定客户端请求的目标方法
// data中包含目标方法所需的参数
// reply中写入目标方法的返回值
// 该方法返回值为false,则客户端请求会失败
}
private static class Proxy implements com.fatdoge.myapplication.IBookManager {
@Override public java.util.List<com.fatwood.myapplication.Book> getBookList() throws android.os.RemoteException {
// 运行在客户端,参数信息写入_data,
// 调用transact方法发起RPC(远程过程调用),当前线程挂起
// 服务端onTransact方法被调用,直到RPC返回当前线程执行
// 并从_reply中取出RPC过程的返回结果,最后返回其中数据
}
@Override public void addBook(com.fatwood.myapplication.Book book) throws android.os.RemoteException {
}
}
}
}
可以看到其内部类Stub是一个Binder类,当客户端和服务端都位于同一个进程时,方法调用不会走跨进程的transact进程,相反则会,而这个逻辑将由Stub的内部代理类来实现。
以此可以了解到,Binder的工作机制大致过程为:客户端发起请求调用目标方法,该请求会由Proxy中的对应的方法先将参数信息写入_data,调用transact方法发起RPC,同时当前线程挂起;服务端onTransact方法被调用,直到RPC返回当前线程才会继续执行,并从_reply中取出RPC过程的返回结果,最后返回其中数据。
对于Binder的工作机制,需要注意两点:首先,当客户端发起请求时,由于当前线程会被挂起直至服务端进程返回数据,所以对于一个耗时的远程方法,不能在UI线程中发起该远程请求;其次,由于服务端的Binder方法运行在Binder的线程池中,所以Binder方法不管是否耗时都应该采用同步的方式去实现。其工作机制可以用如下图所示。
这里需要提一句,AIDL文件的本质是系统为开发者提供的一种快速实现Binder的工具,因此开发者也完全可以自己实现。
另外,Binder中还有两个重要的方法——linkToDeath以及unlinkToDeath。通过这两个方法可以设置Binder死亡代理,当Binder死亡时可以收到通知,此外通过Binder的方法isBinderAlive也可以判断Binder是否死亡。
三、Binder原理
那么Binder的工作机制了解了,好奇的笔者又在想,其作为媒介到底是如何使得服务端和客户端通信的呢?也就是其原理是如何的呢?
Binder通信采用C/S架构,从组件视角来讲,包含Client、Server、ServiceManager以及Binder驱动,其中ServiceManager用于管理系统中的各种服务。Client和Server以及ServiceManager三者之间的交互并不是直接的,而是通过与Binder驱动进行交互的,从而实现IPC通信方式。架构图如下。
Binder通信中ServiceManager进程的作用是将字符形式的Binder名字转化成Client中对该Binder的引用,使用Client能够通过Binder名字获取对Server中Binder实体的引用。
Binder驱动负责进程之间Binder通信的建立,Binder在进程之间的传递,Binder引用计数管理,数据包在进程之间的传递和交互等一系列底层支持。
为了更为具体的了解Binder原理的工作过程,以下为使用服务的具体执行过程。
参考资料:《Android开发艺术探索》
简单理解Binder机制的原理