文章目录

  • 写在前面
  • CompatibilityScorer
  • ScoreCardBasedScorer
  • BubbleFunScorer
  • ThroughputScorer

写在前面

Android R 有四个 WifiCandidates.CandidateScorer,分别是

  • CompatibilityScorer
  • ScoreCardBasedScorer
  • BubbleFunScorer
  • ThroughputScorer

它们在 WifiInjector 的构造函数中被初始化,并通过 mWifiNetworkSelector.registerCandidateScorer 方法被添加到 mWifiNetworkSelector 的 mCandidateScorers 变量中

private final Map<String, WifiCandidates.CandidateScorer> mCandidateScorers = new ArrayMap<>();

在 WifiConnectivityManager 的 handleScanResults 方法中, mWifiNetworkSelector 调用 selectNetwork 方法进行网络选择,其中有这四个评分器的评分环节

// Run all the CandidateScorers
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;}
}

wifiCandidates.choose(candidateScorer) 做的事情就是

ScoredCandidate choice = candidateScorer.scoreCandidates(candidates);
return choice == null ? ScoredCandidate.NONE : choice;

所以我们主要看这个四个评分器对 scoreCandidates 方法的实现

CompatibilityScorer

/*** A candidate scorer that attempts to match the previous behavior.*/
final class CompatibilityScorer implements WifiCandidates.CandidateScorer {//遍历 candidates 进行 scoreCandidate 操作,返回评分最高的一个@Overridepublic ScoredCandidate scoreCandidates(@NonNull Collection<Candidate> candidates) {ScoredCandidate choice = ScoredCandidate.NONE;for (Candidate candidate : candidates) {ScoredCandidate scoredCandidate = scoreCandidate(candidate);if (scoredCandidate.value > choice.value) {choice = scoredCandidate;}}// Here we just return the highest scored candidate; we could// compute a new score, if desired.return choice;}/*** Calculates an individual candidate's score.*/
private ScoredCandidate scoreCandidate(Candidate candidate) {int rssiSaturationThreshold = mScoringParams.getGoodRssi(candidate.getFrequency());int rssi = Math.min(candidate.getScanRssi(), rssiSaturationThreshold);int score = (rssi + RSSI_SCORE_OFFSET) * RSSI_SCORE_SLOPE_IS_4;if (ScanResult.is6GHz(candidate.getFrequency())) {score += BAND_6GHZ_AWARD_IS_40;} else if (ScanResult.is5GHz(candidate.getFrequency())) {score += BAND_5GHZ_AWARD_IS_40;}score += (int) (candidate.getLastSelectionWeight() * LAST_SELECTION_AWARD_IS_480);if (candidate.isCurrentNetwork()) {// Add both traditional awards, as would be be case with firmware roamingscore += CURRENT_NETWORK_BOOST_IS_16 + SAME_BSSID_AWARD_IS_24;}if (!candidate.isOpenNetwork()) {score += SECURITY_AWARD_IS_80;}// To simulate the old strict priority rule, subtract a penalty based on// which nominator added the candidate.score -= 1000 * candidate.getNominatorId();// The old method breaks ties on the basis of RSSI, which we can// emulate easily since our score does not need to be an integer.double tieBreaker = candidate.getScanRssi() / 1000.0;return new ScoredCandidate(score + tieBreaker, 10,USE_USER_CONNECT_CHOICE, candidate);
}
}

由此可见 CompatibilityScorer 的几个加分项
1.rssi值
2.5G或者6G频段的网络
3.是否是上次选择的网络
4.是否是当前网络
5.是否是开放网络

ScoreCardBasedScorer

/*** A candidate scorer that uses the scorecard to influence the choice.*/
final class ScoreCardBasedScorer implements WifiCandidates.CandidateScorer/*** Calculates an individual candidate's score.*/
private ScoredCandidate scoreCandidate(Candidate candidate) {int rssiSaturationThreshold = mScoringParams.getGoodRssi(candidate.getFrequency());int rssi = Math.min(candidate.getScanRssi(), rssiSaturationThreshold);int cutoff = estimatedCutoff(candidate);int score = (rssi - cutoff) * RSSI_SCORE_SLOPE_IS_4;if (ScanResult.is6GHz(candidate.getFrequency())) {score += BAND_6GHZ_AWARD_IS_40;} else if (ScanResult.is5GHz(candidate.getFrequency())) {score += BAND_5GHZ_AWARD_IS_40;}score += (int) (candidate.getLastSelectionWeight() * LAST_SELECTION_AWARD_IS_480);if (candidate.isCurrentNetwork()) {score += CURRENT_NETWORK_BOOST_IS_16 + SAME_BSSID_AWARD_IS_24;}if (!candidate.isOpenNetwork()) {score += SECURITY_AWARD_IS_80;}// To simulate the old strict priority rule, subtract a penalty based on// which nominator added the candidate.score -= 1000 * candidate.getNominatorId();return new ScoredCandidate(score, 10,USE_USER_CONNECT_CHOICE, candidate);
}private int estimatedCutoff(Candidate candidate) {int cutoff = -RSSI_SCORE_OFFSET;int lowest = cutoff - RSSI_RAIL;int highest = cutoff + RSSI_RAIL;WifiScoreCardProto.Signal signal = candidate.getEventStatistics(Event.SIGNAL_POLL);if (signal == null) return cutoff;if (!signal.hasRssi()) return cutoff;if (signal.getRssi().getCount() > MIN_POLLS_FOR_SIGNIFICANCE) {double mean = signal.getRssi().getSum() / signal.getRssi().getCount();double mean_square = signal.getRssi().getSumOfSquares() / signal.getRssi().getCount();double variance = mean_square - mean * mean;double sigma = Math.sqrt(variance);double value = mean - 2.0 * sigma;cutoff = (int) Math.min(Math.max(value, lowest), highest);}return cutoff;
}

ScoreCardBasedScorer 的加分项和上面的评分器一样,但是多了一个 estimatedCutoff 步骤

BubbleFunScorer

/*** A CandidateScorer that weights the RSSIs for more compactly-shaped* regions of selection around access points.*/
final class BubbleFunScorer implements WifiCandidates.CandidateScorer/*** Calculates an individual candidate's score.** Ideally, this is a pure function of the candidate, and side-effect free.*/
private ScoredCandidate scoreCandidate(Candidate candidate) {final int rssi = candidate.getScanRssi();final int rssiEntryThreshold = mScoringParams.getEntryRssi(candidate.getFrequency());double score = shapeFunction(rssi) - shapeFunction(rssiEntryThreshold);// If we are below the entry threshold, make the score more negativeif (score < 0.0) score *= 2.0;// The gain is approximately the derivative of shapeFunction at the given rssi// This is used to estimate the errordouble gain = shapeFunction(rssi + 0.5)- shapeFunction(rssi - 0.5);// Prefer 5GHz/6GHz when all are strong, but at the fringes, 2.4 might be better// Typically the entry rssi is lower for the 2.4 band, which provides the fringe boostif (ScanResult.is24GHz(candidate.getFrequency())) {score *= LOW_BAND_FACTOR;gain *= LOW_BAND_FACTOR;}// A recently selected network gets a large boostscore += candidate.getLastSelectionWeight() * LAST_SELECTION_BOOST;// Hysteresis to prefer staying on the current network.if (candidate.isCurrentNetwork()) {score += CURRENT_NETWORK_BOOST;}if (!candidate.isOpenNetwork()) {score += SECURITY_AWARD;}return new ScoredCandidate(score, TYPICAL_SCAN_RSSI_STD * gain,USE_USER_CONNECT_CHOICE, candidate);
}/*** Reshapes raw RSSI into a value that varies more usefully for scoring purposes.** The most important aspect of this function is that it is monotone (has* positive slope). The offset and scale are not important, because the* calculation above uses differences that cancel out the offset, and* a rescaling here effects all the candidates' scores in the same way.* However, we choose to scale things for an overall range of about 100 for* useful values of RSSI.*/
private static double unscaledShapeFunction(double rssi) {return -Math.exp(-rssi * BELS_PER_DECIBEL);
}
private static final double BELS_PER_DECIBEL = 0.1;private static final double RESCALE_FACTOR = 100.0 / (unscaledShapeFunction(0.0) - unscaledShapeFunction(-85.0));
private static double shapeFunction(double rssi) {return unscaledShapeFunction(rssi) * RESCALE_FACTOR;
}

ThroughputScorer

/*** A candidate scorer that combines RSSI base score and network throughput score.*/
final class ThroughputScorer implements WifiCandidates.CandidateScorer/*** Calculates an individual candidate's score.*/
private ScoredCandidate scoreCandidate(Candidate candidate) {int rssiSaturationThreshold = mScoringParams.getSufficientRssi(candidate.getFrequency());int rssi = Math.min(candidate.getScanRssi(), rssiSaturationThreshold);int rssiBaseScore = (rssi + RSSI_SCORE_OFFSET) * RSSI_SCORE_SLOPE_IS_4;int throughputBonusScore = calculateThroughputBonusScore(candidate);int rssiAndThroughputScore = rssiBaseScore + throughputBonusScore;boolean unExpectedNoInternet = candidate.hasNoInternetAccess()&& !candidate.isNoInternetAccessExpected();int currentNetworkBonusMin = mScoringParams.getCurrentNetworkBonusMin();int currentNetworkBonus = Math.max(currentNetworkBonusMin, rssiAndThroughputScore* mScoringParams.getCurrentNetworkBonusPercent() / 100);int currentNetworkBoost = (candidate.isCurrentNetwork() && !unExpectedNoInternet)? currentNetworkBonus : 0;int securityAward = candidate.isOpenNetwork()? 0: mScoringParams.getSecureNetworkBonus();int unmeteredAward = candidate.isMetered()? 0: mScoringParams.getUnmeteredNetworkBonus();int savedNetworkAward = candidate.isEphemeral() ? 0 : mScoringParams.getSavedNetworkBonus();int trustedAward = TRUSTED_AWARD;if (!candidate.isTrusted()) {savedNetworkAward = 0; // Saved networks are not untrusted, but clear anywayunmeteredAward = 0; // Ignore metered for untrusted networksif (candidate.isCarrierOrPrivileged()) {trustedAward = HALF_TRUSTED_AWARD;} else if (candidate.getNominatorId() == NOMINATOR_ID_SCORED) {Log.e(TAG, "ScoredNetworkNominator is not carrier or privileged!");trustedAward = 0;} else {trustedAward = 0;}}int score = rssiBaseScore + throughputBonusScore+ currentNetworkBoost + securityAward + unmeteredAward + savedNetworkAward+ trustedAward;if (candidate.getLastSelectionWeight() > 0.0) {// Put a recently-selected network in a tier above everything else,// but include rssi and throughput contributions for BSSID selection.score = TOP_TIER_BASE_SCORE + rssiBaseScore + throughputBonusScore;}if (DBG) {Log.d(TAG, " rssiScore: " + rssiBaseScore+ " throughputScore: " + throughputBonusScore+ " currentNetworkBoost: " + currentNetworkBoost+ " securityAward: " + securityAward+ " unmeteredAward: " + unmeteredAward+ " savedNetworkAward: " + savedNetworkAward+ " trustedAward: " + trustedAward+ " final score: " + score);}// The old method breaks ties on the basis of RSSI, which we can// emulate easily since our score does not need to be an integer.double tieBreaker = candidate.getScanRssi() / 1000.0;return new ScoredCandidate(score + tieBreaker, 10,USE_USER_CONNECT_CHOICE, candidate);
}private int calculateThroughputBonusScore(Candidate candidate) {int throughputScoreRaw = candidate.getPredictedThroughputMbps()* mScoringParams.getThroughputBonusNumerator()/ mScoringParams.getThroughputBonusDenominator();return Math.min(throughputScoreRaw, mScoringParams.getThroughputBonusLimit());
}

CandidateScorer相关推荐

  1. 【安卓Framework学习】Wifi框架学习之热点评分机制

    系列文章目录 [安卓Framework学习]Wifi框架学习之核心类 [安卓Framework学习]Wifi框架学习之wifi状态机 [安卓Framework学习]Wifi框架学习之连接与断开流程 [ ...

  2. WifiNetworkSelector 走读

    WifiNetworkSelector代码走读 文章目录 WifiNetworkSelector代码走读 写在前面 解释 NetworkNominator 一些方法 hasSufficientLink ...

最新文章

  1. ORACLE 日期比较
  2. android客户端和服务器实现传图片和文件
  3. TechEmpower Web 框架性能第19轮测试结果正式发布,ASP.NET Core在主流框架中拔得头筹...
  4. P3085 [USACO13OPEN]Yin and Yang G 点分治
  5. python通讯录管理系统 tk_通讯录管理系统课程设计
  6. netty在项目中实际使用_聚合氯化铝在实际使用中的用法和用量
  7. 大文件上传NeatUpload
  8. 什么都不懂的学java难不难_零基础转行学java到底难不难
  9. Hibernate 注解方式
  10. js页面跳转 和 js打开新窗口 方法 【转】
  11. iertutil.dll文件缺失/ 修复方法
  12. word中如何设置页码从任意页开始
  13. might和could的区别用法_KET语法:情态动词Can,Could,May和Might
  14. 程序员面试中一面、二面、三面有什么区别?
  15. 爬取qq音乐的评论并生成词云——以《听妈妈的话》为例
  16. 学人工智能必备的数学课,再也不怕学AI了
  17. C语言简单五子棋实现
  18. 图像处理之高斯金字塔
  19. h5获取当前浏览器ip和城市名称
  20. python绘制太阳系模型_用python做一个漂亮的太阳系运动模拟

热门文章

  1. 仿 IOS 打造一个全局通用的对话框
  2. Biopython操作DNA,RNA和蛋白质序列
  3. 网约车收费器设计(lunwen+任务书+翻译及原文+答辩PPT+程序+原理图)
  4. 2020第十七届华为杯数模C题——P300脑电信号数据预处理算法
  5. C语言第十二课:编写扫雷游戏(综合练习2)
  6. 利用计算机实施盗窃罪300万,盗窃网络虚拟财产的新定性及刑法规制.pdf
  7. Linux 如何在文件中查找指定内容
  8. 关于ORA-03113:end-of-file on communication channel
  9. 第五章-语法分析之抽象语法树的建立
  10. 扰人的异常:net.sf.json.JSONException: Object is null