• 當前位置:首頁 > IT技術 > 其他 > 正文

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

    作者:李威

    簡介

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

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

    Wifi子系統架構

    Wifi子系統架構圖.png

    Wifi架構解析

    Wi-Fi App

    主要是開發者自行開發Wi-Fi相關功能的應用。通過調用Wifi SDK對外提供的API實現對設備Wi-Fi的控制及其功能實現。這一層平臺將會提供相關的API調用示例,以供參考。

    Wi-Fi Native JS:

    JS層使用NAPI機制開發,連接APP層與Framework層,將wifi功能封裝成JS接口提供給應用調用,并同時支持Promise和Callback異步回調。

    Wi-Fi Framework

    Wi-Fi核心功能實現。直接為上層應用提供服務。根據其工作模式的不同分為四大業務服務模塊,分別是STA服務、AP服務、P2P服務、Aware服務,同時DHCP功能。

    Wi-Fi Hal

    為FrameWork層操作Wi-Fi硬件提供統一的接口服務,實現應用框架與硬件操作的分離。主要包括Hal適配器及擴展Hal模塊及Wi-Fi硬件廠家提供的二進制庫模塊。

    WPA Supplicant:

    包含wpa_supplicant和hosapd兩個子模塊,wpa_supplicant和hostapd實現了定義好的驅動API,對外提供控制接口,框架就能通過其控制接口來實現Wifi的各種操作。wpa_supplicant支持STA及P2P模式,hostapd則支持AP模式。

    HDF

    HDF 驅動框架主要由驅動基礎框架、驅動程序、驅動配置文件和驅動接口這四個部分組成,實現WIfi驅動功能,加載驅動,驅動接口部署等。

    Wi-Fi Kernel

    包含Wi-Fi 驅動,包括了對設備的一些基本的讀寫操作由Wi-Fi驅動移植人員編譯進內核。

    代碼結構

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

    關鍵模塊實現

    IPC通信

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

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

    Wifi系統對不同模式各實現了一套Proxy-Stub類,STA模式分別是WifiDeviceProxy和WifiDeviceStub,WifiScanProxy和WifiScanStub,對掃描和其他STA流程進行了分離。

    IPC通信圖.png

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

    以WifiDeviceProxy和WifiDeviceStub為例,分別從代理方和服務方說明實現過程。

    WiFi Native JS作為服務請求方發起流程時,WifiDeviceImpl初始化通過Init函數構造代理WifiDeviceProxy,步驟如下:

    首先,獲取SAMgr。

    然后,通過SAMgr及相應的ability id獲取到對應SA的代理IRemoteObject。

    最后,使用IRemoteObject構造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及相應的ability id獲取到對應SA的代理IRemoteObject
    sptr<IRemoteObject> object = samgr->GetSystemAbility(systemAbilityId);
    if (object == nullptr) {
    WIFI_LOGE("failed to get DEVICESERVICE");
    return false;
    }
    //使用IRemoteObject構造WifiDeviceProxy
    client
    = ifacecast<IWifiDevice>(object);
    if (client
    == nullptr) {
    client_ = new (std::nothrow) WifiDeviceProxy(object); //構造代理
    }

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

    }

    
    我們以打開WiFi為例看看其調用過程,客戶端發起請求后,接口層提供WifiDeviceProxy作為代理發送打開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);  //向服務方發送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模式相關業務函數,調用SendRequest將請求發到服務端Stub。

    WiFi框架提供服務方WifiDeviceStub,繼承IRemoteStub,實現了IWifiDevice接口類中未實現的方法,并重寫了OnRemoteRequest方法。Proxy請求方發來的請求就在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請求事件和相應處理函數進行了映射。
    
    ```c++
    void WifiDeviceStub::InitHandleMap()
    {
        handleFuncMap[WIFI_SVR_CMD_ENABLE_WIFI] = &WifiDeviceStub::OnEnableWifi;  //打開wifi
        handleFuncMap[WIFI_SVR_CMD_DISABLE_WIFI] = &WifiDeviceStub::OnDisableWifi;
        ......
        return;
    }

    根據映射關系調用其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;

    }

    
    這里調用EnableWifi(),其具體實現在子類WifiDeviceServiceImpl。
    
    WifiDeviceServiceImpl作為IPC通信服務方的具體實現,如以下代碼所示,WifiDeviceServiceImpl通過MakeAndRegisterAbility將WifiDeviceServiceImpl實例注冊到SAMgr。接下來,服務請求方就可以通過從SAMgr獲取代理來和服務提供方通信。
    
    ```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)
    {}

    狀態機管理

    Wifi框架維護了四個狀態機,分別是sta statemachine、scan statemachine、p2p statemachine和ap statemachine。Wifi各個模式工作流程中會涉及到各個不同的階段,需要對不同階段的狀態進行管理。對于Native JS通過代理發送到Wifi框架的請求以及HAL回送的WPA Supplicant的響應,需要在相應模式的相應狀態下做合適的處理。

    本章僅介紹Wifi基本模式STA和Scan的狀態機。

    Sta狀態機樹狀圖.png

    STA狀態機維護了wifi打開、關閉、連接、獲取IP及漫游的狀態及切換。Wifi打開時,會啟動staService,構造sta statemachine并初始化。如STA狀態機樹狀圖所示,sta statemachine在初始化時,會創建狀態樹,創建子狀態必須保證相應的父狀態被創建。當遷移到子狀態,子狀態激活,也就是執行GoInState后,其父節點會同時處于激活狀態,不會調用GoOutState,子節點共同需要處理的事件或者不關心的事件由父狀態處理,子狀態只負責處理自己感興趣的消息。

    Sta狀態機遷移圖.png

    比如wifi打開時,狀態機從InitState遷移到目標狀態SeparatedState,這時處于激活狀態的有WpaStartedState及LinkState。

    當wifi關閉時,WpaStartedState處理WIFI_SVR_CMD_STA_DISABLE_WIFI事件,關閉wifi,回到InitState狀態。

    當用戶連接網絡時,LinkState處理CMD_START_CONNECT_SELECTED_NETWORK事件進行連接網絡的動作,收到WIFI_SVR_CMD_STA_NETWORK_CONNECTION_EVENT后,狀態遷移到GetIpState狀態,同時ApLinkedState狀態處于激活。在GetIpState狀態,如果IP地址分配成功,則進入LinkedState。如果分配失敗,則回到SeparatedState。

    不管是在GetIpState還是在LinkedState,只要收到斷開網絡請求WIFI_SVR_CMD_STA_DISCONNECT,都由ApLinkedState處理,進入SeparatedState。

    Scan狀態機樹狀圖.png

    Scan狀態機維護了wifi普通掃描,pno掃描(硬件掃描和軟件掃描)的狀態及切換過程。

    這里對PNO掃描稍加說明,PNO掃描即Preferred Network Offload,用于系統在休眠的時候連接WiFi,當手機休眠時,存在已經保存的網絡并且沒有連接時,進行PNO掃描,只掃描已保存的網絡。PNO模式能讓設備在熄屏時通過搜索最近連接過的Wifi網絡,從而優先連接至Wifi網絡,達到延長續航時間并且減少手機數據流量消耗的目的。

    Wifi打開后,啟動scanService同時構造scan statemachine并初始化,與sta statemachine相同,scan statemachine按照Scan狀態機樹狀圖所示創建狀態機各個狀態。

    Scan狀態機遷移圖.png

    scan statemachine初始化時設置狀態為InitState,隨后發送CMD_SCAN_PREPARE給InitState,進入HardwareReady狀態。

    處于HardwareReady狀態時Native JS調用scan接口進行掃描,HardwareReady會收到CMD_START_COMMON_SCAN消息進入CommonScanning狀態,掃描成功、失敗或者超時后進入CommonScanUnworked狀態,如果這時候再次發起掃描則會回到CommonScanning狀態。

    處于HardwareReady狀態時發起PNO掃描時,首先判斷系統是否支持硬件PNO掃描,如果支持,則進入PnoScanHardware狀態,向底層下發PNO掃描命令。

    在PnoScanHardware狀態,如果收到PNO掃描結果通知,并且NeedCommonScanAfterPno為true,則進入CommonScanAfterPno狀態,等收到CMD_START_COMMON_SCAN進入CommonScanning,或者收到普通掃描命令,進入HardwareReady狀態準備進行普通掃描,否則一直處于PNO硬件掃描狀態。

    當發起PNO掃描后,如果系統不支持硬件PNO掃描,則進入PnoScanSoftware狀態,啟動一次軟件PNO掃描,進入PnoSwScanning狀態,掃描成功或者失敗或者超時后進入PnoSwScanFree狀態。

    在PnoSwScanFree狀態,收到CMD_START_COMMON_SCAN命令,則回到HardwareReady狀態準備進行一次普通掃描;如果收到PNO掃描命令則回到PnoSwScanning狀態。

    STA業務代碼流程

    前面講過,Native Js發起調用,經過IPC通信,調用到WifiDeviceServiceImpl作為服務端的實現。

    Wifi打開流程

    Wifi打開流程時序圖.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服務
    break;
    }
    IStaService *pService = WifiServiceManager::GetInstance().GetStaServiceInst(); //構建StaService
    if (pService == nullptr) {
    WIFI_LOGE("Create %{public}s service failed!", WIFI_SERVICE_STA);
    break;
    }

        errCode = pService->RegisterStaServiceCallback(WifiManager::GetInstance().GetStaCallback());  //注冊回調函數
        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服務,在WifiServiceManager中根據服務名稱WIFI_SERVICE_STA,調用LoadStaService方法加載STA服務;
    2. 構建StaService,獲取接口IStaService實例;
    3. 注冊回調函數;
    4. 調用StaService打開Wifi。
    
    StaService是Wifi框架層Station服務的主要實現,通過創建StaStateMachine和StaMonitor對Wifi Station命令和事件進行處理。
    
    **目錄:foundation/communication/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_sta/sta_service.cpp**
    
    StaService首先在調用之前,首先會初始化:
    
    ```c++
    ErrCode StaService::InitStaService(const StaServiceCallback &callbacks)
    {
        WIFI_LOGI("Enter StaService::InitStaService.
    ");
        pStaStateMachine = new (std::nothrow) StaStateMachine();     //構造StaStateMachine狀態機
        ...
        RegisterStaServiceCallback(callbacks);                      //注冊事件回調函數
    
        pStaMonitor = new (std::nothrow) StaMonitor();              //構造StaMonitor并初始化
        ...
        pStaMonitor->SetStateMachine(pStaStateMachine);             
    
        pStaAutoConnectService = new (std::nothrow) StaAutoConnectService(pStaStateMachine); //構造自動連接服務
        ...
        WIFI_LOGI("Init staservice successfully.
    ");
    
        return WIFI_OPT_SUCCESS;
    }

    初始化主要會做四件事:

    1.構造StaStateMachine狀態機

    2.注冊回調函數

    3.構造StaMonitor

    4.構造自動連接服務

    這些準備工作做完后,就是真正執行EnableWifi的流程。

    ```c++
    ErrCode StaService::EnableWifi() const
    {
    WIFI_LOGI("Enter StaService::EnableWifi. ");
    pStaStateMachine->SendMessage(WIFI_SVR_CMD_STA_ENABLE_WIFI, STA_CONNECT_MODE); //向StaStateMachine發送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在初始化時設置初始狀態為InitState ,”SetFirstState(pInitState)“,故接收到WIFI_SVR_CMD_STA_ENABLE_WIFI在InitState狀態中處理:
    
    ```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();  //調用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(); //調用WifiStaHalInterface的StartWifi()
    //下面是對返回結果的處理
    ...
    }

    
    WifiStaHalInterface是框架調用Wifi Hal的接口。
    
    框架與Wifi Hal的通信主要是借助IDL Client組件,采用RPC服務實現其交互。
    
    無論是框架調用Wifi Hal還是Wifi Hal回調消息到框架,都要經過IDL Clinet,從架構圖來看,它屬于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.構造WifiIdlClient實例

    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實例,調用其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發起RPC調用“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調用客戶端,然后通過RemoteCall(client)方法發起遠程調用。

    Wifi Hal作為RPC服務端,啟動后調用InitRpcFunc初始化RPC函數,然后CreateRpcServer創建RPC服務,最后調用RunRpcLoop循環讀取遠程調用信息,處理客戶端請求。

    目錄: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”消息的處理函數,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;
    }

    根據配對關系調用到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(); //調用Start方法
        WriteBegin(context, 0);
        WriteInt(context, err);
        WriteEnd(context);
        return 0;
    }

    調用Start()實際操作實現在wifi_hal_sta_interface的Start函數,調用完成。

    目錄: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) { //構造并初始化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. 構造并初始化WifiWpaStaInterface,封裝了wpa_supplicant關于STA的操作命令。

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

    以上三步成功后,RPC調用返回WIFI_HAL_SUCCESS,日志會打印"Start wifi successfully"。

    StaStateMachine在EnableWifi成功后,設置wifistate為ENABLED并執行OnStaOpenRes回調:

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

    
    回調在WifiManager中處理,廣播wifi狀態改變消息,構造ScanService并初始化,初始化過程做了這幾件事:
    1. 構造ScanStateMachine并初始化,調用EnrollScanStatusListener綁定Scan狀態上報事件的處理函數。
    2. 構造ScanMonitor并初始化,在初始化函數中調用RegisterSupplicantEventCallback,注冊supplicant事件回調。
    
    **目錄: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;
        //構造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狀態上報事件的處理函數
        if (!pScanStateMachine->EnrollScanStatusListener(
            std::bind(&ScanService::HandleScanStatusReport, this, std::placeholders::_1))) {
            WIFI_LOGE("ScanStateMachine_->EnrollScanStatusListener failed.
    ");
            return false;
        }
        //構造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發送CMD_SCAN_PREPARE
        pScanStateMachine->SendMessage(static_cast<int>(CMD_SCAN_PREPARE));
        GetScanControlInfo();
    
        return true;
    }

    ScanStateMachine初始化狀態為InitState,然后接收到CMD_SCAN_PREPARE消息,調用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切換狀態為為HardwareReadyState
    2. 上報SCAN_STARTED_STATUS狀態

    然后就可以發起掃描的流程了。

    掃描流程

    Wifi掃描流程時序圖.png

    應用調用Native JS的Scan接口,會通過獲取WifiScan實例,調用C++接口,發起IPC通信,通過WifiScanProxy向服務框架發送WIFI_SVR_CMD_FULL_SCAN請求。WifiScanStub作為服務端接收到請求,WifiScanServiceImpl作為服務端的主要實現。

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

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

    
    構造ScanService,通過IScanService接口調用其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.
    ");
        }
        //構造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;
    }

    這里首先構造scanConfig,然后調用SingleScan向ScanStateMachine發送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);
    //發送消息
    pScanStateMachine->SendMessage(interMessage);

    
    ScanService初始化完成后,ScanStateMachine處于HardwareReady是可以發起掃描的激活狀態,
    
    **目錄: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并處理,進行獲取掃描參數的操作,并校驗Scan類型是否合法,之后轉換掃描參數,通過RPC調用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配置參數后,通過wpaCliCmdScan向supplicant發送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發送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。

    調用成功StaStateMachine切換狀態為CommonScanningState。

    掃描結果獲取

    掃描結果獲取流程時序圖.png

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

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

    
    ?    ScanStateMachine此時狀態為CommonScanning,接收消息并處理,發起RPC遠程調用wifi hal獲取掃描結果。
    
    ```c++
    case SCAN_RESULT_EVENT:
                pScanStateMachine->CommonScanInfoProcess();
                pScanStateMachine->SwitchState(pScanStateMachine->commonScanUnworkedState); //切換狀態為CommonScanUnworkedState
                return true;

    ```c++
    void ScanStateMachine::CommonScanInfoProcess()
    {
    WIFI_LOGI("Enter ScanStateMachine::CommonScanInfoProcess. ");
    //構造ScanStatusReport
    ScanStatusReport scanStatusReport;
    //獲取掃描結果
    if (!GetScanInfos(scanStatusReport.scanInfoList)) {
    WIFI_LOGE("GetScanInfos failed.");
    ReportCommonScanFailedAndClear(true);
    return;
    }
    GetRunningIndexList(scanStatusReport.requestIndexList);
    //設置掃描狀態為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.");
        //發起RPC遠程調用wifi hal獲取掃描結果
        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返回掃描結果給ScanStateMachine后,ScanStateMachine構造ScanStatusReport,包含scanInfoList和status為COMMON_SCAN_SUCCESS,通過scanStatusReportHandler上報,在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拿到掃描結果,主要做的事是調用WifiSettings的SaveScanInfoList(filterScanInfo),將掃描結果保存。
    
    之后,應用調用native js的GetScanInfos接口,通過WifiScanServiceImpl調用WifiSettings的GetScanInfoList獲取到保存的掃描結果。
    
    掃描結果中包含的信息如下,一般常用到的信息有:
    
    Bssid - 掃描到的AP的mac地址
    
    Ssid - 掃描到的AP的標識名稱
    
    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連接流程時序圖.png

    應用獲取到掃描結果后,選擇一個Wifi網絡進行連接,調用Native Js的connectToDevice接口調用到WifiDevice,然后通過IPC通信,WifiDeviceProxy作為客戶端代理發送WIFI_SVR_CMD_CONNECT2_TO消息,WifiDeviceStub作為服務端接收到消息后調用IPC服務的實現類WifiDeviceServiceImpl進行發起連接流程。

    目錄: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); //調用StaService的ConnectToDevice
    }

    
    獲取StaService的接口實例,調用其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);//調用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發送WIFI_SVR_CMD_STA_CONNECT_NETWORK消息
        return WIFI_OPT_SUCCESS;
    }

    StaService首先調用AddDeviceConfig,在這個函數中主要做了兩件事:

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

    2)調用ConvertDeviceCfg,在StaStateMachine中將網絡配置參數轉換為idl參數,然后調用HAL的SetDeviceConfig函數,向supplicant發送SET_NETWORK命令。

    StaService在調用AddDeviceConfig得到networkid并且設置配置參數到supplicant成功后,向StaStateMachine發送“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消息調用DealConnectToUserSelectedNetwork

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

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

    StartConnectToNetwork:

    ```c++
    void StaStateMachine::StartConnectToNetwork(int networkId)
    {
    targetNetworkId = networkId;
    SetRandomMac(targetNetworkId); //設置隨機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);

    }

    
    這里主要做了三個操作:發起RPC調用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;
    }

    這里按調用先后向supplicant發送EnableNetwork、SELECT_NETWORK以及SAVE_CONFIG命令,supplicant根據收到的命令完成AP的連接管理。

    Supplicant連接成功后,回送WPA_EVENT_CONNECTED事件,調用WifiHalCbNotifyConnectChanged(WPA_CB_CONNECTED,id,pMacPos)通知連接成功,經過Hal再由StaMonitor的處理回調,發送消息WIFI_SVR_CMD_STA_NETWORK_CONNECTION_EVENT給StaStateMachine,調用DealConnectionEvent方法來處理連接事件,狀態機進入getIpState狀態,獲取ip地址,靜態ip或者dhcp動態獲取成功后,繼續調用StaNetworkCheck檢查網絡連接狀態。

    Wifi-STA接口說明及使用

    接口說明

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

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

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

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

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

    更多原創內容請關注:深開鴻技術團隊

    入門到精通、技巧到案例,系統化分享HarmonyOS開發技術,歡迎投稿和訂閱,讓我們一起攜手前行共建鴻蒙生態。

    想了解更多關于開源的內容,請訪問:

    51CTO 開源基礎軟件社區

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

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

    開通會員,享受整站包年服務
    国产呦精品一区二区三区网站|久久www免费人咸|精品无码人妻一区二区|久99久热只有精品国产15|中文字幕亚洲无线码