亚洲精品亚洲人成在线观看麻豆,在线欧美视频一区,亚洲国产精品一区二区动图,色综合久久丁香婷婷

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

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

              作者:李威

              簡介

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

              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對外提供的API實(shí)現(xiàn)對設(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,對外提供控制接口,框架就能通過其控制接口來實(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),包括了對設(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              # 測試代碼目錄
              │   └── wifi_standard  # service實(shí)現(xiàn)模塊測試代碼
              └── 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ù)請求方(Client)可獲取提供服務(wù)提供方(Server)的代理 (Proxy),并通過此代理讀寫數(shù)據(jù)來實(shí)現(xiàn)進(jìn)程間的數(shù)據(jù)通信。

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

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

              IPC通信圖.png

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

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

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

              首先,獲取SAMgr。

              然后,通過SAMgr及相應(yīng)的ability id獲取到對應(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獲取到對應(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ā)起請求后,接口層提供WifiDeviceProxy作為代理發(fā)送打開WiFi請求:
              
              **目錄: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請求
                  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將請求發(fā)到服務(wù)端Stub。

              WiFi框架提供服務(wù)方WifiDeviceStub,繼承IRemoteStub,實(shí)現(xiàn)了IWifiDevice接口類中未實(shí)現(xiàn)的方法,并重寫了OnRemoteRequest方法。Proxy請求方發(fā)來的請求就在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對proxy請求事件和相應(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í)例注冊到SAMgr。接下來,服務(wù)請求方就可以通過從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è)不同的階段,需要對不同階段的狀態(tài)進(jìn)行管理。對于Native JS通過代理發(fā)送到Wifi框架的請求以及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ò)請求WIFI_SVR_CMD_STA_DISCONNECT,都由ApLinkedState處理,進(jìn)入SeparatedState。

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

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

              這里對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á)到延長續(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());  //注冊回調(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. 注冊回調(diào)函數(shù);
              4. 調(diào)用StaService打開Wifi。
              
              StaService是Wifi框架層Station服務(wù)的主要實(shí)現(xiàn),通過創(chuàng)建StaStateMachine和StaMonitor對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);                      //注冊事件回調(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.注冊回調(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()
              //下面是對返回結(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)用信息,處理客戶端請求。

              目錄: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ù)配對關(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,注冊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請求。WifiScanStub作為服務(wù)端接收到請求,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; 查詢設(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)容請關(guān)注:深開鴻技術(shù)團(tuán)隊(duì)

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

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

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

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

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

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