Android Wi-Fi 评分机制

基于Android S 代码分析:http://aospxref.com/android-13.0.0_r3/

  首先我们要知道两点,一般说道评分机制,需要知道是Wi-Fi内部的评分机制还是整个CS的评分机制,那这里我们记录的是Wi-Fi内部的评分机制,那什么时候触发这个机制呢?自动连接的时候就会触发,会评选出一个分数最高的 Candidate ,不知道Wi-Fi自动连接流程的看这里:Wi-Fi 自动连接流程

具体的看下代码:
http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java

	List<WifiCandidates.Candidate> candidates = mNetworkSelector.getCandidatesFromScan(   ---> 看下这个的实现
													scanDetails, bssidBlocklist, cmmStates,
	                                             	mUntrustedConnectionAllowed,mOemPaidConnectionAllowed, 		             			   				        
												    mOemPrivateConnectionAllowed,mRestrictedConnectionAllowedUids,
												    isMultiInternetConnectionRequested());
     mLatestCandidates = candidates;

http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/service/java/com/android/server/wifi/WifiNetworkSelector.java#getCandidatesFromScan

    public List<WifiCandidates.Candidate> getCandidatesFromScan(
            @NonNull List<ScanDetail> scanDetails, @NonNull Set<String> bssidBlocklist,
            @NonNull List<ClientModeManagerState> cmmStates, boolean untrustedNetworkAllowed,
            boolean oemPaidNetworkAllowed, boolean oemPrivateNetworkAllowed,
            Set<Integer> restrictedNetworkAllowedUids, boolean multiInternetNetworkAllowed) {
        // 清空集合
        mFilteredNetworks.clear();
        mConnectableNetworks.clear();
        // 扫描到的结果不能没有
        if (scanDetails.size() == 0) {
            localLog("Empty connectivity scan result");
            return null;
        }

        // Update the scan detail cache at the start, even if we skip network selection
        updateScanDetailCache(scanDetails); ---> 目的在后续的网络选择和候选网络提名过程中,可以通过网络配置的网络ID从缓存中获取相应的扫描详情。避免频繁地重新扫描和解析扫描结果,提高操作的效率和响应速度

        // Update the registered network nominators.
        for (NetworkNominator registeredNominator : mNominators) {
            registeredNominator.update(scanDetails);
        }

        // Shall we start network selection at all?
        if (!multiInternetNetworkAllowed && !isNetworkSelectionNeeded(scanDetails, cmmStates)) {
            return null;
        }

        // Filter out unwanted networks.
        mFilteredNetworks = filterScanResults(scanDetails, bssidBlocklist, cmmStates);  --->下面单独看下,标记 1
        if (mFilteredNetworks.size() == 0) {
            return null;
        }

		WifiCandidates wifiCandidates = new WifiCandidates(mWifiScoreCard, mContext);
		for (ClientModeManagerState cmmState : cmmStates) {
		    // 始终从WifiInfo中获取当前BSSID,以防固件发起了漫游。
		    String currentBssid = cmmState.wifiInfo.getBSSID();
		    WifiConfiguration currentNetwork =
		            mWifiConfigManager.getConfiguredNetwork(cmmState.wifiInfo.getNetworkId());
		
		    // 将当前网络设置为候选网络
		    if (currentNetwork != null) {
		        wifiCandidates.setCurrent(currentNetwork.networkId, currentBssid);
		
		        MacAddress bssid = MacAddress.fromString(currentBssid);
		        SecurityParams params = currentNetwork.getNetworkSelectionStatus().getLastUsedSecurityParams();
		
		        // 如果当前网络没有已知的候选安全参数,则跳过
		        if (null == params) {
		            localLog("当前网络没有已知的候选安全参数。");
		            continue;
		        }
		
		        // 为当前网络创建一个键
		        WifiCandidates.Key key = new WifiCandidates.Key(
		                ScanResultMatchInfo.fromWifiConfiguration(currentNetwork),
		                bssid, currentNetwork.networkId,
		                params.getSecurityType());
		
		        // 查找当前BSSID的扫描详情
		        ScanDetail scanDetail = findScanDetailForBssid(mFilteredNetworks, currentBssid);
		
		        // 预测扫描详情的吞吐量
		        int predictedTputMbps = (scanDetail == null) ? 0 : predictThroughput(scanDetail);
		
		        // 将当前网络添加为候选网络
		        wifiCandidates.add(key, currentNetwork,
		                NetworkNominator.NOMINATOR_ID_CURRENT,
		                cmmState.wifiInfo.getRssi(),
		                cmmState.wifiInfo.getFrequency(),
		                ScanResult.CHANNEL_WIDTH_20MHZ, // 在WifiInfo中无法获取信道宽度
		                calculateLastSelectionWeight(currentNetwork.networkId),
		                WifiConfiguration.isMetered(currentNetwork, cmmState.wifiInfo),
		                isFromCarrierOrPrivilegedApp(currentNetwork),
		                predictedTputMbps);
		    }
		}

        // 在开始网络选择之前更新所有已配置的网络
        updateConfiguredNetworks();

        for (NetworkNominator registeredNominator : mNominators) {
            localLog("About to run " + registeredNominator.getName() + " :");
            registeredNominator.nominateNetworks(
                    new ArrayList<>(mFilteredNetworks),
                    untrustedNetworkAllowed, oemPaidNetworkAllowed, oemPrivateNetworkAllowed,
                    restrictedNetworkAllowedUids, (scanDetail, config) -> {
                        WifiCandidates.Key key = wifiCandidates.keyFromScanDetailAndConfig(
                                scanDetail, config);
                        if (key != null) {
                            boolean metered = false;
                            for (ClientModeManagerState cmmState : cmmStates) {
                                if (isEverMetered(config, cmmState.wifiInfo, scanDetail)) {
                                    metered = true;
                                    break;
                                }
                            }
                            // TODO(b/151981920) Saved passpoint candidates are marked ephemeral
                            boolean added = wifiCandidates.add(key, config,
                                    registeredNominator.getId(),
                                    scanDetail.getScanResult().level,
                                    scanDetail.getScanResult().frequency,
                                    scanDetail.getScanResult().channelWidth,
                                    calculateLastSelectionWeight(config.networkId),
                                    metered,
                                    isFromCarrierOrPrivilegedApp(config),
                                    predictThroughput(scanDetail));
                            if (added) {
                                mConnectableNetworks.add(Pair.create(scanDetail, config));
                                mWifiConfigManager.updateScanDetailForNetwork(
                                        config.networkId, scanDetail);
                                mWifiMetrics.setNominatorForNetwork(config.networkId,
                                        toProtoNominatorId(registeredNominator.getId()));
                            }
                        }
                    });
        }
        if (mConnectableNetworks.size() != wifiCandidates.size()) {
            localLog("Connectable: " + mConnectableNetworks.size()
                    + " Candidates: " + wifiCandidates.size());
        }
        return wifiCandidates.getCandidates();
    }

