Android -- WifiMonitor分析


Android -- WifiMonitor


在Android的Wifi体系中,WifiMonitor承担着分发来自wpa_supplicant底层事件的任务。当上层下达Wifi的扫描、连接等指令后, 底层驱动以及wpa_s进行实际的扫描、连接操作,操作完成后会向上层反馈一个event,通知framework扫描是否结束、连接是否成功。WifiStateMachine在处理CMD_START_SUPPLICANT消息时,会执行驱动加载、启动wpa_s等操作:
[java] view plain copy
  1. case CMD_START_SUPPLICANT:  
  2.        if (mWifiNative.loadDriver()) {  
  3.            try {  
  4.                mNwService.wifiFirmwareReload(mInterfaceName, "STA");  
  5.            } catch (Exception e) {  
  6.                loge("Failed to reload STA firmware " + e);  
  7.                // Continue  
  8.            }  
  9.   
  10.            try {  
  11.                // A runtime crash can leave the interface up and  
  12.                // IP addresses configured, and this affects  
  13.                // connectivity when supplicant starts up.  
  14.                // Ensure interface is down and we have no IP  
  15.                // addresses before a supplicant start.  
  16.                mNwService.setInterfaceDown(mInterfaceName);  
  17.                mNwService.clearInterfaceAddresses(mInterfaceName);  
  18.   
  19.                // Set privacy extensions  
  20.                mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);  
  21.   
  22.                // IPv6 is enabled only as long as access point is connected since:  
  23.                // - IPv6 addresses and routes stick around after disconnection  
  24.                // - kernel is unaware when connected and fails to start IPv6 negotiation  
  25.                // - kernel can start autoconfiguration when 802.1x is not complete  
  26.                mNwService.disableIpv6(mInterfaceName);  
  27.            } catch (RemoteException re) {  
  28.                loge("Unable to change interface settings: " + re);  
  29.            } catch (IllegalStateException ie) {  
  30.                loge("Unable to change interface settings: " + ie);  
  31.            }  
  32.   
  33.           /* Stop a running supplicant after a runtime restart 
  34.            * Avoids issues with drivers that do not handle interface down 
  35.            * on a running supplicant properly. 
  36.            */  
  37.            mWifiMonitor.killSupplicant(mP2pSupported);  
  38.   
  39.            if (WifiNative.startHal() == false) {  
  40.                /* starting HAL is optional */  
  41.                loge("Failed to start HAL");  
  42.            }  
  43.   
  44.            if (mWifiNative.startSupplicant(mP2pSupported)) {  
  45.                setWifiState(WIFI_STATE_ENABLING);  
  46.                if (DBG) log("Supplicant start successful");  
  47.                mWifiMonitor.startMonitoring();  
  48.                transitionTo(mSupplicantStartingState);  
  49.            } else {  
  50.                loge("Failed to start supplicant!");  
  51.            }  
  52.        } else {  
  53.            loge("Failed to load driver");  
  54.        }  
  55.        break;  
同时调用WifiMonitor::startMonitoring()来开启WifiMonitor进程。启动WifiMonitor,间接调用内部类WifiMonitorSingleton::startMonitoring()方法:
[java] view plain copy
  1. public synchronized void startMonitoring(String iface) {  
  2.            WifiMonitor m = mIfaceMap.get(iface);  
  3.            if (m == null) {  
  4.                Log.e(TAG, "startMonitor called with unknown iface=" + iface);  
  5.                return;  
  6.            }  
  7.   
  8.            Log.d(TAG, "startMonitoring(" + iface + ") with mConnected = " + mConnected);  
  9.   
  10.            if (mConnected) {  
  11.                m.mMonitoring = true;  
  12.                m.mStateMachine.sendMessage(SUP_CONNECTION_EVENT);  
  13.            } else {  
  14.                if (DBG) Log.d(TAG, "connecting to supplicant");  
  15.                int connectTries = 0;  
  16.                while (true) {  
  17.                    if (mWifiNative.connectToSupplicant()) {  
  18.                        m.mMonitoring = true;  
  19.                        m.mStateMachine.sendMessage(SUP_CONNECTION_EVENT);  
  20.                        mConnected = true;  
  21.                        new MonitorThread(mWifiNative, this).start();  
  22.                        break;  
  23.                    }  
  24.                    if (connectTries++ < 5) {  
  25.                        try {  
  26.                            Thread.sleep(1000);  
  27.                        } catch (InterruptedException ignore) {  
  28.                        }  
  29.                    } else {  
  30.                        m.mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);  
  31.                        Log.e(TAG, "startMonitoring(" + iface + ") failed!");  
  32.                        break;  
  33.                    }  
  34.                }  
  35.            }  
  36.        }  
