鸿蒙驱动开发-解决iphone手机热点重启后,设备未自动连接热点

一、问题描述

打开苹果手机热点,设备wifi连接苹果手机热点,当苹果手机重新开启热点,设备无法自动连接。安卓手机重新打开热点后,不会出现这种情况,windows11系统thinkpad也不会出现这种情况。

设备F8 pro  rockpi3A 用4.1.0.4版本的社区代码都会出现这种问题。

二、问题定位

之前没有弄过wifi驱动,只在实习的时候搞过几个月的蓝牙协议栈,所以只能先看OpenHarmony的wifi框架原理,然后一点一点看hilog的日志,定位一下问题大概出现在哪里。

1.wifi子系统架构

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驱动移植人员编译进内核。

2.问题分析

设备作为STA去连接作为AP的iphone,而作为AP的安卓机却没有这种问题,所以关键点在于分析设备与苹果手机和安卓手机的连接机制区别。用串口分析连接过程后,会发现iphone手机重新打开热点后,会重新配置一个mac地址,而安卓手机还是原来的mac地址,这就是不同点。但是仔细看代码会发现,在发起连接机制中,作为mac地址的bssid并不会影响连接过程,所以初步判断问题没有出现在连接过程。深入分析代码,hilog落盘,看wifi打印日志,能够发现wifi重新连接调用的是一个周期函数sta_service中的AutoConnectService。

三、解决方案

加log日志,发现卡在了OnScanInfosReadyHandler

ErrCode StaService::AutoConnectService(const std::vector<InterScanInfo> &scanInfos)
{
    LOGI(" ConnectToDevice, Enter StaService::AutoConnectService\n");
    WIFI_LOGI("Enter AutoConnectService.\n");
    CHECK_NULL_AND_RETURN(pStaAutoConnectService, WIFI_OPT_FAILED);
#ifndef OHOS_ARCH_LITE
    if (IsOtherVapConnect()) {
        LOGI("gly::AutoConnectService: p2p or hml connected, and hotspot is enable");
        return WIFI_OPT_FAILED;
    }
    const std::string wifiBrokerFrameProcessName = ANCO_SERVICE_BROKER;
    std::string ancoBrokerFrameProcessName = GetRunningProcessNameByPid(GetCallingUid(), GetCallingPid());
    if (ancoBrokerFrameProcessName == wifiBrokerFrameProcessName) {
        WifiConfigCenter::GetInstance().SetWifiConnectedMode(true, m_instId);
        WIFI_LOGD("gly::StaService %{public}s, anco, %{public}d", __func__, m_instId);
    } else {
        WifiConfigCenter::GetInstance().SetWifiConnectedMode(false, m_instId);
        WIFI_LOGD("gly::StaService %{public}s,not anco, %{public}d", __func__, m_instId);
    }
#endif
    pStaAutoConnectService->OnScanInfosReadyHandler(scanInfos);
    return WIFI_OPT_SUCCESS;
}

pNetworkSelectionManager->SelectNetwork判断错误

void StaAutoConnectService::OnScanInfosReadyHandler(const std::vector<InterScanInfo> &scanInfos)
{
    WIFI_LOGI("Enter OnScanInfosReadyHandler.\n");
    WIFI_LOGI("gly::StaAutoConnectService::OnScanInfosReadyHandler\n");
    ClearOvertimeBlockedBssid(); /* Refreshing the BSSID Blocklist */

    WifiLinkedInfo info;
    WifiSettings::GetInstance().GetLinkedInfo(info, m_instId);
    if (info.supplicantState == SupplicantState::ASSOCIATING ||
        info.supplicantState == SupplicantState::AUTHENTICATING ||
        info.supplicantState == SupplicantState::FOUR_WAY_HANDSHAKE ||
        info.supplicantState == SupplicantState::GROUP_HANDSHAKE) {
        WIFI_LOGE("Supplicant is under transient state.\n");
        WIFI_LOGI("gly::Supplicant is under transient state\n");
        return;
    }

    if (info.connState == ConnState::CONNECTED) {
        ClearAllBlockedBssids();
    }
    std::vector<std::string> blockedBssids;
    GetBlockedBssids(blockedBssids);
    if (!AllowAutoSelectDevice(info) || !IsAllowAutoJoin()) {
        WIFI_LOGI("gly::AllowAutoSelectDevice(info) faield\n");
        return;
    }
    NetworkSelectionResult networkSelectionResult;
    if (pNetworkSelectionManager->SelectNetwork(networkSelectionResult, NetworkSelectType::AUTO_CONNECT, scanInfos)) {
        int networkId = networkSelectionResult.wifiDeviceConfig.networkId;
        std::string &bssid = networkSelectionResult.interScanInfo.bssid;
        std::string &ssid = networkSelectionResult.interScanInfo.ssid;
        WIFI_LOGI("gly::AutoSelectDevice networkId: %{public}d, ssid: %{public}s, bssid: %{public}s.", networkId,
                  SsidAnonymize(ssid).c_str(), MacAnonymize(bssid).c_str());
        auto message = pStaStateMachine->CreateMessage(WIFI_SVR_CMD_STA_CONNECT_SAVED_NETWORK);
        message->SetParam1(networkId);
        message->SetParam2(NETWORK_SELECTED_BY_AUTO);
        message->AddStringMessageBody(bssid);
        pStaStateMachine->SendMessage(message);
    } else {
        WIFI_LOGI("AutoSelectDevice return fail.");
        WIFI_LOGI("gly::AutoSelectDevice return fail.\n");
        return;
    }
}

