天天看點

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

本文正在參加星光計劃3.0–夏日挑戰賽

作者:巴延興

1. WiFi簡介

1.1 WiFi介紹

WiFi是一種無線通信技術,可以将個人電腦、手持裝置(如pad、手機)等終端以無線方式互相連接配接。WiFi網絡是使用無線通信技術在一定的局部範圍内建立的網絡,是計算機網絡與無線通信技術相結合的産物,它以無線多址信道作為媒介,提供傳統區域網路的功能,使使用者真正實作随時随地随意的寬帶網絡接入。

WiFi主要遵循IEEE802.11系列協定标準,該通信協定于1996年由澳洲的研究機構CSIRO提出,WiFi憑借其獨特的技術優勢,被公認為是目前最為主流的WLAN(無線區域網路)技術标準。随着WiFi無線通信技術的不斷優化和發展,目前主要的通信協定标準有802.11a、802.11b、802.11g、802.11n和802.11ac、802.11ax,根據不同的協定标準主要有兩個工作頻段,分别為2.4GHz和5.0GHz。

下表簡單介紹了各個标準的釋出時間和特點。

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

1.2 基本概念

1.2.1 WiFi網絡結構

WiFi無線網絡中包含了一些基本的組成元素如工作站,接入點等,以下介紹WiFi網絡中一些基礎概念。

(1)工作站(Station)

工作站是指配備無線網絡接口的終端裝置(計算機、手機等),建構網絡的目的就是為了在工作站間傳送資料。

(2)接入點(Access Point)

802.11網絡所使用的幀必須經過轉換,方能被傳遞至其他不同類型的網絡。具備無線至有線(wireless-to-wired)的橋接功能的裝置稱為接入點,簡稱AP。

(3)無線媒介(Wireless medium)

802.11标準以無線媒介在工作站之間傳遞幀。

(4)分布式系統(Distribution system)

幾個接入點串聯起來可以覆寫一塊比較大的區域,接入點之間互相通信可以掌握移動式工作站的行蹤,這就組成了一個分布式系統。分布式系統屬于802.11的邏輯元件,負責将幀(frame)傳送至目的地,分布式系統是接入點間轉發幀的骨幹網絡,是以通常稱為骨幹網絡(backbone network),基本都是以太網(Ethernet)。

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

​ 圖1 WiFi分布式系統組成

如圖,在分布式網絡拓撲結構中,有幾個基本概念:

1)基本服務集(BSS)

由一組彼此通信的工作站組成,這裡隻讨論基礎型BSS,一個熱點覆寫的範圍稱為一個BSS。

2)擴充服務集(ESS)

多個BSS可以構成一個擴充網絡,稱為擴充服務集(ESS)網絡,一個ESS網絡内部的STA可以互相通信,是采用相同的SSID的多個BSS形成的更大規模的虛拟BSS。

連接配接BSS的元件稱為分布式系統(Distribution System,DS)。

3)SSID

Service Set ID,服務集辨別。

SSID是讓網管人員為服務集合(SS)指定的識别碼,組成ESS的所有BSS都會使用相同的SSID。

4)BSSID

Basic Service Set ID,基本服務集辨別。

在基礎網絡裡,BSSID就是接入點(AP)使用的MAC位址。

5)ESSID

Extended Service Set ID,擴充服務集辨別。

因為ESS中所有BSS使用同一辨別,是以ESSID就是SSID。

1.2.2 WiFi網絡安全技術

IEEE802.11技術從出現開始,就一直為安全問題困擾。繼因安全性問題被指責的WEP後,Wifi聯盟先後推出了WPA和WPA2安全标準以及最新的WPA3标準。下面對常見的這幾種安全标準做簡單說明。

l WEP(Wired Equivalent Privacy,有線等效加密),是IEEE802.11最初提出的基于RC4流加密算法的安全協定,存在加密流重用、密鑰管理等問題,已基本被棄用。

l WPA(WiFi Protected Access,WiFi保護通路),WiFi聯盟在IEEE802.11i草案基礎上制定的一項無線網絡安全技術,目的在于替代傳統WEP安全技術,分為WPA Personal(pre-shared key身份驗證)和WPA Enterprise。WPA使用臨時密鑰完整性協定(Temporal Key Integrity Protocol,TKIP),提高了無線網絡的安全性。

