Systrace实现-1-判断Trace是否使能

基于A12

一、isTagEnabled()执行逻辑

这里以binder的 isTagEnabled() 为例进行说明。

相关文件:

android/frameworks/base/core/java/android/os/Binder.java
android/frameworks/base/core/java/android/os/Trace.java
android/frameworks/base/core/jni/android_os_Trace.cpp
android/system/core/libcutils/trace-dev.inc
android/bionic/libc/bionic/system_property_api.cpp


1. Java执行流

execTransactInternal //Binder.java
    if (Binder.isTracingEnabled()) //可有可无
        Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, getClass().getName() + ":" transactionName);
xxx
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);

下面看 Trace.traceBegin() 是如何实现的:

public static void traceBegin(long traceTag, String methodName) { //Trace.java
    if (isTagEnabled(traceTag)) { //不抓trace时主要看它是否影响性能
        nativeTraceBegin(traceTag, methodName);
    }
}

public static boolean isTagEnabled(long traceTag) { //Trace.java
    long tags = nativeGetEnabledTags();
    return (tags & traceTag) != 0;
}

static const JNINativeMethod gTraceMethods[] = { //android_os_Trace.cpp
{ "nativeGetEnabledTags", "()J", (void*)atrace_get_enabled_tags },

uint64_t atrace_get_enabled_tags() //trace-dev.inc
{
    atrace_init();
    return atrace_enabled_tags;
}

/* 正常不抓trace时,这里应该就读一下就退出了 */
void atrace_init() { //trace-dev.inc
#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);
    }
}

uint32_t __system_property_serial(const prop_info* pi) { //system_property_api.cpp 
    return atomic_load_explicit(&pi->serial, memory_order_acquire);
}

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;
    }
    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();
}

void atrace_update_tags() //trace-dev.inc
{
    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 {
        /* 此进程的跟踪已被禁用,因此我们不初始化标签 */
        pthread_mutex_lock(&atrace_tags_mutex);
        atrace_enabled_tags = ATRACE_TAG_NOT_READY;
        pthread_mutex_unlock(&atrace_tags_mutex);
    }
}

/* Read the sysprop and return the value tags should be set to */
static uint64_t atrace_get_property() //trace-dev.inc
{
    char value[PROPERTY_VALUE_MAX];
    char *endptr;
    uint64_t tags;

    property_get("debug.atrace.tags.enableflags", value, "0"); ######
    tags = strtoull(value, &endptr, 0);

    /* 仅当选择此进程进行应用程序级调试跟踪时才设置"app"标签 */
    if (atrace_is_app_tracing_enabled()) {
        tags |= ATRACE_TAG_APP;
    } else {
        tags &= ~ATRACE_TAG_APP;
    }

    return (tags | ATRACE_TAG_ALWAYS) & ATRACE_TAG_VALID_MASK;
}

