Binder 复习笔记
原文链接 http://www.rogerblog.cn/2017/01/03/Binder/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。
关于 Binder 的一些知识点
Binder 作为 Android 底层最重要的 IPC 的方式,其重要性不言而喻,而它所覆盖的知识点又非常的复杂繁琐。记录一下关于 Binder 的一些知识点和要点,以便将来复习方便。
Binder 的作用是什么?
在 Android 启动的时候,Zygote 进程孵化出第一个子进程叫 SystemServer,很多的系统服务都是运行在这个进程的线程中,而我们的各个应用都运行在自己独立的进程中,当应用需要与系统服务进行交互的时候,就需要用到进程间通信,Binder 就是在 Android 中实现的进程通信方式。
Binder 机制是如何实现的?
Binder 主要由四个主要部分构成: Client , Service , ServiceManager , Binder驱动程序。
顾名思义,Client 就是客户端,发起访问的一方,Serivce 就是服务端,被调用的一方, ServiceManager 类似于一个电话簿,维护了一份所有 Service 的列表,而 Binder 驱动程序则是整个 Binder 机制的核心,它是一段运行在内核空间的代码,通过 "/dev/binder" 这个文件在内核空间和用户空间来回搬数据,实现进程间的通信。
在 Android Framewrok 中 Binder 的架构如下图所示(图片来自于Link):
客户端需要调用远程服务的时候,会初始化一个连接,并 block 住自己,等待服务端返回。在服务端,通过线程池的方式来响应请求。如上图所示,Client 通过 Proxy 来完成与 Binder Driver 进行的交互。Process B 是系统服务进程,在这个进程里面维护着多个 binder Thread,直到达到设置的线程上限。客户端主要和 Proxy 交互,服务端主要和 Stub 交互, Proxy 和 Stub 可以理解为一个相同的接口,定义了客户端和服务端相互调用的相同的接口。
从 Framework 角度出发 Binder 的机制大概就是如此,如果要深入到 Native 层的话可以参考 gityuan 的博客,比较深入的说明了 Binder 内核的机制Link
AIDL 原理解析
利用 AIDL 实现 IPC ,原理还是利用 Framework Binder 的架构。写好的 AIDL 文件会被自动编译成一个 java 文件。例如我们写了一个如下的 AIDL 文件:
package com.roger.aidl; interface mInterface{ void invokTest(); }
编译后在 gen 目录会生成一个 java 类:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: F:\\Romworkspace\\APP SDK\\testworkspace\\AidlDemo_client\\src\\com\\roger\\aidl\\mInterface.aidl
*/
package com.roger.aidl;
public interface mInterface extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.roger.aidl.mInterface {
private static final java.lang.String DESCRIPTOR = "com.roger.aidl.mInterface";
/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.roger.aidl.mInterface interface,
* generating a proxy if needed.
*/
public static com.roger.aidl.mInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.roger.aidl.mInterface))) {
return ((com.roger.aidl.mInterface) iin);
}
return new com.roger.aidl.mInterface.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_invokTest: {
data.enforceInterface(DESCRIPTOR);
this.invokTest();
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.roger.aidl.mInterface {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public void invokTest() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_invokTest, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_invokTest = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void invokTest() throws android.os.RemoteException;
}
这个 AIDL 文件客户端和服务端都会有相同的一份,为的是在通信的时候会有相同的接口回调。而明显客户端和服务端都只用到其中对应的部分。对于 Client 来说,使用到的是 Proxy 这个类。
看到 Activity 中的代码:
public void onServiceConnected(ComponentName className, IBinder service) {
Log("connect service");
mService = mInterface.Stub.asInterface(service);
}
在绑定服务成功后,我们首先调用到 asInterface 这个方法将一个 IBinder 类型的 service 传进来,由于 this.attachInterface(this, DESCRIPTOR) 是构造 Stub() 调用的,所以只是在 service 端能调用到, client 调用 queryLocalInterface() 会返回 null ,从而在 client 端使用的是 Proxy ,我们看到 Proxy 类:
private static class Proxy implements com.roger.aidl.mInterface {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public void invokTest() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_invokTest, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
通过获取到的 IBinder,就是我们绑定服务成功后回调获得的 IBinder,生成了一个 Proxy 类,当 Client 调用 invokTest() 方法时,通过 IBinder 的 transact() 方法将数据传输给服务端,并把线程锁住。此时,通过 Binder 驱动的层层调用,会来到 Stub 类的 onTransact 方法:
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_invokTest: {
data.enforceInterface(DESCRIPTOR);
this.invokTest();
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
看到调用到了 this.invokTest(); ,其实就是我们在写服务端的时候调用的方法:
private final mInterface.Stub mBinder = new mInterface.Stub() {
public void invokTest() throws RemoteException {
// TODO Auto-generated method stub
Log.e(TAG, "remote call from client! current thread id = "
+ Thread.currentThread().getId());
}
};
这样来看,一步步调用到服务端的方法实现,完成 IPC 调用。