符号化与反混淆

本文档描述如何将采集的 trace 中的原始指令地址和混淆的 Java/Kotlin 名称转换为人类可读的函数名、源代码位置和类/方法名。这适用于任何采集调用栈的 DataSource:native heap profiler、基于 perf 的 CPU profiler、Java heap profiler、ART 方法 Trace 等。

在本指南中,你将学习如何:

本文档中使用的两个定义:

只要你仍然有匹配的二进制文件和 mapping 文件,你不需要重新采集即可获得符号或反混淆名称。

方式 1:traceconv bundle(推荐)

traceconv bundle 是一个一键命令,它接受一个 trace 并生成一个丰富化的 trace:原始 trace 加上分析它所需的所有符号和反混淆数据,打包在单个文件中。

traceconv bundle input.perfetto-trace enriched-trace

丰富化的 trace 可以像任何其他 trace 一样在 Perfetto UItrace_processor_shell 中打开,符号和反混淆名称已自动应用。

NOTE: 作为实现细节,丰富化的 trace 目前被打包为 TAR 归档文件,包含原始 trace、native 符号 Packet 和 Java/Kotlin 反混淆 Packet。UI 和 trace_processor_shell 透明地读取此格式,因此你通常不需要自行解包。

要求:

自动路径发现

相比方式 2 的主要优势是,bundle 会在所有常见位置查找符号和 mapping 文件,无需配置。它搜索:

使用标志补充发现

当自动发现不够时:

traceconv bundle \ --symbol-paths /path/to/symbols1,/path/to/symbols2 \ --proguard-map com.example.app=/path/to/mapping.txt \ --verbose \ input.perfetto-trace enriched-trace

bundle 标志的属性:

方式 2:传统 traceconv symbolize / deobfuscate

NOTE: 此流程是为了与已有的脚本和 CI 流水线向后兼容而保留的。对于新使用场景,请始终优先使用方式 1——它更简单,具有自动发现功能,并且适用于非 Perfetto trace 格式。

较旧的 traceconv symbolizetraceconv deobfuscate 子命令生成独立的符号和反混淆文件,完全由环境变量驱动,然后必须手动拼接到 trace 上。

Native 符号化

所有工具(traceconvtrace_processor_shellheap_profile 脚本)都遵循 PERFETTO_BINARY_PATH 环境变量:

PERFETTO_BINARY_PATH=somedir tools/heap_profile android --name ${NAME}

为已采集的 trace 生成独立的符号文件:

PERFETTO_BINARY_PATH=somedir traceconv symbolize raw-trace > symbols

或者,设置 PERFETTO_SYMBOLIZER_MODE=index,符号化器将按 Build ID 递归索引目录中的 ELF 文件,因此文件名不需要匹配。

Java/Kotlin 反混淆

通过 PERFETTO_PROGUARD_MAP 提供 ProGuard/R8 mapping,使用格式 packagename=map_filename[:packagename=map_filename...]

PERFETTO_PROGUARD_MAP=com.example.pkg1=foo.txt:com.example.pkg2=bar.txt \ ./tools/heap_profile android -n com.example.app

为现有 trace 生成独立的反混淆文件:

PERFETTO_PROGUARD_MAP=com.example.pkg=proguard_map.txt \ traceconv deobfuscate ${TRACE} > deobfuscation_map

将输出附加到 trace

上面的 symbolsdeobfuscation_map 都是序列化的 TracePacket proto,因此对于 Perfetto protobuf trace,你可以简单地将它们拼接:

cat ${TRACE} symbols > symbolized-trace cat ${TRACE} deobfuscation_map > deobfuscated-trace # 或者两者都加: cat ${TRACE} symbols deobfuscation_map > enriched-trace

tools/heap_profile 脚本在设置了 PERFETTO_BINARY_PATH 时,会在其输出目录中自动执行此操作。

限制:

符号查找顺序

对于 trace 中的每个 native mapping,符号化器查找具有匹配 Build ID 的文件。对于每个搜索路径 P,它按以下顺序尝试:

  1. 库文件相对于 P 的绝对路径。
  2. 同上,但去掉文件名中的 base.apk!
  3. 库文件相对于 P 的基本名称。
  4. 基本名称,去掉 base.apk!
  5. P/.build-id/<前 2 个十六进制数字>/<其余部分>.debug(标准的 Fedora Build ID 布局)。

例如,带有 Build ID abcd1234.../system/lib/base.apk!foo.so 在符号路径 P 下查找:

  1. P/system/lib/base.apk!foo.so
  2. P/system/lib/foo.so
  3. P/base.apk!foo.so
  4. P/foo.so
  5. P/.build-id/ab/cd1234...debug

第一个具有匹配 Build ID 的文件胜出。如果磁盘上的 Build ID 与 trace 中记录的不同,则跳过该文件。

从 C++ 库使用符号化/反混淆

目前没有稳定的公共 C++ API 用于在进程内执行符号化或反混淆。底层实现存在(src/traceconv/trace_to_bundle.h 中的 TraceToBundle,由 src/trace_processor/util/trace_enrichment/trace_enrichment.h 中的 EnrichTrace 支持),但它位于 src/ 而非 include/ 下,不属于公共 API 接口。

如果你需要此功能,请在 GitHub issue #5534 上 +1,以便我们评估需求并确定优先级。

故障排除

找不到库

在对 Profile 进行符号化时,你可能会看到如下消息:

Could not find /data/app/invalid.app-wFgo3GRaod02wSvPZQ==/lib/arm64/somelib.so (Build ID: 44b7138abd5957b8d0a56ce86216d478).

检查 somelib.so 是否存在于某个搜索路径下(--symbol-pathsPERFETTO_BINARY_PATH 或自动发现的位置)。然后使用 readelf -n /path/to/somelib.so 比较磁盘上的 Build ID 与消息中报告的 Build ID。如果它们不匹配,磁盘上的副本是不同于设备上的构建,无法使用。

使用 --verbose 重新运行 traceconv bundle 会打印尝试的每个路径,这通常可以清楚地表明文件是完全缺失还是找到了但 Build ID 不匹配。