android13 4G网络环境和wifi内网说明

1、采用4G模块实现上网,本质上就是把4G模块虚拟成网卡,然后让内核识别网卡,然后进行上网,这期间需要ril库实现android上层与模块的通信,但是我这边因为部分原因,实现不了,只能退而求其次,作为有线网卡,设备名称识别为eth1,则自动上网了,所有4G部分的逻辑全部舍弃掉,但是现有有一个问题,我本身自带一个eth0,系统网卡,一个wifi,然后是我的4G模块,正常逻辑的优先级逻辑是有线网卡> wifi > 4G网卡,现在因为4G网卡作为有线网卡挂载到系统,这个逻辑打破了,所以需要更改android的系统源码实现该逻辑,

1、找到有线网卡的系统评分文件

packages\modules\Connectivity\service-t\src\com\android\server\ethernet\EthernetNetworkFactory.java

cpp 复制代码
        private static NetworkScore getBestNetworkScore() {
			int score = 60; // 未知网口默认评分
			if ("eth0".equals(name)) {
				// 原生网口eth0:满分100,保持最高优先级
				score = 100;
			} else if ("eth1".equals(name)) {
				// 4G模块网口eth1:低分50,降低优先级(可根据需求调整,如40/60)
				score = 30;
			}			
            return new NetworkScore.Builder().setLegacyScore(score).build();
        }

默认4G模块的网络评分是30,有线网卡的评分是100,这时候就只需要该WiFi的评分了

wifi的评分文件在次

packages\modules\Wifi\service\java\com\android\server\wifi\WifiScoreCard.java和

packages\modules\Wifi\service\java\com\android\server\wifi\ClientModeImpl .java和

现在有两个问题,第一个wifi的评分和公网有关,是什么

cpp 复制代码
    /**
     * Updates the score card after IP configuration
     *
     * @param wifiInfo object holding relevant values
     */
    public void noteIpConfiguration(@NonNull ExtendedWifiInfo wifiInfo) {
        IfaceInfo ifaceInfo = getIfaceInfo(wifiInfo.getIfaceName());
        updatePerBssid(Event.IP_CONFIGURATION_SUCCESS, wifiInfo);
        updatePerNetwork(Event.IP_CONFIGURATION_SUCCESS, wifiInfo.getSSID(), wifiInfo.getRssi(),
                wifiInfo.getTxLinkSpeedMbps(), UNKNOWN_REASON, ifaceInfo);
        PerNetwork perNetwork = lookupNetwork(wifiInfo.getSSID());
        perNetwork.initBandwidthFilter(wifiInfo);
        ifaceInfo.attemptingSwitch = false;
        doWrites();
    }
cpp 复制代码
        /**
         * Estimates the probability of getting internet access, based on the
         * device experience.
         *
         * @return a probability, expressed as a percentage in the range 0 to 100
         */
        public int estimatePercentInternetAvailability() {
            // Initialize counts accoring to Laplace's rule of succession
            int trials = 2;
            int successes = 1;
            // Aggregate over all of the frequencies
            for (PerSignal s : mSignalForEventAndFrequency.values()) {
                switch (s.event) {
                    case IP_CONFIGURATION_SUCCESS:
                        if (s.elapsedMs != null) {
                            trials += s.elapsedMs.count;
                        }
                        break;
                    case VALIDATION_SUCCESS:
                        if (s.elapsedMs != null) {
                            successes += s.elapsedMs.count;
                        }
                        break;
                    default:
                        break;
                }
            }
            // Note that because of roaming it is possible to count successes
            // without corresponding trials.
            return Math.min(Math.max(Math.round(successes * 100.0f / trials), 0), 100);
        }

主要是这两个函数,下面是ai分析

你提供的是两段 Android WiFi 相关的 Java 代码,核心是WiFi 网络 IP 配置完成后的计分卡更新 ,以及基于设备使用经验估算 WiFi 网络的互联网可用概率,整体属于 WiFi 网络质量 / 可用性评估的核心逻辑,大概率来自 Android 系统的 WiFi 评分 / 网络诊断相关模块。

