WiFi选网机制

alps/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
handleScanResults			//wifi扫描完会回调各个onResults
         //这里和黑名单机制相关
         Set<String> bssidBlocklist = mBssidBlocklistMonitor.updateAndGetBssidBlocklist();
         if (mStateMachine.isSupplicantTransientState()) {	//检查supplicant当前状态
             localLog(listenerName
                     + " onResults: No network selection because supplicantTransientState is "
                     + mStateMachine.isSupplicantTransientState());
             return false;
         }

alps/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeImpl.java
      public boolean isSupplicantTransientState() {
          SupplicantState supplicantState = mWifiInfo.getSupplicantState();
          if (mVerboseLoggingEnabled) {
              Log.d(TAG, "Supplicant is under steady state: " + supplicantState);
          }		//可以看到,当supplicant处于以下状态时,选网会直接终止
          if (supplicantState == SupplicantState.ASSOCIATING
                  || supplicantState == SupplicantState.AUTHENTICATING
                  || supplicantState == SupplicantState.FOUR_WAY_HANDSHAKE
                  || supplicantState == SupplicantState.GROUP_HANDSHAKE
                  || getCurrentState() == mObtainingIpState) {
              return true;

alps/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
        localLog(listenerName + " onResults: start network selection");
        List<WifiCandidates.Candidate> candidates = 
mNetworkSelector.getCandidatesFromScan(
                 scanDetails, bssidBlocklist, mWifiInfo, mStateMachine.isConnected(),
                 mStateMachine.isDisconnected(), mUntrustedConnectionAllowed);

alps/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNetworkSelector.java
getCandidatesFromScan	
//从所有nominator中挑选出符合要求的network
//nominator也是一个接口,fwk实现并注册了三个
    for (NetworkNominator registeredNominator : mNominators) {
        registeredNominator.nominateNetworks
.
alps/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiInjector.java
//可以看到wifiinjector中注册了三个nominator
mWifiNetworkSelector.registerNetworkNominator(mSavedNetworkNominator); mWifiNetworkSelector.registerNetworkNominator(mNetworkSuggestionNominator); mWifiNetworkSelector.registerNetworkNominator(mScoredNetworkNominator); 
alps/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
if (mDeviceMobilityState == WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT
                 && mContext.getResources().getBoolean(
                         R.bool.config_wifiHighMovementNetworkSelectionOptimizationEnabled)) {             candidates = filterCandidatesHighMovement(candidates, listenerName, isFullScan);
}
 	//开始对以上挑选出的candidates进行评分选最优
         WifiConfiguration candidate = mNetworkSelector.selectNetwork(candidates);
         mLastNetworkSelectionTimeStamp = mClock.getElapsedSinceBootMillis();
         mWifiLastResortWatchdog.updateAvailableNetworks(
                 mNetworkSelector.getConnectableScanDetails());
         mWifiMetrics.countScanResults(scanDetails);	//埋点
         if (candidate != null) {
             localLog(listenerName + ":  WNS candidate-" + candidate.SSID);
             connectToNetwork(candidate);	//连接至评分最高的网络
             return true;

alps/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNetworkSelector.jc WifiConfiguration selectNetwork(List<WifiCandidates.Candidate> candidates) {
         if (candidates == null || candidates.size() == 0) {
             return null;
         }
         WifiCandidates wifiCandidates = new WifiCandidates(mWifiScoreCard, mContext, candidates);
//这里获取到的就是默认的ThroughputScorer
         final WifiCandidates.CandidateScorer activeScorer = getActiveCandidateScorer();
         Collection<Collection<WifiCandidates.Candidate>> groupedCandidates =
                 wifiCandidates.getGroupedCandidates();
         for (Collection<WifiCandidates.Candidate> group : groupedCandidates) {
             WifiCandidates.ScoredCandidate choice = activeScorer.scoreCandidates(group);
             if (choice == null) continue;
             ScanDetail scanDetail = getScanDetailForCandidateKey(choice.candidateKey);
             if (scanDetail == null) continue;
             mWifiConfigManager.setNetworkCandidateScanResult(choice.candidateKey.networkId, scanDetail.getScanResult(), 0);		//分数先清零?
//疑点:分数难道一直在更新?or用户点击或者网络情况变更时,分数也会更新?
//更新到配置文件?下次打开wifi会读取。
         }
 
         for (Collection<WifiCandidates.Candidate> group : groupedCandidates) {
             for (WifiCandidates.Candidate candidate : group.stream()
                     .sorted((a, b) -> (b.getScanRssi() - a.getScanRssi()))
 //这个根据rssi进行排序后面看起来只有埋点有用到,先不追究
                     .collect(Collectors.toList())) {
                 localLog(candidate.toString());
             }
         }
alps/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNetworkSelector.java
     private WifiCandidates.CandidateScorer getActiveCandidateScorer() {
         WifiCandidates.CandidateScorer ans = 
mCandidateScorers.get(PRESET_CANDIDATE_SCORER_NAME);
alps/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNetworkSelector.java
    public static final String PRESET_CANDIDATE_SCORER_NAME = 
"ThroughputScorer";

alps/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNetworkSelector.java
         boolean legacyOverrideWanted = true;
         for (WifiCandidates.CandidateScorer candidateScorer : 
mCandidateScorers.values()) {		
//WifiCandidates.CandidateScorer是一个接口,fwk层总共实现了四个Scorer;
//这里是把四个candidateScorer全部遍历所有的network并返回最高分的那个
//但其实只有ThroughputScorer返回的才有效,不明白这个设计意图
             WifiCandidates.ScoredCandidate choice;
             try {
                 choice = wifiCandidates.choose(candidateScorer);
             } catch (RuntimeException e) {
                 Log.wtf(TAG, "Exception running a CandidateScorer", e);
                 continue;
             }
             int networkId = choice.candidateKey == null
                     ? WifiConfiguration.INVALID_NETWORK_ID
                     : choice.candidateKey.networkId;
             String chooses = " would choose ";
             if (candidateScorer == activeScorer) {	
//这里的activeScorer就是ThroughputScorer,可以看到后续用到的只有selectedNetworkId
                 chooses = " chooses ";
                 legacyOverrideWanted = choice.userConnectChoiceOverride;
                 selectedNetworkId = networkId;
                 updateChosenPasspointNetwork(choice);
             }
             String id = candidateScorer.getIdentifier();
             int expid = experimentIdFromIdentifier(id);
             localLog(id + chooses + networkId
                     + " score " + choice.value + "+/-" + choice.err
                     + " expid " + expid);
             experimentNetworkSelections.put(expid, networkId);
         }
alps/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiCandidates.java
     public @NonNull ScoredCandidate choose(@NonNull CandidateScorer 
candidateScorer) {
         Preconditions.checkNotNull(candidateScorer);
         Collection<Candidate> candidates = new ArrayList<>(mCandidates.values());
//调用所有注册了的WifiCandidates.CandidateScorer的scoreCandidates接口
         ScoredCandidate choice = candidateScorer.scoreCandidates(candidates);
         return choice == null ? ScoredCandidate.NONE : choice;
     }
alps/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ThroughputScorer.java
     public 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;
             }
         }
         return choice;
     }

    private ScoredCandidate scoreCandidate(Candidate candidate) {
// ThroughputScorer里具体的评分细节,可以看到于信号强度、是否保存过,
//加密方式等等都有关系,看不是很懂
        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 anyway
             unmeteredAward = 0; // Ignore metered for untrusted networks
             if (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);
         }
 
         double tieBreaker = candidate.getScanRssi() / 1000.0;
         return new ScoredCandidate(score + tieBreaker, 10,
                 USE_USER_CONNECT_CHOICE, candidate);
     }

大体流程不算复杂,更多是细节性的东西。
小结:
1、	handleScanResults是扫描完成后开始选网的入口;
2、	根据黑名单机制过滤掉部分扫描结果,并判断当前supplicant的状态,空闲则开始选网;
3、	根据在WifiInjector中注册的三个nominator,遍历scandetails并依次调用niminatorNetwork方法,挑选出符合要求的network返回candidates;
4、	根据在WifiInjector中注册的四个scorer,遍历candidates调用choose方法,选取分数最高的一个network并返回(只有ThroughputScorer生效)
5、	connectToNetwork回连至该网络。

add:nominator和scorer中涉及到很多具体的评分项,比如rssi,加密方式,吞吐量等等,都有各自的权重和分数;这里只贴出了部分代码,有需要请自行查看。

另wifi配置最后会保存在WifiConfigStore.xml中,/data/misc/....路径下,启动
WifiServiceImpl时会在onBootPhase中读取并解析xml,用于下一次选网的参考,具体还有待分析。

注意:对于Android系统。上层的自动选网是这样。但是底层各家厂商还会做进一步处理,比如对于上层下发以ssid的连接方式来连接ESS网络,底层还会进一步进行选网(比如打分机制)然后在连接。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值