鸿蒙 WiFi 扫描流程(2)

接着上篇没有记录完的,我们继续梳理,需要上一篇做基础的请看:鸿蒙 WiFi 扫描流程(1)

上一篇我们讲到 scan_service.cpp 里面的 SingleScan 方法,继续这个方法往下看:

cpp 复制代码
// foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_scan/scan_service.cpp

bool ScanService::SingleScan(ScanConfig &scanConfig)
{
    WIFI_LOGI("Enter ScanService::SingleScan.\n");

#ifndef OHOS_ARCH_LITE
    if (!standByListerner.AllowScan()) {
        WIFI_LOGE("Scan not allowed when device in standby state.\n");
        return WIFI_OPT_FAILED;
    }
#endif

    GetAllowBandFreqsControlInfo(scanConfig.scanBand, scanConfig.scanFreqs);                   ---> 哪个Band
    if ((scanConfig.scanBand == SCAN_BAND_UNSPECIFIED) && (scanConfig.scanFreqs.empty())) {
        WIFI_LOGE("Have no allowed band or freq.\n");
        return false;
    }

    InterScanConfig interConfig;
    interConfig.fullScanFlag = scanConfig.fullScanFlag;
    interConfig.hiddenNetworkSsid.assign(scanConfig.hiddenNetworkSsid.begin(), scanConfig.hiddenNetworkSsid.end());
    interConfig.scanStyle = scanConfig.scanStyle;

    /* Specified frequency */
    if (scanConfig.scanBand == SCAN_BAND_UNSPECIFIED) {
        interConfig.scanFreqs.assign(scanConfig.scanFreqs.begin(), scanConfig.scanFreqs.end());
        /*
         * When band is SCAN_BAND_BOTH_WITH_DFS, need to scan all frequency,
         * scanFreqs can be empty.
         */
    } else if (scanConfig.scanBand != SCAN_BAND_BOTH_WITH_DFS) {
        /* Converting frequency bands to frequencies. */
        if (!GetBandFreqs(scanConfig.scanBand, interConfig.scanFreqs)) {
            WIFI_LOGE("GetBandFreqs failed.\n");
            return false;
        }
    }

    /* Save the configuration. */
    int requestIndex = StoreRequestScanConfig(scanConfig, interConfig);
    if (requestIndex == MAX_SCAN_CONFIG_STORE_INDEX) {
        WIFI_LOGE("StoreRequestScanConfig failed.\n");
        return false;
    }

    std::unique_lock<std::mutex> lock(scanConfigMapMutex);
    if (pScanStateMachine == nullptr) {
        WIFI_LOGE("pScanStateMachine is null.\n");
        return false;
    }
    /* Construct a message. */   // 去状态机里面处理这个消息
    InternalMessage *interMessage =pScanStateMachine->CreateMessage(static_cast<int>(CMD_START_COMMON_SCAN), requestIndex);
    if (interMessage == nullptr) {
        scanConfigMap.erase(requestIndex);
        WIFI_LOGE("CreateMessage failed.\n");
        return false;
    }

    if (!AddScanMessageBody(interMessage, interConfig)) {
        scanConfigMap.erase(requestIndex);
        MessageManage::GetInstance().ReclaimMsg(interMessage);
        WIFI_LOGE("AddScanMessageBody failed.\n");
        return false;
    }
    pScanStateMachine->SendMessage(interMessage);

    return true;
}

//foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_scan/scan_state_machine.cpp
bool ScanStateMachine::HardwareReady::ExecuteStateMsg(InternalMessage *msg)
{
    WIFI_LOGI("ScanStateMachine::HardwareReady::ExecuteStateMsg.\n");
    if (msg == nullptr) {
        WIFI_LOGE("msg is null.\n");
        return true;
    }

    switch (msg->GetMessageName()) {
        case CMD_START_COMMON_SCAN:      ---》 处理这个消息
            pScanStateMachine->CommonScanRequestProcess(msg);
            return true;

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

        default:
            return false;
    }
}
// 发起 CommonScanRequestProcess 流程
void ScanStateMachine::CommonScanRequestProcess(InternalMessage *interMessage)
{
    WIFI_LOGI("ScanStateMachine::CommonScanRequestProcess.\n");

    int requestIndex = 0;
    InterScanConfig scanConfig;
    if (!GetCommonScanRequestInfo(interMessage, requestIndex, scanConfig)) {
        ReportCommonScanFailed(requestIndex);
        return;
    }
    if (!VerifyScanStyle(scanConfig.scanStyle)) {
        WIFI_LOGE("invalid scan type");
        return;
    }
    {
        std::unique_lock<std::shared_mutex> guard(lock);
        waitingScans.insert(std::pair<int, InterScanConfig>(requestIndex, scanConfig));
    }
    StartNewCommonScan();
}