l WPA2是WPA的加強版,支援進階加密協定(Advanced Encryption Standard,AES),使用計數器模式密碼塊鍊消息完整碼協定(CCMP),安全性比WPA有進一步提升。

l WPA3是Wi-Fi聯盟組織于2018年1月8日釋出的Wifi新加密協定,是WPA2技術的後續版本。WPA3支援SAE(對等同步認證)以及具有192位加密功能的WPA3-Enterprise,比WPA2更安全。

1.2.3 WiFi工作模式

鴻蒙系統的WiFi元件在驅動支援的前提下,可以支援三種工作模式:STATION模式、AP模式和P2P模式。

  • STATION模式,就是2.2.1中講到的工作站,也就是無線區域網路中的一個用戶端,這是Wifi最基本的工作模式,通過連接配接其他接入點通路網絡。
  • AP模式也就是接入點模式,即裝置作為接入點,為無線區域網路中的用戶端提供網絡接入功能,大多數終端裝置稱其為hotspot(熱點)或者softap,通過wifi的AP模式,可以将裝置的營運商資料網絡共享給接入的用戶端,實作随時随地的網絡資源共享。
  • P2P模式是WFA(WiFi聯盟)推出的一項與藍牙類似的技術,允許裝置間一對一直連,無需通過AP即可互相連接配接。P2P模式中的裝置,稱為P2P Device,P2P裝置組成的網絡叫P2P Group。在P2P網絡中,P2P Device有兩個角色,一個是GO(Group Owner),其作用類似于AP;另一個角色是GC(Group Client),類似于工作站(Station)。P2P裝置完成協商組建為一個P2P網絡的時候,有且隻能有一個裝置作為GO,其他裝置做為GC。Wifi P2P模式傳輸速度和傳輸距離比藍牙有大幅提升,但功耗也要比藍牙高。

2. WiFi子系統介紹

本章主要講解鴻蒙系統中WIFI子系統的架構組成以及部分關鍵子產品的實作。

2.1 系統架構簡介

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

圖1 WiFi系統架構圖

如圖1所示,鴻蒙WiFi系統是典型的分層結構,自上而下包括:

  • 應用層

主要包含鴻蒙提供的settings應用,該應用是典型的使用者使用WiFi的方式,提供使用者可見的設定界面,提供WiFi開關、WiFi掃描、連接配接斷開等基本功能。

應用代碼通過導入接口類,進而調用下層WIFI Native提供的JS接口,這部分實作的代碼在以下目錄中:

applications\standard\settings

  • Wifi Native JS

這部分應用了Node.js推出的用于開發C++原生子產品的接口N-API技術,對架構提供的C++接口進行封裝,為應用提供了調用WiFi功能的JS接口。

這部分代碼在以下目錄中:

foundation\communication\wifi\interfaces

  • WiFi架構

主要包含wifi服務的實作。其中,

wifi_manager_service負責管理STA、SCAN、AP、P2P等服務的加載和解除安裝。

wifi_ap_service實作AP模式的狀态機管理和事件處理。

wifi_p2p_service實作P2P模式的狀态機管理和事件處理。

wifi_scan_service實作SCAN時的狀态機管理和事件處理。

wifi_sta_service實作STA模式的狀态機管理和事件處理。

wifi_idl_client實作了與Wifi HAL進行RPC通信的用戶端。

dhcp_manager_service實作DHCP管理服務,啟動DHCP用戶端或者DHCP伺服器。

dhcp_client_service是DHCP用戶端的實作。

dhcp_server是DHCP伺服器的實作。

這部分代碼在以下目錄中:

foundation\communication\wifi\services\wifi_standard\wifi_framework

  • Wifi HAL

Wifi HAL提供RPC服務端,響應WiFi架構的遠端調用,HAL的主要功能是适配WPA Supplicant,負責啟動wpa_supplicant或者hostapd并添加網絡接口,向wpa_supplicant或hostapd發送控制指令完成WiFi相關的業務操作。Wifi HAL作為wpa_supplicant的适配層,依賴wpa_supplicant的libwpa_cli庫。

這部分代碼在如下目錄中:

foundation\communication\wifi\services\wifi_standard\wifi_hal

  • WPA Supplicant

