Android Netd (Network Daemon) 完整架构分析
目录
1. 概述
1.1 什么是 Netd?
Netd (Network Daemon) 是 Android 系统的核心网络守护进程,运行在 Native 层(C++),负责执行所有底层网络配置和管理操作。它是连接 Android Framework (Java) 与 Linux Kernel 网络栈的关键桥梁。
1.2 基本信息
service netd /system/bin/netd
class main
capabilities CHOWN DAC_OVERRIDE DAC_READ_SEARCH FOWNER IPC_LOCK KILL
NET_ADMIN NET_BIND_SERVICE NET_RAW SETUID SETGID
user root
group root net_admin
socket dnsproxyd stream 0660 root inet
socket mdns stream 0660 root system
socket fwmarkd stream 0660 root inet
onrestart restart zygote
onrestart restart zygote_secondary
updatable
关键特性:
- 进程路径:
/system/bin/netd - 运行权限: root 用户,拥有
NET_ADMIN、NET_RAW等网络特权能力 - 启动时机: 系统启动早期,等待 APEX 模块加载完成
- 重要性: Netd 重启会导致 Zygote 重启(即整个应用层重启)
- 三个 Unix Socket: dnsproxyd, fwmarkd, mdns
2. 整体架构图
┌─────────────────────────────────────────────────────────────────────────┐
│ Android Application Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ Apps (Java) │ │ Browser │ │ Settings │ │ VPN Apps │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬──────┘ │
│ │ │ │ │ │
└─────────┼─────────────────┼──────────────────┼──────────────────┼────────┘
│ │ │ │
│ Binder │ Binder │ Binder │ Binder
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Android Framework (Java/Kotlin) │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ ConnectivityService │ │
│ │ • Network Selection • VPN Management │ │
│ │ • Network Monitoring • Captive Portal Detection │ │
│ │ • NetworkAgent Management • Network Callbacks │ │
│ └─────────────┬──────────────────────────────────────────────────────┘ │
│ │ │
│ │ (INetd AIDL) │
│ │ │
│ ┌─────────────▼──────────────────────────────────────────────────────┐ │
│ │ NetworkManagementService (NMS) │ │
│ │ • Facade Pattern • Interface Config │ │
│ │ • Event Observer • Route Management │ │
│ │ • Firewall Rules • NAT/Tethering │ │
│ │ • Bandwidth Control • IP Forwarding │ │
│ └─────────────┬──────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────▼──────────────────────────────────────────────────────┐ │
│ │ NetworkPolicyManagerService (NPMS) │ │
│ │ • Data Saver Mode • Metered Networks │ │
│ │ • Background Restrict • Firewall Chains (Dozable/Standby) │ │
│ │ • UID Firewall Rules • Network Quotas │ │
│ └────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
│
│ (AIDL Binder: INetd.aidl)
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Netd (Native Daemon - C++) │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ NetdNativeService │ │
│ │ • Binder Service (INetd.aidl) │ │
│ │ • API Entry Point for Framework │ │
│ │ • Permission Enforcement (NETWORK_STACK_PERMISSIONS) │ │
│ └─────────────┬──────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────▼──────────────────────────────────────────────────────┐ │
│ │ Controllers (gCtls) │ │
│ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │
│ │ │ Network │ │ Firewall │ │ Bandwidth │ │ │
│ │ │ Controller │ │ Controller │ │ Controller │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ • Network │ │ • iptables │ │ • Quota │ │ │
│ │ │ Create/Del │ │ Chains │ │ • Alert │ │ │
│ │ │ • Interface │ │ • UID Rules │ │ • Data Saver │ │ │
│ │ │ Add/Remove │ │ • Allowlist/ │ │ • Traffic │ │ │
│ │ │ • Default Net │ │ Denylist │ │ Counting │ │ │
│ │ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ │ │
│ │ │ │ │ │ │
│ │ ┌───────▼──────┐ ┌───────▼──────┐ ┌───────▼──────┐ │ │
│ │ │ Tether │ │ XFRM │ │ Strict │ │ │
│ │ │ Controller │ │ Controller │ │ Controller │ │ │
│ │ │ • Hotspot │ │ • IPsec VPN │ │ • StrictMode │ │ │
│ │ │ • NAT Rules │ │ • SA/Policy │ │ • TLS Detect │ │ │
│ │ │ • dnsmasq │ │ • XFRM NL │ │ │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ │ │ │
│ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │
│ │ │ Idletimer │ │ Wakeup │ │ Interface │ │ │
│ │ │ Controller │ │ Controller │ │ Controller │ │ │
│ │ │ • Idle Timer │ │ • Wakeup Pkt │ │ • Interface │ │ │
│ │ │ • Power Save │ │ • Logging │ │ Config │ │ │
│ │ └──────────────┘ └───────────────┘ └───────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ 三个 Unix Domain Socket 服务 │ │
│ │ │ │
│ │ ┌──────────────────┐ ┌─────────────────┐ ┌──────────────────┐ │ │
│ │ │ dnsproxyd │ │ fwmarkd │ │ mdns │ │ │
│ │ │ Socket Listener │ │ FwmarkServer │ │ MDnsService │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ Path: │ │ Path: │ │ Path: │ │ │
│ │ │ /dev/socket/ │ │ /dev/socket/ │ │ /dev/socket/mdns │ │ │
│ │ │ dnsproxyd │ │ fwmarkd │ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ • DNS Cache │ │ • SO_MARK │ │ • mDNS │ │ │
│ │ │ • Per-Net DNS │ │ • NetId Select │ │ • DNS-SD │ │ │
│ │ │ • DNS-over-TLS │ │ • VPN Bypass │ │ • *.local │ │ │
│ │ │ • Private DNS │ │ • Permission │ │ • Service Disc. │ │ │
│ │ └──────────────────┘ └─────────────────┘ └──────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ RouteController │ │
│ │ • Policy Routing (iproute2 rules) │ │
│ │ • Route Tables: local_network(97), legacy_network(98) │ │
│ │ • Fwmark-based Routing (per-app network selection) │ │
│ │ • Route Add/Update/Remove │ │
│ └─────────────┬──────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────▼──────────────────────────────────────────────────────┐ │
│ │ NetlinkManager/Handler │ │
│ │ • Listen Kernel Netlink Events (NETLINK_ROUTE) │ │
│ │ • RTM_NEWLINK, RTM_DELLINK (Interface Up/Down) │ │
│ │ • RTM_NEWADDR, RTM_DELADDR (IP Address Changes) │ │
│ │ • RTM_NEWROUTE, RTM_DELROUTE (Route Changes) │ │
│ └────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────┬───────────────────────────────────────────────┘
│
│ (iptables, ip route, netlink, sysfs)
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Linux Kernel Network Stack │
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Netfilter (iptables) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ filter │ │ nat │ │ mangle │ │ raw │ │ │
│ │ │ Table │ │ Table │ │ Table │ │ Table │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ • INPUT │ │ • PRERT │ │ • INPUT │ │ • PRERT │ │ │
│ │ │ • OUTPUT │ │ • POSTRT │ │ • OUTPUT │ │ • OUTPUT │ │ │
│ │ │ • FORWARD│ │ • OUTPUT │ │ • FORWARD│ │ │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Policy Routing (iproute2) │ │
│ │ • Multiple Route Tables (local, main, per-network) │ │
│ │ • Policy Rules (fwmark-based, UID-based, iif-based) │ │
│ │ • Route Selection based on Fwmark │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ XFRM │ │ TC (qdisc)│ │ Conntrack │ │ Network │ │
│ │ (IPsec) │ │ Traffic │ │ Connection │ │ Interfaces │ │
│ │ │ │ Control │ │ Tracking │ │ │ │
│ │ • Policy │ │ • Shaping │ │ • NAT │ │ • rmnet0 │ │
│ │ • SA │ │ • QoS │ │ • Stateful │ │ • wlan0 │ │
│ │ │ │ │ │ Firewall │ │ • tun0 │ │
│ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │
└───────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Hardware Layer (Drivers) │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ WiFi Driver │ │ Modem Driver │ │ Ethernet │ │
│ │ (wlan.ko) │ │ (RIL/qcril) │ │ Driver │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
3. 核心组件详解
3.1 Controllers(控制器集合)
class Controllers {
public:
NetworkController netCtrl; // 网络管理
TetherController tetherCtrl; // 热点共享
PppController pppCtrl; // PPP 协议(已废弃)
BandwidthController bandwidthCtrl; // 流量控制
IdletimerController idletimerCtrl; // 空闲计时器
FirewallController firewallCtrl; // 防火墙
StrictController strictCtrl; // StrictMode 检测
EventReporter eventReporter; // 事件上报
IptablesRestoreController iptablesRestoreCtrl; // iptables 批量操作
WakeupController wakeupCtrl; // 唤醒包检测
XfrmController xfrmCtrl; // IPsec VPN
TcpSocketMonitor tcpSocketMonitor; // TCP Socket 监控
void init();
};
3.1.1 NetworkController(网络控制器)
职责:
- 创建/销毁网络(Physical, Virtual, Local, OEM)
- 管理网络接口
- 网络权限控制
- 默认网络设置
- 按 UID 范围分配网络
关键 API:
// 创建物理网络(Cellular/WiFi)
int createPhysicalNetwork(unsigned netId, Permission permission);
// 创建虚拟网络(VPN)
int createVirtualNetwork(unsigned netId, bool secure, NativeVpnType vpnType);
// 添加接口到网络
int addInterfaceToNetwork(unsigned netId, const char* interface);
// 设置默认网络
int setDefaultNetwork(unsigned netId);
// 获取用户的网络
unsigned getNetworkForUser(uid_t uid);
unsigned getNetworkForConnect(uid_t uid);
网络类型:
| NetId | 类型 | 说明 |
|---|---|---|
| 99 | LOCAL_NET_ID | 本地网络(RFC1918 私有地址) |
| 51 | DUMMY_NET_ID | 虚拟黑洞网络(丢弃所有包) |
| 52 | UNREACHABLE_NET_ID | 不可达网络(拒绝所有包) |
| 100+ | Physical/Virtual | 动态分配的网络 ID |
权限类型:
enum Permission {
PERMISSION_NONE = 0, // 普通应用
PERMISSION_NETWORK = 1, // CHANGE_NETWORK_STATE
PERMISSION_SYSTEM = 3 // CONNECTIVITY_INTERNAL
};
3.1.2 FirewallController(防火墙控制器)
防火墙链:
| Chain Name | Mode | 用途 |
|---|---|---|
fw_dozable | Allowlist | Doze 模式白名单 |
fw_standby | Denylist | 后台待机限制(App Standby) |
fw_powersave | Allowlist | 省电模式白名单 |
fw_restricted | Allowlist | 受限应用白名单(后台数据) |
fw_low_power_standby | Allowlist | 低功耗待机白名单 |
iptables 规则示例:
# 创建防火墙链
iptables -t filter -N fw_dozable
# Allowlist 模式:默认 DROP
iptables -A fw_dozable -j DROP
# 添加允许的 UID
iptables -I fw_dozable -m owner --uid-owner 10123 -j RETURN
# 挂载到主链
iptables -I INPUT -j fw_dozable
iptables -I OUTPUT -j fw_dozable
3.1.3 BandwidthController(带宽控制器)
功能:
- 流量配额(Quota)
- 流量告警(Alert)
- Data Saver 省流量模式
- 流量统计(eBPF/xt_qtaguid)
iptables 规则:
# 设置接口配额(500MB)
iptables -I bw_OUTPUT -o wlan0 -m quota2 \
--name wlan0 --quota 524288000 -j ACCEPT
# 设置全局告警(2GB)
iptables -I bw_FORWARD -m quota2 \
--name global_alert --quota 2147483648 -j ACCEPT
# Data Saver: 阻止后台应用
iptables -I bw_costly_shared -m owner \
--uid-owner 10234 -j REJECT --reject-with icmp-port-unreachable
3.1.4 TetherController(热点控制器)
功能:
- USB/WiFi/蓝牙热点
- NAT(MASQUERADE)配置
- dnsmasq(DHCP + DNS 转发)
- IPv4 转发
NAT 规则:
# 启用 IP 转发
echo 1 > /proc/sys/net/ipv4/ip_forward
# MASQUERADE(源地址转换)
iptables -t nat -A POSTROUTING -o rmnet0 -j MASQUERADE
# FORWARD 链允许
iptables -A FORWARD -i wlan0 -o rmnet0 -j ACCEPT
iptables -A FORWARD -i rmnet0 -o wlan0 \
-m state --state RELATED,ESTABLISHED -j ACCEPT
3.1.5 XfrmController(IPsec VPN 控制器)
功能:
- XFRM 策略(Policy)管理
- SA(Security Association)配置
- IPsec 隧道建立
Netlink XFRM 接口:
// 添加 XFRM 策略
xfrm_userpolicy_info policy;
policy.sel.family = AF_INET;
policy.dir = XFRM_POLICY_OUT; // 出站策略
// 添加 SA
xfrm_usersa_info sa;
sa.family = AF_INET;
sa.mode = XFRM_MODE_TUNNEL; // 隧道模式
sa.reqid = 1;
3.2 RouteController(路由控制器)
职责:
- 策略路由(Policy Routing)
- 基于 Fwmark 的路由选择
- 多路由表管理
路由表架构:
# /data/misc/net/rt_tables
255 local # 本地路由表(内核维护)
254 main # 主路由表
97 local_network # 本地网络(RFC1918)
98 legacy_network # 遗留网络
99 legacy_system # 系统专用
# 每个网络一个路由表
1000-1999 # Per-Network Route Tables
策略路由规则:
# 按 Fwmark 路由
ip rule add from all fwmark 0x10064/0x1ffff lookup 100 # NetId=100
ip rule add from all fwmark 0x10065/0x1ffff lookup 101 # NetId=101
# VPN 路由优先级更高
ip rule add from all fwmark 0xc0000/0xd0000 lookup 102 # VPN NetId=102
# 本地网络路由
ip rule add from all fwmark 0x10063/0x1ffff lookup 97 # local_network
4. 通信机制
4.1 Framework → Netd: AIDL Binder (INetd)
接口定义 (INetd.aidl):
interface INetd {
// Network operations
void networkCreate(NativeNetworkConfig config);
void networkDestroy(int netId);
void networkAddInterface(int netId, String iface);
void networkRemoveInterface(int netId, String iface);
// Firewall operations
void firewallSetFirewallType(int firewallType);
void firewallSetUidRule(int childChain, int uid, int firewallRule);
void firewallReplaceUidChain(String chainName, boolean isAllowlist, int[] uids);
// Bandwidth operations
void bandwidthSetInterfaceQuota(String ifName, long bytes);
void bandwidthRemoveInterfaceQuota(String ifName);
void bandwidthSetInterfaceAlert(String ifName, long bytes);
void bandwidthEnableDataSaver(boolean enable);
// Tethering operations
void tetherStart(String[] dhcpRanges);
void tetherStop();
void tetherAddForward(String intIface, String extIface);
void tetherRemoveForward(String intIface, String extIface);
// Interface operations
String[] interfaceGetList();
InterfaceConfigurationParcel interfaceGetCfg(String ifName);
void interfaceSetCfg(InterfaceConfigurationParcel cfg);
}
调用示例 (NetworkManagementService.java):
public void setInterfaceQuota(String iface, long quotaBytes) {
PermissionUtils.enforceNetworkStackPermission(mContext);
synchronized (mQuotaLock) {
try {
mNetdService.bandwidthSetInterfaceQuota(iface, quotaBytes);
mActiveQuotas.put(iface, quotaBytes);
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
}
}
4.2 App → Netd: Unix Domain Socket
4.2.1 dnsproxyd - DNS 代理 Socket
路径: /dev/socket/dnsproxyd
权限: 0660 root inet
协议: Unix Stream Socket
工作流程:
App: getaddrinfo("www.google.com", "80", &hints, &result)
↓
Bionic libc: dns_open_proxy()
↓
Connect to /dev/socket/dnsproxyd
↓
Send DNS query request:
- Domain name: "www.google.com"
- NetId: 100 (from TLS: netIdForResolv)
- UID: 10123
- PID: 1234
↓
DNS Resolver (in Netd APEX):
1. Check per-network DNS cache
2. Get DNS servers for NetId=100
3. Query upstream DNS (or DNS-over-TLS if configured)
4. Cache result
↓
Return IP addresses: [142.250.185.68, 2404:6800:4004:823::2004]
↓
App: Receives struct addrinfo linked list
代码实现 (NetdClient.cpp):
int dns_open_proxy() {
const char* cache_mode = getenv("ANDROID_DNS_MODE");
const bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
int s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
static const struct sockaddr_un proxy_addr = {
.sun_family = AF_UNIX,
.sun_path = "/dev/socket/dnsproxyd",
};
if (connect(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr)) != 0) {
close(s);
return -1;
}
return s;
}
4.2.2 fwmarkd - Fwmark 标记服务 Socket
路径: /dev/socket/fwmarkd
权限: 0660 root inet
协议: Unix Stream Socket + SCM_RIGHTS (传递 fd)
Fwmark 结构 (32-bit SO_MARK):
31 16 15 14 13 12 11 2 1 0
┌──────────────┬──────┬──────┬──────────────┬────────┐
│ NetId │ VPN │ VPN │ Permission │Reserved│
│ (16 bit) │Bypass│Expli │ (2 bit) │ │
│ │(1bit)│(1bit)│ │ │
└──────────────┴──────┴──────┴──────────────┴────────┘
字段说明:
- NetId (Bit 16-31): 网络 ID (0-65535)
- Permission (Bit 1-2):
00: PERMISSION_NONE (普通应用)01: PERMISSION_NETWORK (有网络权限)10: PERMISSION_SYSTEM (系统权限)
- VPN Flags (Bit 12-13):
- Bit 13 (
explicitlySelected): 应用显式选择网络 - Bit 12 (
protectedFromVpn): 绕过 VPN
- Bit 13 (
FwmarkCommand 类型:
enum CmdId {
ON_ACCEPT, // accept4() 后调用
ON_CONNECT, // connect() 前调用
SELECT_NETWORK, // 显式网络选择 (Network.bindSocket)
PROTECT_FROM_VPN, // VPN 绕过 (VpnService.protect)
SELECT_FOR_USER, // 系统代理选择
QUERY_USER_ACCESS, // 查询权限
TAG_SOCKET, // 流量统计标记
UNTAG_SOCKET, // 移除标记
ON_SENDMSG, // sendmsg() 前调用
ON_SENDMMSG, // sendmmsg() 前调用
ON_SENDTO, // sendto() 前调用
ON_CONNECT_COMPLETE, // connect() 完成后调用
};
工作流程:
App: socket(AF_INET, SOCK_STREAM, 0) = sockfd
↓
App: connect(sockfd, "8.8.8.8:53", ...)
↓
Bionic hook: netdClientConnect()
↓
FwmarkClient:
1. socket(AF_UNIX, SOCK_STREAM, 0) = channel_fd
2. connect(channel_fd, "/dev/socket/fwmarkd", ...)
3. Send FwmarkCommand:
- cmdId = ON_CONNECT
- uid = 10123 (filled by kernel)
- Pass sockfd via SCM_RIGHTS
4. Send FwmarkConnectInfo:
- dest_addr = 8.8.8.8:53
- dest_family = AF_INET
↓
FwmarkServer:
1. Receive command + sockfd
2. getsockopt(sockfd, SOL_SOCKET, SO_DOMAIN) -> AF_INET
3. getsockopt(sockfd, SOL_SOCKET, SO_MARK) -> current fwmark
4. NetworkController::getNetworkForConnect(uid=10123)
- Check if user has VPN -> netId=102
- Fallback to default network -> netId=100
5. Calculate new fwmark:
- netId = 100
- permission = PERMISSION_NONE (0)
- protectedFromVpn = false
- explicitlySelected = false
- fwmark = 0x00640000
6. setsockopt(sockfd, SOL_SOCKET, SO_MARK, 0x00640000)
7. Return 0 (success)
↓
App: connect() continues with kernel routing based on fwmark
↓
Kernel Policy Routing:
- Extract netId from fwmark: 100
- Lookup route table 100
- Route packet through interface: wlan0
代码实现 (FwmarkServer.cpp):
int FwmarkServer::processClient(SocketClient* client, int* socketFd) {
FwmarkCommand command;
FwmarkConnectInfo connectInfo;
// Receive command + socket fd via SCM_RIGHTS
ssize_t messageLength = ReceiveFileDescriptorVector(
client->getSocket(), &buf, sizeof(buf), 1, &received_fds);
*socketFd = received_fds[0].release();
// Get current fwmark
Fwmark fwmark;
getsockopt(*socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen);
switch (command.cmdId) {
case FwmarkCommand::ON_CONNECT: {
if (!fwmark.explicitlySelected) {
if (!fwmark.protectedFromVpn) {
fwmark.netId = mNetworkController->getNetworkForConnect(client->getUid());
} else if (!mNetworkController->isVirtualNetwork(fwmark.netId)) {
fwmark.netId = mNetworkController->getDefaultNetwork();
}
}
break;
}
case FwmarkCommand::SELECT_NETWORK: {
fwmark.netId = command.netId;
fwmark.explicitlySelected = true;
break;
}
case FwmarkCommand::PROTECT_FROM_VPN: {
fwmark.protectedFromVpn = true;
if (!fwmark.explicitlySelected &&
mNetworkController->isVirtualNetwork(fwmark.netId)) {
fwmark.netId = mNetworkController->getDefaultNetwork();
}
break;
}
}
fwmark.permission = mNetworkController->getPermissionForUser(client->getUid());
// Set new fwmark
setsockopt(*socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, sizeof(fwmark.intValue));
return 0;
}
4.2.3 mdns - mDNS 服务发现 Socket
路径: /dev/socket/mdns
权限: 0660 root system
协议: Unix Stream Socket
用途:
- Multicast DNS (RFC 6762)
- DNS-SD (DNS Service Discovery, RFC 6763)
- 发现
.local域名设备 - 服务发现(打印机、Chromecast、智能家居)
工作原理:
App: NsdManager.discoverServices("_ipp._tcp", NsdManager.PROTOCOL_DNS_SD, listener)
↓
Framework: NsdService connects to /dev/socket/mdns
↓
MDnsService (Netd):
1. Listen on UDP 224.0.0.251:5353 (mDNS multicast)
2. Send PTR query: _ipp._tcp.local
3. Wait for responses from printers
↓
Response: PTR _ipp._tcp.local -> "My Printer._ipp._tcp.local"
SRV "My Printer._ipp._tcp.local" -> myprinter.local:631
A myprinter.local -> 192.168.1.100
↓
Callback: listener.onServiceFound(serviceInfo)
4.3 Netd → Kernel: Netlink, iptables, sysfs
4.3.1 Netlink Socket
类型:
NETLINK_ROUTE: 路由/接口/地址事件NETLINK_XFRM: IPsec 配置NETLINK_NETFILTER: Netfilter 日志
监听事件:
// NetlinkHandler.cpp
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
switch (evt->getAction()) {
case NetlinkEvent::Action::kLinkUp:
// Interface up: wlan0
notifyInterfaceAdded(ifName);
break;
case NetlinkEvent::Action::kLinkDown:
// Interface down: rmnet0
notifyInterfaceRemoved(ifName);
break;
case NetlinkEvent::Action::kAddressUpdated:
// IP address added: 192.168.1.100/24
notifyAddressUpdated(ifName, address);
break;
case NetlinkEvent::Action::kRouteUpdated:
// Route changed
notifyRouteChange(evt);
break;
}
}
4.3.2 iptables
批量操作 (IptablesRestoreController):
int execIptablesRestore(IptablesTarget target, const std::string& commands) {
std::string cmd = (target == V4) ? "iptables-restore" : "ip6tables-restore";
// 使用管道传递规则,避免多次 fork
FILE* f = popen(cmd.c_str(), "w");
fwrite(commands.c_str(), 1, commands.size(), f);
pclose(f);
}
示例规则:
*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-N fw_dozable
-A fw_dozable -j DROP
-I fw_dozable -m owner --uid-owner 10123 -j RETURN
-I INPUT -j fw_dozable
-I OUTPUT -j fw_dozable
COMMIT
4.3.3 sysfs/procfs
常用文件:
# IP 转发
/proc/sys/net/ipv4/ip_forward
/proc/sys/net/ipv6/conf/all/forwarding
# RP 过滤 (Reverse Path Filtering)
/proc/sys/net/ipv4/conf/*/rp_filter
# IPv6 地址生成模式
/proc/sys/net/ipv6/conf/wlan0/addr_gen_mode
# 接受 RA (Router Advertisement)
/proc/sys/net/ipv6/conf/wlan0/accept_ra
5. 关键功能模块
5.1 Per-App 网络选择
核心机制: Fwmark + Policy Routing
完整流程:
1. Network Setup Phase (ConnectivityService):
ConnectivityService.handleRegisterNetworkAgent(NetworkAgent)
↓
mNetd.networkCreate(config) // netId=100, physical
↓
mNetd.networkAddInterface(100, "wlan0")
↓
NetworkController::addInterfaceToNetwork()
↓
RouteController::addInterfaceToNetwork()
- Create route table 100
- ip route add default via 192.168.1.1 dev wlan0 table 100
- ip rule add from all fwmark 0x10064/0x1ffff lookup 100
2. VPN Activation Phase:
VpnService.establish()
↓
ConnectivityService.establishVpn(VpnConfig)
↓
mNetd.networkCreate(config) // netId=102, vpn
↓
NetworkController::setDefaultNetwork(102) // Set VPN as default for UID range
3. Socket Creation Phase:
App: socket(AF_INET, SOCK_STREAM, 0)
↓
Bionic: netdClientSocket()
- Create socket
- Get netIdForProcess from TLS
- If netId != NETID_UNSET:
FwmarkClient().send(SELECT_NETWORK, netId, sockfd)
4. Connection Phase:
App: connect(sockfd, "8.8.8.8:53", ...)
↓
Bionic: netdClientConnect()
↓
FwmarkClient().send(ON_CONNECT, sockfd, connectInfo)
↓
FwmarkServer::processClient()
↓
NetworkController::getNetworkForConnect(uid)
- Check if uid in VPN UID range -> netId=102 (VPN)
- Else check default network -> netId=100 (WiFi)
↓
Calculate fwmark:
fwmark = (netId << 16) | (permission << 1) | vpnFlags
fwmark = 0x00660000 // netId=102, perm=0, no explicit
↓
setsockopt(sockfd, SOL_SOCKET, SO_MARK, 0x00660000)
↓
Return to app, continue connect()
↓
Kernel IP routing:
- Extract netId from fwmark: 102
- Lookup policy routing rules
- Match: ip rule ... fwmark 0x10066/0x1ffff lookup 102
- Use route table 102
- Send packet via tun0 (VPN interface)
5.2 DNS 解析
架构:
┌──────────────────────────────────────────────────────────┐
│ Application │
│ getaddrinfo("www.example.com", "https", ...) │
└────────────────────┬─────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ Bionic libc (DNS Resolver) │
│ • Check /etc/hosts │
│ • Check per-process netId (TLS: netIdForResolv) │
│ • Connect to /dev/socket/dnsproxyd │
└────────────────────┬─────────────────────────────────────┘
│ Unix Socket
▼
┌──────────────────────────────────────────────────────────┐
│ DNS Resolver (Netd APEX Module) │
│ │
│ DnsProxyListener.cpp: │
│ 1. Receive query: (domain, netId, uid, pid, flags) │
│ 2. resolv_gethostbyname(domain, netId, ...) │
│ ↓ │
│ 3. Check per-network cache: │
│ mDnsCache[netId].get(domain, type) │
│ ↓ │
│ 4. If cache miss, query upstream: │
│ - Get DNS servers for netId from DnsConfiguration │
│ - For netId=100: [8.8.8.8, 8.8.4.4] │
│ - Check if Private DNS (DoT) enabled │
│ ↓ │
│ 5. DNS Query: │
│ If DoT enabled: │
│ - TLS connection to dns.google:853 │
│ - Send DNS query over TLS │
│ Else: │
│ - UDP socket to 8.8.8.8:53 │
│ - Send DNS query │
│ ↓ │
│ 6. Receive response: │
│ - Parse DNS response │
│ - Cache result (TTL-based) │
│ - Apply DNS filtering rules (if any) │
│ ↓ │
│ 7. Return to client: │
│ - Send IP addresses back via dnsproxyd socket │
└────────────────────┬─────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ App receives: │
│ struct addrinfo { │
│ ai_addr = 93.184.216.34 (IPv4) │
│ ai_next -> 2606:2800:220:1:248:1893:25c8:1946 (IPv6) │
│ } │
└──────────────────────────────────────────────────────────┘
DNS 配置管理:
// DnsManager.java
public void setDnsConfigurationForNetwork(
int netId, String[] servers, String[] domains,
int[] params, String tlsHostname) {
ResolverParamsParcel parcel = new ResolverParamsParcel();
parcel.netId = netId;
parcel.servers = servers; // ["8.8.8.8", "8.8.4.4"]
parcel.domains = domains; // ["example.com"]
parcel.tlsName = tlsHostname; // "dns.google" (for DoT)
mNetd.resolverSetConfiguration(parcel);
}
5.3 流量统计与配额
架构:
App -> Socket (tagged with UID) -> Kernel -> eBPF/xt_qtaguid -> Stats
流量标记:
// TrafficStats.java
public static void setThreadStatsTag(int tag) {
NetworkManagementSocketTagger.setThreadSocketStatsTag(tag);
}
// Native implementation
int tagSocket(int socketFd, uint32_t tag, uid_t uid) {
FwmarkCommand command = {FwmarkCommand::TAG_SOCKET, 0, uid, tag};
return FwmarkClient().send(&command, socketFd, nullptr);
}
eBPF 统计 (Android 9+):
// bpf_net_helpers.c
struct stats_key {
uint32_t uid;
uint32_t tag;
uint32_t counterSet;
uint32_t ifaceIndex;
};
struct stats_value {
uint64_t rxPackets;
uint64_t rxBytes;
uint64_t txPackets;
uint64_t txBytes;
};
BPF_MAP_DEF(stats_map, HASH, struct stats_key, struct stats_value, 1024);
配额实施:
# 使用 iptables quota2 模块
iptables -I bw_OUTPUT -o wlan0 \
-m quota2 --name wlan0_quota --quota 524288000 \
-j ACCEPT
# 配额用尽后触发告警
# Kernel netlink event -> NetlinkHandler -> BandwidthController
5.4 Captive Portal 检测
虽然主要在 NetworkMonitor 中,但 Netd 提供网络支持:
// NetworkMonitor.java
private CaptivePortalProbeResult isCaptivePortal() {
// HTTP probe
URL url = new URL("http://connectivitycheck.gstatic.com/generate_204");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// Netd ensures this socket uses the correct network (via Fwmark)
Network network = mNetwork; // Bound to specific netId
network.bindSocket(conn.getSocket());
int responseCode = conn.getResponseCode();
if (responseCode == 204) {
return CaptivePortalProbeResult.SUCCESS; // No captive portal
} else if (responseCode >= 200 && responseCode < 400) {
return CaptivePortalProbeResult.PORTAL; // Captive portal detected
}
}
6. 技术实现细节
6.1 启动流程
int main() {
// 1. 初始化日志
gLog.info("netd 1.0 starting");
// 2. 阻止 SIGPIPE(防止写入已关闭的 socket 导致进程退出)
android::net::process::blockSigPipe();
// 3. 设置 CLOEXEC(子进程不继承 socket fd)
for (const auto& sock : {DNSPROXYLISTENER_SOCKET_NAME, FwmarkServer::SOCKET_NAME}) {
setCloseOnExec(sock);
}
// 4. 初始化 cgroup v2
std::string cg2_path;
CgroupGetControllerPath(CGROUPV2_HIERARCHY_NAME, &cg2_path);
libnetd_updatable_init(cg2_path.c_str());
// 5. 创建 Netlink 管理器(监听内核事件)
NetlinkManager *nm = NetlinkManager::Instance();
nm->start();
// 6. 初始化控制器
gCtls = new android::net::Controllers();
gCtls->init(); // 初始化 iptables 规则
// 7. 创建 NFLog 监听器(用于 WakeupController)
std::unique_ptr<NFLogListener> logListener = makeNFLogListener();
gCtls->wakeupCtrl.init(logListener.get());
// 8. 初始化 DNS Resolver(从 APEX 加载)
setenv("ANDROID_DNS_MODE", "local", 1);
initDnsResolver();
// 9. 启动 FwmarkServer(监听 /dev/socket/fwmarkd)
FwmarkServer fwmarkServer(&gCtls->netCtrl, &gCtls->eventReporter);
fwmarkServer.startListener();
// 10. 注册 Binder 服务
NetdNativeService::start(); // INetd
MDnsService::start(); // mDNS
// 11. 注册 HAL 服务
NetdHwAidlService::run(); // AIDL HAL
NetdHwService::start(); // HIDL HAL (legacy)
// 12. 加入 Binder 线程池(阻塞在这里)
IPCThreadState::self()->joinThreadPool();
}
6.2 iptables 规则初始化
void Controllers::initIptablesRules() {
// 1. 创建子链
initChildChains();
// 2. 设置 OEM 钩子
setupOemIptablesHook();
// 3. 防火墙规则(优先级最高)
firewallCtrl.setupIptablesHooks();
// 4. 热点规则
tetherCtrl.setupIptablesHooks();
// 5. 带宽控制规则
bandwidthCtrl.setupIptablesHooks();
// 6. 空闲计时器规则
idletimerCtrl.setupIptablesHooks();
// 7. StrictMode 规则
strictCtrl.setupIptablesHooks();
// 8. Connmark 规则(用于存储 netId)
setupConnmarkIptablesHooks();
}
生成的 iptables 规则结构:
filter table:
INPUT chain
├─> bw_INPUT (bandwidth counting)
├─> fw_INPUT (firewall chains)
│ ├─> fw_dozable
│ ├─> fw_standby
│ └─> fw_powersave
└─> ACCEPT
OUTPUT chain
├─> bw_OUTPUT (bandwidth counting)
├─> fw_OUTPUT (firewall chains)
└─> ACCEPT
FORWARD chain
├─> bw_FORWARD (bandwidth counting)
├─> tetherctrl_FORWARD (tethering)
└─> DROP (default)
nat table:
PREROUTING chain
└─> idletimer_PREROUTING (idle timer)
POSTROUTING chain
├─> idletimer_POSTROUTING (idle timer)
└─> tetherctrl_nat_POSTROUTING (tethering NAT)
mangle table:
INPUT chain
└─> connmark_mangle_INPUT (restore connmark to fwmark)
OUTPUT chain
└─> connmark_mangle_OUTPUT (save fwmark to connmark)
6.3 Netlink 事件处理
// NetlinkHandler.cpp
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
const char *subsys = evt->getSubsystem();
if (!strcmp(subsys, "net")) {
NetlinkEvent::Action action = evt->getAction();
const char *iface = evt->findParam("INTERFACE");
switch (action) {
case NetlinkEvent::Action::kLinkUp:
// 接口 up: wlan0
notifyInterfaceLinkChanged(iface, true);
break;
case NetlinkEvent::Action::kLinkDown:
// 接口 down: rmnet0
notifyInterfaceLinkChanged(iface, false);
break;
case NetlinkEvent::Action::kAddressUpdated:
// IP 地址变更
const char *address = evt->findParam("ADDRESS");
const char *flags = evt->findParam("FLAGS");
int flag_val = strtol(flags, NULL, 0);
bool addressRemoved = (flag_val & IFA_F_DEPRECATED);
notifyAddressUpdated(iface, address, !addressRemoved);
break;
case NetlinkEvent::Action::kAddressRemoved:
// IP 地址移除
const char *address = evt->findParam("ADDRESS");
notifyAddressRemoved(iface, address);
break;
case NetlinkEvent::Action::kRouteUpdated:
case NetlinkEvent::Action::kRouteRemoved:
// 路由变更(通常忽略,由 RouteController 主动管理)
break;
}
}
}
void NetlinkHandler::notifyInterfaceLinkChanged(const char *name, bool isUp) {
// 通知所有注册的监听器
for (auto& listener : mListeners) {
if (isUp) {
listener->onInterfaceLinkStateChanged(name, true);
} else {
listener->onInterfaceLinkStateChanged(name, false);
}
}
// 通过 Binder 通知 Framework
mNetdUnsolicitedEventListener->onInterfaceLinkStateChanged(
String16(name), isUp);
}
6.4 策略路由实现
// RouteController.cpp
int RouteController::addInterfaceToNetwork(unsigned netId, const char* interface) {
// 1. 创建路由表
uint32_t table = getRouteTableForInterface(interface, false);
if (table == RT_TABLE_UNSPEC) {
return -ESRCH;
}
// 2. 添加默认路由
for (const auto family : {AF_INET, AF_INET6}) {
// ip route add default dev wlan0 table 100
addRoute(RTM_NEWROUTE, family, interface, "default", table);
}
// 3. 添加策略路由规则
Fwmark fwmark;
fwmark.netId = netId;
Fwmark mask;
mask.netId = 0xffff;
// ip rule add from all fwmark 0x10064/0x1ffff lookup 100
for (const auto family : {AF_INET, AF_INET6}) {
modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_EXPLICIT_NETWORK,
family, fwmark.intValue, mask.intValue,
IIF_NONE, OIF_NONE, UID_NONE, UID_NONE, table);
}
return 0;
}
生成的路由规则:
# ip rule show
0: from all lookup local
10000: from all fwmark 0x10064/0x1ffff lookup 100 # netId=100 (wlan0)
10000: from all fwmark 0x10065/0x1ffff lookup 101 # netId=101 (rmnet0)
11000: from all fwmark 0x0/0xffff lookup 252 # legacy system
13000: from all fwmark 0x10063/0x1ffff lookup 97 # local_network
20000: from all fwmark 0x10066/0x1ffff lookup 102 # netId=102 (VPN)
32000: from all lookup main
# ip route show table 100
default via 192.168.1.1 dev wlan0
192.168.1.0/24 dev wlan0 scope link
# ip route show table 102 (VPN)
default dev tun0 scope link
7. 总结
7.1 Netd 的核心价值
-
特权隔离
- App 运行在沙盒中,无法直接操作网络
- Netd 以 root 权限执行,统一管理所有
NET_ADMIN操作 - 安全审计和权限检查集中在一处
-
抽象复杂性
- 隐藏 iptables/iproute2/netlink 的底层复杂性
- 为 Framework 提供高层次、易用的 API
- 跨 Android 版本保持 ABI 稳定性
-
性能优化
- Native C++ 实现,比 Java 层调用 Shell 命令快数十倍
- 批量 iptables 规则应用(iptables-restore)
- 事件驱动架构,减少轮询开销
-
统一管理
- 所有网络配置集中在一个守护进程
- 避免多个组件竞争修改 iptables
- 确保网络状态的一致性和原子性
-
可维护性
- 清晰的模块化设计(Controllers 模式)
- 每个 Controller 负责独立功能
- 易于调试(
dumpsys netd)
7.2 关键设计模式
-
Facade 模式
- NetdNativeService 作为统一入口
- 隐藏内部 Controllers 的复杂性
-
Controller 模式
- 每个功能模块独立封装
- 职责明确,易于扩展
-
Event-Driven 模式
- Netlink 监听内核事件
- 异步通知 Framework
-
IPC 多样化
- Binder: Framework ↔ Netd
- Unix Socket: App ↔ Netd (dnsproxyd, fwmarkd)
- Netlink: Netd ↔ Kernel
7.3 与其他组件的关系
ConnectivityService (策略制定者)
↓ INetd
NetworkManagementService (API 聚合者)
↓ INetd
Netd (执行者)
↓ iptables/iproute2/netlink
Linux Kernel (底层实现)
7.4 演进历史
| 版本 | 变化 |
|---|---|
| Android 2.x | 通过 Socket 命令行接口通信 |
| Android 4.x | 引入 Netd Binder 接口 |
| Android 5.0 | 引入 Fwmark + Policy Routing (per-app VPN) |
| Android 7.0 | 引入 Private DNS (DoT) |
| Android 9.0 | eBPF 流量统计取代 xt_qtaguid |
| Android 10 | DNS Resolver 模块化(APEX) |
| Android 11 | NetworkStack 模块化 |
| Android 12+ | 持续优化性能和安全性 |
7.5 最后的话
Netd 是 Android 网络架构的基石,没有它,Android 的网络功能将无法运作。它体现了以下设计理念:
- 最小权限原则: 只有 Netd 拥有 root 权限,其他组件通过 IPC 调用
- 关注点分离: 策略(Framework)与执行(Netd)分离
- 性能至上: Native 实现 + 批量操作 + 事件驱动
- 可扩展性: Controller 模式易于添加新功能
- 向后兼容: 通过 AIDL versioning 保持 API 稳定
这份文档涵盖了 Netd 的架构、通信机制、核心功能和实现细节,希望能帮助您深入理解 Android 网络栈的底层运作机制!