void ScanStateMachine::StartNewCommonScan()
{
    WIFI_LOGI("Enter ScanStateMachine::StartNewCommonScan.\n");

    {
        std::shared_lock<std::shared_mutex> guard(lock);
        if (waitingScans.size() == 0) {
            ContinuePnoScanProcess();
            return;
        }
        ClearRunningScanSettings();
        bool hasFullScan = false;
        /* Traverse the request list and combine parameters */
        std::map<int, InterScanConfig>::iterator configIter = waitingScans.begin();
        for (; configIter != waitingScans.end(); ++configIter) {
            runningScanSettings.scanStyle = MergeScanStyle(runningScanSettings.scanStyle, configIter->second.scanStyle);
            std::vector<std::string>::iterator hiddenIter = configIter->second.hiddenNetworkSsid.begin();
            /* Remove duplicate hidden list */
            for (; hiddenIter != configIter->second.hiddenNetworkSsid.end(); ++hiddenIter) {
                if (std::find(runningScanSettings.hiddenNetworkSsid.begin(),
                    runningScanSettings.hiddenNetworkSsid.end(),
                    *hiddenIter) != runningScanSettings.hiddenNetworkSsid.end()) {
                    continue;
                }
                runningScanSettings.hiddenNetworkSsid.push_back(*hiddenIter);
            }

            if (!hasFullScan) {
                /* When scanFreqs is empty, it means that scan all frequenties */
                if (configIter->second.scanFreqs.empty()) {
                    runningScanSettings.scanFreqs.clear();
                    runningFullScanFlag = true;
                    hasFullScan = true;
                } else {
                    std::vector<int>::iterator freqIter = configIter->second.scanFreqs.begin();
                    /* Repetitions are eliminated */
                    for (; freqIter != configIter->second.scanFreqs.end(); ++freqIter) {
                        if (std::find(runningScanSettings.scanFreqs.begin(),
                            runningScanSettings.scanFreqs.end(),
                            *freqIter) != runningScanSettings.scanFreqs.end()) {
                            continue;
                        }
                        runningScanSettings.scanFreqs.push_back(*freqIter);
                    }
                }
            }
        }
    }

    if (!StartSingleCommonScan(runningScanSettings)) {       ---》 继续看这个
        ReportCommonScanFailedAndClear(false);
        ContinuePnoScanProcess();
        return;
    }

    std::unique_lock<std::shared_mutex> guard(lock);
    runningScans.swap(waitingScans);
    waitingScans.clear();
    SwitchState(commonScanningState);
    WIFI_LOGI("StartNewCommonScan success.\n");
}

bool ScanStateMachine::StartSingleCommonScan(WifiScanParam &scanParam)
{
    WIFI_LOGI("Enter ScanStateMachine::StartSingleCommonScan.\n");

    for (auto freqIter = scanParam.scanFreqs.begin(); freqIter != scanParam.scanFreqs.end(); ++freqIter) {
        WIFI_LOGI("freq is %{public}d.\n", *freqIter);
    }

    for (auto hiddenIter = scanParam.hiddenNetworkSsid.begin(); hiddenIter != scanParam.hiddenNetworkSsid.end();
         ++hiddenIter) {
        WIFI_LOGI("hidden ssid is %{public}s.\n", SsidAnonymize(*hiddenIter).c_str());
    }

    WIFI_LOGI("Begin call Scan.\n");
    WifiErrorNo ret = WifiStaHalInterface::GetInstance().Scan(scanParam);      ---> 是不是很熟悉,要通过idl_client
    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.\n");

    /*
     * Start the timer. If no result is returned for a long time, the scanning
     * fails
     */
    StartTimer(static_cast<int>(WAIT_SCAN_RESULT_TIMER), MAX_WAIT_SCAN_RESULT_TIME);
    return true;
}

继续看下代码,WifiStaHalInterface里面的 Scan 方法:

foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/idl_client/wifi_sta_hal_interface.cpp

cpp 复制代码
WifiErrorNo WifiStaHalInterface::Scan(const WifiScanParam &scanParam)
{
    CHECK_NULL_AND_RETURN(mIdlClient, WIFI_IDL_OPT_FAILED);
    return mIdlClient->Scan(scanParam);
}

// foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/idl_client/wifi_idl_client.cpp
WifiErrorNo WifiIdlClient::Scan(const WifiScanParam &scanParam)
{
    CHECK_CLIENT_NOT_NULL;
    ScanSettings settings;
    if (memset_s(&settings, sizeof(settings), 0, sizeof(settings)) != EOK) {
        return WIFI_IDL_OPT_FAILED;
    }
    bool bfail = false;
    do {
        if (scanParam.hiddenNetworkSsid.size() > 0) {
            settings.hiddenSsidSize = scanParam.hiddenNetworkSsid.size();
            settings.hiddenSsid = ConVectorToCArrayString(scanParam.hiddenNetworkSsid);
            if (settings.hiddenSsid == nullptr) {
                bfail = true;
                break;
            }
        }
        if (scanParam.scanFreqs.size() > 0) {
            settings.freqSize = scanParam.scanFreqs.size();
            settings.freqs = (int *)calloc(settings.freqSize, sizeof(int));
            if (settings.freqs == nullptr) {
                bfail = true;
                break;
            }
            for (int i = 0; i < settings.freqSize; ++i) {
                settings.freqs[i] = scanParam.scanFreqs[i];
            }
        }
        if (scanParam.scanStyle > 0) {
            settings.scanStyle = scanParam.scanStyle;
        }
    } while (0);
    WifiErrorNo err = WIFI_IDL_OPT_FAILED;
    if (!bfail) {
        err = StartScan(&settings);      ---> 向 Hal 发起扫描
    }
    if (settings.freqs != nullptr) {
        free(settings.freqs);
        settings.freqs = nullptr;
    }
    if (settings.hiddenSsid != nullptr) {
        for (int i = 0; i < settings.hiddenSsidSize; ++i) {
            free(settings.hiddenSsid[i]);
            settings.hiddenSsid[i] = nullptr;
        }
        free(settings.hiddenSsid);
        settings.hiddenSsid = nullptr;
    }
    return err;
}
// 中间省略了 RPC的调用,代码可以看wifi_hal_crpc_server类,处理客户端请求,然后根据请求找到对应的函数,在调用HAL的方法
// 直接看调用的HAL方法:foundation/communication/wifi/wifi/services/wifi_standard/wifi_hal/wifi_hal_sta_interface.c
WifiErrorNo StartScan(const ScanSettings *settings)
{
    LOGD("Ready to start scan with param.");
#ifdef HDI_INTERFACE_SUPPORT
    int ret = HdiStartScan(settings);
#else
    WifiWpaStaInterface *pStaIfc = GetWifiStaInterface(0);
    if (pStaIfc == NULL) {
        return WIFI_HAL_SUPPLICANT_NOT_INIT;
    }
    int ret = pStaIfc->wpaCliCmdScan(pStaIfc, settings);    ---> 往supplicant 发送命令
    if (ret < 0) {
        LOGE("StartScan failed! ret=%{public}d", ret);
        return WIFI_HAL_FAILED;
    }
#endif
    if (ret == WIFI_HAL_SCAN_BUSY) {
        LOGD("StartScan return scan busy");
        return WIFI_HAL_SCAN_BUSY;
    }
    LOGD("StartScan successfully!");
    return WIFI_HAL_SUCCESS;
}

