Native Tracing

This guide describes how to use the native tracing API (trace.h) to write trace events to the system buffer. You can then analyze this trace output by using the Systrace tool. The native tracing API is supported for Android API levels 23 and higher.


Creating a custom trace in native code is similar to the technique for the Java programming language, described in Tracing Application Code. You typically don’t need to put your native tracing code in try/catch blocks unless the traced section throws a native exception or uses an early return.

For each ATrace_beginSection() call, make sure you also have a corresponding ATrace_endSection() call, otherwise it might result in a corrupt trace file.

To avoid building complex strings or arguments when tracing is not enabled, you can add a guard by calling ATrace_isEnabled() .

Tracing a Function

One use case for the native tracing API is to observe the time taken by a particular block of code. Typically, this tracing would be during the pipeline processing stage (for example, when decoding an image, drawing a frame, or waiting on a network request).

To trace the time taken by a block of code, follow these steps:

  1. Include the trace.h header file.
    #include <android/trace.h>
  2. Specify a variable as the section name in ATrace_beginSection(). At the end of the block of code you want to trace, make a corresponding call to ATrace_endSection(). This is particularly important when the traced section throws a native exception or uses an early return.
    void myExpensiveFunction() {
      ... // trace-worthy work here
  3. (Optional) Create a convenience object/macro structure to trace blocks of code. The following example shows how you might implement such an object/macro called ATRACE_CALL().
    #define ATRACE_NAME(name) ScopedTrace ___tracer(name)
    // ATRACE_CALL is an ATRACE_NAME that uses the current function name.
    class ScopedTrace {
        inline ScopedTrace(const char *name) {
        inline ~ScopedTrace() {
    Using the ATRACE_CALL() object/macro, you can simplify the code from the previous step as follows. By using the object/macro this way, you don't need to worry about adding try/catch blocks when the traced section throws an exception or uses an early return.
    void myExpensiveFunction() {
      ... // trace-worthy work here