1. 程式人生 > >Android WIFI原始碼思路詳解(Android4版本之前)

Android WIFI原始碼思路詳解(Android4版本之前)

一:什麼是WIFI

WIFI是一種無線連線技術,可用於手機、電腦、PDA等終端。WIFI技術產生的目的是改善基於IEEE802.11標準的無線網路產品之間的互通性,也就是說WIFI是基於802.11標準的,但WIFI不等同無線網路。

二:Android平臺下的WIFI模組

簡單介紹一下,WIFI模組的基本功能:

1. 開關WIFI
除了在WIFI設定介面可以開關WIFI,還有其他的方法可以設定,要檢視這些開關狀態是否一致。還有就是飛航模式對WIFI開關的影響,由於WIFI開和關都有一個時間過程,而飛航模式的開關瞬間完成,所以有時會出現衝突。

2. 開關新可用網路提醒
新可用網路的定義是自WIFI模組開啟後,從未發現過的,為加密的網路。只有滿足了新可用網路的定義,才會有提醒。

3. 連線斷開網路
連線斷開各種不同加密型別的網路(具體型別下文有詳解)

4. 手動新增網路
需要路由器關閉SIID廣播。可手動輸入SIID,網路加密型別,密碼。對於OPAL手機來說,路由器隱藏了SSID,手動新增的網路是無法連線的。

5. 搜尋網路
手動點選搜尋按鈕可以搜尋網路,也可以等待WIFI模組自動搜尋網路。

6. 休眠設定
由於WIFI模組是用電大戶,所有為了省電,Android的WIFI加了一個休眠策略,可以設定永遠不斷開,充電時不斷開和鎖屏時斷開。要測試休眠設定是否有效,可以在路由器上PING手機的IP,PING通就是連線狀態。OPAL手機的休眠策略屬於完全失效,現在的情況是無論選哪個都會一直保持連線,鎖屏後15分鐘再休眠。

7. 設定靜態IP
Android系統裡對IP設定的輸入限制很有問題,我一直認為這是弱智的限制。正常IP的範圍在0-255之間,android對IP輸入的限制是整數0到整數255之間,也就是說0000.000200.001.001這樣一個IP都能合法輸入。

三:對WIFI模組深入瞭解一點點

1、WIFI的基本執行流程

WIFI的基本執行流程

【初始化】

1 在SystemServer啟動的時候,會生成一個ConnectivityService的例項。

2 ConnectivityService的建構函式會建立WifiService。

3 WifiStateTracker會建立WifiMonitor接收來自底層的事件,WifiService和WifiMonitor是整個模組的核心。WifiService負責啟動關閉wpa_supplicant、啟動關閉WifiMonitor監視執行緒和把命令下發給wpa_supplicant,而WifiMonitor則負責從wpa_supplicant接收事件通知。

【連線AP】

1 WirelessSettings在初始化的時候配置了由WifiEnabler來處理Wifi按鈕。

2 當用戶按下Wifi按鈕後, Android會呼叫WifiEnabler的onPreferenceChange,再由WifiEnabler呼叫WifiManager的setWifiEnabled介面函式,通過AIDL,實際呼叫的是WifiService的setWifiEnabled函式,WifiService接著向自身傳送一條MESSAGE_ENABLE_WIFI訊息,在處理該訊息的程式碼中做真正的使能工作:首先裝載WIFI核心模組(該模組的位置硬編碼為"/system/lib/modules/wlan.ko" ),然 後 啟 動wpa_supplicant (配 置 文 件 硬 編 碼 為"/data/misc/wifi/wpa_supplicant.conf")再通過WifiStateTracker來啟動WifiMonitor中的監視執行緒。

3當使能成功後,會廣播發送WIFI_STATE_CHANGED_ACTION這個Intent通知外界WIFI已 經 成 功 使 能 了 。WifiEnabler創 建 的 時 候 就 會 向Android注 冊 接 收WIFI_STATE_CHANGED_ACTION,因此它會收到該Intent,從而開始掃描。

【查詢AP】

1 掃描的入口函式是WifiService的startScan,它其實也就是往wpa_supplicant傳送SCAN命令。

2 當wpa_supplicant處理完SCAN命令後,它會向控制通道傳送事件通知掃描完成,從而wifi_wait_for_event函式會接收到該事件,由此WifiMonitor中的MonitorThread會被執行來出來這個事件。

3 WifiStateTracker則接著廣播發送SCAN_RESULTS_AVAILABLE_ACTION這個Intent。