加日志,发现可以拿到候选者,但是在候选者过滤后,设备为0。

bool NetworkSelectionManager::SelectNetwork(NetworkSelectionResult &networkSelectionResult,
                                            NetworkSelectType type,
                                            const std::vector<InterScanInfo> &scanInfos)
{
    if (scanInfos.empty()) {
        WIFI_LOGI("gly::scanInfos is empty, ignore this selection");
        return false;
    }

    /* networkCandidates must be declared before networkSelector,
     * so it can be accessed in the destruct of networkSelector and wifiFilter */
    std::vector<NetworkSelection::NetworkCandidate> networkCandidates;
    auto networkSelectorOptional = pNetworkSelectorFactory->GetNetworkSelector(type);
    if (!(networkSelectorOptional.has_value())) {
        WIFI_LOGE("gly::Get NetworkSelector failed for type %{public}d", static_cast<int>(type));
        return false;
    }
    auto &networkSelector = networkSelectorOptional.value();
    WIFI_LOGI("gly::NetworkSelector: %{public}s", networkSelector->GetNetworkSelectorMsg().c_str());

    /* Get the device config for each scanInfo, then create networkCandidate and put it into networkCandidates */
    GetAllDeviceConfigs(networkCandidates, scanInfos);

    /* Traverse networkCandidates and reserve qualified networkCandidate */
    TryNominate(networkCandidates, networkSelector);

    /* Get best networkCandidate from the reserved networkCandidates */
    std::vector<NetworkSelection::NetworkCandidate *> bestNetworkCandidates;

    networkSelector->GetBestCandidates(bestNetworkCandidates);
    if (bestNetworkCandidates.empty()) {
        WIFI_LOGI("gly::bestNetworkCandidates.empty");
        return false;
    }
    WIFI_LOGI("gly::NetworkSelectionManager::SelectNetwork success\n");
    /* if bestNetworkCandidates is not empty, assign the value of first bestNetworkCandidate
     * to the network selection result, and return true which means the network selection is successful */
    networkSelectionResult.wifiDeviceConfig = bestNetworkCandidates.at(0)->wifiDeviceConfig;
    networkSelectionResult.interScanInfo = bestNetworkCandidates.at(0)->interScanInfo;
    return true;
}

问题卡在TryNominate(networkCandidates, networkSelector);深入分析networkSelector,打印筛选条件,可以发现其中有个matchuserselect条件,看到代码是基于bssid匹配筛选的,这下直接对上了与安卓机的区别,于是注销掉了下面这行代码。

auto andFilter = make_shared<AndWifiFilter>();
    andFilter->AddFilter(make_shared<SavedWifiFilter>());
    andFilter->AddFilter(make_shared<PassPointWifiFilter>());
    andFilter->AddFilter(make_shared<EphemeralWifiFilter>());
    andFilter->AddFilter(make_shared<DisableWifiFilter>());
    // andFilter->AddFilter(make_shared<MatchedUserSelectBssidWifiFilter>());

便不会出现这个BUG。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值