系列目录 :第一篇:全景图与调用链路概览 | 第二篇:内核层---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 管理网络接口的生命周期:创建/销毁物理网络和虚拟网络、将接口绑定到指定网络、设置默认网络、管理网络权限。
核心方法:
cpp
int createPhysicalNetwork(unsigned netId, Permission permission);
int createVirtualNetwork(unsigned netId, bool hasDns, bool secure);
int destroyNetwork(unsigned netId);
int addInterfaceToNetwork(unsigned netId, const char* interface);
int removeInterfaceFromNetwork(unsigned netId, const char* interface);
int setDefaultNetwork(unsigned netId);
关键设计 :每个网络由
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 路由优先级,保护直连路由避免被默认路由覆盖。
核心方法:
cpp
static int addInterfaceToPhysicalNetwork(unsigned netId, const char* interface,
Permission permission);
static int removeInterfaceFromPhysicalNetwork(unsigned netId, const char* interface,
Permission permission);
static int addInterfaceToVirtualNetwork(unsigned netId, const char* interface, bool secure,
const UidRanges& uidRanges);
static int removeInterfaceFromVirtualNetwork(unsigned netId, const char* interface, bool secure,
const UidRanges& uidRanges);
static int addRoute(const char* interface, const char* destination, const char* nexthop,
TableType tableType);
static int removeRoute(const char* interface, const char* destination, const char* nexthop,
TableType tableType);
关键设计 :
RouteController的所有方法都是static,不维护实例状态,直接操作内核路由表和策略规则。
fwmark 优先级表定义:
cpp
const uint32_t RULE_PRIORITY_VPN_OVERRIDE_SYSTEM = 10000;
const uint32_t RULE_PRIORITY_VPN_OVERRIDE_OIF = 10500;
const uint32_t RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL = 11000;
const uint32_t RULE_PRIORITY_SECURE_VPN = 12000;
const uint32_t RULE_PRIORITY_PROHIBIT_NON_VPN = 12500;
const uint32_t RULE_PRIORITY_EXPLICIT_NETWORK = 13000;
const uint32_t RULE_PRIORITY_OUTPUT_INTERFACE = 14000;
const uint32_t RULE_PRIORITY_LEGACY_SYSTEM = 15000;
const uint32_t RULE_PRIORITY_LEGACY_NETWORK = 16000;
const uint32_t RULE_PRIORITY_LOCAL_NETWORK = 17000;
const uint32_t RULE_PRIORITY_TETHERING = 18000;
const uint32_t RULE_PRIORITY_IMPLICIT_NETWORK = 19000;
const uint32_t RULE_PRIORITY_BYPASSABLE_VPN = 20000;
const uint32_t RULE_PRIORITY_VPN_FALLTHROUGH = 21000;
const uint32_t RULE_PRIORITY_DEFAULT_NETWORK = 22000;
const uint32_t RULE_PRIORITY_DIRECTLY_CONNECTED = 23000;
const uint32_t RULE_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 输出:
bash
ip rule 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 匹配实现。
防火墙链定义:
cpp
const char* LOCAL_INPUT = "fw_INPUT";
const char* LOCAL_OUTPUT = "fw_OUTPUT";
const char* LOCAL_FORWARD = "fw_FORWARD";
const char* LOCAL_DOZABLE = "fw_dozable";
const char* LOCAL_STANDBY = "fw_standby";
const char* LOCAL_POWERSAVE = "fw_powersave";
关键设计 :
fw_INPUT、fw_OUTPUT、fw_FORWARD是框架链,fw_dozable、fw_standby、fw_powersave是子链,子链通过setupIptablesHooks()按需挂载到框架链上。
| 链 | 触发条件 | 限制规则 |
|---|---|---|
fw_standby |
待机状态 | 限制后台应用的网络 |
fw_powersave |
省电模式 | 限制所有应用使用移动数据 |
fw_dozable |
Doze 深度睡眠 | 严格限制网络访问 |
核心方法:
cpp
int setFirewallUidRule(int chain, int uid, int rule);
关键:防火墙支持 BLACKLIST 和 WHITELIST 两种模式,默认为黑名单模式。
对应的 iptables 操作:
bash
# 禁止 UID 10086 使用 WiFi
iptables -I fw_standby -o wlan0 -m owner --uid-owner 10086 -j REJECT
# 省电模式下禁止 UID 10086 使用移动数据
iptables -I fw_powersave -o rmnet_data0 -m owner --uid-owner 10086 -j REJECT
关键 :
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在内核协议栈中拦截每个数据包,统计和限额检查都在内核态完成,不存在用户态代理的性能开销。
核心命令:
bash
# 启用带宽控制
bandwidth enable
# 设置接口配额(字节)
bandwidth setiquota rmnet_data0 1073741824 # 1GB
# 设置全局警告阈值
bandwidth setglobalalert 943718400 # 900MB 警告
# 移除接口配额
bandwidth removeiquota rmnet_data0
# 设置接口告警(到达指定流量后告警)
bandwidth setinterfacealert rmnet_data0 524288000 # 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 发送命令:
bash
# 列出所有网络接口
ndc interface list
# 查看防火墙状态
ndc firewall is_enabled
# 添加带宽控制接口
ndc bandwidth setiquota rmnet_data0 1073741824
# 查看 tether 状态
ndc tether status
# 添加路由
ndc network route add 100 wlan0 0.0.0.0/0 192.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 的网络评分与切换机制。