第八板块:Android 网络体系与连接管理 | 第二十二篇:ConnectivityService 与 Netd 网络架构

第八板块:Android 网络体系与连接管理 | 第二十二篇:ConnectivityService 与 Netd 网络架构

所属板块:第八板块 --- Android 网络体系与连接管理

前置知识:第二十一篇中的存储体系、Linux 内核网络栈(Netfilter/iptables)、Binder IPC、SELinux 安全上下文

本篇定位 :这是 Android 设备连接世界的神经网络 。如果说应用进程是孤岛,那么 ConnectivityService 就是路由中枢Netd 就是边界网关 。本篇将彻底拆解 Network Stack 的分层架构、ConnectivityService 的网络评分(Network Score)机制Netd (Network Daemon) 的命令执行流水线策略路由(Policy Routing)与 iptables 防火墙VPN 的路由劫持 。我们将深入 Kernel Network StackNative DaemonFramework Service,揭示 Android 如何在复杂的网络环境中(Wi-Fi/蜂窝/以太网/VPN)选择最优路径并确保安全。全程无网络请求代码、无抓包教程,仅保留 Android 网络管理的底层定义与系统级调度规范。


1. 核心结论先行(Thesis Statement)

Android 的网络管理是一个基于评分的动态路由系统

  • ConnectivityService 的本质网络仲裁者 。它运行在 System Server 中,监控所有可用的网络(Wi-Fi, Cellular, Ethernet),根据 NetworkCapabilitiesNetworkScore 决定哪个网络是默认出口(Default Route)
  • Netd 的本质内核配置的执行者。它是一个 Native 守护进程,作为 Framework 与 Kernel 之间的桥梁,负责执行具体的网络操作:设置 IP 地址、配置路由表、刷新 DNS、操作 iptables 规则。
  • 网络评分的本质多维度的权重计算。系统不仅看网络快慢(Bandwidth),还看成本(Metered)、可靠性(Congested)和信任度(Trusted)。
  • 策略路由的本质多路由表共存 。Android 不使用单一的 main 路由表,而是为不同场景(默认、VPN、多用户)创建独立的路由表,并通过 ip rule 决定数据包走哪张表。

2. 网络架构全景图

2.1 从应用 Socket 到物理网卡

#mermaid-svg-tU14S9Uvo42wJNjf{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tU14S9Uvo42wJNjf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tU14S9Uvo42wJNjf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tU14S9Uvo42wJNjf .error-icon{fill:#552222;}#mermaid-svg-tU14S9Uvo42wJNjf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tU14S9Uvo42wJNjf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tU14S9Uvo42wJNjf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tU14S9Uvo42wJNjf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tU14S9Uvo42wJNjf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tU14S9Uvo42wJNjf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tU14S9Uvo42wJNjf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tU14S9Uvo42wJNjf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tU14S9Uvo42wJNjf .marker.cross{stroke:#333333;}#mermaid-svg-tU14S9Uvo42wJNjf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tU14S9Uvo42wJNjf p{margin:0;}#mermaid-svg-tU14S9Uvo42wJNjf .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-tU14S9Uvo42wJNjf .cluster-label text{fill:#333;}#mermaid-svg-tU14S9Uvo42wJNjf .cluster-label span{color:#333;}#mermaid-svg-tU14S9Uvo42wJNjf .cluster-label span p{background-color:transparent;}#mermaid-svg-tU14S9Uvo42wJNjf .label text,#mermaid-svg-tU14S9Uvo42wJNjf span{fill:#333;color:#333;}#mermaid-svg-tU14S9Uvo42wJNjf .node rect,#mermaid-svg-tU14S9Uvo42wJNjf .node circle,#mermaid-svg-tU14S9Uvo42wJNjf .node ellipse,#mermaid-svg-tU14S9Uvo42wJNjf .node polygon,#mermaid-svg-tU14S9Uvo42wJNjf .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-tU14S9Uvo42wJNjf .rough-node .label text,#mermaid-svg-tU14S9Uvo42wJNjf .node .label text,#mermaid-svg-tU14S9Uvo42wJNjf .image-shape .label,#mermaid-svg-tU14S9Uvo42wJNjf .icon-shape .label{text-anchor:middle;}#mermaid-svg-tU14S9Uvo42wJNjf .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tU14S9Uvo42wJNjf .rough-node .label,#mermaid-svg-tU14S9Uvo42wJNjf .node .label,#mermaid-svg-tU14S9Uvo42wJNjf .image-shape .label,#mermaid-svg-tU14S9Uvo42wJNjf .icon-shape .label{text-align:center;}#mermaid-svg-tU14S9Uvo42wJNjf .node.clickable{cursor:pointer;}#mermaid-svg-tU14S9Uvo42wJNjf .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-tU14S9Uvo42wJNjf .arrowheadPath{fill:#333333;}#mermaid-svg-tU14S9Uvo42wJNjf .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-tU14S9Uvo42wJNjf .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-tU14S9Uvo42wJNjf .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tU14S9Uvo42wJNjf .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-tU14S9Uvo42wJNjf .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tU14S9Uvo42wJNjf .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-tU14S9Uvo42wJNjf .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-tU14S9Uvo42wJNjf .cluster text{fill:#333;}#mermaid-svg-tU14S9Uvo42wJNjf .cluster span{color:#333;}#mermaid-svg-tU14S9Uvo42wJNjf div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tU14S9Uvo42wJNjf .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-tU14S9Uvo42wJNjf rect.text{fill:none;stroke-width:0;}#mermaid-svg-tU14S9Uvo42wJNjf .icon-shape,#mermaid-svg-tU14S9Uvo42wJNjf .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tU14S9Uvo42wJNjf .icon-shape p,#mermaid-svg-tU14S9Uvo42wJNjf .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-tU14S9Uvo42wJNjf .icon-shape .label rect,#mermaid-svg-tU14S9Uvo42wJNjf .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tU14S9Uvo42wJNjf .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tU14S9Uvo42wJNjf .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tU14S9Uvo42wJNjf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 外部网络
Linux 内核
Native 层
System Server
应用进程
Socket
决策
Binder IPC
路由劫持
配置
配置
配置
syscall/ioctl
IP Packet
App (HTTP Request)
ConnectivityService
NetworkManagementService
VpnManagerService
Netd (Network Daemon)
dnsmasq (DNS 服务)
Virtual Switch (veth)
Netfilter/iptables
Routing Tables (main/100/200)
Physical NIC (wlan0/rmnet0)
Wi-Fi AP
基站

