您的位置:首页 > 其它

wifi连接流程分析

2010-09-12 14:52 543 查看
Wifi 连接部分





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


public
boolean
onPreferenceTreeClick(PreferenceScreen
screen,
Preference
preference)
{


//点击AP响应函数


if
(preference
instanceof
AccessPoint)
{


mSelected
=
(AccessPoint)
preference;


showDialog(mSelected,
false);


}
else
if
(preference
==
mAddNetwork)
{


mSelected
=
null;


showDialog(null,
true);


}
else
if
(preference
==
mNotifyOpenNetworks)
{


Secure.putInt(getContentResolver(),


Secure.WIFI_NETWORKS_***AILABLE_NOTIFICATION_ON,


mNotifyOpenNetworks.isChecked()
?
1
:
0);


}
else
{


return
super.onPreferenceTreeClick(screen,
preference);


}


return
true;


}



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

public
void
onClick(DialogInterface
dialogInterface,
int
button)
{


//点击连接按钮的响应函数


if
(button
==
WifiDialog.BUTTON_FORGET
&&
mSelected
!=
null)
{


forget(mSelected.networkId);


}
else
if
(button
==
WifiDialog.BUTTON_SUBMIT
&&
mDialog
!=
null)
{


WifiConfiguration
config
=
mDialog.getConfig();




if
(config
==
null)
{


if
(mSelected
!=
null
&&
!requireKeyStore(mSelected.getConfig()))
{


connect(mSelected.networkId);


}


}
else
if
(config.networkId
!=
-1)
{


if
(mSelected
!=
null)
{


mWifiManager.updateNetwork(config);


saveNetworks();


}


}
else
{


int
networkId
=
mWifiManager.addNetwork(config);


if
(networkId
!=
-1)
{


mWifiManager.enableNetwork(networkId,
false);


config.networkId
=
networkId;


if
(mDialog.edit
||
requireKeyStore(config))
{


saveNetworks();


}
else
{


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发送S***E_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函数读取该事件,并以字符串形式返回该事件名。

int wifi_wait_for_event(char
*buf, size_t buflen)

{


.......


result = wpa_ctrl_recv(monitor_conn, buf, &nread);


if (result < 0) {


LOGD("wpa_ctrl_recv failed: %s/n", strerror(errno));


strncpy(buf, WPA_EVENT_TERMINATING
" - recv error", buflen-1);


buf[buflen-1] = '/0';


return strlen(buf);


}


buf[nread] = '/0';


/* LOGD("wait_for_event: result=%d
nread=%d string=/"%s/"/n", result,
nread,
buf); */


/* Check for EOF on the socket */


if (result == 0 && nread == 0) {


/* Fabricate an event to pass up */


LOGD("Received EOF on
supplicant socket/n");


strncpy(buf, WPA_EVENT_TERMINATING
" - signal 0 received", buflen-1);


buf[buflen-1] = '/0';


return strlen(buf);


}


/*


* Events strings are in the format


*


* <N>CTRL-EVENT-XXX


*


* where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,


* etc.) and XXX is the event name. The level information is not useful


* to us, so strip it off.


*/


if (buf[0] ==
'<') {


char *match = strchr(buf,
'>');


if (match != NULL) {


nread -= (match+1-buf);


memmove(buf, match+1, nread+1);


}


}


return nread;

}



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

wpa_supplicant发送和接收。

int wpa_ctrl_request(struct
wpa_ctrl *ctrl, const
char *cmd, size_t cmd_len,char
*reply, size_t *reply_len,void (*msg_cb)(char
*msg, size_t len))

{


.......


res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);


if (FD_ISSET(ctrl->s, &rfds)) {


res = recv(ctrl->s, reply, *reply_len, 0);


if (res < 0)


return res;


if (res > 0 && reply[0] ==
'<') {


/* This is an unsolicited message from


* wpa_supplicant, not the reply to the


* request. Use msg_cb to report this to the


* caller. */


if (msg_cb) {


/* Make sure the message is
nul


* terminated. */


if ((size_t) res == *reply_len)


res = (*reply_len) - 1;


reply[res] = '/0';


msg_cb(reply, res);


}


continue;


}


*reply_len = res;


break;


} else {


return -2;


}


}


return 0;

}



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

void
handleEvent(int
event,
String
remainder)
{


switch
(event)
{


case
DISCONNECTED:


handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED,
remainder);


break;


case
CONNECTED:


handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,
remainder);


break;


case
SCAN_RESULTS:


mWifiStateTracker.notifyScanResultsAvailable();


break;


case
UNKNOWN:


break;


}


}

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

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

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

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

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




private
void
updateConnectionState(DetailedState
state)
{


/* sticky broadcasts can call this when
wifi is disabled */


if
(!mWifiManager.isWifiEnabled())
{


mScanner.pause();


return;


}




if
(state
==
DetailedState.OBTAINING_IPADDR)
{


mScanner.pause();


}
else
{


mScanner.resume();


}




mLastInfo
=
mWifiManager.getConnectionInfo();


if
(state
!=
null)
{


mLastState
=
state;


}




for
(int
i
=
mAccessPoints.getPreferenceCount()
-
1;
i
>=
0;
--i)
{


((AccessPoint)
mAccessPoints.getPreference(i)).update(mLastInfo,
mLastState);


}




if
(mResetNetworks
&&
(state
==
DetailedState.CONNECTED
||


state
==
DetailedState.DISCONNECTED
||
state
==
DetailedState.FAILED))
{


updateAccessPoints();


enableNetworks();


}


}





流程图对应的源代码路径为:
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/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: