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_AVAILABLE_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發送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函數讀取該事件,並以字符串形式返回該事件名。
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/