4 WifiLayer註冊了接收SCAN_RESULTS_AVAILABLE_ACTION這個Intent,所以它的相關處理函式handleScanResultsAvailable會被呼叫,在該函式中,先會去拿到SCAN的結果(最終是往wpa_supplicant傳送SCAN_RESULT命令並讀取返回值來實現的),List<scanresult> list = mWifiManager.getScanResults();對每一個掃描返回的AP,WifiLayer會呼叫WifiSettings的onAccessPointSetChanged函式,從而最終把該AP加到GUI顯示列表中。

【配置AP引數】

當用戶在WifiSettings介面上選擇了一個AP後,會顯示配置AP引數的一個對話方塊。

showAccessPointDialog(state, AccessPointDialog.MODE_INFO);

【連線】

當用戶在AcessPointDialog中選擇好加密方式和輸入金鑰之後,再點選連線按鈕,Android就會去連線這個AP。

1 WifiLayer會先檢測這個AP是不是之前被配置過,這個是通過向wpa_supplicant傳送LIST_NETWORK命令並且比較返回值來實現的,

//Need WifiConfiguration for the AP

WifiConfiguration config = findConfiguredNetwork(state);

如果wpa_supplicant沒有這個AP的配置資訊,則會向wpa_supplicant傳送ADD_NETWORK命令來新增該AP

2 ADD_NETWORK命令會返回一個ID,WifiLayer再用這個返回的ID作為引數向wpa_supplicant傳送ENABLE_NETWORK命令,從而讓wpa_supplicant去連線該AP。

【配置IP地址】

1 當wpa_supplicant成功連線上AP之後,它會向控制通道傳送事件通知連線上AP了,從而wifi_wait_for_event函式會接收到該事件,由此WifiMonitor中的MonitorThread會被執行來出來這個事件。

2 WifiMonitor再呼叫WifiStateTracker的notifyStateChange,WifiStateTracker則接著會往自身傳送EVENT_DHCP_START訊息來啟動DHCP去獲取IP地址。

3 然後再廣播發送NETWORK_STATE_CHANGED_ACTION這個Intent。

4 WifiLayer註冊了接收NETWORK_STATE_CHANGED_ACTION這個Intent,所以它的相關處理函式handleNetworkStateChanged會被呼叫,當DHCP拿到IP地址之後,會再發送EVENT_DHCP_SUCCEEDED訊息。

5 WifiLayer處 理EVENT_DHCP_SUCCEEDED訊息,會再次廣播發送。

至此為止,整個連線過程完成。

2、wpa_supplicant

Android平臺使用的WiFi控制框架是基於大名鼎鼎的wpa_supplicant,它是一個安全中介軟體,為各種無線網絡卡提供統一的安全機制,如下圖所示:

wpa_supplicant

對應上述結構,基於Android的手機中的WiFi控制分為三大元件:

1 客戶端程式,包括wpa_cli命令列或java圖形介面程式,通過unix本地socket與wpa_supplicant daemon服務通訊,傳送命令並接收結果。

2 wpa_supplicant daemon服務,對應上述中間部分,功能是“上傳下達”。所有客戶端通過它控制硬體網絡卡,通過傳送字串命令控制是否掃描AP,提取掃描結果和是否關聯AP等操作,同時將驅動的執行狀態傳送給使用者。該服務是設計支援多種無線網絡卡晶片,因此各個廠商共同提供了一個通用介面給wpa_supplicant呼叫。

3 網絡卡驅動。

在手機記憶體的/etc/wpa_supplicant.conf中我們可以直接看到WIFI支援的網路型別,每種型別都有例子,比如:

#Both WPA-PSK and WPA-EAP is accepted. Only CCMP is accepted as pairwise and
# group cipher.
#network={
# ssid="example"
# bssid=00:11:22:33:44:55
# proto=WPA RSN
# key_mgmt=WPA-PSK WPA-EAP
# pairwise=CCMP
# group=CCMP
# psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb
#}

不同型別的網路,不同的引數等等,應有盡有。

四:對WIFI模組的LOG瞭解多一點點

我們在上面已經知道WIFI的啟動過程,在功能執行中也會輸出相應的日誌資訊,下面就來詳細瞭解一下。(請注意,WIFI開啟後會更改電池狀態等其他狀態。關閉WIFI時,android的策略是解除安裝驅動來省電。如有缺失就是問題。不過下文刪去了與WIFI無關的LOG!)

1、開啟WIFI&自動搜尋

E/WifiHW ( 1201): ==JOHN DEBUG==: [WIFI] Load Driver

載入驅動
D/SettingsWifiEnabler( 1321): Received wifi state changed from Disabled to Enabling

