Binder是Android中的一种跨进程通信方式,Android的四大组件、各种Manager 和其对应ManagerService等无不与Binder挂钩。从Android Framework角度来说,Binder是ServiceManager连接ActivityManager、WindowManager等Manager和他们相应ManagerService的桥梁; 从Android 应用层来说,Binder是客户端和服务端进行通信的媒介,正如我们在使用Service时bindService时, Service的onBind方法会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取Service中提供的服务或数据,这里的服务包括普通服务和基于AIDL的服务。
Binder单词翻译过来叫“粘合剂”,它的机制是将Client、Server、ServiceManager和Binder驱动粘合起来。其中Client、Server和Service Manager运行在用户空间,Binder驱动运行在内核空间。Service Manager和Binder驱动已经在Android平台中实现好,我们在开发过程中只要按照规范实现自己的Client和Server组件就可以了。
了解内核空间 和 用户空间
Linux内核独立于普通的应用程序,它可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。内核和上层的应用程序抽像隔离开,分别称之为内核空间和用户空间。
ServiceManager
ServiceManager是整个Binder IPC通信过程中的守护进程,本身也是一个Binder服务,它的主要就两个工作就是查询和注册Service。
Binder驱动 内核模块
linux进程间通信有很多种比如信号量、通道、socket等,但是android是用的binder。用户空间可以通过系统提供的方法调用访问内核空间,而一个用户空间想与另外一个用户空间进行通信的话,就得使用Linux的动态可加载内核模块机制(Loadable Kernel Module,LKM),因为Android系统可以通过添加一个内核模块运行在内核空间,用户进程之间通过这个模块作为桥梁,就可以完成通信了,而这个负责各个用户进程通过Binder通信的内核模块程序叫做Binder驱动。
通信过程
我们通过例子来讲述Binder的通信过程,当你想给你的朋友打电话时,那么你就是Client,而你的朋友就是Server,而电话公司就是ServiceManager,它系统里注册了很多人的电话号码。当你在拔打你朋友电话时,若你朋友电话号码是没有在电话公司注册过,就会返回空号的错误,也就是Server没有在ServiceManager中注册,否则就能拔打电话,在这个拔过电话过程中,是要通过基站来完成接线的,而基站就是Binder驱动。
划重点 AIDL原理
AIDL是Binder的延伸,我们知道,当新建一个aidl文件后执行编译后,便会在app\build\generated\source\aidl\debug\目录下生成对应的同名的类文件。我们在日常开发中,大可不必理会此文件,也正因为此文件是自动生成和格式错乱使很多人对其望而止步。其实只要将该Java文件格式化后,就会清晰多了,这个类的结构其实很简单的。只要读懂该类,基本上就会明白AIDL的工作原理了。
首先创建一个IMyAidl.aidl文件,内容如下:
interface IMyAidl {
int sum(int a, int b);
}
在执行编译后,就会在app\build\generated\source\aidl\debug目录下生成IMyAidl.java文件。在介绍IMyAidl.java文件前,先来创建 Client端和Server端的调用代码。
Client端的MainActivity.Java代码:
public class MainActivity extends Activity {
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
IMyAidl myaidl = IMyAidl.Stub.asInterface(iBinder);
try {
myaidl.sum(1, 2);
} catch (Exception e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName className) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, MyService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
Server端的MyService.Java代码:
public class MyService extends Service {
private Binder mBinder = new IMyAidl.Stub() {
@Override
publicint sum(int a, int b) throws RemoteException {
return a + b;
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
IMyAidl.java内容部分是这样:
public interface IMyAidl extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements com.***.IMyAidl {
……
}
public void sum(int a, int b) throws android.os.RemoteException;
}
IMyAidl.java文件中,存在一个继承自己的内部类Stub和我们在aidl中定义的sum方法。Stub就是一个Binder类。可以看出,它就是MyService中onBind方法return的mBinder对象的类。再来细看下Stub类的代码:
public static abstract class Stub extends android.os.Binder implements com***.IMyAidl {
private static final java.lang.String DESCRIPTOR = "com.***.IMyAidl";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static ***.IMyAidl asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof ***.IMyAidl))) {
return ((com.***.IMyAidl) iin);
}
return new com.***.IMyAidl.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 {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_sum: {
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.sum(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com***.IMyAidl {
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 int sum(int a, int b) 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(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_sum, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_sum = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
下面我们来看看Stub类的变量和方法的含义:
DESCRIPTOR
DESCRIPTOR是Binder的唯一标识,一般用当前Binder的类名表示
asInterface
asInterface方法用于将Server端的Binder对象转换成Client端所需的AIDL接口类型的对象,正如我们可以看到asInterface方法就是我们在Client端中代码:
IMyAidl myaidl = IMyAidl.Stub.asInterface(iBinder);
try {
myaidl.sum(1, 2);
} catch (Exception e) {
e.printStackTrace();
}
asInterface方法它的参数是接收由服务绑定成功后返回的一个IBinder对象,返回值一个AIDL接口类型的对象,从代码中可以发现,该对象有三种情况返回值,第一种因为参数输入错误所以返回了null; 接着判断了Client端和Server端是否位于同一进程,如果是同一进程,则是第二情况,返回就是Server端中的Stub对象本身,也就是本示例中就是MyService中的mBinder对象; 如果Client端和Server端不是同一进程,那么就是第三种情况,返回的是Stub类的内部代理类Proxy对象。而Client端中代码:myaidl.sum(1, 2);调用的就是Proxy类的sum方法。
Proxy
Proxy类是内部类Stub的内部代理类,同样也是继承于IMyAidl.java。它的sum方法会使用Parcelable来准备数据,把参数都写入_data,让_reply接收方法返回值。最后使用IBinder的transact方法把数据传给Binder的Server端去。代码中mRemote就是asInterface方法接收的参数obj。这时当前线程挂起,Server端的onTransact方法会被调用。
onTransact
onTransact方法是运行在Server中的Binder线程池中的,当Client端发起跨进程请求时,远程请求会通过系统底层封装后交由onTransact方法来处理。通过TRANSACTION_sum找到对应的方法sum,接着从data中取出从Client端进程传递过来的参数,然后执行目标方法sum,在执行完毕后就向reply中写入返回值。此时,Proxy中的sum方法线程恢复执行。