1、WifiConnectivityManager的初始化

frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java

private void setupClientMode() {    Log.d(TAG, "setupClientMode() ifacename = " + mInterfaceName);    mWifiStateTracker.updateState(WifiStateTracker.INVALID);    if (mWifiConnectivityManager == null) {        synchronized (mWifiReqCountLock) {            mWifiConnectivityManager =                    mWifiInjector.makeWifiConnectivityManager(mWifiInfo,                                                              hasConnectionRequests());            mWifiConnectivityManager.setUntrustedConnectionAllowed(mUntrustedReqCount > 0);            mWifiConnectivityManager.handleScreenStateChanged(mScreenOn);        }    }

frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiInjector.java

public WifiConnectivityManager makeWifiConnectivityManager(WifiInfo wifiInfo,                                                           boolean hasConnectionRequests) {    return new WifiConnectivityManager(mContext, getScoringParams(),            mWifiStateMachine, getWifiScanner(),            mWifiConfigManager, wifiInfo, mWifiNetworkSelector, mWifiConnectivityHelper,            mWifiLastResortWatchdog, mOpenNetworkNotifier, mCarrierNetworkNotifier,            mCarrierNetworkConfig, mWifiMetrics, mWifiStateMachineHandlerThread.getLooper(),            mClock, mConnectivityLocalLog, hasConnectionRequests, mFrameworkFacade,            mSavedNetworkEvaluator, mScoredNetworkEvaluator, mPasspointNetworkEvaluator);}

构造方法里注册了3个NetworkEvaluator
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java

WifiConnectivityManager(Context context, ScoringParams scoringParams,        WifiStateMachine stateMachine,        WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo,    // Register the network evaluators    mNetworkSelector.registerNetworkEvaluator(savedNetworkEvaluator,            SAVED_NETWORK_EVALUATOR_PRIORITY);    if (hs2Enabled) {        mNetworkSelector.registerNetworkEvaluator(passpointNetworkEvaluator,                PASSPOINT_NETWORK_EVALUATOR_PRIORITY);    }    mNetworkSelector.registerNetworkEvaluator(scoredNetworkEvaluator,            SCORED_NETWORK_EVALUATOR_PRIORITY);}

注册方法就是初始化一个NetworkEvaluator数组,大小为6,即优先级从高到低0-5。
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNetworkSelector.java

public boolean registerNetworkEvaluator(NetworkEvaluator evaluator, int priority) {    if (priority < 0 || priority >= EVALUATOR_MIN_PRIORITY) {        localLog("Invalid network evaluator priority: " + priority);        return false;    }    if (mEvaluators[priority] != null) {        localLog("Priority " + priority + " is already registered by "                + mEvaluators[priority].getName());        return false;    }    mEvaluators[priority] = evaluator;    return true;}private final NetworkEvaluator[] mEvaluators = new NetworkEvaluator[MAX_NUM_EVALUATORS];public static final int MAX_NUM_EVALUATORS = EVALUATOR_MIN_PRIORITY;/** * WiFi Network Selector supports various types of networks. Each type can * have its evaluator to choose the best WiFi network for the device to connect * to. When registering a WiFi network evaluator with the WiFi Network Selector, * the priority of the network must be specified, and it must be a value between * 0 and (EVALUATOR_MIN_PIRORITY - 1) with 0 being the highest priority. Wifi * Network Selector iterates through the registered scorers from the highest priority * to the lowest till a network is selected. */public static final int EVALUATOR_MIN_PRIORITY = 6;

2、WifiConnectivityManager的网络评估

处理扫描结果
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java

private boolean handleScanResults(List<ScanDetail> scanDetails, String listenerName) {    // Check if any blacklisted BSSIDs can be freed.    refreshBssidBlacklist();    if (mStateMachine.isSupplicantTransientState()) {        localLog(listenerName                + " onResults: No network selection because supplicantTransientState is "                + mStateMachine.isSupplicantTransientState());        return false;    }    localLog(listenerName + " onResults: start network selection");    WifiConfiguration candidate =            mNetworkSelector.selectNetwork(scanDetails, buildBssidBlacklist(), mWifiInfo,            mStateMachine.isConnected(), mStateMachine.isDisconnected(),            mUntrustedConnectionAllowed);    mWifiLastResortWatchdog.updateAvailableNetworks(            mNetworkSelector.getConnectableScanDetails());    mWifiMetrics.countScanResults(scanDetails);    if (candidate != null) {        localLog(listenerName + ":  WNS candidate-" + candidate.SSID);        connectToNetwork(candidate);        return true;    } else {        if (mWifiState == WIFI_STATE_DISCONNECTED) {            mOpenNetworkNotifier.handleScanResults(                    mNetworkSelector.getFilteredScanDetailsForOpenUnsavedNetworks());            if (mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()) {                mCarrierNetworkNotifier.handleScanResults(                        mNetworkSelector.getFilteredScanDetailsForCarrierUnsavedNetworks(                                mCarrierNetworkConfig));            }        }        return false;    }}

如注释所说:处理周期性,单次和Pno ScanListener的“ onResult”回调。 执行潜在网络候选者的选择,启动与该网络的连接尝试。

然后看candidate是如何生成的:
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNetworkSelector.java

public WifiConfiguration selectNetwork(List<ScanDetail> scanDetails,        HashSet<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();    // Shall we start network selection at all?    if (!isNetworkSelectionNeeded(scanDetails, wifiInfo, connected, disconnected)) {        return null;    }    // Update the registered network evaluators.    for (NetworkEvaluator registeredEvaluator : mEvaluators) {        if (registeredEvaluator != null) {            registeredEvaluator.update(scanDetails);        }    }    // Filter out unwanted networks.    mFilteredNetworks = filterScanResults(scanDetails, bssidBlacklist,            connected, currentBssid);    if (mFilteredNetworks.size() == 0) {        return null;    }    // Go through the registered network evaluators from the highest priority    // one to the lowest till a network is selected.    WifiConfiguration selectedNetwork = null;    for (NetworkEvaluator registeredEvaluator : mEvaluators) {        if (registeredEvaluator != null) {            localLog("About to run " + registeredEvaluator.getName() + " :");            selectedNetwork = registeredEvaluator.evaluateNetworks(                    new ArrayList<>(mFilteredNetworks), currentNetwork, currentBssid, connected,                    untrustedNetworkAllowed, mConnectableNetworks);            if (selectedNetwork != null) {                localLog(registeredEvaluator.getName() + " selects "                        + WifiNetworkSelector.toNetworkString(selectedNetwork) + " : "                        + selectedNetwork.getNetworkSelectionStatus().getCandidate().BSSID);                break;            }        }    }    if (selectedNetwork != null) {        selectedNetwork = overrideCandidateWithUserConnectChoice(selectedNetwork);        mLastNetworkSelectionTimeStamp = mClock.getElapsedSinceBootMillis();    }    return selectedNetwork;}

2.1、判断是否需要网络选择

private boolean isNetworkSelectionNeeded(List<ScanDetail> scanDetails, WifiInfo wifiInfo,                    boolean connected, boolean disconnected) {    if (scanDetails.size() == 0) {        localLog("Empty connectivity scan results. Skip network selection.");        return false;    }    if (connected) {        // Is roaming allowed?        if (!mEnableAutoJoinWhenAssociated) {            localLog("Switching networks in connected state is not allowed."                    + " Skip network selection.");            return false;        }        // Has it been at least the minimum interval since last network selection?        if (mLastNetworkSelectionTimeStamp != INVALID_TIME_STAMP) {            long gap = mClock.getElapsedSinceBootMillis()                        - mLastNetworkSelectionTimeStamp;            if (gap < MINIMUM_NETWORK_SELECTION_INTERVAL_MS) {                localLog("Too short since last network selection: " + gap + " ms."                        + " Skip network selection.");                return false;            }        }        if (isCurrentNetworkSufficient(wifiInfo, scanDetails)) {            localLog("Current connected network already sufficient. Skip network selection.");            return false;        } else {            localLog("Current connected network is not sufficient.");            return true;        }    } else if (disconnected) {        return true;    } else {        // No network selection if WifiStateMachine is in a state other than        // CONNECTED or DISCONNECTED.        localLog("WifiStateMachine is in neither CONNECTED nor DISCONNECTED state."                + " Skip network selection.");        return false;    }}

2.2、SavedNetworkEvaluator的筛选

根据扫描结果评估所有网络,并返回选择用于连接的网络的WifiConfiguration
frameworks/opt/net/wifi/service/java/com/android/server/wifi/SavedNetworkEvaluator.java

/** * Evaluate all the networks from the scan results and return * the WifiConfiguration of the network chosen for connection. * * @return configuration of the chosen network; *         null if no network in this category is available. */public WifiConfiguration evaluateNetworks(List<ScanDetail> scanDetails,                WifiConfiguration currentNetwork, String currentBssid, boolean connected,                boolean untrustedNetworkAllowed,                List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks) {    int highestScore = Integer.MIN_VALUE;    ScanResult scanResultCandidate = null;    WifiConfiguration candidate = null;    StringBuffer scoreHistory = new StringBuffer();    for (ScanDetail scanDetail : scanDetails) {        ScanResult scanResult = scanDetail.getScanResult();        // One ScanResult can be associated with more than one networks, hence we calculate all        // the scores and use the highest one as the ScanResult's score.        WifiConfiguration network =                mWifiConfigManager.getConfiguredNetworkForScanDetailAndCache(scanDetail);        if (network == null) {            continue;        }        /**         * Ignore Passpoint and Ephemeral networks. They are configured networks,         * but without being persisted to the storage. They are evaluated by         * {@link PasspointNetworkEvaluator} and {@link ScoredNetworkEvaluator}         * respectively.         */        if (network.isPasspoint() || network.isEphemeral()) {            continue;        }        WifiConfiguration.NetworkSelectionStatus status =                network.getNetworkSelectionStatus();        status.setSeenInLastQualifiedNetworkSelection(true);        if (!status.isNetworkEnabled()) {            continue;        } else if (network.BSSID != null &&  !network.BSSID.equals("any")                && !network.BSSID.equals(scanResult.BSSID)) {            // App has specified the only BSSID to connect for this            // configuration. So only the matching ScanResult can be a candidate.            localLog("Network " + WifiNetworkSelector.toNetworkString(network)                    + " has specified BSSID " + network.BSSID + ". Skip "                    + scanResult.BSSID);            continue;        } else if (TelephonyUtil.isSimConfig(network)                && !mWifiConfigManager.isSimPresent()) {            // Don't select if security type is EAP SIM/AKA/AKA' when SIM is not present.            continue;        }        int score = calculateBssidScore(scanResult, network, currentNetwork, currentBssid,                scoreHistory);        // Set candidate ScanResult for all saved networks to ensure that users can        // override network selection. See WifiNetworkSelector#setUserConnectChoice.        // TODO(b/36067705): consider alternative designs to push filtering/selecting of        // user connect choice networks to RecommendedNetworkEvaluator.        if (score > status.getCandidateScore() || (score == status.getCandidateScore()                && status.getCandidate() != null                && scanResult.level > status.getCandidate().level)) {            mWifiConfigManager.setNetworkCandidateScanResult(                    network.networkId, scanResult, score);        }        // If the network is marked to use external scores, or is an open network with        // curate saved open networks enabled, do not consider it for network selection.        if (network.useExternalScores) {            localLog("Network " + WifiNetworkSelector.toNetworkString(network)                    + " has external score.");            continue;        }        if (connectableNetworks != null) {            connectableNetworks.add(Pair.create(scanDetail,                    mWifiConfigManager.getConfiguredNetwork(network.networkId)));        }        if (score > highestScore                || (score == highestScore                && scanResultCandidate != null                && scanResult.level > scanResultCandidate.level)) {            highestScore = score;            scanResultCandidate = scanResult;            mWifiConfigManager.setNetworkCandidateScanResult(                    network.networkId, scanResultCandidate, highestScore);            // Reload the network config with the updated info.            candidate = mWifiConfigManager.getConfiguredNetwork(network.networkId);        }    }    if (scoreHistory.length() > 0) {        localLog("\n" + scoreHistory.toString());    }    if (scanResultCandidate == null) {        localLog("did not see any good candidates.");    }    return candidate;}

忽略Passpoint和临时网络。

/** * Ignore Passpoint and Ephemeral networks. They are configured networks, * but without being persisted to the storage. They are evaluated by * {@link PasspointNetworkEvaluator} and {@link ScoredNetworkEvaluator} * respectively. */if (network.isPasspoint() || network.isEphemeral()) {    continue;}

判断当前网络是否允许加入网络选择,如果不允许,则过滤掉

if (!status.isNetworkEnabled()) {    continue;} else if (network.BSSID != null &&  !network.BSSID.equals("any")        && !network.BSSID.equals(scanResult.BSSID)) {    // App has specified the only BSSID to connect for this    // configuration. So only the matching ScanResult can be a candidate.    localLog("Network " + WifiNetworkSelector.toNetworkString(network)            + " has specified BSSID " + network.BSSID + ". Skip "            + scanResult.BSSID);    continue;

如果该网络被标记为使用外部得分,或者该网络是启用了保存已保存的开放网络的开放网络,则不要将其视为网络选择

if (network.useExternalScores) {    localLog("Network " + WifiNetworkSelector.toNetworkString(network)            + " has external score.");    continue;}

2.3、评分机制

frameworks/opt/net/wifi/service/java/com/android/server/wifi/SavedNetworkEvaluator.java

private int calculateBssidScore(ScanResult scanResult, WifiConfiguration network,                    WifiConfiguration currentNetwork, String currentBssid,                    StringBuffer sbuf) {    int score = 0;    boolean is5GHz = scanResult.is5GHz();    sbuf.append("[ ").append(scanResult.SSID).append(" ").append(scanResult.BSSID)            .append(" RSSI:").append(scanResult.level).append(" ] ");    // Calculate the RSSI score.    int rssiSaturationThreshold = mScoringParams.getGoodRssi(scanResult.frequency);    int rssi = scanResult.level < rssiSaturationThreshold ? scanResult.level            : rssiSaturationThreshold;    score += (rssi + mRssiScoreOffset) * mRssiScoreSlope;    sbuf.append(" RSSI score: ").append(score).append(",");    // 5GHz band bonus.    if (is5GHz) {        score += mBand5GHzAward;        sbuf.append(" 5GHz bonus: ").append(mBand5GHzAward).append(",");    }    // Last user selection award.    int lastUserSelectedNetworkId = mWifiConfigManager.getLastSelectedNetwork();    if (lastUserSelectedNetworkId != WifiConfiguration.INVALID_NETWORK_ID            && lastUserSelectedNetworkId == network.networkId) {        long timeDifference = mClock.getElapsedSinceBootMillis()                - mWifiConfigManager.getLastSelectedTimeStamp();        if (timeDifference > 0) {            int bonus = mLastSelectionAward - (int) (timeDifference / 1000 / 60);            score += bonus > 0 ? bonus : 0;            sbuf.append(" User selection ").append(timeDifference / 1000 / 60)                    .append(" minutes ago, bonus: ").append(bonus).append(",");        }    }    // Same network award.    if (currentNetwork != null            && (network.networkId == currentNetwork.networkId            //TODO(b/36788683): re-enable linked configuration check            /* || network.isLinked(currentNetwork) */)) {        score += mSameNetworkAward;        sbuf.append(" Same network bonus: ").append(mSameNetworkAward).append(",");        // When firmware roaming is supported, equivalent BSSIDs (the ones under the        // same network as the currently connected one) get the same BSSID award.        if (mConnectivityHelper.isFirmwareRoamingSupported()                && currentBssid != null && !currentBssid.equals(scanResult.BSSID)) {            score += mSameBssidAward;            sbuf.append(" Equivalent BSSID bonus: ").append(mSameBssidAward).append(",");        }    }    // Same BSSID award.    if (currentBssid != null && currentBssid.equals(scanResult.BSSID)) {        score += mSameBssidAward;        sbuf.append(" Same BSSID bonus: ").append(mSameBssidAward).append(",");    }    // Security award.    if (!WifiConfigurationUtil.isConfigForOpenNetwork(network)) {        score += mSecurityAward;        sbuf.append(" Secure network bonus: ").append(mSecurityAward).append(",");    }    sbuf.append(" ## Total score: ").append(score).append("\n");    return score;}
2.3.1、RSSI
int rssiSaturationThreshold = mScoringParams.getGoodRssi(scanResult.frequency);int rssi = scanResult.level < rssiSaturationThreshold ? scanResult.level        : rssiSaturationThreshold;score += (rssi + mRssiScoreOffset) * mRssiScoreSlope;
2.3.2、5G

如果频率是5G,会加分

if (is5GHz) {    score += mBand5GHzAward;    sbuf.append(" 5GHz bonus: ").append(mBand5GHzAward).append(",");}
2.3.3、Last user selection award

最后一个使用的网络会加分

// Last user selection award.int lastUserSelectedNetworkId = mWifiConfigManager.getLastSelectedNetwork();if (lastUserSelectedNetworkId != WifiConfiguration.INVALID_NETWORK_ID        && lastUserSelectedNetworkId == network.networkId) {    long timeDifference = mClock.getElapsedSinceBootMillis()            - mWifiConfigManager.getLastSelectedTimeStamp();    if (timeDifference > 0) {        int bonus = mLastSelectionAward - (int) (timeDifference / 1000 / 60);        score += bonus > 0 ? bonus : 0;        sbuf.append(" User selection ").append(timeDifference / 1000 / 60)                .append(" minutes ago, bonus: ").append(bonus).append(",");    }}
2.3.4、Same network award

相同的networkId会加分,相同的networkId且支持漫游也会加分

// Same network award.if (currentNetwork != null        && (network.networkId == currentNetwork.networkId        //TODO(b/36788683): re-enable linked configuration check        /* || network.isLinked(currentNetwork) */)) {    score += mSameNetworkAward;    sbuf.append(" Same network bonus: ").append(mSameNetworkAward).append(",");    // When firmware roaming is supported, equivalent BSSIDs (the ones under the    // same network as the currently connected one) get the same BSSID award.    if (mConnectivityHelper.isFirmwareRoamingSupported()            && currentBssid != null && !currentBssid.equals(scanResult.BSSID)) {        score += mSameBssidAward;        sbuf.append(" Equivalent BSSID bonus: ").append(mSameBssidAward).append(",");    }}
2.3.5、Same BSSID award

相同的BSSID会加分

// Same BSSID award.if (currentBssid != null && currentBssid.equals(scanResult.BSSID)) {    score += mSameBssidAward;    sbuf.append(" Same BSSID bonus: ").append(mSameBssidAward).append(",");}
2.3.6、Security award

不是开放的网络会加分

// Security award.if (!WifiConfigurationUtil.isConfigForOpenNetwork(network)) {    score += mSecurityAward;    sbuf.append(" Secure network bonus: ").append(mSecurityAward).append(",");}

3、总结

SavedNetworkEvaluator评分几大要素:
rssi
5G
Last user selection award
Same network award 支持漫游
Same BSSID award
Security award

关注公众号,获取更多开发必备知识

更多相关文章

  1. OpenWrt上运行Android(安卓)OS
  2. windows下android 开发环境建立
  3. Android搜索视媒体库视频 列表显示选择
  4. Android下载网络图片到本地
  5. Android(安卓)环境搭建
  6. android实现猜扑克牌小游戏(改进:每次只可以选择一张)
  7. android中获取网络图片
  8. android ping 网络延迟
  9. android设备信息获取

随机推荐

  1. iPhone的网站主题 - 什么是基本成分?
  2. 如何在bing地图中添加信息框到一个航点
  3. 函数的作用是:在javascript中将时间戳转
  4. Vue自定义指令实现checkbox全选功能
  5. 多种方法用javascript输出黑白棋
  6. javascript 动态数组的使用
  7. 检查重复项后使用insertbefore()
  8. 数组中的值由于未知原因而更改
  9. Crypto.js:在IE 11中未定义“Uint8Clamped
  10. 使用自动化测试框架selenium,批量的进行截