Android ANR(Application Not Responding)分析看起来像是在“读日志”,但真正困难的地方并不只是日志太多,而是证据太散、时间线不一致、系统上下文复杂,并且很容易因为某一段醒目的堆栈或日志而过早定责。

llm-anr 这个仓库要解决的正是这个问题:把 trace、EventLog、logcat、AnrManager dump、meminfo、kernel log 等多源原始材料,转换成按 ANR 事件隔离、可审计、可复盘的证据工作区,再引导 AI 或人工分析者逐层完成保守分析。

这篇文章从三个角度介绍这个项目:它为什么这样设计、开发流程如何组织,以及当前最终交付出了什么能力。

项目地址:yuchuangu85/llm-anr: Agent-driven Android ANR evidence extraction and AI-assisted root cause analysis pipeline.


一、项目要解决的问题

在实际 Android 稳定性分析中,ANR bugreport 往往有几个典型痛点:

  1. 日志规模巨大
    logcat、event log、kernel log 可能达到数百 MB 甚至 GB 级,直接把全文交给人或 LLM 都不可行。

  2. 证据分布在不同来源
    trace 里有线程状态和调用栈,EventLog 里有 am_anr anchor,logcat/AnrManager 里有 reason、CPU、PSI、dump flow,meminfo/kernel log 又提供资源压力背景。单看任何一个来源都可能误判。

  3. 时间锚点并不总是直观
    AnrManager: ANR in 往往发生在 dump 阶段,不一定等于真实 ANR 触发时间。项目因此强调以 am_anr、trace header、类型特定日志做交叉锚定。

  4. 多个 ANR 容易相互污染
    同一份输入里可能存在多个 ANR。如果不按 anchor 拆组,trace、logcat、AnrManager、meminfo 很容易串用,导致把 A 事件的证据套到 B 事件上。

  5. AI 容易“像专家一样武断”
    ANR 分析需要候选链路、证据缺口和人工确认,而不是一上来输出“最终根因”。因此项目把所有自动分析结论都设计为保守候选:finalJudgment = falsenotRootCauseYet = truerequiresHumanConfirmation = true

所以,agent-anr 的目标不是“自动替人拍板”,而是:

高召回地抽取关键证据,用结构化方式压缩上下文,用分来源分析降低幻觉,用跨源融合形成可审计的候选根因链。


二、核心设计思想

1. Baseline evidence 是硬保证

项目最重要的设计原则之一是:baseline evidence 不可被类型策略删除

也就是说,不管当前 ANR 被识别成 input_dispatching_timeoutno_focus_windowbroadcast_timeout 还是未知类型,基础证据源都必须保留。类型模板只能做加法:增加关注窗口、关键词和提示,而不能因为“看起来不像某类问题”就把 trace、EventLog、logcat 或系统上下文裁掉。

这个原则直接服务于高召回:在早期证据不足时,宁可保留更多上下文,也不让过滤器把真正根因删掉。

2. 先锚定事件,再切分证据

llm-anr 将 ANR anchor 作为分析中心。典型 anchor 包括:

  • EventLog 中的 am_anr
  • trace 文件头中的 ANR 时间;
  • logcat 或 AnrManager 中的 ANR reason;
  • 特定类型日志,例如 InputDispatcher timeout、no focused window、broadcast timeout、service timeout 等。

当输入中出现多个 ANR 时,系统会按 anchor 拆成多个独立 group,并为每个 group 生成独立目录:

1
2
3
4
5
anr_ai_context/
index.json
anr-<timestamp-or-anchor>/
anr_analysis.md
logcat.txt

这样做的价值在于:每个 ANR 都有自己的证据窗口、logcat 文件、分析槽位和完成状态,避免跨事件串证据。

3. 从原始文本转向 Evidence Slice

设计文档中把核心架构概括为:

1
Raw Data -> Evidence Slices -> Hypothesis Generation -> Causal Conclusion

系统并不鼓励把原始日志全文直接交给 AI,而是通过预处理、过滤和归一化,把日志转为更高信噪比的证据片段。证据片段保留来源、时间、重要性、原始内容和关联实体,便于后续聚合与审计。

相关模块包括:

  • evidence_slice.py:Evidence Slice Schema;
  • time_norm.py / normalizer.py:时间归一化与 Phase 2 标准化;
  • entity_linker.py:PID/TID/UID/包名等实体关联;
  • weighting.py:证据重要性分级;
  • context_flooding.py:上下文防溢出策略。

这背后的思想是:LLM 不应该被迫在海量噪声中“猜重点”,而应该拿到经过工程侧处理后的高密度证据。

4. 按来源分阶段分析,避免过早综合

AI 工作区 anr_analysis.md 固定包含四个分析槽位:

  1. Trace-only analysis;
  2. EventLog / anchor-only analysis;
  3. Logcat + AnrManager + meminfo follow-up analysis;
  4. Final cross-source ANR synthesis。

前三段只允许做来源内分析,不能提前下最终根因。最终综合必须在前三段完成后再整合,并写回同一个 Markdown 文件。

