Android 7系统网络(八)应用API层—ConnectivityManager使用与实战调试

系列目录第一篇:全景图与调用链路概览 | 第二篇:内核层---netfilter/iptables与路由策略 | 第三篇:Native层(上)---netd守护进程与CommandListener | 第四篇:Native层(下)---netd Controller详解 | 第五篇:Framework层(上)---ConnectivityService核心机制 | 第六篇:Framework层(下)---NMS/NPMS/NSS三大服务 | 第七篇:连接建立---WiFi/移动数据/以太网完整流程 | 第八篇:应用API层---ConnectivityManager使用与实战调试


一、ConnectivityManager 核心 API

源码路径frameworks/base/core/java/android/net/ConnectivityManager.java

1.1 查询网络状态(旧 API)

java 复制代码
ConnectivityManager cm = (ConnectivityManager) context
    .getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo wifiInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
NetworkInfo mobileInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null && activeNetwork.isConnected();

关键 :旧 API 通过 TYPE_WIFITYPE_MOBILE 等常量按网络类型查询,getActiveNetworkInfo() 返回当前默认网络信息,Android 5.0 后推荐使用 NetworkRequest 替代。

1.2 请求特定网络(新 API --- Android 5.0+)

java 复制代码
NetworkRequest request = new NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .build();

ConnectivityManager.NetworkCallback callback = new ConnectivityManager.NetworkCallback() {
    @Override public void onAvailable(Network network) { /* 网络可用 */ }
    @Override public void onLost(Network network) { /* 网络丢失 */ }
    @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {}
    @Override public void onLinkPropertiesChanged(Network network, LinkProperties lp) {}
};
cm.requestNetwork(request, callback);
// 释放时:cm.unregisterNetworkCallback(callback);

关键设计NetworkRequest.Builder 通过 addTransportTypeaddCapability 精确指定网络需求,NetworkCallback 以回调方式通知网络状态变化,替代了传统广播机制。

1.3 绑定进程/套接字到特定网络

java 复制代码
// 绑定整个进程
Network wifiNetwork = ...;
cm.bindProcessToNetwork(wifiNetwork);

// 只绑定单个 socket
Network mobileNetwork = ...;
Socket socket = new Socket();
mobileNetwork.bindSocket(socket);

// 打开指定网络的 URL 连接
URL url = new URL("https://example.com");
HttpURLConnection conn = (HttpURLConnection) wifiNetwork.openConnection(url);

关键设计bindProcessToNetwork 绑定整个进程的网络出口,bindSocket 仅绑定单个 Socket,openConnection 在指定 Network 上打开 URL 连接,三者提供不同粒度的网络绑定能力。

1.4 多网络并存的实战示例

java 复制代码
// 下载大文件用 WiFi,IM 长连接用最优网络
NetworkRequest downloadReq = new NetworkRequest.Builder()
    .addTransportType(TRANSPORT_WIFI)
    .addCapability(NET_CAPABILITY_INTERNET)
    .addCapability(NET_CAPABILITY_NOT_METERED)
    .build();
cm.requestNetwork(downloadReq, new NetworkCallback() {
    @Override public void onAvailable(Network network) {
        network.bindSocket(downloadSocket);
        startDownload();
    }
});

NetworkRequest imReq = new NetworkRequest.Builder()
    .addCapability(NET_CAPABILITY_INTERNET)
    .build();
cm.requestNetwork(imReq, new NetworkCallback() {
    @Override public void onAvailable(Network network) {
        cm.bindProcessToNetwork(network);
        startIMConnection();
    }
});

关键设计 :同时注册两个 NetworkRequest,通过不同的 NetworkCallback 将下载流量绑定到 WiFi(NOT_METERED),将 IM 长连接绑定到最优网络(仅要求 INTERNET),实现多网络并发使用。


二、调试命令大全

2.1 dumpsys --- 网络诊断的最强工具

源码路径adb shell(Android 调试桥)

bash 复制代码
adb shell dumpsys connectivity    # ConnectivityService 完整状态
adb shell dumpsys netpolicy       # 网络策略与省电模式
adb shell dumpsys netstats        # 流量统计(按 UID+接口)
adb shell dumpsys wifi            # WiFi 完整状态

关键dumpsys 是网络诊断的首选工具,dumpsys connectivity 输出包含所有 NetworkAgent、NetworkRequest、评分和验证状态。

2.2 ndc --- 直接与 netd 通信

源码路径adb shell(Android 调试桥)

bash 复制代码
adb shell ndc interface list                    # 列出所有接口
adb shell ndc firewall is_enabled               # 防火墙状态
adb shell ndc bandwidth getiquota rmnet_data0   # 查看配额
adb shell ndc tether status                     # 网络共享状态
adb shell ndc resolver getdnsserversnetid 100   # DNS 配置
adb shell ndc network route add 100 wlan0 0.0.0.0/0 192.168.1.1

关键ndc 通过 NativeDaemonConnectornetd 守护进程直接通信,可执行 CommandListener 中注册的所有命令。

2.3 iptables / iproute2 --- 内核层诊断

源码路径adb shell(Android 调试桥)

bash 复制代码
adb shell iptables -L -n -v                     # filter 表规则
adb shell iptables -t nat -L -n -v              # nat 表(网络共享)
adb shell iptables -L fw_powersave -n -v        # 省电模式规则
adb shell iptables -L fw_dozable -n -v          # Doze 规则

adb shell ip rule show                          # 策略路由规则
adb shell ip route show table 100               # netId=100 的路由表
adb shell ip addr show                          # 所有接口地址

关键iptablesip 命令直接查看内核层网络规则,是排查防火墙拦截和路由异常的核心手段。

2.4 tcpdump --- 抓包分析

源码路径adb shell(Android 调试桥)

