當(dāng)前位置:首頁 > IT技術(shù) > 其他 > 正文

OpenHarmony3.1-WIFI子系統(tǒng)之STA模式源碼解析
2022-05-31 17:16:06

作者:李威

簡(jiǎn)介

Wi-Fi是WLAN具體采用的技術(shù),也是目前WLAN的主流技術(shù)。Wi-Fi采用的技術(shù)是IEEE80211系列協(xié)議,IEEE (Institute of Electrical and Electronics Engineers)是美國電氣和電子工程師協(xié)會(huì)的簡(jiǎn)稱。

STA模式:Station,類似于無線終端,sta本身并不接受無線的接入,它可以連接到AP(AccessPoint),一般無線網(wǎng)卡即工作在該模式,這是Wifi最基本的工作模式。

Wifi子系統(tǒng)架構(gòu)

Wifi子系統(tǒng)架構(gòu)圖.png

Wifi架構(gòu)解析

Wi-Fi App

主要是開發(fā)者自行開發(fā)Wi-Fi相關(guān)功能的應(yīng)用。通過調(diào)用Wifi SDK對(duì)外提供的API實(shí)現(xiàn)對(duì)設(shè)備Wi-Fi的控制及其功能實(shí)現(xiàn)。這一層平臺(tái)將會(huì)提供相關(guān)的API調(diào)用示例,以供參考。

Wi-Fi Native JS:

JS層使用NAPI機(jī)制開發(fā),連接APP層與Framework層,將wifi功能封裝成JS接口提供給應(yīng)用調(diào)用,并同時(shí)支持Promise和Callback異步回調(diào)。

Wi-Fi Framework

Wi-Fi核心功能實(shí)現(xiàn)。直接為上層應(yīng)用提供服務(wù)。根據(jù)其工作模式的不同分為四大業(yè)務(wù)服務(wù)模塊,分別是STA服務(wù)、AP服務(wù)、P2P服務(wù)、Aware服務(wù),同時(shí)DHCP功能。

Wi-Fi Hal

為FrameWork層操作Wi-Fi硬件提供統(tǒng)一的接口服務(wù),實(shí)現(xiàn)應(yīng)用框架與硬件操作的分離。主要包括Hal適配器及擴(kuò)展Hal模塊及Wi-Fi硬件廠家提供的二進(jìn)制庫模塊。

WPA Supplicant:

包含wpa_supplicant和hosapd兩個(gè)子模塊,wpa_supplicant和hostapd實(shí)現(xiàn)了定義好的驅(qū)動(dòng)API,對(duì)外提供控制接口,框架就能通過其控制接口來實(shí)現(xiàn)Wifi的各種操作。wpa_supplicant支持STA及P2P模式,hostapd則支持AP模式。

HDF

HDF 驅(qū)動(dòng)框架主要由驅(qū)動(dòng)基礎(chǔ)框架、驅(qū)動(dòng)程序、驅(qū)動(dòng)配置文件和驅(qū)動(dòng)接口這四個(gè)部分組成,實(shí)現(xiàn)WIfi驅(qū)動(dòng)功能,加載驅(qū)動(dòng),驅(qū)動(dòng)接口部署等。

Wi-Fi Kernel

包含Wi-Fi 驅(qū)動(dòng),包括了對(duì)設(shè)備的一些基本的讀寫操作由Wi-Fi驅(qū)動(dòng)移植人員編譯進(jìn)內(nèi)核。

代碼結(jié)構(gòu)

/foundation/communication/wifi
├── figures            # 圖片資源目錄
├── interfaces         # 接口適配目錄
│   ├── innerkits      # 內(nèi)部接口適配目錄
│   └── kits           # WLAN組件接口的適配代碼存放目錄
├── services           # service適配目錄
│   └── wifi_standard  # service實(shí)現(xiàn)目錄
├── tests              # 測(cè)試代碼目錄
│   └── wifi_standard  # service實(shí)現(xiàn)模塊測(cè)試代碼
└── utils              # 實(shí)用函數(shù)目錄
    ├── inc            # 實(shí)用函數(shù)頭文件目錄
    └── src            # 實(shí)用函數(shù)實(shí)現(xiàn)目錄

關(guān)鍵模塊實(shí)現(xiàn)

IPC通信

Native JS和Wifi框架通過IPC(Inter-Process Communication)進(jìn)行通信,實(shí)現(xiàn)接口調(diào)用及事件傳遞。IPC通信采用客戶端-服務(wù)器(Client-Server)模型,服務(wù)請(qǐng)求方(Client)可獲取提供服務(wù)提供方(Server)的代理 (Proxy),并通過此代理讀寫數(shù)據(jù)來實(shí)現(xiàn)進(jìn)程間的數(shù)據(jù)通信。

在鴻蒙系統(tǒng)中,首先服務(wù)端注冊(cè)系統(tǒng)能力(System Ability)到系統(tǒng)能力管理者(System Ability Manager,縮寫SAMgr),SAMgr負(fù)責(zé)管理這些SA并向客戶端提供相關(guān)的接口??蛻舳艘湍硞€(gè)具體的SA通信,必須先從SAMgr中獲取該SA的代理,然后使用代理和服務(wù)端通信,Proxy表示服務(wù)請(qǐng)求方,Stub表示服務(wù)提供方。

Wifi系統(tǒng)對(duì)不同模式各實(shí)現(xiàn)了一套Proxy-Stub類,STA模式分別是WifiDeviceProxy和WifiDeviceStub,WifiScanProxy和WifiScanStub,對(duì)掃描和其他STA流程進(jìn)行了分離。

IPC通信圖.png

由圖所示,首先WifiDeviceImpl是Native JS層WifiDevice的實(shí)現(xiàn)類,是服務(wù)請(qǐng)求方,作為IPC服務(wù)客戶端,WifiDeviceProxy作為代理類,通過它來向服務(wù)方發(fā)起請(qǐng)求;WifiDeviceStub作為服務(wù)方接收請(qǐng)求并處理;WifiDeviceServiceImpl繼承WifiDeviceStub類和SystemAbility類,是IPC通信服務(wù)方的具體實(shí)現(xiàn)。

以WifiDeviceProxy和WifiDeviceStub為例,分別從代理方和服務(wù)方說明實(shí)現(xiàn)過程。

WiFi Native JS作為服務(wù)請(qǐng)求方發(fā)起流程時(shí),WifiDeviceImpl初始化通過Init函數(shù)構(gòu)造代理WifiDeviceProxy,步驟如下:

首先,獲取SAMgr。

然后,通過SAMgr及相應(yīng)的ability id獲取到對(duì)應(yīng)SA的代理IRemoteObject。

最后,使用IRemoteObject構(gòu)造WifiDeviceProxy。

目錄:foundation/communication/wifi/interfaces/innerkits/native_cpp/wifi_standard/src/wifi_device_impl.cpp

