织梦CMS - 轻松建站从此开始!

罗索

当前位置: 主页>嵌入式开发>Android>

wifi连接流程分析

落鹤生 发布于 2012-09-18 09:31 点击:次 
这是Android WIFI Setting/Service/Framwork/JNI到wpa_supplicant的详解
TAG:

Wifi 连接部分

当用户选择一个AP时会弹出一个AP参数配置对话框,此对话框会显示当前选择的AP信号强度,若此AP设置了密码则需要用户输入密码才能登录。WifiSettings中的 onPreferenceTreeClick会被调用

  1. @Override 
  2.  
  3. ic boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) { 
  4.  
  5.  //点击AP响应函数 
  6.  
  7. if (preference instanceof AccessPoint) { 
  8.  
  9.     mSelected = (AccessPoint) preference; 
  10.  
  11.     showDialog(mSelected, false); 
  12.  
  13. else if (preference == mAddNetwork) { 
  14.  
  15.     mSelected = null
  16.  
  17.     showDialog(nulltrue); 
  18.  
  19. else if (preference == mNotifyOpenNetworks) { 
  20.  
  21.     Secure.putInt(getContentResolver(), 
  22.  
  23.             Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 
  24.  
  25.             mNotifyOpenNetworks.isChecked() ? 1 : 0); 
  26.  
  27. else { 
  28.  
  29.     return super.onPreferenceTreeClick(screen, preference); 
  30.  
  31.  
  32. return true

用户配置好之后点击连接按钮,onClick函数会被调用。

  1. public void onClick(DialogInterface dialogInterface, int button) 
  2. //点击连接按钮的响应函数 
  3. if (button == WifiDialog.BUTTON_FORGET && mSelected != null) { 
  4. forget(mSelected.networkId); 
  5. else if (button == WifiDialog.BUTTON_SUBMIT && mDialog != null) { 
  6. WifiConfiguration config = mDialog.getConfig(); 
  7.  
  8. if (config == null) { 
  9. if (mSelected != null && !requireKeyStore(mSelected.getConfig())) { 
  10. connect(mSelected.networkId); 
  11. else if (config.networkId != -1) { 
  12. if (mSelected != null) { 
  13. mWifiManager.updateNetwork(config); 
  14. saveNetworks(); 
  15. else { 
  16. int networkId = mWifiManager.addNetwork(config); 
  17. if (networkId != -1) { 
  18. mWifiManager.enableNetwork(networkId, false); 
  19. config.networkId = networkId; 
  20. if (mDialog.edit || requireKeyStore(config)) { 
  21. saveNetworks(); 
  22. else { 
  23. connect(networkId); 

连接请求部分

一.Settings的connect函数响应连接,更新网络保存配置,更新设置当前选择的优先级最高,并保存。然后通过enableNetwork使得其他网络不可用来进行连接。最后调用WifiManager的reconnect函数连接当前选择的网络。

二.WifiManager的reconnect函数通过AIDL的Binder机制,调用WifiService的reconnect函数

三.然后会调用 WifiStateTracker的reconnectCommand函数,通过JNI(android_net_wifi_Wifi)的android_net_wifi_reconnectCommand 函数向WPA_WPASUPPLICANT发送 RECONNECT命令。

四. android_net_wifi_Wifi通过 doCommand(命令名,响应缓冲,响应缓存大小)调用wifi.c中的 wifi_command函数来发送命令。

五.最后通过 wpa_ctrl的wpa_ctrl_request函数向控制通道发送连接命令。

返回请求部分

六.当连接上之后WPA_SUPPLICANT会向控制通道发送连接成功命令。wifi.c的 wifi_wait_for_event函数阻塞调用并返回这个命令的字符串(CONNECTED).

七.而后WifiMonitor会被执行来处理这个事件,WifiMonitor 再调用 WifiStateTracker的notifyStateChange,WifiStateTracker 则接着会往自身发送 EVENT_DHCP_START 消息来启动DHCP 去获取 IP 地址,然后广播NETWORK_STATE_CHANGED_ACTION消息,最后由WifiSettings类来响应,改变状态和界面信息。

关键函数功能介绍

一.connect函数功能

  1.updateNetwork:updateNetwork(config)会将当前选择连接的AP配置信息

   信息传递进去,配置信息有(网络ID等)。如果网络ID为-1则重新添加网络配置,然后向wpa_supplicant 发送SET_NETWORK命令(即通过这个网络ID设置其他一些相关信息,设置SSID,密码等)如果网络配置不为-1则直接执行后面步骤即发送SET_NETWORK命令。

  2.saveNetwork:告诉supplicant保存当前网络配置并更新列表。SaveNetwork会调用WifiService的saveConfiguration向wpa_supplicant发送SAVE_CONFIG命令保存当前网络配置信息,如果返回false,则向wpa_supplicant重新发送RECONFIGURE命令获取配置信息,如果获取信息成功后,会Intent一个  NETWORK_IDS_CHANGED_ACTION事件WifiSettings会注册接受这个 时间并更新列表。

  3.enableNetwork函数,向系统获取接口名并使得该接口有效。由于之前传递的disableOthers为true则向wpa_supplicant发送SELECT_NETWORK(如果传递的为false则发送ENABLE_NETWORK命令),

4.reconnect函数:连接AP

二.reconnect函数功能:connect函数会调用WifiManager的reconnect然后通过Binder机制调用WifiService的reconnect,再由WifiStateTracke调用WifiNative向wpa_supplicant发送RECONNECT命令去连接网络,当连接上wpa_supplicant之后会向控制通道发送连接成功的命令,wifi_wait_for_event函数阻塞等待该事件的发生,并返回这个命令的字符串(CONNECTED)

三.android_net_wifi_Wifi函数的doCommand函数会调用wifi.c的wifi_command函数将上层的命令向wpa_supplicant发送。

四.wifi_wait_for_event函数以阻塞的方式,等待控制通道传递的事件。当有事件传递过来的时候该函数会通过wpa_ctrl的wpa_ctrl_recv函数读取该事件,并以字符串形式返回该事件名。

  1. int wifi_wait_for_event(char *buf, size_t buflen) 
  2.  
  3.  
  4. ....... 
  5.  
  6.     result = wpa_ctrl_recv(monitor_conn, buf, &nread); 
  7.  
  8.     if (result < 0) { 
  9.  
  10.         LOGD("wpa_ctrl_recv failed: %s/n", strerror(errno)); 
  11.  
  12.         strncpy(buf, WPA_EVENT_TERMINATING " - recv error", buflen-1); 
  13.  
  14.         buf[buflen-1] = '/0'
  15.  
  16.         return strlen(buf); 
  17.  
  18.     } 
  19.  
  20.     buf[nread] = '/0'
  21.  
  22.     /* LOGD("wait_for_event: result=%d nread=%d string=/"%s/"/n", result, nread, buf); */ 
  23.  
  24.     /* Check for EOF on the socket */ 
  25.  
  26.     if (result == 0 && nread == 0) { 
  27.  
  28.         /* Fabricate an event to pass up */ 
  29.  
  30.         LOGD("Received EOF on supplicant socket/n"); 
  31.  
  32.         strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1); 
  33.  
  34.         buf[buflen-1] = '/0'
  35.  
  36.         return strlen(buf); 
  37.  
  38.     } 
  39.  
  40.     /* 
  41.  
  42.      * Events strings are in the format 
  43.  
  44.      * 
  45.  
  46.      *     <N>CTRL-EVENT-XXX 
  47.  
  48.      * 
  49.  
  50.      * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG, 
  51.  
  52.      * etc.) and XXX is the event name. The level information is not useful 
  53.  
  54.      * to us, so strip it off. 
  55.  
  56.      */ 
  57.  
  58.     if (buf[0] == '<') { 
  59.  
  60.         char *match = strchr(buf, '>'); 
  61.  
  62.         if (match != NULL) { 
  63.  
  64.             nread -= (match+1-buf); 
  65.  
  66.             memmove(buf, match+1, nread+1); 
  67.  
  68.         } 
  69.  
  70.     } 
  71.  
  72.     return nread; 
  73.  

五.wpa_ctrl_request,通过socket方式向wpa_supplicant发送命令,以select模式阻塞在wpa_supplicant发送和接收。

  1. int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len
  2. char *reply, size_t *reply_len,void(*msg_cb)(char *msg, size_t len)) 
  3.    ....... 
  4.                    res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 
  5.  
  6.                    if (FD_ISSET(ctrl->s, &rfds)) { 
  7.  
  8.                             res = recv(ctrl->s, reply, *reply_len, 0); 
  9.  
  10.                             if (res < 0) 
  11.  
  12.                                      return res; 
  13.  
  14.                             if (res > 0 && reply[0] == '<') { 
  15.  
  16.  /* This is an unsolicited message from 
  17. * wpa_supplicant, not the reply to the 
  18. * request. Use msg_cb to report this to the 
  19. * caller. */ 
  20.  
  21.                                      if (msg_cb) { 
  22.  
  23.  /* Make sure the message is nul* terminated. */ 
  24.  
  25.    if ((size_t) res == *reply_len) 
  26.        res = (*reply_len) - 1; 
  27.        reply[res] = '/0'
  28.        msg_cb(reply, res); 
  29.   } 
  30.  
  31.      continue
  32.  
  33.                             } 
  34.  
  35.                             *reply_len = res; 
  36.  
  37.                             break
  38.  
  39.                    } else { 
  40.  
  41.                             return -2; 
  42.  
  43.                    } 
  44.  
  45.          } 
  46.  
  47.          return 0; 
  48.  

六.WifiMonitor 维护一个监视线程分发处理底层返回上来的事件

  1. void handleEvent(int event, String remainder) {
  2.             switch (event) {
  3.                 case DISCONNECTED:
  4. handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);
  5.                     break;
  6.                 case CONNECTED:
  7. handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);
  8.                     break;
  9.                 case SCAN_RESULTS:
  10. mWifiStateTracker.notifyScanResultsAvailable();
  11.                     break;
  12.                 case UNKNOWN:
  13.                     break;
  14.             }
  15.         }

此时返回的事件是CONNECTED因此 handleNetworkStateChange会被调用,验证一下BSSID,重新获得networkId

,然后调用WifiStateTrackenotifyStateChange通知状态改变了的消息(EVENT_NETWORK_STATE_CHANGED

接着处理这个消息,会移除可用网络通告,然后通过 configureInterface()的动态获取IP地址。最后

发送一个NETWORK_STATE_CHANGED_ACTION IntentWifiSetings注册了此Intent因此会响应该它。由updateConnectionState函数响应。

.updateConnectionState 获取连接信息,更新列表状态,设置为Connected,然后设置当前网络为可用状态

  1. private void updateConnectionState(DetailedState state) { 
  2.  
  3.         /* sticky broadcasts can call this when wifi is disabled */ 
  4.  
  5.         if (!mWifiManager.isWifiEnabled()) { 
  6.  
  7.             mScanner.pause(); 
  8.  
  9.             return
  10.  
  11.         } 
  12.  
  13.   
  14.  
  15.         if (state == DetailedState.OBTAINING_IPADDR) { 
  16.  
  17.             mScanner.pause(); 
  18.  
  19.         } else { 
  20.  
  21.             mScanner.resume(); 
  22.  
  23.         } 
  24.  
  25.   
  26.  
  27.         mLastInfo = mWifiManager.getConnectionInfo(); 
  28.  
  29.         if (state != null) { 
  30.  
  31.             mLastState = state; 
  32.  
  33.         } 
  34.  
  35.   
  36.  
  37.         for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) { 
  38.  
  39. ((AccessPoint) mAccessPoints.getPreference(i)).update(mLastInfo, mLastState); 
  40.  
  41.         } 
  42.  
  43.   
  44.  
  45.         if (mResetNetworks && (state == DetailedState.CONNECTED || 
  46. state == DetailedState.DISCONNECTED || state == DetailedState.FAILED)) { 
  47.  
  48.             updateAccessPoints(); 
  49.  
  50.             enableNetworks(); 
  51.  
  52.         } 
  53.  
  54.     } 

流程图对应的源代码路径为:

 

 WifiEnabler,WifiSettings对应的路径如下: froyo/packages/apps/Settings/src/com/android/settings/

WifiManager,WifiMonitor,WifiStateTracker,WifiNative.对应的源代码路径如下:froyo/frameworrks/base/wifi/java/android/net/wifi/

WifiService 对应代码的位置froyo/frameworks/base/services/java/com/android/server/

android_net_wifi_Wifi源代码路径如下:froyo/frameworks/base/core/jni/

wifi_command,wifi_wait_for_envent源代码路径如下:/hardware/libhardware_legacy/wifi/wifi.c

wpa_ctrl_源代码路径如下:/external/wpa_supplicant/wpa_ctrl.c

wpa_supplicant源代码路径如下:froyo/external/wpa_supplicant/

(liuying_0408)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201209/16271.html]
本文出处:CSDN博客 作者:liuying_0408 原文
顶一下
(2)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容