实时监控 Android 主线程消息调度,抓取消息积压和处理超时,生成结构化记录文件,通过 Python 脚本处理成聚合时间图表,直观展示 ANR 根因。
| 能力 | 实现方式 |
|---|---|
| 慢消息检测 | LooperHook 拦截每条消息 dispatch,Wall/CPU 双计时 |
| 积压检测 | QueueSniffer 每 100ms 反射读取 MessageQueue 链表 |
| Barrier 检测 | 检测 msg.target == null,标注持续时间 + 自动触发 dump |
| 消息来源 | StackSampler 抓取堆栈提取业务代码帧 |
| 消息分类 | 9 种标签:ACTIVITY / SERVICE / BROADCAST / VSYNC / INPUT / BARRIER / IDLE / APP_START / PROVIDER / CUSTOM |
| 聚合降噪 | 参考今日头条 Raster 的 4 种策略:多消息聚合 / 聚合拆分 / 关键消息标记 / IDLE 识别 |
| 图表分析 | 5 张 Matplotlib 图表 + 自动分析报告 |
anr-message-monitor/
├── build.gradle.kts # 根构建脚本(AGP 8.7.3 + Kotlin 2.1.0)
├── settings.gradle.kts # 项目配置
├── gradle.properties
├── gradle/wrapper/gradle-wrapper.properties # Gradle 8.9
│
├── sdk/ # Android Library 模块
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ └── src/main/java/com/monitor/
│ ├── MessageMonitor.kt # SDK 入口(单例 object)
│ ├── LooperHook.kt # Printer 注入,消息耗时监控
│ ├── QueueSniffer.kt # 反射遍历队列,Barrier 检测
│ ├── StackSampler.kt # 对齐式超时堆栈采样
│ ├── DataAggregator.kt # 4 种聚合策略
│ ├── RingBuffer.kt # 循环缓冲区
│ ├── RecordWriter.kt # JSONL 文件写入
│ ├── MessageClassifier.kt # 消息分类
│ ├── CpuTimeReader.kt # /proc/stat 读 CPU 时间
│ └── model/
│ ├── DispatchRecord.kt
│ └── QueueSnapshot.kt
│
├── scripts/ # Python 分析工具
│ ├── analyze.py # 主入口
│ ├── parser.py # JSONL 解析
│ ├── mpl_config.py # CJK 字体配置
│ ├── chart_timeline.py # 消息调度时间线图
│ ├── chart_wall_cpu.py # Wall vs CPU 对比图
│ ├── chart_backlog.py # 积压趋势图
│ ├── chart_source.py # 来源归属图
│ ├── chart_classification.py # 消息分类统计图
│ └── generate_test_data.py # 测试数据生成
├── requirements.txt
└── README.md
在 Application.onCreate() 中初始化:
import com.monitor.MessageMonitor
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
MessageMonitor.init(this)
MessageMonitor.start()
}
}可选配置(必须在 init() 之前调用):
MessageMonitor.setRingBufferCapacity(300) // 环形缓冲区容量(默认 200)
MessageMonitor.setQueueCheckIntervalMs(150) // 队列检测间隔 ms(默认 100)
MessageMonitor.setStackSamplingEnabled(false) // 关闭堆栈采样以降低开销// 手动触发
MessageMonitor.dump("user_report")
// 自动触发条件:
// - Barrier 检测到 → 自动 dump(5s 限频)
// - 待调度消息 > 50 条 → 自动 dump
// - 主线程疑似 ANR → 自动 dump
// - stop() 时自动 dump 残余数据// 获取输出目录
val path = MessageMonitor.outputPath
// 通常为: /data/data/<package>/files/message_monitor/adb pull /data/data/com.your.app/files/message_monitor/ ./dump_data/cd scripts
pip install -r ../requirements.txt
python analyze.py ./dump_data/dump_barrier_20260504_120000.jsonl ./output/| 图表 | 说明 |
|---|---|
chart_timeline.png |
核心图 — 消息调度时间线(Gantt 风格),蓝色=聚合,红色=慢消息,橙色=Barrier,黄色=关键消息 |
chart_wall_cpu.png |
Wall vs CPU 双柱对比,Wall/CPU > 3 标注为等待/抢占型 |
chart_backlog.png |
积压趋势折线图 + Barrier 高亮区域 |
chart_source.png |
来源模块耗时分布(按 Handler 类名聚合) |
chart_classification.png |
消息分类统计(耗时 + 数量 + Wall/CPU 比值) |
report.txt |
文字分析报告(含初步结论) |
用 Android Studio 打开项目根目录,或命令行:
# 生成 AAR
./gradlew :sdk:assembleRelease
# 收集完整 SDK 发布包(AAR + sources.jar + proguard)
./gradlew :sdk:assembleSdk
# 打包 zip
./gradlew :sdk:packageSdk输出位置:sdk/build/outputs/sdk/
基于以下领域知识设计(详见项目文档目录):
- Raster 监控工具(今日头条):消息调度时序监控,由点到面回放"过去、现在和将来"
- Barrier 机制:同步屏障消息
msg.target == null未正确移除会导致主线程假死 - Wall vs CPU Duration:区分真耗时(密集计算)和被抢占/等待(IO、锁、系统负载)
- ANR 六步分析法:Trace → 关键字 → 系统负载 → 进程 CPU → 线程 CPU → 消息调度