这种约束非常关键:它迫使分析过程先回答“每个来源能单独证明什么”,再回答“多个来源合起来是否支持同一条因果链”。

5. 触发类型与根因提示分层

项目区分两个概念:

  • triggerType:ANR 触发机制,例如 input dispatch timeout、no focus window、broadcast timeout;
  • rootCausePatternHints[]:候选根因模式,例如 deadlock、memory pressure、high load、binder wait、render fence 等。

二者不能混为一谈。一个 input dispatch timeout 可能由主线程锁等待导致,也可能由 Binder 对端、渲染 fence、系统高负载、内存压力等因素触发。触发类型回答“ANR 是怎么被系统报出来的”,根因 hint 回答“可能是什么链路造成的”。

6. 大文件过滤采用流式和窗口化思路

仓库中的算法设计文档强调“正向定位锚点 + 倒序块扫描”:

  • 先流式扫描找到 am_anr 等 anchor;
  • 记录 timestamp 和文件 offset;
  • 再从 anchor 附近按时间窗口回溯;
  • 只保留窗口内且语义相关的行。

工程上,这让内存占用与目标时间窗口相关,而不是与原始日志总大小相关。对于超大 logcat,这是从“能不能跑”到“可以稳定跑”的关键差异。


三、开发流程

Phase 0:输入加载与预处理

项目支持多种输入:

  • fixture JSON;
  • 已解压 bugreport 目录;
  • 普通日志目录;
  • .zip
  • .tar.tar.gz.tgz.tar.bz2.tar.xz

入口包括:

1
python3 scripts/anr_to_ai.py <input> [--package <pkg>] [--anr-type <type>]

以及包形式 CLI:

1
2
python3 -m anr_evidence <input>
python3 -m anr_evidence --build-ai-context <input>

加载层会识别常见 Android / 厂商目录结构,例如:

  • data/anr/FS/data/anr/
  • event-log/
  • logs/android-logs/
  • dropbox/
  • System_log/meminfo.txt
  • last_kmsglastkmsgconsole_ramoops

Phase 1:证据抽取

核心入口是 anr_evidence/extractor.py。它会完成:

  • 输入标准化;
  • ANR 类型识别;
  • anchor candidate 收集与主 anchor 选择;
  • baseline evidence 抽取;
  • 类型模板的加法扩展;
  • source summary 与 warning 汇总。

与之配套的模块包括:

1
2
3
4
5
6
7
8
9
10
11
12
13
anr_evidence/extraction/
anchors.py
classification.py
common.py
evidence.py
summary.py

anr_evidence/sources/
trace/filter.py
event_log/filter.py
logcat/filter.py
meminfo/filter.py
shared/

Phase 2:标准化

normalizer.py 负责把 Phase 1 的证据转成更统一的结构,包括来源、时间、provenance、fallback/degraded 状态等。

这个阶段的重点不是“下结论”,而是让后续阶段看到一致的数据形态。

Phase 3:辅助分析

analyzer.py 在标准化证据基础上生成:

  • timeline;
  • signal summary;
  • trace insight;
  • input insight;
  • 非最终 finding。

这里仍然保持“非最终”语义,只描述现象和候选信号。

Phase 5/6/7/8:候选链路到交付报告

确定性流水线继续向后推进:

1
2
3
4
python3 -m anr_evidence --hypothesize <input>
python3 -m anr_evidence --root-cause <input>
python3 -m anr_evidence --remediate <input>
python3 -m anr_evidence --deliver <input>

对应模块是:

  • hypothesis.py:生成候选因果链;
  • root_cause.py:生成保守根因候选;
  • remediation.py:生成受证据门控的修复建议草案;
  • delivery.py:渲染最终交付 Markdown 模板。

这条线强调“候选链路 + 证据强度 + 缺口 + 修复建议”,而不是单点判断。

AI 工作区:面向 Agent 的交付形态

最推荐的 Agent 入口是:

1
2
3
python3 scripts/anr_to_ai.py <bugreport_dir_or_archive_or_fixture> \
[--package <package.name>] \
[--anr-type <type>]

它会生成:

1
2
3
4
5
anr_ai_context/
index.json
anr-<id>/
anr_analysis.md
logcat.txt

index.json 是所有 ANR group 的索引;anr_analysis.md 包含分析说明、过滤证据和四个分析槽位;logcat.txt 保存该 ANR group 的过滤后 logcat,避免主文件上下文膨胀。

AI 或人工分析者必须按槽位填写:Trace → EventLog → Logcat/AnrManager → Final ANR,并把最终综合结论写回 Final ANR 槽位。


四、当前最终结果

截至当前仓库状态,agent-anr 已经形成了一个比较完整的 ANR 证据工程与辅助分析工具链。

1. 已支持的输入与证据源

输入侧支持 fixture、目录、ZIP/TAR 归档;证据侧覆盖:

  • trace;
  • EventLog;
  • logcat;
  • AnrManager dump flow;
  • meminfo;
  • kernel log;
  • dropbox / bugreport 常见路径。

并且支持多个 ANR group 独立生成分析工作区。

2. 已支持的 ANR 类型与根因提示