2.2 核心组件职责表

组件 层级 职责 学术定义
ConnectivityService Framework 仲裁者 管理 NetworkAgent,计算 NetworkScore,切换默认网络。
NetworkAgent Framework 代理 每个网络连接的代表(如 Wi-Fi Agent, Cell Agent),向 CS 汇报状态。
Netd Native 执行者 接收 Framework 命令,通过 syscall 配置内核网络参数。
NetworkManagementService Framework 接口 封装与 Netd 的 Binder 通信。
Netfilter (iptables) Kernel 防火墙 过滤数据包,实现 NAT、端口重定向、流量统计。

3. ConnectivityService 的评分机制

3.1 网络评分(Network Score)

系统通过 NetworkCapabilitiesNetworkScore 来评估网络质量。

学术定义

  • Transport Type: 传输类型(Wi-Fi, Cellular, Ethernet, Bluetooth)。
  • Capability: 能力(Internet, Not Metered, Trusted, Not Congested)。
  • Signal Strength: 信号强度(Wi-Fi RSSI, Cell Signal)。

3.2 评分算法

ConnectivityService 维护一个 NetworkRanker

网络类型 基础分 扣分因素 结果
Ethernet 70 70 (最高)
Wi-Fi 60 信号弱 (-10), 计费 (-20) 30 - 60
Cellular (LTE) 50 计费 (-20), 漫游 (-30) 0 - 30
VPN 40 依赖底层网络 继承底层

决策逻辑

  1. 当 Wi-Fi 连接时,CS 计算 Wi-Fi 得分(例如 55)。
  2. CS 比较 Wi-Fi (55) 和 Cellular (20)。
  3. Wi-Fi 胜出,CS 命令 Netd 将默认路由切换到 wlan0

3.3 网络切换(Handover)