下面为你逐段解析代码的功能、核心逻辑、关键变量和设计思路,同时补充相关背景让你更好理解:

一、noteIpConfiguration 方法解析

核心功能

WiFi 设备完成IP 配置(获取到 IP 地址、网关、DNS 等网络参数)后,更新网络评分卡(score card)的核心方法,会同步更新 BSSID、网络(SSID)维度的统计信息,并重置接口切换状态、持久化数据。

逐行 / 关键逻辑解析

java

运行

复制代码
public void noteIpConfiguration(@NonNull ExtendedWifiInfo wifiInfo) {
    // 1. 根据WiFi接口名,获取对应的接口信息(包含接口状态、切换标记等)
    IfaceInfo ifaceInfo = getIfaceInfo(wifiInfo.getIfaceName());
    // 2. 按BSSID维度更新事件:记录IP配置成功的事件
    updatePerBssid(Event.IP_CONFIGURATION_SUCCESS, wifiInfo);
    // 3. 按网络(SSID)维度更新事件:传入IP配置成功事件+WiFi核心参数
    updatePerNetwork(Event.IP_CONFIGURATION_SUCCESS, wifiInfo.getSSID(), wifiInfo.getRssi(),
            wifiInfo.getTxLinkSpeedMbps(), UNKNOWN_REASON, ifaceInfo);
    // 4. 根据SSID查找该网络的持久化统计对象,初始化带宽过滤器(用于后续带宽统计)
    PerNetwork perNetwork = lookupNetwork(wifiInfo.getSSID());
    perNetwork.initBandwidthFilter(wifiInfo);
    // 5. 重置接口的「正在切换」标记:IP配置完成,说明接口切换(如有)已结束
    ifaceInfo.attemptingSwitch = false;
    // 6. 执行数据持久化:将本次更新的评分卡数据写入存储(避免进程重启丢失)
    doWrites();
}
关键参数 / 类说明
  1. ExtendedWifiInfo:系统扩展的 WiFi 信息类,继承自原生WifiInfo,新增了接口名、BSSID、自定义统计参数等;
  2. IfaceInfo:WiFi网络接口信息类 ,记录接口名、是否正在切换(attemptingSwitch)、接口状态等;
  3. Event.IP_CONFIGURATION_SUCCESS:枚举事件,代表「IP 配置成功」,是网络可用性评估的重要前置事件;
  4. 核心更新维度:
    • PerBssid:按BSSID(WiFi 热点的物理地址,一个 SSID 可能对应多个 BSSID,如双频路由器)统计;
    • PerNetwork:按SSID(WiFi 名称)统计,是用户感知的「网络维度」;
  5. 传入的 WiFi 参数:
    • Rssi:信号强度(负值,越接近 0 信号越好);
    • TxLinkSpeedMbps:传输链路速度(Mbps);
    • UNKNOWN_REASON:默认原因常量,代表本次事件无明确触发原因。

二、estimatePercentInternetAvailability 方法解析

核心功能

基于设备对当前 WiFi 网络的历史使用经验估算互联网访问的可用概率 ,返回0-100 的百分比(0 = 完全不可用,100 = 百分百可用),是 WiFi 网络质量评估的核心指标(比如系统选择 WiFi / 蜂窝网络、判断 WiFi 是否可用时会用到)。

