天天看点

浅析Android binder机制

概述:

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机制远程通信调用机制过程。

浅析Android 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:文章如有错误之处,欢迎大家指出讨论,共同进步~