Android 异步通道 -- AsyncChannel

Android -- AsyncChannel

转自http://blog.csdn.net/csdn_of_coder/article/details/51523409

在学习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:

  1. public WifiManager(Context context, IWifiManager service) {  
  2.      mContext = context;  
  3.      mService = service;  
  4.      mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;  
  5.      init();  
  6.  }  
真正的创建过程在init()函数中:
  1. private void init() {  
  2.         synchronized (sThreadRefLock) {  
  3.             if (++sThreadRefCount == 1) {  
  4.                 Messenger messenger = getWifiServiceMessenger(); //获取到一个代表Handler对象的引用,我们可以用它来发送消息  
  5.                 if (messenger == null) {  
  6.                     sAsyncChannel = null;  
  7.                     return;  
  8.                 }  
  9.   
  10.                 sHandlerThread = new HandlerThread("WifiManager");  
  11.                 sAsyncChannel = new AsyncChannel();  
  12.                 sConnected = new CountDownLatch(1);  
  13.   
  14.                 sHandlerThread.start();  
  15.                 Handler handler = new ServiceHandler(sHandlerThread.getLooper());  
  16.                 sAsyncChannel.connect(mContext, handler, messenger);  
  17.                 try {  
  18.                     sConnected.await();  
  19.                 } catch (InterruptedException e) {  
  20.                     Log.e(TAG, "interrupted wait at init");  
  21.                 }  
  22.             }  
  23.         }  
  24.     }  

1)、该函数首先通过AIDL机制(Binder)调用 WifiService的getWifiServiceMessenger()函数,创建一个Messenger对象。Messenger继承自Parcelable类。其内部维护了一个

  1. private final IMessenger mTarget;  

对象,它可用于进程间的Binder通信。通过以下两个函数可知:

  1. /** 
  2.      * Create a new Messenger pointing to the given Handler.  Any Message 
  3.      * objects sent through this Messenger will appear in the Handler as if 
  4.      * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had 
  5.      * been called directly. 
  6.      *  
  7.      * @param target The Handler that will receive sent messages. 
  8.      */  
  9.     public Messenger(Handler target) {  
  10.         mTarget = target.getIMessenger();  
  11.     }  
  12.       
  13.     /** 
  14.      * Send a Message to this Messenger's Handler. 
  15.      *  
  16.      * @param message The Message to send.  Usually retrieved through 
  17.      * {@link Message#obtain() Message.obtain()}. 
  18.      *  
  19.      * @throws RemoteException Throws DeadObjectException if the target 
  20.      * Handler no longer exists. 
  21.      */  
  22.     public void send(Message message) throws RemoteException {  
  23.         mTarget.send(message);  
  24.     }  
Messenger可以看做是一个Handler对象的引用,我们可以使用该对象代替Handler发送消息。

再看init()函数,Client中的Handler运行在名为“WifiManager”的sHandlerThread线程中,调用connect()函数进行连接。这里,handler是WifiManager中ServiceHandler对象,messenger对象是一个WifiService中ClientHandler的一个引用,从这里就可以看出此次异步通道通信之间的两个Handler对象分别是什么了:一个是WifiManager中的ServiceHandler对象;另一个是WifiService中的ClientHandler对象。

进入AsyncChannel::connect()函数:

  1. /** 
  2.      * Connect handler and messenger. 
  3.      * 
  4.      * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. 
  5.      *      msg.arg1 = status 
  6.      *      msg.obj = the AsyncChannel 
  7.      * 
  8.      * @param srcContext 
  9.      * @param srcHandler 
  10.      * @param dstMessenger 
  11.      */  
  12.     public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {  
  13.         if (DBG) log("connect srcHandler to the dstMessenger  E");  
  14.   
  15.         // We are connected  
  16.         connected(srcContext, srcHandler, dstMessenger);  
  17.   
  18.         // Tell source we are half connected  
  19.         replyHalfConnected(STATUS_SUCCESSFUL);  
  20.   
  21.         if (DBG) log("connect srcHandler to the dstMessenger X");  
  22.     }  
  23.   /** 
  24.      * Connect handler to messenger. This method is typically called 
  25.      * when a server receives a CMD_CHANNEL_FULL_CONNECTION request 
  26.      * and initializes the internal instance variables to allow communication 
  27.      * with the dstMessenger. 
  28.      * 
  29.      * @param srcContext 
  30.      * @param srcHandler 
  31.      * @param dstMessenger 
  32.      */  
  33.     public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {  
  34.         if (DBG) log("connected srcHandler to the dstMessenger  E");  
  35.   
  36.         // Initialize source fields  
  37.         mSrcContext = srcContext;  
  38.         mSrcHandler = srcHandler;  
  39.         mSrcMessenger = new Messenger(mSrcHandler);  
  40.   
  41.         // Initialize destination fields  
  42.         mDstMessenger = dstMessenger;  
  43.   
  44.         if (DBG) log("connected srcHandler to the dstMessenger X");  
  45.     }  
