一. Android wifi框架圖
Android WIFI系統引入了wpa_supplicant,它的整個WIFI系統以wpa_supplicant為核心來定義上層介面和下層驅動介面,Android WIFI主要分為六大層,分別是WiFi Settings層,Wifi Framework層,Wifi JNI 層, Wifi HardWare 層, Wpa_supplicant 層和 Wifi Kernel 層,

圖1.1 Android WIFI 系統架構
Wifi Settings層 ------> Java應用層
Wifi Framework層 ------> Java框架層
Wifi JNI層 ------> C框架層
Wifi HardWare層 ------> C框架層
Wpa_supplicant層 ------> C框架層
Wifi Kernel層 ------> 內核空間
下面對上圖的部分做出分析:
1.1 Wifi Service
由SystemServer啟動的時候生成的ConnecttivityService創建,負責啟動關閉wpa_supplicant,啟動和關閉WifiMonitor執行緒,把命令下發給wpa_supplicant以及更新WIFI的狀態,處理其它模塊通過WifiManager介面發送過來的遠端WiFi操作,
1.2 WifiMonitor
負責從wpa_supplicant接收事件通知,
1.3 wpa_supplicant
1)讀取組態檔
2)初始化配置引數
3)讓驅動scan當前所有的bssid
4)檢查掃描的引數是否和用戶設定的相符
5)如果相符,通知驅動進行權限和認證操作
6)連上AP
注意:
AP(Access Point),也就是無線接入點,是一個無線網路的創建者,是網路的中心節點,俗稱“熱點”,無線網路中的無線交換機,它是使用無線設備(手機等移動設備和筆記本電腦等無線設備)用戶進入有線網路的接入點,大多數無線AP還帶有接入點客戶端模式(AP client),可以和其它AP進行無線連接,延展網路的覆寫范圍,

