Android 7系统网络(五)Framework层(上)—ConnectivityService核心机制

系列目录第一篇:全景图与调用链路概览 | 第二篇:内核层---netfilter/iptables与路由策略 | 第三篇:Native层(上)---netd守护进程与CommandListener | 第四篇:Native层(下)---netd Controller详解 | 第五篇:Framework层(上)---ConnectivityService核心机制 | 第六篇:Framework层(下)---NMS/NPMS/NSS三大服务 | 第七篇:连接建立---WiFi/移动数据/以太网完整流程 | 第八篇:应用API层---ConnectivityManager使用与实战调试


一、ConnectivityService 概述

ConnectivityService 是 Framework 层最核心的网络服务,负责管理系统中所有网络连接的状态。如果把 Android 网络比作一座城市,ConnectivityService 就是交通调度中心------它决定哪个网络是"默认网络"、何时切换网络、如何处理应用的网络请求。

源码路径frameworks/base/services/core/java/com/android/server/ConnectivityService.java

核心职责:

职责 说明
管理 NetworkAgent 维护所有活跃网络连接(WiFi、移动数据、以太网等)的代理
评分与选择 比较各网络的评分,决定默认网络
处理 NetworkRequest 应用请求特定类型网络时的分配
网络切换 在可用网络之间自动切换
广播通知 发送 CONNECTIVITY_ACTION 广播
Legacy 类型支持 兼容旧的 TYPE_WIFI / TYPE_MOBILE API

二、启动流程

ConnectivityServiceSystemServer 中创建并启动。

源码路径frameworks/base/services/java/com/android/server/SystemServer.java

java 复制代码
// SystemServer.startOtherServices() 中
connectivity = new ConnectivityService(
        context, networkManagement, networkStats, networkPolicy);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
networkStats.bindConnectivityManager(connectivity);
networkPolicy.bindConnectivityManager(connectivity);

关键设计ConnectivityService 创建后先注册到 ServiceManager,再与 NetworkStatsServiceNetworkPolicyManagerService 双向绑定,systemReady() 在后续阶段单独调用。

ConnectivityService 构造函数中的初始化:

复制代码
new ConnectivityService()
    ├── 创建 InternalHandler(消息处理线程)
    ├── 创建 NetworkFactoryInfo 列表
    ├── 创建 NetworkAgentInfo 列表
    ├── 创建 NetworkRequestInfo 列表
    ├── 注册 NetworkFactory 的 Trackers
    └── 启动 LegacyTypeTracker

关键LegacyTypeTracker 在构造函数中初始化,负责维护 TYPE_WIFI / TYPE_MOBILE 等旧 API 类型到 NetworkAgentInfo 的映射。

这三个核心数据结构支撑了整个网络管理:

  • NetworkAgentInfo:每个活跃网络对应一个,包含类型、状态、评分、LinkProperties
  • NetworkRequestInfo:每个应用网络请求对应一个,包含请求的类型、回调等
  • NetworkFactoryInfo:每个 NetworkFactory 对应一个,用于生产新网络

三、核心数据结构

3.1 NetworkAgentInfo

源码路径frameworks/base/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java

java 复制代码
public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    public NetworkInfo networkInfo;              // 网络信息(类型、状态等)
    public final Network network;                // Network 对象
    public LinkProperties linkProperties;        // IP、网关、DNS 等
    public NetworkCapabilities networkCapabilities; // 网络能力
    public final NetworkMonitor networkMonitor;  // 网络连通性探测器
    public final NetworkMisc networkMisc;        // 网络杂项配置
    public boolean created;                      // 是否已在 netd 创建
    public boolean everConnected;                // 是否曾经连接过
    public boolean everValidated;                // 是否曾经验证通过
    public boolean lastValidated;                // 最后验证结果
    public boolean avoidUnvalidated;             // 是否避免未验证网络
    // ...
}

关键设计network 字段声明为 final,保证每个 NetworkAgentInfoNetwork 对象在构造后不再变化;createdeverConnected 是 sticky bit,一旦设置就不会清除。

3.2 NetworkCapabilities

源码路径frameworks/base/core/java/android/net/NetworkCapabilities.java

描述网络能做什么(不能做什么)。

java 复制代码
public final class NetworkCapabilities {
    // Transport 类型
    public static final int TRANSPORT_CELLULAR = 0;
    public static final int TRANSPORT_WIFI = 1;
    public static final int TRANSPORT_ETHERNET = 3;
    public static final int TRANSPORT_VPN = 4;
    // ...
    
