Android R Wi-Fi 自动连接流程

该代码段展示了AndroidR系统如何处理Wi-Fi扫描结果,包括更新频道统计、处理用户禁用列表、检查BSSID状态、筛选候选网络并尝试连接。在连接过程中,会检查网络的有效性、避免重复连接,并处理漫游情况。最终目标是从扫描结果中选择最佳网络并发起连接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里我们选择Android R原生代码记录:http://aospxref.com/android-11.0.0_r21

主要流程在下面这个类里:
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
处理扫描结果:

   private boolean handleScanResults(List<ScanDetail> scanDetails, String listenerName,
        boolean isFullScan) {
    // 刷新频道统计信息和频道利用率
    mWifiChannelUtilization.refreshChannelStatsAndChannelUtilization(
            mStateMachine.getWifiLinkLayerStats(), WifiChannelUtilization.UNKNOWN_FREQ);

    // 更新用户禁用列表
    updateUserDisabledList(scanDetails);

    // 检查是否可以释放任何被列入阻止列表的BSSID
    mBssidBlocklistMonitor.tryEnablingBlockedBssids(scanDetails);   ---> 移除之前由于RSSI过低的AP
    Set<String> bssidBlocklist = mBssidBlocklistMonitor.updateAndGetBssidBlocklistForSsid(  ---> 时间到期的AP可以移除
            mWifiInfo.getSSID());

    // 检查supplicant是否处于转换阶段的状态,如果是则返回false
    if (mStateMachine.isSupplicantTransientState()) {
        localLog(listenerName
                + " onResults: No network selection because supplicantTransientState is "
                + mStateMachine.isSupplicantTransientState());
        return false;
    }

    localLog(listenerName + " onResults: start network selection");

    // 从扫描结果中获取候选网络列表
    List<WifiCandidates.Candidate> candidates = mNetworkSelector.getCandidatesFromScan(
            scanDetails, bssidBlocklist, mWifiInfo, mStateMachine.isConnected(),
            mStateMachine.isDisconnected(), mUntrustedConnectionAllowed);
    mLatestCandidates = candidates;
    mLatestCandidatesTimestampMs = mClock.getElapsedSinceBootMillis();

    // 在设备高移动性状态下进行候选网络筛选
    if (mDeviceMobilityState == WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT
            && mContext.getResources().getBoolean(
                    R.bool.config_wifiHighMovementNetworkSelectionOptimizationEnabled)) {
        candidates = filterCandidatesHighMovement(candidates, listenerName, isFullScan);
    }

    // 选择最佳的候选网络
    WifiConfiguration candidate = mNetworkSelector.selectNetwork(candidates);
    mLastNetworkSelectionTimeStamp = mClock.getElapsedSinceBootMillis();
    mWifiLastResortWatchdog.updateAvailableNetworks(
            mNetworkSelector.getConnectableScanDetails());
    mWifiMetrics.countScanResults(scanDetails);

    // 如果有候选网络,连接到网络并返回true
    if (candidate != null) {
        localLog(listenerName + ":  WNS candidate-" + candidate.SSID);
        connectToNetwork(candidate);   ----> 发起连接
        return true;
    } else {
        // 如果没有候选网络且Wi-Fi状态为断开状态,处理开放/未保存网络的扫描结果,并返回false
        if (mWifiState == WIFI_STATE_DISCONNECTED) {
            mOpenNetworkNotifier.handleScanResults(
                    mNetworkSelector.getFilteredScanDetailsForOpenUnsavedNetworks());
        }
        return false;
    }
}

总结下上面的代码做了这些事,最终目的就是选出候选网络 candidate,发起连接
1. 更新频道统计信息和频道利用率
2. 更新用户禁用列表
3. 尝试启用被阻止的BSSID
4. 获取当前网络的BSSID阻止列表
5. 检查supplicant是否处于临时状态(切状态),如果是,则返回false
6. 从扫描结果中获取候选网络列表
7. 更新最新的候选网络列表和时间戳
8. 如果设备处于高移动性状态且启用了高移动性网络选择优化,则对候选网络进行筛选
9. 选择最佳的候选网络
10. 更新网络选择的时间戳和可用网络列表
11. 记录扫描结果的统计信息
12. 如果有候选网络,则连接到网络并返回true
13. 如果没有候选网络且Wi-Fi状态为断开状态,则处理开放/未保存网络的扫描结果

