系列目录第一篇全景图与调用链路概览 | 第二篇内核层—netfilter/iptables与路由策略 | 第三篇Native层(上)—netd守护进程与CommandListener | 第四篇Native层(下)—netd Controller详解 | 第五篇Framework层(上)—ConnectivityService核心机制 |第六篇Framework层(下)—NMS/NPMS/NSS三大服务| 第七篇连接建立—WiFi/移动数据/以太网完整流程 | 第八篇应用API层—ConnectivityManager使用与实战调试一、为什么要了解这三大服务第五篇讲到的ConnectivityService是总调度但实际执行网络策略、统计流量、与 netd 通信的是它背后的三个服务。当你遇到以下问题时答案就在它们之中“为什么开启了省电模式某个应用还能用移动数据”——NPMS的白名单可能没有覆盖到该应用“为什么流量统计显示的数字和运营商账单对不上”——NSS的统计周期或持久化文件可能有问题“为什么 Framework 下发的防火墙规则在 netd 中没有生效”——NMS的NativeDaemonConnector通信链路可能断了NMS、NPMS、NSS 三者通过ConnectivityService协调形成执行-统计-决策的闭环┌───────────────────────────────────────────────────┐ │ ConnectivityService (总调度) │ │ 网络评分、切换、默认网络管理 │ └───────────────────────────────────────────────────┘ │ │ │ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ │ NMS │ │ NPMS │ │ NSS │ │ netd通信 │ │ 网络策略 │ │ 流量统计 │ │ 桥梁 │ │ 省电/限制 │ │ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ ▼ ▼ ▼ netd FirewallCtrl xt_qtaguid关键NMS 负责执行NSS 负责统计NPMS 负责决策三者通过ConnectivityService协调形成闭环。二、NetworkManagementService (NMS)2.1 定位与职责NMS 是 Framework 层与 netd 通信的唯一桥梁封装 netd 命令并提供 Java 接口。它的核心职责包括管理网络接口、设置防火墙规则、管理带宽配额、监控网络事件。2.2 与 netd 的通信桥梁NativeDaemonConnectorNMS 不直接操作 Socket而是通过NativeDaemonConnector与 netd 交互。源码路径frameworks/base/services/core/java/com/android/server/NativeDaemonConnector.javafinalclassNativeDaemonConnectorimplementsRunnable,Handler.Callback,Watchdog.Monitor{privateStringmSocket;// 与 netd 的 Socket 路径privateOutputStreammOutputStream;// 发送命令privateLocalLogmLocalLog;// 本地日志privateHandlermCallbackHandler;// 回调分发privateINativeDaemonConnectorCallbacksmCallbacks;// 响应回调privatefinalResponseQueuemResponseQueue;// 响应队列privatestaticfinallongDEFAULT_TIMEOUT1*60*1000;// 默认超时 1 分钟// ...// 入口可变参数格式最常用publicNativeDaemonEventexecute(Stringcmd,Object...args)throwsNativeDaemonConnectorException{returnexecute(DEFAULT_TIMEOUT,cmd,args);}// 带超时版本publicNativeDaemonEventexecute(longtimeoutMs,Stringcmd,Object...args)throwsNativeDaemonConnectorException{finalNativeDaemonEvent[]eventsexecuteForList(timeoutMs,cmd,args);if(events.length!1){thrownewNativeDaemonConnectorException(Expected exactly one response, but received events.length);}returnevents[0];← 期望单条响应多条则抛异常}}关键设计execute最终委托给executeForList后者负责实际的 Socket 通信——将命令序列化为字符串发送、读取响应、解析为NativeDaemonEvent数组。execute校验返回数组长度必须为 1确保单条命令→单条响应的严格对应。关键设计NativeDaemonConnector实现Watchdog.Monitor接口保证与 netd 的通信链路被系统健康监控覆盖——一旦通信线程阻塞超过阈值Watchdog 会触发系统重启。通信过程NMS 调用 mConnector.execute(firewall, set_uid_rule, ...) ↓ NativeDaemonConnector 通过 LocalSocket 发送字符串命令 ↓ netd 的 CommandListener 接收并处理 ↓ NativeDaemonConnector 读取响应由 NativeDaemonEvent 解析 ↓ 解析响应码200 系列成功 / 400/500 系列错误 ↓ 返回给 NMS关键netd 的响应格式为code message由NativeDaemonEvent解析200 系列表示成功400/500 系列表示错误。2.3 NMS 的核心方法NMS 每个方法内部都通过mConnector.execute()向 netd 发送命令方法签名与 netd 支持的命令一一对应。源码路径frameworks/base/services/core/java/com/android/server/NetworkManagementService.javapublicclassNetworkManagementServiceextendsINetworkManagementService.Stub{// ...privatefinalNativeDaemonConnectormConnector;// 与 netd 通信的连接器// —— 接口管理 ——publicString[]listInterfaces();// 列出所有接口publicInterfaceConfigurationgetInterfaceConfig(Stringiface);// 获取接口配置publicvoidsetInterfaceConfig(Stringiface,InterfaceConfigurationcfg);// 设置接口配置publicvoidsetInterfaceDown(Stringiface);// 关闭接口publicvoidsetInterfaceUp(Stringiface);// 启用接口publicvoidaddRoute(intnetId,RouteInforoute);// 添加路由publicvoidremoveRoute(intnetId,RouteInforoute);// 删除路由// —— 防火墙 ——publicvoidsetFirewallEnabled(booleanenabled);// 启用防火墙publicvoidsetFirewallUidRule(intchain,intuid,intrule);// 设置 UID 规则publicvoidsetFirewallInterfaceRule(Stringiface,booleanallow);// 设置接口规则// —— 带宽控制 ——publicvoidsetInterfaceQuota(Stringiface,longquotaBytes);// 设置接口配额publicvoidremoveInterfaceQuota(Stringiface);// 移除接口配额publicvoidsetGlobalAlert(longalertBytes);// 设置全局警告// —— 网络共享 ——publicvoidtetherInterface(Stringiface);// 添加共享接口publicvoiduntetherInterface(Stringiface);// 移除共享接口publicString[]listTetheredInterfaces();// 列出生效的共享接口publicvoidstartTethering(String[]dhcpRange);// 启动共享publicvoidstopTethering();// 停止共享// —— DNS ——publicvoidsetDnsServersForNetwork(intnetId,String[]servers,Stringdomains);// 设置 DNS}2.4 NMS 的命令封装模式每条 NMS 方法都封装成对应的 netd 命令。以setFirewallUidRule为例publicclassNetworkManagementServiceextendsINetworkManagementService.Stub{// ...privatefinalNativeDaemonConnectormConnector;// 与 netd 通信的连接器privatefinalObjectmQuotaLocknewObject();// 配额操作锁publicvoidsetFirewallUidRule(intchain,intuid,intrule){enforceSystemUid();// 强制调用者必须是系统 UIDsynchronized(mQuotaLock){setFirewallUidRuleLocked(chain,uid,rule);}}privatevoidsetFirewallUidRuleLocked(intchain,intuid,intrule){if(updateFirewallUidRuleLocked(chain,uid,rule)){mConnector.execute(firewall,set_uid_rule,getFirewallChainName(chain),uid,getFirewallRuleName(chain,rule));}}}关键设计enforceSystemUid()强制调用者必须是系统 UID防止第三方应用直接操作防火墙规则。关键设计同步锁mQuotaLock保证防火墙规则与配额操作互斥setFirewallUidRuleLocked内部通过mConnector.execute(firewall, set_uid_rule, ...)将命令下发给 netd。2.5 Observer 机制NMS 通过 AIDL 定义的INetworkManagementEventObserver接口让上层服务监听网络事件。Observer 定义在 AIDL 文件中跨进程通信——netd 通过NativeDaemonConnector回调到 NMSNMS 再通过 AIDL 回调通知上层服务。源码路径frameworks/base/core/java/android/net/INetworkManagementEventObserver.aidlinterfaceINetworkManagementEventObserver{voidinterfaceStatusChanged(Stringiface,booleanup);// 接口状态变化voidinterfaceLinkStateChanged(Stringiface,booleanup);// 链路状态变化voidinterfaceAdded(Stringiface);// 接口新增voidinterfaceRemoved(Stringiface);// 接口移除voidaddressUpdated(Stringiface,inLinkAddressaddress);// 地址更新voidaddressRemoved(Stringiface,inLinkAddressaddress);// 地址移除voidlimitReached(StringlimitName,Stringiface);// 达到带宽限制voidinterfaceClassDataActivityChanged(Stringlabel,booleanactive,longtsNanos);// 数据活动voidinterfaceDnsServerInfo(Stringiface,longlifetime,inString[]servers);// DNS 信息voidrouteUpdated(inRouteInforoute);// 路由更新voidrouteRemoved(inRouteInforoute);// 路由移除}netd 通过NetlinkManager检测到内核事件后会向所有已连接的 NMS Observer 发送通知内核接口 wlan0 UP ↓ netd NetlinkManager 收到 RTM_NEWLINK ↓ 通知 NativeDaemonConnector通过 Socket ↓ NMS 收到 600 Iface change 消息 ↓ NMS 遍历所有 Observer ↓ ConnectivityService 收到 interfaceStatusChanged(wlan0, true)关键600 系列响应码是 netd 主动推送的异步事件通知与 200/400/500 系列的命令响应不同——NMS 通过onEvent()回调处理异步事件。三、NetworkPolicyManagerService (NPMS)3.1 定位与职责NPMS 管理系统的网络策略核心功能包括省电模式、流量周期、应用白名单、Doze 模式。3.2 策略的数据结构NetworkPolicy定义了网络策略的核心字段流量周期、警告阈值、硬限制、是否计费网络等。源码路径frameworks/base/core/java/android/net/NetworkPolicy.javapublicclassNetworkPolicyimplementsParcelable,ComparableNetworkPolicy{publicstaticfinalintCYCLE_NONE-1;// 无周期publicstaticfinallongWARNING_DISABLED-1;publicstaticfinallongLIMIT_DISABLED-1;publicstaticfinallongSNOOZE_NEVER-1;publicNetworkTemplatetemplate;// 模板匹配规则publicintcycleDay;// 计费周期日publicStringcycleTimezone;// 时区publiclongwarningBytes;// 警告阈值publiclonglimitBytes;// 硬限制publiclonglastWarningSnooze;// 上次警告推迟时间publiclonglastLimitSnooze;// 上次限制推迟时间publicbooleanmetered;// 是否计费网络publicbooleaninferred;// 是否推断出来的策略}关键设计template字段的类型是NetworkTemplate而非int通过NetworkTemplate的matches()方法匹配具体网络支持通配符匹配如所有 WiFi 网络。3.3 省电模式实现省电模式的核心逻辑是限制后台应用使用移动数据。源码路径frameworks/base/services/core/java/com/android/server/net/NetworkPolicyManagerService.javapublicclassNetworkPolicyManagerServiceextendsINetworkPolicyManager.Stub{// ...privatestaticfinalintFIREWALL_CHAIN_POWERSAVE1;// 省电模式防火墙链privatevoidupdateRulesForGlobalChangeAL(booleanrestrictedNetworksChanged){// restrictedNetworksChanged 为 true 时// 遍历所有非白名单应用将其加入 fw_powersave 链// 同步白名单到 NMS确保白名单应用不受限制}}省电模式生效流程用户开启省电模式 ↓ NPMS.updateRulesForGlobalChangeAL(true) ↓ 遍历所有非白名单应用 ↓ NMS.setFirewallUidRule(CHAIN_POWERSAVE, uid, DENY) ↓ 向 netd 发送 ↓ firewall set_uid_rule powersave uid deny ↓ netd FirewallController 执行 iptables 规则 iptables -I fw_powersave -o rmnet_data0 -m owner --uid-owner uid -j REJECT ↓ 该 UID 的应用发送移动数据 → 被 iptables REJECT关键省电模式只限制移动数据-o rmnet_data0WiFi 不受影响确保用户在 WiFi 环境下仍可正常使用。白名单有三个来源系统预置白名单来自SystemConfig/system/etc/permissions/下的 XML 配置用户手动添加的白名单持久化在/data/system/deviceidle.xml临时白名单仅存于内存。NPMS通过DeviceIdleController.getAppIdWhitelist()获取白名单再调用updateRulesForWhitelistedPowerSaveUL同步到NMS确保白名单应用不受防火墙规则限制。3.4 Doze 模式与网络限制Doze 模式比省电模式更严格——完全禁止后台应用的网络访问不仅是移动数据只在设备长时间不使用时激活定期打开维护窗口让应用同步数据。publicclassNetworkPolicyManagerServiceextendsINetworkPolicyManager.Stub{// ...privatebooleanmDeviceIdleMode;// Doze 模式标志voidupdateRulesForDeviceIdleUL(){// deviceIdle true 时// 所有非白名单应用加入 fw_dozable 链禁止所有网络访问包括 WiFiupdateRulesForWhitelistedPowerSaveUL(mDeviceIdleMode,FIREWALL_CHAIN_DOZABLE,mUidFirewallDozableRules);}}关键Doze 模式下fw_dozable链同时作用于 INPUT 和 OUTPUT但 ICMPv6 邻居发现协议RS/RA/NS/NA会被放行避免 IPv6 连接完全中断。3.5 流量周期与警告warningBytes和limitBytes分离——警告只是通知不阻断网络硬限制会直接禁用移动数据。NPMS通过NetworkPolicy的warningBytes和limitBytes字段驱动通知逻辑用户设置流量上限为 1GB ↓ NPMS 创建/更新 NetworkPolicy (limitBytes 1GB) ↓ 每次 NSS 更新流量数据后通知 NPMS ↓ NPMS 调用 NSS.getNetworkStats(mobileTemplate) ↓ 获取移动数据总流量 ↓ 比较 total vs warning / limit ├── total warning (900MB) → 正常 ├── total warning → 发送警告通知 └── total limit (1GB) → 禁用移动数据四、NetworkStatsService (NSS)4.1 定位与职责NSS 负责统计系统的网络流量是 NPMS 的眼睛——NPMS 需要流量数据来判断是否达到警告或限制阈值。4.2 数据源NSS 从内核xt_qtaguid模块收集流量数据。xt_qtaguid在内核中为每个 Socket 创建唯一的 tag所有数据包在协议栈中自动统计。来源1xt_qtaguid内核统计内核 xt_qtaguid 模块 → /proc/net/xt_qtaguid/stats ↓ NetworkStatsFactory 定期读取 ↓ 解析为 NetworkStats 对象每条统计记录由NetworkStats.Entry承载源码路径frameworks/base/core/java/android/net/NetworkStats.javapublicclassNetworkStatsimplementsParcelable{publicstaticclassEntry{publicStringiface;// 接口名wlan0 / rmnet_data0publicintuid;// 应用 UIDpublicintset;// DEFAULT / FOREGROUND / BACKGROUNDpublicinttag;// 流量标记0x0 或应用的标记publicintroaming;// 是否漫游publiclongrxBytes;// 接收字节数publiclongrxPackets;// 接收数据包数publiclongtxBytes;// 发送字节数publiclongtxPackets;// 发送数据包数publiclongoperations;// 操作计数}}关键设计set字段区分前台FOREGROUND和后台BACKGROUND流量让 NPMS 可以分别控制前后台的数据使用策略。关键设计tag字段支持应用通过TrafficStats.setThreadStatsTag()自定义标记实现 Socket 级别的精细化流量追踪。来源2当应用调用TrafficStats.setThreadStatsTag()时NSS 也会记录这些标记统计。4.3 统计周期与持久化NSS 按多个周期统计流量三种 bucket 粒度不同——设备级只关心接口总量UID 级按应用区分UIDTag 级最细粒度。源码路径frameworks/base/services/core/java/com/android/server/net/NetworkStatsService.javapublicclassNetworkStatsServiceextendsINetworkStatsService.Stub{// ...// 统计周期配置从 Settings.Global 读取// NETSTATS_DEV_BUCKET_DURATION — 设备级默认 1 小时// NETSTATS_UID_BUCKET_DURATION — UID 级默认 2 小时// NETSTATS_UID_TAG_BUCKET_DURATION — UIDTag 级默认 2 小时// 持久化目录privatestaticfinalStringPREFIX_XTxt;// 与 /data/system/netstats/ 组合// 实际持久化文件// /data/system/netstats/netstats.bin — 设备级// /data/system/netstats/netstats_xt.bin — 按 UIDTag// /data/system/netstats/netstats_uid.bin — 按 UID}数据持久化流程NSS 定期从内核读取流量数据 ↓ 与已有数据合并accumulate ↓ 写入 /data/system/netstats/netstats*.bin ↓ NPMS 读取该文件判断是否达到限制关键持久化使用二进制格式重启后可以恢复统计数据避免因重启丢失流量记录。4.4 NetworkTemplate 匹配机制NSS 通过NetworkTemplate来匹配特定网络的流量。源码路径frameworks/base/core/java/android/net/NetworkTemplate.javapublicclassNetworkTemplate{// 匹配所有 WiFi 网络publicstaticNetworkTemplatebuildTemplateWifiWildcard();// 匹配所有移动数据网络按 IMSIpublicstaticNetworkTemplatebuildTemplateMobileAll(StringsubscriberId);// 匹配所有移动数据网络通配符不区分运营商publicstaticNetworkTemplatebuildTemplateMobileWildcard();// 匹配以太网publicstaticNetworkTemplatebuildTemplateEthernet();}这样 NPMS 可以查询特定网络的流量getNetworkStats()返回的是累计值NPMS 需要自行计算周期内的增量。// 查询移动数据本月流量NetworkTemplatemobileTemplateNetworkTemplate.buildTemplateMobileAll(subscriberId);NetworkStatsstatsmNetworkStatsService.getNetworkStats(mobileTemplate);longtotalBytesstats.getTotalBytes();4.5 与 NPMS 的协作用户设置流量上限为 1GB ↓ NPMS 创建 NetworkPolicy (limitBytes 1GB) ↓ 每次 NSS 更新流量数据后通知 NPMS ↓ NPMS 调用 NSS.getNetworkStats(mobileTemplate) ↓ 获取移动数据总流量 ↓ 比较 total vs limit ├── total warning (900MB) → 正常 ├── total warning → 发送警告通知 └── total limit (1GB) → 禁用移动数据关键NSS 和 NPMS 通过INetworkStatsService/INetworkPolicyManager的 AIDL 接口通信两者相互独立通过ConnectivityService协调。五、三大服务协作全景 — 省电流量限制 完整链路用一个完整的省电 流量限制场景串联三大服务用户开启省电模式 设置了 1GB 流量上限 ↓ ┌──────────────────────────────────────────┐ │ NPMS策略管理层 │ │ ├── 监听省电模式开关 │ │ ├── 加载 NetworkPolicy (1GB 上限) │ │ └── 决定限制哪些应用的网络 │ └──────────┬──────────┬─────────────────────┘ │ │ ┌──────▼──────┐ │ │ NSS │ │ │ 提供流量 │ │ │ 统计数据 │←──┘ └─────────────┘ │ NPMS 调用 NMS │ ┌──────────▼─────────────────────────────────┐ │ NMS命令执行层 │ │ ├── setFirewallUidRule(powersave, uid, deny) │ │ └── setInterfaceQuota(rmnet0, 1GB) │ └──────────┬─────────────────────────────────┘ │ NativeDaemonConnector ▼ ┌──────────────────────────────────────────┐ │ netd Controller 层 │ │ FirewallController → iptables 规则 │ │ BandwidthController → xt_qtaguid 配额 │ └──────────┬─────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────┐ │ 内核层 │ │ netfilter/iptables 拦截包 │ │ xt_qtaguid 统计流量 │ └──────────────────────────────────────────┘关键NPMS 是决策层“限制谁”NSS 是感知层“用了多少”NMS 是执行层“怎么限制”三者通过ConnectivityService协调完成完整的网络策略闭环。六、关键源码文件索引文件路径本文涉及内容NetworkManagementService.javaframeworks/base/services/core/java/com/android/server/netd 通信桥梁、防火墙规则、Observer 机制NativeDaemonConnector.javaframeworks/base/services/core/java/com/android/server/Socket 通信、命令封装INetworkManagementEventObserver.aidlframeworks/base/core/java/android/net/网络事件回调接口NetworkPolicyManagerService.javaframeworks/base/services/core/java/com/android/server/net/省电模式、Doze、流量周期NetworkPolicy.javaframeworks/base/core/java/android/net/网络策略数据结构NetworkStatsService.javaframeworks/base/services/core/java/com/android/server/net/流量统计、持久化NetworkStats.javaframeworks/base/core/java/android/net/流量统计条目NetworkTemplate.javaframeworks/base/core/java/android/net/网络匹配模板七、小结三大服务各有侧重协同工作服务核心职责关键交互NMSnetd 通信桥梁NativeDaemonConnectorINetworkManagementEventObserverNPMS网络策略管理省电/Doze/流量周期NSS流量统计xt_qtaguid 持久化下一篇将进入网络代理层逐一拆解 WiFi、移动数据、以太网三种网络的完整建立流程。