当 Wi-Fi 断开时,CS 会无缝切换到 Cellular。
Kernel Netd ConnectivityService 应用 Kernel Netd ConnectivityService 应用 #mermaid-svg-QVXLUkbzplRfjUvy{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QVXLUkbzplRfjUvy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QVXLUkbzplRfjUvy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QVXLUkbzplRfjUvy .error-icon{fill:#552222;}#mermaid-svg-QVXLUkbzplRfjUvy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QVXLUkbzplRfjUvy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QVXLUkbzplRfjUvy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QVXLUkbzplRfjUvy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QVXLUkbzplRfjUvy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QVXLUkbzplRfjUvy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QVXLUkbzplRfjUvy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QVXLUkbzplRfjUvy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QVXLUkbzplRfjUvy .marker.cross{stroke:#333333;}#mermaid-svg-QVXLUkbzplRfjUvy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QVXLUkbzplRfjUvy p{margin:0;}#mermaid-svg-QVXLUkbzplRfjUvy .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QVXLUkbzplRfjUvy text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-QVXLUkbzplRfjUvy .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-QVXLUkbzplRfjUvy .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-QVXLUkbzplRfjUvy .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-QVXLUkbzplRfjUvy .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-QVXLUkbzplRfjUvy #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-QVXLUkbzplRfjUvy .sequenceNumber{fill:white;}#mermaid-svg-QVXLUkbzplRfjUvy #sequencenumber{fill:#333;}#mermaid-svg-QVXLUkbzplRfjUvy #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-QVXLUkbzplRfjUvy .messageText{fill:#333;stroke:none;}#mermaid-svg-QVXLUkbzplRfjUvy .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QVXLUkbzplRfjUvy .labelText,#mermaid-svg-QVXLUkbzplRfjUvy .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-QVXLUkbzplRfjUvy .loopText,#mermaid-svg-QVXLUkbzplRfjUvy .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-QVXLUkbzplRfjUvy .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-QVXLUkbzplRfjUvy .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-QVXLUkbzplRfjUvy .noteText,#mermaid-svg-QVXLUkbzplRfjUvy .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-QVXLUkbzplRfjUvy .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QVXLUkbzplRfjUvy .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QVXLUkbzplRfjUvy .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QVXLUkbzplRfjUvy .actorPopupMenu{position:absolute;}#mermaid-svg-QVXLUkbzplRfjUvy .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-QVXLUkbzplRfjUvy .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QVXLUkbzplRfjUvy .actor-man circle,#mermaid-svg-QVXLUkbzplRfjUvy line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-QVXLUkbzplRfjUvy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Wi-Fi 断开 请求网络评估 Wi-Fi (Score: 55)设置默认路由 ->> wlan0网络可用 (Wi-Fi)评估 Cellular (Score: 20)删除 wlan0 路由设置默认路由 ->> rmnet0网络变更 (Cellular)


4. Netd 的执行流水线

4.1 Netd 的模块划分

Netd 是一个非常复杂的守护进程,包含多个模块。

模块 职责 学术定义
FirewallController 防火墙 管理 iptables 规则,控制应用联网权限。
RouteController 路由 管理路由表和 ip rule。
DnsController DNS 配置 DNS 服务器,管理 dnsmasq。
BandwidthController 带宽 流量统计和限速(Quota)。
NatController 地址转换 配置 SNAT/DNAT,实现热点共享。

4.2 命令执行流程

Framework 通过 Binder 向 Netd 发送命令字符串。

示例:设置默认路由

java 复制代码
// Framework 端
mNetdService.routeAdd("default", "wlan0", "192.168.1.1");

// Netd 端 (CommandListener.cpp)
void CommandListener::RouteCmd::runCommand(...) {
    if (strcmp(argv[1], "add") == 0) {
        // 调用 libcutils 或执行 iproute2 命令
        runIpRouteAdd(argv);
    }
}

// 实际执行的 shell 命令
ip route add default via 192.168.1.1 dev wlan0 table 100

5. 策略路由(Policy Routing)

5.1 多路由表机制

Android 不使用默认的 main 路由表,而是为不同场景创建独立的表。

路由表 ID 名称 用途
255 local 本地路由
254 main 系统默认(通常不用)
253 default 备用
100 wlan0 Wi-Fi 路由
200 rmnet0 蜂窝路由
61 oif 输出接口规则

5.2 ip rule 规则

ip rule 决定什么时候哪张表

学术定义

  • Rule: 匹配条件(源 IP、目标 IP、接口、fwmark)。
  • Lookup: 要查询的路由表。

Android 的典型规则

bash 复制代码
# 查看规则
ip rule show

# 输出:
0:      from all lookup local
10000:  from all fwmark 0xc0000/0xd0000 lookup legacy_system
13000:  from all fwmark 0x10063/0x1ffff lookup local_network
14000:  from all oif wlan0 lookup wlan0
15000:  from all oif rmnet0 lookup rmnet0
16000:  from all lookup main
17000:  from all lookup default

解释

  • 如果数据包来自 wlan0 接口,查表 wlan0
  • 如果数据包带有特定的 fwmark(防火墙标记),查表 legacy_system

6. 防火墙与 iptables

6.1 应用联网控制

当你在设置中禁止某个应用联网时,Netd 实际上是在操作 iptables。

学术定义

  • Owner Match : iptables 的 --uid-owner 模块,匹配数据包属于哪个 UID。
  • DROP: 丢弃数据包。

命令示例