为了监听wpa_supplicant的事件,需要先建立与wpa_s的消息通道,这一步调用WifiNative.connectToSupplicant()实现。
如果是第一次进行监听mConnected为false,进入else分支。先建立与wpa_s的消息通道,建立成功后会向WifiStateMachine发送SUP_CONNECTION_EVENT消息,通知Wifi状态机。随后,开启事件监听线程:new MonitorThread(mWifiNative, this).start():
[java] view plain copy
  1. private static class MonitorThread extends Thread {  
  2.         private final WifiNative mWifiNative;  
  3.         private final WifiMonitorSingleton mWifiMonitorSingleton;  
  4.         private final LocalLog mLocalLog = WifiNative.getLocalLog();  
  5.   
  6.         public MonitorThread(WifiNative wifiNative, WifiMonitorSingleton wifiMonitorSingleton) {  
  7.             super("WifiMonitor");  
  8.             mWifiNative = wifiNative;  
  9.             mWifiMonitorSingleton = wifiMonitorSingleton;  
  10.         }  
  11.   
  12.         public void run() {  
  13.             if (DBG) {  
  14.                 Log.d(TAG, "MonitorThread start with mConnected=" +  
  15.                      mWifiMonitorSingleton.mConnected);  
  16.             }  
  17.             //noinspection InfiniteLoopStatement  
  18.             for (;;) {  
  19.                 if (!mWifiMonitorSingleton.mConnected) {  
  20.                     if (DBG) Log.d(TAG, "MonitorThread exit because mConnected is false");  
  21.                     break;  
  22.                 }  
  23.                 String eventStr = mWifiNative.waitForEvent();  
  24.   
  25.                 // Skip logging the common but mostly uninteresting events  
  26.                 if (eventStr.indexOf(BSS_ADDED_STR) == -1  
  27.                         && eventStr.indexOf(BSS_REMOVED_STR) == -1) {  
  28.                     if (DBG) Log.d(TAG, "Event [" + eventStr + "]");  
  29.                     mLocalLog.log("Event [" + eventStr + "]");  
  30.                 }  
  31.   
  32.                 if (mWifiMonitorSingleton.dispatchEvent(eventStr)) {  
  33.                     if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events");  
  34.                     break;  
  35.                 }  
  36.             }  
  37.         }  
  38.     }  
这里有两个重要函数:调用WifiNative.waitForEvent()接受来自wpa_s的事件;调用WifiMonitorSingleton.dispatchEvent(eventStr)分发来自wpa_s的底层event:
[java] view plain copy
  1. private synchronized boolean dispatchEvent(String eventStr) {  
  2.      String iface;  
  3.      // IFNAME=wlan0 ANQP-QUERY-DONE addr=18:cf:5e:26:a4:88 result=SUCCESS  
  4.      if (eventStr.startsWith("IFNAME=")) {  
  5.          int space = eventStr.indexOf(' ');  
  6.          if (space != -1) {  
  7.              iface = eventStr.substring(7, space);  
  8.              if (!mIfaceMap.containsKey(iface) && iface.startsWith("p2p-")) {  
  9.                  // p2p interfaces are created dynamically, but we have  
  10.                  // only one P2p state machine monitoring all of them; look  
  11.                  // for it explicitly, and send messages there ..  
  12.                  iface = "p2p0";  
  13.              }  
  14.              eventStr = eventStr.substring(space + 1);  
  15.          } else {  
  16.              // No point dispatching this event to any interface, the dispatched  
  17.              // event string will begin with "IFNAME=" which dispatchEvent can't really  
  18.              // do anything about.  
  19.              Log.e(TAG, "Dropping malformed event (unparsable iface): " + eventStr);  
  20.              return false;  
  21.          }  
  22.      } else {  
  23.          // events without prefix belong to p2p0 monitor  
  24.          iface = "p2p0";  
  25.      }  
  26.   
  27.      if (VDBG) Log.d(TAG, "Dispatching event to interface: " + iface);  
  28.   
  29.      WifiMonitor m = mIfaceMap.get(iface);  
  30.      if (m != null) {  
  31.          if (m.mMonitoring) {  
  32.              if (m.dispatchEvent(eventStr, iface)) {  
  33.                  mConnected = false;  
  34.                  return true;  
  35.              }  
  36.   
  37.              return false;  
  38.          } else {  
  39.              if (DBG) Log.d(TAG, "Dropping event because (" + iface + ") is stopped");  
  40.              return false;  
  41.          }  
  42.      } else {  
  43.          if (DBG) Log.d(TAG, "Sending to all monitors because there's no matching iface");  
  44.          boolean done = false;  
  45.          boolean isMonitoring = false;  
  46.          boolean isTerminating = false;  
  47.          if (eventStr.startsWith(EVENT_PREFIX_STR)  
  48.                  && eventStr.contains(TERMINATING_STR)) {  
  49.              isTerminating = true;  
  50.          }  
  51.          for (WifiMonitor monitor : mIfaceMap.values()) {  
  52.              if (monitor.mMonitoring) {  
  53.                  isMonitoring = true;  
  54.                  if (monitor.dispatchEvent(eventStr, iface)) {  
  55.                      done = true;  
  56.                  }  
  57.              }  
  58.          }  
  59.   
  60.          if (!isMonitoring && isTerminating) {  
  61.              done = true;  
  62.          }  
  63.   
  64.          if (done) {  
  65.              mConnected = false;  
  66.          }  
  67.   
  68.          return done;  
  69.      }  
  70.  }  
