鸿蒙 WiFi 扫描流程(2)

news/2024/7/21 11:13:56 标签: harmonyos, 华为

接着上篇没有记录完的,我们继续梳理,需要上一篇做基础的请看:鸿蒙 WiFi 扫描流程(1)
上一篇我们讲到 scan_service.cpp 里面的 SingleScan 方法,继续这个方法往下看:

// 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

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


http://www.niftyadmin.cn/n/5366386.html

相关文章

【Unity优化(一)】音频优化

整理资教程&#xff1a;https://learn.u3d.cn/tutorial/unity-optimization-metaverse 1.音频优化 音频一般不会成为性能瓶颈&#xff0c;是为了节省内存和优化包体大小。 1.0 文件格式和压缩格式 原始音频资源尽量采用WAV格式。 移动平台音频尽量采用Vorbis压缩格式&#x…

20240202在WIN10下使用whisper.cpp

20240202在WIN10下使用whisper.cpp 2024/2/2 14:15 【结论&#xff1a;在Windows10下&#xff0c;确认large模式识别7分钟中文视频&#xff0c;需要83.7284 seconds&#xff0c;需要大概1.5分钟&#xff01;效率太差&#xff01;】 83.7284/4200.1993533333333333333333333333…

OpenCV 图像处理六(傅里叶变换、模板匹配与霍夫变换)

文章目录 一、傅里叶变换1.1 NumPy实现和逆实现1.1.1 NumPy实现傅里叶变换Demo 1.1.2 NumPy实现逆傅里叶变换Demo 1.2 OpenCV实现和逆实现1.2.1 OpenCV实现傅里叶变换Demo 1.2.2 OpenCV实现逆傅里叶变换Demo 1.3 频域滤波1.3.1低频、高频1.3.2 高通滤波器构造高通滤波器Demo 1.…

4.0 Zookeeper Java 客户端搭建

本教程使用的 IDE 为 IntelliJ IDEA&#xff0c;创建一个 maven 工程&#xff0c;命名为 zookeeper-demo&#xff0c;并且引入如下依赖&#xff0c;可以自行在maven中央仓库选择合适的版本&#xff0c;介绍原生 API 和 Curator 两种方式。 IntelliJ IDEA 相关介绍&#xff1a;…

LeetCode每日一题 | 1696. 跳跃游戏 VI

文章目录 题目描述问题分析程序代码 题目描述 给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 一开始你在下标 0 处。每一步&#xff0c;你最多可以往前跳 k 步&#xff0c;但你不能跳出数组的边界。也就是说&#xff0c;你可以从下标 i 跳到 [i 1&#xff0c; min(…

什么样的台灯适合学生做作业的?眼科医生都说好的学生台灯

现在的孩子学业压力确实蛮重的&#xff0c;像我们以前小时候基本没什么作业可言的&#xff0c;放学回家很快就能完成作业去玩耍了。而现在的孩子不仅每天都需要高强度的学习用眼&#xff0c;而且放学回到家后就开始伏案在书桌前一直完成老师布置的作业&#xff0c;有时候甚至写…

mac检查CPU温度和风扇速度软件:Macs Fan Control Pro 1.5.17中文版

Macs Fan Control Pro for Mac是一款专业的电脑风扇控制工具&#xff0c;旨在帮助Mac用户有效控制电脑的风扇速度&#xff0c;提高电脑的运行效率和稳定性。 软件下载&#xff1a;Macs Fan Control Pro 1.5.17中文版 该软件支持多种风扇控制模式和预设方案&#xff0c;用户可以…

elementUI 表格中如何合并动态数据的单元格

elementUI 表格中如何合并动态数据的单元格 ui中提供的案例是固定写法无法满足 实际开发需求 下面进行改造如下 准备数据如下 //在表格中 设置单元格的方法 :span-method"spanMethodFun" <el-table :data"tableData" border :span-method"spa…