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