1.4 Wifi 驅動模塊
廠商提供的source,主要進行load firware和kernel的wireless進行通信
1.5 Wifi 電源管理模塊
主要控制硬體的GPIO和上下電,讓CPU和Wifi模組之間通過sdio介面或者USB介面通信,
1.6 Wifi 作業步驟
1)Wifi 啟動
2)開始掃描
3)顯示掃描的AP
4)配置AP
5)連接AP
6)獲取IP地址
7)上網
二. Android Wifi 原始碼架構
1. Wifi Settings層
//代碼目錄
packages/apps/Settings/src/com/android/settings/wifi/
主要的類:
WifiSettings.java : 負責顯示 Wifi 的設定界面
WifiEnabler.java : 負責 Wifi 的開關邏輯
WifiDialog.java : 負責Wifi的對話框
WifiDInfo.java : 表示Wifi 的相關配置資訊
2. Wifi Framework 層
//代碼目錄
frameworks/base/wifi/Java/android/net/wifi/
frameworks/base/core/java/android/net/
frameworks/opt/net/wifi/service/java/com/android/server/wifi
主要的類:
WifiManager : 它是 Wifi 模塊向外部應用透漏出來的介面,其它所有應用都可以通過WiFi Manager 來操作Wifi 的各項功能,當時WifiManager 本身不具備處理請求的能力,而是把所有的請求轉發給WifiServicelmpl 來處理,
WifiService : Java Framework中 Wifi 功能的總入口,負責 Wifi 功能的核心業務,它是服務器端的實作,作為 Wifi 部分的核心,處理實際的驅動加載、掃描、鏈接、斷開等命令,以及底層上報的事件,對于主動的命令控制,Wifi 是一個簡單的封裝,針對來自客戶端的控制命令,呼叫相應的WifiNative底層實作,
WifiServicelmpl : 本身也不具備處理請求的能力,而是將請求分類后交給不同的處理者處理,比如WifiStateMachine,
WifiStateMachine : 它是一個復雜的狀態機,維護了Wifi的啟動、掃描、連接、斷開等多個狀態,它運行自己獨有的執行緒中,擁有自己的訊息佇列,
WifiState Tracker : 除了負責Wifi 的電源管理模式等功能外,其核心是WifiMonitor所實作的事件輪詢機制,以及訊息處理函式handleMessage(),
WifiMonitor : 專門負責接收來自wpa_supplicant的事件,并將這些資訊進行分類再交予StateMachine處理,
WifiNative :一個介面類,主要是提供一些native方法用于wifi framework層和 WPAS 通信,WifiNative 的主要實作都在 wifi.c 函式里,WifiNative 僅是將其封裝,給framework層呼叫,
注意:WifiService 和 WifiMonitor 是整個模塊的核心,WifiService 負責啟動關閉wpa_supplicant,啟動關閉WifiMonitor監視執行緒和把命令下發給wpa_supplicant,而WifiMonitor則負責從wpa_supplicant接收事件通知,
也就是說Wifiservice負責wifi整個流程的控制,而WifiMonitor負責監視底層的事件,
3. Wifi JNI 層
//代碼目錄
frameworks/base/core/jni/android_net_wifi_Wifi.cpp
android_net_wifi_Wifi.cpp就是典型jni介面,通過它可以直接呼叫Wifi的硬體抽象層,
4. Wifi Hardware 層(wifi管理庫)
//代碼目錄
hardware/libhardware_legacy/wifi/wifi.c
Wifi Hardware 層也被稱為wpa_supplicant適配層,是通用wpa_supplicant的封裝,wpa_supplicant適配層起著承上啟下的作用,主要用于和wpa_supplicant守護行程的通信,以供給Wifi框架層使用,
5. wpa_supplicant層(wifi tool)
//代碼目錄
external/wpa_supplicant/
wpa_supplicant是一個開源專案,已經移植到Linux、Windows以及其它嵌入式系統上,它是WPA(WiFi Protected Access,Wifi 網路安全存取)的應用層認證客戶端,負責完成認證相關的登錄、加密等作業,該層是Wifi Framework層的基石,也叫Wifi 服務層,
經過編譯后主要結果是生成動態庫libwpa_client.so和可執行程式wpa_supplicant,
1)wpa_client (生成庫libwpaclient.so)
external/wpa_supplicant_8/wpa_supplicant/src/common/wpa_ctrl.c
2) wpa_server (生成守護行程wpa_supplicant)
external/wpa_supplicant_8/wpa_supplicant/main.c
6. Wifi Kernel 層
//代碼目錄
kernel/drivers/net/wireless
三. WifiService 和 wpa_supplicant啟動流程