包含libwpa、libwpa_client庫和wpa_cli、wpa_supplicant、hostapd可執行程式。

libwpa是一個包含了wpa_suppliant和hostapd具體實作的庫,Wifi HAL啟動WPAS就是通過加載libwpa庫,去執行wpa_supplicant或hostapd的入口函數。WPAS是一個開源項目,其中,wpa_supplicant是wpa的認證用戶端,負責完成認證相關的登入、加密等工作,hostapd包含了IEEE802.11接入點管理、IEEE802.1X/WPA/WPA2認證、EAP伺服器以及Radius鑒權伺服器功能。

libwpa_client是一個給用戶端連接配接和調用的庫,提供建立與wpa_supplicant或hostapd通信控制接口的能力。

wpa_cli和wpa_supplicant是用戶端和伺服器的關系,通過wpa_cli可以向wpa_supplicant發送指令,進行掃描、連接配接等做操作,可用來進行Wifi功能的驗證,Wifi HAL也是wpa_supplicant的用戶端。

wpa_supplicant和hostapd可執行程式依賴libwpa,啟動這兩個可執行程式,可以運作WPAS提供的所有功能。

這部分所處的路徑為:

third_party\wpa_supplicant\wpa_supplicant-2.9_standard

  • WiFi驅動架構

鴻蒙提供了HDF驅動架構的WiFi驅動模型,可實作跨作業系統遷移,自适應器件差異,子產品化拼裝編譯等功能。各WiFi廠商驅動開發人員可根據WiFi子產品提供的向下統一接口适配各自的驅動代碼。

  • 核心驅動

包含linux核心标準的Wifi驅動程式和協定。

2.2 關鍵子產品實作

2.2.1 程序間通信

Native JS和Wifi架構通過IPC(Inter-Process Communication)進行通信,實作接口調用及事件傳遞。IPC通信采用用戶端-伺服器(Client-Server)模型,服務請求方(Client)可擷取提供服務提供方(Server)的代理 (Proxy),并通過此代理讀寫資料來實作程序間的資料通信。

在鴻蒙系統中,首先服務端注冊系統能力(System Ability)到系統能力管理者(System Ability Manager,縮寫SAMgr),SAMgr負責管理這些SA并向用戶端提供相關的接口。用戶端要和某個具體的SA通信,必須先從SAMgr中擷取該SA的代理,然後使用代理和服務端通信,Proxy表示服務請求方,Stub表示服務提供方。

Wifi系統對不同模式各實作了一套Proxy-Stub類,分别是WifiDeviceProxy和WifiDeviceStub、WifiHotspotProxy和WifiHotspotStub、WifiP2pProxy和WifiP2pStub、WifiScanProxy和WifiScanStub,對于不同業務流程進行了分離。

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

WifiDeviceProxy和WifiDeviceStub類圖

以WifiDeviceProxy和WifiDeviceStub為例,分别從服務方和代理方說明實作過程。

WiFi架構提供服務方WifiDeviceStub,繼承IRemoteStub,實作了IWifiDevice接口類中未實作的方法,并重寫了OnRemoteRequest方法。Proxy請求方發來的請求就在OnRemoteRequest中處理。

1. int WifiDeviceStub::OnRemoteRequest(uint32\_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)

2. {

3. int exception = data.ReadInt32();

4. if (exception) {

5. return WIFI\_OPT\_FAILED;

6. }

7.

8. HandleFuncMap::iterator iter = handleFuncMap.find(code);

9. if (iter == handleFuncMap.end()) {

10. WIFI\_LOGI("not find function to deal, code %{public}u", code);

11. reply.WriteInt32(0);

12. reply.WriteInt32(WIFI\_OPT\_NOT\_SUPPORTED);

13. } else {

14. (this-\>\*(iter-\>second))(code, data, reply);

15. }

16.

17. return 0;

18. }

           

以開關wifi接口處理函數為例,WifiDeviceStub對proxy請求事件和相應處理函數進行了映射。

1. handleFuncMap[WIFI\_SVR\_CMD\_ENABLE\_WIFI] = &WifiDeviceStub::OnEnableWifi;

2. handleFuncMap[WIFI\_SVR\_CMD\_DISABLE\_WIFI] = &WifiDeviceStub::OnDisableWifi;

           

