Binder是什么
Binder是安卓中的一种跨进程通信的机制。我们知道安卓系统提供了各种各样的系统服务,如AMS,PMS等,系统服务是运行在SystemServer进程中的。
当我们想要用到这些服务时,就会用到一个API。
getSystemService(String name)
我们来看一个AMS的调用例子感受一下
ActivityManager manager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
List runningTaskInfos = manager.getRunningTasks(1);
public List getRunningTasks(int maxNum)
throws SecurityException {
try {
return ActivityManagerNative.getDefault().getTasks(maxNum, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
public List getTasks(int maxNum, int flags) throws RemoteException;
分析一下这个过程
首先,我们在应用进程调用getSystemService方法,拿到了一个ActivityManager类的对象,并调用了该类的getRunningTasks方法,在这个方法内部又调用了getTasks方法,而这个方法的具体实现是由ActivityMangerService(处于系统服务进程)完成的,该方法执行完毕后,会返回一个信息给调用者,这个调用者显然处于应用进程。在这个过程中,就是通过Binder机制完成了两个不同进程之间的通信。
Binder进程通讯过程
在阐述这个过程之前,我先来说明一下为什么需要进程通讯
进程隔离
进程隔离是为保护操作系统中进程互不干扰而设计的一组不同硬件和软件的技术。这个技术是为了避免进程A写入进程B的情况发生。 进程的隔离实现,使用了虚拟地址空间。进程A的虚拟地址和进程B的虚拟地址不同,这样就防止进程A将数据信息写入进程B。
以上来自维基百科;操作系统的不同进程之间,数据不共享;对于每个进程来说,它都天真地以为自己独享了整个系统,完全不知道其他进程的存在;因此一个进程需要与另外一个进程通信,需要某种系统机制才能完成。
先来看一幅图
简单分析一下这幅图
Binder机制的通讯过程中有四个角色分别是Client端,Server端,Binder驱动,ServiceManger。
Client端:add方法的调用者
Server端:add方法的真正实现者
Binder驱动:负责向Server端传递Cilent端的参数,并且向Cilent端返回Server端执行的结果
ServiceManger:一张记录Server端能力的表
我们来贯穿一下这个过程
首先,Client端发起add调用,Binder驱动在SM表中查找哪个Server具有add的能力,找到之后,会将Client端的参数传递给该Server,然后,Server端收到参数并执行自己的add方法,执行完毕之后将结果告诉Binder驱动,最后Binder驱动在将这个结果返回给Client端。这样就完成了一次跨进程的通信
本文只是介绍Binder通信的大致过程,由于知识水平有限,里面的细节请浏览以下网址
Binder学习指南
AIDL过程分析
简单分析一下aidl的过程
1.在aidl目录创建一个aidl的接口,这时系统会帮我们生成一个同名的java类。
2.在Service端编写如下代码,并实现具体方法
PlayServiceAIDL.Stub iBinder = new PlayServiceAIDL.Stub() {
@Override
public void play() throws RemoteException {
PlayService.this.play();
}
@Override
public void playNext() throws RemoteException {
PlayService.this.playNext();
}
@Override
public void playPre() throws RemoteException {
PlayService.this.playPre();
}
@Override
public void pause() throws RemoteException {
PlayService.this.pause();
}
@Override
public void seekTo(int progress) throws RemoteException {
PlayService.this.seekTo(progress);
}
@Override
public void destroy() throws RemoteException {
PlayService.this.destroy();
}
};
我们来看一下Stub类的部分代码
public static abstract class Stub extends android.os.Binder implements com.sf.sofarmusic.PlayServiceAIDL {
private static final java.lang.String DESCRIPTOR = "com.sf.sofarmusic.PlayServiceAIDL";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.sf.sofarmusic.PlayServiceAIDL interface,
* generating a proxy if needed.
*/
public static com.sf.sofarmusic.PlayServiceAIDL asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.sf.sofarmusic.PlayServiceAIDL))) {
return ((com.sf.sofarmusic.PlayServiceAIDL) iin);
}
return new com.sf.sofarmusic.PlayServiceAIDL.Stub.Proxy(obj);
}
在构造方法中,有一个方法
this.attachInterface(this, DESCRIPTOR);
这个方法就相当于Server端在SM表中注册了自己
-
在客户端会绑定这个服务,代码如下
private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { iBinder = PlayServiceAIDL.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { iBinder = null; } };
注意这句代码
iBinder = PlayServiceAIDL.Stub.asInterface(service);
在看看Stub里面该方法的具体实现
public static com.sf.sofarmusic.PlayServiceAIDL asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.sf.sofarmusic.PlayServiceAIDL))) {
return ((com.sf.sofarmusic.PlayServiceAIDL) iin);
}
return new com.sf.sofarmusic.PlayServiceAIDL.Stub.Proxy(obj);
}
通过queryLocalInterface方法在SM表中找到了刚才注册过的Server端,然后判断一下本地有木有这个Binder对象,有就返回本地的Binder对象,否则返回远程进程的Binder对象的代理。
通过上述步骤,客户端就和服务端建立了一个关系,之后客户端就可以调用服务端的方法了。