看下标记 1:

private List<ScanDetail> filterScanResults(List<ScanDetail> scanDetails,
        Set<String> bssidBlocklist, List<ClientModeManagerState> cmmStates) {
    List<ScanDetail> validScanDetails = new ArrayList<>();
    StringBuffer noValidSsid = new StringBuffer();
    StringBuffer blockedBssid = new StringBuffer();
    StringBuffer lowRssi = new StringBuffer();
    StringBuffer mboAssociationDisallowedBssid = new StringBuffer();
    StringBuffer adminRestrictedSsid = new StringBuffer();
    List<String> currentBssids = cmmStates.stream()
            .map(cmmState -> cmmState.wifiInfo.getBSSID())
            .collect(Collectors.toList());
    Set<String> scanResultPresentForCurrentBssids = new ArraySet<>();

    int adminMinimumSecurityLevel = 0;
    boolean adminSsidRestrictionSet = false;
    Set<WifiSsid> adminSsidAllowlist = new ArraySet<>();
    Set<WifiSsid> admindSsidDenylist = new ArraySet<>();

    // 获取设备策略管理器
    DevicePolicyManager devicePolicyManager =
            WifiPermissionsUtil.retrieveDevicePolicyManagerFromContext(mContext);

    if (devicePolicyManager != null && SdkLevel.isAtLeastT()) {
        // 获取最低要求的 Wi-Fi 安全级别
        adminMinimumSecurityLevel =
                devicePolicyManager.getMinimumRequiredWifiSecurityLevel();
        // 获取 Wi-Fi SSID 策略
        WifiSsidPolicy policy = devicePolicyManager.getWifiSsidPolicy();
        if (policy != null) {
            adminSsidRestrictionSet = true;
            if (policy.getPolicyType() == WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST) {
                // 获取允许的 SSID 列表
                adminSsidAllowlist = policy.getSsids();
            } else {
                // 获取拒绝的 SSID 列表
                admindSsidDenylist = policy.getSsids();
            }
        }
    }

    for (ScanDetail scanDetail : scanDetails) {
        ScanResult scanResult = scanDetail.getScanResult();

        if (TextUtils.isEmpty(scanResult.SSID)) {
            // 扫描结果的 SSID 为空
            noValidSsid.append(scanResult.BSSID).append(" / ");
            continue;
        }

        // 检查扫描结果是否与当前连接的 BSSID 相同
        if (currentBssids.contains(scanResult.BSSID)) {
            scanResultPresentForCurrentBssids.add(scanResult.BSSID);
            validScanDetails.add(scanDetail);
            continue;
        }

        final String scanId = toScanId(scanResult);

        if (bssidBlocklist.contains(scanResult.BSSID)) {
            // 扫描结果的 BSSID 在黑名单中
            blockedBssid.append(scanId).append(" / ");
            numBssidFiltered++;
            continue;
        }

        // 跳过信号强度过低的网络
        if (isSignalTooWeak(scanResult)) {
            lowRssi.append(scanId);
            if (scanResult.is24GHz()) {
                lowRssi.append("(2.4GHz)");
            } else if (scanResult.is5GHz()) {
                lowRssi.append("(5GHz)");
            } else if (scanResult.is6GHz()) {
                lowRssi.append("(6GHz)");
            }
            lowRssi.append(scanResult.level).append(" / ");
            continue;
        }

        // 跳过不接受新连接的 BSS
        NetworkDetail networkDetail = scanDetail.getNetworkDetail();
        if (networkDetail != null) {
            if (networkDetail.getMboAssociationDisallowedReasonCode()
                    != MboOceConstants.MBO_OCE_ATTRIBUTE_NOT_PRESENT) {
                // MBO (无线接入点之间的无线管理和优化) 禁止关联 BSSID
                mWifiMetrics
                        .incrementNetworkSelectionFilteredBssidCountDueToMboAssocDisallowInd();
                mboAssociationDisallowedBssid.append(scanId).append("(")
                        .append(networkDetail.getMboAssociationDisallowedReasonCode())
                        .append(")").append(" / ");
                continue;
            }
        }

        // 跳过不符合管理员设置的 SSID 限制的网络
        if (adminSsidRestrictionSet) {
            WifiSsid ssid = scanResult.getWifiSsid();
            // 允许列表策略设置但网络不在列表中
            if (!adminSsidAllowlist.isEmpty() && !adminSsidAllowlist.contains(ssid)) {
                adminRestrictedSsid.append(scanId).append(" / ");
                continue;
            }
            // 拒绝列表策略设置但网络在列表中
            if (!admindSsidDenylist.isEmpty() && admindSsidDenylist.contains(ssid)) {
                adminRestrictedSsid.append(scanId).append(" / ");
                continue;
            }
        }

        // 跳过不符合管理员设置的最低安全级别限制的网络
        if (adminMinimumSecurityLevel != 0) {
            boolean securityRestrictionPassed = false;
            @WifiInfo.SecurityType int[] securityTypes = scanResult.getSecurityTypes();
            for (int type : securityTypes) {
                int securityLevel = WifiInfo.convertSecurityTypeToDpmWifiSecurity(type);

                // 跳过未知安全类型,因为无法确定安全级别
                // 如果所有安全类型都未知,并且设置了最低安全级别限制,则忽略扫描结果
                if (securityLevel == WifiInfo.DPM_SECURITY_TYPE_UNKNOWN) continue;

                if (adminMinimumSecurityLevel <= securityLevel) {
                    securityRestrictionPassed = true;
                    break;
                }
            }
            if (!securityRestrictionPassed) {
                adminRestrictedSsid.append(scanId).append(" / ");
                continue;
            }
        }

        validScanDetails.add(scanDetail);
    }
    mWifiMetrics.incrementNetworkSelectionFilteredBssidCount(numBssidFiltered);

    // WNS 监听所有单次扫描结果。
    // 有些扫描请求可能不包含当前连接网络的频道,
    // 所以当前连接的网络不会出现在扫描结果中。
    // 为了避免触发断开连接的频繁网络切换,不处理这些扫描结果。
    // TODO:这可能不再需要(待修复的 bug)。
    for (ClientModeManagerState cmmState : cmmStates) {
        if (cmmState.connected && cmmState.wifiInfo.getScore() >= WIFI_POOR_SCORE
                && !scanResultPresentForCurrentBssids.contains(cmmState.wifiInfo.getBSSID())) {
            localLog("Current connected BSSID " + cmmState.wifiInfo.getBSSID()
                    + " is not in the scan results. Skip network selection.");
            validScanDetails.clear();
            return validScanDetails;
        }
    }

    if (noValidSsid.length() != 0) {
        localLog("Networks filtered out due to invalid SSID: " + noValidSsid);
    }

    if (blockedBssid.length() != 0) {
        localLog("Networks filtered out due to blocklist: " + blockedBssid);
    }

    if (lowRssi.length() != 0) {
        localLog("Networks filtered out due to low signal strength: " + lowRssi);
    }

    if (mboAssociationDisallowedBssid.length() != 0) {
        localLog("Networks filtered out due to mbo association disallowed indication: "
                + mboAssociationDisallowedBssid);
    }

    if (adminRestrictedSsid.length() != 0) {
        localLog("Networks filtered out due to admin restrictions: " + adminRestrictedSsid);
    }

    return validScanDetails;
}