WifiDeviceServiceImpl繼承WifiDeviceStub類和SystemAbility類,是IPC通信服務方的具體實作,如以下代碼所示,WifiDeviceServiceImpl通過MakeAndRegisterAbility将WifiDeviceServiceImpl執行個體注冊到SAMgr。接下來,服務請求方就可以通過從SAMgr擷取代理來和服務提供方通信。

1. const bool REGISTER\_RESULT = SystemAbility::MakeAndRegisterAbility(WifiDeviceServiceImpl::GetInstance().GetRefPtr());

2.

3. sptr\<WifiDeviceServiceImpl\> WifiDeviceServiceImpl::GetInstance()

4. {

5. if (g\_instance == nullptr) {

6. std::lock\_guard\<std::mutex\> autoLock(g\_instanceLock);

7. if (g\_instance == nullptr) {

8. auto service = new (std::nothrow) WifiDeviceServiceImpl;

9. g\_instance = service;

10. }

11. }

12. return g\_instance;

13. }

14.

15. WifiDeviceServiceImpl::WifiDeviceServiceImpl()

16. : SystemAbility(WIFI\_DEVICE\_ABILITY\_ID, true), mPublishFlag(false), mState(ServiceRunningState::STATE\_NOT\_START)

17. {}

           

WifiDeviceProxy繼承自IRemoteProxy,封裝WiFi Station模式相關業務函數,調用SendRequest将請求發到服務端Stub。

WiFi Native JS作為服務請求方構造代理WifiDeviceProxy,WifiDeviceImpl執行個體初始化時通過Init函數構造WifiDeviceProxy,步驟如下:

首先,擷取SAMgr。

然後,通過SAMgr及相應的ability id擷取到對應SA的代理IRemoteObject。

最後,使用IRemoteObject構造WifiDeviceProxy。

1. bool WifiDeviceImpl::Init()

2. {

3. sptr\<ISystemAbilityManager\> sa\_mgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();

4. if (sa\_mgr == nullptr) {

5. WIFI\_LOGE("failed to get SystemAbilityManager");

6. return false;

7. }

8.

9. sptr\<IRemoteObject\> object = sa\_mgr-\>GetSystemAbility(systemAbilityId\_);

10. if (object == nullptr) {

11. WIFI\_LOGE("failed to get DEVICE\_SERVICE");

12. return false;

13. }

14.

15. client\_ = iface\_cast\<IWifiDevice\>(object);

16. if (client\_ == nullptr) {

17. client\_ = new (std::nothrow) WifiDeviceProxy(object);

18. }

19.

20. if (client\_ == nullptr) {

21. WIFI\_LOGE("wifi device init failed. %{public}d", systemAbilityId\_);

22. return false;

23. }

24.

25. return true;

}

           

WifiDeviceProxy通過Remote()->SendRequest()發送請求,服務方通過OnRemoteRequest進行處理。以EnableWifi為例:

1. ErrCode WifiDeviceProxy::EnableWifi()

2. {

3. if (mRemoteDied) {

4. WIFI\_LOGD("failed to `%{public}s`,remote service is died!", \_\_func\_\_);

5. return WIFI\_OPT\_FAILED;

6. }

7. MessageOption option;

8. MessageParcel data;

9. MessageParcel reply;

10. data.WriteInt32(0);

11.

12. int error = Remote()-\>SendRequest(WIFI\_SVR\_CMD\_ENABLE\_WIFI, data, reply, option);

13. if (error != ERR\_NONE) {

14. WIFI\_LOGE("Set Attr(%{public}d) failed,error code is %{public}d", WIFI\_SVR\_CMD\_ENABLE\_WIFI, error);

15. return WIFI\_OPT\_FAILED;

16. }

17.

18. int exception = reply.ReadInt32();

19. if (exception) {

20. return WIFI\_OPT\_FAILED;

21. }

22. return ErrCode(reply.ReadInt32());

23. }

           

2.2.2 狀态機管理

Wifi架構維護了四個狀态機,分别是sta statemachine、scan statemachine、p2p statemachine和ap statemachine。Wifi各個模式工作流程中會涉及到各個不同的階段,需要對不同階段的狀态進行管理。對于Native JS通過代理發送到Wifi架構的請求以及HAL回送的WPA Supplicant的響應,需要在相應模式的相應狀态下做合适的處理。

