Android -- WifiMonitor
在Android的Wifi体系中,WifiMonitor承担着分发来自wpa_supplicant底层事件的任务。当上层下达Wifi的扫描、连接等指令后, 底层驱动以及wpa_s进行实际的扫描、连接操作,操作完成后会向上层反馈一个event,通知framework扫描是否结束、连接是否成功。WifiStateMachine在处理CMD_START_SUPPLICANT消息时,会执行驱动加载、启动wpa_s等操作:
同时调用WifiMonitor::startMonitoring()来开启WifiMonitor进程。启动WifiMonitor,间接调用内部类WifiMonitorSingleton::startMonitoring()方法:
为了监听wpa_supplicant的事件,需要先建立与wpa_s的消息通道,这一步调用WifiNative.connectToSupplicant()实现。
- 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;
- 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;
- }
- }
- }
- }
如果是第一次进行监听mConnected为false,进入else分支。先建立与wpa_s的消息通道,建立成功后会向WifiStateMachine发送SUP_CONNECTION_EVENT消息,通知Wifi状态机。随后,开启事件监听线程:new MonitorThread(mWifiNative, this).start():
这里有两个重要函数:调用WifiNative.waitForEvent()接受来自wpa_s的事件;调用WifiMonitorSingleton.dispatchEvent(eventStr)分发来自wpa_s的底层event:
解析eventStr,调用相应interface的WifiMonitor::dispatchEvent()方法分发具体的事件给WifiStateMachine处理:
这里我们假设事先下发的是一个wifi扫描的指令,wpa_s反馈event通知wifi扫描的结果:
根据实现的一些匹配规则,最后进入handleEvent()函数:
此处event是SCAN_RESULTS,向WifiStateMachine发送SCAN_RESULTS_EVENT消息,告知它扫描已经结束,可以去读取扫描结果了。这样,处理流程就用返回到Wifi状态机中。WifiStateMachine收到此消息后,调用WifiStateMachine::setScanResults()方法从wpa_s读取扫描结果,并向外界发送WifiManager.SCAN_RESULTS_AVAILABLE_ACTION广播通知应用。此时一些注册过该广播的应用,例如手机中的Setting app,就能通过调用WifiManager::getScanResults()读取扫描结果了。至此,一个简单的WifiMonitor分发事件的流程结束,其他类型事件的分发跟此过程相似。
转载地址:http://blog.csdn.net/csdn_of_coder/article/details/51533576
- 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;
- }
- }
- }
- }
- 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;
- }
- }
- /* @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 (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 if (eventName.equals(SCAN_RESULTS_STR))
- event = SCAN_RESULTS;
- /**
- * 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;
- }
- }
转载地址:http://blog.csdn.net/csdn_of_coder/article/details/51533576