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