App 运行环境复杂,用户投诉中很大一部分来源于”页面加载慢”、“登录失败”、“连接不稳定”等网络相关问题,而这些问题在测试环境中难以复现。传统的服务端监控或 CDN 日志,无法还原终端真实的网络状态。
因此,我们希望:
- 主动感知用户当前网络情况
- 识别网络故障的真实原因
- 为定位、修复、优化网络问题提供结构化数据支持
应用网速检查
🔍 原理
该模块基于 Android 原生的 TrafficStats
API,按应用 UID 粒度,在固定短时窗口内(如 5 秒)读取接收流量增量,并通过增量字节数除以时间差来计算出客户端的真实下载速度,无需额外权限或网络请求,运行轻量且接近用户真实网络体验。
🕒 检查时机
- 应用启动时:首次启动立即检查
- 网络切换时:如 WiFi 切换到 移动网络
- 应用回前台时:预防后台期间网络发生变化
- 请求失败时:辅助诊断网络层面的问题
- 每 20 秒定期执行:用于长时间留存的场景下持续采样
每次检查都有去重机制,确保 5 秒内不重复执行。
📊 数据上报
内容 | 示例值 |
---|---|
平均下载速度 | 32000 |
当前网络类型 | WIFI / 4G / 5G |
运营商名称 | 中国联通 |
移动网络信号强度 | -88 |
是否处于漫游状态 | false |
WiFi 信号等级 | 3 |
当前检测的触发场景 | app_launch / net_change 等 |
注:部分字段需特定权限支持,只会判断不会尝试申请,若权限缺失将不会上报对应字段
DNS 劫持检测
🔍 原理
DNS 劫持是客户端常见的网络安全问题,尤其在公共 WiFi 或部分三线运营商环境下更易复现。我们通过 “系统 DNS” 与 “可信 DoH 服务” 的解析结果对比 来识别是否存在劫持行为。
- 系统 DNS:调用
InetAddress.getAllByName()
- DoH 服务:如 Google DNS、AliDNS,通过加密连接获取的权威解析结果
判断逻辑:
- 若系统解析结果 ⊈ DoH 汇总池 → 判定为劫持
- 若系统 IP 全部包含在 DoH 返回值中 → 视为正常(即便 DoH 多返回 IP)
🕒 检查时机
为了节省资源,DNS 劫持检查 仅在出现网络请求失败且命中特定异常类型集合时触发,并设置 5 秒冷却时间防止重复触发。
相比启动时、切网时等高频触发机制,这种 按需触发 + 精准异常命中 的策略更具性价比,避免不必要的资源开销。
⚠️ 异常类型集
网络异常中可能与 DNS 劫持有关的典型异常。
异常类型 | 原因分类 | 说明 |
---|---|---|
CertPathValidatorException | 证书不可信 | TLS 证书签名链不受信任,常见于中间人攻击 |
SSLHandshakeException / SSLPeerUnverifiedException | TLS 握手失败 | 证书链异常或握手中断 |
UnknownHostException | DNS 解析失败 | 无法将域名解析为 IP,常见于 DNS 劫持或被污染 |
ConnectException | 连接被拒绝 | 网络可达但目标端口未响应,可能是劫持后伪地址 |
SocketTimeoutException | TCP 超时 | 网络拥堵或服务不可达 |
📊 数据上报
内容 | 示例值 |
---|---|
检查目标域名 | api.example.com |
系统 DNS 返回的 IP 列表 | 1.2.3.4,5.6.7.8 |
DoH 返回的 IP 汇总池 | 1.2.3.4,9.9.9.9 |
是否判定为 DNS 劫持 | true / false |
触发检查的异常类型 | UnknownHostException |
当前网络类型 | WIFI / 4G |
编辑于 Jul 13