请尊重原创,转载请注明出处【tianyl】的博客
前言
说到Android,有一个绕不过去的知识点就是IPC,也叫进程间通信,鉴于市面上已经很多Binder的深入解析,这里我也不说重复的话了,感觉从AIDl的角度聊聊BInder(因为我看好像很少有博客从这个角度切入)
本文概要
1 什么是Binder
2 什么Android要使用Binder作为IPC的方式?Linux现有的IPC方式不能用吗
3 什么是AIDL,AIDL和BInder又是什么关系
4 AIDL的基础用法
5 什么是Stub和Proxy,它们又是如何通信的?
1 什么是Binder
Binder是Android系统进程间通信(IPC)方式之一,说到IPC,就要介绍一些Linux中的IPC方式
2 Linux的IPC方式
- 管道(Pipe)
- 一个线性的内存区域,存消息时将数据写入管道,取消息时从管道拷贝数据,因为有两次拷贝(效率低)
- 插口(Socket)
- 是一个通用接口,导致其传输效率低,开销大,有两次拷贝(效率低)
- 报文队列(Message)
- 有两次拷贝(效率低)
- 共享内存(Share Memory)
- 机制复杂,管理内存机制复杂
- 信号量(Semaphore)
- 信号(Signal)
- 跟踪(Trace)
3 Binder
3.1 Binder的优点
- 安全性
- Linux的IPC机制在本身的实现中,并没有安全措施,得依赖上层协议来进行安全控制。而Binder机制的UID/PID是由Binder机制本身在内核空间添加身份标识,安全性高
- 私有管道
- Binder可以建立私有通道,这是linux的通信机制所无法实现的(Linux访问的接入点是开放的)
- 效率性
- LInux原有的IPC方式,要么是需要多次拷贝(2次或2次以上),要么则是机制复杂,而BInder只需要一次拷贝,在多线程时管理内存也相对容易
所以从效率上和安全性上考虑,Google摒弃了LInux的IPC方式,重新构建了一套属于Android的IPC方式——BInder
4 Binder和AIDL
AIDL全称:Android Interface Definition Language,Binder是IPC的机制,AIDL是Binder的具体规范
5 AIDL详解
关于AIDL,它是Android Interface Definition Language,对于一个.aild文件,它经过IDE的处理后,会生成一个java文件
这个java类会实现android.os.IInterface接口,并且含有一个Stub的静态抽象内部类
public interface IAIDLTest extends android.os.IInterface
5.1 Stub
仔细查看抽象类Stub,它继承了android.os.Binder,并实现了我们定义的AIDL接口
public static abstract class Stub extends android.os.Binder implements com.demo.tianyl.demo.IAIDLTest
5.2 Proxy
Proxy是抽象类Stub中的一个静态内部类,它也实现了我们定义的AIDL接口
private static class Proxy implements com.demo.tianyl.demo.IAIDLTest
5.3 Stub和Proxy
介绍完了Stub和Proxy的类的定义,下面来说说AIDL使用时它们之间的关系
1
首先要从我们定义的AIDL说起了,如果我们要使用AIDL,那么我们首先需要定义一个AIDL接口文件(IAidlTest.aidl),根据这个.aidl文件自动生成一个.java文件,并且构建一个Service实现我们定义的AIDL接口(AidlTestService.java),并且在manifest中注册这个服务
2
在其他的进程,需要使用AIDL的地方,调用bindService开启这个服务,然后在ServiceConnection中处理返回的IBinder对象
//开启服务
bindService(service, mConnection, Context.BIND_AUTO_CREATE);
//处理IBinder对象
IAIDLTest mService = null
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IAIDLTest.Stub.asInterface(service)
}
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null
}
};
3
说完了用法,下面来解析
首先在bindService中,获得我们在AidlTestService.java(aidl实现类)中的onBind方法中返回的IBinder
实现类一般写法如下
public class AidlTestService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
IAIDLTest.Stub mBinder = new IAIDLTest.Stub() {
//do something
};
}
4
然后在ServiceConnection中,处理上面返回的IBinder
mService = IAIDLTest.Stub.asInterface(service)
看内部类Stub中的方法asInterface
public static com.demo.tianyl.demo.IAIDLTest asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.demo.tianyl.demo.IAIDLTest))) {
return ((com.demo.tianyl.demo.IAIDLTest) iin);
}
return new com.demo.tianyl.demo.IAIDLTest.Stub.Proxy(obj);
}
asInterface方法会根据当前的进程还决定返回Stub或者Proxy
- 如果当前进程和AIDL定义的进程相同,就返回Stub的实现类(AidlTestService.java)
- 如果当前进程和AIDL定义的进程不同,就返回Proxy
所以我们可以猜到,AidlTestService.java是Stub的真实实现类,Proxy是Stub在其他进程的代理实现类
5.4 Stub和Proxy的通信
说完了Stub和Proxy的关系,再说说它们是如何通信的
既然Proxy是Stub在其他进程的实现类,那么其他进程在调用AIDL接口中的方法时,肯定是通过Proxy进行的,例如一个求和方法add
1
Proxy中的方法如下
@Override
public int add(int x, int y) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(x);
_data.writeInt(y);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
这个方法主要做了2件事
- 序列化参数x和y
- 调用mRemote.transact方法
其中Stub.TRANSACTION_add是定义的一个标准常量,用于确定调用的是哪个方法
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
2
从mRemote的transact,会回调到Stub的onTransact,在这个方法中,会有
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_add: {
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
在TRANSACTION_add分支中,会将参数反序列化,然后调用this.add(_arg0, _arg1),就是它的实现类,然后将结果回传回去
6 总结
关于AIDL和Binder的相关描述,到此就结束了,因为考虑到已经有不少源码分析的博客,所以这里就较少的涉及源码方面,想必开篇的问题,大家心中已经有答案了吧