bash 复制代码
adb shell tcpdump -i wlan0 -w /sdcard/cap.pcap  # 抓 WiFi 包
adb shell tcpdump -i wlan0 port 53               # 只抓 DNS
adb pull /sdcard/cap.pcap .

关键tcpdump 抓取原始网络数据包,配合 Wireshark 分析协议交互细节,是定位网络不通问题的终极手段。

2.5 日志分析技巧

源码路径adb shell(Android 调试桥)

bash 复制代码
# WiFi 连接过程
adb logcat -s WifiStateMachine:D WifiNative:D DhcpClient:D

# ConnectivityService 评分切换
adb logcat -s ConnectivityService:D

# netd 命令交互
adb logcat -s NativeDaemonConnector:D

# 网络策略
adb logcat -s NetworkPolicy:D

# 移动数据连接
adb logcat -s DcTracker:D DataConnection:D RILJ:D

# 全套网络日志
adb logcat -s ConnectivityService:D NetworkPolicy:D NetworkStats:D NetworkMonitor:D

关键logcat -s 按 tag 过滤日志,覆盖 WiFi 连接、评分切换、netd 交互、网络策略和移动数据连接五大核心模块。


三、六大典型问题分析

问题一:"WiFi 已连接但无法上网"

排查 :检查 DHCP 是否获取 IP (ip addr show wlan0),检查默认路由 (ip route show table 100),检查 DNS 可达性 (ping 8.8.8.8),检查 NetworkMonitor 验证 (dumpsys connectivity | grep VALIDATED),检查 Captive Portal (dumpsys connectivity | grep captive)。

常见原因:DHCP 失败、NetworkMonitor 验证失败(Captive Portal 检测不可达)、DNS 错误、iptables 防火墙阻止。

问题二:"WiFi 切换移动数据太慢"

排查dumpsys connectivity 查看评分切换,logcat -s WifiStateMachine 查看断开时间点。常见原因:Linger 暂缓时间过长、DHCP 租约过短、移动数据未保持激活、依赖 CONNECTIVITY_ACTION 广播延迟。

优化:保持移动数据 always on、使用 NetworkCallback 替代 BroadcastReceiver、调整 WiFi 信号阈值。

问题三:"省电模式限制了后台网络"

排查iptables -L fw_powersave -n -v | grep <uid> 查看是否被拦截,dumpsys netpolicy 查看白名单。解决:加入省电白名单、使用前台服务保持连接。

问题四:"VPN 连上后网络断开"

排查dumpsys connectivity | grep VPN 查看 VPN NetworkAgent,ip rule show 查看 fwmark 规则,ndc resolver getdnsserversnetid <vpnNetId> 检查 DNS。常见原因:路由表错误、VPN DNS 不可达、路由表未正确清理。

问题五:"热点共享失败"

排查cat /proc/sys/net/ipv4/ip_forward(应为 1),iptables -t nat -L POSTROUTING(应有 MASQUERADE),ps | grep dnsmasq(应正在运行)。

问题六:"流量统计不准确"

排查dumpsys netstats 查看系统统计,cat /proc/net/xt_qtaguid/stats 查看内核原始数据。常见原因:IP 层 vs 链路层统计差异、运营商包含信令流量、计费周期不一致。


四、快速诊断速查表

症状 第一命令 关键检查点
WiFi 无法上网 `dumpsys connectivity grep -A10 WiFi`
切换慢 logcat -s ConnectivityService Linger 时间、评分变化
应用被限网 `iptables -L fw_powersave -n grep `
VPN 故障 ip rule show fwmark 优先级、tun0 接口
热点失败 cat /proc/sys/net/ipv4/ip_forward IP 转发、NAT 规则
流量异常 dumpsys netstats 按 UID 定位、与 /proc 对比

五、系列总结

本系列从 Linux 内核一路走到 Android 应用 API,覆盖了以下关键层级:

层级 核心内容 关键文件/模块
内核层 netfilter/iptables、fwmark、策略路由 RouteController.cpp
Native 层 netd 守护进程、八大 Controller main.cpp / CommandListener.cpp
Framework 层 ConnectivityService + NMS/NPMS/NSS ConnectivityService.java
网络代理层 WiFi/移动数据/以太网 NetworkAgent WifiStateMachine / DataConnection
应用 API 层 ConnectivityManager + 调试工具链 ConnectivityManager.java

理解 Android 网络系统的最有效方式:带着一个问题,沿着调用链路从头走到尾。每次追踪一个具体场景(如 WiFi 连接),从应用层一直追到内核 iptables 规则,这种"纵深阅读"能让各个环节的交互变得清晰。

下一篇将进入车机定制实践,展示多接口绑定、流量配额管理和网络共享管控的完整实现方案,将前八篇的理论知识应用到实际工程场景中。

相关推荐
plainGeekDev2 小时前
kapt 替换为 KSP
android·java·kotlin
蜡台2 小时前
通过Gradle脚本声明更改Java变量
android·java·开发语言·python·kotlin·gradle·groovy
希望奇迹很安静3 小时前
数通基本实验
运维·服务器·网络
ITxiaobing20234 小时前
如何构建IP维度的假量排查流程:以AppsFlyer Protect360判假后的实战为例
网络·数据库
Eloudy4 小时前
基于 RDMA-CM(librdmacm)的聊天程序
网络·人工智能
(Charon)4 小时前
【C/C++】手写内存池(三):大块内存的申请、记录与单独释放
网络
阿pin5 小时前
Android随笔-SharedPreferences
android·sp
一只小菜鸡..6 小时前
Stanford CS144 学习笔记 (二):传输层与数据通信机制
网络·笔记·学习
超防局6 小时前
网络安全渗透测试常用工具详解
网络·安全·web安全