```c++
bool WifiDeviceImpl::Init()
{
//獲取SAMgr
sptr<ISystemAbilityManager> sa_mgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (sa_mgr == nullptr) {
WIFI_LOGE("failed to get SystemAbilityManager");
return false;
}
//通過SAMgr及相應(yīng)的ability id獲取到對(duì)應(yīng)SA的代理IRemoteObject
sptr<IRemoteObject> object = samgr->GetSystemAbility(systemAbilityId);
if (object == nullptr) {
WIFI_LOGE("failed to get DEVICESERVICE");
return false;
}
//使用IRemoteObject構(gòu)造WifiDeviceProxy
client
= ifacecast<IWifiDevice>(object);
if (client
== nullptr) {
client_ = new (std::nothrow) WifiDeviceProxy(object); //構(gòu)造代理
}

if (client_ == nullptr) {
    WIFI_LOGE("wifi device init failed. %{public}d", systemAbilityId_);
    return false;
}

return true;

}


我們以打開WiFi為例看看其調(diào)用過程,客戶端發(fā)起請(qǐng)求后,接口層提供WifiDeviceProxy作為代理發(fā)送打開WiFi請(qǐng)求:

**目錄:foundation/communication/wifi/interfaces/innerkits/native_cpp/wifi_standard/src/wifi_device_proxy.cpp**

```c++
ErrCode WifiDeviceProxy::EnableWifi()
{
    if (mRemoteDied) {
        WIFI_LOGD("failed to `%{public}s`,remote service is died!", __func__);
        return WIFI_OPT_FAILED;
    }
    MessageOption option;
    MessageParcel data;
    MessageParcel reply;
    data.WriteInt32(0);

    int error = Remote()->SendRequest(WIFI_SVR_CMD_ENABLE_WIFI, data, reply, option);  //向服務(wù)方發(fā)送WIFI_SVR_CMD_ENABLE_WIFI請(qǐng)求
    if (error != ERR_NONE) {
        WIFI_LOGE("Set Attr(%{public}d) failed,error code is %{public}d", WIFI_SVR_CMD_ENABLE_WIFI, error);
        return WIFI_OPT_FAILED;
    }

    int exception = reply.ReadInt32();
    if (exception) {
        return WIFI_OPT_FAILED;
    }
    return ErrCode(reply.ReadInt32());
}

WifiDeviceProxy繼承自IRemoteProxy,封裝WiFi Station模式相關(guān)業(yè)務(wù)函數(shù),調(diào)用SendRequest將請(qǐng)求發(fā)到服務(wù)端Stub。

WiFi框架提供服務(wù)方WifiDeviceStub,繼承IRemoteStub,實(shí)現(xiàn)了IWifiDevice接口類中未實(shí)現(xiàn)的方法,并重寫了OnRemoteRequest方法。Proxy請(qǐng)求方發(fā)來的請(qǐng)求就在OnRemoteRequest中處理。

目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_device_stub.cpp

```c++
int WifiDeviceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
int exception = data.ReadInt32();
if (exception) {
return WIFI_OPT_FAILED;
}

HandleFuncMap::iterator iter = handleFuncMap.find(code);
if (iter == handleFuncMap.end()) {
    WIFI_LOGI("not find function to deal, code %{public}u", code);
    reply.WriteInt32(0);
    reply.WriteInt32(WIFI_OPT_NOT_SUPPORTED);
} else {
    (this->*(iter->second))(code, data, reply);
}

return 0;

}


WifiDeviceStub對(duì)proxy請(qǐng)求事件和相應(yīng)處理函數(shù)進(jìn)行了映射。

```c++
void WifiDeviceStub::InitHandleMap()
{
    handleFuncMap[WIFI_SVR_CMD_ENABLE_WIFI] = &WifiDeviceStub::OnEnableWifi;  //打開wifi
    handleFuncMap[WIFI_SVR_CMD_DISABLE_WIFI] = &WifiDeviceStub::OnDisableWifi;
    ......
    return;
}

根據(jù)映射關(guān)系調(diào)用其OnEnableWifi方法:

```c++
void WifiDeviceStub::OnEnableWifi(uint32_t code, MessageParcel &data, MessageParcel &reply)
{
WIFI_LOGD("run %{public}s code %{public}u, datasize %{public}zu", func, code, data.GetRawDataSize());
ErrCode ret = EnableWifi();
reply.WriteInt32(0);
reply.WriteInt32(ret);

return;

}


這里調(diào)用EnableWifi(),其具體實(shí)現(xiàn)在子類WifiDeviceServiceImpl。

WifiDeviceServiceImpl作為IPC通信服務(wù)方的具體實(shí)現(xiàn),如以下代碼所示,WifiDeviceServiceImpl通過MakeAndRegisterAbility將WifiDeviceServiceImpl實(shí)例注冊(cè)到SAMgr。接下來,服務(wù)請(qǐng)求方就可以通過從SAMgr獲取代理來和服務(wù)提供方通信。

```c++
const bool REGISTER_RESULT = SystemAbility::MakeAndRegisterAbility(WifiDeviceServiceImpl::GetInstance().GetRefPtr());

sptr<WifiDeviceServiceImpl> WifiDeviceServiceImpl::GetInstance()
{
    if (g_instance == nullptr) {
        std::lock_guard<std::mutex> autoLock(g_instanceLock);
        if (g_instance == nullptr) {
            auto service = new (std::nothrow) WifiDeviceServiceImpl;
            g_instance = service;
        }
    }
    return g_instance;
}

WifiDeviceServiceImpl::WifiDeviceServiceImpl()
    : SystemAbility(WIFI_DEVICE_ABILITY_ID, true), mPublishFlag(false), mState(ServiceRunningState::STATE_NOT_START)
{}

狀態(tài)機(jī)管理

Wifi框架維護(hù)了四個(gè)狀態(tài)機(jī),分別是sta statemachine、scan statemachine、p2p statemachine和ap statemachine。Wifi各個(gè)模式工作流程中會(huì)涉及到各個(gè)不同的階段,需要對(duì)不同階段的狀態(tài)進(jìn)行管理。對(duì)于Native JS通過代理發(fā)送到Wifi框架的請(qǐng)求以及HAL回送的WPA Supplicant的響應(yīng),需要在相應(yīng)模式的相應(yīng)狀態(tài)下做合適的處理。

本章僅介紹Wifi基本模式STA和Scan的狀態(tài)機(jī)。

Sta狀態(tài)機(jī)樹狀圖.png

STA狀態(tài)機(jī)維護(hù)了wifi打開、關(guān)閉、連接、獲取IP及漫游的狀態(tài)及切換。Wifi打開時(shí),會(huì)啟動(dòng)staService,構(gòu)造sta statemachine并初始化。如STA狀態(tài)機(jī)樹狀圖所示,sta statemachine在初始化時(shí),會(huì)創(chuàng)建狀態(tài)樹,創(chuàng)建子狀態(tài)必須保證相應(yīng)的父狀態(tài)被創(chuàng)建。當(dāng)遷移到子狀態(tài),子狀態(tài)激活,也就是執(zhí)行GoInState后,其父節(jié)點(diǎn)會(huì)同時(shí)處于激活狀態(tài),不會(huì)調(diào)用GoOutState,子節(jié)點(diǎn)共同需要處理的事件或者不關(guān)心的事件由父狀態(tài)處理,子狀態(tài)只負(fù)責(zé)處理自己感興趣的消息。

Sta狀態(tài)機(jī)遷移圖.png

比如wifi打開時(shí),狀態(tài)機(jī)從InitState遷移到目標(biāo)狀態(tài)SeparatedState,這時(shí)處于激活狀態(tài)的有WpaStartedState及LinkState。

當(dāng)wifi關(guān)閉時(shí),WpaStartedState處理WIFI_SVR_CMD_STA_DISABLE_WIFI事件,關(guān)閉wifi,回到InitState狀態(tài)。

