系列目录第一篇全景图与调用链路概览 | 第二篇内核层—netfilter/iptables与路由策略 |第三篇Native层(上)—netd守护进程与CommandListener| 第四篇Native层(下)—netd Controller详解 | 第五篇Framework层(上)—ConnectivityService核心机制 | 第六篇Framework层(下)—NMS/NPMS/NSS三大服务 | 第七篇连接建立—WiFi/移动数据/以太网完整流程 | 第八篇应用API层—ConnectivityManager使用与实战调试一、netd 是什么netd 全称 Network Daemon是 Android 网络管理的核心守护进程。它运行在 Native 层向上接收 Framework 的命令向下操作内核的网络配置。理解 netd 的架构是理解整个 Android 网络系统的关键。netd 的核心职责┌─────────────────────────────────────────────┐ │ netd (Network Daemon) │ │ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ CommandListener │ │ NetlinkManager │ │ │ │ 接收Framework命令 │ │ 监听内核UEvent │ │ │ └────────┬─────────┘ └────────┬─────────┘ │ │ │ │ │ │ ┌────────▼─────────────────────▼─────────┐ │ │ │ Controller 层 │ │ │ │ NetworkController RouteController │ │ │ │ FirewallController BandwidthController │ │ │ │ TetherController SoftapController │ │ │ │ IdletimerController │ │ │ └────────┬──────────────────────────────┘ │ │ │ │ │ ┌────────▼──────────────────────────────┐ │ │ │ DnsProxyListener → DNS 代理 │ │ │ └───────────────────────────────────────┘ │ └─────────────────────────────────────────────┘ │ │ ┌────▼────┐ ┌─────▼──────┐ │ 内核层 │ │ Framework │ │iptables │ │ 层服务 │ │路由表 │ │ │ └─────────┘ └────────────┘关键设计netd 采用南北向分离架构——北向通过CommandListener和DnsProxyListener与 Framework/应用通信南向通过NetlinkManager和 Controller 操作内核中间由 Controller 层将命令翻译为具体的 iptables 规则和 netlink 消息。二、netd 启动流程2.1 init.rc 中的定义源码路径system/netd/server/netd.rcservicenetd /system/bin/netd class main socket netd stream 0660 root system socket dnsproxyd stream 0660 root inet socket mdns stream 0660 root system socket fwmarkd stream 0660 root inet关键设计所有 Socket 都是stream类型TCP而不是dgramUDP。netd 的命令协议基于文本行需要可靠的面向连接传输。四个 SocketSocket类型权限用途netdstream (TCP)0660 root systemFramework 控制通道dnsproxydstream (TCP)0660 root inetDNS 代理mdnsstream (TCP)0660 root system多播 DNS (mDNS)fwmarkdstream (TCP)0660 root inetfwmark 设置2.2 main.cpp 入口源码路径system/netd/server/main.cppintmain(){// 1. 日志初始化// 2. 创建并启动 NetlinkManager// 3. 创建并启动 CommandListener// 4. 创建并启动 DnsProxyListener// 5. 创建并启动 MDnsSdListener用于 mDNS/DNS-SD 服务发现// 6. 创建并启动 FwmarkServer// 7. 进入主循环等待事件}关键设计main()遵循先启动基础设施再启动服务的顺序——NetlinkManager 在内核事件监听就绪后才启动 CommandListener 接收 Framework 命令最后启动 DNS 代理和 FwmarkServer 等面向应用的 Socket 服务。启动顺序很重要main() ├── NetlinkManager::start() // 1. 先启动内核事件监听 ├── CommandListener::startListener() // 2. 启动命令监听 ├── DnsProxyListener::startListener() // 3. DNS 代理 ├── MDnsSdListener::startListener() // 4. mDNS └── FwmarkServer::startListener() // 5. fwmark关键设计NetlinkManager 须先于其他组件启动因为 NetworkController 和 RouteController 等依赖它接收的内核事件来维护接口状态。三、CommandListener 架构3.1 整体设计源码路径system/netd/server/CommandListener.hclassCommandListener:publicFrameworkListener{// ...};源码路径system/netd/server/CommandListener.cppCommandListener 继承自 FrameworkListener而 FrameworkListener 又继承自 SocketListener。这种多层继承体现了 Android 系统服务的通用设计模式SocketListener ← 通用 Socket 监听libsysutils ↑ FrameworkListener ← Android Framework 专用监听libsysutils ↑ CommandListener ← netd 的具体命令分发关键设计SocketListener提供 socket 的创建、监听和事件分发FrameworkListener在其上增加命令解析和响应码机制CommandListener只负责注册各 Controller 的具体命令——三层各司其职任意一层可独立替换。3.2 命令注册机制CommandListener 在构造函数中为每个 Controller 注册命令CommandListener::CommandListener(){// 注册各 Controller 的命令registerCmd(newInterfaceCmd());// interface 命令族registerCmd(newIpFwdCmd());// ipfwd 命令族registerCmd(newTetherCmd());// tether 命令族registerCmd(newNatCmd());// nat 命令族registerCmd(newResolverCmd());// resolver 命令族registerCmd(newBandwidthControlCmd());// bandwidth 命令族registerCmd(newFirewallCmd());// firewall 命令族registerCmd(newIdletimerCmd());// idletimer 命令族registerCmd(newStrictCmd());// strict 命令族registerCmd(newNetworkCmd());// network 命令族// 等等...}关键设计每个 Cmd 类对应一个命令族例如InterfaceCmd可以处理interface list、interface getcfg、interface setcfg等子命令——命令族内的子命令通过runCommand()的argc/argv参数进一步分发。每个 Cmd 类对应一个命令族例如InterfaceCmd可以处理interface list、interface getcfg、interface setcfg等子命令。3.3 命令执行流程当 NetworkManagementService 通过 Socket 发送一条命令时完整的执行流程NetworkManagementService (Java) │ │ NativeDaemonConnector.execute(interface list) │ 通过 /dev/socket/netd socket 发送 │ ▼ CommandListener::onDataAvailable() │ │ 读取一行interface list │ ▼ FrameworkListener::dispatchCommand(interface list) │ │ 解析命令名 interface查找对应的 Cmd 对象 │ ▼ InterfaceCmd::runCommand(client, argc, argv) │ argv[0] interface, argv[1] list │ ▼ NetworkController::getInterfaceList() │ │ 读取 /proc/net/dev 或调用 ioctl │ ▼ 返回字符串200 wlan0 rmnet_data0 lo │ │ 通过 Socket 返回给 NetworkManagementService │ ▼ NetworkManagementService 收到 200 wlan0 rmnet_data0 lo │ │ NativeDaemonConnector 解析响应码 200 │ ▼ 调用方得到结果关键整条命令链路从 Java 层到 Native 层再到内核每个环节的职责清晰——NativeDaemonConnector负责协议封装CommandListener负责命令分发Controller 负责执行操作响应码200表示全程成功。3.4 通信协议netd 与 Framework 之间的协议非常简单字符串命令 数字响应码。请求格式命令名 [参数...]响应格式响应码 [内容]响应码约定响应码含义200成功400客户端错误参数错误500服务端错误命令执行失败600命令未找到213表示后面还有多行数据每行后跟 213 继续直到 200 结束多行响应示例213 00 01 02 03 04 05 06 00 00 00 00 00 00 00 00 00 00 213 01 02 03 04 05 06 07 00 00 00 00 00 00 00 00 00 00 200 Interface list completed四、NetlinkManager — 内核事件监听4.1 netlink 协议简介netlink 是 Linux 中内核与用户态通信的一种机制。Android 用它来接收内核网络事件内核 用户态 (netd) │ │ │ 接口 wlan0 UP │ │ ↓ │ │ 生成 RTM_NEWLINK 消息 │ │ ↓ │ │ 通过 netlink socket 发送 ────→ NetlinkManager.handleEvent() │ │ ↓ │ │ NetlinkHandler.onEvent() │ │ ↓ │ │ 更新接口状态关键netlink 是内核主动推送事件给用户态的唯一通道——不需要轮询接口状态变化UP/DOWN、地址变更、路由变更都在毫秒级到达 netd然后通过广播通知 Framework 层。4.2 NetlinkManager 实现源码路径system/netd/server/NetlinkManager.cppclassNetlinkManager{NetlinkHandler*mHandler;intmSock;// netlink socket fdintstart();intstop();};关键设计NetlinkManager是单例模式内部通过setupSocket()创建多个 netlink socket 分别监听 UEvent、路由、配额和严格模式四种事件每种事件由独立的NetlinkHandler处理。源码路径system/netd/server/NetlinkHandler.cppclassNetlinkHandler:publicNetlinkListener{virtualvoidonEvent(NetlinkEvent*evt);};关键设计NetlinkHandler继承自NetlinkListener负责 netlink socket 的数据读取onEvent()是事件分发的核心入口——根据事件的subsystem和action字段路由到不同的notify*()方法最终通过广播通知 Framework 层。onEvent方法处理以下类型的事件事件类型含义处理方式RTM_NEWLINK接口创建/状态变化更新接口列表RTM_DELLINK接口删除清理接口数据RTM_NEWADDR新 IP 地址更新地址信息RTM_DELADDRIP 地址删除清理地址信息RTM_NEWROUTE新路由更新路由表缓存RTM_DELROUTE路由删除清理路由缓存4.3 NetlinkEvent 结构源码路径system/core/include/sysutils/NetlinkEvent.h每个 netlink 事件被解析成 NetlinkEvent 对象classNetlinkEvent{intmAction;// ACTION_ADD / ACTION_REMOVE / ACTION_CHANGEstd::string mSubsystem;// netstd::string mInterfaceName;// wlan0std::mapstd::string,std::stringmParams;// 键值对参数};关键设计NetlinkEvent将内核的二进制 netlink 消息解析为结构化的字段——mAction表示增删改mSubsystem区分事件来源net/qlog/strictmParams以键值对存储具体参数如 ADDRESS、PREFIX、FLAGS方便上层按名取值而非按位解析。例如当 wlan0 获得 IP 地址 192.168.1.100 时Action: ADD Subsystem: net Interface: wlan0 Params: {ADDRESS: 192.168.1.100, PREFIX: 24, FLAGS: 128}关键这个结构化的 NetlinkEvent 会被NetlinkHandler::onEvent()解析识别出kAddressUpdated动作然后通过广播通知 Framework 层wlan0 获得了新 IP 地址触发后续的路由配置流程。五、DnsProxyListener — DNS 代理5.1 为何需要 DNS 代理传统 Linux 上每个进程直接读取/etc/resolv.conf并自行发起 DNS 查询。但在 Android 中不同网络WiFi / 移动数据 / VPN有不同的 DNS 服务器需要按应用控制 DNS如 VPN 应用使用 VPN 的 DNS需要统一 DNS 缓存因此Android 将所有 DNS 请求拦截到 netd 的 dnsproxyd socket由 netd 统一代理。5.2 代理流程APP 调用 getaddrinfo(www.google.com) │ │ libc 中的 DNS 解析代码 │ bionic/libc/dns/ │ ▼ 连接 /dev/socket/dnsproxyd │ │ 发送 DNS 查询请求二进制格式 │ ▼ DnsProxyListener::DnsProxyListener() │ │ 解析请求转发给 ResolverController │ ▼ ResolverController::getDnsForwarders(netId) │ │ 根据 netId 获取对应的上游 DNS 服务器 │ ▼ 发送 DNS 查询到上游服务器 (8.8.8.8 等) │ │ 收到响应 │ ▼ 通过 dnsproxyd socket 返回给 APP关键DNS 代理的流程是应用发请求 - netd 转发 - 上游 DNS 响应 - netd 回传——应用只跟/dev/socket/dnsproxyd通信完全不知道真正的 DNS 服务器是谁netd 根据 netId 透明地选择了正确的上游服务器。源码路径system/netd/server/DnsProxyListener.cpp5.3 按 netId 管理 DNS每个网络有独立的 DNS 服务器配置ResolverController 中存储的数据结构 netId → [ 8.8.8.8, 8.8.4.4, dns.example.com ]关键ResolverController内部维护一个netId - DNS服务器列表的映射表Framework 通过resolver setnetdns命令写入DNS 查询时根据请求 socket 的 netId 查找对应的上游服务器实现不同网络使用不同 DNS。设置 DNS 服务器的命令resolver setnetdns netId domain dns1 dns2 ...六、FwmarkServer — Socket 标记6.1 FwmarkServer 的作用源码路径system/netd/server/FwmarkServer.cpp当应用需要将自己的 Socket 绑定到特定网络时需要设置 fwmark// ConnectivityManager 中的方法network.bindSocket(socket);该操作最终通过/dev/socket/fwmarkd发送命令到 netd 的 FwmarkServerAPP │ │ network.bindSocket(socket) │ ▼ ConnectivityManager │ │ 通过 JNI 调用 native 方法 │ ▼ 通过 /dev/socket/fwmarkd 发送socket_fd netId explicit │ ▼ FwmarkServer 收到命令 │ │ 调用 setsockopt(socket_fd, SOL_SOCKET, SO_MARK, fwmark) │ ▼ 内核为该 Socket 设置 fwmark │ │ 此后该 Socket 的数据包走对应 netId 的路由表 │ ▼ 所有从该 Socket 发出的数据包都走正确的网络出口关键FwmarkServer是 fwmark 机制的用户态入口——应用调用network.bindSocket()后通过setsockopt(SO_MARK)将 fwmark 写入 socket 的内核数据结构此后该 socket 的所有数据包会自动被策略路由匹配到正确的路由表。七、小结本篇覆盖了 netd 的三大核心模块模块方向作用CommandListener上接 Framework接收并分发网络管理命令NetlinkManager下接内核监听内核网络事件并处理DnsProxyListener上接应用代理所有进程的 DNS 请求下一篇将逐一拆解 netd 内部的八个 Controller它们才是真正执行网络操作的核心。