// int (*wpaCliCmdScan)(WifiWpaStaInterface *p, const ScanSettings *settings);
// wifi/services/wifi_standard/wifi_hal/wifi_hal_module/wpa_supplicant_hal/wpa_sta_hal/wifi_supplicant_hal.c
static int WpaCliCmdScan(WifiWpaStaInterface *this, const ScanSettings *settings)
{
    if (this == NULL) {
        LOGE("WpaCliCmdScan, this is NULL!");
        return -1;
    }

    /* Invalidate expired scan results */
    WpaCliCmdBssFlush(this);
    unsigned len = CMD_BUFFER_SIZE;
    unsigned expectedLen = 0;
    if (settings != NULL) {
        expectedLen = AssignCmdLen(this, settings);
    }
    if (expectedLen >= len) {
        len = expectedLen + 1;
    }
    char *pcmd = (char *)calloc(len, sizeof(char));
    if (pcmd == NULL) {
        LOGE("WpaCliCmdScan, pcmd is NULL!");
        return -1;
    }
    int pos = 0;
    int res = 0;
    if (settings != NULL) {
        if (settings->scanStyle == SCAN_TYPE_PNO && settings->isStartPnoScan) {
            res = snprintf_s(pcmd, len, len - 1, "IFNAME=%s set pno 1", this->ifname);
        } else if (settings->scanStyle == SCAN_TYPE_PNO && !settings->isStartPnoScan) {
            res = snprintf_s(pcmd, len, len - 1, "IFNAME=%s set pno 0", this->ifname);
        } else {
            res = snprintf_s(pcmd, len, len - 1, "IFNAME=%s SCAN", this->ifname);
        }
    }
    if (res < 0) {
        LOGE("WpaCliCmdScan, snprintf_s error!");
        free(pcmd);
        return -1;
    }
    pos += res;
    if (settings != NULL && ConcatScanSetting(settings, pcmd + pos, len - pos) < 0) {
        LOGE("snprintf scan settings error");
        free(pcmd);
        return -1;
    }
    char buf[REPLY_BUF_SMALL_LENGTH] = {0};
    if (WpaCliCmd(pcmd, buf, sizeof(buf)) != 0) {      ---》 命令下发
        free(pcmd);
        return -1;
    }
    free(pcmd);
    if (strncmp(buf, "FAIL-BUSY", strlen("FAIL-BUSY")) == 0) {
        LOGE("WpaCliCmdScan, WpaCliCmd return FAIL-BUSY!");
        return FAIL_BUSY;
    }
    return 0;
}

// foundation/communication/wifi/wifi/services/wifi_standard/wifi_hal/wifi_hal_module/wpa_supplicant_hal/wifi_wpa_common.c
int WpaCliCmd(const char *cmd, char *buf, size_t bufLen)
{
    if (cmd == NULL || buf == NULL || bufLen <= 0) {
        LOGE("WpaCliCmd, invalid parameters!");
        return -1;
    }
    WpaCtrl *ctrl = GetWpaCtrl();
    if (ctrl == NULL || ctrl->pSend == NULL) {
        LOGE("WpaCliCmd, ctrl/ctrl->pSend is NULL!");
        return -1;
    }
    size_t len = bufLen - 1;
    LOGI("wpa_ctrl_request -> cmd: %{private}s", cmd);
    int ret = wpa_ctrl_request(ctrl->pSend, cmd, strlen(cmd), buf, &len, NULL);
    if (ret == WPA_CMD_RETURN_TIMEOUT) {
        LOGE("[%{private}s] command timed out.", cmd);
        return WPA_CMD_RETURN_TIMEOUT;
    } else if (ret < 0) {
        LOGE("[%{private}s] command failed.", cmd);
        return -1;
    }
    buf[len] = '\0';
    LOGI("wpa_ctrl_request -> buf: %{private}s", buf);
    if (strncmp(buf, "FAIL\n", strlen("FAIL\n")) == 0 ||
        strncmp(buf, "UNKNOWN COMMAND\n", strlen("UNKNOWN COMMAND\n")) == 0) {
        LOGE("%{private}s request success, but response %{public}s", cmd, buf);
        return -1;
    }
    return 0;
}

到此我们就看到命令发送到wpa,然后wpa 收到命令后去做扫描动作,那扫描到结果如何通知上层呢?下一篇我们继续记录。

相关推荐
小冷爱学习!8 小时前
华为动态路由-OSPF-完全末梢区域
服务器·网络·华为
2501_904447749 小时前
华为发力中端,上半年nova14下半年nova15,大力普及原生鸿蒙
华为·智能手机·django·scikit-learn·pygame
MarkHD10 小时前
第十八天 WebView深度优化指南
华为·harmonyos
塞尔维亚大汉10 小时前
OpenHarmony(鸿蒙南向)——平台驱动开发【MIPI CSI】
harmonyos·领域驱动设计
别说我什么都不会11 小时前
鸿蒙轻内核M核源码分析系列十五 CPU使用率CPUP
操作系统·harmonyos
feiniao865112 小时前
2025年华为手机解锁BL的方法
华为·智能手机
塞尔维亚大汉12 小时前
OpenHarmony(鸿蒙南向)——平台驱动开发【I3C】
harmonyos·领域驱动设计
VVVVWeiYee12 小时前
BGP配置华为——路径优选验证
运维·网络·华为·信息与通信
今阳14 小时前
鸿蒙开发笔记-6-装饰器之@Require装饰器,@Reusable装饰器
android·app·harmonyos
余多多_zZ15 小时前
鸿蒙初学者学习手册(HarmonyOSNext_API14)_组件截图(@ohos.arkui.componentSnapshot (组件截图) )
学习·华为·harmonyos·鸿蒙·鸿蒙系统