當前位置:
首頁 > 最新 > 關於Android Wifi掃描相關

關於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掃描的一個基本步驟,具體流程就不做詳細分析了。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 一個人的Android 的精彩文章:

打開Wifi以及與Hal層服務建立連接的流程

TAG:一個人的Android |