鸿蒙 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 收到命令后去做扫描动作,那扫描到结果如何通知上层呢?下一篇我们继续记录。

相关推荐
yilylong2 小时前
鸿蒙(Harmony)实现滑块验证码
华为·harmonyos·鸿蒙
baby_hua2 小时前
HarmonyOS第一课——DevEco Studio的使用
华为·harmonyos
HarmonyOS_SDK3 小时前
融合虚拟与现实,AR Engine为用户提供沉浸式交互体验
harmonyos
- 羊羊不超越 -4 小时前
App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)
android·ios·harmonyos
长弓三石6 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙
SameX7 小时前
鸿蒙 Next 电商应用安全支付与密码保护实践
前端·harmonyos
SuperHeroWu78 小时前
【HarmonyOS】键盘遮挡输入框UI布局处理
华为·harmonyos·压缩·keyboard·键盘遮挡·抬起
sanzk13 小时前
华为鸿蒙应用开发
华为·harmonyos
SoraLuna17 小时前
「Mac畅玩鸿蒙与硬件28」UI互动应用篇5 - 滑动选择器实现
macos·ui·harmonyos
ClkLog-开源埋点用户分析18 小时前
ClkLog企业版(CDP)预售开启,更有鸿蒙SDK前来助力
华为·开源·开源软件·harmonyos