Home | History | Annotate | Download | only in atrace
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <errno.h>
     18 #include <fcntl.h>
     19 #include <getopt.h>
     20 #include <signal.h>
     21 #include <stdarg.h>
     22 #include <stdbool.h>
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <sys/sendfile.h>
     26 #include <time.h>
     27 #include <zlib.h>
     28 
     29 #include <binder/IBinder.h>
     30 #include <binder/IServiceManager.h>
     31 #include <binder/Parcel.h>
     32 
     33 #include <cutils/properties.h>
     34 
     35 #include <utils/String8.h>
     36 #include <utils/Trace.h>
     37 
     38 using namespace android;
     39 
     40 #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
     41 
     42 enum { MAX_SYS_FILES = 8 };
     43 
     44 const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
     45 const char* k_traceAppCmdlineProperty = "debug.atrace.app_cmdlines";
     46 
     47 typedef enum { OPT, REQ } requiredness  ;
     48 
     49 struct TracingCategory {
     50     // The name identifying the category.
     51     const char* name;
     52 
     53     // A longer description of the category.
     54     const char* longname;
     55 
     56     // The userland tracing tags that the category enables.
     57     uint64_t tags;
     58 
     59     // The fname==NULL terminated list of /sys/ files that the category
     60     // enables.
     61     struct {
     62         // Whether the file must be writable in order to enable the tracing
     63         // category.
     64         requiredness required;
     65 
     66         // The path to the enable file.
     67         const char* path;
     68     } sysfiles[MAX_SYS_FILES];
     69 };
     70 
     71 /* Tracing categories */
     72 static const TracingCategory k_categories[] = {
     73     { "gfx",        "Graphics",         ATRACE_TAG_GRAPHICS, { } },
     74     { "input",      "Input",            ATRACE_TAG_INPUT, { } },
     75     { "view",       "View System",      ATRACE_TAG_VIEW, { } },
     76     { "webview",    "WebView",          ATRACE_TAG_WEBVIEW, { } },
     77     { "wm",         "Window Manager",   ATRACE_TAG_WINDOW_MANAGER, { } },
     78     { "am",         "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
     79     { "audio",      "Audio",            ATRACE_TAG_AUDIO, { } },
     80     { "video",      "Video",            ATRACE_TAG_VIDEO, { } },
     81     { "camera",     "Camera",           ATRACE_TAG_CAMERA, { } },
     82     { "hal",        "Hardware Modules", ATRACE_TAG_HAL, { } },
     83     { "res",        "Resource Loading", ATRACE_TAG_RESOURCES, { } },
     84     { "dalvik",     "Dalvik VM",        ATRACE_TAG_DALVIK, { } },
     85     { "sched",      "CPU Scheduling",   0, {
     86         { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
     87         { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
     88     } },
     89     { "freq",       "CPU Frequency",    0, {
     90         { REQ,      "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
     91         { OPT,      "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
     92     } },
     93     { "membus",     "Memory Bus Utilization", 0, {
     94         { REQ,      "/sys/kernel/debug/tracing/events/memory_bus/enable" },
     95     } },
     96     { "idle",       "CPU Idle",         0, {
     97         { REQ,      "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
     98     } },
     99     { "disk",       "Disk I/O",         0, {
    100         { REQ,      "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
    101         { REQ,      "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
    102         { REQ,      "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
    103         { REQ,      "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
    104     } },
    105     { "load",       "CPU Load",         0, {
    106         { REQ,      "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
    107     } },
    108     { "sync",       "Synchronization",  0, {
    109         { REQ,      "/sys/kernel/debug/tracing/events/sync/enable" },
    110     } },
    111     { "workq",      "Kernel Workqueues", 0, {
    112         { REQ,      "/sys/kernel/debug/tracing/events/workqueue/enable" },
    113     } },
    114 };
    115 
    116 /* Command line options */
    117 static int g_traceDurationSeconds = 5;
    118 static bool g_traceOverwrite = false;
    119 static int g_traceBufferSizeKB = 2048;
    120 static bool g_compress = false;
    121 static bool g_nohup = false;
    122 static int g_initialSleepSecs = 0;
    123 static const char* g_kernelTraceFuncs = NULL;
    124 static const char* g_debugAppCmdLine = "";
    125 
    126 /* Global state */
    127 static bool g_traceAborted = false;
    128 static bool g_categoryEnables[NELEM(k_categories)] = {};
    129 
    130 /* Sys file paths */
    131 static const char* k_traceClockPath =
    132     "/sys/kernel/debug/tracing/trace_clock";
    133 
    134 static const char* k_traceBufferSizePath =
    135     "/sys/kernel/debug/tracing/buffer_size_kb";
    136 
    137 static const char* k_tracingOverwriteEnablePath =
    138     "/sys/kernel/debug/tracing/options/overwrite";
    139 
    140 static const char* k_currentTracerPath =
    141     "/sys/kernel/debug/tracing/current_tracer";
    142 
    143 static const char* k_printTgidPath =
    144     "/sys/kernel/debug/tracing/options/print-tgid";
    145 
    146 static const char* k_funcgraphAbsTimePath =
    147     "/sys/kernel/debug/tracing/options/funcgraph-abstime";
    148 
    149 static const char* k_funcgraphCpuPath =
    150     "/sys/kernel/debug/tracing/options/funcgraph-cpu";
    151 
    152 static const char* k_funcgraphProcPath =
    153     "/sys/kernel/debug/tracing/options/funcgraph-proc";
    154 
    155 static const char* k_funcgraphFlatPath =
    156     "/sys/kernel/debug/tracing/options/funcgraph-flat";
    157 
    158 static const char* k_funcgraphDurationPath =
    159     "/sys/kernel/debug/tracing/options/funcgraph-duration";
    160 
    161 static const char* k_ftraceFilterPath =
    162     "/sys/kernel/debug/tracing/set_ftrace_filter";
    163 
    164 static const char* k_tracingOnPath =
    165     "/sys/kernel/debug/tracing/tracing_on";
    166 
    167 static const char* k_tracePath =
    168     "/sys/kernel/debug/tracing/trace";
    169 
    170 // Check whether a file exists.
    171 static bool fileExists(const char* filename) {
    172     return access(filename, F_OK) != -1;
    173 }
    174 
    175 // Check whether a file is writable.
    176 static bool fileIsWritable(const char* filename) {
    177     return access(filename, W_OK) != -1;
    178 }
    179 
    180 // Truncate a file.
    181 static bool truncateFile(const char* path)
    182 {
    183     // This uses creat rather than truncate because some of the debug kernel
    184     // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
    185     // calls to truncate, but they are cleared by calls to creat.
    186     int traceFD = creat(path, 0);
    187     if (traceFD == -1) {
    188         fprintf(stderr, "error truncating %s: %s (%d)\n", path,
    189             strerror(errno), errno);
    190         return false;
    191     }
    192 
    193     close(traceFD);
    194 
    195     return true;
    196 }
    197 
    198 static bool _writeStr(const char* filename, const char* str, int flags)
    199 {
    200     int fd = open(filename, flags);
    201     if (fd == -1) {
    202         fprintf(stderr, "error opening %s: %s (%d)\n", filename,
    203                 strerror(errno), errno);
    204         return false;
    205     }
    206 
    207     bool ok = true;
    208     ssize_t len = strlen(str);
    209     if (write(fd, str, len) != len) {
    210         fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
    211                 strerror(errno), errno);
    212         ok = false;
    213     }
    214 
    215     close(fd);
    216 
    217     return ok;
    218 }
    219 
    220 // Write a string to a file, returning true if the write was successful.
    221 static bool writeStr(const char* filename, const char* str)
    222 {
    223     return _writeStr(filename, str, O_WRONLY);
    224 }
    225 
    226 // Append a string to a file, returning true if the write was successful.
    227 static bool appendStr(const char* filename, const char* str)
    228 {
    229     return _writeStr(filename, str, O_APPEND|O_WRONLY);
    230 }
    231 
    232 // Enable or disable a kernel option by writing a "1" or a "0" into a /sys
    233 // file.
    234 static bool setKernelOptionEnable(const char* filename, bool enable)
    235 {
    236     return writeStr(filename, enable ? "1" : "0");
    237 }
    238 
    239 // Check whether the category is supported on the device with the current
    240 // rootness.  A category is supported only if all its required /sys/ files are
    241 // writable and if enabling the category will enable one or more tracing tags
    242 // or /sys/ files.
    243 static bool isCategorySupported(const TracingCategory& category)
    244 {
    245     bool ok = category.tags != 0;
    246     for (int i = 0; i < MAX_SYS_FILES; i++) {
    247         const char* path = category.sysfiles[i].path;
    248         bool req = category.sysfiles[i].required == REQ;
    249         if (path != NULL) {
    250             if (req) {
    251                 if (!fileIsWritable(path)) {
    252                     return false;
    253                 } else {
    254                     ok = true;
    255                 }
    256             } else {
    257                 ok |= fileIsWritable(path);
    258             }
    259         }
    260     }
    261     return ok;
    262 }
    263 
    264 // Check whether the category would be supported on the device if the user
    265 // were root.  This function assumes that root is able to write to any file
    266 // that exists.  It performs the same logic as isCategorySupported, but it
    267 // uses file existance rather than writability in the /sys/ file checks.
    268 static bool isCategorySupportedForRoot(const TracingCategory& category)
    269 {
    270     bool ok = category.tags != 0;
    271     for (int i = 0; i < MAX_SYS_FILES; i++) {
    272         const char* path = category.sysfiles[i].path;
    273         bool req = category.sysfiles[i].required == REQ;
    274         if (path != NULL) {
    275             if (req) {
    276                 if (!fileExists(path)) {
    277                     return false;
    278                 } else {
    279                     ok = true;
    280                 }
    281             } else {
    282                 ok |= fileExists(path);
    283             }
    284         }
    285     }
    286     return ok;
    287 }
    288 
    289 // Enable or disable overwriting of the kernel trace buffers.  Disabling this
    290 // will cause tracing to stop once the trace buffers have filled up.
    291 static bool setTraceOverwriteEnable(bool enable)
    292 {
    293     return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
    294 }
    295 
    296 // Enable or disable kernel tracing.
    297 static bool setTracingEnabled(bool enable)
    298 {
    299     return setKernelOptionEnable(k_tracingOnPath, enable);
    300 }
    301 
    302 // Clear the contents of the kernel trace.
    303 static bool clearTrace()
    304 {
    305     return truncateFile(k_tracePath);
    306 }
    307 
    308 // Set the size of the kernel's trace buffer in kilobytes.
    309 static bool setTraceBufferSizeKB(int size)
    310 {
    311     char str[32] = "1";
    312     int len;
    313     if (size < 1) {
    314         size = 1;
    315     }
    316     snprintf(str, 32, "%d", size);
    317     return writeStr(k_traceBufferSizePath, str);
    318 }
    319 
    320 // Enable or disable the kernel's use of the global clock.  Disabling the global
    321 // clock will result in the kernel using a per-CPU local clock.
    322 static bool setGlobalClockEnable(bool enable)
    323 {
    324     return writeStr(k_traceClockPath, enable ? "global" : "local");
    325 }
    326 
    327 static bool setPrintTgidEnableIfPresent(bool enable)
    328 {
    329     if (fileExists(k_printTgidPath)) {
    330         return setKernelOptionEnable(k_printTgidPath, enable);
    331     }
    332     return true;
    333 }
    334 
    335 // Poke all the binder-enabled processes in the system to get them to re-read
    336 // their system properties.
    337 static bool pokeBinderServices()
    338 {
    339     sp<IServiceManager> sm = defaultServiceManager();
    340     Vector<String16> services = sm->listServices();
    341     for (size_t i = 0; i < services.size(); i++) {
    342         sp<IBinder> obj = sm->checkService(services[i]);
    343         if (obj != NULL) {
    344             Parcel data;
    345             if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
    346                     NULL, 0) != OK) {
    347                 if (false) {
    348                     // XXX: For some reason this fails on tablets trying to
    349                     // poke the "phone" service.  It's not clear whether some
    350                     // are expected to fail.
    351                     String8 svc(services[i]);
    352                     fprintf(stderr, "error poking binder service %s\n",
    353                         svc.string());
    354                     return false;
    355                 }
    356             }
    357         }
    358     }
    359     return true;
    360 }
    361 
    362 // Set the trace tags that userland tracing uses, and poke the running
    363 // processes to pick up the new value.
    364 static bool setTagsProperty(uint64_t tags)
    365 {
    366     char buf[64];
    367     snprintf(buf, 64, "%#llx", tags);
    368     if (property_set(k_traceTagsProperty, buf) < 0) {
    369         fprintf(stderr, "error setting trace tags system property\n");
    370         return false;
    371     }
    372     return true;
    373 }
    374 
    375 // Set the system property that indicates which apps should perform
    376 // application-level tracing.
    377 static bool setAppCmdlineProperty(const char* cmdline)
    378 {
    379     if (property_set(k_traceAppCmdlineProperty, cmdline) < 0) {
    380         fprintf(stderr, "error setting trace app system property\n");
    381         return false;
    382     }
    383     return true;
    384 }
    385 
    386 // Disable all /sys/ enable files.
    387 static bool disableKernelTraceEvents() {
    388     bool ok = true;
    389     for (int i = 0; i < NELEM(k_categories); i++) {
    390         const TracingCategory &c = k_categories[i];
    391         for (int j = 0; j < MAX_SYS_FILES; j++) {
    392             const char* path = c.sysfiles[j].path;
    393             if (path != NULL && fileIsWritable(path)) {
    394                 ok &= setKernelOptionEnable(path, false);
    395             }
    396         }
    397     }
    398     return ok;
    399 }
    400 
    401 // Verify that the comma separated list of functions are being traced by the
    402 // kernel.
    403 static bool verifyKernelTraceFuncs(const char* funcs)
    404 {
    405     int fd = open(k_ftraceFilterPath, O_RDONLY);
    406     if (fd == -1) {
    407         fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
    408             strerror(errno), errno);
    409         return false;
    410     }
    411 
    412     char buf[4097];
    413     ssize_t n = read(fd, buf, 4096);
    414     close(fd);
    415     if (n == -1) {
    416         fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath,
    417             strerror(errno), errno);
    418         return false;
    419     }
    420 
    421     buf[n] = '\0';
    422     String8 funcList = String8::format("\n%s", buf);
    423 
    424     // Make sure that every function listed in funcs is in the list we just
    425     // read from the kernel.
    426     bool ok = true;
    427     char* myFuncs = strdup(funcs);
    428     char* func = strtok(myFuncs, ",");
    429     while (func) {
    430         String8 fancyFunc = String8::format("\n%s\n", func);
    431         bool found = funcList.find(fancyFunc.string(), 0) >= 0;
    432         if (!found || func[0] == '\0') {
    433             fprintf(stderr, "error: \"%s\" is not a valid kernel function "
    434                 "to trace.\n", func);
    435             ok = false;
    436         }
    437         func = strtok(NULL, ",");
    438     }
    439     free(myFuncs);
    440 
    441     return ok;
    442 }
    443 
    444 // Set the comma separated list of functions that the kernel is to trace.
    445 static bool setKernelTraceFuncs(const char* funcs)
    446 {
    447     bool ok = true;
    448 
    449     if (funcs == NULL || funcs[0] == '\0') {
    450         // Disable kernel function tracing.
    451         if (fileIsWritable(k_currentTracerPath)) {
    452             ok &= writeStr(k_currentTracerPath, "nop");
    453         }
    454         if (fileIsWritable(k_ftraceFilterPath)) {
    455             ok &= truncateFile(k_ftraceFilterPath);
    456         }
    457     } else {
    458         // Enable kernel function tracing.
    459         ok &= writeStr(k_currentTracerPath, "function_graph");
    460         ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
    461         ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
    462         ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
    463         ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
    464 
    465         // Set the requested filter functions.
    466         ok &= truncateFile(k_ftraceFilterPath);
    467         char* myFuncs = strdup(funcs);
    468         char* func = strtok(myFuncs, ",");
    469         while (func) {
    470             ok &= appendStr(k_ftraceFilterPath, func);
    471             func = strtok(NULL, ",");
    472         }
    473         free(myFuncs);
    474 
    475         // Verify that the set functions are being traced.
    476         if (ok) {
    477             ok &= verifyKernelTraceFuncs(funcs);
    478         }
    479     }
    480 
    481     return ok;
    482 }
    483 
    484 // Set all the kernel tracing settings to the desired state for this trace
    485 // capture.
    486 static bool setUpTrace()
    487 {
    488     bool ok = true;
    489 
    490     // Set up the tracing options.
    491     ok &= setTraceOverwriteEnable(g_traceOverwrite);
    492     ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
    493     ok &= setGlobalClockEnable(true);
    494     ok &= setPrintTgidEnableIfPresent(true);
    495     ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
    496 
    497     // Set up the tags property.
    498     uint64_t tags = 0;
    499     for (int i = 0; i < NELEM(k_categories); i++) {
    500         if (g_categoryEnables[i]) {
    501             const TracingCategory &c = k_categories[i];
    502             tags |= c.tags;
    503         }
    504     }
    505     ok &= setTagsProperty(tags);
    506     ok &= setAppCmdlineProperty(g_debugAppCmdLine);
    507     ok &= pokeBinderServices();
    508 
    509     // Disable all the sysfs enables.  This is done as a separate loop from
    510     // the enables to allow the same enable to exist in multiple categories.
    511     ok &= disableKernelTraceEvents();
    512 
    513     // Enable all the sysfs enables that are in an enabled category.
    514     for (int i = 0; i < NELEM(k_categories); i++) {
    515         if (g_categoryEnables[i]) {
    516             const TracingCategory &c = k_categories[i];
    517             for (int j = 0; j < MAX_SYS_FILES; j++) {
    518                 const char* path = c.sysfiles[j].path;
    519                 bool required = c.sysfiles[j].required == REQ;
    520                 if (path != NULL) {
    521                     if (fileIsWritable(path)) {
    522                         ok &= setKernelOptionEnable(path, true);
    523                     } else if (required) {
    524                         fprintf(stderr, "error writing file %s\n", path);
    525                         ok = false;
    526                     }
    527                 }
    528             }
    529         }
    530     }
    531 
    532     return ok;
    533 }
    534 
    535 // Reset all the kernel tracing settings to their default state.
    536 static void cleanUpTrace()
    537 {
    538     // Disable all tracing that we're able to.
    539     disableKernelTraceEvents();
    540 
    541     // Reset the system properties.
    542     setTagsProperty(0);
    543     setAppCmdlineProperty("");
    544     pokeBinderServices();
    545 
    546     // Set the options back to their defaults.
    547     setTraceOverwriteEnable(true);
    548     setTraceBufferSizeKB(1);
    549     setGlobalClockEnable(false);
    550     setPrintTgidEnableIfPresent(false);
    551     setKernelTraceFuncs(NULL);
    552 }
    553 
    554 
    555 // Enable tracing in the kernel.
    556 static bool startTrace()
    557 {
    558     return setTracingEnabled(true);
    559 }
    560 
    561 // Disable tracing in the kernel.
    562 static void stopTrace()
    563 {
    564     setTracingEnabled(false);
    565 }
    566 
    567 // Read the current kernel trace and write it to stdout.
    568 static void dumpTrace()
    569 {
    570     int traceFD = open(k_tracePath, O_RDWR);
    571     if (traceFD == -1) {
    572         fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
    573                 strerror(errno), errno);
    574         return;
    575     }
    576 
    577     if (g_compress) {
    578         z_stream zs;
    579         uint8_t *in, *out;
    580         int result, flush;
    581 
    582         bzero(&zs, sizeof(zs));
    583         result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
    584         if (result != Z_OK) {
    585             fprintf(stderr, "error initializing zlib: %d\n", result);
    586             close(traceFD);
    587             return;
    588         }
    589 
    590         const size_t bufSize = 64*1024;
    591         in = (uint8_t*)malloc(bufSize);
    592         out = (uint8_t*)malloc(bufSize);
    593         flush = Z_NO_FLUSH;
    594 
    595         zs.next_out = out;
    596         zs.avail_out = bufSize;
    597 
    598         do {
    599 
    600             if (zs.avail_in == 0) {
    601                 // More input is needed.
    602                 result = read(traceFD, in, bufSize);
    603                 if (result < 0) {
    604                     fprintf(stderr, "error reading trace: %s (%d)\n",
    605                             strerror(errno), errno);
    606                     result = Z_STREAM_END;
    607                     break;
    608                 } else if (result == 0) {
    609                     flush = Z_FINISH;
    610                 } else {
    611                     zs.next_in = in;
    612                     zs.avail_in = result;
    613                 }
    614             }
    615 
    616             if (zs.avail_out == 0) {
    617                 // Need to write the output.
    618                 result = write(STDOUT_FILENO, out, bufSize);
    619                 if ((size_t)result < bufSize) {
    620                     fprintf(stderr, "error writing deflated trace: %s (%d)\n",
    621                             strerror(errno), errno);
    622                     result = Z_STREAM_END; // skip deflate error message
    623                     zs.avail_out = bufSize; // skip the final write
    624                     break;
    625                 }
    626                 zs.next_out = out;
    627                 zs.avail_out = bufSize;
    628             }
    629 
    630         } while ((result = deflate(&zs, flush)) == Z_OK);
    631 
    632         if (result != Z_STREAM_END) {
    633             fprintf(stderr, "error deflating trace: %s\n", zs.msg);
    634         }
    635 
    636         if (zs.avail_out < bufSize) {
    637             size_t bytes = bufSize - zs.avail_out;
    638             result = write(STDOUT_FILENO, out, bytes);
    639             if ((size_t)result < bytes) {
    640                 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
    641                         strerror(errno), errno);
    642             }
    643         }
    644 
    645         result = deflateEnd(&zs);
    646         if (result != Z_OK) {
    647             fprintf(stderr, "error cleaning up zlib: %d\n", result);
    648         }
    649 
    650         free(in);
    651         free(out);
    652     } else {
    653         ssize_t sent = 0;
    654         while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
    655         if (sent == -1) {
    656             fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
    657                     errno);
    658         }
    659     }
    660 
    661     close(traceFD);
    662 }
    663 
    664 static void handleSignal(int signo)
    665 {
    666     if (!g_nohup) {
    667         g_traceAborted = true;
    668     }
    669 }
    670 
    671 static void registerSigHandler()
    672 {
    673     struct sigaction sa;
    674     sigemptyset(&sa.sa_mask);
    675     sa.sa_flags = 0;
    676     sa.sa_handler = handleSignal;
    677     sigaction(SIGHUP, &sa, NULL);
    678     sigaction(SIGINT, &sa, NULL);
    679     sigaction(SIGQUIT, &sa, NULL);
    680     sigaction(SIGTERM, &sa, NULL);
    681 }
    682 
    683 static bool setCategoryEnable(const char* name, bool enable)
    684 {
    685     for (int i = 0; i < NELEM(k_categories); i++) {
    686         const TracingCategory& c = k_categories[i];
    687         if (strcmp(name, c.name) == 0) {
    688             if (isCategorySupported(c)) {
    689                 g_categoryEnables[i] = enable;
    690                 return true;
    691             } else {
    692                 if (isCategorySupportedForRoot(c)) {
    693                     fprintf(stderr, "error: category \"%s\" requires root "
    694                             "privileges.\n", name);
    695                 } else {
    696                     fprintf(stderr, "error: category \"%s\" is not supported "
    697                             "on this device.\n", name);
    698                 }
    699                 return false;
    700             }
    701         }
    702     }
    703     fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
    704     return false;
    705 }
    706 
    707 static void listSupportedCategories()
    708 {
    709     for (int i = 0; i < NELEM(k_categories); i++) {
    710         const TracingCategory& c = k_categories[i];
    711         if (isCategorySupported(c)) {
    712             printf("  %10s - %s\n", c.name, c.longname);
    713         }
    714     }
    715 }
    716 
    717 // Print the command usage help to stderr.
    718 static void showHelp(const char *cmd)
    719 {
    720     fprintf(stderr, "usage: %s [options] [categories...]\n", cmd);
    721     fprintf(stderr, "options include:\n"
    722                     "  -a appname      enable app-level tracing for a comma "
    723                         "separated list of cmdlines\n"
    724                     "  -b N            use a trace buffer size of N KB\n"
    725                     "  -c              trace into a circular buffer\n"
    726                     "  -k fname,...    trace the listed kernel functions\n"
    727                     "  -n              ignore signals\n"
    728                     "  -s N            sleep for N seconds before tracing [default 0]\n"
    729                     "  -t N            trace for N seconds [defualt 5]\n"
    730                     "  -z              compress the trace dump\n"
    731                     "  --async_start   start circular trace and return immediatly\n"
    732                     "  --async_dump    dump the current contents of circular trace buffer\n"
    733                     "  --async_stop    stop tracing and dump the current contents of circular\n"
    734                     "                    trace buffer\n"
    735                     "  --list_categories\n"
    736                     "                  list the available tracing categories\n"
    737             );
    738 }
    739 
    740 int main(int argc, char **argv)
    741 {
    742     bool async = false;
    743     bool traceStart = true;
    744     bool traceStop = true;
    745     bool traceDump = true;
    746 
    747     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
    748         showHelp(argv[0]);
    749         exit(0);
    750     }
    751 
    752     for (;;) {
    753         int ret;
    754         int option_index = 0;
    755         static struct option long_options[] = {
    756             {"async_start",     no_argument, 0,  0 },
    757             {"async_stop",      no_argument, 0,  0 },
    758             {"async_dump",      no_argument, 0,  0 },
    759             {"list_categories", no_argument, 0,  0 },
    760             {           0,                0, 0,  0 }
    761         };
    762 
    763         ret = getopt_long(argc, argv, "a:b:ck:ns:t:z",
    764                           long_options, &option_index);
    765 
    766         if (ret < 0) {
    767             for (int i = optind; i < argc; i++) {
    768                 if (!setCategoryEnable(argv[i], true)) {
    769                     fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
    770                     exit(1);
    771                 }
    772             }
    773             break;
    774         }
    775 
    776         switch(ret) {
    777             case 'a':
    778                 g_debugAppCmdLine = optarg;
    779             break;
    780 
    781             case 'b':
    782                 g_traceBufferSizeKB = atoi(optarg);
    783             break;
    784 
    785             case 'c':
    786                 g_traceOverwrite = true;
    787             break;
    788 
    789             case 'k':
    790                 g_kernelTraceFuncs = optarg;
    791             break;
    792 
    793             case 'n':
    794                 g_nohup = true;
    795             break;
    796 
    797             case 's':
    798                 g_initialSleepSecs = atoi(optarg);
    799             break;
    800 
    801             case 't':
    802                 g_traceDurationSeconds = atoi(optarg);
    803             break;
    804 
    805             case 'z':
    806                 g_compress = true;
    807             break;
    808 
    809             case 0:
    810                 if (!strcmp(long_options[option_index].name, "async_start")) {
    811                     async = true;
    812                     traceStop = false;
    813                     traceDump = false;
    814                     g_traceOverwrite = true;
    815                 } else if (!strcmp(long_options[option_index].name, "async_stop")) {
    816                     async = true;
    817                     traceStop = false;
    818                 } else if (!strcmp(long_options[option_index].name, "async_dump")) {
    819                     async = true;
    820                     traceStart = false;
    821                     traceStop = false;
    822                 } else if (!strcmp(long_options[option_index].name, "list_categories")) {
    823                     listSupportedCategories();
    824                     exit(0);
    825                 }
    826             break;
    827 
    828             default:
    829                 fprintf(stderr, "\n");
    830                 showHelp(argv[0]);
    831                 exit(-1);
    832             break;
    833         }
    834     }
    835 
    836     registerSigHandler();
    837 
    838     if (g_initialSleepSecs > 0) {
    839         sleep(g_initialSleepSecs);
    840     }
    841 
    842     bool ok = true;
    843     ok &= setUpTrace();
    844     ok &= startTrace();
    845 
    846     if (ok && traceStart) {
    847         printf("capturing trace...");
    848         fflush(stdout);
    849 
    850         // We clear the trace after starting it because tracing gets enabled for
    851         // each CPU individually in the kernel. Having the beginning of the trace
    852         // contain entries from only one CPU can cause "begin" entries without a
    853         // matching "end" entry to show up if a task gets migrated from one CPU to
    854         // another.
    855         ok = clearTrace();
    856 
    857         if (ok && !async) {
    858             // Sleep to allow the trace to be captured.
    859             struct timespec timeLeft;
    860             timeLeft.tv_sec = g_traceDurationSeconds;
    861             timeLeft.tv_nsec = 0;
    862             do {
    863                 if (g_traceAborted) {
    864                     break;
    865                 }
    866             } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
    867         }
    868     }
    869 
    870     // Stop the trace and restore the default settings.
    871     if (traceStop)
    872         stopTrace();
    873 
    874     if (ok && traceDump) {
    875         if (!g_traceAborted) {
    876             printf(" done\nTRACE:\n");
    877             fflush(stdout);
    878             dumpTrace();
    879         } else {
    880             printf("\ntrace aborted.\n");
    881             fflush(stdout);
    882         }
    883         clearTrace();
    884     } else if (!ok) {
    885         fprintf(stderr, "unable to start tracing\n");
    886     }
    887 
    888     // Reset the trace buffer size to 1.
    889     if (traceStop)
    890         cleanUpTrace();
    891 
    892     return g_traceAborted ? 1 : 0;
    893 }
    894