    // 能力定义
    public static final int NET_CAPABILITY_INTERNET = 12;     // 能上互联网
    public static final int NET_CAPABILITY_NOT_METERED = 11;  // 不计流量
    public static final int NET_CAPABILITY_VALIDATED = 16;    // 已验证可上网
    // ...
}

关键设计TRANSPORT_* 描述网络的传输介质,NET_CAPABILITY_* 描述网络的能力,两者独立判断------一个 VPN 可以同时具备 TRANSPORT_VPNNET_CAPABILITY_INTERNET

3.3 NetworkRequest

源码路径frameworks/base/core/java/android/net/NetworkRequest.java

应用通过 NetworkRequest 描述它需要的网络类型:

java 复制代码
public class NetworkRequest {
    public NetworkCapabilities networkCapabilities; // 请求的网络能力
    public int legacyType;  // 旧 API 中的 TYPE_WIFI 等
    public int requestId;   // 唯一请求 ID
}

关键legacyType 用于兼容旧的 TYPE_WIFI / TYPE_MOBILE API,新代码应使用 networkCapabilities 描述需求。

应用构建请求的示例:

java 复制代码
NetworkRequest request = new NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .build();

connectivityManager.requestNetwork(request, callback);

关键Builder 模式的链式调用让应用可以精确描述网络需求,ConnectivityService 根据这些约束匹配最合适的网络。


四、网络评分与选择机制

4.1 整体流程

ConnectivityService 的核心算法是网络评分与匹配。当有新网络出现或有新请求时:

复制代码
触发条件(新网络建立 / 新请求到达 / 网络断开)
    ↓
rematchAllNetworksAndRequests()
    ↓
对每个 NetworkRequest,遍历所有 NetworkAgent
    ↓
找到评分最高、能力匹配的 NetworkAgent
    ↓
更新默认网络(如果最高分网络变化)
    ↓
通知 NetworkCallback(onAvailable / onLost / onCapabilitiesChanged)

关键rematchAllNetworksAndRequests() 是重匹配的入口,每次网络拓扑变化时调用,确保默认网络始终是评分最高且满足条件的那一个。

4.2 evalRequest --- 评分核心逻辑

源码路径frameworks/base/core/java/android/net/NetworkFactory.java

java 复制代码
private void evalRequest(NetworkRequestInfo n) {
    if (n.requested == false && n.score < mScore &&
            n.request.networkCapabilities.satisfiedByNetworkCapabilities(
            mCapabilityFilter) && acceptRequest(n.request, n.score)) {
        needNetworkFor(n.request, n.score);
        n.requested = true;
    } else if (n.requested == true &&
            (n.score > mScore || n.request.networkCapabilities.satisfiedByNetworkCapabilities(
            mCapabilityFilter) == false || acceptRequest(n.request, n.score) == false)) {
        releaseNetworkFor(n.request);
        n.requested = false;
    }
}

关键设计evalRequest 通过比较 n.score 与当前工厂的 mScore 决定是否需要此网络------请求的评分低于工厂评分时,工厂接手;请求评分高于工厂评分时,释放网络交给更高评分的工厂。

每个 NetworkFactory 根据自身类型给出基础评分:

网络类型 基础评分 说明
以太网 70 有线,最稳定
WiFi 60 无线局域网
移动数据(4G) 50 蜂窝网络
蓝牙共享 69 蓝牙网络共享

4.3 评分对比实例

假设设备同时连接了 WiFi 和移动数据:

复制代码
场景:用户开启 WiFi 并连接到路由器

NetworkAgent[WiFi].currentScore = 60
NetworkAgent[MOBILE].currentScore = 50

默认网络请求:
  - 遍历所有 NetworkAgent
  - WiFi: 60分,具备 INTERNET 能力 ✓
  - MOBILE: 50分,具备 INTERNET 能力 ✓
  - 最高分:WiFi (60)
  
结果:WiFi 成为默认网络,所有未绑定网络的应用走 WiFi

关键:评分比较是纯数值比较,不涉及网络类型偏好------只要 WiFi 评分高于移动数据,WiFi 就优先。

WiFi 断开时的切换:

复制代码
用户关闭 WiFi
    ↓
NetworkAgent[WiFi] 被移除
    ↓
rematchAllNetworksAndRequests()
    ↓
只剩 NetworkAgent[MOBILE] (50分)
    ↓
移动数据成为默认网络
    ↓
应用无感知切换(TCP 连接会断开需要重连)

