Is logging Android systrace events directly from native code possible, without JNI?

后端 未结 2 1263
礼貌的吻别
礼貌的吻别 2021-01-06 14:16

The Android systrace logging system is fantastic, but it only works in the Java portion of the code, through Trace.beginSection() and Trace.endSection()

2条回答
  •  没有蜡笔的小新
    2021-01-06 14:52

    Posting a follow-up answer with some code, based on fadden's pointers. Please read his/her answer first for the overview.

    All it takes is writing properly formatted strings to /sys/kernel/debug/tracing/trace_marker, which can be opened without problems. Below is some very minimal code based on the cutils header and C file. I preferred to re-implement it instead of pulling in any dependencies, so if you care a lot about correctness check the rigorous implementation there, and/or add your own extra checks and error-handling.

    This was tested to work on Android 4.4.2.

    The trace file must first be opened, saving the file descriptor in an atrace_marker_fd global:

    #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 */ }
    }
    

    Normal 'nested' traces like the Java Trace.beginSection and Trace.endSection are obtained with:

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

    Two more trace types are available, which are not accessible to Java as far as I know: trace counters and asynchronous traces.

    Counters track the value of an integer and draw a little graph in the systrace HTML output. Very useful stuff:

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

    Asynchronous traces produce non-nested (i.e. simply overlapping) intervals. They show up as grey segments above the thin thread-state bar in the systrace HTML output. They take an extra 32-bit integer argument that "distinguishes simultaneous events". The same name and integer must be used when ending traces:

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

    Finally, there indeed seems to be no way of specifying times to log, short of recompiling Android, so this doesn't do anything for the "bonus twist".

提交回复
热议问题