评分机制简介
当扫描到多个wifi网络时,系统又是如何确定到底连接哪一个AP呢,在Android WiFi Framework中,存在一套评分机制,它会对每一个扫描到的AP进行打分,最后选择一个最优的进行连接。
以WifiConnectivityManager
的handleScanResults()
方法为入口。当收到扫描结果后,现通过WifiNetworkSelector
的getCandidatesFromScan()
方法生成所有待评分的candidates,随后再通过WifiNetworkSelector
的selectNetwork()
方法对每个candidate进行评分并选择最优的一个candidate。
// packages/modules/Wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
private void handleScanResults(@NonNull List<ScanDetail> scanDetails,
@NonNull String listenerName,
boolean isFullScan,
@NonNull HandleScanResultsListener handleScanResultsListener) {
// ... ...
List<WifiCandidates.Candidate> candidates = mNetworkSelector.getCandidatesFromScan(
scanDetails, bssidBlocklist, cmmStates, mUntrustedConnectionAllowed,
mOemPaidConnectionAllowed, mOemPrivateConnectionAllowed,
mRestrictedConnectionAllowedUids, isMultiInternetConnectionRequested());
mLatestCandidates = candidates;
mLatestCandidatesTimestampMs = mClock.getElapsedSinceBootMillis();
// ... ...
handleCandidatesFromScanResultsForPrimaryCmmUsingMbbIfAvailable(
listenerName, candidates, handleScanResultsListener);
}
private void handleCandidatesFromScanResultsForPrimaryCmmUsingMbbIfAvailable(
@NonNull String listenerName, @NonNull List<WifiCandidates.Candidate> candidates,
@NonNull HandleScanResultsListener handleScanResultsListener) {
WifiConfiguration candidate = mNetworkSelector.selectNetwork(candidates);
if (candidate != null) {
localLog(listenerName + ": WNS candidate-" + candidate.SSID);
connectToNetworkForPrimaryCmmUsingMbbIfAvailable(candidate);
handleScanResultsWithCandidate(handleScanResultsListener);
} else {
localLog(listenerName + ": No candidate");
handleScanResultsWithNoCandidate(handleScanResultsListener);
}
}
selectNetwork()
的步骤如下:
-
获取评分器CandidateScorer
final WifiCandidates.CandidateScorer activeScorer = getActiveCandidateScorer();
目前系统默认的评分器是
ThroughputScorer
public static final String PRESET_CANDIDATE_SCORER_NAME = "ThroughputScorer"; private WifiCandidates.CandidateScorer getActiveCandidateScorer() { WifiCandidates.CandidateScorer ans = mCandidateScorers.get(PRESET_CANDIDATE_SCORER_NAME);
-
运行所有评分器
其实对最后结果产生影响的只有
ThroughputScorer
for (WifiCandidates.CandidateScorer candidateScorer : mCandidateScorers.values()) { WifiCandidates.ScoredCandidate choice; try { choice = wifiCandidates.choose(candidateScorer); } catch (RuntimeException e) { Log.wtf(TAG, "Exception running a CandidateScorer", e); continue; }
总结
Android的WiFi选择器功能是通过WifiNetworkSelector
实现的。
WifiNetworkSelector
通过通过打分算法对每一个scan result进行打分,最终选择分数最高的进行连接。
目前支持的评分器有:
-
BubbleFunScorer
只关心信号强度rssi(received signal strength indicator)
-
CompatibilityScorer
-
ScoreCardBasedScorer
-
ThroughputScorer
WifiNetworkSelector
的selectNetwork()
方法会运行所有的评分器,但是有效(active)的评分器只有ThroughputScorer
。