本章僅介紹Wifi基本模式sta和scan的狀态機。

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

Sta狀态機樹狀圖

Sta狀态機維護了wifi打開、關閉、連接配接、擷取IP及漫遊的狀态及切換。Wifi打開時,會啟動staService,構造sta statemachine并初始化。如sta狀态機樹狀圖所示,sta statemachine在初始化時,會建立狀态樹,建立子狀态必須保證相應的父狀态被建立。當遷移到子狀态,子狀态激活,也就是執行GoInState後,其父節點會同時處于激活狀态,不會調用GoOutState,子節點共同需要處理的事件或者不關心的事件由父狀态處理,子狀态隻負責處理自己感興趣的消息。

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

Sta狀态機遷移圖

比如wifi打開時,狀态機從InitState遷移到目标狀态SeparatedState,這時處于激活狀态的有WpaStartedState及LinkState。

當wifi關閉時,WpaStartedState處理WIFI_SVR_CMD_STA_DISABLE_WIFI事件,關閉wifi,回到InitState狀态。

當使用者連接配接網絡時,LinkState處理CMD_START_CONNECT_SELECTED_NETWORK事件進行連接配接網絡的動作,收到WIFI_SVR_CMD_STA_NETWORK_CONNECTION_EVENT後,狀态遷移到GetIpState狀态,同時ApLinkedState狀态處于激活。在GetIpState狀态,如果IP位址配置設定成功,則進入LinkedState。如果配置設定失敗,則回到SeparatedState。

不管是在GetIpState還是在LinkedState,隻要收到斷開網絡請求WIFI_SVR_CMD_STA_DISCONNECT,都由ApLinkedState處理,進入SeparatedState。

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

Scan狀态機維護了wifi普通掃描,pno掃描(硬體掃描和軟體掃描)的狀态及切換過程。

這裡對PNO掃描稍加說明,PNO掃描即Preferred Network Offload,用于系統在休眠的時候連接配接WiFi,當手機休眠時,存在已經儲存的網絡并且沒有連接配接時,進行PNO掃描,隻掃描已儲存的網絡。PNO模式能讓裝置在熄屏時通過搜尋最近連接配接過的Wifi網絡,進而優先連接配接至Wifi網絡,達到延長續航時間并且減少手機資料流量消耗的目的。

Wifi打開後,啟動scanService同時構造scan statemachine并初始化,與sta statemachine相同,scan statemachine按照Scan狀态機樹狀圖所示建立狀态機各個狀态。

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

Scan狀态機遷移

scan statemachine初始化時設定狀态為InitState,随後發送CMD_SCAN_PREPARE給InitState,進入HardwareReady狀态。

處于HardwareReady狀态時Native JS調用scan接口進行掃描,HardwareReady會收到CMD_START_COMMON_SCAN消息進入CommonScanning狀态,掃描成功、失敗或者逾時後進入CommonScanUnworked狀态,如果這時候再次發起掃描則會回到CommonScanning狀态。

處于HardwareReady狀态時發起PNO掃描時,首先判斷系統是否支援硬體PNO掃描,如果支援,則進入PnoScanHardware狀态,向底層下發PNO掃描指令。

在PnoScanHardware狀态,如果收到PNO掃描結果通知,并且NeedCommonScanAfterPno為true,則進入CommonScanAfterPno狀态,等收到CMD_START_COMMON_SCAN進入CommonScanning,或者收到普通掃描指令,進入HardwareReady狀态準備進行普通掃描,否則一直處于PNO硬體掃描狀态。

當發起PNO掃描後,如果系統不支援硬體PNO掃描,則進入PnoScanSoftware狀态,啟動一次軟體PNO掃描,進入PnoSwScanning狀态,掃描成功或者失敗或者逾時後進入PnoSwScanFree狀态。

在PnoSwScanFree狀态,收到CMD_START_COMMON_SCAN指令,則回到HardwareReady狀态準備進行一次普通掃描;如果收到PNO掃描指令則回到PnoSwScanning狀态。

2.2.3 WPA Supplicant

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

wpa_supplicant架構圖

wpa_supplicant是一個獨立運作的守護程序,其核心是一個消息循環,在消息循環中處理WPA狀态機、控制指令、驅動事件、配置資訊等。

