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;
}