Android 异步通道 -- AsyncChannel

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)对象。


回到WifiManager中看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));
    }








  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值