接收到廣播:WIFI正在開啟
D/WifiService( 1201): ACTION_BATTERY_CHANGED pluggedType: 2

電池狀態改變
E/WifiHW(1201):==JOHNDEBUG==:moduleaddress:4b938008 filename:/system/lib/modules/dhd.ko args:firmware_path=/system/wlan/broadcom/rtecdc.bin nvram_path=/system/wlan/broadcom/nvram.txt

WIFI硬體:載入核心模組
I/wpa_supplicant( 2490): CTRL-EVENT-STATE-CHANGE id=-1 state=2

wpa_supplicant發出事件通知

V/WifiMonitor( 1201): Event [CTRL-EVENT-STATE-CHANGE id=-1 state=2]

WifiMonitor從wpa_supplicant接收事件通知

I/wpa_supplicant( 2490): CTRL-EVENT-SCAN-RESULTS Ready

wpa_supplicant發出事件通知:準備好開始搜尋網路了

E/wpa_supplicant( 2490): wpa_driver_priv_driver_cmd SCAN-ACTIVE len = 4096

wpa_supplicant發出事件通知:驅動命令列.主動搜尋.LEN

E/wpa_supplicant( 2490): wpa_driver_priv_driver_cmd SCAN-ACTIVE len = 0, 11

wpa_supplicant發出事件通知:驅動命令列.主動搜尋.LEN

E/wpa_supplicant( 2490): wpa_driver_priv_driver_cmd SCAN-PASSIVE len = 4096

wpa_supplicant發出事件通知:驅動命令列.被動搜尋.LEN

E/wpa_supplicant( 2490): wpa_driver_priv_driver_cmd SCAN-PASSIVE len = 0, 12

wpa_supplicant發出事件通知:驅動命令列.被動搜尋.LEN=0.12

D/SettingsWifiEnabler( 1321): Received wifi state changed from Enabling to Enabled

接收到廣播:WIFI已經開啟

E/wpa_supplicant( 2490): wpa_driver_priv_driver_cmd RSSI len = 4096

wpa_supplicant發出事件通知:

E/wpa_supplicant( 2490): wpa_driver_priv_driver_cmd RSSI len = 4, 4

wpa_supplicant發出事件通知:

E/wpa_supplicant( 2490): wpa_driver_priv_driver_cmd LINKSPEED len = 4096

wpa_supplicant發出事件通知:

E/wpa_supplicant( 2490): wpa_driver_priv_driver_cmd LinkSpeed 54 len = 12, 12

wpa_supplicant發出事件通知:

E/wpa_supplicant( 2490): wpa_driver_priv_driver_cmd MACADDR len = 4096

wpa_supplicant發出事件通知:驅動命令列.MAC地址.LEN

E/wpa_supplicant( 2490): wpa_driver_priv_driver_cmd Macaddr = 44:A4:2D:27:25:BE

wpa_supplicant發出事件通知:驅動命令列.MAC地址

E/wpa_supplicant( 2490): len = 28, 28

wpa_supplicant發出事件通知:

V/WifiStateTracker( 1201): Connection to supplicant established, state=SCANNING

WIFI狀態跟蹤:連線請求確認,狀態=搜尋

D/NetworkStateTracker( 1201): setDetailed state, ld =IDLE and new state=SCANNING

網路狀態跟蹤:更新顯示為搜尋狀態

V/WifiStateTracker( 1201): Changing supplicant state: SCANNING ==> INACTIVE

WIFI狀態跟蹤:更改請求狀態:搜尋中->不活動


2、點選連線&獲取狀態

E/WifiHW ( 1201): ==JOHN DEBUG==: [WIFI] Load Driver

WIFI硬體:載入驅動
D/SettingsWifiEnabler( 1321): Received wifi state changed from Disabled to Enabling

收到廣播,WIFI狀態正在開啟
E/WifiHW(1201):==JOHNDEBUG==:moduleaddress:4b938008 filename:/system/lib/modules/dhd.ko args:firmware_path=/system/wlan/broadcom/rtecdc.bin nvram_path=/system/wlan/broadcom/nvram.txt

WIFI硬體:載入核心模組
E/WifiHW ( 1201): ==JOHN DEBUG==: return of insmod : ret = 0, Unknown error: 0

WIFI硬體:返回裝載模組報告:返回指令0,未知錯誤0

……

I/wpa_supplicant( 2490): Trying to associate with 1c:bd:b9:f6:a7:9f (SSID='LosAngeles' freq=2412 MHz)

wpa_supplicant發出事件通知:嘗試連線,(SSID='LosAngeles'頻段=2412 MHz)