触发类型包括:

  • input_dispatching_timeout
  • no_focus_window
  • broadcast_timeout
  • service_timeout
  • content_provider_timeout
  • job_scheduler_timeout
  • system_watchdog_swt
  • unknown fallback。

根因模式提示包括但不限于:

  • deadlock / lock owner chain;
  • Binder wait;
  • render fence / vsync / buffer wait;
  • native poll idle / busy / ambiguous;
  • memory leak / OOM / LMK / PSI memory pressure;
  • high CPU / IO / system load;
  • SharedPreferences apply / DB / network / file IO / GC 等主线程阻塞模式。

3. CLI 与脚本入口完整

常用入口包括:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 生成 AI 工作区
python3 scripts/anr_to_ai.py <input> --package <pkg>

# 确定性流水线
python3 -m anr_evidence <input>
python3 -m anr_evidence --normalize <input>
python3 -m anr_evidence --analyze <input>
python3 -m anr_evidence --hypothesize <input>
python3 -m anr_evidence --root-cause <input>
python3 -m anr_evidence --remediate <input>
python3 -m anr_evidence --deliver <input>

# 单来源过滤/调试
python3 scripts/anr_trace_filter.py <trace>
python3 scripts/anr_event_log_filter.py <event_log>
python3 scripts/anr_logcat_filter.py <logcat>
python3 scripts/anr_meminfo_filter.py <meminfo_or_dir> --package <pkg>

此外还有 replay、dashboard、eval 等辅助能力,用于回放评估和回归验证。

4. 测试验证结果

本次基于仓库当前状态执行了完整 unittest:

1
2
Ran 285 tests in 4.724s
OK (skipped=1)

测试覆盖范围包括:

  • AI context 生成与再生成保留分析槽;
  • anchor 选择与多 ANR 分组;
  • ANR 类型扩展与 root cause hint;
  • AnrManager block 解析;
  • ZIP/TAR/目录加载;
  • Phase 2 到 Phase 8 流水线;
  • context flooding;
  • 跨源融合;
  • entity linker;
  • evidence slice;
  • groundtruth eval;
  • log filter 与大文件扫描;
  • meminfo;
  • native poll;
  • pattern catalog;
  • trace deadlock / lock chain / cross-trace consistency;
  • source workflow;
  • weighting。

这说明项目不是只有概念文档,而是已经通过较完整的单元测试与集成测试把“证据抽取—标准化—分析—候选根因—修复建议—交付”串了起来。


五、一个典型使用故事

假设我们拿到一份客户 bugreport,要分析包名为 com.example.app 的 ANR:

1
python3 scripts/anr_to_ai.py ./bugreport --package com.example.app

系统会先加载目录或归档,识别 trace、event log、logcat、meminfo 等来源;然后定位 am_anr 或其他 anchor;如果存在多个 ANR,会拆成多个 group;接着为每个 group 生成独立工作区。

分析者打开:

1
2
3
anr_ai_context/index.json
anr_ai_context/<anr-id>/anr_analysis.md
anr_ai_context/<anr-id>/logcat.txt

然后按顺序填写:

  1. Trace:主线程是否 blocked、native poll、Binder wait、锁等待、render fence;
  2. EventLog:am_anr 前后窗口内 Activity/Window/Input/进程/内存信号;
  3. Logcat/AnrManager:reason、CPU、Load、PSI、Top processes、dump flow;
  4. Final ANR:整合时间线、直接阻塞点、候选根因链、证据质量和修复建议。

最终输出不是一句“根因是 X”,而是一份可复查的 Markdown 报告:每条结论都能回到具体来源和具体证据。


六、这个项目的工程价值

llm-anr 的价值不在于把 ANR 分析“神秘地自动化”,而在于把分析工作拆成稳定、可验证的工程步骤:

  • 用 anchor 和时间窗口解决“证据从哪里来”;
  • 用 source filter 和 weighting 解决“哪些证据更重要”;
  • 用 Evidence Slice 和 entity link 解决“证据如何被 AI 理解”;
  • 用四阶段槽位解决“AI 如何不乱下结论”;
  • 用保守 JSON tail 解决“自动化结论如何留有人审边界”;
  • 用 unittest / replay / eval 解决“规则变化如何防回归”。

这是一种很适合稳定性场景的 Agent 设计范式:让程序做确定性、可测试、可复用的证据工程;让 AI 做阅读、归纳、假设排序和报告组织;让人类保留最终确认权。


七、结语

ANR 分析最怕两件事:一是淹没在海量日志里,二是在证据不足时过早定责。llm-anr 的设计正好围绕这两个风险展开:高召回抽取证据,按 anchor 隔离事件,按来源分步分析,用候选链路表达不确定性,再用测试和评估守住工程质量。

从当前仓库结果看,它已经具备了一个可运行、可扩展、可审计的 ANR 分析基础设施:既能作为命令行工具独立跑确定性流水线,也能作为 AI Agent 的证据工作区生成器,把复杂 bugreport 转成结构化、可复盘的分析任务。

对稳定性工程来说,这种“证据先行、结论保守、流程可验证”的方法,可能比单次自动判断更重要。