Android -- AsyncChannel简介
在学习Android Wifi部分的源码时,发现WifiManager和WifiService之间使用了AsyncChannel来进行通信,AsyncChannel用于两个Handler之间的通信,这里简单介绍下AsyncChannel的实现机制,文章中如有错误的地方,请批评指出,小弟感激不尽。
首先介绍下AsyncChannel:
AsyncChannel用于两个Handler之间通信,它并不关心这两个Handler是否寸在于同一进程。AsyncChannel有两种使用模式:
1)、简单的request/reply模式:该模式下Server不关心Client的任何信息,它只负责处理来自Client的请求。
2)、与request/reply模式不同,第二种使用场景Server需要区分不同的Client,它需要知道它连接的是哪个Client。例如,Server会主动地向Client发送一些消息;或者Server会为每个Client维护一些状态信息。
WifiManager和WifiService之间采用的是第二种使用模式,下面就以此例来介绍如何使用不同的两个Handler来进行通信(基于andr 6.0)。
WiFiManager在其构造函数中创建AsyncChannel:
public WifiManager(Context context, IWifiManager service) {
mContext = context;
mService = service;
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
init();
}
真正的创建过程在init()函数中:
private void init() {
synchronized (sThreadRefLock) {
if (++sThreadRefCount == 1) {
Messenger messenger = getWifiServiceMessenger(); //获取到一个代表Handler对象的引用,我们可以用它来发送消息
if (messenger == null) {
sAsyncChannel = null;
return;
}
sHandlerThread = new HandlerThread("WifiManager");
sAsyncChannel = new AsyncChannel();
sConnected = new CountDownLatch(1);
sHandlerThread.start();
Handler handler = new ServiceHandler(sHandlerThread.getLooper());
sAsyncChannel.connect(mContext, handler, messenger);
try {
sConnected.await();
} catch (InterruptedException e) {
Log.e(TAG, "interrupted wait at init");
}
}
}
}
1)、该函数首先通过AIDL机制(Binder)调用 WifiService的getWifiServiceMessenger()函数,创建一个Messenger对象。Messenger继承自Parcelable类。其内部维护了一个
private final IMessenger mTarget;
对象,它可用于进程间的Binder通信。通过以下两个函数可知:
/**
* Create a new Messenger pointing to the given Handler. Any Message
* objects sent through this Messenger will appear in the Handler as if
* {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
* been called directly.
*
* @param target The Handler that will receive sent messages.
*/
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
/**
* Send a Message to this Messenger's Handler.
*
* @param message The Message to send. Usually retrieved through
* {@link Message#obtain() Message.obtain()}.
*
* @throws RemoteException Throws DeadObjectException if the target
* Handler no longer exists.
*/
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
Messenger可以看做是一个Handler对象的引用,我们可以使用该对象代替Handler发送消息。
再看init()函数,Client中的Handler运行在名为“WifiManager”的sHandlerThread线程中,调用connect()函数进行连接。这里,handler是WifiManager中ServiceHandler对象,messenger对象是一个WifiService中ClientHandler的一个引用。
从这里就可以看出此次异步通道通信之间的两个Handler对象分别是什么了:
- 一个是WifiManager中的ServiceHandler对象;
- 另一个是WifiService中的ClientHandler对象。
进入AsyncChannel::connect()函数:
/**
* Connect handler and messenger.
*
* Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
* msg.arg1 = status
* msg.obj = the AsyncChannel
*
* @param srcContext
* @param srcHandler
* @param dstMessenger
*/
public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
if (DBG) log("connect srcHandler to the dstMessenger E");
// We are connected
connected(srcContext, srcHandler, dstMessenger);
// Tell source we are half connected
replyHalfConnected(STATUS_SUCCESSFUL);
if (DBG) log("connect srcHandler to the dstMessenger X");
}
/**
* Connect handler to messenger. This method is typically called
* when a server receives a CMD_CHANNEL_FULL_CONNECTION request
* and initializes the internal instance variables to allow communication
* with the dstMessenger.
*
* @param srcContext
* @param srcHandler
* @param dstMessenger
*/
public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
if (DBG) log("connected srcHandler to the dstMessenger E");
// Initialize source fields
mSrcContext = srcContext;
mSrcHandler = srcHandler;
mSrcMessenger = new Messenger(mSrcHandler);
// Initialize destination fields
mDstMessenger = dstMessenger;
if (DBG) log("connected srcHandler to the dstMessenger X");
}
从函数实现可知,这里主要是初始化一些对象,并调用replyHalfConnected()函数向mSrcHandler发送一个CMD_CHANNEL_HALF_CONNECTED消息:
/**
* Reply to the src handler that we're half connected.
* see: CMD_CHANNEL_HALF_CONNECTED for message contents
*
* @param status to be stored in msg.arg1
*/
private void replyHalfConnected(int status) {
Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
msg.arg1 = status;
msg.obj = this;
msg.replyTo = mDstMessenger;
/*
* Link to death only when bindService isn't used.
*/
if (mConnection == null) {
mDeathMonitor = new DeathMonitor();
try {
mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);//若Server端所在的进程已经死掉,来通知Client端进程进行一些后期处理
} catch (RemoteException e) {
mDeathMonitor = null;
// Override status to indicate failure
msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
}
}
mSrcHandler.sendMessage(msg);
}
这里,srcHandler就是Client端的Handler(ServiceHandler)对象。
private static class ServiceHandler extends Handler {
ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message message) {
Object listener = removeListener(message.arg2);
switch (message.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
} else {
Log.e(TAG, "Failed to set up channel connection");
// This will cause all further async API calls on the WifiManager
// to fail and throw an exception
sAsyncChannel = null;
}
sConnected.countDown();
break;
case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
// Ignore
break;
case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Log.e(TAG, "Channel connection lost");
// This will cause all further async API calls on the WifiManager
// to fail and throw an exception
sAsyncChannel = null;
getLooper().quit();
break;
/* ActionListeners grouped together */
}
}
}
调用sendMessage()函数向WifiService的ClientHandler发送CMD_CHANNEL_FULL_CONNECTION消息。
查看sendMessage()函数源码可知,mDstMessenger是它的target,该对象代表WifiService中ClientHandler的一个引用。我们看WifiService::ClientHandler怎么处理该消息:
/**
* Handles client connections
*/
private class ClientHandler extends Handler {
ClientHandler(android.os.Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
// We track the clients by the Messenger
// since it is expected to be always available
mTrafficPoller.addClient(msg.replyTo);
} else {
Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
}
break;
}
case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
if (DBG) Slog.d(TAG, "Send failed, client connection lost");
} else {
if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
}
mTrafficPoller.removeClient(msg.replyTo);
break;
}
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
AsyncChannel ac = new AsyncChannel();
ac.connect(mContext, this, msg.replyTo);
break;
}
}
}
}
处理的结果是再次调用AsyncChannel::connect(mContext, this, msg.replyTo);
这里this代表的是WifiService::ClientHandler对象,msg.replyTo代表WifiManager::ServiceHandler对象。
connect函数的实现上面已经看过,即向ClientHandler发送CMD_CHANNEL_HALF_CONNECTED消息,参数是STATUS_SUCCESSFUL;
相应的处理的是:mTrafficPoller.addClient(msg.replyTo);
将WifiMananger的ServiceHandler加入到Wifi系统的流量轮询管理机制当中,用于以后通知ServiceHandler不同的状态。
到此,WifiManager和WifiService之间的一个基于AsyncChannel的双向通信连接就建立完成;至此,WifiManager就可以通过AsyncChannel来发送一些指令了:
public void connect(int networkId, ActionListener listener) {
if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
validateChannel();
sAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
}