在Android的Wifi体系中,WifiMonitor承担着分发来自wpa_supplicant底层事件的任务。当上层下达Wifi的扫描、连接等指令后, 底层驱动以及wpa_s进行实际的扫描、连接操作,操作完成后会向上层反馈一个event,通知framework扫描是否结束、连接是否成功。
WifiStateMachine在处理CMD_START_SUPPLICANT消息时,会执行驱动加载、启动wpa_s等操作:
case CMD_START_SUPPLICANT: if (mWifiNative.loadDriver()) { try { mNwService.wifiFirmwareReload(mInterfaceName, "STA"); } catch (Exception e) { loge("Failed to reload STA firmware " + e); // Continue } try { // A runtime crash can leave the interface up and // IP addresses configured, and this affects // connectivity when supplicant starts up. // Ensure interface is down and we have no IP // addresses before a supplicant start. mNwService.setInterfaceDown(mInterfaceName); mNwService.clearInterfaceAddresses(mInterfaceName); // Set privacy extensions mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); // IPv6 is enabled only as long as access point is connected since: // - IPv6 addresses and routes stick around after disconnection // - kernel is unaware when connected and fails to start IPv6 negotiation // - kernel can start autoconfiguration when 802.1x is not complete mNwService.disableIpv6(mInterfaceName); } catch (RemoteException re) { loge("Unable to change interface settings: " + re); } catch (IllegalStateException ie) { loge("Unable to change interface settings: " + ie); } /* Stop a running supplicant after a runtime restart * Avoids issues with drivers that do not handle interface down * on a running supplicant properly. */ mWifiMonitor.killSupplicant(mP2pSupported); if (WifiNative.startHal() == false) { /* starting HAL is optional */ loge("Failed to start HAL"); } if (mWifiNative.startSupplicant(mP2pSupported)) { setWifiState(WIFI_STATE_ENABLING); if (DBG) log("Supplicant start successful"); mWifiMonitor.startMonitoring(); transitionTo(mSupplicantStartingState); } else { loge("Failed to start supplicant!"); } } else { loge("Failed to load driver"); } break; 同时调用WifiMonitor::startMonitoring()来开启WifiMonitor进程。启动WifiMonitor,间接调用内部类WifiMonitorSingleton::startMonitoring()方法:
public synchronized void startMonitoring(String iface) { WifiMonitor m = mIfaceMap.get(iface); if (m == null) { Log.e(TAG, "startMonitor called with unknown iface=" + iface); return; } Log.d(TAG, "startMonitoring(" + iface + ") with mConnected = " + mConnected); if (mConnected) { m.mMonitoring = true; m.mStateMachine.sendMessage(SUP_CONNECTION_EVENT); } else { if (DBG) Log.d(TAG, "connecting to supplicant"); int connectTries = 0; while (true) { if (mWifiNative.connectToSupplicant()) { m.mMonitoring = true; m.mStateMachine.sendMessage(SUP_CONNECTION_EVENT); mConnected = true; new MonitorThread(mWifiNative, this).start(); break; } if (connectTries++ < 5) { try { Thread.sleep(1000); } catch (InterruptedException ignore) { } } else { m.mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); Log.e(TAG, "startMonitoring(" + iface + ") failed!"); break; } } } } 为了监听wpa_supplicant的事件,需要先建立与wpa_s的消息通道,这一步调用WifiNative.connectToSupplicant()实现。如果是第一次进行监听mConnected为false,进入else分支。先建立与wpa_s的消息通道,建立成功后会向WifiStateMachine发送SUP_CONNECTION_EVENT消息,通知Wifi状态机。
随后,开启事件监听线程:new MonitorThread(mWifiNative, this).start():
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; } } } } 这里有两个重要函数:调用WifiNative.waitForEvent()接受来自wpa_s的事件;调用WifiMonitorSingleton.dispatchEvent(eventStr)分发来自wpa_s的底层event: 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; } } 解析eventStr,调用相应interface的WifiMonitor::dispatchEvent()方法分发具体的事件给WifiStateMachine处理: /* 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 (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; } 这里我们假设事先下发的是一个wifi扫描的指令,wpa_s反馈event通知wifi扫描的结果: else if (eventName.equals(SCAN_RESULTS_STR)) event = SCAN_RESULTS; 根据实现的一些匹配规则,最后进入handleEvent()函数: /** * Handle all supplicant events except STATE-CHANGE * event the event type * 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; } } 此处event是SCAN_RESULTS,向WifiStateMachine发送SCAN_RESULTS_EVENT消息,告知它扫描已经结束,可以去读取扫描结果了。这样,处理流程就用返回到Wifi状态机中。WifiStateMachine收到此消息后,调用WifiStateMachine::setScanResults()方法从wpa_s读取扫描结果,并向外界发送WifiManager.SCAN_RESULTS_AVAILABLE_ACTION广播通知应用。
此时一些注册过该广播的应用,例如手机中的Setting app,就能通过调用WifiManager::getScanResults()读取扫描结果了。至此,一个简单的WifiMonitor分发事件的流程结束,其他类型事件的分发跟此过程相似。