Android调试-Perfetto与Trace

2025-07-30

Perfetto

Perfetto结构

perfetto

Perfetto Buffer

Buffer 配置

在Perfetto 配置文件中,可以配置Buffer:

buffers {
  size_kb: ...
  fill_policy: RING_BUFFER| DISCARD 
}
// long trace
write_into_file: true
file_write_period_ms: ...
max_file_size_bytes: ...

分别配置了buffer的大小和buffer的写入规则,buffer的写入规则分为三种:

  1. 写满时停止写: DISCARD
  2. 环形缓冲区: RING_BUFFER
  3. 环形缓冲区写,被覆盖的数据写入文件 (long trace):配置write_into_file, file_write_period_ms, max_file_size_bytes

Buffer 结构

结构 每个采集进程都对应一个Shared Memory Buffer,采集的数据都会放到这个Shared Memory Buffer中,在 Tracing Service中,每个Shared Memory Buffer都对应着一个Buffer, 每一个Shared Memory Buffer与Buffer的大小比例为1:1

Shared Memory Buffer 和 Buffer都由一系列Buffer Page组成

Perfetto Buffer

写入流程

  • 当一个数据源需要写数据时,会找到一个空闲的Buffer Page, 将采集的数据写入到Page中,当Page写满后,采集进程会发送一个IPC请求给Tracing Service

  • 当Tracing Service接收到IPC请求后,会将Page信息复制到Buffer中的下一个Page中

  • 当Tracing Service写完Buffer后,会重新将Shared Memory Buffer中的Page设置为空闲

  • 当采集过程结束时,采集进程会发送一个Flush命令给所有的数据源,这是所有数据源都会提交写入到Shared Memory Buffer中的数据,并由Tracing Service拷贝到Buffer中

使用Perfetto追踪自定义event

在函数中添加Trace.beginSection(name)/Trace.endSection()

private void setVisibleFragment(SettingItem item, SettingItem preItem){
    Trace.beginSection("trace test");
    ...
    Trace.endSection();
}

,设置Perfetto Config:

buffers {
  size_kb: 65536
  fill_policy: RING_BUFFER
}
data_sources {
  config {
    name: "linux.ftrace"
    ftrace_config {
      atrace_apps: "com.example.carsettingapplication"
    }
  }
}
duration_ms: 2000

,保存到config.pbtx并运行命令:

cat config.pbtx | perfetto -c - --txt -o /data/misc/perfetto-traces/trace.pftrace

,导出文件到perfetto ui中: perfetto ui

Java Trace如何调用atrace并写入ftrace的环形缓冲区

使用perfetto追踪自定义事件或者System Server中的一些事件时,都调用了Trace类中的静态方法,这些方法会将事件写入到ftrace的环形缓冲区中

Trace调用atrace

sequenceDiagram
autonumber
participant SomeMethod
participant Trace
participant android_os_Trace.cpp
participant tracing_perfetto.cpp
participant trace.h

note over SomeMethod, trace.h : 开启trace
alt system
SomeMethod->>Trace: traceBegin
else
SomeMethod->>Trace: beginSection
end
Trace->>Trace:nativeTraceBegin
Trace->>android_os_Trace.cpp: android_os_Trace_nativeTraceBegin
android_os_Trace.cpp->>tracing_perfetto.cpp: traceBegin
tracing_perfetto.cpp->>trace.h: atrace_begin

note over SomeMethod, trace.h : 关闭trace

alt system
SomeMethod->>Trace: traceEnd
else
SomeMethod->>Trace: endSection
end
Trace->>Trace:nativeTraceEnd
Trace->>android_os_Trace.cpp: android_os_Trace_nativeTraceEnd
android_os_Trace.cpp->>tracing_perfetto.cpp: traceEnd
tracing_perfetto.cpp->>trace.h: atrace_end

traceBegin/ beginSection

使用traceBegin/beginSection方法开启trace,traceBegin支持自定义Tag,只能给System App使用,而beginSection给其他App使用,Tag默认为TRACE_TAG_APP = 4096

@UnsupportedAppUsage
@SystemApi(client = MODULE_LIBRARIES)
public static void traceBegin(long traceTag, @NonNull String methodName) {
    if (isTagEnabled(traceTag)) {
        nativeTraceBegin(traceTag, methodName);
    }
}

public static void beginSection(@NonNull String sectionName) {
    if (isTagEnabled(TRACE_TAG_APP)) {
        ...
        nativeTraceBegin(TRACE_TAG_APP, sectionName);
    }
}

,两个方法都调用了natvieTraceBegin方法:

nativeTraceBegin

private static native void nativeTraceBegin(long tag, String name);

,方法对应了一个JNI方法android_os_Trace_nativeTraceBegin

android_os_Trace_natvieTraceBegin