wpa_supplicant由啟動,通過建立兩個上行接口,通過這兩個接口進行指令發送和事件監聽;通過通信實作下行接口,與核心進行通信,下發指令和擷取消息。

3. WiFi業務流程

3.1 WiFi Station流程

3.1.1 打開流程

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

wifi啟動時序

上圖為wifi啟動時序圖,其中WifiDeviceImpl是Native JS層WifiDevice的實作類。

WifiDeviceServiceImpl是Wifi架構層對Navtive JS端IPC通信服務的實作類。

StaService是Wifi架構層Station服務的主要實作,通過建立StaStateMachine和StaMonitor對Wifi Station指令和事件進行處理。如上圖中所示,調用Native JS中的EnableWifi接口,首先擷取WifiDevice執行個體,調用該執行個體提供的EnableWifi。 然後通過WifiDeviceProxy向Stub發送請求,Stub響應請求。

Stub服務端實作了EnableWifi的實作邏輯,首先,構造StaService并進行初始化,StaService初始化時構造StaStateMachine并初始化狀态機,進入InitState狀态,接下來構造StaMonitor并初始化,注冊事件回調函數。StaMonitor主要對AP連接配接狀态改變等事件進行處理。

這些準備工作做完後,就是真正執行EnableWifi的流程。

StaService向StaStateMachine發送WIFI_SVR_CMD_STA_ENABLE_WIFI消息,StaStateMachine轉化為WIFI_SVR_CMD_STA_START_SUPPLICANT消息後通過wifi_idl_client向wifi hal發起RPC調用"Start"。

Wifi Hal作為RPC服務端,啟動後調用InitRpcFunc初始化RPC函數,然後CreateRpcServer,最後調用RunRpcLoop循環讀取遠端調用資訊,處理用戶端請求。

InitRpcFunc中Map了"Start"消息的處理函數,PushRpcFunc("Start", RpcStart)。RpcStart實際操作實作在wifi_hal_sta_interface的Start函數,主要做了三步操作:

  1. start supplicant

指令:wpa_supplicant -iglan0 -g/data/misc/wifi/sockets

  1. Add a new interface wlan0

指令:interface_add wlan0 /data/misc/wifi/wpa_supplicant/wpa_supplicant.conf

  1. 構造并初始化WifiWpaStaInterface,封裝了wpa_supplicant關于STA的操作指令。

以上三步成功後,RPC調用傳回WIFI_HAL_SUCCESS。

StaStateMachine在EnableWifi成功後,執行OnStaOpenRes回調,在此回調裡,廣播wifi狀态改變消息,構造ScanService并初始化。初始化過程做了這幾件事:

  1. 構造ScanStateMachine并初始化,調用EnrollScanStatusListener綁定Scan狀态上報事件的處理函數。
  2. 構造ScanMonitor并初始化,在初始化函數中調用RegisterSupplicantEventCallback,注冊supplicant事件回調。

3.1.2 掃描流程

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

​ Wifi掃描時序

上圖為WiFi掃描時序圖,其中WifiScanImpl是Native JS層WifiScan的實作類。

WifiScanServiceImpl是Wifi架構層對Navtive JS端IPC通信服務的實作類。

ScanService是Wifi架構層Scan服務的主要實作,通過建立ScanStateMachine和ScanMonitor對Wifi Station指令和事件進行處理。

當應用調用Native JSOL的Scan接口,與WiFi打開過程類似,會通過擷取WifiScan執行個體,調用C++接口,最終通過WifiScanProxy向服務架構發送WIFI_SVR_CMD_FULL_SCAN請求。

收到請求,WifiScanServiceImpl調用ScanService,構造scanConfig,然後向ScanStateMachine發送CMD_START_COMMON_SCAN指令并攜帶scanConfig。

ScanStateMachine如果處于HardwareReady等可以發起掃描的激活狀态下,則進行擷取掃描參數的操作,并校驗Scan類型是否合法,之後轉換掃描參數,通過RPC調用HAL的scan操作,HAL得去scan配置參數後,向supplicant發送SCAN指令。

接着擷取掃描結果,時序圖如下:

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

​ 擷取掃描結果

Supplicant執行掃描成功後,調用WifiHalCbNotifyScanEnd(WPA_CB_SCAN_OVER_OK)通知掃描成功。ScanMonitor執行回調,向ScanStateMachine發送SCAN_RESULT_EVENT事件:

pScanStateMachine->SendMessage(static_cast<int>(SCAN_RESULT_EVENT));

ScanStateMachine處理事件,遠端調用wifi hal擷取掃描結果。

WifiHal傳回掃描結果給ScanStateMachine後,ScanStateMachine構造ScanStatusReport,包含scanInfoList和status,交給回調函數ScanService::HandleScanStatusReport處理。

ScanService拿到掃描結果,主要做的事是調用WifiSettings的SaveScanInfoList(filterScanInfo),将掃描結果儲存。之後,調用native js的GetScanInfos接口,通過WifiScanServiceImpl調用WifiSettings的GetScanInfoList擷取到儲存的掃描結果。

掃描結果中包含的資訊如下,一般常用到的資訊有:

Bssid - 掃描到的AP的mac位址

Ssid - 掃描到的AP的辨別名稱

Band - 支援頻段為2.4G還是5G

securityType - 安全類型:

OPEN/WEP/PSK/EAP/SAE/EAP_SUITE_B/OWE/WAPI_CERT/WAPI_PSK

3.1.3 連接配接流程

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

Wifi連接配接時序圖

Native JS調用connectToDevice連接配接選擇的wifi網絡,通過IPC代理發送請求,調用到staService的ConnectToDevice函數。

StaService首先調用AddDeviceConfig,在這個函數中主要做了兩件事:

調用GetNextNetworkId,通過HAL向supplicant發送ADD_NETWORK指令,得到netwrok id,儲存在WifiDeviceConfig。

調用ConvertDeviceCfg,在StaStateMachine中将網絡配置參數轉換為idl參數,然後調用HAL的SetDeviceConfig函數,向supplicant發送SET_NETWORK指令。

StaService在調用AddDeviceConfig得到networkid并且設定配置參數到supplicant成功後,向StaStateMachine發送消息,向supplicant發送EnableNetwork、SELECT_NETWORK以及SAVE_CONFIG指令,supplicant根據收到的指令完成AP的連接配接管理。

Supplicant連接配接成功後,回送事件,經過,轉換為由的回調函數處理,發送消息給,狀态機進入,擷取,靜态或者擷取成功後,繼續調用檢查網絡連接配接狀态。

3.2 WiFi P2P流程

3.2.1 裝置發現流程

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

​ p2p裝置發現時序圖

WiFi架構調用DiscoverDevices啟動WiFi P2P裝置搜尋,DiscoverDevices主要的工作是調用WIFI HAL的WpaP2pCliCmdP2pFound函數,向wpa_supplicant發送P2P_FIND指令。

wpa_supplicant收到P2P_FIND後,就會開始搜尋周邊的P2P裝置,如果找到,給WIFI HAL HAL發送P2P_EVENT_DEVICE_FOUND事件,這個event會帶有對方裝置的資訊,包括MAC位址、device type、裝置名字以及config methods等。

WiFi HAL收到這樣的event後,會将P2P_EVENT_DEVICE_FOUND事件攜帶的資料封裝成HidlP2pDeviceInfo,通過RPC服務端回送給WiFi架構。

作為PRC用戶端,WiFi架構收到HAL事件P2P_DEVICE_FOUND_EVENT對應的事件WIFI_IDL_CBK_CMD_P2P_DEVICE_FOUND_EVENT,讀取HidlP2pDeviceInfo,發送P2P_EVENT_DEVICE_FOUND事件通知wifiP2pStateMachine。

wifiP2pStateMachine調用WifiP2pDeviceManager的UpdateDeviceSupplicantInf函數,更新并儲存本地裝置清單之後調用BroadcastP2pPeersChanged發送裝置清單改變的通知。

注冊了相關事件監聽的應用,在收到通知後調用QueryP2pDevices擷取裝置清單。

QueryP2pDevices最終調用WifiP2pDeviceManager的GetDevicesList擷取本地儲存的裝置清單。

3.3 WiFi 熱點流程

#夏日挑戰賽#OpenHarmony 短距子系統-WIFI源碼分析

熱點啟動時序圖

上圖為WiFi熱點啟動時序圖,其中WifiHotspotImpl是Native JS層WifiHotspot的實作類。