解析eventStr,调用相应interface的WifiMonitor::dispatchEvent()方法分发具体的事件给WifiStateMachine处理:
[java] view plain copy
  1.  /* @return true if the event was supplicant disconnection */  
  2.     private boolean dispatchEvent(String eventStr, String iface) {  
  3.   
  4.         if (DBG) {  
  5.             // Dont log CTRL-EVENT-BSS-ADDED which are too verbose and not handled  
  6.             if (eventStr != null && !eventStr.contains("CTRL-EVENT-BSS-ADDED")) {  
  7.                 logDbg("WifiMonitor:" + iface + " cnt=" + Integer.toString(eventLogCounter)  
  8.                         + " dispatchEvent: " + eventStr);  
  9.             }  
  10.         }  
  11.   
  12.         if (!eventStr.startsWith(EVENT_PREFIX_STR)) {  
  13.             if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&  
  14.                     0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) {  
  15.                mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT, eventLogCounter);  
  16.             } else if (eventStr.startsWith(WPS_SUCCESS_STR)) {  
  17.                 mStateMachine.sendMessage(WPS_SUCCESS_EVENT);  
  18.             } else if (eventStr.startsWith(WPS_FAIL_STR)) {  
  19.                 handleWpsFailEvent(eventStr);  
  20.             } else if (eventStr.startsWith(WPS_OVERLAP_STR)) {  
  21.                 mStateMachine.sendMessage(WPS_OVERLAP_EVENT);  
  22.             } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {  
  23.                 mStateMachine.sendMessage(WPS_TIMEOUT_EVENT);  
  24.             } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {  
  25.                 handleP2pEvents(eventStr);  
  26.             } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {  
  27.                 handleHostApEvents(eventStr);  
  28.             } else if (eventStr.startsWith(ANQP_DONE_STR)) {  
  29.                 try {  
  30.                     handleAnqpResult(eventStr);  
  31.                 }  
  32.                 catch (IllegalArgumentException iae) {  
  33.                     Log.e(TAG, "Bad ANQP event string: '" + eventStr + "': " + iae);  
  34.                 }  
  35.             } else if (eventStr.startsWith(GAS_QUERY_PREFIX_STR)) {        // !!! clean >>End  
  36.                 handleGasQueryEvents(eventStr);  
  37.             } else if (eventStr.startsWith(RX_HS20_ANQP_ICON_STR)) {  
  38.                 if (mStateMachine2 != null)  
  39.                     mStateMachine2.sendMessage(RX_HS20_ANQP_ICON_EVENT,  
  40.                             eventStr.substring(RX_HS20_ANQP_ICON_STR_LEN + 1));  
  41.             } else if (eventStr.startsWith(HS20_PREFIX_STR)) {                  // !!! <  
  42.                 handleHs20Events(eventStr);  
  43.             } else if (eventStr.startsWith(REQUEST_PREFIX_STR)) {  
  44.                 handleRequests(eventStr);  
  45.             } else if (eventStr.startsWith(TARGET_BSSID_STR)) {  
  46.                 handleTargetBSSIDEvent(eventStr);  
  47.             } else if (eventStr.startsWith(ASSOCIATED_WITH_STR)) {  
  48.                 handleAssociatedBSSIDEvent(eventStr);  
  49.             } else if (eventStr.startsWith(AUTH_EVENT_PREFIX_STR) &&  
  50.                     eventStr.endsWith(AUTH_TIMEOUT_STR)) {  
  51.                 mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);  
  52.             } else {  
  53.                 if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr);  
  54.             }  
  55.             eventLogCounter++;  
  56.             return false;  
  57.         }  
  58.   
  59.         String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);  
  60.         int nameEnd = eventName.indexOf(' ');  
  61.         if (nameEnd != -1)  
  62.             eventName = eventName.substring(0, nameEnd);  
  63.         if (eventName.length() == 0) {  
  64.             if (DBG) Log.i(TAG, "Received wpa_supplicant event with empty event name");  
  65.             eventLogCounter++;  
  66.             return false;  
  67.         }  
  68.         /* 
  69.         * Map event name into event enum 
  70.         */  
  71.         int event;  
  72.         if (eventName.equals(CONNECTED_STR))  
  73.             event = CONNECTED;  
  74.         else if (eventName.equals(DISCONNECTED_STR))  
  75.             event = DISCONNECTED;  
  76.         else if (eventName.equals(STATE_CHANGE_STR))  
  77.             event = STATE_CHANGE;  
  78.         else if (eventName.equals(SCAN_RESULTS_STR))  
  79.             event = SCAN_RESULTS;  
  80.         else if (eventName.equals(SCAN_FAILED_STR))  
  81.             event = SCAN_FAILED;  
  82.         else if (eventName.equals(LINK_SPEED_STR))  
  83.             event = LINK_SPEED;  
  84.         else if (eventName.equals(TERMINATING_STR))  
  85.             event = TERMINATING;  
  86.         else if (eventName.equals(DRIVER_STATE_STR))  
  87.             event = DRIVER_STATE;  
  88.         else if (eventName.equals(EAP_FAILURE_STR))  
  89.             event = EAP_FAILURE;  
  90.         else if (eventName.equals(ASSOC_REJECT_STR))  
  91.             event = ASSOC_REJECT;  
  92.         else if (eventName.equals(TEMP_DISABLED_STR)) {  
  93.             event = SSID_TEMP_DISABLE;  
  94.         } else if (eventName.equals(REENABLED_STR)) {  
  95.             event = SSID_REENABLE;  
  96.         } else if (eventName.equals(BSS_ADDED_STR)) {  
  97.             event = BSS_ADDED;  
  98.         } else if (eventName.equals(BSS_REMOVED_STR)) {  
  99.             event = BSS_REMOVED;  
  100.         } else  
  101.             event = UNKNOWN;  
  102.   
  103.         String eventData = eventStr;  
  104.         if (event == DRIVER_STATE || event == LINK_SPEED)  
  105.             eventData = eventData.split(" ")[1];  
  106.         else if (event == STATE_CHANGE || event == EAP_FAILURE) {  
  107.             int ind = eventStr.indexOf(" ");  
  108.             if (ind != -1) {  
  109.                 eventData = eventStr.substring(ind + 1);  
  110.             }  
  111.         } else {  
  112.             int ind = eventStr.indexOf(" - ");  
  113.             if (ind != -1) {  
  114.                 eventData = eventStr.substring(ind + 3);  
  115.             }  
  116.         }  
  117.   
  118.         if ((event == SSID_TEMP_DISABLE)||(event == SSID_REENABLE)) {  
  119.             String substr = null;  
  120.             int netId = -1;  
  121.             int ind = eventStr.indexOf(" ");  
  122.             if (ind != -1) {  
  123.                 substr = eventStr.substring(ind + 1);  
  124.             }  
  125.             if (substr != null) {  
  126.                 String status[] = substr.split(" ");  
  127.                 for (String key : status) {  
  128.                     if (key.regionMatches(0"id="03)) {  
  129.                         int idx = 3;  
  130.                         netId = 0;  
  131.                         while (idx < key.length()) {  
  132.                             char c = key.charAt(idx);  
  133.                             if ((c >= 0x30) && (c <= 0x39)) {  
  134.                                 netId *= 10;  
  135.                                 netId += c - 0x30;  
  136.                                 idx++;  
  137.                             } else {  
  138.                                 break;  
  139.                             }  
  140.                         }  
  141.                     }  
  142.                 }  
  143.             }  
  144.             mStateMachine.sendMessage((event == SSID_TEMP_DISABLE)?  
  145.                     SSID_TEMP_DISABLED:SSID_REENABLED, netId, 0, substr);  
  146.         } else if (event == STATE_CHANGE) {  
  147.             handleSupplicantStateChange(eventData);  
  148.         } else if (event == DRIVER_STATE) {  
  149.             handleDriverEvent(eventData);  
  150.         } else if (event == TERMINATING) {  
  151.             /** 
  152.              * Close the supplicant connection if we see 
  153.              * too many recv errors 
  154.              */  
  155.             if (eventData.startsWith(WPA_RECV_ERROR_STR)) {  
  156.                 if (++sRecvErrors > MAX_RECV_ERRORS) {  
  157.                     if (DBG) {  
  158.                         Log.d(TAG, "too many recv errors, closing connection");  
  159.                     }  
  160.                 } else {  
  161.                     eventLogCounter++;  
  162.                     return false;  
  163.                 }  
  164.             }  
  165.   
  166.             // Notify and exit  
  167.             mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT, eventLogCounter);  
  168.             return true;  
  169.         } else if (event == EAP_FAILURE) {  
  170.             if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) {  
  171.                 logDbg("WifiMonitor send auth failure (EAP_AUTH_FAILURE) ");  
  172.                 mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT, eventLogCounter);  
  173.             }  
  174.         } else if (event == ASSOC_REJECT) {  
  175.             Matcher match = mAssocRejectEventPattern.matcher(eventData);  
  176.             String BSSID = "";  
  177.             int status = -1;  
  178.             if (!match.find()) {  
  179.                 if (DBG) Log.d(TAG, "Assoc Reject: Could not parse assoc reject string");  
  180.             } else {  
  181.                 BSSID = match.group(1);  
  182.                 try {  
  183.                     status = Integer.parseInt(match.group(2));  
  184.                 } catch (NumberFormatException e) {  
  185.                     status = -1;  
  186.                 }  
  187.             }  
  188.             mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT, eventLogCounter, status, BSSID);  
  189.         } else if (event == BSS_ADDED && !VDBG) {  
  190.             // Ignore that event - it is not handled, and dont log it as it is too verbose  
  191.         } else if (event == BSS_REMOVED && !VDBG) {  
  192.             // Ignore that event - it is not handled, and dont log it as it is too verbose  
  193.         }  else {  
  194.                 handleEvent(event, eventData);  
  195.         }  
  196.         sRecvErrors = 0;  
  197.         eventLogCounter++;  
  198.         return false;  
  199. }  