/* 确定是否为此进程启用了应用程序级跟踪。 */
static bool atrace_is_app_tracing_enabled() //trace-dev.inc
{
    bool sys_debuggable = property_get_bool("ro.debuggable", 0);
    bool result = false;

    if (sys_debuggable || atrace_is_debuggable) {
        /* Check whether tracing is enabled for this process. */
        FILE * file = fopen("/proc/self/cmdline", "re");
        if (file) {
            if (fgets(cmdline, sizeof(cmdline), file)) {
                result = atrace_is_cmdline_match(cmdline);
            }
            fclose(file);
    }
    return result;
}


/* 检查给定的命令行是否与 app_cmdlines 属性中列出的逗号分隔的值之一匹配 */
static bool atrace_is_cmdline_match(const char* cmdline) //trace-dev.inc
{
    int count = property_get_int32("debug.atrace.app_number", 0);
    char buf[PROPERTY_KEY_MAX];
    char value[PROPERTY_VALUE_MAX];

    for (int i = 0; i < count; i++) {
        snprintf(buf, sizeof(buf), "debug.atrace.app_%d", i);
        property_get(buf, value, "");
        if (strcmp(value, "*") == 0 || strcmp(value, cmdline) == 0) {
            return true;
        }
    }
    return false;
}

"ro.debuggable" userdebug 版本是1,user 版本是0.

若是正常不抓systrace的时候,Trace.traceBegin() 对性能的影响应该就是一次JNI调用 + 一次原子变量的读取


2. atrace_is_debuggable 是如何赋值的

void atrace_set_debuggable(bool debuggable) //trace-dev.inc
{
    atrace_is_debuggable = debuggable;
    atrace_update_tags();
}

static void android_os_Trace_nativeSetAppTracingAllowed(JNIEnv*, jclass, jboolean allowed) { //android_os_Trace.cpp
    atrace_set_debuggable(allowed);
}
static const JNINativeMethod gTraceMethods[] = {
    { "nativeSetAppTracingAllowed", "(Z)V", (void*)android_os_Trace_nativeSetAppTracingAllowed },
}

public static void setAppTracingAllowed(boolean allowed) { //Trace.java
    nativeSetAppTracingAllowed(allowed);
}

//android/frameworks/base/core/java/android/app/ActivityThread.java
private void handleBindApplication(AppBindData data) {
    /* 如果我们 profileable 的话,允许 Binder trace和应用程序生成的 systrace 消息。 */
    boolean isAppDebuggable = (data.appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
    boolean isAppProfileable = isAppDebuggable || data.appInfo.isProfileable();
    Trace.setAppTracingAllowed(isAppProfileable); //唯一调用位置
    if ((isAppProfileable || Build.IS_DEBUGGABLE) && data.enableBinderTracking) {
        Binder.enableTracing(); //还有可能使能binder trace
    }
}

在 handleBindApplication() 中使能。


3. ATRACE_TAG_APP 谁在用

全局检索 ATRACE_TAG_APP 只有下面这个文件中使用了这个TAG.

//android/frameworks/base/native/android/trace.cpp

但是在系统中检索这里面实现的函数,几乎没有调用位置。


二、trace相关属性

1. trace属性值

/ # getprop | grep trace
[debug.atrace.app_0]: []       //ro.debuggable为true时不存在,应该只user版本用
[debug.atrace.app_number]: []  //ro.debuggable为true时不存在,应该只user版本用
[debug.atrace.tags.enableflags]: [0] //不抓trace时是0,抓trace时是 0x496e
[debug.atrace.user_initiated]: []    //ro.debuggable为true时不存在,应该只user版本用
[init.svc.traced]: [running]         //抓不抓trace都恒为running,TODO: 这个traced服务是谁呀?
[init.svc.traced_perf]: [stopped]    //抓不抓trace都恒为stopped
[init.svc.traced_probes]: [running]  //抓trace时是stopped,停止抓取时是running
[init.svc.vendor.atrace-hal-1-0]: [running] //恒为running, TODO: 是 atrace@1.0-serv 吗?看它是做什么的?
[init.svc_debug_pid.traced]: [991]
[init.svc_debug_pid.traced_perf]: []
[init.svc_debug_pid.traced_probes]: [988] //这个会变
[init.svc_debug_pid.vendor.atrace-hal-1-0]: [486]
[persist.debug.trace]: [0]
[persist.traced.enable]: [1]
[ro.boottime.traced]: [5760607183]
[ro.boottime.traced_probes]: [5737517444]
[ro.boottime.vendor.atrace-hal-1-0]: [4075050727]

当使能 ro.debuggable 后,debug.atrace.app_0、debug.atrace.app_number、debug.atrace.user_initiated 就都不存在了

抓trace时,在默认的配置下 debug.atrace.tags.enableflags 属性的值是 0x496e(0b0100,1001,0110,1110) 对应 atrace 抓取命令的使能项 "gfx input view wm am sched idle freq irq disk workq binder_driver binder_lock audio dalvik hal"

这些值是与 /android/system/core/libcutils/include/cutils/trace.h 里面的定义是对应的:

//android/system/core/libcutils/include/cutils/trace.h
//0x496e = 0b0100,1001,0110,1101 = 
#define ATRACE_TAG_GRAPHICS         (1<<1)  //对应"gfx"
#define ATRACE_TAG_INPUT            (1<<2)  //对应"input"
#define ATRACE_TAG_VIEW             (1<<3)  //对应"view"
#define ATRACE_TAG_WINDOW_MANAGER   (1<<5)  //对应"wm"
#define ATRACE_TAG_ACTIVITY_MANAGER (1<<6)  //对应"am"
#define ATRACE_TAG_AUDIO            (1<<8)  //对应"audio"
#define ATRACE_TAG_HAL              (1<<11) //对应"hal"
#define ATRACE_TAG_DALVIK           (1<<14) //对应"dalvik"

atrace增加一个 "aidl" 项后是 0x100496e, 多出 1<<24, 刚好是 ATRACE_TAG_AIDL 的值。

[debug.atrace.tags.enableflags]: [0x100496e]
#define ATRACE_TAG_AIDL (1<<24)


2. ro.debuggable 属性

Android系统中 ro.debuggable 属性的初始化逻辑主要分为以下三个阶段:

(1) 编译阶段固化
ro.debuggable 的初始值在 Android 系统编译时由 build.prop 或 default.prop 文件设定,具体取决于设备厂商的配置。例如:
a. 普通用户版 ROM 通常设为 0(禁止全局调试);
b. 开发版或模拟器镜像可能预设为 1(允许全局调试)。

(2) 启动阶段加载
Android 启动时,init 进程会从 boot.img 的 ramdisk 挂载分区,读取 default.prop 并加载所有系统属性(包括 ro.debuggable)。一旦 init 进程完成初始化,ro.debuggable 会被标记为只读(read-only),普通方法无法修改。

实测 ro.debuggable 位于机器中的 /default.prop 文件中。实测改为1后再push到机器中,无论是执行 stop/start,还是 reboot 都不会改变其值。


三、atrace选项与TAG的对应关系

每一个 TAG 与 atrace 选项的对应关系见 k_categories[]

//android/frameworks/native/cmds/atrace/atrace.cpp

/* Tracing categories */
static const TracingCategory k_categories[] = {
    { "gfx",        "Graphics",                 ATRACE_TAG_GRAPHICS, {
        { OPT,      "events/gpu_mem/gpu_mem_total/enable" },
    } },
    { "input",      "Input",                    ATRACE_TAG_INPUT, { } },
    { "view",       "View System",              ATRACE_TAG_VIEW, { } },
    { "webview",    "WebView",                  ATRACE_TAG_WEBVIEW, { } },
    { "wm",         "Window Manager",           ATRACE_TAG_WINDOW_MANAGER, { } },
    { "am",         "Activity Manager",         ATRACE_TAG_ACTIVITY_MANAGER, { } },
    { "sm",         "Sync Manager",             ATRACE_TAG_SYNC_MANAGER, { } },
    { "audio",      "Audio",                    ATRACE_TAG_AUDIO, { } },
    { "video",      "Video",                    ATRACE_TAG_VIDEO, { } },
    { "camera",     "Camera",                   ATRACE_TAG_CAMERA, { } },
    { "hal",        "Hardware Modules",         ATRACE_TAG_HAL, { } },
    { "res",        "Resource Loading",         ATRACE_TAG_RESOURCES, { } },
    { "dalvik",     "Dalvik VM",                ATRACE_TAG_DALVIK, { } },
    { "rs",         "RenderScript",             ATRACE_TAG_RS, { } },
    { "bionic",     "Bionic C Library",         ATRACE_TAG_BIONIC, { } },
    { "power",      "Power Management",         ATRACE_TAG_POWER, { } },
    { "pm",         "Package Manager",          ATRACE_TAG_PACKAGE_MANAGER, { } },
    { "ss",         "System Server",            ATRACE_TAG_SYSTEM_SERVER, { } },
    { "database",   "Database",                 ATRACE_TAG_DATABASE, { } },
    { "network",    "Network",                  ATRACE_TAG_NETWORK, { } },
    { "adb",        "ADB",                      ATRACE_TAG_ADB, { } },
    { "vibrator",   "Vibrator",                 ATRACE_TAG_VIBRATOR, { } },
    { "aidl",       "AIDL calls",               ATRACE_TAG_AIDL, { } },
    { "nnapi",      "NNAPI",                    ATRACE_TAG_NNAPI, { } },
    { "rro",        "Runtime Resource Overlay", ATRACE_TAG_RRO, { } },
    { k_coreServiceCategory, "Core services", 0, { } },
    { k_pdxServiceCategory, "PDX services", 0, { } },
    { "sched",      "CPU Scheduling",   0, {
        { REQ,      "events/sched/sched_switch/enable" },
        { REQ,      "events/sched/sched_wakeup/enable" },
        { OPT,      "events/sched/sched_waking/enable" },
        { OPT,      "events/sched/sched_blocked_reason/enable" },
        { OPT,      "events/sched/sched_cpu_hotplug/enable" },
        { OPT,      "events/sched/sched_pi_setprio/enable" },
        { OPT,      "events/sched/sched_process_exit/enable" },
        { OPT,      "events/cgroup/enable" },
        { OPT,      "events/oom/oom_score_adj_update/enable" },
        { OPT,      "events/task/task_rename/enable" },
        { OPT,      "events/task/task_newtask/enable" },
    } },
    { "irq",        "IRQ Events",   0, {
        { REQ,      "events/irq/enable" },
        { OPT,      "events/ipi/enable" },
    } },
    { "irqoff",     "IRQ-disabled code section tracing", 0, {
        { REQ,      "events/preemptirq/irq_enable/enable" },
        { REQ,      "events/preemptirq/irq_disable/enable" },
    } },
    { "preemptoff", "Preempt-disabled code section tracing", 0, {
        { REQ,      "events/preemptirq/preempt_enable/enable" },
        { REQ,      "events/preemptirq/preempt_disable/enable" },
    } },
    { "i2c",        "I2C Events",   0, {
        { REQ,      "events/i2c/enable" },
        { REQ,      "events/i2c/i2c_read/enable" },
        { REQ,      "events/i2c/i2c_write/enable" },
        { REQ,      "events/i2c/i2c_result/enable" },
        { REQ,      "events/i2c/i2c_reply/enable" },
        { OPT,      "events/i2c/smbus_read/enable" },
        { OPT,      "events/i2c/smbus_write/enable" },
        { OPT,      "events/i2c/smbus_result/enable" },
        { OPT,      "events/i2c/smbus_reply/enable" },
    } },
    { "freq",       "CPU Frequency",    0, {
        { REQ,      "events/power/cpu_frequency/enable" },
        { OPT,      "events/power/clock_set_rate/enable" },
        { OPT,      "events/power/clock_disable/enable" },
        { OPT,      "events/power/clock_enable/enable" },
        { OPT,      "events/clk/clk_set_rate/enable" },
        { OPT,      "events/clk/clk_disable/enable" },
        { OPT,      "events/clk/clk_enable/enable" },
        { OPT,      "events/power/cpu_frequency_limits/enable" },
        { OPT,      "events/power/suspend_resume/enable" },
        { OPT,      "events/cpuhp/cpuhp_enter/enable" },
        { OPT,      "events/cpuhp/cpuhp_exit/enable" },
        { OPT,      "events/cpuhp/cpuhp_pause/enable" },
    } },
    { "membus",     "Memory Bus Utilization", 0, {
        { REQ,      "events/memory_bus/enable" },
    } },
    { "idle",       "CPU Idle",         0, {
        { REQ,      "events/power/cpu_idle/enable" },
    } },
    { "disk",       "Disk I/O",         0, {
        { OPT,      "events/f2fs/f2fs_sync_file_enter/enable" },
        { OPT,      "events/f2fs/f2fs_sync_file_exit/enable" },
        { OPT,      "events/f2fs/f2fs_write_begin/enable" },
        { OPT,      "events/f2fs/f2fs_write_end/enable" },
        { OPT,      "events/ext4/ext4_da_write_begin/enable" },
        { OPT,      "events/ext4/ext4_da_write_end/enable" },
        { OPT,      "events/ext4/ext4_sync_file_enter/enable" },
        { OPT,      "events/ext4/ext4_sync_file_exit/enable" },
        { REQ,      "events/block/block_rq_issue/enable" },
        { REQ,      "events/block/block_rq_complete/enable" },
    } },
    { "mmc",        "eMMC commands",    0, {
        { REQ,      "events/mmc/enable" },
    } },
    { "load",       "CPU Load",         0, {
        { REQ,      "events/cpufreq_interactive/enable" },
    } },
    { "sync",       "Synchronization",  0, {
        // linux kernel < 4.9
        { OPT,      "events/sync/enable" },
        // linux kernel == 4.9.x
        { OPT,      "events/fence/enable" },
        // linux kernel > 4.9
        { OPT,      "events/dma_fence/enable" },
    } },
    { "workq",      "Kernel Workqueues", 0, {
        { REQ,      "events/workqueue/enable" },
    } },
    { "memreclaim", "Kernel Memory Reclaim", 0, {
        { REQ,      "events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
        { REQ,      "events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
        { REQ,      "events/vmscan/mm_vmscan_kswapd_wake/enable" },
        { REQ,      "events/vmscan/mm_vmscan_kswapd_sleep/enable" },
        { OPT,      "events/lowmemorykiller/enable" },
    } },
    { "regulators",  "Voltage and Current Regulators", 0, {
        { REQ,      "events/regulator/enable" },
    } },
    { "binder_driver", "Binder Kernel driver", 0, {
        { REQ,      "events/binder/binder_transaction/enable" },
        { REQ,      "events/binder/binder_transaction_received/enable" },
        { REQ,      "events/binder/binder_transaction_alloc_buf/enable" },
        { OPT,      "events/binder/binder_set_priority/enable" },
    } },
    { "binder_lock", "Binder global lock trace", 0, {
        { OPT,      "events/binder/binder_lock/enable" },
        { OPT,      "events/binder/binder_locked/enable" },
        { OPT,      "events/binder/binder_unlock/enable" },
    } },
    { "pagecache",  "Page cache", 0, {
        { REQ,      "events/filemap/enable" },
    } },
    { "memory",  "Memory", 0, {
        { OPT,      "events/mm_event/mm_event_record/enable" },
        { OPT,      "events/kmem/rss_stat/enable" },
        { OPT,      "events/kmem/ion_heap_grow/enable" },
        { OPT,      "events/kmem/ion_heap_shrink/enable" },
        { OPT,      "events/ion/ion_stat/enable" },
        { OPT,      "events/gpu_mem/gpu_mem_total/enable" },
    } },
    { "thermal",  "Thermal event", 0, {
        { REQ,      "events/thermal/thermal_temperature/enable" },
        { OPT,      "events/thermal/cdev_update/enable" },
    } },
};

注: REQ 是必须要使能的,若写失败会返回false, 而 OPT 可选使能的, 即使不能写或写失败也不报错。

 

posted on 2025-03-27 17:35  Hello-World3  阅读(110)  评论(0)    收藏  举报

导航