WifiHotspotServiceImpl是Wifi架構層對Navtive JS端IPC通信服務的實作類。

ApService是Wifi架構層AP服務的主要實作,通過建立ApStateMachine和ApMonitor對Wifi熱點指令和事件進行處理。

WifiHotspotImpl通過IPC調用架構WifiHotspotServiceImpl的EnableHotspot,首先檢查是否處于飛行模式或者省電模式,在這兩種模式中禁用熱點,傳回相應的錯誤碼。然後加載APService并初始化,注冊WifiManager的回調函數到APService并通過APService向APStateMachine發送CMD_START_HOTSPOT消息,APStateMachine切換到ApStartedState狀态。

進入啟動狀态時:

啟動APMonitor,RegisterApEvent到WifiApHalInterface處理工作站接入或離開事件以及熱點狀态變化事件。

調用WifiApHalInterface的StartAp啟動hostapd,構造WifiHostapdHalDevice并建立于hostapd通信的控制接口ctrlConn和ctrlRecv,ctrlConn用于向hostapd發送指令,ctrlRecv用于接收從hostapd通知的事件。

調用WifiApHalInterface的SetSoftApConfig對softap進行配置,基本配置資訊包括:ssid(wifi熱點名稱)、熱點密碼以及安全類型(可選的有無加密、WPA-PSK和WPA2-PSK)、最大連接配接數、支援頻帶及信道等。通過RPC調用,向hostapd下發以下一系列指令:

SET wpa_passphrase:設定密碼

SET ssid:設定熱點名稱

SET wpa:設定加密類型 0為NONE,1為WPA-PSK,2位WPA2-PSK

SET hw_mode:設定頻段,參數分别為"any"、"g"(2.4G)、"a"(5G)

SET channel:設定信道

SET max_num_sta:設定最大連接配接數

RELOAD:重新加載配置

DISABLE:關閉AP

ENABLE:使能AP

Hostapd處理完以上指令之後,會上報AP-ENABLED,HAL通知ApMonitor将其轉化為CMD_UPDATE_HOTSPOTCONFIG_RESULT給到ApStartedState,ApStartedState啟動DHCP伺服器,負責為連接配接的工作站配置設定IP,最後通過之前注冊在狀态機的回調函數通知上層AP狀态變為AP_STATE_STATED。

當有工作站連接配接熱點,底層連接配接成功後,hostapd會向HAL發送AP-STA-CONNECTED消息,通知ApMonitor後發送指令CMD_STATION_JOIN到ApStateMachine,調用ApStationsManager通過WifiSettings添加連接配接裝置的資訊,之後廣播COMMON_EVENT_WIFI_AP_STA_JOIN事件,應用通過注冊該事件監聽知道有裝置連接配接。

4. WiFi接口說明

WiFi基礎功能由@ohos.wifi類提供,其接口(JS接口)說明如下。

| 接口名 | 描述 |

| ------------------------------------------------------------ | :-------------------------------------------------------: |

| function enableWifi(): boolean | 打開WiFi |

| function disableWifi(): boolean | 關閉WiFi。 |

| function isWifiActive(): boolean | 查詢WiFi是否處于打開狀态。 |

| function scan(): boolean | 發起WiFi掃描。 |

| function getScanlnfos():Promise<Array<WifiScanlnfo>>function getScanlnfos(callback: AsyncCallback<Array<WifiScanlnfo>>): void | 擷取WiFi掃描結果,接口可采用promise或callback 方式調用。 |

| function addDeviceConfig(config: WifiDeviceConfig):Promise<number>function addDeviceConfig(config: WifiDeviceConfig, callback: AsyncCallback<number>): void | 添加WiFi的配置資訊,接口可采用promise或callback方式調用。 |

| function connectToNetwork(networkld: number): boolean | 連接配接到WiFi網絡。 |

| function connectToDevice(config: WifiDeviceConfig):boolean | 連接配接到WiFi網絡。 |

| function disconnect(): boolean | 斷開WiFi連接配接。 |

| function getSignalLevel(rssi: number, band: number):number | 擷取WiFi信号強度。 |

更多原創内容請關注:深開鴻技術團隊

入門到精通、技巧到案例,系統化分享HarmonyOS開發技術,歡迎投稿和訂閱,讓我們一起攜手前行共建鴻蒙生态。

繼續閱讀