Android 7系统网络(四)Native层(下)—netd Controller详解

系列目录第一篇:全景图与调用链路概览 | 第二篇:内核层---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 地址配置由上层通过 netdinterface 命令间接完成。

以 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_INPUTfw_OUTPUTfw_FORWARD 是框架链,fw_dozablefw_standbyfw_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 的网络评分与切换机制。

相关推荐
2603_954708311 小时前
全维度容错设计,打造微电网安全运行屏障
服务器·网络·数据库·人工智能·分布式·安全
青岛前景互联信息技术有限公司2 小时前
以新标准为底座,前景互联打造高危场景智能接处警新体系
大数据·网络·人工智能
大飞记Python2 小时前
Linux命令速查手册(测试开发4年实战总结,附PDF)
linux·网络·pdf
爱笑鱼3 小时前
Handler(一):post 之后,Runnable 到底在哪个线程执行?
android
Sirius Wu3 小时前
OpenClaw(UpClaw)三层Tool全链路治理深度详解
网络·人工智能·架构·aigc
源图客3 小时前
云途物流API开发-鉴权认证(Java)
java·网络·python
huashengzsj3 小时前
Shopify个人建站如何搭建独立站:从零开始的完整指南
前端·网络·人工智能
木木子223 小时前
[特殊字符] 音乐播放器——状态驱动的多媒体控制
android·开发语言·华为·php·harmonyos
雨白4 小时前
C 语言基础:结构体、联合体与枚举
android