关键 :切换本身对应用无感知(Socket 不会收到断开通知),但已建立的 TCP 连接会因路由变化而中断,应用需要在 onLost 回调中重建连接。

4.4 以太网接入时的抢占

当网线插入,以太网接口获得 IP 后,EthernetNetworkFactory 创建一个 NetworkAgent 并注册到 ConnectivityService

复制代码
以太网插入
    ↓
EthernetNetworkFactory 创建 NetworkAgent (score=70)
    ↓
ConnectivityService.registerNetworkAgent(ethernetAgent)
    ↓
rematchAllNetworksAndRequests()
    ↓
WiFi: 60分,MOBILE: 50分,Ethernet: 70分
    ↓
以太网成为新的默认网络
    ↓
应用流量切换到以太网出口

关键:以太网因有线连接的特性,评分最高(70),插入网线后会自动抢占 WiFi 的默认网络地位。


五、网络切换流程:WiFi 与 移动数据 全链路

5.1 WiFi 断开到移动数据接管

复制代码
WifiStateMachine 检测到 WiFi 断开
    ↓
WifiStateMachine 通知 ConnectivityService: network lost
    ↓
ConnectivityService.updateNetworkInfo()
    ↓
NetworkAgentInfo[WiFi].networkInfo.setState(DISCONNECTED)
    ↓
ConnectivityService.rematchAllNetworksAndRequests()
    ├── 遍历所有 NetworkAgent
    ├── WiFi 不可用,跳过
    ├── MOBILE 可用(score=50)
    └── 移动数据成为默认网络
    ↓
更新默认网络(updateDnses / addDefaultRoute)
    ↓
发送 CONNECTIVITY_ACTION 广播
    ↓
通知所有 NetworkCallback: onAvailable(MOBILE)

关键 :切换过程中 updateDnsesaddDefaultRoute 先执行,确保新网络的 DNS 和路由就绪后才发送广播,避免应用收到广播后发起请求时网络尚未配置完成。

5.2 新 WiFi 连接,从移动数据切换

复制代码
WifiStateMachine 建立 WiFi 连接(DHCP 获取 IP 后)
    ↓
创建 NetworkAgent(WiFi, score=60)
    ↓
ConnectivityService.registerNetworkAgent(wifiAgent)
    ↓
rematchAllNetworksAndRequests()
    ├── WiFi: 60分 → 最高分
    ├── MOBILE: 50分
    └── WiFi 成为默认网络
    ↓
更新路由:默认路由指向 wlan0
    ↓
更新 DNS:使用 WiFi 网络的 DNS 服务器
    ↓
发送 CONNECTIVITY_ACTION 广播
    ↓
移动数据降级(可能保持连接以便快速切换回来)

关键:移动数据降级后不会立即断开,而是保持连接以支持快速回切------这避免了因 WiFi 信号短暂波动导致的频繁切换。

5.3 Linger 机制

当一个高分网络可用时,低分网络不会立即断开,而是进入 Linger(暂缓)状态:

源码路径frameworks/base/services/core/java/com/android/server/ConnectivityService.java

java 复制代码
private void handleLingerComplete(NetworkAgentInfo oldNetwork) {
    if (oldNetwork == null) {
        loge("Unknown NetworkAgentInfo in handleLingerComplete");
        return;
    }
    oldNetwork.clearLingerState();
    if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) {
        teardownUnneededNetwork(oldNetwork);
    } else {
        updateCapabilities(oldNetwork.getCurrentScore(), oldNetwork,
                oldNetwork.networkCapabilities);
    }
}

关键设计handleLingerComplete 在 linger 超时后调用------如果旧网络仍有后台请求需要它,则保留但降级为后台网络;如果完全没有请求,则拆除网络。

Linger 的作用:给应用一些时间在新网络上建立连接,然后才断开旧网络,减少数据传输的中断时间。


六、默认网络的特殊性

默认网络是 Android 系统的特殊概念:未明确调用 bindProcessToNetwork() 的 Socket 自动走默认网络。

6.1 默认网络的切换流程

复制代码
ConnectivityService.setDefaultNetwork(netId)
    ↓
NetworkManagementService.setDefaultNetwork(netId)
    ↓ 通过 NativeDaemonConnector 发送:
    ↓ "network default set <netId>"
    ↓
netd 的 NetworkController.setDefaultNetwork()
    ↓
更新路由表中的默认路由
    ↓
应用流量切换到新网络

关键 :默认网络切换通过 netdnetwork default set 命令完成,netd 负责更新 fwmark 规则和路由表,Java 层不直接操作路由。

