系列目录:第一篇:全景图与调用链路概览 | 第二篇:内核层—netfilter/iptables与路由策略 | 第三篇:Native层(上)—netd守护进程与CommandListener |第四篇:Native层(下)—netd Controller详解| 第五篇:Framework层(上)—ConnectivityService核心机制 | 第六篇:Framework层(下)—NMS/NPMS/NSS三大服务 | 第七篇:连接建立—WiFi/移动数据/以太网完整流程 | 第八篇:应用API层—ConnectivityManager使用与实战调试
一、Controller 层概述
如果说 CommandListener 是 netd 的"耳朵",Controller 层就是 netd 的"手"——所有实际的网络操作都在 Controller 中执行。
netd 内部有八类主要的 Controller:
CommandListener(命令接收) │ ├── NetworkController ← 网络接口管理 ├── RouteController ← 路由策略管理 ├── FirewallController ← 防火墙(UID过滤) ├── BandwidthController ← 带宽控制(流量限制) ├── TetherController ← 网络共享 ├── SoftapController ← WiFi热点管理 ├── IdletimerController ← 接口空闲检测 └── ResolverController ← DNS解析器管理每个 Controller 对应一类网络操作,由 CommandListener 的对应 Cmd 类转发调用。
二、NetworkController — 网络接口管理
源码路径:system/netd/server/NetworkController.cpp
NetworkController管理网络接口的生命周期:创建/销毁物理网络和虚拟网络、将接口绑定到指定网络、设置默认网络、管理网络权限。
核心方法:
intcreatePhysicalNetwork(unsignednetId,Permission permission);intcreateVirtualNetwork(unsignednetId,boolhasDns,boolsecure);intdestroyNetwork(unsignednetId);intaddInterfaceToNetwork(unsignednetId,constchar*interface);intremoveInterfaceFromNetwork(unsignednetId,constchar*interface);intsetDefaultNetwork(unsignednetId);关键设计:每个网络由
netId标识,接口通过addInterfaceToNetwork绑定到网络,而非直接操作接口属性。IP 地址配置由上层通过netd的interface命令间接完成。
以 WiFi 连接获取 IP 为例的调用过程:
NetworkController.createPhysicalNetwork(100, PERMISSION_SYSTEM) → 创建 netId=100 的物理网络 NetworkController.addInterfaceToNetwork(100, "wlan0") → 将 wlan0 接口绑定到 netId=100 NetworkController.setDefaultNetwork(100) → 设置 netId=100 为默认网络,后续路由走此网络关键:
netId范围是 100-65535(与ConnectivityService保持同步),物理网络和虚拟网络使用不同的创建方法。
三、RouteController — 路由策略管理
源码路径:system/netd/server/RouteController.cpp
RouteController是 Android 多网络并存的关键。它为每个网络(netId)创建独立的路由表,配置 fwmark 策略路由规则,管理 VPN 路由优先级,保护直连路由避免被默认路由覆盖。
核心方法:
staticintaddInterfaceToPhysicalNetwork(unsignednetId,constchar*interface,Permission permission);staticintremoveInterfaceFromPhysicalNetwork(unsignednetId,constchar*interface,Permission permission);staticintaddInterfaceToVirtualNetwork(unsignednetId,constchar*interface,boolsecure,constUidRanges&uidRanges);staticintremoveInterfaceFromVirtualNetwork(unsignednetId,constchar*interface,boolsecure,constUidRanges&uidRanges);staticintaddRoute(constchar*interface,constchar*destination,constchar*nexthop,TableType tableType);staticintremoveRoute(constchar*interface,constchar*destination,constchar*nexthop,TableType tableType);关键设计:
RouteController的所有方法都是static,不维护实例状态,直接操作内核路由表和策略规则。
fwmark 优先级表定义:
constuint32_tRULE_PRIORITY_VPN_OVERRIDE_SYSTEM=10000;constuint32_tRULE_PRIORITY_VPN_OVERRIDE_OIF=10500;constuint32_tRULE_PRIORITY_VPN_OUTPUT_TO_LOCAL=11000;constuint32_tRULE_PRIORITY_SECURE_VPN=12000;constuint32_tRULE_PRIORITY_PROHIBIT_NON_VPN=12500;constuint32_tRULE_PRIORITY_EXPLICIT_NETWORK=13000;constuint32_tRULE_PRIORITY_OUTPUT_INTERFACE=14000;constuint32_tRULE_PRIORITY_LEGACY_SYSTEM=15000;constuint32_tRULE_PRIORITY_LEGACY_NETWORK=16000;constuint32_tRULE_PRIORITY_LOCAL_NETWORK=17000;constuint32_tRULE_PRIORITY_TETHERING=18000;constuint32_tRULE_PRIORITY_IMPLICIT_NETWORK=19000;constuint32_tRULE_PRIORITY_BYPASSABLE_VPN=20000;constuint32_tRULE_PRIORITY_VPN_FALLTHROUGH=21000;constuint32_tRULE_PRIORITY_DEFAULT_NETWORK=22000;constuint32_tRULE_PRIORITY_DIRECTLY_CONNECTED=23000;constuint32_tRULE_PRIORITY_UNREACHABLE=32000;关键设计:优先级数值越小越优先,从 VPN(10000)到不可达(32000)共 16 级,覆盖了 VPN 覆盖、显式网络、传统网络、网络共享、直连路由等全部场景。
| 优先级常量 | 数值 | 用途 |
|---|---|---|
VPN_OVERRIDE_SYSTEM | 10000 | VPN 覆盖系统网络 |
VPN_OVERRIDE_OIF | 10500 | VPN 覆盖出口接口 |
VPN_OUTPUT_TO_LOCAL | 11000 | VPN 发往本地的流量 |
SECURE_VPN | 12000 | 安全 VPN(不允许绕过) |
PROHIBIT_NON_VPN | 12500 | 禁止非 VPN 流量 |
EXPLICIT_NETWORK | 13000 | 应用显式绑定的网络 |
DEFAULT_NETWORK | 22000 | 默认网络(较低优先级) |
关键:应用通过
bindProcessToNetwork()显式绑定的网络走EXPLICIT_NETWORK(13000),未绑定的 Socket 走DEFAULT_NETWORK(22000),确保显式绑定优先于默认路由。
典型设备上的 ip rule 输出:
iprule show# 0: from all lookup local# 10000: from all fwmark 0x3e8/0xc0000 lookup 1000 ← VPN 优先# 13000: from all fwmark 0x64/0x1ffff lookup 100 ← netId=100 (WiFi)# 13000: from all fwmark 0x65/0x1ffff lookup 101 ← netId=101 (移动数据)# 22000: from all fwmark 0x0/0x0 lookup 99 ← 默认关键:每个网络拥有独立的
fwmark标记和路由表,内核根据fwmark值选择对应的路由表进行查找,实现多网络流量隔离。
四、FirewallController — 防火墙
源码路径:system/netd/server/FirewallController.cpp
FirewallController基于 UID 控制应用的网络访问权限,通过 iptables 的-m owner --uid-owner匹配实现。
防火墙链定义:
constchar*LOCAL_INPUT="fw_INPUT";constchar*LOCAL_OUTPUT="fw_OUTPUT";constchar*LOCAL_FORWARD="fw_FORWARD";constchar*LOCAL_DOZABLE="fw_dozable";constchar*LOCAL_STANDBY="fw_standby";constchar*LOCAL_POWERSAVE="fw_powersave";关键设计:
fw_INPUT、fw_OUTPUT、fw_FORWARD是框架链,fw_dozable、fw_standby、fw_powersave是子链,子链通过setupIptablesHooks()按需挂载到框架链上。
| 链 | 触发条件 | 限制规则 |
|---|---|---|
fw_standby | 待机状态 | 限制后台应用的网络 |
fw_powersave | 省电模式 | 限制所有应用使用移动数据 |
fw_dozable | Doze 深度睡眠 | 严格限制网络访问 |
核心方法:
intsetFirewallUidRule(intchain,intuid,intrule);关键:防火墙支持 BLACKLIST 和 WHITELIST 两种模式,默认为黑名单模式。
对应的 iptables 操作:
# 禁止 UID 10086 使用 WiFiiptables-Ifw_standby-owlan0-mowner --uid-owner10086-jREJECT# 省电模式下禁止 UID 10086 使用移动数据iptables-Ifw_powersave-ormnet_data0-mowner --uid-owner10086-jREJECT关键:
fw_dozable链同时作用于 INPUT 和 OUTPUT,同时拦截接收和发送的 IPv6 邻居发现报文也会被放行,避免 Doze 模式导致 IPv6 完全不可用。
省电模式切换时的规则变化流程:
用户关闭屏幕 → Doze 模式 ↓ NetworkPolicyManagerService 判断是否进入省电 ↓ NetworkManagementService.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid, DENY) ↓ 通过 NativeDaemonConnector 向 netd 发送命令: ↓ "firewall set_uid_rule dozable <uid> deny" ↓ FirewallController 执行 iptables -I fw_dozable -m owner --uid-owner <uid> -j REJECT ↓ 该 UID 的应用发出的所有网络请求被拒绝关键:
FIREWALL_CHAIN_DOZABLE是 Java 层的枚举常量,对应 netd 侧的fw_dozable链,两层命名有差异但通过getFirewallChainName()映射。
五、BandwidthController — 带宽控制
源码路径:system/netd/server/BandwidthController.cpp
BandwidthController依赖内核的xt_qtaguid模块,控制网络的带宽使用限制:设置接口的配额限制(每天/每月流量上限)、设置全局警告阈值、限制特定 UID 的带宽。
xt_qtaguid的工作原理:
应用 (UID=10086) Socket.send() ↓ 内核 xt_qtaguid 模块 ├── 检查接口配额 → 未超 → 放行 │ → 已超 → DROP └── 更新统计计数 ↓ 统计数据写入 /proc/net/xt_qtaguid/stats ↓ NetworkStatsService 定期读取统计文件关键:
xt_qtaguid在内核协议栈中拦截每个数据包,统计和限额检查都在内核态完成,不存在用户态代理的性能开销。
核心命令:
# 启用带宽控制bandwidthenable# 设置接口配额(字节)bandwidth setiquota rmnet_data01073741824# 1GB# 设置全局警告阈值bandwidth setglobalalert943718400# 900MB 警告# 移除接口配额bandwidth removeiquota rmnet_data0# 设置接口告警(到达指定流量后告警)bandwidth setinterfacealert rmnet_data0524288000# 500MB 告警关键:配额和告警是独立的——配额超限会直接丢弃数据包,告警只产生通知事件,两者可以组合使用。
六、TetherController — 网络共享
源码路径:system/netd/server/TetherController.cpp
TetherController实现 USB 和 WiFi 网络共享功能,依赖三种技术:
| 技术 | 作用 |
|---|---|
| IP 转发 | 允许数据包从内网转发到外网 |
| iptables NAT (MASQUERADE) | 将内网 IP 替换为外网接口 IP |
| DHCP 服务器(dnsmasq) | 为连接的设备分配 IP 和 DNS |
启动网络共享的完整流程:
用户开启 WiFi 热点 ↓ ConnectivityManager.startTethering() ↓ NetworkManagementService.tetherInterface("wlan0") ↓ 向 netd 发送:tether interface add wlan0 ↓ TetherController::tetherInterface("wlan0") ├── 1. 启用 IP 转发:echo 1 > /proc/sys/net/ipv4/ip_forward ├── 2. 添加 NAT 规则:iptables -t nat -A POSTROUTING -o rmnet_data0 -j MASQUERADE ├── 3. 添加 FORWARD 规则 │ iptables -A FORWARD -i wlan0 -o rmnet_data0 -j ACCEPT │ iptables -A FORWARD -i rmnet_data0 -o wlan0 -m state --state ESTABLISHED,RELATED -j ACCEPT ├── 4. 配置 wlan0 的 IP:ifconfig wlan0 192.168.43.1 netmask 255.255.255.0 up └── 5. 启动 dnsmasq DHCP 服务器关键:FORWARD 链的
ESTABLISHED,RELATED规则只放行已建立连接的回包,确保外网设备无法主动向内网发起连接。
TetherController支持同时共享多个下游接口,通过mInterfaces列表管理。
七、SoftapController — WiFi 热点
源码路径:system/netd/server/SoftapController.cpp
SoftapController管理 WiFi 热点的软件配置。它不直接操作 WiFi 硬件(由hostapd负责),而是管理 AP 接口的创建与删除、SSID/密码/加密方式的配置、信道选择等。
与TetherController的协作关系:
SoftapController::startSoftap() ↓ 启动 hostapd,创建 AP Interface ↓ NetworkManagementService ↓ setIpForwardingEnabled(true) ↓ startTethering(["wlan0"]) → 调用 TetherController ↓ TetherController 配置 NAT + FORWARD 规则,启动 dnsmasq DHCP ↓ 网络共享可用关键:
SoftapController负责 WiFi 硬件的 AP 模式配置,TetherController负责 IP 层的 NAT 和 DHCP,两者职责分离,通过NetworkManagementService协调。
八、IdletimerController — 空闲检测
源码路径:system/netd/server/IdletimerController.cpp
IdletimerController监控网络接口的空闲状态。当接口在指定时间内没有流量时,触发告警。基于内核的xt_IDLETIMER模块实现。
典型使用场景是运营商要求数据连接在空闲一段时间后断开:
IdletimerController 监控 rmnet_data0,timeout = 600 秒 ├── 有流量 → 重置计时器 └── 10分钟无流量 → 触发告警 ↓ NetworkManagementService 收到空闲通知 ↓ ConnectivityService 断开移动数据连接关键:
xt_IDLETIMER通过/sys/class/net/<iface>/idletimer接口与用户态通信,计时器在内核中维护,没有用户态定时器的精度问题。
九、ndc 命令实战
ndc(Native Daemon Connector)是一个命令行工具,可以直接向netd发送命令:
# 列出所有网络接口ndc interface list# 查看防火墙状态ndc firewall is_enabled# 添加带宽控制接口ndc bandwidth setiquota rmnet_data01073741824# 查看 tether 状态ndc tether status# 添加路由ndc network routeadd100wlan00.0.0.0/0192.168.1.1关键:
ndc的命令格式与NativeDaemonConnector发送的协议完全一致,输出直接反映netd的内部状态,是调试网络问题的首选工具。
十、本篇总结
八大 Controller 各司其职,共同构成了netd的执行层:
| Controller | 操作内核对象 | 上层调用方 |
|---|---|---|
NetworkController | 网络接口(ioctl + netlink) | ConnectivityService |
RouteController | 路由表 + ip rule | ConnectivityService |
FirewallController | iptables (filter表) | NetworkPolicyManagerService |
BandwidthController | xt_qtaguid | NetworkPolicyManagerService |
TetherController | iptables (nat表) + dnsmasq | ConnectivityService |
SoftapController | hostapd 配置 | WifiStateMachine |
IdletimerController | xt_IDLETIMER | ConnectivityService |
ResolverController | DNS 服务器配置 | ConnectivityService |
每个 Controller 都是对特定内核机制的一层封装。下一篇将上升到 Framework 层,深入ConnectivityService的网络评分与切换机制。