• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
fileExists(const char * filename)175 static bool fileExists(const char* filename) {
176     return access(filename, F_OK) != -1;
177 }
178 
179 // Check whether a file is writable.
fileIsWritable(const char * filename)180 static bool fileIsWritable(const char* filename) {
181     return access(filename, W_OK) != -1;
182 }
183 
184 // Truncate a file.
truncateFile(const char * path)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 
_writeStr(const char * filename,const char * str,int flags)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.
writeStr(const char * filename,const char * str)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.
appendStr(const char * filename,const char * str)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.
setKernelOptionEnable(const char * filename,bool enable)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.
isCategorySupported(const TracingCategory & category)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.
isCategorySupportedForRoot(const TracingCategory & category)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.
setTraceOverwriteEnable(bool enable)295 static bool setTraceOverwriteEnable(bool enable)
296 {
297     return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
298 }
299 
300 // Enable or disable kernel tracing.
setTracingEnabled(bool enable)301 static bool setTracingEnabled(bool enable)
302 {
303     return setKernelOptionEnable(k_tracingOnPath, enable);
304 }
305 
306 // Clear the contents of the kernel trace.
clearTrace()307 static bool clearTrace()
308 {
309     return truncateFile(k_tracePath);
310 }
311 
312 // Set the size of the kernel's trace buffer in kilobytes.
setTraceBufferSizeKB(int size)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.
setGlobalClockEnable(bool enable)326 static bool setGlobalClockEnable(bool enable)
327 {
328     return writeStr(k_traceClockPath, enable ? "global" : "local");
329 }
330 
setPrintTgidEnableIfPresent(bool enable)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.
pokeBinderServices()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.
setTagsProperty(uint64_t tags)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.
setAppCmdlineProperty(const char * cmdline)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.
disableKernelTraceEvents()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.
verifyKernelTraceFuncs(const char * funcs)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.
setKernelTraceFuncs(const char * funcs)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.
setUpTrace()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.
cleanUpTrace()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.
startTrace()560 static bool startTrace()
561 {
562     return setTracingEnabled(true);
563 }
564 
565 // Disable tracing in the kernel.
stopTrace()566 static void stopTrace()
567 {
568     setTracingEnabled(false);
569 }
570 
571 // Read the current kernel trace and write it to stdout.
dumpTrace()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 
handleSignal(int signo)668 static void handleSignal(int signo)
669 {
670     if (!g_nohup) {
671         g_traceAborted = true;
672     }
673 }
674 
registerSigHandler()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 
setCategoryEnable(const char * name,bool enable)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 
listSupportedCategories()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.
showHelp(const char * cmd)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 
main(int argc,char ** argv)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