版权声明:本文为博主原创文章,未经博主允许不得转载。
https://blog.csdn.net/huangweiqing80/article/details/82702979
三、 WIFI扫描
前面说到wifi打开状态机会停在DisconnectedState状态,之后会开始进行自动扫描,自动扫描的流程可以参考自动扫描流程
在我本地的Android6.0 源码中是在DisconnectedState状态的enter函数中会去调用startScan函数进行扫描,因为DisconnectedState状态的enter函数是打开wifi之后调用到的,所以在打开wifi时就会调用startScan函数,这样便不需用户点击扫描也能自动进行扫描了,有些平台调用的是startDelayedScan或者startScanNative,在原理上都一样。
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
class DisconnectedState extends State {
@Override
public void enter() {
// We dont scan frequently if this is a temporary disconnect
// due to p2p
if (mTemporarilyDisconnectWifi) {
mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
return;
}
if (PDBG) {
logd(" Enter DisconnectedState scan interval "
+ mWifiConfigStore.wifiDisconnectedShortScanIntervalMilli.get()
+ " mLegacyPnoEnabled= " + mLegacyPnoEnabled
+ " screenOn=" + mScreenOn
+ " useGscan=" + mHalBasedPnoDriverSupported + "/"
+ mWifiConfigStore.enableHalBasedPno.get());
}
/** clear the roaming state, if we were roaming, we failed */
mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
if (useHalBasedAutoJoinOffload()) {
startGScanDisconnectedModeOffload("disconnectedEnter");
} else {
if (mScreenOn) {
/**
* screen lit and => start scan immediately
*/
startScan(UNKNOWN_SCAN_SOURCE, 0, null, null);
} else {
/**
* screen dark and PNO supported => scan alarm disabled
*/
if (mBackgroundScanSupported) {
/* If a regular scan result is pending, do not initiate background
* scan until the scan results are returned. This is needed because
* initiating a background scan will cancel the regular scan and
* scan results will not be returned until background scanning is
* cleared
*/
if (!mIsScanOngoing) {
enableBackgroundScan(true);
}
} else {
setScanAlarm(true);
}
}
}
/**
* If we have no networks saved, the supplicant stops doing the periodic scan.
* The scans are useful to notify the user of the presence of an open network.
* Note that these are not wake up scans.
*/
if (mNoNetworksPeriodicScan != 0 && !mP2pConnected.get()
&& mWifiConfigStore.getConfiguredNetworks().size() == 0) {
sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
}
mDisconnectedTimeStamp = System.currentTimeMillis();
mDisconnectedPnoAlarmCount = 0;
}
startScan函数被调用来进行扫描
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
public void startScan(int callingUid, int scanCounter,
ScanSettings settings, WorkSource workSource) {
Bundle bundle = new Bundle();
bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings);
bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis());
sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle);
}
此函数将往 WifiStateMachine 中发送 CMD_START_SCAN 消息。由 DisconnectedState 状态处理
DisconnectedState extends State {
...
case CMD_START_SCAN:
if (!checkOrDeferScanAllowed(message)) {
// The scan request was rescheduled
messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
return HANDLED;
}
if (message.arg1 == SCAN_ALARM_SOURCE) {
// Check if the CMD_START_SCAN message is obsolete (and thus if it should
// not be processed) and restart the scan
int period = mWifiConfigStore.wifiDisconnectedShortScanIntervalMilli.get();
if (mP2pConnected.get()) {
period = (int)Settings.Global.getLong(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
period);
}
if (!checkAndRestartDelayedScan(message.arg2,
true, period, null, null)) {
messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
logd("Disconnected CMD_START_SCAN source "
+ message.arg1
+ " " + message.arg2 + ", " + mDelayedScanCounter
+ " -> obsolete");
return HANDLED;
}
/* Disable background scan temporarily during a regular scan */
enableBackgroundScan(false);
handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
ret = HANDLED;
} else {
/*
* The SCAN request is not handled in this state and
* would eventually might/will get handled in the
* parent's state. The PNO, if already enabled had to
* get disabled before the SCAN trigger. Hence, stop
* the PNO if already enabled in this state, though the
* SCAN request is not handled(PNO disable before the
* SCAN trigger in any other state is not the right
* place to issue).
*/
enableBackgroundScan(false);
ret = NOT_HANDLED;
}
break;
代码走的是else语句,返回NOT_HANDLED,所以会调用父状态的processMessage方法接着处理。(当前状态执行完processMessage方法返回了false,也就是对当前消息NOT_HANDLED,那么就会持续调用这个状态的父状态执行方法。)
@Override
public boolean processMessage(Message message) {
logStateAndMessage(message, this);
switch(message.what) {
case CMD_START_SCAN:
handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
break;
调用了handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
private void handleScanRequest(int type, Message message) {
ScanSettings settings = null;
WorkSource workSource = null;
// unbundle parameters
Bundle bundle = (Bundle) message.obj;
if (bundle != null) {
settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING);
workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE);
}
// parse scan settings
String freqs = null;
if (settings != null && settings.channelSet != null) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (WifiChannel channel : settings.channelSet) {
if (!first) sb.append(',');
else first = false;
sb.append(channel.freqMHz);
}
freqs = sb.toString();
}
// call wifi native to start the scan
if (startScanNative(type, freqs)) {
// only count battery consumption if scan request is accepted
noteScanStart(message.arg1, workSource);
// a full scan covers everything, clearing scan request buffer
if (freqs == null)
mBufferedScanMsg.clear();
messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
if (workSource != null) {
// External worksource was passed along the scan request,
// hence always send a broadcast
mSendScanResultsBroadcast = true;
}
return;
}
// if reach here, scan request is rejected
if (!mIsScanOngoing) {
// if rejection is NOT due to ongoing scan (e.g. bad scan parameters),
// discard this request and pop up the next one
if (mBufferedScanMsg.size() > 0) {
sendMessage(mBufferedScanMsg.remove());
}
messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
} else if (!mIsFullScanOngoing) {
// if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan,
// buffer the scan request to make sure specified channels will be scanned eventually
if (freqs == null)
mBufferedScanMsg.clear();
if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) {
Message msg = obtainMessage(CMD_START_SCAN,
message.arg1, message.arg2, bundle);
mBufferedScanMsg.add(msg);
} else {
// if too many requests in buffer, combine them into a single full scan
bundle = new Bundle();
bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null);
bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
Message msg = obtainMessage(CMD_START_SCAN, message.arg1, message.arg2, bundle);
mBufferedScanMsg.clear();
mBufferedScanMsg.add(msg);
}
messageHandlingStatus = MESSAGE_HANDLING_STATUS_LOOPED;
} else {
// mIsScanOngoing and mIsFullScanOngoing
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
}
}
代码很多,但是我们只看startScanNative(type, freqs)这句,下面看看startScanNative源码
/**
* return true iff scan request is accepted
*/
private boolean startScanNative(int type, String freqs) {
if (mWifiNative.scan(type, freqs)) {
mIsScanOngoing = true;
mIsFullScanOngoing = (freqs == null);
lastScanFreqs = freqs;
return true;
}
return false;
}
这里调用了mWifiNative.scan(type, freqs)
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
public boolean scan(int type, String freqList) {
if (type == SCAN_WITHOUT_CONNECTION_SETUP) {
if (freqList == null) return doBooleanCommand("SCAN TYPE=ONLY");
else return doBooleanCommand("SCAN TYPE=ONLY freq=" + freqList);
} else if (type == SCAN_WITH_CONNECTION_SETUP) {
if (freqList == null) return doBooleanCommand("SCAN");
else return doBooleanCommand("SCAN freq=" + freqList);
} else {
throw new IllegalArgumentException("Invalid scan type");
}
}
这里调用return doBooleanCommand(“SCAN”);
private boolean doBooleanCommand(String command) {
if (DBG) Log.d(mTAG, "doBoolean: " + command);
synchronized (mLock) {
int cmdId = getNewCmdIdLocked();
String toLog = Integer.toString(cmdId) + ":" + mInterfacePrefix + command;
boolean result = doBooleanCommandNative(mInterfacePrefix + command);
localLog(toLog + " -> " + result);
if (DBG) Log.d(mTAG, command + ": returned " + result);
return result;
}
}
这里实际调用到的是doBooleanCommandNative函数,下面来看看这个函数在JNI的定义
frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp
{ "doBooleanCommandNative", "(Ljava/lang/String;)Z", (void*)android_net_wifi_doBooleanCommand },
对应的实现是android_net_wifi_doBooleanCommand
frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp
static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring javaCommand) {
return doBooleanCommand(env, javaCommand);
}
static jboolean doBooleanCommand(JNIEnv* env, jstring javaCommand) {
char reply[REPLY_BUF_SIZE];
if (!doCommand(env, javaCommand, reply, sizeof(reply))) {
return JNI_FALSE;
}
jboolean result = (strcmp(reply, "OK") == 0);
if (!result) {
ScopedUtfChars command(env, javaCommand);
ALOGI("command '%s' returned '%s", command.c_str(), reply);
}
return result;
}
static bool doCommand(JNIEnv* env, jstring javaCommand,
char* reply, size_t reply_len) {
ScopedUtfChars command(env, javaCommand);
if (command.c_str() == NULL) {
return false; // ScopedUtfChars already threw on error.
}
if (DBG) {
ALOGD("doCommand: %s", command.c_str());
}
--reply_len; // Ensure we have room to add NUL termination.
if (::wifi_command(command.c_str(), reply, &reply_len) != 0) {
return false;
}
// Strip off trailing newline.
if (reply_len > 0 && reply[reply_len-1] == '\n') {
reply[reply_len-1] = '\0';
} else {
reply[reply_len] = '\0';
}
return true;
}
看到最后会调用到的是 (::wifi_command(command.c_str(), reply, &reply_len) != 0)
hardware/libhardware_legacy/wifi/wifi.c
int wifi_command(const char *command, char *reply, size_t *reply_len)
{
return wifi_send_command(command, reply, reply_len);
}
int wifi_send_command(const char *cmd, char *reply, size_t *reply_len)
{
int ret;
if (ctrl_conn == NULL) {
ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
return -1;
}
ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), reply, reply_len, NULL);
if (ret == -2) {
ALOGD("'%s' command timed out.\n", cmd);
/* unblocks the monitor receive socket for termination */
TEMP_FAILURE_RETRY(write(exit_sockets[0], "T", 1));
return -2;
} else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
return -1;
}
if (strncmp(cmd, "PING", 4) == 0) {
reply[*reply_len] = '\0';
}
return 0;
这就调用到wifi.c 中的函数将命令发送给wpa_supplicant了。这个wpa_ctrl_request是wpa_supplicant的API.这样我们便通过上层让wpa_supplicant去驱动wifi driver进行扫描了。当扫描结束后wpa_supplicant会产生一个时间给wpa_ctrl_recv接口。
四、
我们前面讲到startMonitoring();
在startMonitoring会做三件事
1.首先要判断是够和wpa_supplicant建立连接,如果建立连接了,就一个wifi状态机发送一个SUP_CONNECTION_EVENT消息。如果没有建立连接就尝试建立连接。
2.使用mWifiNative.connectToSupplicant()和wpa_supplicant建立连接。
3.创建MonitorThread监听线程。
下面我们来看看MonitorThread
private static class MonitorThread extends Thread {
private final WifiNative mWifiNative;
private final WifiMonitorSingleton mWifiMonitorSingleton;
private final LocalLog mLocalLog = WifiNative.getLocalLog();
public MonitorThread(WifiNative wifiNative, WifiMonitorSingleton wifiMonitorSingleton) {
super("WifiMonitor");
mWifiNative = wifiNative;
mWifiMonitorSingleton = wifiMonitorSingleton;
}
public void run() {
if (DBG) {
Log.d(TAG, "MonitorThread start with mConnected=" +
mWifiMonitorSingleton.mConnected);
}
//noinspection InfiniteLoopStatement
for (;;) {
if (!mWifiMonitorSingleton.mConnected) {
if (DBG) Log.d(TAG, "MonitorThread exit because mConnected is false");
break;
}
String eventStr = mWifiNative.waitForEvent();
// Skip logging the common but mostly uninteresting events
if (eventStr.indexOf(BSS_ADDED_STR) == -1
&& eventStr.indexOf(BSS_REMOVED_STR) == -1) {
if (DBG) Log.d(TAG, "Event [" + eventStr + "]");
mLocalLog.log("Event [" + eventStr + "]");
}
if (mWifiMonitorSingleton.dispatchEvent(eventStr)) {
if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events");
break;
}
}
}
}
可以看到这个线程主要做了两件事
1.使用mWifiNative.waitForEvent();监听wpa_supplicant发送上来的事件。
2.使用mWifiMonitorSingleton.dispatchEvent(eventStr)分发事件。
先来看看mWifiNative.waitForEvent()是怎样来监听事件的。
waitForEvent ==> waitForEventNative ==>android_net_wifi_waitForEvent ==>wifi_wait_for_event ==>wifi_wait_on_socket ==> wifi_ctrl_recv ==> wpa_ctrl_recv
wpa_ctrl_recv接口定义在wpa_ctrl.c中;wpa_ctrl_recv接口是在控制接口的事件监视注册成功后,用来接受事件消息,这是一个阻塞的操作,当没有可用的消息时,就会一直阻塞
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
{
int res;
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
*reply_len = res;
return 0;
}
所以mWifiNative.waitForEvent()会阻塞等待事件上报,一直阻塞到有消息上报上来之后才会接着使用mWifiMonitorSingleton.dispatchEvent(eventStr)分发事件。另外我们可以看到,这两个函数又是放在for循环中的,所以会循环去监听和分发事件。
下面我们来看看mWifiMonitorSingleton.dispatchEvent(eventStr)分发事件过程
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMonitor.java
private synchronized boolean dispatchEvent(String eventStr) {
String iface;
// IFNAME=wlan0 ANQP-QUERY-DONE addr=18:cf:5e:26:a4:88 result=SUCCESS
if (eventStr.startsWith("IFNAME=")) {
int space = eventStr.indexOf(' ');
if (space != -1) {
iface = eventStr.substring(7, space);
if (!mIfaceMap.containsKey(iface) && iface.startsWith("p2p-")) {
// p2p interfaces are created dynamically, but we have
// only one P2p state machine monitoring all of them; look
// for it explicitly, and send messages there ..
iface = "p2p0";
}
eventStr = eventStr.substring(space + 1);
} else {
// No point dispatching this event to any interface, the dispatched
// event string will begin with "IFNAME=" which dispatchEvent can't really
// do anything about.
Log.e(TAG, "Dropping malformed event (unparsable iface): " + eventStr);
return false;
}
} else {
// events without prefix belong to p2p0 monitor
iface = "p2p0";
}
if (VDBG) Log.d(TAG, "Dispatching event to interface: " + iface);
WifiMonitor m = mIfaceMap.get(iface);
if (m != null) {
if (m.mMonitoring) {
if (m.dispatchEvent(eventStr, iface)) {
mConnected = false;
return true;
}
return false;
} else {
if (DBG) Log.d(TAG, "Dropping event because (" + iface + ") is stopped");
return false;
}
} else {
if (DBG) Log.d(TAG, "Sending to all monitors because there's no matching iface");
boolean done = false;
boolean isMonitoring = false;
boolean isTerminating = false;
if (eventStr.startsWith(EVENT_PREFIX_STR)
&& eventStr.contains(TERMINATING_STR)) {
isTerminating = true;
}
for (WifiMonitor monitor : mIfaceMap.values()) {
if (monitor.mMonitoring) {
isMonitoring = true;
if (monitor.dispatchEvent(eventStr, iface)) {
done = true;
}
}
}
if (!isMonitoring && isTerminating) {
done = true;
}
if (done) {
mConnected = false;
}
return done;
}
}
1.wpa_supplicant发送上来的事件是一个字符串,这里需要对这个字符串做一个解析,找到对应接口(wlan0)的WifiMontor.
2.调用对应WifiMontor的事件分发方法:monitor.dispatchEvent(eventStr, iface)。
wifi的接口一般为wlan0,此时下面的方法会被调用:
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMonitor.java
/* @return true if the event was supplicant disconnection */
private boolean dispatchEvent(String eventStr, String iface) {
if (DBG) {
// Dont log CTRL-EVENT-BSS-ADDED which are too verbose and not handled
if (eventStr != null && !eventStr.contains("CTRL-EVENT-BSS-ADDED")) {
logDbg("WifiMonitor:" + iface + " cnt=" + Integer.toString(eventLogCounter)
+ " dispatchEvent: " + 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, eventLogCounter);
} 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 (eventStr.startsWith(ANQP_DONE_STR)) {
try {
handleAnqpResult(eventStr);
}
catch (IllegalArgumentException iae) {
Log.e(TAG, "Bad ANQP event string: '" + eventStr + "': " + iae);
}
} else if (eventStr.startsWith(GAS_QUERY_PREFIX_STR)) { // !!! clean >>End
handleGasQueryEvents(eventStr);
} else if (eventStr.startsWith(RX_HS20_ANQP_ICON_STR)) {
if (mStateMachine2 != null)
mStateMachine2.sendMessage(RX_HS20_ANQP_ICON_EVENT,
eventStr.substring(RX_HS20_ANQP_ICON_STR_LEN + 1));
} else if (eventStr.startsWith(HS20_PREFIX_STR)) { // !!! <<End
handleHs20Events(eventStr);
} else if (eventStr.startsWith(REQUEST_PREFIX_STR)) {
handleRequests(eventStr);
} else if (eventStr.startsWith(TARGET_BSSID_STR)) {
handleTargetBSSIDEvent(eventStr);
} else if (eventStr.startsWith(ASSOCIATED_WITH_STR)) {
handleAssociatedBSSIDEvent(eventStr);
} else if (eventStr.startsWith(AUTH_EVENT_PREFIX_STR) &&
eventStr.endsWith(AUTH_TIMEOUT_STR)) {
mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
} else if (eventStr.startsWith(RSN_PMKID_STR)) {
mStateMachine.sendMessage(RSN_PMKID_MISMATCH_EVENT);
} else {
if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr);
}
eventLogCounter++;
return false;
}
String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);
int nameEnd = eventName.indexOf(' ');
if (nameEnd != -1)
eventName = eventName.substring(0, nameEnd);
if (eventName.length() == 0) {
if (DBG) Log.i(TAG, "Received wpa_supplicant event with empty event name");
eventLogCounter++;
return false;
}
/*
* Map event name into event enum
*/
int event;
if (eventName.equals(CONNECTED_STR))
event = CONNECTED;
else if (eventName.equals(DISCONNECTED_STR))
event = DISCONNECTED;
else if (eventName.equals(STATE_CHANGE_STR))
event = STATE_CHANGE;
else if (eventName.equals(SCAN_RESULTS_STR))
event = SCAN_RESULTS;
else if (eventName.equals(SCAN_FAILED_STR))
event = SCAN_FAILED;
else if (eventName.equals(LINK_SPEED_STR))
event = LINK_SPEED;
else if (eventName.equals(TERMINATING_STR))
event = TERMINATING;
else if (eventName.equals(DRIVER_STATE_STR))
event = DRIVER_STATE;
else if (eventName.equals(EAP_FAILURE_STR))
event = EAP_FAILURE;
else if (eventName.equals(ASSOC_REJECT_STR))
event = ASSOC_REJECT;
else if (eventName.equals(TEMP_DISABLED_STR)) {
event = SSID_TEMP_DISABLE;
} else if (eventName.equals(REENABLED_STR)) {
event = SSID_REENABLE;
} else if (eventName.equals(BSS_ADDED_STR)) {
event = BSS_ADDED;
} else if (eventName.equals(BSS_REMOVED_STR)) {
event = BSS_REMOVED;
} else
event = UNKNOWN;
String eventData = eventStr;
if (event == DRIVER_STATE || event == LINK_SPEED)
eventData = eventData.split(" ")[1];
else if (event == STATE_CHANGE || event == EAP_FAILURE) {
int ind = eventStr.indexOf(" ");
if (ind != -1) {
eventData = eventStr.substring(ind + 1);
}
} else {
int ind = eventStr.indexOf(" - ");
if (ind != -1) {
eventData = eventStr.substring(ind + 3);
}
}
if ((event == SSID_TEMP_DISABLE)||(event == SSID_REENABLE)) {
String substr = null;
int netId = -1;
int ind = eventStr.indexOf(" ");
if (ind != -1) {
substr = eventStr.substring(ind + 1);
}
if (substr != null) {
String status[] = substr.split(" ");
for (String key : status) {
if (key.regionMatches(0, "id=", 0, 3)) {
int idx = 3;
netId = 0;
while (idx < key.length()) {
char c = key.charAt(idx);
if ((c >= 0x30) && (c <= 0x39)) {
netId *= 10;
netId += c - 0x30;
idx++;
} else {
break;
}
}
}
}
}
mStateMachine.sendMessage((event == SSID_TEMP_DISABLE)?
SSID_TEMP_DISABLED:SSID_REENABLED, netId, 0, substr);
} else if (event == STATE_CHANGE) {
handleSupplicantStateChange(eventData);
} else if (event == DRIVER_STATE) {
handleDriverEvent(eventData);
} else if (event == TERMINATING) {
/**
* Close the supplicant connection if we see
* too many recv errors
*/
if (eventData.startsWith(WPA_RECV_ERROR_STR)) {
if (++sRecvErrors > MAX_RECV_ERRORS) {
if (DBG) {
Log.d(TAG, "too many recv errors, closing connection");
}
} else {
eventLogCounter++;
return false;
}
}
// Notify and exit
mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT, eventLogCounter);
return true;
} else if (event == EAP_FAILURE) {
if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) {
logDbg("WifiMonitor send auth failure (EAP_AUTH_FAILURE) ");
mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT, eventLogCounter);
}
} else if (event == ASSOC_REJECT) {
Matcher match = mAssocRejectEventPattern.matcher(eventData);
String BSSID = "";
int status = -1;
if (!match.find()) {
if (DBG) Log.d(TAG, "Assoc Reject: Could not parse assoc reject string");
} else {
BSSID = match.group(1);
try {
status = Integer.parseInt(match.group(2));
} catch (NumberFormatException e) {
status = -1;
}
}
mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT, eventLogCounter, status, BSSID);
} else if (event == BSS_ADDED && !VDBG) {
// Ignore that event - it is not handled, and dont log it as it is too verbose
} else if (event == BSS_REMOVED && !VDBG) {
// Ignore that event - it is not handled, and dont log it as it is too verbose
} else {
handleEvent(event, eventData);
}
sRecvErrors = 0;
eventLogCounter++;
return false;
}
从
else {
handleEvent(event, eventData);
}
部分dispatchEvent没有处理的事件会调用handleEvent(event, eventData);进一步处理:
/**
* Handle all supplicant events except STATE-CHANGE
* @param event the event type
* @param remainder the rest of the string following the
* event name and " — "
*/
void handleEvent(int event, String remainder) {
if (DBG) {
logDbg("handleEvent " + Integer.toString(event) + " " + remainder);
}
switch (event) {
case DISCONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);
break;
case CONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);
break;
case SCAN_RESULTS:
mStateMachine.sendMessage(SCAN_RESULTS_EVENT);
break;
case SCAN_FAILED:
mStateMachine.sendMessage(SCAN_FAILED_EVENT);
break;
case UNKNOWN:
if (DBG) {
logDbg("handleEvent unknown: " + Integer.toString(event) + " " + remainder);
}
break;
default:
break;
}
}
可以看到wpa_supplicant扫描结束后会发送SCAN_RESULTS事件上来,在handleEvent方法中,检测到事件为SCAN_RESULTS后就向wifi状态机发送一个消息:mStateMachine.sendMessage(SCAN_RESULTS_EVENT);在wifi状态机中处理过程如下所示:
SCAN_RESULTS_EVENT在DisconnectedState 返回NOT_HANDLED,交给父状态DriverStartedState;
DisconnectedState 返回NOT_HANDLED,再交给DisconnectedState 父状态SupplicantStartedState 进行处理
class SupplicantStartedState extends State {
...
case WifiMonitor.SCAN_RESULTS_EVENT:
case WifiMonitor.SCAN_FAILED_EVENT:
maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered
noteScanEnd();
setScanResults();
if (mIsFullScanOngoing || mSendScanResultsBroadcast) {
/* Just updated results from full scan, let apps know about this */
boolean scanSucceeded = message.what == WifiMonitor.SCAN_RESULTS_EVENT;
sendScanResultsAvailableBroadcast(scanSucceeded);
}
mSendScanResultsBroadcast = false;
mIsScanOngoing = false;
mIsFullScanOngoing = false;
if (mBufferedScanMsg.size() > 0)
sendMessage(mBufferedScanMsg.remove());
break;
1.使用setScanResults设置扫描的结果。
2.使用sendScanResultsAvailableBroadcast(scanSucceeded);发送扫描结果可用的广播。
综上,整个Android系统的wifi框架我们通过对源码的追踪,梳理了一遍。wifi框架中有两个非常重要的状态机:mWifiController 和mWifiStateMachine,他们相互配合,维护这wifi的各个状态。mWifiStateMachine内部使用WifiNative向wpa_supplicant发送各种命令。WifiStateMachine中还有一个WifiMonitor,它负责接收wpa_supplicant发送上来的事件。这样,结合事件的发送和接收,我们就理清了应用程序和wpa_supplicant交互的过程。