首页 > 技术 > 正文

Android Perfetto 系列 15:Boot Trace、长时刻现场 Trace 与偶发问题抓取

2026-10-30  ·  阅读:272

现场测试经常会断 USB。普通现场长 Trace 优先用 --background-wait,它会等 data source 启动后再返回 PID,比直接 --background 少丢开头。

Android 12 及以上设备可将配置放进 /data/misc/perfetto-configs,再启动后台 trace;具体写入权限仍以设备为准:

1
2
3
4
5
6
7
adb push field.pbtxt /data/misc/perfetto-configs/field.pbtxt

PID=$(adb shell perfetto --background-wait --txt \
-c /data/misc/perfetto-configs/field.pbtxt \
-o /data/misc/perfetto-traces/field.perfetto-trace | tr -d '\r')

echo "perfetto pid: $PID"

如果 Android 12–17 的方向设备无法使用上述配置路径,也可以从 stdin 传入配置。生产 M2M 工具链更应该用审核过的 preset 或 binary TraceConfig,而不是让服务支持支持端下发任意文本配置:

1
2
3
4
5
PID=$(adb shell perfetto --background-wait --txt \
-c - \
-o /data/misc/perfetto-traces/field.perfetto-trace tr -d '\r')

echo "perfetto pid: $PID"

停止时不要 kill 后立刻 adb pull。Perfetto 还要把尾部数据写完。至少等 perfetto 进程退出,并确认文件存在且大小稳定后再拉取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
case "$PID" in
''|*[!0-9]*) echo "Invalid perfetto PID" >&2; exit 1 ;;
esac
[ "$PID" -gt 1 ] || exit 1
adb shell "kill -INT $PID" || exit 1
adb shell "attempts=0; while kill -0 $PID 2>/dev/null; do
attempts=\$((attempts + 1))
[ \$attempts -lt 60 ] || exit 1
sleep 1
done" || exit 1
adb shell '
path=/data/misc/perfetto-traces/field.perfetto-trace
stable=0
prev=0
attempts=0
while [ "$stable" -lt 3 ] && [ "$attempts" -lt 60 ]; do
attempts=$((attempts + 1))
size=$(stat -c %s "$path" 2>/dev/null || echo 0)
if [ "$size" -gt 0 ] && [ "$size" = "$prev" ]; then
stable=$((stable + 1))
else
stable=0
fi
prev=$size
sleep 1
done
[ "$stable" -ge 3 ] || { echo "Trace missing or not stable" >&2; exit 1; }
' || exit 1

adb pull /data/misc/perfetto-traces/field.perfetto-trace

如果脚本能控制两端,可以在发 kill 前启动 inotifyd 监听 close_write;设备上没有 inotifyd 时,在进程已退出后用连续大小稳定作为 fallback。文件大小稳定本身不是关闭证明;trigger 未命中、启动失败或文件为空时应有超时并退出,不能无限等待或继续拉取。

trigger 怎么用

Perfetto trigger 的作用是权限隔离:有权限的一方提前声明 trigger 名称和行为;普通 App 或系统组件只报告“事件发生了”,不能决定抓什么、抓多大、传哪里。

现场方案要把 trigger emitter 写清楚。UI jank 可以由 App 侧 JankStats / FrameMetrics / 自研阈值检测后激活 app_ui_jank,也可以由平台服务或测试 harness 代理激活。无论哪条路,都要做去重和限流,并在 metadata 里记录 trigger source、触发时刻和判断阈值。

App emitter 协议建议固定成一条 JSON 事件,并同时写入同 event_id 的 Track Event:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"event_id": "evt-20260504-153012-001",
"trigger_name": "app_ui_jank",
"trigger_source": "app_jankstats",
"page": "Feed",
"action": "scroll",
"reason": "slow_frame",
"threshold_ms": 50,
"observed_value_ms": 83.4,
"window_start_elapsed_ns": 123456700000000,
"window_end_elapsed_ns": 123456789000000,
"dedupe_key": "Feed:scroll:slow_frame:202605041530",
"sample_decision": "record",
"app_state": "foreground"
}

服务支持提供端或分析脚本用 event_id 和时间窗口把外部 trigger 记录、trace 内 Track Event、FrameTimeline 慢帧对上。对不上时,这份 Trace 只能当平台侧上下文,不能直接归因到页面或业务动作。

测试环境可以用下面两种 shell 途径激活 trigger,但上面的 preset 设置了 producer_name_regex: "com\\.example\\.app":shell 工具的 producer 名若不匹配,trigger 会被过滤。测试时应使用匹配的 App producer 激活,或在仅用于实验室的配置里调整这项过滤,不能把命令执行成功当成 trigger 已命中。

1
adb shell /system/bin/trigger_perfetto app_ui_jank

也可以用一段只包含 activate_triggers 的配置激活同名 trigger:

本文由News整理发布,仅供参考。

123456789
评论加载中…

友情链接申请友链

联盟矩阵53