从函数实现可知,这里主要是初始化一些对象,并调用replyHalfConnected()函数向mSrcHandler发送一个CMD_CHANNEL_HALF_CONNECTED消息:
  1. /** 
  2.  * Reply to the src handler that we're half connected. 
  3.  * see: CMD_CHANNEL_HALF_CONNECTED for message contents 
  4.  * 
  5.  * @param status to be stored in msg.arg1 
  6.  */  
  7. private void replyHalfConnected(int status) {  
  8.     Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);  
  9.     msg.arg1 = status;  
  10.     msg.obj = this;  
  11.     msg.replyTo = mDstMessenger;  
  12.   
  13.     /* 
  14.      * Link to death only when bindService isn't used. 
  15.      */  
  16.     if (mConnection == null) {  
  17.         mDeathMonitor = new DeathMonitor();  
  18.         try {  
  19.             mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);//若Server端所在的进程已经死掉,来通知Client端进程进行一些后期处理  
  20.         } catch (RemoteException e) {  
  21.             mDeathMonitor = null;  
  22.             // Override status to indicate failure  
  23.             msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;  
  24.         }  
  25.     }  
  26.   
  27.     mSrcHandler.sendMessage(msg);  
  28. }  
这里,srcHandler就是Client端的Handler(ServiceHandler)对象。
回到WifiManager中看ServiceHandler怎样处理此消息:
  1. private static class ServiceHandler extends Handler {  
  2.         ServiceHandler(Looper looper) {  
  3.             super(looper);  
  4.         }  
  5.   
  6.         @Override  
  7.         public void handleMessage(Message message) {  
  8.             Object listener = removeListener(message.arg2);  
  9.             switch (message.what) {  
  10.                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:  
  11.                     if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {  
  12.                         sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);  
  13.                     } else {  
  14.                         Log.e(TAG, "Failed to set up channel connection");  
  15.                         // This will cause all further async API calls on the WifiManager  
  16.                         // to fail and throw an exception  
  17.                         sAsyncChannel = null;  
  18.                     }  
  19.                     sConnected.countDown();  
  20.                     break;  
  21.                 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:  
  22.                     // Ignore  
  23.                     break;  
  24.                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:  
  25.                     Log.e(TAG, "Channel connection lost");  
  26.                     // This will cause all further async API calls on the WifiManager  
  27.                     // to fail and throw an exception  
  28.                     sAsyncChannel = null;  
  29.                     getLooper().quit();  
  30.                     break;  
  31.                     /* ActionListeners grouped together */  
  32.             }  
  33.       }  
  34.   }  
调用sendMessage()函数向WifiService的ClientHandler发送CMD_CHANNEL_FULL_CONNECTION消息;查看sendMessage()函数源码可知,mDstMessenger是它的target,该对象代表WifiService中ClientHandler的一个引用。我们看WifiService::ClientHandler怎么处理该消息:
  1. /** 
  2.  * Handles client connections 
  3.  */  
  4. private class ClientHandler extends Handler {  
  5.   
  6.     ClientHandler(android.os.Looper looper) {  
  7.         super(looper);  
  8.     }  
  9.   
  10.     @Override  
  11.     public void handleMessage(Message msg) {  
  12.         switch (msg.what) {  
  13.             case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {  
  14.                 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {  
  15.                     if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");  
  16.                     // We track the clients by the Messenger  
  17.                     // since it is expected to be always available  
  18.                     mTrafficPoller.addClient(msg.replyTo);  
  19.                 } else {  
  20.                     Slog.e(TAG, "Client connection failure, error=" + msg.arg1);  
  21.                 }  
  22.                 break;  
  23.             }  
  24.             case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {  
  25.                 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {  
  26.                     if (DBG) Slog.d(TAG, "Send failed, client connection lost");  
  27.                 } else {  
  28.                     if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);  
  29.                 }  
  30.                 mTrafficPoller.removeClient(msg.replyTo);  
  31.                 break;  
  32.             }  
  33.             case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {  
  34.                 AsyncChannel ac = new AsyncChannel();  
  35.                 ac.connect(mContext, this, msg.replyTo);  
  36.                 break;  
  37.             }  
  38.          }  
  39.     }  

处理的结果是再次调用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来发送一些指令了:

  1. public void connect(int networkId, ActionListener listener) {  
  2.      if (networkId < 0throw new IllegalArgumentException("Network id cannot be negative");  
  3.      validateChannel();  
  4.      sAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener));  
  5.  }  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值