背景
针对程序如何在自己的代码中加入相关的trace方法和TAG来方便在systrace/perfetto中进行查看,下面这篇文章已经进行了详细的讲解:
systrace/perfetto中需要actrace打tag相关方法-车载车机framework系统开发实战
有针对native的c++代码,也有系统app的java代码,但是缺少了普通第三方app如何打印trace,有学员朋友在第三方app尝试打印trace时候发现了一些问题,那就是使用perfetto抓取的trace死活没有自己打印的trace,马哥这边经过验证也确实有存在相关的问题,下面针对第三方app没办法打印trace问题来进行详细的分析。
问题复现过程
第三应用一般只能使用如下类:
frameworks/base/core/java/android/os/Trace.java
这里可以看到Trace总共才可以使用上面几个公开方法,其他方法和变量第三方应用均不可以使用,当然也可以使用反射的方式。
正常代码中如果加入trace一般使用如下方式:
void beginSection( String sectionName);//sectionName代表打印trace的名字,一般可以写成当前方法等
void endSection();//trace代表结束,与上面方法成对出现
打印如下:
运行抓取:
使用写好perfetto脚本抓取
sh capture.sh
capture.sh源码如下:
#!/system/bin/sh
~/aosp/external/perfetto/tools/record_android_trace -o $(date +%Y%m%d_%H%M%S)_trace_file.perfetto-trace -t 5s -b 32mb sched freq idle am wm power gfx view binder_driver hal dalvik camera input res memory gfx view wm ss video camera hal res sync idle binder_driver binder_lock ss
上面就是使用aosp源码的record_android_trace工具抓取的,大家自己改成自己合适路径。
结果如下:
发现完全没有"MainActivity onclick"这里trace。
原因分析
public static void beginSection(@NonNull String sectionName) {
android.util.Log.i("beginSection","beginSection isTagEnabled " + isTagEnabled(TRACE_TAG_APP));
if (isTagEnabled(TRACE_TAG_APP)) {//关键的使用APP的TAG判断
if (sectionName.length() > MAX_SECTION_NAME_LEN) {
throw new IllegalArgumentException("sectionName is too long");
}
nativeTraceBegin(TRACE_TAG_APP, sectionName);
}
}
这里可以看到也加入了相关的打印看看isTagEnabled(TRACE_TAG_APP)是否使能了,结果如下:
可以看出isTagEnabled(TRACE_TAG_APP)为false是导致没办法查看trace的关键,看看isTagEnabled源码:
public static boolean isTagEnabled(long traceTag) {
long tags = nativeGetEnabledTags();
return (tags & traceTag) != 0;
}
这里是native方法会调用到jni的cpp文件
最后调用到这里
system/core/libcutils/trace-dev.inc
uint64_t atrace_get_enabled_tags()
{
atrace_init();
return atrace_enabled_tags;
}
void atrace_init() {
#if defined(__BIONIC__)
uint32_t seq_no = __system_property_serial(atrace_property_info); // Acquire semantics.
#else
uint32_t seq_no = 0;
#endif
uint32_t prev_seq_no = atomic_load_explicit(&last_sequence_number, memory_order_relaxed);
if (CC_UNLIKELY(seq_no != prev_seq_no)) {
atrace_seq_number_changed(prev_seq_no, seq_no);
}
}
会调用到atrace_seq_number_changed方法中
system/core/libcutils/trace-dev.cpp
static void atrace_seq_number_changed(uint32_t prev_seq_no, uint32_t seq_no) {
if (!atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
return;
}
// Someone raced us.
if (!atomic_compare_exchange_strong(&last_sequence_number, &prev_seq_no, seq_no)) {
return;
}
if (CC_UNLIKELY(prev_seq_no == kSeqNoNotInit)) {
#if defined(__BIONIC__)
const prop_info* new_pi = __system_property_find("debug.atrace.tags.enableflags");
if (new_pi) atrace_property_info = new_pi;
#endif
pthread_once(&atrace_once_control, atrace_init_once);
}
atrace_update_tags();
}
这里用调用到了atrace_update_tags
system/core/libcutils/trace-dev.inc
void atrace_update_tags()
{
uint64_t tags;
if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
tags = atrace_get_property();
pthread_mutex_lock(&atrace_tags_mutex);
atrace_enabled_tags = tags;
pthread_mutex_unlock(&atrace_tags_mutex);
} else {
// Tracing is disabled for this process, so we simply don't
// initialize the tags.
pthread_mutex_lock(&atrace_tags_mutex);
atrace_enabled_tags = ATRACE_TAG_NOT_READY;
pthread_mutex_unlock(&atrace_tags_mutex);
}
}
最后到了
void atrace_update_tags()
{
uint64_t tags;
if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
tags = atrace_get_property();
pthread_mutex_lock(&atrace_tags_mutex);
atrace_enabled_tags = tags;
pthread_mutex_unlock(&atrace_tags_mutex);
} else {
// Tracing is disabled for this process, so we simply don't
// initialize the tags.
pthread_mutex_lock(&atrace_tags_mutex);
atrace_enabled_tags = ATRACE_TAG_NOT_READY;
pthread_mutex_unlock(&atrace_tags_mutex);
}
}
再调用到atrace_get_property方法
static uint64_t atrace_get_property()
{
char value[PROPERTY_VALUE_MAX];
char *endptr;
uint64_t tags;
property_get("debug.atrace.tags.enableflags", value, "0");//属性中获取这些设置的tag
errno = 0;
tags = strtoull(value, &endptr, 0);
if (value[0] == '\0' || *endptr != '\0') {
ALOGE("Error parsing trace property: Not a number: %s", value);
return 0;
} else if (errno == ERANGE || tags == ULLONG_MAX) {
ALOGE("Error parsing trace property: Number too large: %s", value);
return 0;
}
// Only set the "app" tag if this process was selected for app-level debug
// tracing.
if (atrace_is_app_tracing_enabled()) { //注意这里针对tag_app的是单独设置的哈
tags |= ATRACE_TAG_APP;
} else {
tags &= ~ATRACE_TAG_APP;
}
return (tags | ATRACE_TAG_ALWAYS) & ATRACE_TAG_VALID_MASK;
}
上面可以看出tag最后其实有2个部分:普通tag,ATRACE_TAG_APP。
既可以看出ATRACE_TAG_APP和其他如下TAG不同:
sched freq idle am wm power gfx view binder_driver hal dalvik camera input res
下面分别分析一下普通tag和ATRACE_TAG_APP是如何进行设置的,这里为了简单方便拿atrace代码来分析。
1 普通tag
上面代码看出主要是"debug.atrace.tags.enableflags"属性获取值,那么可以把这里作为切入点反推
使用这个属性的只有setTagsProperty方法
那么看看setTagsProperty是在哪调用的
这里核心变量g_categoryEnables和k_categories就是常见携带的参数映射表进行匹配,然后设置相关tags这个整型变量
g_categoryEnables是哪里设置呢?
在下面的setCategoryEnable方法设置
setCategoryEnable是靠atrace传递来的相关tag参数解析调用
2 单独的ATRACE_TAG_APP
识别是否有-a参数然后进行获取参数赋值g_debugAppCmdLine
在上面提到的setUpUserspaceTracing方法中调用了setAppCmdlineProperty
看看setAppCmdlineProperty实现
看得出来本质也是调用了属性设置而已。
然后在
system/core/libcutils/trace-dev.inc
会进行属性获取,并且与当前进程名字进行比较决定是否开启app的trace。
最后在atrace_get_property时候会进行ATRACE_TAG_APP的或操作
配置不一样,不是和他们一起,需要单独设置,具体如何设置呢?
如何开放ATRACE_TAG_APP
如何设置可以看看perfetto和atrace命令的help:
这里要加入-a方式
执行结果如下:
包名为com.example.injectmotion
sh capture.sh com.example.injectmotion
抓取trace后看到结果如下:
更多framework详细代码和资料参考如下链接
hal+perfetto+surfaceflinger
https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
其他课程七件套专题:
点击这里
https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw
视频试看:
https://www.bilibili.com/video/BV1wc41117L4/
参考相关链接:
https://blog.csdn.net/zhimokf/article/details/137958615