当前位置:   article > 正文

NetworkSelector 和 WifiConnectivityManager_wifinetworksuggestion connectivitymanager

wifinetworksuggestion connectivitymanager

本文源自 WifiConfigManager NetworkSelector 和 WifiConnectivityManager

1. WifiConnectivityManager 管理连接过程

在其收到底层传递的扫描结果消息时,在 handleScanResults 中处理,里面调用了如下主要步骤:

  • 用到了 NetworkSelector 类对象进行处理,getCandidatesFromScan,以 ScanDetail 对象列表为输入获取到 WifiCandidates.Candidate 对象列表;
  • 用到了 NetworkSelector 类对象进行处理,SelectNetwork,以前面的 WifiCandidates.Candidate 列表为输入,经过处理获取到 WifiConfiguration 对象用来连接;
  • 继续调用同类方法 connectToNetwork,传入 WifiConfiguration 对象作为参数开启连接过程
1.1 WifiNetworkSelector 获取候选 WifiCandidates

WifiNetworkSelector 主要的两个方法如前面提到,这里分析第一个用于获取候选扫描结果的接口

getCandidatesFromScan

/* WifiNetworkSelector.java */
/**
 * Returns the list of Candidates from networks in range.
 *
 * @param scanDetails             List of ScanDetail for all the APs in range
 * @param bssidBlacklist          Blacklisted BSSIDs
 * @param wifiInfo                Currently connected network
 * @param connected               True if the device is connected
 * @param disconnected            True if the device is disconnected
 * @param untrustedNetworkAllowed True if untrusted networks are allowed for connection
 * @return list of valid Candidate(s)
 */