上面已经返回一个Candidates的范围了,所以在继续回到WCM里面看下面的代码
http://aospxref.com/android-13.0.0_r3/xref/packages/modules/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);
}

// 更新最后一次网络选择的时间戳
mLastNetworkSelectionTimeStamp = mClock.getElapsedSinceBootMillis();

// 更新最后一次可用网络的信息
mWifiLastResortWatchdog.updateAvailableNetworks(
        mNetworkSelector.getConnectableScanDetails());

// 统计扫描结果
mWifiMetrics.countScanResults(scanDetails);

// 如果没有候选网络,提前返回
if (candidates == null || candidates.size() == 0) {
    localLog(listenerName + ": 没有候选网络");
    handleScanResultsWithNoCandidate(handleScanResultsListener);
    return;
}
// 如果设备支持STA + STA并且允许OEM有偿/私有网络连接请求
if ((mOemPaidConnectionAllowed || mOemPrivateConnectionAllowed)
        && mActiveModeWarden.isStaStaConcurrencySupportedForRestrictedConnections()) {
    // 根据是否是OEM有偿/私有网络将候选网络进行分组
    Map<Boolean, List<WifiCandidates.Candidate>> candidatesPartitioned =
            candidates.stream()
                    .collect(Collectors.groupingBy(c -> c.isOemPaid() || c.isOemPrivate()));
    List<WifiCandidates.Candidate> primaryCmmCandidates =
            candidatesPartitioned.getOrDefault(false, Collections.emptyList());
    List<WifiCandidates.Candidate> secondaryCmmCandidates =
            candidatesPartitioned.getOrDefault(true, Collections.emptyList());
    // 如果存在OEM有偿/私有网络的候选项,则使用辅助CMM流程
    if (!secondaryCmmCandidates.isEmpty()) {
        handleCandidatesFromScanResultsUsingSecondaryCmmIfAvailable(
                listenerName, primaryCmmCandidates, secondaryCmmCandidates,
                handleScanResultsListener);
        return;
    }
    // 没有OEM有偿/私有网络的候选项,回退到传统流程
}