V/WifiMonitor( 1201):Event[Trying to associate with 1c:bd:b9:f6:a7:9f (SSID='LosAngeles' freq=2412 MHz)]

WifiMonitor接收wpa_supplicant的事件

V/WifiMonitor( 1201): Event [CTRL-EVENT-STATE-CHANGE id=-1 state=3]

WifiMonitor接收事件

V/WifiStateTracker( 1201): Changing supplicant state: SCANNING ==> ASSOCIATING

WIFI狀態跟蹤:更改請求狀態:搜尋中->匹配中

D/NetworkStateTracker( 1201): setDetailed state, ld =SCANNING and new state=CONNECTING

網路狀態跟蹤:更新顯示為正在連線狀態

D/ConnectivityService( 1201): ConnectivityChange for WIFI: CONNECTING/CONNECTING

連線管理服務:改變WIFI連線狀態:正在連線/正在連線

V/WifiStateTracker( 1201): Changing supplicant state: ASSOCIATING ==> ASSOCIATED

WIFI狀態跟蹤:更改請求狀態:匹配中->已匹配

D/NetworkStateTracker( 1201): setDetailed state, ld =CONNECTING and new state=CONNECTING

網路狀態跟蹤:更新顯示為正在連線狀態

I/wpa_supplicant( 2490): Associated with 1c:bd:b9:f6:a7:9f

wpa_supplicant發出事件通知:已和1c:bd:b9:f6:a7:9f匹配

V/WifiMonitor( 1201): Event [Associated with 1c:bd:b9:f6:a7:9f]

WifiMonitor接收wpa_supplicant的事件

V/WifiStateTracker( 1201): Changing supplicant state: ASSOCIATED ==> FOUR_WAY_HANDSHAKE

WIFI狀態跟蹤:更改請求狀態:已匹配->TCP中斷連線

D/NetworkStateTracker( 1201): setDetailed state, ld =CONNECTING and new state=AUTHENTICATING

網路狀態跟蹤:更新顯示為鑑定中

D/ConnectivityService( 1201): Dropping ConnectivityChange for WIFI: CONNECTING/AUTHENTICATING

連線管理服務:丟擲WIFI連線狀態改變:已連線/鑑定中

V/WifiStateTracker( 1201): Changing supplicant state: FOUR_WAY_HANDSHAKE ==> GROUP_HANDSHAKE

WIFI狀態跟蹤:更改請求狀態:TCP中斷連線->確認標誌位

D/NetworkStateTracker( 1201): setDetailed state, ld =AUTHENTICATING and new state=AUTHENTICATING

網路狀態跟蹤:更新顯示為鑑定中

I/wpa_supplicant( 2490): WPA: Key negotiation completed with 1c:bd:b9:f6:a7:9f [PTK=CCMP GTK=TKIP]

wpa_supplicant發出事件通知:WPA:與1c:bd:b9:f6:a7:9f確定標誌位

I/wpa_supplicant( 2490): CTRL-EVENT-STATE-CHANGE id=0 state=7

wpa_supplicant發出事件通知:

I/wpa_supplicant( 2490): CTRL-EVENT-CONNECTED - Connection to 1c:bd:b9:f6:a7:9f completed (auth) [id=0 id_str=]

wpa_supplicant發出事件通知:連線完成

V/WifiMonitor( 1201): Event [WPA: Key negotiation completed with 1c:bd:b9:f6:a7:9f [PTK=CCMP GTK=TKIP]]

WifiMonitor接收wpa_supplicant事件

V/WifiMonitor( 1201): Event [CTRL-EVENT-STATE-CHANGE id=0 state=7]

WifiMonitor接收wpa_supplicant事件

V/WifiMonitor( 1201): Event [CTRL-EVENT-CONNECTED - Connection to 1c:bd:b9:f6:a7:9f completed (auth) [id=0 id_str=]]

WifiMonitor接收wpa_supplicant事件

V/WifiStateTracker( 1201): Changing supplicant state: GROUP_HANDSHAKE ==> COMPLETED

WIFI狀態跟蹤:更改請求狀態:確認標誌位->完成

V/WifiStateTracker( 1201): New network state is CONNECTED

WIFI狀態跟蹤:新網路狀態為已連線

D/NetworkStateTracker( 1201): setDetailed state, ld =AUTHENTICATING and new state=OBTAINING_IPADDR

網路狀態跟蹤:更新顯示為獲取IP地址

D/ConnectivityService( 1201): Dropping ConnectivityChange for WIFI: CONNECTING/OBTAINING_IPADDR

連線管理服務:丟擲WIFI