Android wifi-framework WifiMonitor和WifiNative學習

WifiStateMachine作爲wifi-framework層最核心的類,其他很多wifi的類都是爲其服務的,接下來記錄下對WifiNative和WifiMonitor這兩個類的學習(閱讀《深入理解Android:WiFi模塊 NFC和GPS卷 - 鄧凡平》和android4.2代碼的一些筆記)。
兩者都是WifiStateMachine在構造函數中創建的,是WifiStateMachine中重要的成員。

1、WifiNative

WifiNative是一個接口類,主要是提供一些native方法用於wifi-framework層和WPAS通信。WifiNative的主要實現都在wifi.c函數,WifiNative不過是將其封裝,供framework層調用。

底層的相關代碼在:
framework/base/jni/android_net_wifi_WifiNative.cpp和hardware/libhardware_legacy/wifi.cpp

(1)loadDriver:該方法是用於加載wifi驅動,主要實現是調用insmod函數進行wifi驅動的加載,然後根據加載是否成功來設置”wlan.driver.status”屬性,值爲”ok”/”failed”/”timeout”。
(2)startSupplicant:用於啓動WPAS,後續我們將會看到它在WifiStateMachine是如何被調用的。WPAS的啓動和dhcpcd的啓動類似,都是使用init.svc.xxx屬性來啓動的,根據不同的平臺配置,使用的Supplicant可能不同。
總結下就幾個重要的步驟:
首先確定使用的Supplicant,確定init.svc.xxx屬性;
然後判斷”/data/misc/wifi/wpa_supplicant.conf”配置文件是否存在,因爲在WPAS中,將會根據該文件進行wifi配置。
最後設置init.svc.xxx屬性啓動WPAS,超時時間根據代碼設置,啓動完成則設置init.svc.xxx爲running,否則爲stopped。
(3)connectToSupplicant:該函數將通過wpa Ctrl的接口和WPAS建立起交互關係。
該函數首先創建兩個wpa_ctrl對象, ctrl_conn用於向WPAS發送命令並接收對應命令的回覆, 而monitor_conn用於接收來自WPAS的unsolicited event。
ps:從Client角度來看,它發送給WPAS的命令所對應的回覆屬於solicited event( 有請求的事件),而CTRL-EVENT事件(用於通知事件)對應爲unsolicited event( 未請求的事件)。
然後monitor_conn調用wpa_ctrl_attach函數以啓用unsolicited event接收功能。
最後創建一個socketpair, 用於觸發WifiNative關閉和WPAS的連接。
(4)waitForEvent:主要是調用wpa_ctrl_recv函數從monitor_conn對象接收來自WPAS的unsolicited event(CTRL-EVENT事件)。
(5)doCommand類命令:其他一些函數,有很多是調用doCommand類,到底層就是調用的wpa_ctrl_request,使用ctrl_conn向WPAS發送命令並得到回覆。

2、WifiMonitor

WifiMonitor最主要的內容是創建了一個MonitorThread,用於接收WPAS的消息。
第一部分,該線程調用了waitForEvent函數,等待WPAS的unsolicited event。

public void run() {
            //noinspection InfiniteLoopStatement
            for (;;) {
                String eventStr = mWifiNative.waitForEvent();

                // Skip logging the common but mostly uninteresting scan-results event
                if (DBG && eventStr.indexOf(SCAN_RESULTS_STR) == -1) {
                    Log.d(TAG, "Event [" + eventStr + "]");
                }
            ......

第二部分,其調用了dispatchEvent函數,用於向WifiStateMachine分發消息。

public void run() {
            //noinspection InfiniteLoopStatement
            for (;;) {
             ......
                if (mStateMachine != null) {
                    if (dispatchEvent(eventStr)) {
                        break;
                    }
                } else {
                    if (DBG) Log.d(TAG, "Sending to all monitors because there's no interface id");
                    boolean done = false;
                    Iterator<Map.Entry<String, WifiMonitor>> it =
                            mWifiMonitorSingleton.mIfaceMap.entrySet().iterator();
                    while (it.hasNext()) {
                        Map.Entry<String, WifiMonitor> e = it.next();
                        m = e.getValue();
                        mStateMachine = m.mWifiStateMachine;
                        if (dispatchEvent(eventStr)) {
                            done = true;
                        }
                    }
         ......
        }

讓我們看下dispatchEvent函數,首先是處理非”CTRL-EVENT-“的消息:

private boolean dispatchEvent(String eventStr) {

            if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
                if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&
                        0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) {
                    mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
                } else if (eventStr.startsWith(WPS_SUCCESS_STR)) {
                    mStateMachine.sendMessage(WPS_SUCCESS_EVENT);
                } else if (eventStr.startsWith(WPS_FAIL_STR)) {
                    handleWpsFailEvent(eventStr);
                } else if (eventStr.startsWith(WPS_OVERLAP_STR)) {
                    mStateMachine.sendMessage(WPS_OVERLAP_EVENT);
                } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {
                    mStateMachine.sendMessage(WPS_TIMEOUT_EVENT);
                } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {
                    handleP2pEvents(eventStr);
                } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
                    handleHostApEvents(eventStr);
                }
                else {
                    if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr);
                }
                return false;
            ......

接下來是主要部分,對”CTRL-EVENT-“的消息消息的處理。分以下三種:
handleSupplicantStateChange處理WPAS的狀態變化,並把變化情況發給WifiStateMachine
handleDriverEvent用於處理來Driver的信息。
handleEvent處理DISCONNECTED / CONNECTED / SCAN_RESULTS 三個消息,並把響應的消息發給WifiStateMachine。

private boolean dispatchEvent(String eventStr) {
    ......
 if (event == STATE_CHANGE) {
               handleSupplicantStateChange(eventData);
            } else if (event == DRIVER_STATE) {
                handleDriverEvent(eventData);
            ......
            } else {
                handleEvent(event, eventData);
            }
            mRecvErrors = 0;
            return false;
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章