#夏日挑战赛#OpenHarmony 短距子系统-WIFI源码分析 原创 精华
作者:巴延兴
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函数,主要做了三步操作:
- start supplicant
命令:wpa_supplicant -iglan0 -g/data/misc/wifi/sockets
- Add a new interface wlan0
命令:interface_add wlan0 /data/misc/wifi/wpa_supplicant/wpa_supplicant.conf
- 构造并初始化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<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 连接流程
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():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开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
这篇对WiFi的讲解非常全面,如果想进一步了解老师有什么好的推荐书籍吗?
现在WiFi不都是hdf框架了吗,怎么还是 wpa