设计核心:拉普拉斯继起法则(Laplace's rule of succession)

方法开头初始化的trials=2successes=1拉普拉斯平滑 的经典应用,解决小样本 / 无样本时的概率估算偏差问题:

  • 若网络无任何历史数据,默认概率为 1/2 = 50%,避免出现0/0的除零错误,也符合「未知网络默认有一定可用性」的实际场景;
  • 若有历史数据,平滑值的影响会随样本量增加而逐渐降低,最终概率趋近于真实的成功数/总尝试数
逐行 / 关键逻辑解析

java

运行

复制代码
public int estimatePercentInternetAvailability() {
    // 1. 拉普拉斯平滑初始化:避免无样本时除零,默认赋予基础尝试数和成功数
    int trials = 2;   // 总尝试数(分母)
    int successes = 1;// 成功数(分子)
    // 2. 遍历所有「事件+频率」对应的信号统计对象,聚合统计数据
    for (PerSignal s : mSignalForEventAndFrequency.values()) {
        switch (s.event) {
            // 2.1 匹配「IP配置成功」事件:计入「总尝试数」(IP配置是联网的前提)
            case IP_CONFIGURATION_SUCCESS:
                if (s.elapsedMs != null) { // 非空校验:确保有统计计数
                    trials += s.elapsedMs.count; // 累加IP配置成功的次数
                }
                break;
            // 2.2 匹配「验证成功」事件:计入「成功数」(验证成功=实际能访问互联网)
            case VALIDATION_SUCCESS:
                if (s.elapsedMs != null) {
                    successes += s.elapsedMs.count; // 累加互联网验证成功的次数
                }
                break;
            default:
                break;
        }
    }
    // 3. 注释说明:因漫游(roaming)可能出现「成功数>尝试数」(漫游后直接验证成功,无新IP配置)
    // 4. 计算概率并做边界限制:确保结果在0-100之间,四舍五入为整数
    return Math.min(Math.max(Math.round(successes * 100.0f / trials), 0), 100);
}
关键参数 / 类说明
  1. mSignalForEventAndFrequency:存储 **「事件 + 频率」与信号统计对象 ** 的映射集合,key 是「事件类型 + WiFi 频率(2.4G/5G/6G)」,value 是PerSignal
  2. PerSignal:WiFi 信号的统计类,记录对应事件的计数(count)、耗时(elapsedMs)等核心统计数据;
  3. s.elapsedMs.countelapsedMs是耗时统计对象,其count属性代表该事件发生的总次数
  4. 核心事件映射:
    • IP_CONFIGURATION_SUCCESS联网尝试的前提 → 计入总尝试数trials
    • VALIDATION_SUCCESS互联网验证成功 (系统会通过 ping / 访问校验地址等方式验证)→ 计入成功数successes
  5. 边界处理:Math.max(...,0) 避免负数,Math.min(...,100) 避免超过 100,符合「百分比」的定义。
概率计算示例
  1. 无历史数据trials=2,successes=11*100/2 = 50%
  2. 有历史数据 :假设 IP 配置成功 10 次,验证成功 8 次 → trials=2+10=12,successes=1+8=99*100/12=75%
  3. 漫游导致成功数 > 尝试数 :假设 IP 配置成功 2 次,验证成功 5 次 → trials=4,successes=66*100/4=150% → 被Math.min限制为100%

三、两段代码的关联关系

这两段代码是同一 WiFi 评分卡模块的上下游逻辑,关联紧密:

  1. noteIpConfiguration数据采集层 :IP 配置成功后,向评分卡中写入IP_CONFIGURATION_SUCCESS事件的计数,为后续概率计算提供「总尝试数」的数据源;
  2. estimatePercentInternetAvailability数据计算层 :从评分卡中读取IP_CONFIGURATION_SUCCESS(总尝试数)和VALIDATION_SUCCESS(成功数)的统计数据,结合拉普拉斯平滑计算互联网可用概率;
  3. 补充:VALIDATION_SUCCESS事件的写入逻辑未在代码中展示,其触发时机是IP 配置成功后,系统完成互联网访问验证(如 ping 通网关、访问 Google / 国内校验地址)。

四、核心设计亮点 & 业务背景

五、注意事项

  1. 多维度统计:按 BSSID/SSID/ 接口 / 频率分层统计,兼顾 WiFi 的物理特性(BSSID / 频率)和用户感知(SSID);

  2. 拉普拉斯平滑:解决小样本概率估算的经典方案,符合工程实践;

  3. 数据持久化doWrites() 保证统计数据不丢失,让概率估算基于长期使用经验;

  4. 边界安全:概率计算做 0-100 的限制,避免异常数据导致结果失效;

  5. 漫游兼容 :代码注释明确考虑了 WiFi 漫游的场景,兼容漫游时的统计偏差。

    要让内网通过 ClientModeImpl 的网络验证,核心是绕过外网检测逻辑,直接标记网络为「已验证有效」,以下是具体实现方案(基于代码逻辑推导):

    一、核心原理

    Android 网络验证的关键判断是 NetworkAgent.VALIDATION_STATUS_VALID(验证有效),内网验证失败的本质是系统检测不到外网连通性,因此只需强制触发「验证成功」的回调流程,跳过外网检测即可。

    二、具体实现方案(3 种优先级,从简单到彻底)

    方案 1:直接调用验证成功核心代码(最便捷)

    L3ConnectedState 状态的 enter() 方法中,添加验证成功的触发逻辑,内网连接后自动标记为已验证:

    java

    运行

    复制代码
    class L3ConnectedState extends State {
        @Override
        public void enter() {
            // 原有代码不变...
            registerConnected();
            mTargetWifiConfiguration = null;
            mWifiScoreReport.reset();
            mLastSignalLevel = -1;
            mIsAutoRoaming = false;
            mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
            mWifiLastResortWatchdog.connectedStateTransition(true);
            mWifiStateTracker.updateState(mInterfaceName, WifiStateTracker.CONNECTED);
            mWifiLockManager.updateWifiClientConnected(mClientModeManager, true);
            WifiConfiguration config = getConnectedWifiConfigurationInternal();
            mWifiScoreReport.startConnectedNetworkScorer(
                    mNetworkAgent.getNetwork().getNetId(), isRecentlySelectedByTheUser(config));
            updateLinkLayerStatsRssiAndScoreReport();
            mWifiScoreCard.noteIpConfiguration(mWifiInfo);
            mWifiMetrics.noteFirstL3ConnectionAfterBoot(true);
    
            // 新增:内网验证强制通过(核心代码)
            if (config != null) {
                // 1. 标记网络已验证可访问互联网(持久化到配置)
                mWifiConfigManager.setNetworkValidatedInternetAccess(config.networkId, true);
                // 2. 启用自动连接
                mWifiConfigManager.updateNetworkSelectionStatus(
                        config.networkId, WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE);
                // 3. 记录验证成功(更新评分卡,避免后续重复验证)
                mWifiScoreCard.noteValidationSuccess(mWifiInfo);
                // 4. 从黑名单移除(若之前被标记为无效)
                mWifiBlocklistMonitor.handleNetworkValidationSuccess(mLastBssid, mWifiInfo.getSSID());
                // 5. 通知监控器验证成功
                mCmiMonitor.onInternetValidated(mClientModeManager);
                Log.d(getTag(), "内网强制通过网络验证");
            }
        }
    }
    方案 2:修改验证状态回调(更彻底)

    WifiNetworkAgentCallbackonValidationStatus 方法中,强制将状态改为 VALID,无视系统检测结果:

    java

    运行

    复制代码
    private class WifiNetworkAgentCallback implements WifiNetworkAgent.Callback {
        @Override
        public void onValidationStatus(int status, @Nullable Uri redirectUri) {
            if (!isThisCallbackActive()) return;
            if (status == mLastNetworkStatus) return;
            
            // 新增:内网场景强制设为验证有效
            boolean isIntranet = true; // 可根据内网IP段(如192.168.x.x、10.x.x.x)判断,这里简化为true
            if (isIntranet) {
                status = NetworkAgent.VALIDATION_STATUS_VALID; // 强制标记为有效
                redirectUri = null; // 清除门户网络标记
            }
            
            mLastNetworkStatus = status;
            if (status == NetworkAgent.VALIDATION_STATUS_NOT_VALID) {
                unwantedNetwork(NETWORK_STATUS_UNWANTED_VALIDATION_FAILED);
            } else if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
                mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK);
                doNetworkStatus(status); // 触发验证成功流程
            }
            // 原有代码不变...
        }
    }
    方案 3:禁用网络验证检测(适合完全不需要验证的场景)

    直接注释 / 删除验证失败的处理逻辑,让系统无法触发「验证失败」的禁用流程:

  6. 找到 CMD_UNWANTED_NETWORK 分支中「验证失败」的处理代码,注释如下:

  7. java

    运行

    复制代码
    case CMD_UNWANTED_NETWORK: {
        if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
            // 原有逻辑不变...
        } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN
                || message.arg1 == NETWORK_STATUS_UNWANTED_VALIDATION_FAILED) {
            Log.d(getTag(), "忽略验证失败处理(内网模式)");
            // 注释掉以下验证失败的核心逻辑,避免网络被禁用
            /*
            WifiConfiguration config = getConnectedWifiConfigurationInternal();
            if (config != null) {
                if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN) {
                    mWifiConfigManager.setNetworkValidatedInternetAccess(config.networkId, false);
                    // ... 原有禁用逻辑 ...
                } else {
                    mWifiConfigManager.incrementNetworkNoInternetAccessReports(config.networkId);
                    // ... 原有临时禁用逻辑 ...
                }
            }
            */
        }
        break;
    }

    三、关键补充:内网 IP 段判断(可选,让逻辑更严谨)

    可在方案中添加内网 IP 判断,避免影响外网连接,示例代码:

    java

    运行

    复制代码
    // 判断当前IP是否为内网
    private boolean isIntranetIp() {
        InetAddress inetAddress = mWifiInfo.getInetAddress();
        if (inetAddress == null) return false;
        String ip = inetAddress.getHostAddress();
        // 内网IP段:10.0.0.0/8、172.16.0.0/12、192.168.0.0/16
        return ip.startsWith("10.") 
                || ip.startsWith("172.") && Integer.parseInt(ip.split("\\.")[1]) >=16 && Integer.parseInt(ip.split("\\.")[1]) <=31
                || ip.startsWith("192.168.");
    }

    将方案 1/2 中的 isIntranet = true 替换为 isIntranet = isIntranetIp() 即可。

    四、验证生效标志

    修改后,内网连接成功后满足以下条件,说明验证通过:

  8. mWifiConfigManager.getNetworkValidatedInternetAccess(config.networkId) 返回 true

  9. 网络不会被标记为 DISABLED_NO_INTERNET_TEMPORARY(临时禁用);

  10. 状态栏 WiFi 图标正常显示(无「无互联网」提示)。

  11. 仅修改 ClientModeImpl 即可,无需改动其他模块(如 ConnectivityService);

  12. 方案 1/2 不会影响外网连接(外网仍会走正常验证流程),方案 3 会完全禁用验证失败处理,仅适合纯内网场景;

  13. 若内网有门户认证(Captive Portal),需额外清除 mTermsAndConditionsUrl(方案 1 已包含)。

