atrace命令可以开启trace,让系统中埋下的trace标记开始记录,这是怎么实现的呢,
我们以系统层的trace为例来查看,
atrace的代码
frameworks/native/cmds/atrace/atrace.cpp
93/* Tracing categories */ 94static const TracingCategory k_categories[] = { 95 { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { 96 { OPT, "events/mdss/enable" }, 97 { OPT, "events/sde/enable" }, 98 } }, 99 { "input", "Input", ATRACE_TAG_INPUT, { } }, 100 { "view", "View System", ATRACE_TAG_VIEW, { } }, 101 { "webview", "WebView", ATRACE_TAG_WEBVIEW, { } }, 102 { "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } },
里面通过设置属性的值,来传递信息,即哪些tag需要进行记录
606// Set the trace tags that userland tracing uses, and poke the running 607// processes to pick up the new value. 608static bool setTagsProperty(uint64_t tags) 609{ 610 std::string value = android::base::StringPrintf("%#" PRIx64, tags); 611 if (!android::base::SetProperty(k_traceTagsProperty, value)) { 612 fprintf(stderr, "error setting trace tags system property\n"); 613 return false; 614 } 615 return true; 616}
60const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
执行函数由于执行的次数很多,所以没有必要每次都读取属性 debug.atrace.tags.enableflags的值来判断当前tag是否需要打印,只需要读一次,保存下来即可。
但是进程怎么知道属性值变化了呢,这里调用每个系统服务的SYSPROPS_TRANSACTION方法,来推送,
531// Poke all the binder-enabled processes in the system to get them to re-read 532// their system properties. 533static bool pokeBinderServices() 534{ 535 sp<IServiceManager> sm = defaultServiceManager(); 536 Vector<String16> services = sm->listServices(); 537 for (size_t i = 0; i < services.size(); i++) { 538 sp<IBinder> obj = sm->checkService(services[i]); 539 if (obj != NULL) { 540 Parcel data; 541 if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data, 542 NULL, 0) != OK) { 543 if (false) { 544 // XXX: For some reason this fails on tablets trying to 545 // poke the "phone" service. It's not clear whether some 546 // are expected to fail. 547 String8 svc(services[i]); 548 fprintf(stderr, "error poking binder service %s\n", 549 svc.string()); 550 return false; 551 } 552 } 553 } 554 } 555 return true; 556}
SYSPROPS_TRANSACTION 方法执行起来做什么?
status_t BBinder::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
{
switch (code) {
...
case SYSPROPS_TRANSACTION: {
report_sysprop_change();
return NO_ERROR;
}
...
}
}
report_sysprop_change()方法会调用属性变化的回调函数,
void report_sysprop_change() {
do_report_sysprop_change();
#if defined(__ANDROID__)
// libutils.so is double loaded; from the default namespace and from the
// 'sphal' namespace. Redirect the sysprop change event to the other instance
// of libutils.so loaded in the 'sphal' namespace so that listeners attached
// to that instance is also notified with this event.
static auto func = get_report_sysprop_change_func();
if (func != nullptr) {
(*func)();
}
#endif
}
所以,服务进程中写了回调函数后,就可以更新属性的值了。
这里使用了binder来进行通知。
InputDispatcher里的trace调用
3868void InputDispatcher::traceInboundQueueLengthLocked() { 3869 if (ATRACE_ENABLED()) { 3870 ATRACE_INT("iq", mInboundQueue.count()); 3871 } 3872}
ATRACE_ENABLED
/system/core/include/cutils/ | ||
H A D | trace.h | 168 #define ATRACE_ENABLED() atrace_is_tag_enabled(ATRACE_TAG) |
156#define ATRACE_GET_ENABLED_TAGS() atrace_get_enabled_tags() 157static inline uint64_t atrace_get_enabled_tags() 158{ 159 atrace_init(); 160 return atrace_enabled_tags; 161} 162 163/** 164 * Test if a given tag is currently enabled. 165 * Returns nonzero if the tag is enabled, otherwise zero. 166 * It can be used as a guard condition around more expensive trace calculations. 167 */ 168#define ATRACE_ENABLED() atrace_is_tag_enabled(ATRACE_TAG) 169static inline uint64_t atrace_is_tag_enabled(uint64_t tag) 170{ 171 return atrace_get_enabled_tags() & tag; 172}
调用traceInit()可以设置属性变化的回调,会调用
22static void traceInit() { 23 ::android::add_sysprop_change_callback(atrace_update_tags, 0); 24}
这里有个很有意思的知识点,在代码中搜不到traceInit的调用,只看到定义,
20static void traceInit() __attribute__((constructor)); 21 22static void traceInit() { 23 ::android::add_sysprop_change_callback(atrace_update_tags, 0); 24}
那到底是怎样设置的回调函数呢?
其实设置了 __attribute__((constructor)) 这个高端写法,在main函数开始的地方,就会调用traceInit方法,我们可以搜一下 __attribute__((constructor))这个用法。也可以写个例子来验证这种调用,情况确实如此。
查看atrace_update_tags的定义,在里面读取属性"debug.atrace.tags.enableflags"的值,更新了atrace_enabled_tags的值,
98/** 99 * If tracing is ready, set atrace_enabled_tags to the system property 100 * debug.atrace.tags.enableflags. Can be used as a sysprop change callback. 101 */ 102void atrace_update_tags();
在 system/core/libcutils/trace-dev.inc
里有其实现,获取了要监控的属性值
136// Update tags if tracing is ready. Useful as a sysprop change callback. 137void atrace_update_tags() 138{ 139 uint64_t tags; 140 if (CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) { 141 if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) { 142 tags = atrace_get_property(); 143 pthread_mutex_lock(&atrace_tags_mutex); 144 atrace_enabled_tags = tags; 145 pthread_mutex_unlock(&atrace_tags_mutex); 146 } else { 147 // Tracing is disabled for this process, so we simply don't 148 // initialize the tags. 149 pthread_mutex_lock(&atrace_tags_mutex); 150 atrace_enabled_tags = ATRACE_TAG_NOT_READY; 151 pthread_mutex_unlock(&atrace_tags_mutex); 152 } 153 } 154}
总结:
细节很多,这里回顾一下大体过程,atrace里设置tag,标识哪些tag可以进行写trace,然后写到属性值debug.atrace.tags.enableflags里,atrace又进行了binder调用所有系统服务的SYSPROPS_TRANSACTION对应的方法,告诉它们,属性值变化了,可以调用属性变化回调函数了。
系统服务进程就调用预定的回调函数,读取debug.atrace.tags.enableflags的值,保存起来,以后就可以用这个值来和tag进行比较,判断当前的tag是否需要写trace,避免每次都属性值,那个读取代价太大。
普通应用中的trace原理类似,也是设置了属性值。
相关知识点:属性值的变化可以设置回调函数。
binder中竟然有个冷门方法SYSPROPS_TRANSACTION,通知属性值的变化。
参考资料:
[Android systrace系列] systrace的信息从哪里来 - zzc1024 - 博客园
监听SystemProperties变化_m0_52481422的博客-CSDN博客_android 监听property变化