當(dāng)用戶連接網(wǎng)絡(luò)時(shí),LinkState處理CMD_START_CONNECT_SELECTED_NETWORK事件進(jìn)行連接網(wǎng)絡(luò)的動(dòng)作,收到WIFI_SVR_CMD_STA_NETWORK_CONNECTION_EVENT后,狀態(tài)遷移到GetIpState狀態(tài),同時(shí)ApLinkedState狀態(tài)處于激活。在GetIpState狀態(tài),如果IP地址分配成功,則進(jìn)入LinkedState。如果分配失敗,則回到SeparatedState。

不管是在GetIpState還是在LinkedState,只要收到斷開網(wǎng)絡(luò)請(qǐng)求WIFI_SVR_CMD_STA_DISCONNECT,都由ApLinkedState處理,進(jìn)入SeparatedState。

Scan狀態(tài)機(jī)樹狀圖.png

Scan狀態(tài)機(jī)維護(hù)了wifi普通掃描,pno掃描(硬件掃描和軟件掃描)的狀態(tài)及切換過程。

這里對(duì)PNO掃描稍加說明,PNO掃描即Preferred Network Offload,用于系統(tǒng)在休眠的時(shí)候連接WiFi,當(dāng)手機(jī)休眠時(shí),存在已經(jīng)保存的網(wǎng)絡(luò)并且沒有連接時(shí),進(jìn)行PNO掃描,只掃描已保存的網(wǎng)絡(luò)。PNO模式能讓設(shè)備在熄屏?xí)r通過搜索最近連接過的Wifi網(wǎng)絡(luò),從而優(yōu)先連接至Wifi網(wǎng)絡(luò),達(dá)到延長(zhǎng)續(xù)航時(shí)間并且減少手機(jī)數(shù)據(jù)流量消耗的目的。

Wifi打開后,啟動(dòng)scanService同時(shí)構(gòu)造scan statemachine并初始化,與sta statemachine相同,scan statemachine按照Scan狀態(tài)機(jī)樹狀圖所示創(chuàng)建狀態(tài)機(jī)各個(gè)狀態(tài)。

Scan狀態(tài)機(jī)遷移圖.png

scan statemachine初始化時(shí)設(shè)置狀態(tài)為InitState,隨后發(fā)送CMD_SCAN_PREPARE給InitState,進(jìn)入HardwareReady狀態(tài)。

處于HardwareReady狀態(tài)時(shí)Native JS調(diào)用scan接口進(jìn)行掃描,HardwareReady會(huì)收到CMD_START_COMMON_SCAN消息進(jìn)入CommonScanning狀態(tài),掃描成功、失敗或者超時(shí)后進(jìn)入CommonScanUnworked狀態(tài),如果這時(shí)候再次發(fā)起掃描則會(huì)回到CommonScanning狀態(tài)。

處于HardwareReady狀態(tài)時(shí)發(fā)起PNO掃描時(shí),首先判斷系統(tǒng)是否支持硬件PNO掃描,如果支持,則進(jìn)入PnoScanHardware狀態(tài),向底層下發(fā)PNO掃描命令。

在PnoScanHardware狀態(tài),如果收到PNO掃描結(jié)果通知,并且NeedCommonScanAfterPno為true,則進(jìn)入CommonScanAfterPno狀態(tài),等收到CMD_START_COMMON_SCAN進(jìn)入CommonScanning,或者收到普通掃描命令,進(jìn)入HardwareReady狀態(tài)準(zhǔn)備進(jìn)行普通掃描,否則一直處于PNO硬件掃描狀態(tài)。

當(dāng)發(fā)起PNO掃描后,如果系統(tǒng)不支持硬件PNO掃描,則進(jìn)入PnoScanSoftware狀態(tài),啟動(dòng)一次軟件PNO掃描,進(jìn)入PnoSwScanning狀態(tài),掃描成功或者失敗或者超時(shí)后進(jìn)入PnoSwScanFree狀態(tài)。

在PnoSwScanFree狀態(tài),收到CMD_START_COMMON_SCAN命令,則回到HardwareReady狀態(tài)準(zhǔn)備進(jìn)行一次普通掃描;如果收到PNO掃描命令則回到PnoSwScanning狀態(tài)。

STA業(yè)務(wù)代碼流程

前面講過,Native Js發(fā)起調(diào)用,經(jīng)過IPC通信,調(diào)用到WifiDeviceServiceImpl作為服務(wù)端的實(shí)現(xiàn)。

Wifi打開流程

Wifi打開流程時(shí)序圖.png

目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_device_service_impl.cpp

