前置阅读:本文档是 V1 方案(基于 Perfetto 与 AI 的 Android 性能自动化诊断方案) 的升级版。V1 中已详细介绍了 Perfetto 基础知识、SQL 表结构、采集类别、
2_trace_filter.py的完整源码和 JSON 输出协议、环境依赖安装等内容,本文不再重复,请按需查阅。
一、从 V1 到 V2
1.1 V1 的缺陷
| 缺陷 | 表现 |
|---|---|
| 源码搜索粗糙 | 靠正则 + find 搜类名,无法追踪接口实现、Lambda、依赖注入等间接调用,上下文残缺 |
| 上下文易失真 | 源码全文 cat 拼进 Prompt,十几兆文本灌入单次 API 请求,极易触发大模型幻觉 |
| 重构无法落地 | 结论以 Markdown 文件输出,开发者只能手动复制粘贴到 IDE 中 |
| 密钥硬编码 | API Key 明文写在脚本中随仓库提交 |
1.2 V2 怎么解决
核心思路:砍掉冗余编排,只保留底座( 2_trace_filter.py ),智能层上移至 IDE Agent。
| 能力维度 | V1(CLI 管线) | V2(IDE Agent) |
|---|---|---|
| 设备采样 | 1_ai_sampler.sh(手动按 Enter 截断) | Agent 直接执行 adb(按秒定时,自动停止) |
| Trace 解析 | 2_trace_filter.py(六步 SQL 管线) | 2_trace_filter.py(复用,零改动) |
| 源码搜索 | find + grep(正则,易漏间接调用) | Agent 原生工具链(可递归追踪整条调用链) |
| AI 推理 | 远端 API(需把全量源码外传到云端) | IDE 内置 Agent(源码留在本地,按需精准读取) |
| Prompt 编排 | Bash 字符串拼接(脆弱,长度受限) | SKILL.md 声明式协议(Agent 自主编排) |
| 结果交付 | Markdown 文件(人工复制粘贴) | IDE 内对话输出诊断与修复建议,询问用户是否需要直接修改源码 |
| 密钥安全 | 脚本硬编码 | IDE 内置鉴权,无需暴露 |
二、V2 整体架构
一句话概括: 用户说一句话 → Agent 在真机上采集 Trace → 2_trace_filter.py 六步 SQL 管线提纯为 JSON → Agent 按 JSON 线索搜源码 → 读完后交付诊断报告与修复建议 → 询问用户是否需要修改代码。
V2 仅需两个文件:
| 文件 | 作用 | 位置 |
|---|---|---|
| 2_trace_filter.py | 底座:把二进制 Trace 翻译成 Agent 能读懂的 JSON(详见 V1 文档) | tools/ai_profiler/ |
| SKILL.md | 契约:告诉 Agent 该按什么流程、什么规则工作 | .agent/skills/performance-profiler/ |
三、行为契约 — SKILL.md
3.1 什么是 SKILL.md
简单说,SKILL.md 就是一份写给 AI Agent 看的"工作手册"。
你不需要写代码来编排 Agent 的行为——只需要用 Markdown 写清楚"先做什么、再做什么、什么不能做",Agent 就会严格照着执行。它取代了 V1 中 run_profiler.sh + 3_ai_reporter.sh 两个脚本的全部编排工作。
文件位置:.agent/skills/performance-profiler/SKILL.md
3.2 四个阶段怎么流转
3.3 Perfetto Config 技术要点
Config 模式的 SELinux 绕过原理、Text Proto 格式说明、完整 TraceConfig 字段含义等技术细节,请参考 V1 文档
AI_EMPOWERMENT.md及1_ai_sampler.sh源码中的注释。V2 的SKILL.md中已内嵌与1_ai_sampler.sh完全一致的配置模板,Agent 只需替换target_cmdline即可,无需理解底层细节。
3.4 完整文件内容
以下是 SKILL.md 的完整内容。部署时应原封不动复制到 .agent/skills/performance-profiler/SKILL.md:
---
name: Android 性能靶向诊断 (Performance Trace Profiler)
description: 当用户提出优化 Android 页面滑落卡顿、抓取底层 Trace 查找耗时点等诉求时自动被唤起。触发示例:帮我抓个 5s 的 Trace 看看滑动掉帧、抓 10s 诊断找找卡顿元凶。
---
# 绝对禁令
1. **必须透明化展示核心 JSON 特征**:在解析出最终指纹时,第一时间通过 ```json 向用户毫无保留地展示供其核验,但**严禁**吐出中间过程的繁杂跑库数据。
2. **严禁无源码回话**:在定位并阅读过相关源码之前,禁止输出诊断结论。
3. **严禁建议 ui.perfetto.dev**:除非你同时给出了源码级分析和修复代码,否则禁止提供该链接。
---
# Phase 1: Trace 采集
> 本阶段是唯一允许与用户交互的阶段。每个步骤必须严格按顺序执行,不得合并、不得跳过、不得自行推断"已完成"。
> 每个步骤执行前,须先向用户输出对应的「进度提示」,再执行命令。
**步骤 1:设备检测**
> 进度提示:输出 "🔍 **[1/14] 正在检测 Android 设备连接状态...**"
执行 `adb devices`。若无在线设备直接终止流程并告知用户;若有多台设备,列出序列号并询问用户选定目标。
---
**步骤 2:推导目标包名**
> 进度提示:输出 "📦 **[2/14] 正在推导目标应用包名...**"
按以下优先级确定包名:
1. 如果用户消息中已明确给出包名(如 `com.xxx.xxx`),直接使用。
2. 否则搜索项目中所有 `build.gradle` / `build.gradle.kts`,查找 `applicationId`:
- 全项目只有 1 个明文 `applicationId`:直接使用。
- 有多个或使用了动态变量:**立刻停止**,列出找到的信息,询问用户指定包名,等待回复后再继续。
---
**步骤 3:确定采集时长**
> 进度提示:输出 "⏱️ **[3/14] 正在确认采集时长...**"
从用户消息中提取采集时长(如"抓 8s" → 8 秒),未指定时默认 **10 秒**。此时长仅用于步骤 11 的 `sleep`,不写入配置文件。
---
**步骤 4:生成探针配置文件**
> 进度提示:输出 "⚙️ **[4/14] 正在生成 Perfetto 探针配置(包名: <包名>,时长: <时长>s)...**"
将步骤 2 确定的包名填入下方模板的 `target_cmdline` 字段。**其余所有内容一字不改**,写入 **`/tmp/trace_config.pbtxt`**(系统临时目录,不污染项目工程)。
> ⚠️ 以下模板与 `1_ai_sampler.sh` 完全一致,不得增删任何字段!
> - `duration_ms` 固定 `600000`(10 分钟安全上限),由步骤 12 的 `pkill -INT` 控制实际采集时长。
> - 唯一需要替换的是 `target_cmdline` 的值。
```protobuf
buffers {
size_kb: 65536
fill_policy: RING_BUFFER
}
data_sources {
config {
name: "linux.ftrace"
ftrace_config {
atrace_categories: "sched"
atrace_categories: "freq"
atrace_categories: "idle"
atrace_categories: "am"
atrace_categories: "wm"
atrace_categories: "gfx"
atrace_categories: "view"
atrace_categories: "binder_driver"
atrace_categories: "hal"
atrace_categories: "dalvik"
atrace_categories: "memory"
ftrace_events: "sched/sched_switch"
}
}
}
data_sources {
config {
name: "android.surfaceflinger.frametimeline"
}
}
data_sources {
config {
name: "android.packages_list"
}
}
data_sources {
config {
name: "linux.perf"
perf_event_config {
timebase {
counter: SW_CPU_CLOCK
frequency: 500
timestamp_clock: PERF_CLOCK_MONOTONIC
}
callstack_sampling {
kernel_frames: false
}
target_cmdline: "<替换为步骤2的包名>"
}
}
}
data_sources {
config {
name: "linux.process_stats"
process_stats_config {
scan_all_processes_on_start: true
record_thread_names: true
}
}
}
duration_ms: 600000
```
---
**步骤 5:清理设备旧数据**
> 进度提示:输出 "🧹 **[5/14] 正在清理设备端旧 Trace 文件...**"
执行:`adb shell rm -f /data/misc/perfetto-traces/app.trace`
---
**步骤 6:推送配置文件到设备**
> 进度提示:输出 "📤 **[6/14] 正在将探针配置推送到设备...**"
通过 stdin 重定向将配置写入设备(与 `1_ai_sampler.sh` 完全一致的方式):
`adb shell "cat > /data/local/tmp/trace_config.pbtxt" < /tmp/trace_config.pbtxt`
写入成功后,立即删除本地临时文件(不留垃圾):`rm -f /tmp/trace_config.pbtxt`
---
**步骤 7:在后台启动 perfetto**
> 进度提示:输出 "🚀 **[7/14] 正在启动 Perfetto 性能探针...**"
执行(`>/dev/null 2>&1 &` 在引号外部,将 adb 进程放到本机后台,与 `1_ai_sampler.sh` 一致):
`adb shell "cat /data/local/tmp/trace_config.pbtxt | perfetto --txt -c - -o /data/misc/perfetto-traces/app.trace" >/dev/null 2>&1 &`
> 由于 `duration_ms: 600000`,perfetto 会持续运行最长 10 分钟,不会自动退出。
---
**步骤 8:等待 perfetto 初始化**
> 进度提示:输出 "⏳ **[8/14] 等待探针初始化(2秒)...**"
执行:`sleep 2`
---
**步骤 9:检查 perfetto 进程是否存活**
> 进度提示:输出 "🔎 **[9/14] 正在验证探针进程存活状态...**"
执行:`adb shell pidof perfetto`
- **有 PID 输出**:记录为 **Config 模式**,继续步骤 10。
- **无 PID 输出**:记录为**降级模式**,先清理再启动降级命令:
1. `adb shell rm -f /data/misc/perfetto-traces/app.trace`
2. `adb shell "perfetto -o /data/misc/perfetto-traces/app.trace sched freq idle am wm gfx view binder_driver hal dalvik memory" >/dev/null 2>&1 &`
3. `sleep 1`
然后继续步骤 10。
---
**步骤 10:【必须执行】通知用户开始复现卡顿**
> ⚠️ 此步骤是整个流程最关键的用户交互节点。
> **必须完整输出以下内容后,才能继续步骤 11。不得跳过,不得与任何步骤合并。**
向用户输出:
```
🟢 [10/14] 性能探针已就绪!
• 采集模式:Config 模式(含 Frame Timeline + Callstack Sampling)/ 命令行降级模式
• 目标应用:<包名>
• ⏱️ 采集倒计时:<步骤3的时长> 秒
👉 请 立刻 在手机上操作,复现您想诊断的卡顿场景!
(如:快速滑动列表、打开目标页面、触发卡顿动作等)
采集将在 <时长> 秒后自动停止,无需手动操作。
```
---
**步骤 11:等待采集结束**
> 此步骤静默等待,不得输出任何内容。
执行:`sleep <步骤3的时长(秒)>`
---
**步骤 12:停止 perfetto**
> 进度提示:输出 "🛑 **[12/14] 采集窗口结束,正在停止探针...**"
执行:`adb shell pkill -INT perfetto`
---
**步骤 13:等待数据落盘**
> 进度提示:输出 "💾 **[13/14] 正在等待性能数据写入磁盘(2秒)...**"
执行:`sleep 2`
清理设备端临时配置文件:`adb shell rm -f /data/local/tmp/trace_config.pbtxt`
---
**步骤 14:拉取 Trace 文件**
> 进度提示:输出 "📥 **[14/14] 正在将 Trace 文件拉取到本地...**"
执行:`adb pull /data/misc/perfetto-traces/app.trace ./tools/ai_profiler/temp_issue.perfetto-trace`
---
# Phase 2: 协议解析
> 进度提示:输出 "🔬 **[Phase 2] 正在运行六步 SQL 分析管线,提取性能指纹...**"
执行以下命令(包名换成步骤 2 推导出的实际包名):
```bash
python3 ./tools/ai_profiler/2_trace_filter.py ./tools/ai_profiler/temp_issue.perfetto-trace "<包名>"
```
根据返回 JSON 的 `status` 字段处理:
- `perfect`:告知用户本次窗口未检测到卡顿帧,询问是否重新采集。
- `error`:终止流程,报告错误信息。
- `anomaly_detected`:**立即使用 ```json 代码块将完整 JSON 输出给用户核验**,并告知:"这是从内核中提纯的卡顿指纹,我正在顺这些指纹下潜至最深层的代码网寻找原凶...",随后进入 Phase 3。
---
# Phase 3: 源码溯源
> 进度提示:输出 "🕵️ **[Phase 3] 正在深度溯源相关业务代码,请稍候...**"
> 本阶段禁止向用户输出任何未经证实的猜测或半成品推演。
基于 JSON 中以下字段,自主在项目中搜索并深度阅读所有相关源码(`.kt` / `.java` / `.xml`):
| JSON 字段 | 线索类型 | 诊断价值 |
|-----------|---------|---------|
| `suspect_root_cause_methods` | 主线程耗时方法名 | 定位卡顿函数 |
| `thread_os_states` | CPU 调度微状态 | 判断 I/O 阻塞 / 锁等待 / CPU 抢占 |
| `callstack_chains` | 函数级 CPU 调用链 | `[APP]` 标记的调用链是首要分析对象 |
| `frame_timeline_jank` | 帧级卡顿归因 | App / GPU / SurfaceFlinger 定责 |
| `top_jank_frames` | Top 3 卡顿帧 | 偶发 vs 持续性卡顿 |
---
# Phase 4: 诊断交付
完成 Phase 3 全部源码阅读后,输出诊断报告:
1. **肇事片段**:精确引用源码,标注文件路径和行号。
2. **根因剖析**:结合 Trace 数据和源码逻辑,分析为什么这些代码构成瓶颈。
3. **重构建议代码**:基于真实源码给出可直接应用的修改方案。
4. **用户确认**:"需要我帮你直接修改代码吗?"
---
# 失败准则
满足以下任一条件即判定为失败,必须立即纠正:
- 未完整输出步骤 10 的复现通知,就直接执行步骤 11 的 sleep。
- 自行推断 perfetto "已完成"或"已退出"而跳过步骤 10-13 中的任何步骤。
- 将配置文件写入项目目录而非 `/tmp/` 系统临时目录。
- 修改了配置模板中除 `target_cmdline` 以外的任何字段。
- 将 `duration_ms` 设为用户指定的采集时长(必须固定为 `600000`)。
- 未在项目中搜索和阅读源码就输出了诊断结论。
- 未将 JSON 特征展示给用户核验就直接进入源码分析。
- 诊断报告中未包含真实源码引用(文件路径 + 代码片段)。
四、部署指南
4.1 前置条件
环境依赖(adb、python3、perfetto 库)的安装方式见 V1 文档 · 环境准备。
此外,需要确认你使用的 AI IDE 支持 Agent Skill:
| IDE | 技能文件放在哪里 |
|---|---|
| Claude Code | .agent/skills/ 目录下 |
| Cursor | .cursor/skills/ 或等效目录下 |
| 其他 AI IDE | 需确认该 IDE 的 Agent Skill 目录约定 |
4.2 目录结构
部署完成后,项目中会多出以下文件:
<项目根目录>/
├── .agent/
│ └── skills/
│ └── performance-profiler/
│ └── SKILL.md ← Agent 行为契约(V2 新增)
├── tools/
│ └── ai_profiler/
│ ├── 2_trace_filter.py ← Trace 解析脚本(V1 & V2 共用)
│ └── temp_issue.perfetto-trace ← 运行时产物(建议加入 .gitignore)
└── ...
4.3 三步部署
第一步:创建技能目录
mkdir -p .agent/skills/performance-profiler
第二步:放入 SKILL.md
将本文档 第三章 3.3 节 代码框内的文本原封不动复制到 .agent/skills/performance-profiler/SKILL.md 中并保存。
第三步:安装 Python 依赖(如果 V1 已装过可跳过)
pip3 install perfetto
4.4 唤起方式
在 IDE 的 AI 对话窗口中用自然语言触发即可:
| 示例话术 | Agent 识别到的采集时长 |
|---|---|
| "帮我抓个 8s 的 Trace 诊断下" | 8 秒 |
| "抓 5s Trace 看看滑动为啥卡" | 5 秒 |
| "帮我抓个 Trace 看看" | 10 秒(默认值) |
以下是实际执行的一次诊断截图,从输入一句话到最终输出带源码引用的修复方案,全流程自动完成:
帮我抓个 8s 的 Trace 诊断下
五、总结
V2 升级为 IDE Agent 原生融合:砍掉了 3_ai_reporter.sh 和 run_profiler.sh,只保留 2_trace_filter.py 作为分析底座,源码溯源和诊断推理全部由 Agent 在本地完成——源码不外传、API Key 不暴露。Agent 自动完成从采集到诊断的全流程,输出带源码引用的修复建议,询问用户是否需要执行代码修改。