Android wifi-framework StateMachine和AsyncChannel 學習

android中,wifi的核心是WPAS(wpa_supplicant),它管理和控制Android平臺中的Wi-Fi功能。在整個wifi模塊中,其更像是一個一個服務端,實現了連接,認證等工作流程。
而客戶端有wpa_cli,和wpa_supplicant之間的通信依靠wpa ctrl接口來實現,而在wifi的framework層,其實主要工作就是向下實現wpa_cli的功能和wpa_supplicant通信,向上實現WiFiManager的簡易接口供上層app調用。

wifi的framework分析起來相對於wpa_supplicant比較簡單,先記錄這幾天看代碼的一些點(閱讀《深入理解Android:WiFi模塊 NFC和GPS卷 - 鄧凡平》和android4.2代碼的一些筆記)。

首先必須瞭解兩個類:StateMachine和AsyncChannel

1、StateMachine

在wifi模塊framework層的東西中,有很多地方都是用了狀態機的機制:WifiStateMachine,SupplicantStateTracker,DhcpStateMachine,WifiWatchdogStateMachine等。瞭解狀態機的運行方式,是瞭解wifi模塊在framework層運作的基礎。

StateMachine是具有層級關係的狀態機類,記錄幾個重要的點:
(1)addState函數可以增加一個狀態,同時,該函數可以指定父子層級關係。
setInitialState函數指定初始狀態。調用start函數時,狀態機開始運行。
(2)從一個狀態跳轉到另一個狀態時調用transitionTo函數。進入另一個狀態時會先調用到狀態的enter函數,退出時調用exit函數,同時得考慮他們的層級關係,而不是直接跳轉。以WifiWatchdogStateMachine的狀態機map爲例,從Disabled 狀態轉到Verifying ,會先調用Disabled的exit,再依次調用Enabled和Verifying的enter。
下面是WifiWatchdogStateMachine的狀態機map:

/**
 * STATE MAP
 *          Default
 *         /       \
 * Disabled      Enabled
 *             /     \     \
 * NotConnected  Verifying  Connected
 *                         /---------\
 *                       (all other states)
 */

(3)消息會在當前的狀態中處理,對應的函數爲processMessage。如果當前狀態不能處理,會返回NOT_HANDLED。轉到父狀態處理,如果父狀態依舊處理不了,則依次上去,如果都不能處理,最後unhandledMessage函數會被調用。
已經處理則返回HANDLED,如果一個消息想保留到下個狀態再處理,可以調用deferMessage函數。
(4)由於StateMachine內部是圍繞一個Handler來工作的, 所以外界只能調用StateMachine的obtainMessage函數以獲取一個Message。發想送消息給StateMachine,調用sendMessage函數,StateMachine中的Handler會處理它。

2、AsyncChannel

這個類在wifi模塊中也是被大量使用,是瞭解wifi的framework避不開的類。該類用於在兩個handler之間傳遞消息。
有兩種工作模式:一種是單通道模式,只有客戶端連接了AsyncChannel,能向客戶端發送請求,服務端只要迴應即可。另一種是雙通道模式,客戶端服務端都連接AsyncChannel,雙方均可以向對方發送請求。

單通道使用步驟:
(1)客戶端拿到自己的handler;
(2)拿到服務端的Messenger(使用服務端handler構建),或者是服務端的handler;
(3)創建AsyncChannel對象,調用其connect函數,請求連接客戶端自己的handler和服務端的Messenger;
(4)連接成功後,服務端會迴應CMD_CHANNEL_HALF_CONNECTED消息。

雙通道使用步驟:
其實雙通道是在單通道的基礎上完成的,
(1)客戶端在接收到CMD_CHANNEL_HALF_CONNECTED消息後,
發送sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
(2)服務端在handler中會受到該消息,接着服務端也創建AsyncChannel對象,調用其connect函數connect(mContext, this, msg.replyTo)。
(3)另外還有一種比較方便的方法創建雙通道,即調用該函數即可:
public int fullyConnectSync(Context srcContext, Handler srcHandler, Handler dstHandler)
需要傳入客戶端的context,客戶端的handler和服務端的handler。返回值STATUS_SUCCESSFUL即代表建立成功。

一些例子:
(1)在wifi的framework層,WifiManager和WifiService之間建立起了雙通道:
WifiManager作爲客戶端:
申請單通道連接:

private void init() {
        synchronized (sThreadRefLock) {
            if (++sThreadRefCount == 1) {
                Messenger messenger = getWifiServiceMessenger();
                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);
            ......
            }
        }
    }

在單通道連接基礎上,請求雙通道連接
sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION):

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 {
            ......

WifiService作爲服務端,在接收到CMD_CHANNEL_FULL_CONNECTION消息後,請求connect:

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_FULL_CONNECTION: {
                    AsyncChannel ac = new AsyncChannel();
                    ac.connect(mContext, this, msg.replyTo);
                    break;
                }

(2)WifiService和WifiStateMachine之間連接方式爲單通道,WifiStateMachine作爲服務端,WifiService作爲客戶端,連接後,使用sendMessageSynchronously來進行請求,而WifiStateMachine會使用replyToMessage來進行回覆(WifiStateMachine會用到mReplyChannel這個對象):

private class WifiStateMachineHandler extends Handler {
        private AsyncChannel mWsmChannel;

        WifiStateMachineHandler(android.os.Looper looper) {
            super(looper);
            mWsmChannel = new AsyncChannel();
            mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
                        mWifiStateMachineChannel = mWsmChannel;
                    } else {
                        Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);
                        mWifiStateMachineChannel = null;
                    }
                    break;
                }
發佈了58 篇原創文章 · 獲贊 46 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章