6.2 默认网络与绑定网络的关系

java 复制代码
// 绑定到 WiFi 的进程(如 VoIP 应用需要一直用 WiFi)
connectivityManager.bindProcessToNetwork(wifiNetwork);
// 此进程的所有 Socket 走 WiFi,不受默认网络切换影响

// 未绑定的进程
// 始终跟随默认网络,WiFi 断开后自动切到移动数据

关键bindProcessToNetwork() 通过 setsockopt(SO_MARK) 设置 Socket 的 fwmark,内核根据 fwmark 选择路由表,实现进程级别的网络绑定。


七、LegacyTypeTracker --- 旧 API 兼容

Android 7 中,旧的 TYPE_WIFI / TYPE_MOBILE API 仍被广泛应用。LegacyTypeTracker 负责维护新老 API 的映射:

源码路径frameworks/base/services/core/java/com/android/server/ConnectivityService.java

java 复制代码
private class LegacyTypeTracker {
    private static final boolean DBG = true;
    private static final boolean VDBG = false;
    private final SparseArray<NetworkAgentInfo> mTypeMap = new SparseArray<>();

    // 添加类型映射
    public void add(int type, NetworkAgentInfo nai) { ... }
    // 移除类型映射
    public void remove(int type, NetworkAgentInfo nai) { ... }
    // 获取指定类型的网络
    public NetworkAgentInfo getNetworkForType(int type) { ... }
}

关键mTypeMapSparseArray<NetworkAgentInfo>,以 int 类型的 TYPE_WIFI(1)/ TYPE_MOBILE(0)为 key,值是对应的 NetworkAgentInfo

当调用旧的 API 如 getNetworkInfo(TYPE_WIFI) 时,ConnectivityService 通过 LegacyTypeTracker 找到对应的 NetworkAgent 并返回信息。


八、CONNECTIVITY_ACTION 广播

网络变化时 ConnectivityService 发送广播通知所有应用:

源码路径frameworks/base/services/core/java/com/android/server/ConnectivityService.java

java 复制代码
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
if (info.isFailover()) {
    intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
}
if (info.getReason() != null) {
    intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
}
if (info.getExtraInfo() != null) {
    intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
}
sendStickyBroadcast(intent);

关键设计 :使用 Sticky Broadcast 确保新注册的 BroadcastReceiver 可以立刻收到最新的网络状态,而不需要等到下一次变化。同时通过 FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 防止未启动完成的应用过早收到广播。


九、小结

本篇覆盖了 ConnectivityService 的核心机制:

机制 关键方法/数据 作用
网络代理管理 NetworkAgentInfo 列表 跟踪所有活跃网络
评分与选择 rematchAllNetworksAndRequests() 决定默认网络
Linger 暂缓 handleLingerComplete() 减少切换影响
旧 API 兼容 LegacyTypeTracker TYPE_WIFI 等映射
广播通知 CONNECTIVITY_ACTION 通知应用网络变化

下一篇将深入 Framework 层的另外三大服务:NetworkManagementService(与 netd 通信)、NetworkPolicyManagerService(网络策略)、NetworkStatsService(流量统计)。

相关推荐
液态不合群1 小时前
卡死在生产流程?AI破解制造业数字化落地顽疾
网络·人工智能·低代码·重构
技术不好的崎鸣同学1 小时前
Windows 命令提示符(CMD)恶意脚本分析篇
网络·windows·安全·系统安全
m0_715674431 小时前
2026年医疗行业数据库风险监测产品综合能力排名分析
网络·数据库
apihz2 小时前
台风实时与历史详情查询免费 API 接口完整教程
android·开发语言·tcp/ip·dubbo·台风·天气预报
浪客川3 小时前
AOSP源码隐藏状态栏
android·aosp
阿米亚波3 小时前
【EVE-NG 实战】防火墙基础(VLAN · VRRP · NAT · ACL · 静态路由)
运维·网络·笔记·网络协议·计算机网络·网络安全·运维开发
零意@3 小时前
海光平台debian11的系统,打开pstore功能和验证功能
网络
没有了遇见3 小时前
AI Agent 是什么?—— 一文理解 LLM、Memory、Skills、Tools、MCP、Workflow,Context
android·前端·程序员
blueman88883 小时前
qt5-serialbus详细解析
开发语言·网络·qt
学究天人4 小时前
数学公理体系大全:Comprehensive Collection of Mathematical Axiom Systems(卷6)
网络·算法·数学建模·动态规划·几何学·图论·拓扑学