onValidationStatus 方法解析(内网适配核心)

该方法是 WifiNetworkAgentCallback 的核心回调,负责接收 NetworkAgent 上报的网络验证状态(有效 / 无效 / 门户网络),是内网绕过验证的关键改造点。

一、方法核心逻辑

验证状态 触发动作 内网适配关键
VALIDATION_STATUS_NOT_VALID(验证无效) 调用 unwantedNetwork 标记网络废弃,触发禁用 / 黑名单逻辑 需阻止该分支执行,避免内网被误判为无效
VALIDATION_STATUS_VALID(验证有效) 记录埋点、调用 doNetworkStatus 执行成功逻辑(启用自动连接、清除黑名单) 内网需强制走该分支,直接标记验证通过
检测到门户网络(redirectUri 非空) 标记门户状态,不触发成功 / 失败逻辑 内网无门户时可忽略,有内网门户需额外处理

二、内网适配改造方案(直接可用)

在原方法基础上添加 内网 IP 判断,强制让内网走验证成功逻辑,改造后代码如下:

java

运行

复制代码
public void onValidationStatus(int status, @Nullable Uri redirectUri) {
    if (!isThisCallbackActive()) return;
    if (status == mLastNetworkStatus) return;
    
    // 新增:内网IP判断(10.0.0.0/8、172.16.0.0/12、192.168.0.0/16)
    boolean isIntranet = isCurrentIpIntranet();
    if (isIntranet) {
        status = NetworkAgent.VALIDATION_STATUS_VALID; // 强制标记为验证有效
        redirectUri = null; // 清除门户网络标记(避免误判)
    }
    
    mLastNetworkStatus = status;
    if (status == NetworkAgent.VALIDATION_STATUS_NOT_VALID) {
        if (mVerboseLoggingEnabled) {
            logd("WifiNetworkAgent -> Wifi networkStatus invalid, score="
                    + mWifiInfo.getScore());
        }
        unwantedNetwork(NETWORK_STATUS_UNWANTED_VALIDATION_FAILED);
    } else if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
        if (mVerboseLoggingEnabled) {
            logd("WifiNetworkAgent -> Wifi networkStatus valid, score= "
                    + mWifiInfo.getScore());
        }
        mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK);
        doNetworkStatus(status); // 核心:执行验证成功逻辑
    }
    boolean captivePortalDetected = redirectUri != null
            && redirectUri.toString() != null
            && redirectUri.toString().length() > 0;
    if (captivePortalDetected) {
        Log.i(getTag(), "Captive Portal detected, status=" + status
                + ", redirectUri=" + redirectUri);
        mWifiConfigManager.noteCaptivePortalDetected(mWifiInfo.getNetworkId());
        mCmiMonitor.onCaptivePortalDetected(mClientModeManager);
        mCurrentConnectionDetectedCaptivePortal = true;
    }
}

