赞
踩
本文源自 WifiConfigManager NetworkSelector 和 WifiConnectivityManager
在其收到底层传递的扫描结果消息时,在 handleScanResults 中处理,里面调用了如下主要步骤:
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(); }
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);
重点是 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);
}
在此处调用的接口 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())); } } })
经过 nominateNetworks 处理最终得到了 WifiCandidates 对象 wifiCandidates,最终将其 Candidates 对象列表返回
这里需要分析 NetworkNominator 以及其 nominateNetworks 接口的处理过程才能明白 wifiCandidates 和 mConnectableNetworks 如何生成其列表的
是 NetworkSelector 的内部类,其内部对象记录在 mNominators 中,通过 WifiNetworkSelector 的 registerNetworkNominator 方法注册
在 WifiInjector 的构造过程中注册了三个 Nominator 对象:
SavedNetworkNominator:用于保存的网络
NetworkSuggestionNominator:用于提供最高可用性候选建议
ScoredNetworkNominator:用于通过评分机制选择网络连接,用到了 NetworkScoreManager 用于管理网络评分
SavedNetworkNominator::nominateNetworks 采用两个步骤 分别通过 findMatchedSavedNetworks 和 findMatchedPasspointNetworks 对 用户配置保存的 和 passpoint 网络信息 进行查询,提取信息,生成对应的 WifiConfiguration 对象列表
其他两个 NetworkNonimator 类似的处理方式~
这里我会自己做解析
重点处理扫描结果的入口是 handleScanResults ,其中调用了 NetworkSelector 的方法进行处理,也会调用 WifiConfigManager 的 addOrUpdateNetwork 更新已有的配置
WifiConnectivityManager 的 connectToNetwork 方法在其 handleScanResults 过程中被调用,进而调用 ClientModeImpl 的 startConnectToNetwork 接口进入实际的连接过程
当 Candidate 为空的时候 handleScanResult 会调用 OpenNetworkNotifier 的 handleScanResults 将对应的扫描结果(可用未保存)进行广播通知,这里面会调用 recommendNetwork 首先进行过滤,查询到对应的 ScanResult 对象 recommendation,调用 postInitialNotification 处理,recommend 的方式就是选择 rssi 最高的对象
处理方法是调用 postNotification,传入通过 NotificationBuilder 的 createConnectToAvailableNetworkNotification 方法创建的 Notification 对象
ScanResultUtil::createNetworkFromScanResult 接口创建
ScoreTracker::getCandidateConfiguration 接口根据 mBestCandidateType 的判断,是 ScoreTracker.EXTERNAL_SCORED_UNTRUSTED_NETWORK,在其 switch 分支中处理时调用了上述接口创建 WifiConfiguration 对象;
ScoreTracker::getCandidateConfiguration 中调用了 WifiConfigManager::addOrUpdateNetwork 将新创建的配置保存起来;
ScoreTracker::getCandidateConfiguration 会重新在 WifiConfigManager 中通过 getConfiguredNetwork 获取配置并且对其调用 onConnectableListener 的 onConnectable 方法;
上述过程发生在 ScoredNetworkNominator::nominateNetworks 中,在执行 2,3,4 步骤之前会遍历 ScanDetail 列表,通过 ScoreTracker 分别记录保存的以及不信任的(未保存的)结果,设置如 mBestCandidateType 等信息用于 getCandidateConfiguration 处理;
再次回溯,对应的 nominateNetworks 方法在 WifiNetworkSelector::getCandidatesFromScan 中,对三种 NetworkNominator 进行遍历,分别调用其 nominateNetworks 方法;
同样从对应的 onConnectable 方法看到,wifiCandidates 和 mConnectableNetworks 的 add 方法被调用,生成了对应的 WifiCandidates 对象中的 Candidates 列表;
将上述列表返回到 handleScanResults 继续处理
WifiNetworkSelector 主要的两个方法如前面提到,这里分析第二个用于获取候选扫描结果的接口
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 进行连接
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。