static void android_os_Trace_nativeTraceBegin(JNIEnv* env, jclass,
        jlong tag, jstring nameStr) {
    withString(env, nameStr, [tag](const char* str) { tracing_perfetto::traceBegin(tag, str); });
}

,调用了tracing_perfetto::traceBegin方法:

tracing_perfetto::traceBegin

void traceBegin(uint64_t category, const char* name) {
  struct PerfettoTeCategory* perfettoTeCategory =
      internal::toPerfettoCategory(category);

  if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
    atrace_begin(category, name);
  } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
    internal::perfettoTraceBegin(*perfettoTeCategory, name);
  }
}

,如果internal::shouldPreferAtrace为真,则调用atrace_begin方法启用atrace开始trace

与开启trace相似,结束trace也有System App和其他App两种版本:

traceEnd/ endSection

@UnsupportedAppUsage
@SystemApi(client = MODULE_LIBRARIES)
public static void traceEnd(long traceTag) {
    if (isTagEnabled(traceTag)) {
        nativeTraceEnd(traceTag);
    }
}

public static void endSection() {
    if (isTagEnabled(TRACE_TAG_APP)) {
        nativeTraceEnd(TRACE_TAG_APP);
    }
}

,都调用了nativeTraceEnd方法:

nativeTraceEdd

private static native void nativeTraceEnd(long tag);

,对应了一个JNI方法android_os_Trace_nativeTraceEnd

android_os_Trace_nativeTraceEnd

static void android_os_Trace_nativeTraceEnd(JNIEnv*, jclass, jlong tag) {
    tracing_perfetto::traceEnd(tag);
}

,调用了tracing_perfetto::traceEnd方法:

tracing_perfetto::traceEnd

void traceEnd(uint64_t category) {
  struct PerfettoTeCategory* perfettoTeCategory =
      internal::toPerfettoCategory(category);

  if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
    atrace_end(category);
  } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
    internal::perfettoTraceEnd(*perfettoTeCategory);
  }
}

,会调用atrace_end方法结束trace

atrace用户空间事件写入到Ring Buffer

实现方法: 通过trace_marker 把相关trace 信息从用户空间注入到内核空间

flowchart LR
A@{ shape: rounded, label: "trace.h" } -- write() --> B@{shape: rounded, label: "trace_marker"}
B -- 写入 --> C@{shape: rounded, label: "环形缓冲区"}

观察trace.h中的atrace_begin方法:

static inline void atrace_begin(uint64_t tag, const char* name)
{
    if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
        atrace_begin_body(name);
    }
}

,调用了tracedev.cpp中的atrace_begin_body方法:

void atrace_begin_body(const char* name)
{
    WRITE_MSG("B|%d|", "%s", "", name, "");
}

,执行了trace-dev.inc中定义的WRITE_MSG

#define WRITE_MSG(format_begin, format_end, track_name, name, value) { \
    ...
    if (len > 0) { \
        write(atrace_marker_fd, buf, len); \
    } \
}

,执行后向atrace_marker_fd中写入了一行信息,为B|pid|name,表示开始记录trace并记录pid和name

atrace_end方法如下:

static inline void atrace_end(uint64_t tag)
{
    if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
        atrace_end_body();
    }
}

,调用了atrace_end_body方法:

void atrace_end_body()
{
    WRITE_MSG("E|%d", "%s", "", "", "");
}

,与atrace_begin相同,执行了WRITE_MSG,此时写入的信息为E|pid,表示结束记录trace

trace_marker的文件描述符,在tracedev.cpp中:

static void atrace_init_once()
{
    atrace_marker_fd = open("/sys/kernel/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
    if (atrace_marker_fd == -1) {
        atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
    }
    ...
}

,为了兼容不同版本,分别从/sys/kernel/tracing/trace_marker/sys/kernel/debug/tracing/trace_marker中打开trace_marker文件

在Linux的kernel/trace/trace.c中,定义了trace_marker文件的写操作函数:

static ssize_t tracing_mark_write(struct file *filp, const char __user *ubuf,
					size_t cnt, loff_t *fpos)
{
    ...
 else {
		written = write_marker_to_buffer(tr, ubuf, cnt, ip);
	}

	return written;
}

,在执行写操作时,会调用trace.cwrite_marker_to_buffer方法:

static ssize_t write_marker_to_buffer(struct trace_array *tr, const char __user *ubuf,
				      size_t cnt, unsigned long ip)
{
    //对ring buffer上锁,得到buffer中的最后一个事件
    event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
					    tracing_gen_ctx());
    ...
    //根据最后一个事件得到相应的entry
    entry = ring_buffer_event_data(event);
    ...
    //将数据从user buffer copy 到 ring buffer
    len = __copy_from_user_inatomic(&entry->buf, ubuf, cnt);
    ...
    //提交写入并解锁buffer
    __buffer_unlock_commit(buffer, event);

    ...
}

,该方法会将marker写入到环形缓冲区中