【鸿蒙南向开发】OpenHarmony 短距子系统-WIFI源码分析

199 篇文章 0 订阅
198 篇文章 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。

下表简单介绍了各个标准的发布时间和特点。

在这里插入图片描述

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)。

在这里插入图片描述

​ 图 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 系统架构简介

在这里插入图片描述

图 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,对于不同业务流程进行了分离。

在这里插入图片描述

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 的状态机。
在这里插入图片描述

Sta 状态机树状图

Sta 状态机维护了 wifi 打开、关闭、连接、获取 IP 及漫游的状态及切换。Wifi 打开时,会启动 staService,构造 sta statemachine 并初始化。如 sta 状态机树状图所示,sta statemachine 在初始化时,会创建状态树,创建子状态必须保证相应的父状态被创建。当迁移到子状态,子状态激活,也就是执行 GoInState 后,其父节点会同时处于激活状态,不会调用 GoOutState,子节点共同需要处理的事件或者不关心的事件由父状态处理,子状态只负责处理自己感兴趣的消息。

在这里插入图片描述

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。

在这里插入图片描述

Scan 状态机维护了 wifi 普通扫描,pno 扫描(硬件扫描和软件扫描)的状态及切换过程。

这里对 PNO 扫描稍加说明,PNO 扫描即 Preferred Network Offload,用于系统在休眠的时候连接 WiFi,当手机休眠时,存在已经保存的网络并且没有连接时,进行 PNO 扫描,只扫描已保存的网络。PNO 模式能让设备在熄屏时通过搜索最近连接过的 Wifi 网络,从而优先连接至 Wifi 网络,达到延长续航时间并且减少手机数据流量消耗的目的。

Wifi 打开后,启动 scanService 同时构造 scan statemachine 并初始化,与 sta statemachine 相同,scan statemachine 按照 Scan 状态机树状图所示创建状态机各个状态。

在这里插入图片描述

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

在这里插入图片描述

wpa_supplicant 框架图

wpa_supplicant 是一个独立运行的守护进程,其核心是一个消息循环,在消息循环中处理 WPA 状态机、控制命令、驱动事件、配置信息等。

wpa_supplicant 由启动,通过创建两个上行接口,通过这两个接口进行命令发送和事件监听;通过通信实现下行接口,与内核进行通信,下发命令和获取消息。

3. WiFi 业务流程

3.1 WiFi Station 流程

3.1.1 打开流程

在这里插入图片描述

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

2.Add a new interface wlan0
命令:interface_add wlan0 /data/misc/wifi/wpa_supplicant/wpa_supplicant.conf

3.构造并初始化 WifiWpaStaInterface,封装了 wpa_supplicant 关于 STA 的操作命令。
以上三步成功后,RPC 调用返回 WIFI_HAL_SUCCESS。

StaStateMachine 在 EnableWifi 成功后,执行 OnStaOpenRes 回调,在此回调里,广播 wifi 状态改变消息,构造 ScanService 并初始化。初始化过程做了这几件事:

构造 ScanStateMachine 并初始化,调用 EnrollScanStatusListener 绑定 Scan 状态上报事件的处理函数。
构造 ScanMonitor 并初始化,在初始化函数中调用 RegisterSupplicantEventCallback,注册 supplicant 事件回调。

3.1.2 扫描流程

在这里插入图片描述

​ 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 命令。

接着获取扫描结果,时序图如下:
在这里插入图片描述

​ 获取扫描结果

Supplicant 执行扫描成功后,调用 WifiHalCbNotifyScanEnd(WPA_CB_SCAN_OVER_OK)通知扫描成功。ScanMonitor 执行回调,向 ScanStateMachine 发送 SCAN_RESULT_EVENT 事件:

pScanStateMachine->SendMessage(static_cast(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 连接流程

在这里插入图片描述

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 设备发现流程

在这里插入图片描述

​ 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 热点流程

在这里插入图片描述

热点启动时序图

上图为 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():Promisefunction getScanlnfos(callback: AsyncCallback): void | 获取 WiFi 扫描结果,接口可采用 promise 或 callback 方式调用。 |

| function addDeviceConfig(config: WifiDeviceConfig):Promisefunction addDeviceConfig(config: WifiDeviceConfig, callback: AsyncCallback): 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 NEXT)文档用来跟着学习是非常有必要的。

这份鸿蒙(HarmonyOS NEXT)文档包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习文档能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习文档

鸿蒙(HarmonyOS NEXT)5.0最新学习路线

在这里插入图片描述

有了路线图,怎么能没有学习文档呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习文档

《鸿蒙 (OpenHarmony)开发入门教学视频》

在这里插入图片描述

《鸿蒙生态应用开发V3.0白皮书》

在这里插入图片描述

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

在这里插入图片描述

《鸿蒙开发基础》

●ArkTS语言
●安装DevEco Studio
●运用你的第一个ArkTS应用
●ArkUI声明式UI开发
.……
在这里插入图片描述

《鸿蒙开发进阶》

●Stage模型入门
●网络管理
●数据管理
●电话服务
●分布式应用开发
●通知与窗口管理
●多媒体技术
●安全技能
●任务管理
●WebGL
●国际化开发
●应用测试
●DFX面向未来设计
●鸿蒙系统移植和裁剪定制
……
在这里插入图片描述

《鸿蒙进阶实战》

●ArkTS实践
●UIAbility应用
●网络案例
……
在这里插入图片描述

获取以上完整鸿蒙HarmonyOS学习文档,请点击→纯血版全套鸿蒙HarmonyOS学习文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值