// 新增:判断当前IP是否为内网(辅助方法)
private boolean isCurrentIpIntranet() {
    InetAddress inetAddress = mWifiInfo.getInetAddress();
    if (inetAddress == null) return false;
    String ip = inetAddress.getHostAddress();
    // 内网IP段匹配
    return ip.startsWith("10.")
            || (ip.startsWith("172.") && Integer.parseInt(ip.split("\\.")[1]) >= 16 && Integer.parseInt(ip.split("\\.")[1]) <= 31)
            || ip.startsWith("192.168.");
}

三、改造关键说明

强制验证有效 :通过 isCurrentIpIntranet() 判断内网 IP 后,直接将 status 设为 VALIDATION_STATUS_VALID,跳过无效逻辑; 清除门户标记 :内网无门户时,置空 redirectUri 避免触发门户网络处理; 不影响外网:外网 IP 会走原逻辑,仅内网触发强制通过,兼容性拉满;

四、验证生效标志

改造后内网连接时,该方法会输出日志 WifiNetworkAgent -> Wifi networkStatus valid,且:

  1. mWifiConfigManager.getNetworkValidatedInternetAccess(config.networkId) 返回 true
  2. 网络不会被标记为 DISABLED_NO_INTERNET_TEMPORARY
  3. 状态栏 WiFi 无「无互联网」提示,内网可正常使用。
    • 自动联动成功逻辑doNetworkStatus 会调用后续验证成功流程(启用自动连接、清除黑名单、持久化验证状态),无需额外修改。
相关推荐
Linux运维技术栈2 小时前
Magento 2.3.5 宝塔Linux环境完整安装指南(避坑版+图文详解)
linux·运维·服务器
CS创新实验室2 小时前
《计算机网络》深入学:自治系统 (Autonomous System)
网络·计算机网络
酣大智2 小时前
FTP--文件传输协议
运维·网络·网络协议·tcp/ip·华为
古月-一个C++方向的小白2 小时前
Linux——命令行参数与环境变量
linux·运维
gaize12132 小时前
服务器核心功能与应用场景全解析
服务器
qinyia2 小时前
使用AI助手完成服务器系统备份迁移任务
linux·运维·服务器
乐迪信息2 小时前
乐迪信息:AI防爆摄像机的船舶船体烟火智能预警系统
大数据·网络·人工智能·算法·无人机
hoududubaba2 小时前
ORAN C平面传输和基本功能——Section Type 4:slot配置控制
网络·网络协议
知行合一。。。2 小时前
Linux--10---crontab -e定时任务
java·linux·运维