#夏日挑战赛#OpenHarmony 短距子系统-WIFI源码分析 原创 精华

深开鸿
发布于 2022-7-15 17:09
浏览
4收藏

本文正在参加星光计划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开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
3
收藏 4
回复
举报
2条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

这篇对WiFi的讲解非常全面,如果想进一步了解老师有什么好的推荐书籍吗?

回复
2022-7-18 17:44:45
一个爱技术的码农
一个爱技术的码农

现在WiFi不都是hdf框架了吗,怎么还是 wpa

回复
2022-7-25 08:30:43
回复
    相关推荐