概述:
Android系统基于linux内核,一般来说,每个Android应用程序对应一个进程,进程包含了android组件,进程间的数据是私有的。Android提供binder机制实现跨进程通信,通过binder机制,进程之间可以相互访问内部数据,同时,又不破坏进程内部数据的私有性。Binder机制底层实现很复杂,今天我们主要关注应用层面怎么利用binder机制跨进程通信,搞懂binder通信机制,对于理解Framework层很有帮助,毕竟Framework层各种组件的启动都是通过binder机制与ActivityManagerService完成的。
AIDL:
说到AIDL,相信大家都不陌生,AIDL是Android提供的应用内部数据共享方式,通过AIDL,可以实现进程之间通信,今天我们就通过一个简单的AIDL调用过程来说明其工作原理,从而理解Binder机制的工作方式。
定义一个AIDL文件,实现两个数相加
interface IAddServer{
int add(int a, int b);
}
IDE自动帮我们生成了IAddServer.java文件,在服务端定义AddService.java
public class AddService extends Service {
private IAddServer.Stub mBinder = new IAddServer.Stub() {
@Override
public int add(int a, int b) throws RemoteException {
Log.e("AddService", "call Add");
return a + b;
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
将IAddServer.java拷贝到远程客户端,在Activity中通过bindService绑定服务,服务绑定成功后,会回调相关方法,最后完成远程对象初始化
private ServiceConnection mCon = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
if(mServer != null) {
mServer = null;
}
}
@Override
public void onServiceConnected(ComponentName arg0, IBinder binder) {
//绑定服务成功
mServer = IAddServer.Stub.asInterface(binder);
}
};
客户端的详细代码我这里就不贴出了,关于AIDL的使用,网上有很多资料,大家可以查阅。
重点关注IAddServer.Stub.asInterface(binder)方法。先看IAddServer.java类
public interface IAddServer extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.duke.server.aidl.IAddServer
{
private static final java.lang.String DESCRIPTOR = "com.duke.server.aidl.IAddServer";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.duke.server.aidl.IAddServer interface,
* generating a proxy if needed.
*/
public static com.duke.server.aidl.IAddServer asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.duke.server.aidl.IAddServer))) {
return ((com.duke.server.aidl.IAddServer)iin);
}
return new com.duke.server.aidl.IAddServer.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_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;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.duke.server.aidl.IAddServer
{
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 add(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);
Log.e("Client", "before call transact");
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
Log.e("Client", "after call transact");
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public int add(int a, int b) throws android.os.RemoteException;
}
代码量有点多,看起来很混乱,但是结构很清晰。
IAddServer.Stub.asInterface方法传入IBinder对象,这个IBinder对象是调用bindService方法后,远程服务端响应,调用onBinder方法,返回的IAddServer.Stub对象。
从asInterface实现方法中可以看到,返回对象是Stub.Proxy对象,而这个对象,实现了IAddServer接口,所以可以用asInterface的返回值初始化IAddServer对象。再看Proxy的构造函数,在Proxy内部,会将传入的IBinder对象赋值给mRemote对象。在客户端通过IAddServer对象调用add方法,实际上是调用Proxy对象的add方法,再看IAddServer.java中Proxy add方法的实现。
add方法中,首先会获取_data _reply,这两个对象都是声明为Parcel对象,其中data是客户端传送到远程服务的参数,而reply用于接收远程方法调用返回值,从这里可以看到,AIDL使用中,对象必须要实现Parcel接口。data对象接下来写入两个参数a,b。然后调用mRemote.transact方法,该方法有一个参数,用于告诉远程服务,客户端调用了什么方法,还含有data,和reply参数。transact方法调用了,Android系统会通知底层Binder驱动,Binder驱动收到这个调用消息后,唤醒远程服务,并且调用onTransact方法。
onTransact方法中,首先会根据code参数判定调用哪个函数。这里通过this.add调用,this就是一个Stub对象,最后调用的是AddService中IAddServer.Stub的add函数。
我们总结一下binder机制远程通信调用机制过程。
mRemote的transact方法最终会进入JNI层,通知驱动,这里我们就不再分析。
AIDL使用要注意以下三点:
1. Incoming calls are not guaranteed to be executed on the main thread, so you need to think about multithreading from the start and properly build your service to be thread-safe.
2. By default, RPC calls are synchronous. If you know that the service takes more than a few milliseconds to complete a request, you should not call it from the activity's main thread, because it might hang the application (Android might display an "Application is Not Responding" dialog)—you should usually call them from a separate thread in the client.
3. No exceptions that you throw are sent back to the caller.
除了AIDL外,Android系统提供了另外一个API Messenger,实现Binder通信,下面我们来看看。
Messenger:
Messenger 是Android提供的另外一种利用binder机制跨进程通信的API,使用Messenger双方可以相互持有一个远程Messenger对象,利用这个对象,实现跨进程通信,相对于AIDL而言,灵活性更高。我们还是先通过一个例子来说明:
有两个进程client, server, Client进程中,应用代码如下:
private Messenger mClientMessenger;
private Messenger mServerMessenger;
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if(msg.what == RESPONSE_MSG) {
Log.e("MessengerActivity", "远程服务回送消息--->");
}
}
};
private ServiceConnection mCon = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
}
@Override
public void onServiceConnected(ComponentName arg0, IBinder binder) {
mServerMessenger = new Messenger(binder);
}
};
client中定义mHandler,用户处理Server中发过来的消息,和aidl一样,通过bindService方式绑定服务,回调onServiceConnected方法,然后创建mServerMessenger对象。Messenger封装了远程接口对象,我们稍后再分析Messenger构造函数的实现。
mClientMessenger = new Messenger(mHandler);
//client send msg to server
public void sendMsgToServer() throws Exception{
if(mServerMessenger != null) {
Message msg = Message.obtain(null, SAY_HELLO);
msg.replyTo = mClientMessenger;
mServerMessenger.send(msg);
}
}
在onCreate方法中初始化mClientMessenger,然后通过mServerMessenger的send方法,将消息发送到服务端。这里注意msg.replyTo = mClientMessenger。通过msg对象,将mClientMessenger传递到远程服务,这样,Server端就可以利用该Messenger向client发送消息。
Server端
public class MessengerService extends Service {
private final static int SAY_HELLO = 0x1;
private final static int RESPONSE_MSG = 0x2;
private Messenger mServerMessenger;
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if(msg.what == SAY_HELLO) {
Toast.makeText(MessengerService.this, "收到客户端连接请求", Toast.LENGTH_SHORT).show();
Messenger clientMessenger = msg.replyTo;
try {
Message msgToClient = Message.obtain(null, RESPONSE_MSG);
clientMessenger.send(msgToClient);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
};
@Override
public void onCreate() {
super.onCreate();
mServerMessenger = new Messenger(mHandler);
}
@Override
public IBinder onBind(Intent intent) {
return mServerMessenger.getBinder();
}
}
定义一个Service,client通过bindService绑定服务,会回调onBind方法,将IBinder对象返回到客户端。上面代码中,client端通过sendMsgToServer,服务端收到这个消息后,会通过Handler处理,取出mClientMessenger对象,然后往client发送消息,client也是通过Handler处理server发过来的消息。
上面的例子展示了Messenger的使用过程,相当的简单,但是相对于AIDL,灵活性更高。下面我们从源码角度来分析,Messenger是怎样通过binder机制实现跨进程通信的。
首先看Server端
mServerMessenger = new Messenger(mHandler);
Messenger有两个构造函数,一种传入Handler,一种传入IBinder。
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
我们看一下Handler的getIMessenger()
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
Handler通过调用getIMessenger方法,返回一个MessengerImpl对象,而MessengerImpl对象又继承自IMessenger.Stub类,从上面AIDL分析中我们可以知道,IMessenger.Stub继承自Binder类,实现了IMessenger接口。所以这里mTarget其实就是IMessenger对象。我们再看一下MessengerImp类的实现。
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
Handler.this.sendMessage(msg);
}
}
里面有send方法,最终是通过Handler发送消息到消息队列,最后由Handler处理。到了这里,我们知道,Messenger其实只是封装了IMessenger.Stub对象,客户端发送请求到Server,会导致IMessenger.Stub的send方法调用。我们再看Client端,验证刚才的结论。
client端通过mServerMessenger = new Messenger(IBinder)对象构造一个远程的Messenger
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
其内部也是通过asInterface的方式,传入远程的IBinder接口,初始化mTarget对象,刚才提到,mTarget是IMessenger对象,和AIDL分析实例中的IAddServer是一个概念,利用Messenger发送函数调用请求为:
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
实质上是调用mTarget的send方法。和IAddServer对象调用add函数是一样的。
后记:
至此,Android系统应用层binder跨进程通信分析完毕,本文之所以标题为浅析binder,是因为我们只是弄清楚了应用层利用binder通信机制的工作流程,并没有深究binder机制底层实现,大家如果敢兴趣,可以上网查询相关资料。AIDL和Messenger都是通过binder机制实现内部通信,相对来说,Messenger更加灵活,具体开发的时候,大家可以根据项目需求,选用合适的API,当然,如果你不想使用AIDL,又觉得Messenger不符合要求,可以自己实现binder通信的相关代码,也不复杂,这里就不再演示。
PS:文章如有错误之处,欢迎大家指出讨论,共同进步~