Netd (Network Daemon) 完整架构与作用

5 阅读17分钟

Android Netd (Network Daemon) 完整架构分析

目录

  1. 概述
  2. 整体架构图
  3. 核心组件详解
  4. 通信机制
  5. 关键功能模块
  6. 技术实现细节
  7. 总结

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_ADMINNET_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类型说明
99LOCAL_NET_ID本地网络(RFC1918 私有地址)
51DUMMY_NET_ID虚拟黑洞网络(丢弃所有包)
52UNREACHABLE_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 NameMode用途
fw_dozableAllowlistDoze 模式白名单
fw_standbyDenylist后台待机限制(App Standby)
fw_powersaveAllowlist省电模式白名单
fw_restrictedAllowlist受限应用白名单(后台数据)
fw_low_power_standbyAllowlist低功耗待机白名单

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 resultReturn 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

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.100Callback: 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 的核心价值

  1. 特权隔离

    • App 运行在沙盒中,无法直接操作网络
    • Netd 以 root 权限执行,统一管理所有 NET_ADMIN 操作
    • 安全审计和权限检查集中在一处
  2. 抽象复杂性

    • 隐藏 iptables/iproute2/netlink 的底层复杂性
    • 为 Framework 提供高层次、易用的 API
    • 跨 Android 版本保持 ABI 稳定性
  3. 性能优化

    • Native C++ 实现,比 Java 层调用 Shell 命令快数十倍
    • 批量 iptables 规则应用(iptables-restore)
    • 事件驱动架构,减少轮询开销
  4. 统一管理

    • 所有网络配置集中在一个守护进程
    • 避免多个组件竞争修改 iptables
    • 确保网络状态的一致性和原子性
  5. 可维护性

    • 清晰的模块化设计(Controllers 模式)
    • 每个 Controller 负责独立功能
    • 易于调试(dumpsys netd

7.2 关键设计模式

  1. Facade 模式

    • NetdNativeService 作为统一入口
    • 隐藏内部 Controllers 的复杂性
  2. Controller 模式

    • 每个功能模块独立封装
    • 职责明确,易于扩展
  3. Event-Driven 模式

    • Netlink 监听内核事件
    • 异步通知 Framework
  4. 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.0eBPF 流量统计取代 xt_qtaguid
Android 10DNS Resolver 模块化(APEX)
Android 11NetworkStack 模块化
Android 12+持续优化性能和安全性

7.5 最后的话

Netd 是 Android 网络架构的基石,没有它,Android 的网络功能将无法运作。它体现了以下设计理念:

  • 最小权限原则: 只有 Netd 拥有 root 权限,其他组件通过 IPC 调用
  • 关注点分离: 策略(Framework)与执行(Netd)分离
  • 性能至上: Native 实现 + 批量操作 + 事件驱动
  • 可扩展性: Controller 模式易于添加新功能
  • 向后兼容: 通过 AIDL versioning 保持 API 稳定

这份文档涵盖了 Netd 的架构、通信机制、核心功能和实现细节,希望能帮助您深入理解 Android 网络栈的底层运作机制!