是否可以直接从本机代码记录Android systrace事件,而不使用JNI?

Android systrace日志记录系统非常棒,但它只能在代码的Java部分工作,通过Trace.beginSection()Trace.endSection() 。 在代码的C / C ++ NDK(本机)部分中,它只能通过JNI使用,JNI在没有Java环境的线程中很慢或不可用…

是否有任何方法可以将事件添加到主systrace跟踪缓冲区,甚至从本机C代码生成单独的日志?

这个较老的问题提到atrace / ftrace是Android的systrace使用的内部系统。 这可以(轻松)进入吗?

BONUS TWIST:由于跟踪调用通常位于性能关键部分,理想情况下应该可以在实际事件时间之后运行调用。 即我一个人宁愿能够指定记录的时间,而不是自己轮询的呼叫。 但那只会锦上添花。

我不认为它是从NDK暴露出来的。

如果查看源代码,可以看到android.os.Trace类调用本机代码来完成实际工作。 该代码调用atrace_begin()atrace_end() ,它们在cutils库的头文件中声明。

如果从完整源代码树中提取标头并链接到内部库,则可以直接使用atrace函数。 但是,您可以从标题中看到atrace_begin()只是:

 static inline void atrace_begin(uint64_t tag, const char* name) { if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { char buf[ATRACE_MESSAGE_LENGTH]; size_t len; len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "B|%d|%s", getpid(), name); write(atrace_marker_fd, buf, len); } } 

事件直接写入跟踪文件描述符。 (请注意,时间戳不是事件的一部分;它是自动添加的。)您可以在代码中执行类似操作; 请参阅.c文件中的 atrace_init_once()以查看文件的打开方式。

请记住,除非atrace作为NDK的一部分发布,否则使用它的任何代码都将是不可移植的,并且可能在过去或未来版本的Android中失败。 但是,由于systrace是一个调试工具而不是您实际想要在应用中启用的function,因此兼容性可能不是问题。

根据fadden的指针发布一些代码的后续答案。 请首先阅读他/她的回答以获得概述。

所需要的只是将格式正确的字符串写入/sys/kernel/debug/tracing/trace_marker ,可以/sys/kernel/debug/tracing/trace_marker地打开它们。 下面是一些基于cutils头 文件和C文件的极小代码。 我更喜欢重新实现它,而不是引入任何依赖项,所以如果你非常关心正确性,请检查那里的严格实现,和/或添加自己的额外检查和error handling。

这已经过测试,适用于Android 4.4.2。

必须首先打开跟踪文件,将文件描述符保存在atrace_marker_fd全局:

 #include  #include  #include  #define ATRACE_MESSAGE_LEN 256 int atrace_marker_fd = -1; void trace_init() { atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY); if (atrace_marker_fd == -1) { /* do error handling */ } } 

正常的“嵌套”跟踪(如Java Trace.beginSectionTrace.endSection可通过Trace.endSection方式获得:

 inline void trace_begin(const char *name) { char buf[ATRACE_MESSAGE_LEN]; int len = snprintf(buf, ATRACE_MESSAGE_LEN, "B|%d|%s", getpid(), name); write(atrace_marker_fd, buf, len); } inline void trace_end() { char c = 'E'; write(atrace_marker_fd, &c, 1); } 

还有两种跟踪类型可供使用,据我所知,Java无法访问这些类型:跟踪计数器和异步跟踪。

计数器跟踪整数的值并在systrace HTML输出中绘制一个小图。 非常有用的东西:

 inline void trace_counter(const char *name, const int value) { char buf[ATRACE_MESSAGE_LEN]; int len = snprintf(buf, ATRACE_MESSAGE_LEN, "C|%d|%s|%i", getpid(), name, value); write(atrace_marker_fd, buf, len); } 

异步跟踪产生非嵌套(即简单重叠)的间隔。 它们在systrace HTML输出中的细线程状态栏上方显示为灰色段。 它们采用额外的32位整数参数来“区分同时发生的事件”。 结束跟踪时必须使用相同的名称和整数:

 inline void trace_async_begin(const char *name, const int32_t cookie) { char buf[ATRACE_MESSAGE_LEN]; int len = snprintf(buf, ATRACE_MESSAGE_LEN, "S|%d|%s|%i", getpid(), name, cookie); write(atrace_marker_fd, buf, len); } inline void trace_async_end(const char *name, const int32_t cookie) { char buf[ATRACE_MESSAGE_LEN]; int len = snprintf(buf, ATRACE_MESSAGE_LEN, "F|%d|%s|%i", getpid(), name, cookie); write(atrace_marker_fd, buf, len); } 

最后,确实似乎没有办法指定记录时间,没有重新编译Android,所以这对“奖励扭曲”没有任何作用。