```c++
ErrCode WifiDeviceServiceImpl::EnableWifi()
{
...
errCode = WIFI_OPT_FAILED;
do {
if (WifiServiceManager::GetInstance().CheckAndEnforceService(WIFI_SERVICE_STA) < 0) {//加載STA服務(wù)
break;
}
IStaService *pService = WifiServiceManager::GetInstance().GetStaServiceInst(); //構(gòu)建StaService
if (pService == nullptr) {
WIFI_LOGE("Create %{public}s service failed!", WIFI_SERVICE_STA);
break;
}

    errCode = pService->RegisterStaServiceCallback(WifiManager::GetInstance().GetStaCallback());  //注冊(cè)回調(diào)函數(shù)
    if (errCode != WIFI_OPT_SUCCESS) {
        WIFI_LOGE("Register sta service callback failed!");
        break;
    }

    errCode = pService->EnableWifi();    //打開wifi
    if (errCode != WIFI_OPT_SUCCESS) {
        WIFI_LOGE("service enable sta failed, ret %{public}d!", static_cast<int>(errCode));
        break;
    }
} while (false);
...
return WIFI_OPT_SUCCESS;

}


這里主要做了四件事情:

1. 加載STA服務(wù),在WifiServiceManager中根據(jù)服務(wù)名稱WIFI_SERVICE_STA,調(diào)用LoadStaService方法加載STA服務(wù);
2. 構(gòu)建StaService,獲取接口IStaService實(shí)例;
3. 注冊(cè)回調(diào)函數(shù);
4. 調(diào)用StaService打開Wifi。

StaService是Wifi框架層Station服務(wù)的主要實(shí)現(xiàn),通過創(chuàng)建StaStateMachine和StaMonitor對(duì)Wifi Station命令和事件進(jìn)行處理。

**目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_sta/sta_service.cpp**

StaService首先在調(diào)用之前,首先會(huì)初始化:

```c++
ErrCode StaService::InitStaService(const StaServiceCallback &callbacks)
{
    WIFI_LOGI("Enter StaService::InitStaService.
");
    pStaStateMachine = new (std::nothrow) StaStateMachine();     //構(gòu)造StaStateMachine狀態(tài)機(jī)
    ...
    RegisterStaServiceCallback(callbacks);                      //注冊(cè)事件回調(diào)函數(shù)

    pStaMonitor = new (std::nothrow) StaMonitor();              //構(gòu)造StaMonitor并初始化
    ...
    pStaMonitor->SetStateMachine(pStaStateMachine);             

    pStaAutoConnectService = new (std::nothrow) StaAutoConnectService(pStaStateMachine); //構(gòu)造自動(dòng)連接服務(wù)
    ...
    WIFI_LOGI("Init staservice successfully.
");

    return WIFI_OPT_SUCCESS;
}

初始化主要會(huì)做四件事:

1.構(gòu)造StaStateMachine狀態(tài)機(jī)

2.注冊(cè)回調(diào)函數(shù)

3.構(gòu)造StaMonitor

4.構(gòu)造自動(dòng)連接服務(wù)

這些準(zhǔn)備工作做完后,就是真正執(zhí)行EnableWifi的流程。

```c++
ErrCode StaService::EnableWifi() const
{
WIFI_LOGI("Enter StaService::EnableWifi. ");
pStaStateMachine->SendMessage(WIFI_SVR_CMD_STA_ENABLE_WIFI, STA_CONNECT_MODE); //向StaStateMachine發(fā)送WIFI_SVR_CMD_STA_ENABLE_WIFI消息
return WIFI_OPT_SUCCESS;
}


**目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_sta/sta_state_machine.cpp**

StaStateMachine在初始化時(shí)設(shè)置初始狀態(tài)為InitState ,”SetFirstState(pInitState)“,故接收到WIFI_SVR_CMD_STA_ENABLE_WIFI在InitState狀態(tài)中處理:

```c++
bool StaStateMachine::InitState::ExecuteStateMsg(InternalMessage *msg)
{
    if (msg == nullptr) {
        return false;
    }

    bool ret = NOT_EXECUTED;
    switch (msg->GetMessageName()) {
        case WIFI_SVR_CMD_STA_ENABLE_WIFI: {     //StastateMachine接收到WIFI_SVR_CMD_STA_ENABLE_WIFI消息
            ret = EXECUTED;
            pStaStateMachine->operationalMode = msg->GetParam1();
            pStaStateMachine->StartWifiProcess();  //調(diào)用StartWifiProcess()方法
            break;
        }

        case WIFI_SVR_CMD_STA_OPERATIONAL_MODE:
            break;

        default:
            LOGI("InitState-msgCode=%d not handled.
", msg->GetMessageName());
            break;
    }
    return ret;
}

```c++
void StaStateMachine::StartWifiProcess()
{
WifiSettings::GetInstance().SetWifiState(static_cast<int>(WifiState::ENABLING));
staCallback.OnStaOpenRes(OperateResState::OPEN_WIFI_OPENING);
int res = WifiStaHalInterface::GetInstance().StartWifi(); //調(diào)用WifiStaHalInterface的StartWifi()
//下面是對(duì)返回結(jié)果的處理
...
}


WifiStaHalInterface是框架調(diào)用Wifi Hal的接口。

框架與Wifi Hal的通信主要是借助IDL Client組件,采用RPC服務(wù)實(shí)現(xiàn)其交互。

無論是框架調(diào)用Wifi Hal還是Wifi Hal回調(diào)消息到框架,都要經(jīng)過IDL Clinet,從架構(gòu)圖來看,它屬于Wifi框架的一部分,我們先來看看它。

IDL客戶端初始化:

**目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/idl_client/wifi_base_hal_interface.cpp**

```c++
bool WifiBaseHalInterface::InitIdlClient(void)
{
    if (mIdlClient == nullptr) {
        mIdlClient = new (std::nothrow) WifiIdlClient;
    }
    if (mIdlClient == nullptr) {
        LOGE("Failed to create idl client");
        return false;
    }
    if (mIdlClient->InitClient() != 0) {
        LOGE("Failed to init idl client");
        return false;
    }
    return true;
}

IDL客戶端初始化主要做了兩件事:

1.構(gòu)造WifiIdlClient實(shí)例

2.初始化RPC通信客戶端

```c++
int WifiIdlClient::InitClient(void)
{
const std::string idlSockPath = "/data/misc/wifi/unix_sock.sock";
pRpcClient = CreateRpcClient(idlSockPath.c_str());
if (pRpcClient == nullptr) {
LOGE("init rpc client failed!");
return -1;
}
return 0;
}


有了WifiIdlClient實(shí)例,調(diào)用其StartWifi()。

**目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/idl_client/wifi_sta_hal_interface.cpp**

```c++
WifiErrorNo WifiStaHalInterface::StartWifi(void)
{
    return mIdlClient->StartWifi();
}

通過wifi_idl_client向wifi hal發(fā)起RPC調(diào)用“Start”。

目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/idl_client/wifi_idl_client.cpp

```c++
WifiErrorNo WifiIdlClient::StartWifi(void)
{
CHECK_CLIENT_NOT_NULL;
return Start();
}


**目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/idl_client/idl_interface/i_wifi.c**

```c
WifiErrorNo Start(void)
{
    RpcClient *client = GetStaRpcClient();
    LockRpcClient(client);
    Context *context = client->context;
    WriteBegin(context, 0);
    WriteFunc(context, "Start");
    WriteEnd(context);
    if (RpcClientCall(client, "Start") != WIFI_IDL_OPT_OK) {
        return WIFI_IDL_OPT_FAILED;
    }
    int result = WIFI_IDL_OPT_FAILED;
    ReadInt(context, &result);
    ReadClientEnd(client);
    UnlockRpcClient(client);
    return result;
}

這里主要操作是獲取RPC調(diào)用客戶端,然后通過RemoteCall(client)方法發(fā)起遠(yuǎn)程調(diào)用。

Wifi Hal作為RPC服務(wù)端,啟動(dòng)后調(diào)用InitRpcFunc初始化RPC函數(shù),然后CreateRpcServer創(chuàng)建RPC服務(wù),最后調(diào)用RunRpcLoop循環(huán)讀取遠(yuǎn)程調(diào)用信息,處理客戶端請(qǐng)求。

目錄:foundation/communication/wifi/services/wifi_standard/wifi_hal/main.c

int main(void)
{
    char rpcSockPath[] = "/data/misc/wifi/unix_sock.sock";

    if (access(rpcSockPath, 0) == 0) {
        unlink(rpcSockPath);
    }
    if (InitRpcFunc() < 0) {                            //
        LOGE("Init Rpc Function failed!");
        return -1;
    }
    RpcServer *server = CreateRpcServer(rpcSockPath);  //framework中server.c
    if (server == NULL) {
        LOGE("Create RPC Server by %{public}s failed!", rpcSockPath);
        return -1;
    }
    SetRpcServerInited(server);
    setvbuf(stdout, NULL, _IOLBF, 0);
    signal(SIGINT, SignalExit);
    signal(SIGTERM, SignalExit);
    signal(SIGPIPE, SIG_IGN);

    RunRpcLoop(server);
    /* stop wpa_supplicant, hostapd, and other resources */
    ForceStop();
    StopSoftAp();
    P2pForceStop();
    ReleaseWifiHalVendorInterface();
    /* clear RPC Server */
    SetRpcServerInited(NULL);
    ReleaseRpcServer(server);
    ReleaseRpcFunc();
    LOGI("hal service exists!");
    return 0;
}

InitRpcFunc中Map了“Start”消息的處理函數(shù),PushRpcFunc("Start", RpcStart)。

目錄:foundation/communication/wifi/services/wifi_standard/wifi_hal/wifi_hal_crpc_server.c

static int InitRpcFuncMapSta(void)
{
    int ret = 0;
    ret += PushRpcFunc("Start", RpcStart);
    ret += PushRpcFunc("Stop", RpcStop);
    ......
    return ret;
}

根據(jù)配對(duì)關(guān)系調(diào)用到RpcStart,

目錄:foundation/communication/wifi/services/wifi_standard/wifi_hal/wifi_hal_crpc_sta.c

int RpcStart(RpcServer *server, Context *context)
{
    if (server == NULL || context == NULL) {
        return -1;
    }
    WifiErrorNo err = Start(); //調(diào)用Start方法
    WriteBegin(context, 0);
    WriteInt(context, err);
    WriteEnd(context);
    return 0;
}

調(diào)用Start()實(shí)際操作實(shí)現(xiàn)在wifi_hal_sta_interface的Start函數(shù),調(diào)用完成。

目錄:foundation/communication/wifi/services/wifi_standard/wifi_hal/wifi_hal_sta_interface.c

WifiErrorNo Start(void)
{
    LOGD("Ready to start wifi");
    if (StartSupplicant() != WIFI_HAL_SUCCESS) {    //start supplicant
        LOGE("wpa_supplicant start failed!");
        return WIFI_HAL_OPEN_SUPPLICANT_FAILED;
    }
    LOGD("wpa_supplicant start successfully!");

    if (AddWpaIface(0) != WIFI_HAL_SUCCESS) {       //Add a new interface wlan0
        LOGE("Failed to add wpa interface!");
        StopWpaAndWpaHal(0);
        return WIFI_HAL_CONN_SUPPLICANT_FAILED;
    }

    if (ConnectSupplicant() != WIFI_HAL_SUCCESS) { //構(gòu)造并初始化WifiWpaStaInterface
        LOGE("SupplicantHal connect wpa_supplicant failed!");
        StopWpaAndWpaHal(0);
        return WIFI_HAL_CONN_SUPPLICANT_FAILED;
    }
    LOGD("SupplicantHal connect wpa_supplicant successfully!");
    LOGD("Start wifi successfully");
    return WIFI_HAL_SUCCESS;
}

主要做了三步操作:

  1. start supplicant

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

```c++
const char *wpaConf = "/data/misc/wifi/wpa_supplicant/wpa_supplicant.conf";


2. Add a new interface wlan0

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

```c++
pWpaInterface->wpaCliAddIface(pWpaInterface, &argv)
  1. 構(gòu)造并初始化WifiWpaStaInterface,封裝了wpa_supplicant關(guān)于STA的操作命令。

    ```c++
    WifiWpaStaInterface *pStaIfc = GetWifiStaInterface(0);

以上三步成功后,RPC調(diào)用返回WIFI_HAL_SUCCESS,日志會(huì)打印"Start wifi successfully"。

StaStateMachine在EnableWifi成功后,設(shè)置wifistate為ENABLED并執(zhí)行OnStaOpenRes回調(diào):

```c++
WifiSettings::GetInstance().SetWifiState(static_cast<int>(WifiState::ENABLED));
staCallback.OnStaOpenRes(OperateResState::OPEN_WIFI_SUCCEED);


回調(diào)在WifiManager中處理,廣播wifi狀態(tài)改變消息,構(gòu)造ScanService并初始化,初始化過程做了這幾件事:
1. 構(gòu)造ScanStateMachine并初始化,調(diào)用EnrollScanStatusListener綁定Scan狀態(tài)上報(bào)事件的處理函數(shù)。
2. 構(gòu)造ScanMonitor并初始化,在初始化函數(shù)中調(diào)用RegisterSupplicantEventCallback,注冊(cè)supplicant事件回調(diào)。

**目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_scan/scan_service.cpp**

```c++
bool ScanService::InitScanService(const IScanSerivceCallbacks &scanSerivceCallbacks)
{
    WIFI_LOGI("Enter ScanService::InitScanService.
");

    mScanSerivceCallbacks = scanSerivceCallbacks;
    //構(gòu)造ScanStateMachine
    pScanStateMachine = new (std::nothrow) ScanStateMachine();
    if (pScanStateMachine == nullptr) {
        WIFI_LOGE("Alloc pScanStateMachine failed.
");
        return false;
    }
    //初始化ScanStateMachine
    if (!pScanStateMachine->InitScanStateMachine()) {
        WIFI_LOGE("InitScanStateMachine failed.
");
        return false;
    }
    //綁定Scan狀態(tài)上報(bào)事件的處理函數(shù)
    if (!pScanStateMachine->EnrollScanStatusListener(
        std::bind(&ScanService::HandleScanStatusReport, this, std::placeholders::_1))) {
        WIFI_LOGE("ScanStateMachine_->EnrollScanStatusListener failed.
");
        return false;
    }
    //構(gòu)造ScanMonitor
    pScanMonitor = new (std::nothrow) ScanMonitor();
    if (pScanMonitor == nullptr) {
        WIFI_LOGE("Alloc pScanMonitor failed.
");
        return false;
    }
    //初始化ScanMonitor
    if (!pScanMonitor->InitScanMonitor()) {
        WIFI_LOGE("InitScanMonitor failed.
");
        return false;
    }
    //獲取支持頻段
    if ((WifiStaHalInterface::GetInstance().GetSupportFrequencies(SCAN_BAND_24_GHZ, freqs2G) != WIFI_IDL_OPT_OK) ||
        (WifiStaHalInterface::GetInstance().GetSupportFrequencies(SCAN_BAND_5_GHZ, freqs5G) != WIFI_IDL_OPT_OK) ||
        (WifiStaHalInterface::GetInstance().GetSupportFrequencies(SCAN_BAND_5_GHZ_DFS_ONLY, freqsDfs) !=
        WIFI_IDL_OPT_OK)) {
        WIFI_LOGE("GetSupportFrequencies failed.
");
    }

    pScanMonitor->SetScanStateMachine(pScanStateMachine);
    //向ScanStateMachine發(fā)送CMD_SCAN_PREPARE
    pScanStateMachine->SendMessage(static_cast<int>(CMD_SCAN_PREPARE));
    GetScanControlInfo();

    return true;
}

ScanStateMachine初始化狀態(tài)為InitState,然后接收到CMD_SCAN_PREPARE消息,調(diào)用LoadDriver();

```c++
bool ScanStateMachine::InitState::ExecuteStateMsg(InternalMessage *msg)
{
......
switch (msg->GetMessageName()) {
case CMD_SCAN_PREPARE:
LoadDriver();
return true;

    case CMD_SCAN_FINISH:
        UnLoadDriver();
        return true;
    ......
    default:
        return false;
}

}


```c++
void ScanStateMachine::InitState::LoadDriver()
{
    WIFI_LOGI("Enter ScanStateMachine::LoadDriver.
");
    pScanStateMachine->SwitchState(pScanStateMachine->hardwareReadyState);
    pScanStateMachine->ReportStatusChange(SCAN_STARTED_STATUS);
    WIFI_LOGI("Start Scan Service Success.
");
}

LoadDriver()做了兩件事情:

  1. ScanStateMAchine切換狀態(tài)為為HardwareReadyState
  2. 上報(bào)SCAN_STARTED_STATUS狀態(tài)

然后就可以發(fā)起掃描的流程了。

掃描流程

Wifi掃描流程時(shí)序圖.png

應(yīng)用調(diào)用Native JS的Scan接口,會(huì)通過獲取WifiScan實(shí)例,調(diào)用C++接口,發(fā)起IPC通信,通過WifiScanProxy向服務(wù)框架發(fā)送WIFI_SVR_CMD_FULL_SCAN請(qǐng)求。WifiScanStub作為服務(wù)端接收到請(qǐng)求,WifiScanServiceImpl作為服務(wù)端的主要實(shí)現(xiàn)。

目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_scan_service_impl.cpp

```c++
ErrCode WifiScanServiceImpl::Scan()
{
WIFI_LOGI("Scan");
.....
//判斷ScanService是否啟動(dòng)
if (!IsScanServiceRunning()) {
return WIFI_OPT_SCAN_NOT_OPENED;
}
//獲取IScanService實(shí)例
IScanService *pService = WifiServiceManager::GetInstance().GetScanServiceInst();
if (pService == nullptr) {
return WIFI_OPT_SCAN_NOT_OPENED;
}
return pService->Scan(true);
}


構(gòu)造ScanService,通過IScanService接口調(diào)用其Scan方法:

```c++
ErrCode ScanService::Scan(bool externFlag)
{
    WIFI_LOGI("Enter ScanService::Scan.
");

    if (!scanStartedFlag) {
        WIFI_LOGE("Scan service has not started.
");
        return WIFI_OPT_FAILED;
    }

    if (externFlag) {
        ErrCode rlt = ApplyScanPolices(ScanType::SCAN_TYPE_EXTERN);
        if (rlt != WIFI_OPT_SUCCESS) {
            return rlt;
        }
    }

    ScanConfig scanConfig;
    /*
     * Invoke the interface provided by the configuration center to obtain the
     * hidden network list.
     */
    if (!GetHiddenNetworkSsidList(scanConfig.hiddenNetworkSsid)) {
        WIFI_LOGE("GetHiddenNetworkSsidList failed.
");
    }
    //構(gòu)造ScanConfig
    scanConfig.scanBand = SCAN_BAND_BOTH_WITH_DFS;
    scanConfig.fullScanFlag = true;
    scanConfig.externFlag = externFlag;
    scanConfig.scanStyle = SCAN_TYPE_HIGH_ACCURACY;
    if (!SingleScan(scanConfig)) {
        WIFI_LOGE("SingleScan failed.
");
        return WIFI_OPT_FAILED;
    }

    return WIFI_OPT_SUCCESS;
}

這里首先構(gòu)造scanConfig,然后調(diào)用SingleScan向ScanStateMachine發(fā)送CMD_START_COMMON_SCAN命令并攜帶scanConfig,

```c++
//保存scanConfig
int requestIndex = StoreRequestScanConfig(scanConfig, interConfig);
//生成Message
InternalMessage *interMessage = pScanStateMachine->CreateMessage(static_cast<int>(CMD_START_COMMON_SCAN), requestIndex);
//發(fā)送消息
pScanStateMachine->SendMessage(interMessage);


ScanService初始化完成后,ScanStateMachine處于HardwareReady是可以發(fā)起掃描的激活狀態(tài),

**目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_scan/scan_state_machine.cpp**

```c++
bool ScanStateMachine::HardwareReady::ExecuteStateMsg(InternalMessage *msg)
{
    WIFI_LOGI("ScanStateMachine::HardwareReady::ExecuteStateMsg.
");
    if (msg == nullptr) {
        WIFI_LOGE("msg is null.
");
        return true;
    }

    switch (msg->GetMessageName()) {
        //處理CMD_START_COMMON_SCAN消息  
        case CMD_START_COMMON_SCAN:
            pScanStateMachine->CommonScanRequestProcess(msg);
            return true;

        case CMD_START_PNO_SCAN:
            pScanStateMachine->PnoScanRequestProcess(msg);
            return true;

        default:
            return false;
    }
}

接收CMD_START_COMMON_SCAN并處理,進(jìn)行獲取掃描參數(shù)的操作,并校驗(yàn)Scan類型是否合法,之后轉(zhuǎn)換掃描參數(shù),通過RPC調(diào)用HAL的scan操作,

```c++
WIFI_LOGI("Begin call Scan. ");
WifiErrorNo ret = WifiStaHalInterface::GetInstance().Scan(scanParam);
if ((ret != WIFI_IDL_OPT_OK) && (ret != WIFI_IDL_OPT_SCAN_BUSY)) {
WIFI_LOGE("WifiStaHalInterface::GetInstance().scan failed.");
return false;
}
WIFI_LOGI("End call Scan. ");


HAL得到scan配置參數(shù)后,通過wpaCliCmdScan向supplicant發(fā)送SCAN命令,

**目錄:foundation/communication/wifi/services/wifi_standard/wifi_hal/wifi_hal_sta_interface.c**

```c++
WifiErrorNo StartScan(const ScanSettings *settings)
{
    LOGD("Ready to start scan with param.");
    WifiWpaStaInterface *pStaIfc = GetWifiStaInterface(0);
    if (pStaIfc == NULL) {
        return WIFI_HAL_SUPPLICANT_NOT_INIT;
    }
    int ret = pStaIfc->wpaCliCmdScan(pStaIfc, settings);   //向supplicant發(fā)送SCAN命令
    if (ret < 0) {
        LOGE("StartScan failed! ret=%{public}d", ret);
        return WIFI_HAL_FAILED;
    }
    if (ret == WIFI_HAL_SCAN_BUSY) {
        LOGD("StartScan return scan busy");
        return WIFI_HAL_SCAN_BUSY;
    }
    LOGD("StartScan successfully!");
    return WIFI_HAL_SUCCESS;
}

掃描成功,HAL返回WIFI_HAL_SUCCESS。

調(diào)用成功StaStateMachine切換狀態(tài)為CommonScanningState。

掃描結(jié)果獲取

掃描結(jié)果獲取流程時(shí)序圖.png

Supplicant執(zhí)行掃描成功后,調(diào)用WifiHalCbNotifyScanEnd(WPA_CB_SCAN_OVER_OK)通知掃描成功。ScanMonitor執(zhí)行回調(diào),向ScanStateMachine發(fā)送SCAN_RESULT_EVENT事件:

```c++
void ScanMonitor::SendScanInfoEvent()
{
pScanStateMachine->SendMessage(static_cast<int>(SCAN_RESULT_EVENT));
return;
}


?    ScanStateMachine此時(shí)狀態(tài)為CommonScanning,接收消息并處理,發(fā)起RPC遠(yuǎn)程調(diào)用wifi hal獲取掃描結(jié)果。

```c++
case SCAN_RESULT_EVENT:
            pScanStateMachine->CommonScanInfoProcess();
            pScanStateMachine->SwitchState(pScanStateMachine->commonScanUnworkedState); //切換狀態(tài)為CommonScanUnworkedState
            return true;

```c++
void ScanStateMachine::CommonScanInfoProcess()
{
WIFI_LOGI("Enter ScanStateMachine::CommonScanInfoProcess. ");
//構(gòu)造ScanStatusReport
ScanStatusReport scanStatusReport;
//獲取掃描結(jié)果
if (!GetScanInfos(scanStatusReport.scanInfoList)) {
WIFI_LOGE("GetScanInfos failed.");
ReportCommonScanFailedAndClear(true);
return;
}
GetRunningIndexList(scanStatusReport.requestIndexList);
//設(shè)置掃描狀態(tài)為COMMON_SCAN_SUCCESS
scanStatusReport.status = COMMON_SCAN_SUCCESS;
if (scanStatusReportHandler) {
scanStatusReportHandler(scanStatusReport);
}
runningScans.clear();

return;

}


```c++
bool ScanStateMachine::GetScanInfos(std::vector<InterScanInfo> &scanInfos)
{
    WIFI_LOGI("Enter ScanStateMachine::GetScanInfos.
");

    WIFI_LOGI("Begin: QueryScanInfos.");
    //發(fā)起RPC遠(yuǎn)程調(diào)用wifi hal獲取掃描結(jié)果
    if (WifiStaHalInterface::GetInstance().QueryScanInfos(scanInfos) != WIFI_IDL_OPT_OK) {
        WIFI_LOGE("WifiStaHalInterface::GetInstance().GetScanInfos failed.");
        return false;
    }
    WIFI_LOGI("End: QueryScanInfos.");
    GetSecurityTypeAndBand(scanInfos);

    return true;
}

WifiHal返回掃描結(jié)果給ScanStateMachine后,ScanStateMachine構(gòu)造ScanStatusReport,包含scanInfoList和status為COMMON_SCAN_SUCCESS,通過scanStatusReportHandler上報(bào),在ScanService::HandleScanStatusReport中處理。

```c++
oid ScanService::HandleScanStatusReport(ScanStatusReport &scanStatusReport)
{
WIFI_LOGI("Enter ScanService::HandleScanStatusReport. ");

switch (scanStatusReport.status) {
  ......
    case COMMON_SCAN_SUCCESS: {
        HandleCommonScanInfo(scanStatusReport.requestIndexList, scanStatusReport.scanInfoList);
        break;
    }
  ......
}
return;

}


ScanService拿到掃描結(jié)果,主要做的事是調(diào)用WifiSettings的SaveScanInfoList(filterScanInfo),將掃描結(jié)果保存。

之后,應(yīng)用調(diào)用native js的GetScanInfos接口,通過WifiScanServiceImpl調(diào)用WifiSettings的GetScanInfoList獲取到保存的掃描結(jié)果。

掃描結(jié)果中包含的信息如下,一般常用到的信息有:

Bssid - 掃描到的AP的mac地址

Ssid - 掃描到的AP的標(biāo)識(shí)名稱

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

securityType - 安全類型: OPEN/WEP/PSK/SAE

```c++
struct WifiScanInfo {
    std::string bssid;
    std::string ssid;
    /**
     * Network performance, including authentication,
     * key management, and encryption mechanisms
     * supported by the access point
     */
    std::string capabilities;
    int frequency;
    int band;  /* ap band: 1 - 2.4GHZ, 2 - 5GHZ */
    WifiChannelWidth channelWidth;
    int centerFrequency0;
    int centerFrequency1;
    int rssi; /* signal level */
    WifiSecurity securityType;
    std::vector<WifiInfoElem> infoElems;
    int64_t features;
    int64_t timestamp;
}

連接流程

Wifi連接流程時(shí)序圖.png

應(yīng)用獲取到掃描結(jié)果后,選擇一個(gè)Wifi網(wǎng)絡(luò)進(jìn)行連接,調(diào)用Native Js的connectToDevice接口調(diào)用到WifiDevice,然后通過IPC通信,WifiDeviceProxy作為客戶端代理發(fā)送WIFI_SVR_CMD_CONNECT2_TO消息,WifiDeviceStub作為服務(wù)端接收到消息后調(diào)用IPC服務(wù)的實(shí)現(xiàn)類WifiDeviceServiceImpl進(jìn)行發(fā)起連接流程。

目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_device_service_impl.cpp

```c++
ErrCode WifiDeviceServiceImpl::ConnectToDevice(const WifiDeviceConfig &config)
{
......
if (!IsStaServiceRunning()) {
return WIFI_OPT_STA_NOT_OPENED;
}
IStaService *pService = WifiServiceManager::GetInstance().GetStaServiceInst();
if (pService == nullptr) {
return WIFI_OPT_STA_NOT_OPENED;
}
return pService->ConnectToDevice(config); //調(diào)用StaService的ConnectToDevice
}


獲取StaService的接口實(shí)例,調(diào)用其ConnectToDevice方法。

**目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_sta/sta_service.cpp**

```c++
ErrCode StaService::ConnectToDevice(const WifiDeviceConfig &config) const
{
    LOGI("Enter StaService::ConnectToDevice.
");
    int netWorkId = AddDeviceConfig(config);//調(diào)用AddDeviceConfig
    if(netWorkId == INVALID_NETWORK_ID) {
        LOGD("StaService::ConnectTo  AddDeviceConfig failed!");
        return WIFI_OPT_FAILED;
    }
    LOGD("StaService::ConnectTo  AddDeviceConfig succeed!");
    pStaStateMachine->SendMessage(WIFI_SVR_CMD_STA_CONNECT_NETWORK, netWorkId, NETWORK_SELECTED_BY_THE_USER);//向StaStateMachine發(fā)送WIFI_SVR_CMD_STA_CONNECT_NETWORK消息
    return WIFI_OPT_SUCCESS;
}

StaService首先調(diào)用AddDeviceConfig,在這個(gè)函數(shù)中主要做了兩件事:

1).調(diào)用GetNextNetworkId,通過HAL向supplicant發(fā)送ADD_NETWORK命令,得到netwrok id,保存在WifiDeviceConfig。

2)調(diào)用ConvertDeviceCfg,在StaStateMachine中將網(wǎng)絡(luò)配置參數(shù)轉(zhuǎn)換為idl參數(shù),然后調(diào)用HAL的SetDeviceConfig函數(shù),向supplicant發(fā)送SET_NETWORK命令。

StaService在調(diào)用AddDeviceConfig得到networkid并且設(shè)置配置參數(shù)到supplicant成功后,向StaStateMachine發(fā)送“WIFI_SVR_CMD_STA_CONNECT_NETWORK”消息,

目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_sta/sta_state_machine.cpp

StaStateMachine接收WIFI_SVR_CMD_STA_CONNECT_NETWORK消息調(diào)用DealConnectToUserSelectedNetwork

```c++
staSmHandleFuncMap[WIFI_SVR_CMD_STA_CONNECT_NETWORK] = &StaStateMachine::DealConnectToUserSelectedNetwork;


```c++
void StaStateMachine::DealConnectToUserSelectedNetwork(InternalMessage *msg)
{
    LOGI("enter DealConnectToUserSelectedNetwork.
");
    ...... //一些狀態(tài)設(shè)置
    StartConnectToNetwork(networkId); //開啟連接
}

StartConnectToNetwork:

```c++
void StaStateMachine::StartConnectToNetwork(int networkId)
{
targetNetworkId = networkId;
SetRandomMac(targetNetworkId); //設(shè)置隨機(jī)Mac
//EnableNetwork
if (WifiStaHalInterface::GetInstance().EnableNetwork(targetNetworkId) != WIFI_IDL_OPT_OK) {
LOGE("EnableNetwork() failed!");
return;
}
//Connect
if (WifiStaHalInterface::GetInstance().Connect(targetNetworkId) != WIFI_IDL_OPT_OK) {
LOGE("Connect failed!");
staCallback.OnStaConnChanged(OperateResState::CONNECT_SELECT_NETWORK_FAILED, linkedInfo);
return;
}
//SaveDeviceConfig
if (WifiStaHalInterface::GetInstance().SaveDeviceConfig() != WIFI_IDL_OPT_OK) {
LOGE("SaveDeviceConfig() failed!");
}

StopTimer(static_cast<int>(CMD_NETWORK_CONNECT_TIMEOUT));
StartTimer(static_cast<int>(CMD_NETWORK_CONNECT_TIMEOUT), STA_NETWORK_CONNECTTING_DELAY);

}


這里主要做了三個(gè)操作:發(fā)起RPC調(diào)用EnableNetwork,Connect,SaveDeviceConfig。

**目錄:foundation/communication/wifi/services/wifi_standard/wifi_hal/wifi_hal_sta_interface.c**

EnableNetwork:     

```c
WifiErrorNo EnableNetwork(int networkId)
{
    LOGD("EnableNetwork() networkid [%{public}d]", networkId);
    WifiWpaStaInterface *pStaIfc = GetWifiStaInterface(0);
    if (pStaIfc == NULL) {
        return WIFI_HAL_SUPPLICANT_NOT_INIT;
    }
    int ret = pStaIfc->wpaCliCmdEnableNetwork(pStaIfc, networkId);
    if (ret < 0) {
        LOGE("WpaCliCmdEnableNetwork failed! ret=%{public}d", ret);
        return WIFI_HAL_FAILED;
    }
    return WIFI_HAL_SUCCESS;
}

Connect:

WifiErrorNo Connect(int networkId)
{
    LOGD("Connect() networkid %{public}d", networkId);
    WifiWpaStaInterface *pStaIfc = GetWifiStaInterface(0);
    if (pStaIfc == NULL) {
        return WIFI_HAL_SUPPLICANT_NOT_INIT;
    }
    int ret = pStaIfc->wpaCliCmdSelectNetwork(pStaIfc, networkId);
    if (ret < 0) {
        LOGE("WpaCliCmdSelectNetwork failed! ret=%{public}d", ret);
        return WIFI_HAL_FAILED;
    }
    return WIFI_HAL_SUCCESS;
}

SaveDeviceConfig:

WifiErrorNo SaveNetworkConfig(void)
{
    LOGD("SaveNetworkConfig()");
    WifiWpaStaInterface *pStaIfc = GetWifiStaInterface(0);
    if (pStaIfc == NULL) {
        return WIFI_HAL_SUPPLICANT_NOT_INIT;
    }
    int ret = pStaIfc->wpaCliCmdSaveConfig(pStaIfc);
    if (ret < 0) {
        LOGE("WpaCliCmdSaveConfig failed! ret=%{public}d", ret);
        return WIFI_HAL_FAILED;
    }
    return WIFI_HAL_SUCCESS;
}

這里按調(diào)用先后向supplicant發(fā)送EnableNetwork、SELECT_NETWORK以及SAVE_CONFIG命令,supplicant根據(jù)收到的命令完成AP的連接管理。

Supplicant連接成功后,回送WPA_EVENT_CONNECTED事件,調(diào)用WifiHalCbNotifyConnectChanged(WPA_CB_CONNECTED,id,pMacPos)通知連接成功,經(jīng)過Hal再由StaMonitor的處理回調(diào),發(fā)送消息WIFI_SVR_CMD_STA_NETWORK_CONNECTION_EVENT給StaStateMachine,調(diào)用DealConnectionEvent方法來處理連接事件,狀態(tài)機(jī)進(jìn)入getIpState狀態(tài),獲取ip地址,靜態(tài)ip或者dhcp動(dòng)態(tài)獲取成功后,繼續(xù)調(diào)用StaNetworkCheck檢查網(wǎng)絡(luò)連接狀態(tài)。

Wifi-STA接口說明及使用

接口說明

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

表 1 WLAN功能接口(JS接口)

接口名 描述
function enableWifi(): boolean 打開WLAN。
function disableWifi(): boolean 關(guān)閉WLAN。
function isWifiActive(): boolean 查詢WLAN是否處于打開狀態(tài)。
function scan(): boolean 發(fā)起WLAN掃描。
function getScanInfos(): Promise<Array<WifiScanInfo>>;<br/>function getScanInfos(callback: AsyncCallback<Array<WifiScanInfo>>): void; 獲取WLAN掃描結(jié)果,接口可采用promise或callback方式調(diào)用。
function addDeviceConfig(config: WifiDeviceConfig): Promise<number>;<br/>function addDeviceConfig(config: WifiDeviceConfig, callback: AsyncCallback<number>): void; 添加WLAN熱點(diǎn)的配置信息,接口可采用promise或callback方式調(diào)用。
function connectToNetwork(networkId: number): boolean 連接到WLAN網(wǎng)絡(luò)。(一般為隱藏?zé)狳c(diǎn)的連接)
function connectToDevice(config: WifiDeviceConfig): boolean 連接到WLAN網(wǎng)絡(luò)。
function disconnect(): boolean 斷開WLAN連接。
function getSignalLevel(rssi: number, band: number): number 獲取WLAN信號(hào)強(qiáng)度。
function getLinkedInfo(): Promise<WifiLinkedInfo>;<br/>function getLinkedInfo(callback: AsyncCallback<WifiLinkedInfo>): void; 獲取WLAN連接信息接口可采用promise或callback方式調(diào)用。
function isConnected(): boolean; 查詢是否是連接狀態(tài)。
function getSupportedFeatures(): number; 獲取設(shè)備支持的feature。
function isFeatureSupported(featureId: number): boolean; 查詢?cè)O(shè)備是否支持指定feature。
function getDeviceMacAddress(): string[]; 獲取MAC地址。
function getIpInfo(): IpInfo; 獲取IP。
function getCountryCode(): string; 獲取國家碼。
function reassociate(): boolean; 重新連接當(dāng)前網(wǎng)絡(luò)。
function reconnect(): boolean; 重新連接當(dāng)前Wifi。
function getDeviceConfigs(): Array<WifiDeviceConfig>; 獲取現(xiàn)存的Wifi列表。
function updateNetwork(config: WifiDeviceConfig): number; 更新指定的Wifi配置。
function disableNetwork(netId: number): boolean; 關(guān)閉指定的網(wǎng)絡(luò)。
function removeAllNetwork(): boolean; 移除所有的網(wǎng)絡(luò)。
function removeDevice(id: number): boolean; 刪除指定ID的網(wǎng)絡(luò)。

表 1 WLAN事件接口(JS接口)

接口名 描述
function on(type: "wifiStateChange", callback: Callback<number>): void;<br/>function off(type: "wifiStateChange", callback?: Callback<number>): void; Wifi狀態(tài)監(jiān)聽事件
function on(type: "wifiConnectionChange", callback: Callback<number>): void;<br/>function off(type: "wifiConnectionChange", callback?: Callback<number>): void; Wifi連接狀態(tài)監(jiān)聽
function on(type: "wifiScanStateChange", callback: Callback<number>): void;<br/>function off(type: "wifiScanStateChange", callback?: Callback<number>): void; Wifi掃描狀態(tài)監(jiān)聽
function on(type: "wifiRssiChange", callback: Callback<number>): void;<br/>function off(type: "wifiRssiChange", callback?: Callback<number>): void; Wifi信號(hào)監(jiān)聽

更多原創(chuàng)內(nèi)容請(qǐng)關(guān)注:深開鴻技術(shù)團(tuán)隊(duì)

入門到精通、技巧到案例,系統(tǒng)化分享HarmonyOS開發(fā)技術(shù),歡迎投稿和訂閱,讓我們一起攜手前行共建鴻蒙生態(tài)。

想了解更多關(guān)于開源的內(nèi)容,請(qǐng)?jiān)L問:

51CTO 開源基礎(chǔ)軟件社區(qū)

https://ost.51cto.com/#bkwz

本文摘自 :https://blog.51cto.com/h

開通會(huì)員,享受整站包年服務(wù)立即開通 >