这里我们假设事先下发的是一个wifi扫描的指令,wpa_s反馈event通知wifi扫描的结果:
[java] view plain copy
  1. else if (eventName.equals(SCAN_RESULTS_STR))  
  2.             event = SCAN_RESULTS;  
根据实现的一些匹配规则,最后进入handleEvent()函数:
[java] view plain copy
  1. /** 
  2.  * Handle all supplicant events except STATE-CHANGE 
  3.  * @param event the event type 
  4.  * @param remainder the rest of the string following the 
  5.  * event name and " — " 
  6.  */  
  7. void handleEvent(int event, String remainder) {  
  8.     if (DBG) {  
  9.         logDbg("handleEvent " + Integer.toString(event) + "  " + remainder);  
  10.     }  
  11.     switch (event) {  
  12.         case DISCONNECTED:  
  13.             handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);  
  14.             break;  
  15.   
  16.         case CONNECTED:  
  17.             handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);  
  18.             break;  
  19.   
  20.         case SCAN_RESULTS:  
  21.             mStateMachine.sendMessage(SCAN_RESULTS_EVENT);  
  22.             break;  
  23.   
  24.         case SCAN_FAILED:  
  25.             mStateMachine.sendMessage(SCAN_FAILED_EVENT);  
  26.             break;  
  27.   
  28.         case UNKNOWN:  
  29.             if (DBG) {  
  30.                 logDbg("handleEvent unknown: " + Integer.toString(event) + "  " + remainder);  
  31.             }  
  32.             break;  
  33.         default:  
  34.             break;  
  35.     }  
  36. }  
此处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

你可能感兴趣的:(andoroid源码分析)