bash 复制代码
# 禁止 UID 10001 (应用) 访问网络
iptables -A OUTPUT -m owner --uid-owner 10001 -j DROP

6.2 VPN 的路由劫持

VPN 的核心是将所有流量重定向到 VPN 隧道接口(tun0)。

学术定义

  • NAT (SNAT): 将源 IP 改为 VPN 服务器的 IP。
  • Routing: 添加默认路由指向 tun0。

Netd 操作

bash 复制代码
# 创建 tun0 接口
ip link add tun0 type tun
ip addr add 10.0.0.2/24 dev tun0

# 添加默认路由
ip route add default via 10.0.0.1 dev tun0 table 200

# 添加 ip rule
ip rule add from all table 200

7. 关键源码深度解析

7.1 ConnectivityService 的评分逻辑

java 复制代码
// frameworks/base/services/core/java/com/android/server/connectivity/ConnectivityService.java
private int evaluateNetworkScore(NetworkAgentInfo nai) {
    int score = nai.getCurrentScore();

    // 如果是计费网络,扣分
    if (nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED) == false) {
        score -= 20;
    }

    // 如果信号弱,扣分
    int signal = nai.getCurrentSignalStrength();
    if (signal < SIGNAL_STRENGTH_THRESHOLD) {
        score -= 10;
    }

    return score;
}

7.2 Netd 的 iptables 调用

cpp 复制代码
// system/netd/server/FirewallController.cpp
int FirewallController::setUidRule(int childChain, int uid, FirewallRule rule) {
    std::string command = "*filter\n";
    command += StringPrintf("-A %s -m owner --uid-owner %d -j %s\n",
                            chainName, uid, rule == ALLOW ? "ACCEPT" : "DROP");
    command += "COMMIT\n";

    // 通过 socket 发送给 iptables 进程
    sendCommand(command);
}

8. 网络管理的常见误区

误区 学术解释
Wi-Fi 一定比 4G 快 不一定。Wi-Fi 信号弱或有线拥塞时,评分可能低于 4G。
VPN 会影响所有流量 是的。VPN 通过路由劫持,强制所有流量走 tun0。
禁止应用联网就是关 Socket 不是。是通过 iptables 的 Owner Match 在 Kernel 层丢弃数据包。
多网卡可以叠加网速 Android 默认不支持。策略路由只能选一条默认路,除非应用自己绑定 Socket 到特定网卡。

9. 本篇总结(Knowledge Closure)

关键点 纯学术定义
ConnectivityService 的本质 网络仲裁者,基于 NetworkScore 动态选择默认路由。
Netd 的本质 内核配置执行者,通过 iptables 和 iproute2 配置网络。
策略路由 多路由表共存,通过 ip rule 实现基于条件的路由选择。
防火墙机制 基于 UID 的 iptables 过滤,实现应用级联网控制。
VPN 原理 路由劫持 + NAT,强制流量进入隧道接口。

10. 第八板块结语

至此,第八板块:Android 网络体系与连接管理 已全部完结。

我们从 ConnectivityService 的评分仲裁 出发,深入 Netd 的执行流水线 ,探索 策略路由与 iptables 防火墙 ,最终抵达 VPN 的路由劫持与多网卡管理

我们揭示了 Android 网络管理的核心逻辑:用评分选择最优路径,用策略路由隔离流量,用防火墙控制访问。

下一篇预告第九板块:Android 多媒体体系 | 第二十三篇:AudioFlinger 与 AudioPolicyService 音频架构

相关推荐
咖啡星人k1 小时前
MonkeyCode 后端架构全解析:Go微服务如何支撑万级并发AI任务
微服务·架构·golang·monkeycode
cjie2212 小时前
常用视频缩放架构
fpga开发·架构
大神15732 小时前
Cordova Android 签名三种方式详解:证书生成、命令行直接签名与配置文件自动签名
android·java
私人珍藏库2 小时前
【Android】压缩视频1.1.28-视频压缩-解放内存
android·app·工具·软件·多功能
踏雪羽翼2 小时前
android 实现文字打印机效果
android·前端·javascript
朱莉^_^JuneLee2 小时前
Flutter 模块化架构实战:用 Barrel Export 管控模块边界
flutter·架构
“码”力全开2 小时前
打通安防孤岛:基于 Docker 与 GB28181/RTSP 架构的 AI 视频管理平台,全源码交付解锁二次开发自主权
人工智能·docker·架构
IT探索2 小时前
服务器 BIOS 测试
运维·服务器·网络
hj2862512 小时前
Rsync 数据同步 + Inotify 实时监控 完整版实操笔记3
linux·运维·网络