// 如果存在双互联网网络请求并且设备支持STA + STA
if (hasMultiInternetConnection() && mMultiInternetManager.hasPendingConnectionRequests()) {
    // 尝试连接到多互联网网络
    if (handleConnectToMultiInternetConnectionInternal(candidates,
            listenerName, handleScanResultsListener)) {
        return;
    }
    // 没有多互联网连接的候选项,回退到传统流程
}

// 使用Mbb(主CMM)来处理主要的候选项  
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);
        // 使用Mbb(多模式并发)连接尝试连接到主要CMM的网络
        connectToNetworkForPrimaryCmmUsingMbbIfAvailable(candidate);
        // 处理扫描结果中找到了候选项
        handleScanResultsWithCandidate(handleScanResultsListener);
    } else {
        localLog(listenerName + ":  No candidate");
        // 处理扫描结果中没有找到候选项
        handleScanResultsWithNoCandidate(handleScanResultsListener);
    }
}

http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/service/java/com/android/server/wifi/WifiNetworkSelector.java#selectNetwork

/**
 * 从提供的候选项列表中选择最佳网络配置。
 *
 * @param candidates        候选项列表
 * @param overrideEnabled   是否允许用户连接选择覆盖
 * @return 最佳网络配置,如果未找到候选项,则返回null
 */
