關於Android Wifi掃描相關
在之前介紹Wifi服務的時候有介紹過WifiScanningService,這篇文章就來分析Wifi掃描相關,獲取掃描結果(WifiList),至於發起掃描的流程,首先他和獲取Wifilist的流程幾乎相同,其次,這次工作也沒有做過多的整理,所以不做詳細分析,只是貼出大概流程和總結。
接下來開始分析獲取掃描結果(wifiList),首先應用如果需要獲取WifiList需要通過WifiManager的getScanResults介面來發起。
1 WiFiManager的getScanResults函數:
實際上這裡就是直接調用了WifiServiceImpl的getScanResults函數。
2 WifiServiceImpl的getScanResults函數:
這個函數主要是:
2.1 創建mWifiScanner對象。
2.2 調用mWifiScanner的getSingleScanResults函數獲取掃描結果。
2.1 創建mWifiScanner對象。
這個函數首先獲取WifiScanningService的binder代理對象,他對應的Binder本地對象是WifiScanningServiceImpl,主要用於和WifiScanningService交互。
然後獲取WifiStateMachine的looper對象,有了Looper對象就能和往WifiStateMachine狀態機裡面發送消息。
最後創建一個WifiScanner對象。
2.2 WifiScanner 構造函數:
messenger: Messager類對象,內部封裝了一個IMessenger介面的Binder代理對象mTarget,可以往別的進程的消息隊列發送消息。
Message: 消息隊列裡面的消息,有一個成員變數replyTo,保存的是一個Messager對象。
上面兩點是Android系統消息隊列裡面就提供的機制。
mAsyncChannel:AsyncChannel類對象,這個他可以實現同步非同步消息的處理。怎麼理解呢?
AsyncChannel 簡單總結:
成員變數mDstMessenger: 這個是用於記錄要發送的Message的目的消息隊列。(處理該消息的消息隊列)
成員變數mSrcMessenger: 這個是用於記錄要發送的Message 來源的消息隊列(接收處理完該消息結果的消息隊列)
關於非同步消息處理的理解:
當通過AsyncChannel發送一條非同步消息的時候,他會用mDstMessenger的sendMessage函數發送該Message(消息),同時設置該Message(消息)的replyTo為mDstMessenger,這樣的話當mDstMessenger所在進程的消息隊列處理完該Message(消息)的時候,就會調用Message(消息)的replyTo的sendMessage函數把處理的結果返回到mSrcMessenger所在進程的消息隊列。
內部類SyncMessenger: 他主要用於發送同步消息的
這個內部類裡面包含一個HandlerThread,同時還有另外一個成員變數mMessenger,就是往該HandlerThread的消息隊列發送消息的Messager。
關於同步消息處理的理解:
當通過AsyncChannel發送一條同步消息的時候,他會用mDstMessenger的sendMessage函數發送該Message(消息),同時設置該Message(消息)的replyTo為SyncMessenger的HandlerThread的Messager,同時讓進入Wait。
喚醒Wait的條件就是當mDstMessenger處理完消息,調用replyTo(也就是SyncMessenger的HandlerThread的消息隊列收到處理結果的時候喚醒Wait),
最後直接返回該消息的結果。
這裡重點講了一下AsyncChannel對消息的處理,以便後面分析消息的分發和處理。
這個構造函數主要,獲取WifiScanningServiceImpl的 Messager, 有了這個 Messager 就可以往 WifiScanningServiceImpl 的消息隊列發送消息。
然後用 messenger 初始化 mAsyncChannel. messenger被保存在AsyncChannel的mDstMessenger成員變數裡面,以後的消息主要就是通過mAsyncChannel來往WifiScanningServiceImpl發送消息,完成請求。
3 調用mWifiScanner的getSingleScanResults函數獲取掃描結果
有了前面對AsyncChannel的分析,這裡就很好理解了。
這個函數主要是通過 mAsyncChannel 發送一個同步的消息 CMD_GET_SINGLE_SCAN_RESULTS 到WifiScanningServiceImpl消息隊列中。然後等待結果的返回。
如果返回成功CMD_OP_SUCCEEDED,則在reply.obj中獲取WifiList返回結果。
4 WifiScanningServiceImpl 處理CMD_GET_SINGLE_SCAN_RESULTS消息的是ClientHandler的handleMessage函數具體如下:
這個只是發送 CMD_GET_SINGLE_SCAN_RESULTS 消息到狀態機mSingleScanStateMachine
5 mSingleScanStateMachine處理消息 CMD_GET_SINGLE_SCAN_RESULTS 的代碼如下:
這個函數主要是調用 filterCachedScanResultsByAge 獲取掃描結果
然後創建ParcelableScanResults 實例,然後把掃描結果返回。
6 獲取掃描結果:filterCachedScanResultsByAge
這裡實際上只是把緩存掃描的結果mCachedScanResults返回。
這裡我們會發現原來獲取Wifi掃描結果(WifiList)只是從緩存mCachedScanResults中取數據。
mCachedScanResults這個緩存的數據是從哪裡來的?如何更新的呢?
在了解mCachedScanResults的數據來源之前先要說明如下兩點:
說明1: 在打開Wifi的那篇文章中說過 mWificondScanner Binder代理對象,主要用戶發起掃描和獲取掃描結果。同時mWificondScanner註冊了一個Scan的Event Callback: mScanEventHandler
mScanEventHandler是一個Binder對象,當有Scan數據的時候底層通過調用mScanEventHandler的OnScanResultReady函數告訴Framework層有Wifi掃描的數據了。
說明2: 在WifiScanningService服務啟動後會構建一個 WificondScannerImpl 的binder對象保存到ServiceManger中。
在WificondScannerImpl有一個成員變數 mScannerImpl ,是在 WifiBackgroundScanStateMachine 狀態機處理DefaultState處理CMD_DRIVER_LOADED命令的時候構建的。
在mScannerImpl的構建過程中(也就是WificondScannerImpl構造函數中)會向WifiMonitor中註冊一個Event:具體如下:
mEventHandler他的消息隊列就是 WifiScanningServiceImpl 的消息隊列,他的處理的函數handleMessage就在WificondScannerImpl中。
這段代碼的意思就是,如果有SCAN_RESULTS_EVENT消息,就用 mEventHandler 發送到 WificondScannerImpl的handleMessage函數來處理。
1 mScanEventHandler的OnScanResultReady函數:
這個函數就是直接調用了mWifiMonitor的broadcastScanResultEvent函數:
這個也比較簡單,就是發送了一個消息 SCAN_RESULTS_EVENT,
在前面第二點說過,WifiMinitor最終會把這個消息發送到 WifiScanningServiceImpl的消息隊列裡面來。
最終處理該消息的就是WificondScannerImpl的handleMessage函數:
2 WificondScannerImpl處理 SCAN_RESULTS_EVENT 消息
這個函數主要做了如下幾件事情:
2.1 調用mWifiNative.getScanResults();獲取掃描結果:nativeResults
2.2 循環處理後把掃描結果保存到singleScanResults
2.3 把得到的singleScanResults保存到mLatestSingleScanResult中,最後調用singleScanEventHandler的onScanStatus函數通知framework層處理。
這裡singleScanEventHandler 就是 WifiScanningServiceImpl
3 先看mWifiNative.getScanResults()獲取掃描結果:
這裡只是調用了mWificondControl的getScanResults函數:這個函數最重要的一行代碼如下:
NativeScanResult[] nativeResults = mWificondScanner.getScanResults();
mWificondScanner在說明1裡面有分析了,他是一個Binder代理對象,他對應的binder本地對象是wificond服務中的 ScannerImpl
也就是說實際上這裡調用的是 ScannerImpl 的 getScanResults
4 底層服務wificond裡面的代碼就不詳細說了,這裡就簡單介紹一下,以便我們可以理解整個邏輯。
在Wificond服務中有一個 NetlinkManager 對象,在他的內部創建了一個用於和驅動交互的Socket。
ScannerImpl的getScanResults函數就會創建一個包含 NL80211_CMD_GET_SCAN命令的 NL80211Packet 對象。
然後調用NetlinkManager的Socket NL80211Packet的對象發送到 Wifi80211的驅動,同時驅動返回的掃描結果:
也就是nativeResults
5 把nativeResults通過處理之後,調用singleScanEventHandler的onScanStatus
前面說過他實際調用的是WifiScanningServiceImpl的onScanStatus函數。
這裡只是往WifiSingleScanStateMachine狀態機裡面發送了一條 CMD_SCAN_RESULTS_AVAILABLE的命令
6 下面看看這個狀態機中 ScanningState 是如何處理這條消息的
mScannerImpl:就是WificondScannerImpl
這裡mScannerImpl.getLatestSingleScanResults() 就是把前面處理完掃描結果保存在mLatestSingleScanResult的掃描數據取出來。
總結一下:
1 應用獲取Wifi掃描結果(wifiList),其實是從緩存mCachedScanResults中取出來的。
2 關於緩存mCachedScanResults的更新,其實是一個通知更新,然後獲取的過程。
首先在Wifi打開的過程中,在連接Wificond服務的時候獲取了一個mWificondScanner的Binder代理對象,
然後通過mWificondScanner往wificondHal層服務註冊了一個mScanEventHandler的binder對象
當需要更新WifiList的時候mScanEventHandler收到通知,然後通過WifiMonitor發送消息到WifiScanningService中。
WifiScanningServiceImpl處理該消息的時候,最終會通過mWificondScanner往WifiCond服務發送消息,獲取Wifi掃描結果。
關於Wifi發起掃描的流程:
了解了Wifi掃描結果的獲取流程,了解了刷新Wifi掃描結果緩存的流程其實分析起來還是比較得心應手了。
因為他肯定繞不開如下幾點。
1 應用是通過WifiManager的介面發起的。
2 WifiManager對應的就是WifiServiceImpl服務的介面來處理。
3 在WifiScanningService中有一個WifiScanner包含了一個AsyncChannel類對象mAsyncChannel,他可以往WifiScanningService的消息隊列裡面發送消息。
4 在WifiScanningService中處理消息的時候可能會繞幾圈但是最終還是會調用,在Wifi打開流程中創建的 mWificondScanner 這個Binder代理對象和WifiCond服務交互。
下面我列出發起Wifi掃描的一個基本步驟,具體流程就不做詳細分析了。


TAG:一個人的Android |