圖 3.1 WifiService 和 wpa_supplicant啟動流程
狀態變化
加載wifi驅動的狀態變化流程如下:
mInitialState(初始狀態)
|
mDriverUnloadedState
|
mWaitForP2pDisableState
|
mDriverLoadingState(其enter中呼叫WifiNative.loadDriver)
啟動wpa_supplicant的狀態變化如下:
在DriverLoadedState狀態的processMessage中呼叫WifiNative.startSupplicant
生產時自動打開Wifi
在生產時, 默認Wifi是關閉的,如果需要默認打開,可修改wifiservice.java中的如下代碼:
/**
* Check if Wi-Fi needs to be enabled and start
* if needed
*
* This function is used only at boot time
*/
public void checkAndStartWifi() {
mAirplaneModeOn.set(isAirplaneModeOn());
mPersistWifiState.set(getPersistedWifiState());
/* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
Slog.i(TAG, "WifiService starting up with Wi-Fi " +
(wifiEnabled ? "enabled" : "disabled"));
setWifiEnabled(wifiEnabled); //強制設定為true
mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
makeWifiWatchdogStateMachine(mContext);
}
四. wpa_supplicant
wpa_supplicant是一個開源軟體源專案,它實作了Station對無線網路進行管理和控制的功能,wpa_supplicant支持的功能非常多,下面列舉幾個重要的功能,
- 支持WPA和IEEE 802.11i定義的大部分功能,
1)支持WPA—PSK(WPA-Personal)和WPA-Enterprise(利用RAIDUS認證服務器來完成身份認證的情況)
2)資料加密方面支持CCMP,TKIP,WEP104和WER40,其中,WEP104和WEP40中的數字代表密鑰的長度,
3)完全支持WPA和WPA2,包括PMKSA快取,預認證(pre-authentication)等功能
4)完全支持IEEE 802.11r和802.11w,其中802.11r規范定義了快速基礎服務轉移功能,而802.11w新增對了對管理幀的安全保護機制,
5)支持WFA制定的WIFI protected Setup功能,P2P,TDLS等,
-
支持多種EAP Method,
主要和802.1X中的Supplicant的功能有關,wpa_supplicant支持多達25種EAP Method,包括以下EAP-TLS,EAP-PEAP,EAP-TTLS和EAP-SIM、EAP-PSK、EAP-GPSK等其他認證方法, -
對各種無線網卡和驅動的支持,
1)支持nl80211/cfg80211驅動和Linux Wireless Extension驅動,
2)支持Windows平臺中的NDIS驅動,
wpa_supplicant包含三個主要子目錄,如下:
1)hostapd:當手機進入Soft AP模式時,手機扮演AP的角色,需要hostapd來提供AP功能,
2)wpa_supplicant:Station模式,也叫Managed模式(重點)
3)src:hostapd和wpa_supplicant中都包含了一些通用的資料結構和處理方法,這些內容都放在src目錄中,
wpa_supplicant是Android用戶空間中無線網路部分的核心模塊,所有Framework層中和WIFI相關的操作最終都由wpa_supplicant來完成,
五. wpa_supplicant架構
wpa_supplicant是比較龐大的開源軟體專案,內部模塊結構如圖:

圖 5.1 wpa_supplicant軟體架構
1)WPAS所有作業都圍繞事件(event loop模塊)展開,它是基于事件驅動的,事件驅動和訊息驅動類似,主執行緒等待事件的發生并處理它們,
2)位于event loop模塊下方的driver interface介面模塊用于隔離和底層驅動直接互動的那些driver控制模塊(wext、ndiswrapper等,WPAS中稱為driver wrapper)
3)dirver wrapper經常回傳一些資訊給上層,
六. wpa_supplicant命令和控制API
WPAS對外通過控制介面模塊與客戶端通信,在Android平臺中,WPAS的客戶端是位于Framework中的WifiService,用戶在Settings界面進行WiFi相關的操作最終都會經由WifiService通過發送命令的方式轉交給wpa_supplicant去執行,
1. 命令
WPAS定義了許多命令,
PING:心跳檢測命令,客戶端用它判斷WPAS是否作業正常,WPAS收到"PING"命令后需要回復"PONG",
MIB:客戶端用該命令獲取設備的MIB資訊,
STATUS:客戶端用該命令獲取設備的MIB資訊,
ADD_NETWORK:為WPAS添加一個新的無線網路,它將回傳此新無線網路的ID
SET_NETWORK:network id是無線網路的ID,此命令用于設定指定無線網路的資訊,其中variable為引數名,value為引數的值,
ENABLE_NETWORK: 使能某個無線網路,此命令最終將促使WPAS發起一系列操作以加入該無線網路,
除了接收來自client的命令外,WPAS也會主動給client發送命令,
2. 控制API
Android平臺中wifiService是WPAS的客戶端,它和WPAS互動時必須使用wpa_supplicant提供的API,這些API宣告于wpa_ctrl.h中,用法如下:
//必須包含此頭檔案,鏈接時需要包含libwpa_client.so動態庫,
#include "wpa_ctrl.h"
客戶端使用wpa_ctrl時首先要分配控制物件,下面兩個API用于創建和銷毀控制物件wpa_ctrl,
//創建一個wpa控制端物件wpa_ctrl,Android平臺中,引數ctrl——path代表unix域socket的位置
struct wpa_ctrl *wpa_ctrl_open(const char *ctrl_path);
//注銷wpa_ctrl控制物件
void wpa_ctrl_close(struct wpa_ctrl *ctrl);
下面這個函式用于發送命令給WAPS,
//客戶端發送命令給wpa_supplicant,回復的訊息保存在reply中
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));
msg_cb是一個回呼函式,該引數的設定和WPAS中C/S通信機制的設計有關,
打開通知事件監聽功能相關的API如下所示,
//打開通知事件功能
int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
//打開通知事件監聽功能的wpa_ctrl物件能直接呼叫下面的函式來接收unsolicited event
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
如果客戶端并不發送命令,而只是想接收Unsolicited event,可通過wpa_ctrl_recv函式來此達到目的,
綜上所述,單獨使用wpa_ctrl_recv和wpa_ctrl_request都不方便,因此,常用的方法是:客戶端創建兩個wpa_ctrl物件來簡化自己的邏輯處理,
1)一個打開了通知事件監聽功能的wpa_ctrl物件將只通過wpa_ctrl_recv來接收通知事件,
2)另外一個wpa_ctrl專職用于發送命令和接識訓復,由于沒有呼叫wpa_ctrl_attach,所以它不會收到通知事件,
七. wpa_supplicant連接無線網路分析
通過命令列發送命令的方式觸發wpa_supplicant進行相關作業,使手機加入一個利WPA_PSK進行認證的無線網路,

dhcpcd成功執行后,手機將從AP那邊分配到一個IP地址,至此,手機就可以使用"Tes" 無線網路,

綜上所述,所有來自客戶端的命令都由wpa_supplicant_ctrl_iface_receive函式處理;絕大部分命令都由wpa_supplicant_ctrl_iface_process函式處理,
ENABLE_NETWORK命令處理
ENABLE_NETWORK命令由wpa_supplicant_ctrl_iface_enable_network進行處理,其代碼如下:


- 無線網路掃描流程分析
ENABLE_NETWORK將發起無線網路掃描請求,這是由wpa_supplicant_req_scan完成的,其代碼如下:

wpa_supplicant_scan是無線網路掃描的核心函式,其代碼比較復雜,分段來分析,
1)wpa_supplicant_scan分析之一
這一段的代碼主要和scan請求的引數準備有關,


一個Probe Request要么指定wildcard ssid以掃描周圍所有的無線網路,要么指定某個ssid以掃描指定無限網路,為了方便WPAS的使用,wlan driver新增一個功能,使得上層可通過一次scan請求來掃描多個不同ssid的無線網路,一個scan請求在代碼中對應的資料結構就是wpa_driver_scan_params,而wpa_supplicant_scan最重要的作業就是準備好這個請求,
2)wpa_supplicant_scan分析之二
接著來看代碼段二



上訴wpa_supplicant_scan代碼主要展示了如何填寫掃描請求引數,復雜的點在于細節處理,
3)wpa_supplicant_scan分析三
當scan請求的引數準備好,wpa_supplicant_scan將直接向driver wrapper發起scan請求,

對driver_nl80211,對應的函式是wpa_driver_nl80211_scan,看下面代碼,


本例來說,ENABLE_WORK命令處理的第一步就是要掃描周圍的無線網路,至于目標無線網路是否存在,則屬于掃描結果處理流程的作業了,
4)無線網路掃描流程總結
下圖為觸發掃描掃描功能的流程圖,

圖 7.1 觸發掃描的流程圖
圖中的函式,wpa_supplicant_scan的內容較豐富,其中有很多細節內容,初次學習,可先不考慮圖中函式的細節,只需把握圖中函式呼叫流程即可,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/291516.html
標籤:其他
