Android WIFI模塊分析

一:什麼是WIFIhtml

WIFI是一種無線鏈接技術。可用於手機、電腦、PDA等終端。java

WIFI技術產生的目的是改善基於IEEE802.11標準的無線網絡產品之間的互通性,也就是說WIFI是基於802.11標準的,但WIFI不等同無線網絡。linux

二:Android平臺下的WIFI模塊android

簡介一下,WIFI模塊的基本功能:api

1. 開關WIFI
除了在WIFI設置界面可以開關WIFI,還有其它的方法可以設置。要查看這些開關狀態是否一致。還有就是飛行模式對WIFI開關的影響。由於WIFI開和關都有一個時間過程,而飛行模式的開關瞬間完畢,因此有時會出現衝突。安全

2. 開關新可用網絡提醒
新可用網絡的定義是自WIFI模塊開啓後,從未發現過的,爲加密的網絡。微信

僅僅有知足了新可用網絡的定義,纔會有提醒。網絡

3. 鏈接斷開網絡
鏈接斷開各類不一樣加密類型的網絡(具體類型下文有具體解釋)app

4. 手動加入網絡
需要路由器關閉SIID廣播。框架

可手動輸入SIID。網絡加密類型,password。

對於OPAL手機來講,路由器隱藏了SSID,手動加入的網絡是沒法鏈接的。

5. 搜索網絡
手動點擊搜索button可以搜索網絡。也可以等待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模塊深刻了解一點點

一、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來處理Wifibutton。

2 當用戶按下Wifibutton後, 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中選擇好加密方式和輸入密鑰以後,再點擊鏈接button,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消息,會再次廣播發送。

至此爲止,整個鏈接過程完畢。

二、wpa_supplicant

Android平臺使用的WiFi控制框架是基於大名鼎鼎的wpa_supplicant,它是一個安全中間件。爲各類無線網卡提供統一的安全機制,例如如下圖所看到的:

wpa_supplicant

相應上述結構。基於Android的手機中的WiFi控制分爲三大組件:

1 client程序,包含wpa_cli命令行或java圖形界面程序,經過unix本地socket與wpa_supplicant daemon服務通訊。發送命令並接收結果。

2 wpa_supplicant daemon服務,相應上述中間部分,功能是「上傳下達」。所有client經過它控制硬件網卡,經過發送字符串命令控制是否掃描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。)

一、開啓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狀態跟蹤:更改請求狀態:搜索中->不活動


二、點擊鏈接&獲取狀態

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

<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?

v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>

閱讀(32) | 評論(0) | 轉發(0) |
相關文章
相關標籤/搜索