public WifiConfiguration selectNetwork(@NonNull List<WifiCandidates.Candidate> candidates,
        boolean overrideEnabled) {
    if (candidates == null || candidates.size() == 0) {
        return null;
    }

    // 创建WifiCandidates对象用于评分和选择候选项
    WifiCandidates wifiCandidates = new WifiCandidates(mWifiScoreCard, mContext, candidates);

    // 更新当前候选项的NetworkSelectionStatus
    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;
        WifiConfiguration config = mWifiConfigManager
                .getConfiguredNetwork(choice.candidateKey.networkId);
        if (config == null) continue;
        updateNetworkCandidateSecurityParams(config, scanDetail);
    }

    // 打印候选项按信号强度降序排列的日志
    for (Collection<WifiCandidates.Candidate> group : groupedCandidates) {
        for (WifiCandidates.Candidate candidate : group.stream()
                .sorted((a, b) -> (b.getScanRssi() - a.getScanRssi())) // 按信号强度降序排列
                .collect(Collectors.toList())) {
            localLog(candidate.toString());
        }
    }

    ArrayMap<Integer, Integer> experimentNetworkSelections = new ArrayMap<>(); // 用于度量

    int selectedNetworkId = WifiConfiguration.INVALID_NETWORK_ID;

    // 运行所有的CandidateScorers,在Android R的版本主要就是ThroughputScorer,这个S的代码不确定是否还有使用其他的CandidateScorers
    boolean legacyOverrideWanted = true;
    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;
        }
        //选出候选者后,拿到对应的网络ID
        int networkId = choice.candidateKey == null
                ? WifiConfiguration.INVALID_NETWORK_ID
                : choice.candidateKey.networkId;
        String chooses = " would choose ";
        if (candidateScorer == activeScorer) {
            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);
    }

    // 更新关于各种方法选择的差异的度量信息
    final int activeExperimentId = experimentIdFromIdentifier(activeScorer.getIdentifier());
    for (Map.Entry<Integer, Integer> entry :
            experimentNetworkSelections.entrySet()) {
        int experimentId = entry.getKey();
        if (experimentId == activeExperimentId) continue;
        int thisSelectedNetworkId = entry.getValue();
        mWifiMetrics.logNetworkSelectionDecision(experimentId, activeExperimentId,
                selectedNetworkId == thisSelectedNetworkId,
                groupedCandidates.size());
    }

    // 获取反映任何扫描结果更新的新的WifiConfiguration副本
    WifiConfiguration selectedNetwork =
            mWifiConfigManager.getConfiguredNetwork(selectedNetworkId);
    if (selectedNetwork != null && legacyOverrideWanted && overrideEnabled) {
        // 根据用户连接选择覆盖,如果需要,修改候选项的用户优先级
        selectedNetwork = overrideCandidateWithUserConnectChoice(selectedNetwork);
    }
    if (selectedNetwork != null) {
        mLastNetworkSelectionTimeStamp = mClock.getElapsedSinceBootMillis();
    }
    return selectedNetwork;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值