public List<WifiCandidates.Candidate> getCandidatesFromScan(
        List<ScanDetail> scanDetails, Set<String> bssidBlacklist, WifiInfo wifiInfo,
        boolean connected, boolean disconnected, boolean untrustedNetworkAllowed) {
    mFilteredNetworks.clear();
    mConnectableNetworks.clear();
    if (scanDetails.size() == 0) {
        localLog("Empty connectivity scan result");
        return null;
    }

    WifiConfiguration currentNetwork =
            mWifiConfigManager.getConfiguredNetwork(wifiInfo.getNetworkId());

    // Always get the current BSSID from WifiInfo in case that firmware initiated
    // roaming happened.
    String currentBssid = wifiInfo.getBSSID();

    // Update the scan detail cache at the start, even if we skip network selection
    updateScanDetailCache(scanDetails);

    // Shall we start network selection at all?
    if (!isNetworkSelectionNeeded(scanDetails, wifiInfo, connected, disconnected)) {
        return null;
    }

    // Update all configured networks before initiating network selection.
    updateConfiguredNetworks();

    // Update the registered network nominators.
    for (NetworkNominator registeredNominator : mNominators) {
        registeredNominator.update(scanDetails);
    }

    // Filter out unwanted networks.
    mFilteredNetworks = filterScanResults(scanDetails, bssidBlacklist,
            connected && wifiInfo.getScore() >= WIFI_POOR_SCORE, currentBssid);
    if (mFilteredNetworks.size() == 0) {
        return null;
    }

    WifiCandidates wifiCandidates = new WifiCandidates(mWifiScoreCard, mContext);
    if (currentNetwork != null) {
        wifiCandidates.setCurrent(currentNetwork.networkId, currentBssid);
        // We always want the current network to be a candidate so that it can participate.
        // It may also get re-added by a nominator, in which case this fallback
        // will be replaced.
        MacAddress bssid = MacAddress.fromString(currentBssid);
        WifiCandidates.Key key = new WifiCandidates.Key(
                ScanResultMatchInfo.fromWifiConfiguration(currentNetwork),
                bssid, currentNetwork.networkId);
        wifiCandidates.add(key, currentNetwork,
                NetworkNominator.NOMINATOR_ID_CURRENT,
                wifiInfo.getRssi(),
                wifiInfo.getFrequency(),
                calculateLastSelectionWeight(currentNetwork.networkId),
                WifiConfiguration.isMetered(currentNetwork, wifiInfo),
                isFromCarrierOrPrivilegedApp(currentNetwork),
                0 /* Mbps */);
    }
    for (NetworkNominator registeredNominator : mNominators) {
        localLog("About to run " + registeredNominator.getName() + " :");
        registeredNominator.nominateNetworks(
                new ArrayList<>(mFilteredNetworks), currentNetwork, currentBssid, connected,
                untrustedNetworkAllowed,
                (scanDetail, config) -> {
                    WifiCandidates.Key key = wifiCandidates.keyFromScanDetailAndConfig(
                            scanDetail, config);
                    if (key != null) {
                        boolean metered = isEverMetered(config, wifiInfo, scanDetail);
                        // TODO(b/151981920) Saved passpoint candidates are marked ephemeral
                        boolean added = wifiCandidates.add(key, config,
                                registeredNominator.getId(),
                                scanDetail.getScanResult().level,
                                scanDetail.getScanResult().frequency,
                                calculateLastSelectionWeight(config.networkId),
                                metered,
                                isFromCarrierOrPrivilegedApp(config),
                                predictThroughput(scanDetail));
                        if (added) {
                            mConnectableNetworks.add(Pair.create(scanDetail, config));
                            mWifiConfigManager.updateScanDetailForNetwork(
                                    config.networkId, scanDetail);
                            mWifiMetrics.setNominatorForNetwork(config.networkId,
                                    toProtoNominatorId(registeredNominator.getId()));
                        }
                    }
                });
    }
    if (mConnectableNetworks.size() != wifiCandidates.size()) {
        localLog("Connectable: " + mConnectableNetworks.size()
                + " Candidates: " + wifiCandidates.size());
    }
    return wifiCandidates.getCandidates();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 通过 isNetworkSelectionNeeded 判断是否需要进行网络选择
  • 通过 filterScanResults 获取 mFilteredNetworks
  • new 一个 WifiCandidates 对象, add 当前网络
  • 遍历所有已注册的 NetworkNominator 对象,执行其 nominateNetworks 接口

nominateNetworks 接口的参数信息和说明如下:

/**
 * Interface for WiFi Network Nominator
 *
 * A network nominator examines the scan results reports the
 * connectable candidates in its category for further consideration.
 */
public interface NetworkNominator

/**
 * Evaluate all the networks from the scan results.
 *
 * @param scanDetails             a list of scan details constructed from the scan results
 * @param currentNetwork          configuration of the current connected network
 *                                or null if disconnected
 * @param currentBssid            BSSID of the current connected network or null if
 *                                disconnected
 * @param connected               a flag to indicate if ClientModeImpl is in connected
 *                                state
 * @param untrustedNetworkAllowed a flag to indicate if untrusted networks like
 *                                ephemeral networks are allowed
 * @param onConnectableListener   callback to record all of the connectable networks
 */
void nominateNetworks(List<ScanDetail> scanDetails,
        WifiConfiguration currentNetwork, String currentBssid,
        boolean connected, boolean untrustedNetworkAllowed,
        OnConnectableListener onConnectableListener);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

重点是 scanDetails 和 onConnectableListener 两个对象,其中 OnConnectableListener 接口类如下:

/**
 * Callback for recording connectable candidates
 */
public interface OnConnectableListener {
    /**
     * Notes that an access point is an eligible connection candidate
     *
     * @param scanDetail describes the specific access point
     * @param config     is the WifiConfiguration for the network
     */
    void onConnectable(ScanDetail scanDetail, WifiConfiguration config);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在此处调用的接口 onConnectable 用了匿名写法,实际上为:

(scanDetail, config) -> {
    WifiCandidates.Key key = wifiCandidates.keyFromScanDetailAndConfig(
            scanDetail, config);
    if (key != null) {
        boolean metered = isEverMetered(config, wifiInfo, scanDetail);
        // TODO(b/151981920) Saved passpoint candidates are marked ephemeral
        boolean added = wifiCandidates.add(key, config,
                registeredNominator.getId(),
                scanDetail.getScanResult().level,
                scanDetail.getScanResult().frequency,
                calculateLastSelectionWeight(config.networkId),
                metered,
                isFromCarrierOrPrivilegedApp(config),
                predictThroughput(scanDetail));
        if (added) {
            mConnectableNetworks.add(Pair.create(scanDetail, config));
            mWifiConfigManager.updateScanDetailForNetwork(
                    config.networkId, scanDetail);
            mWifiMetrics.setNominatorForNetwork(config.networkId,
                    toProtoNominatorId(registeredNominator.getId()));
        }
    }
    })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

经过 nominateNetworks 处理最终得到了 WifiCandidates 对象 wifiCandidates,最终将其 Candidates 对象列表返回

这里需要分析 NetworkNominator 以及其 nominateNetworks 接口的处理过程才能明白 wifiCandidates 和 mConnectableNetworks 如何生成其列表的

2. NetworkNominator

是 NetworkSelector 的内部类,其内部对象记录在 mNominators 中,通过 WifiNetworkSelector 的 registerNetworkNominator 方法注册

2.1 详解

在 WifiInjector 的构造过程中注册了三个 Nominator 对象:

SavedNetworkNominator:用于保存的网络
NetworkSuggestionNominator:用于提供最高可用性候选建议
ScoredNetworkNominator:用于通过评分机制选择网络连接,用到了 NetworkScoreManager 用于管理网络评分

SavedNetworkNominator::nominateNetworks 采用两个步骤 分别通过 findMatchedSavedNetworks 和 findMatchedPasspointNetworks 对 用户配置保存的passpoint 网络信息 进行查询,提取信息,生成对应的 WifiConfiguration 对象列表

其他两个 NetworkNonimator 类似的处理方式~

这里我会自己做解析

3. WifiConfigManager 管理的配置出处

重点处理扫描结果的入口是 handleScanResults ,其中调用了 NetworkSelector 的方法进行处理,也会调用 WifiConfigManager 的 addOrUpdateNetwork 更新已有的配置

WifiConnectivityManager 的 connectToNetwork 方法在其 handleScanResults 过程中被调用,进而调用 ClientModeImpl 的 startConnectToNetwork 接口进入实际的连接过程

当 Candidate 为空的时候 handleScanResult 会调用 OpenNetworkNotifier 的 handleScanResults 将对应的扫描结果(可用未保存)进行广播通知,这里面会调用 recommendNetwork 首先进行过滤,查询到对应的 ScanResult 对象 recommendation,调用 postInitialNotification 处理,recommend 的方式就是选择 rssi 最高的对象

处理方法是调用 postNotification,传入通过 NotificationBuilder 的 createConnectToAvailableNetworkNotification 方法创建的 Notification 对象

3.1 创建新的 WifiConfiguration 和 WifiCandidates
  1. ScanResultUtil::createNetworkFromScanResult 接口创建

  2. ScoreTracker::getCandidateConfiguration 接口根据 mBestCandidateType 的判断,是 ScoreTracker.EXTERNAL_SCORED_UNTRUSTED_NETWORK,在其 switch 分支中处理时调用了上述接口创建 WifiConfiguration 对象;

  3. ScoreTracker::getCandidateConfiguration 中调用了 WifiConfigManager::addOrUpdateNetwork 将新创建的配置保存起来;

  4. ScoreTracker::getCandidateConfiguration 会重新在 WifiConfigManager 中通过 getConfiguredNetwork 获取配置并且对其调用 onConnectableListener 的 onConnectable 方法;

  5. 上述过程发生在 ScoredNetworkNominator::nominateNetworks 中,在执行 2,3,4 步骤之前会遍历 ScanDetail 列表,通过 ScoreTracker 分别记录保存的以及不信任的(未保存的)结果,设置如 mBestCandidateType 等信息用于 getCandidateConfiguration 处理;

  6. 再次回溯,对应的 nominateNetworks 方法在 WifiNetworkSelector::getCandidatesFromScan 中,对三种 NetworkNominator 进行遍历,分别调用其 nominateNetworks 方法;

  7. 同样从对应的 onConnectable 方法看到,wifiCandidates 和 mConnectableNetworks 的 add 方法被调用,生成了对应的 WifiCandidates 对象中的 Candidates 列表;

  8. 将上述列表返回到 handleScanResults 继续处理

4. WifiNetworkSelector 选定连接的网络

WifiNetworkSelector 主要的两个方法如前面提到,这里分析第二个用于获取候选扫描结果的接口

SelectNetwork

SelectNetwork

  • 使用传进来的 Candidate 列表重新创建新的 WifiCandidates 对象

  • 生成根据 configuration id 组织的 groupedCandidates;

  • 对每个 group 成员使用 activeScorer 进行 scoreCandidates 处理,生成对应的 ScoredCandidate 对象 choice;

  • 调用 WifiConfigManager 的 setNetworkCandidateScanResult 进行 NetworkSelectionStatus更新;

  • 接下来遍历所有的 CandidateScorer 采用其 scoreCandidates 方法,对 WifiCandidates 进行计算获得对应的 ScoredCandidate 对象 choice;

  • 如果 CandidateScorer 是当前的 activeScorer 则说明是当前最佳选择,记录其 networkId 信息到 selectedNetworkId;

  • 根据 selectedNetworkId 记录信息从 WifiConfigManager 通过 getConfiguredNetwork 获取到 WifiConfiguration 信息返回;

到此网络的选择完成,接下来通过 connectToNetwork 进行连接

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/295504
推荐阅读
相关标签
  

闽ICP备14008679号