码迷,mamicode.com
首页 > 移动开发 > 详细

Android N selectQualifiedNetwork分析

时间:2021-01-29 11:41:44      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:lang   reconnect   现在   RKE   call   ast   conf   sso   with   

前言:

       参考:Android N wifi auto connect流程分析

后续

       Android 8.0/9.0 wifi 自动连接评分机制

分析

       前面说了,handleScanResults会去调QualifiedNetworkSelector.selectQualifiedNetwork去筛选目标ssid,selectQualifiedNetwork是网络的选择算法,我们分析下它的原理
 

  • 1、判断是否需要needQualifiedNetworkSelection,如果返回false,代表
    • scanDetails=null or isLinkDebouncing
    • or skipQualifiedNetworkSelectionForAutoConnect(auto connect disabled)
    • or connecting/disconnecting or WifiConfiguration=null
    • or not allowed to switch network
    • or short time pass since last select
  • 2、迭代所有扫描结果,找到得分最高的最佳候选人
    • ssid=null, add to noValidSsid, ignore
    • isBlackListed() ignore, addToBlacklist(bssid) will add to blackList
    • too weak signal strength add to lowSignalScan, ignore 2.4G level<-85 5G level<-85
    • 未保存的网络(添加到notSavedScan)或保存但短暂,忽略
    • 计算每个关联网络不是短暂的扫描结果的得分。由于一个扫描结果可以关联多个网络,我们需要计算所有,并使用最高的一个作为扫描结果的分数。
  • 3、现在我们需要遍历整个用户偏好来选择一个用户最喜欢的
     