接着看下对候选网络发起连接的流程:
private void connectToNetwork(WifiConfiguration candidate) {
    ScanResult scanResultCandidate = candidate.getNetworkSelectionStatus().getCandidate();

    // 检查候选网络的扫描结果是否有效
    if (scanResultCandidate == null) {
        localLog("connectToNetwork: bad candidate - " + candidate
                + " scanResult: " + scanResultCandidate);
        return;
    }

    String targetBssid = scanResultCandidate.BSSID;
    String targetAssociationId = candidate.SSID + " : " + targetBssid;

    // 检查是否已连接到目标BSSID或正在连接到目标BSSID,是就直接返回了
    if (targetBssid != null
            && (targetBssid.equals(mLastConnectionAttemptBssid)
                || targetBssid.equals(mWifiInfo.getBSSID()))
            && SupplicantState.isConnecting(mWifiInfo.getSupplicantState())) {
        localLog("connectToNetwork: Either already connected "
                + "or is connecting to " + targetAssociationId);
        return;
    }

    // 检查候选网络的BSSID是否与配置中指定的BSSID匹配
    if (candidate.BSSID != null
            && !candidate.BSSID.equals(ClientModeImpl.SUPPLICANT_BSSID_ANY)
            && !candidate.BSSID.equals(targetBssid)) {
        localLog("connecToNetwork: target BSSID " + targetBssid + " does not match the "
                + "config specified BSSID " + candidate.BSSID + ". Drop it!");
        return;
    }

    long elapsedTimeMillis = mClock.getElapsedSinceBootMillis();

    // 检查是否应该跳过连接尝试
    if (!mScreenOn && shouldSkipConnectionAttempt(elapsedTimeMillis)) {
        localLog("connectToNetwork: Too many connection attempts. Skipping this attempt!");
        mTotalConnectivityAttemptsRateLimited++;
        return;
    }
    noteConnectionAttempt(elapsedTimeMillis);

    mLastConnectionAttemptBssid = targetBssid;

    // 获取当前已连接的网络配置和关联信息
    WifiConfiguration currentConnectedNetwork = mConfigManager
            .getConfiguredNetwork(mWifiInfo.getNetworkId());
    String currentAssociationId = (currentConnectedNetwork == null) ? "Disconnected" :
            (mWifiInfo.getSSID() + " : " + mWifiInfo.getBSSID());

    // 如果当前已连接的网络与候选网络相同或存在关联,则进行漫游处理
    if (currentConnectedNetwork != null
            && (currentConnectedNetwork.networkId == candidate.networkId)) {
        // Framework仅在固件不支持漫游时启动漫游(例如,不支持{@link android.net.wifi.WifiManager#WIFI_FEATURE_CONTROL_ROAMING})
        if (mConnectivityHelper.isFirmwareRoamingSupported()) {
            // 目前仅用于验证固件漫游行为,日志保留在这里
            localLog("connectToNetwork: Roaming candidate - " + targetAssociationId + "."
                    + " The actual roaming target is up to the firmware.");
        } else {
            localLog("connectToNetwork: Roaming to " + targetAssociationId + " from "
                    + currentAssociationId);
            mStateMachine.startRoamToNetwork(candidate.networkId, scanResultCandidate);
        }
    } else {
        // 如果固件支持漫游或候选配置包含指定的BSSID,则指定连接目标BSSID
        if (mConnectivityHelper.isFirmwareRoamingSupported() && (candidate.BSSID == null
                  || candidate.BSSID.equals(ClientModeImpl.SUPPLICANT_BSSID_ANY))) {
            targetBssid = ClientModeImpl.SUPPLICANT_BSSID_ANY;
            localLog("connectToNetwork: Connect to " + candidate.SSID + ":" + targetBssid
                    + " from " + currentAssociationId);
        } else {
            localLog("connectToNetwork: Connect to " + targetAssociationId + " from "
                    + currentAssociationId);
        }
        mStateMachine.startConnectToNetwork(candidate.networkId, Process.WIFI_UID, targetBssid);   ---> 继续看这个
    }
}

总结下:
1. 获取候选网络的扫描结果。
2. 检查候选网络的有效性。
3. 获取目标BSSID和关联ID。
4. 检查是否已连接到目标BSSID或正在连接到目标BSSID,避免重复连接。
5. 检查候选网络的BSSID是否与配置中指定的BSSID匹配。
6. 检查是否应该跳过连接尝试,根据屏幕状态和连接尝试次数限制。
7. 记录连接尝试时间。
8. 更新最后一次连接尝试的BSSID。
9. 获取当前已连接的网络配置和关联信息。
10. 如果当前已连接的网络与候选网络相同或存在关联,则进行漫游处理(如果固件不支持漫游)。
11. 如果固件支持漫游或候选配置包含指定的BSSID,则指定连接目标BSSID。
12. 根据连接目标启动连接或漫游到网络。

http://aospxref.com/android-11.0.0_r21/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeImpl.java?fi=startConnectToNetwork#startConnectToNetwork
这个就是走到我们熟悉的连接流程了:

    public void startConnectToNetwork(int networkId, int uid, String bssid) {
        sendMessage(CMD_START_CONNECT, networkId, uid, bssid);
    }

自动连接流程,总结一句话就是从扫描结果中选取到符合的候选网络发起连接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值