// Start a periodic scan when screen is on
public WifiConfiguration selectQualifiedNetwork(boolean forceSelectNetwork ,
    boolean isUntrustedConnectionsAllowed, List<ScanDetail>  scanDetails,
    boolean isLinkDebouncing, boolean isConnected, boolean isDisconnected,
    boolean isSupplicantTransient) {
          ....
    /*1.判断是否需要needQualifiedNetworkSelection,如果返回false,代表
    * -scanDetails=null or isLinkDebouncing
    * -or skipQualifiedNetworkSelectionForAutoConnect(auto connect disabled)
    * -or connecting/disconnecting or WifiConfiguration=null
    * -or not allowed to switch network
    * -or short time pass since last select
    */ 
    if (!forceSelectNetwork && !needQualifiedNetworkSelection(isLinkDebouncing, isConnected,  
            isDisconnected, isSupplicantTransient)) {  
        localLog("Quit qualified Network Selection since it is not forced and current network"  
                + " is qualified already");  
        mFilteredScanDetails = filteredScanDetails;  
        return null;  
    }  

 	...
 	
    updateSavedNetworkSelectionStatus();  
    updateBssidBlacklist();  

    StringBuffer lowSignalScan = new StringBuffer();  
    StringBuffer notSavedScan = new StringBuffer();  
    StringBuffer noValidSsid = new StringBuffer();  
    StringBuffer scoreHistory =  new StringBuffer();  
    ArrayList<NetworkKey> unscoredNetworks = new ArrayList<NetworkKey>();  

    //iterate all scan results and find the best candidate with the highest score
    //2.迭代所有扫描结果,找到得分最高的最佳候选人  
    for (ScanDetail scanDetail : mScanDetails) {  
        ScanResult scanResult = scanDetail.getScanResult();  
        //skip bad scan result
        //2.1 ssid=null, add to noValidSsid,  ignore  
        if (scanResult.SSID == null || TextUtils.isEmpty(scanResult.SSID)) {  
            if (mDbg) {  
                //We should not see this in ePNO  
                noValidSsid.append(scanResult.BSSID + " / ");  
            }  
            continue;  
        }  

        final String scanId = toScanId(scanResult);  
        //check whether this BSSID is blocked or not
        //2.2 isBlackListed() ignore, addToBlacklist(bssid) will add to blackList 
        if (mWifiConfigManager.isBssidBlacklisted(scanResult.BSSID)  
                || isBssidDisabled(scanResult.BSSID)) {  
            //We should not see this in ePNO  
            Log.e(TAG, scanId + " is in blacklist.");  
            continue;  
        }  

        //skip scan result with too weak signals
        //2.3 too weak signal strength add to lowSignalScan, ignore 2.4G level<-85  5G level<-85  
        if ((scanResult.is24GHz() && scanResult.level  
                < mWifiConfigManager.mThresholdMinimumRssi24.get())  
                || (scanResult.is5GHz() && scanResult.level  
                < mWifiConfigManager.mThresholdMinimumRssi5.get())) {  
            if (mDbg) {  
                lowSignalScan.append(scanId + "(" + (scanResult.is24GHz() ? "2.4GHz" : "5GHz")  
                        + ")" + scanResult.level + " / ");  
            }  
            continue;  
        }  

        //check if there is already a score for this network  
        if (mNetworkScoreCache != null && !mNetworkScoreCache.isScoredNetwork(scanResult)) {  
            //no score for this network yet.  
            WifiKey wifiKey;  

            try {  
                wifiKey = new WifiKey("\"" + scanResult.SSID + "\"", scanResult.BSSID);  
                NetworkKey ntwkKey = new NetworkKey(wifiKey);  
                //add to the unscoredNetworks list so we can request score later  
                unscoredNetworks.add(ntwkKey);  
            } catch (IllegalArgumentException e) {  
                Log.w(TAG, "Invalid SSID=" + scanResult.SSID + " BSSID=" + scanResult.BSSID  
                        + " for network score. Skip.");  
            }  
        }  
		//2.4 未保存的网络(添加到notSavedScan)或保存但短暂,忽略
        //check whether this scan result belong to a saved network  
        boolean potentiallyEphemeral = false;  
        // Stores WifiConfiguration of potential connection candidates for scan result filtering  
        WifiConfiguration potentialEphemeralCandidate = null;  
        List<WifiConfiguration> associatedWifiConfigurations =  
                mWifiConfigManager.updateSavedNetworkWithNewScanDetail(scanDetail,  
                        isSupplicantTransient || isConnected || isLinkDebouncing);  
        if (associatedWifiConfigurations == null) {  
            potentiallyEphemeral =  true;  
            if (mDbg) {  
                notSavedScan.append(scanId + " / ");  
            }  
        } else if (associatedWifiConfigurations.size() == 1) {  
            //if there are more than 1 associated network, it must be a passpoint network  
            WifiConfiguration network = associatedWifiConfigurations.get(0);  
            if (network.ephemeral) {  
                potentialEphemeralCandidate = network;  
                potentiallyEphemeral =  true;  
            }  
        }  
        // Evaluate the potentially ephemeral network as a possible candidate if untrusted  
        // connections are allowed and we have an external score for the scan result.  
        if (potentiallyEphemeral) {  
            if (isUntrustedConnectionsAllowed) {  
                Integer netScore = getNetworkScore(scanResult, false);  
                if (netScore != null  
                    && !mWifiConfigManager.wasEphemeralNetworkDeleted(scanResult.SSID)) {  
                    externalScoreEvaluator.evalUntrustedCandidate(netScore, scanResult);  
                    // scanDetail is for available ephemeral network  
                    filteredScanDetails.add(Pair.create(scanDetail,  
                            potentialEphemeralCandidate));  
                }  
            }  
            continue;  
        }  
		// 2.5 计算每个关联网络不是短暂的扫描结果的得分。由于一个扫描结果可以关联多个网络,我们需要计算所有,并使用最高的一个作为扫描结果的分数。
        // calculate the score of each scanresult whose associated network is not ephemeral. Due  
        // to one scan result can associated with more than 1 network, we need calculate all  
        // the scores and use the highest one as the scanresults score.  
        int highestScore = Integer.MIN_VALUE;  
        int score;  
        WifiConfiguration configurationCandidateForThisScan = null;  
        WifiConfiguration potentialCandidate = null;  
        for (WifiConfiguration network : associatedWifiConfigurations) {  
            WifiConfiguration.NetworkSelectionStatus status =  
                    network.getNetworkSelectionStatus();  
            status.setSeenInLastQualifiedNetworkSelection(true);  
            if (potentialCandidate == null) {  
                potentialCandidate = network;  
            }  
            if (!status.isNetworkEnabled()) {  
                continue;  
            } else if (network.BSSID != null && !network.BSSID.equals("any")  
                    && !network.BSSID.equals(scanResult.BSSID)) {  
                //in such scenario, user (APP) has specified the only BSSID to connect for this  
                // configuration. So only the matched scan result can be candidate  
                localLog("Network: " + getNetworkString(network) + " has specified" + "BSSID:"  
                        + network.BSSID + ". Skip " + scanResult.BSSID);  
                continue;  
            }  

            // If the network is marked to use external scores then attempt to fetch the score.  
            // These networks will not be considered alongside the other saved networks.  
            if (network.useExternalScores) {  
                Integer netScore = getNetworkScore(scanResult, false);  
                externalScoreEvaluator.evalSavedCandidate(netScore, network, scanResult);  
                continue;  
            }  

            score = calculateBssidScore(scanResult, network, mCurrentConnectedNetwork,  
                    (mCurrentBssid == null ? false : mCurrentBssid.equals(scanResult.BSSID)),  
                    (lastUserSelectedNetwork == null ? false : lastUserSelectedNetwork.networkId  
                     == network.networkId), scoreHistory);  
            if (score > highestScore) {  
                highestScore = score;  
                configurationCandidateForThisScan = network;  
                potentialCandidate = network;  
            }  
            //update the cached candidate
            //更新缓存的候选对象  
            if (score > status.getCandidateScore() || (score == status.getCandidateScore()  
                  && status.getCandidate() != null  
                  && scanResult.level > status.getCandidate().level)) {  
                status.setCandidate(scanResult);  
                status.setCandidateScore(score);  
            }  
        }  
        // Create potential filteredScanDetail entry  
        filteredScanDetails.add(Pair.create(scanDetail, potentialCandidate));  

        if (highestScore > currentHighestScore || (highestScore == currentHighestScore  
                && scanResultCandidate != null  
                && scanResult.level > scanResultCandidate.level)) {  
            currentHighestScore = highestScore;  
            scanResultCandidate = scanResult;  
            networkCandidate = configurationCandidateForThisScan;  
            networkCandidate.getNetworkSelectionStatus().setCandidate(scanResultCandidate);  
        }  
    }  

    mFilteredScanDetails = filteredScanDetails;  

    //kick the score manager if there is any unscored network  
    if (mScoreManager != null && unscoredNetworks.size() != 0) {  
        NetworkKey[] unscoredNetworkKeys =  
                unscoredNetworks.toArray(new NetworkKey[unscoredNetworks.size()]);  
        mScoreManager.requestScores(unscoredNetworkKeys);  
    }  

    if (mDbg) {  
        localLog(lowSignalScan + " skipped due to low signal\n");  
        localLog(notSavedScan + " skipped due to not saved\n ");  
        localLog(noValidSsid + " skipped due to not valid SSID\n");  
        localLog(scoreHistory.toString());  
    }  

    //we need traverse the whole user preference to choose the one user like most now
    //2.6 现在我们需要遍历整个用户偏好来选择一个用户最喜欢的
    if (scanResultCandidate != null) {  
        WifiConfiguration tempConfig = networkCandidate;  

        while (tempConfig.getNetworkSelectionStatus().getConnectChoice() != null) {  
            String key = tempConfig.getNetworkSelectionStatus().getConnectChoice();  
            tempConfig = mWifiConfigManager.getWifiConfiguration(key);  

            if (tempConfig != null) {  
                WifiConfiguration.NetworkSelectionStatus tempStatus =  
                        tempConfig.getNetworkSelectionStatus();  
                if (tempStatus.getCandidate() != null && tempStatus.isNetworkEnabled()) {  
                    scanResultCandidate = tempStatus.getCandidate();  
                    networkCandidate = tempConfig;  
                }  
            } else {  
                //we should not come here in theory  
                localLoge("Connect choice: " + key + " has no corresponding saved config");  
                break;  
            }  
        }  
        localLog("After user choice adjust, the final candidate is:"  
                + getNetworkString(networkCandidate) + " : " + scanResultCandidate.BSSID);  
    }  

    // At this point none of the saved networks were good candidates so we fall back to  
    // externally scored networks if any are available.  
    if (scanResultCandidate == null) {  
        localLog("Checking the externalScoreEvaluator for candidates...");  
        networkCandidate = getExternalScoreCandidate(externalScoreEvaluator);  
        if (networkCandidate != null) {  
            scanResultCandidate = networkCandidate.getNetworkSelectionStatus().getCandidate();  
        }  
    }  

    if (scanResultCandidate == null) {  
        localLog("Can not find any suitable candidates");  
        return null;  
    }  

    String currentAssociationId = mCurrentConnectedNetwork == null ? "Disconnected" :  
            getNetworkString(mCurrentConnectedNetwork);  
    String targetAssociationId = getNetworkString(networkCandidate);  
    //In passpoint, saved configuration has garbage SSID. We need update it with the SSID of  
    //the scan result.  
    if (networkCandidate.isPasspoint()) {  
        // This will update the passpoint configuration in WifiConfigManager  
        networkCandidate.SSID = "\"" + scanResultCandidate.SSID + "\"";  
    }  

    //For debug purpose only  
    if (scanResultCandidate.BSSID.equals(mCurrentBssid)) {  
        localLog(currentAssociationId + " is already the best choice!");  
    } else if (mCurrentConnectedNetwork != null  
            && (mCurrentConnectedNetwork.networkId == networkCandidate.networkId  
            || mCurrentConnectedNetwork.isLinked(networkCandidate))) {  
        localLog("Roaming from " + currentAssociationId + " to " + targetAssociationId);  
    } else {  
        localLog("reconnect from " + currentAssociationId + " to " + targetAssociationId);  
    }  

    mCurrentBssid = scanResultCandidate.BSSID;  
    mCurrentConnectedNetwork = networkCandidate;  
    mLastQualifiedNetworkSelectionTimeStamp = mClock.elapsedRealtime();  
    return networkCandidate;  
}  

Android N selectQualifiedNetwork分析

标签:lang   reconnect   现在   RKE   call   ast   conf   sso   with   

原文地址:https://www.cnblogs.com/rougungun/p/14338792.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!