blob: e90baf6e97ba9f847a6c2f444908ddd62a614750 [file] [log] [blame]
Jamie Gennis6eea6fb2012-12-07 14:03:07 -08001/*
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>
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -070020#include <inttypes.h>
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080021#include <signal.h>
22#include <stdarg.h>
23#include <stdbool.h>
24#include <stdio.h>
25#include <stdlib.h>
Elliott Hughes3da5d232015-01-25 08:35:20 -080026#include <string.h>
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080027#include <sys/sendfile.h>
28#include <time.h>
29#include <zlib.h>
30
31#include <binder/IBinder.h>
32#include <binder/IServiceManager.h>
33#include <binder/Parcel.h>
34
35#include <cutils/properties.h>
36
37#include <utils/String8.h>
38#include <utils/Trace.h>
39
40using namespace android;
41
42#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
43
Mohamad Ayyash26dbcbe2014-04-08 15:24:11 -070044enum { MAX_SYS_FILES = 10 };
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080045
46const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
Jamie Gennisf7f29c82013-03-27 15:50:58 -070047const char* k_traceAppCmdlineProperty = "debug.atrace.app_cmdlines";
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080048
49typedef enum { OPT, REQ } requiredness ;
50
51struct TracingCategory {
52 // The name identifying the category.
53 const char* name;
54
55 // A longer description of the category.
56 const char* longname;
57
58 // The userland tracing tags that the category enables.
59 uint64_t tags;
60
61 // The fname==NULL terminated list of /sys/ files that the category
62 // enables.
63 struct {
64 // Whether the file must be writable in order to enable the tracing
65 // category.
66 requiredness required;
67
68 // The path to the enable file.
69 const char* path;
70 } sysfiles[MAX_SYS_FILES];
71};
72
73/* Tracing categories */
74static const TracingCategory k_categories[] = {
Jamie Gennisb2a89e32013-03-11 19:37:53 -070075 { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { } },
76 { "input", "Input", ATRACE_TAG_INPUT, { } },
77 { "view", "View System", ATRACE_TAG_VIEW, { } },
78 { "webview", "WebView", ATRACE_TAG_WEBVIEW, { } },
79 { "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } },
80 { "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
Jeff Brown3200b0b2014-08-14 19:24:47 -070081 { "sync", "Sync Manager", ATRACE_TAG_SYNC_MANAGER, { } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -070082 { "audio", "Audio", ATRACE_TAG_AUDIO, { } },
83 { "video", "Video", ATRACE_TAG_VIDEO, { } },
84 { "camera", "Camera", ATRACE_TAG_CAMERA, { } },
85 { "hal", "Hardware Modules", ATRACE_TAG_HAL, { } },
Jeff Brown3200b0b2014-08-14 19:24:47 -070086 { "app", "Application", ATRACE_TAG_APP, { } },
Dianne Hackborn9380d782013-04-12 14:52:35 -070087 { "res", "Resource Loading", ATRACE_TAG_RESOURCES, { } },
Jamie Genniseff2e8d2013-05-07 15:20:39 -070088 { "dalvik", "Dalvik VM", ATRACE_TAG_DALVIK, { } },
Tim Murrayf0f28412013-05-23 14:39:42 -070089 { "rs", "RenderScript", ATRACE_TAG_RS, { } },
Brigid Smith750aa972014-05-28 14:23:24 -070090 { "bionic", "Bionic C Library", ATRACE_TAG_BIONIC, { } },
Jeff Brown3200b0b2014-08-14 19:24:47 -070091 { "power", "Power Management", ATRACE_TAG_POWER, { } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -070092 { "sched", "CPU Scheduling", 0, {
93 { REQ, "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
94 { REQ, "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -080095 } },
Dan Willemsenf440d392014-04-11 15:44:09 -070096 { "irq", "IRQ Events", 0, {
97 { REQ, "/sys/kernel/debug/tracing/events/irq/enable" },
98 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -070099 { "freq", "CPU Frequency", 0, {
100 { REQ, "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
101 { OPT, "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800102 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700103 { "membus", "Memory Bus Utilization", 0, {
104 { REQ, "/sys/kernel/debug/tracing/events/memory_bus/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800105 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700106 { "idle", "CPU Idle", 0, {
107 { REQ, "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800108 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700109 { "disk", "Disk I/O", 0, {
Mohamad Ayyash26dbcbe2014-04-08 15:24:11 -0700110 { REQ, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable" },
111 { REQ, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable" },
112 { REQ, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable" },
113 { REQ, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable" },
114 { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable" },
115 { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable" },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700116 { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
117 { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
118 { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
119 { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800120 } },
Ken Sumralld3fa5612013-07-03 12:32:03 -0700121 { "mmc", "eMMC commands", 0, {
122 { REQ, "/sys/kernel/debug/tracing/events/mmc/enable" },
123 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700124 { "load", "CPU Load", 0, {
125 { REQ, "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800126 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700127 { "sync", "Synchronization", 0, {
128 { REQ, "/sys/kernel/debug/tracing/events/sync/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800129 } },
Jamie Gennisb2a89e32013-03-11 19:37:53 -0700130 { "workq", "Kernel Workqueues", 0, {
131 { REQ, "/sys/kernel/debug/tracing/events/workqueue/enable" },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800132 } },
Colin Cross580407f2014-08-18 15:22:13 -0700133 { "memreclaim", "Kernel Memory Reclaim", 0, {
134 { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
135 { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
136 { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" },
137 { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" },
138 } },
Aaron Schulmanc2c6ecd2015-02-25 08:37:09 -0800139 { "regulators", "Voltage and Current Regulators", 0, {
140 { REQ, "/sys/kernel/debug/tracing/events/regulator/enable" },
141 } },
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800142};
143
144/* Command line options */
145static int g_traceDurationSeconds = 5;
146static bool g_traceOverwrite = false;
147static int g_traceBufferSizeKB = 2048;
148static bool g_compress = false;
149static bool g_nohup = false;
150static int g_initialSleepSecs = 0;
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700151static const char* g_kernelTraceFuncs = NULL;
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700152static const char* g_debugAppCmdLine = "";
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800153
154/* Global state */
155static bool g_traceAborted = false;
156static bool g_categoryEnables[NELEM(k_categories)] = {};
157
158/* Sys file paths */
159static const char* k_traceClockPath =
160 "/sys/kernel/debug/tracing/trace_clock";
161
162static const char* k_traceBufferSizePath =
163 "/sys/kernel/debug/tracing/buffer_size_kb";
164
165static const char* k_tracingOverwriteEnablePath =
166 "/sys/kernel/debug/tracing/options/overwrite";
167
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700168static const char* k_currentTracerPath =
169 "/sys/kernel/debug/tracing/current_tracer";
170
171static const char* k_printTgidPath =
172 "/sys/kernel/debug/tracing/options/print-tgid";
173
174static const char* k_funcgraphAbsTimePath =
175 "/sys/kernel/debug/tracing/options/funcgraph-abstime";
176
177static const char* k_funcgraphCpuPath =
178 "/sys/kernel/debug/tracing/options/funcgraph-cpu";
179
180static const char* k_funcgraphProcPath =
181 "/sys/kernel/debug/tracing/options/funcgraph-proc";
182
183static const char* k_funcgraphFlatPath =
184 "/sys/kernel/debug/tracing/options/funcgraph-flat";
185
186static const char* k_funcgraphDurationPath =
187 "/sys/kernel/debug/tracing/options/funcgraph-duration";
188
189static const char* k_ftraceFilterPath =
190 "/sys/kernel/debug/tracing/set_ftrace_filter";
191
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800192static const char* k_tracingOnPath =
193 "/sys/kernel/debug/tracing/tracing_on";
194
195static const char* k_tracePath =
196 "/sys/kernel/debug/tracing/trace";
197
198// Check whether a file exists.
199static bool fileExists(const char* filename) {
200 return access(filename, F_OK) != -1;
201}
202
203// Check whether a file is writable.
204static bool fileIsWritable(const char* filename) {
205 return access(filename, W_OK) != -1;
206}
207
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700208// Truncate a file.
209static bool truncateFile(const char* path)
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800210{
Jamie Gennis43122e72013-03-21 14:06:31 -0700211 // This uses creat rather than truncate because some of the debug kernel
212 // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
213 // calls to truncate, but they are cleared by calls to creat.
214 int traceFD = creat(path, 0);
215 if (traceFD == -1) {
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700216 fprintf(stderr, "error truncating %s: %s (%d)\n", path,
Jamie Gennis43122e72013-03-21 14:06:31 -0700217 strerror(errno), errno);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700218 return false;
219 }
220
Jamie Gennis43122e72013-03-21 14:06:31 -0700221 close(traceFD);
222
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700223 return true;
224}
225
226static bool _writeStr(const char* filename, const char* str, int flags)
227{
228 int fd = open(filename, flags);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800229 if (fd == -1) {
230 fprintf(stderr, "error opening %s: %s (%d)\n", filename,
231 strerror(errno), errno);
232 return false;
233 }
234
235 bool ok = true;
236 ssize_t len = strlen(str);
237 if (write(fd, str, len) != len) {
238 fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
239 strerror(errno), errno);
240 ok = false;
241 }
242
243 close(fd);
244
245 return ok;
246}
247
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700248// Write a string to a file, returning true if the write was successful.
249static bool writeStr(const char* filename, const char* str)
250{
251 return _writeStr(filename, str, O_WRONLY);
252}
253
254// Append a string to a file, returning true if the write was successful.
255static bool appendStr(const char* filename, const char* str)
256{
257 return _writeStr(filename, str, O_APPEND|O_WRONLY);
258}
259
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800260// Enable or disable a kernel option by writing a "1" or a "0" into a /sys
261// file.
262static bool setKernelOptionEnable(const char* filename, bool enable)
263{
264 return writeStr(filename, enable ? "1" : "0");
265}
266
267// Check whether the category is supported on the device with the current
268// rootness. A category is supported only if all its required /sys/ files are
269// writable and if enabling the category will enable one or more tracing tags
270// or /sys/ files.
271static bool isCategorySupported(const TracingCategory& category)
272{
273 bool ok = category.tags != 0;
274 for (int i = 0; i < MAX_SYS_FILES; i++) {
275 const char* path = category.sysfiles[i].path;
276 bool req = category.sysfiles[i].required == REQ;
277 if (path != NULL) {
278 if (req) {
279 if (!fileIsWritable(path)) {
280 return false;
281 } else {
282 ok = true;
283 }
284 } else {
285 ok |= fileIsWritable(path);
286 }
287 }
288 }
289 return ok;
290}
291
292// Check whether the category would be supported on the device if the user
293// were root. This function assumes that root is able to write to any file
294// that exists. It performs the same logic as isCategorySupported, but it
295// uses file existance rather than writability in the /sys/ file checks.
296static bool isCategorySupportedForRoot(const TracingCategory& category)
297{
298 bool ok = category.tags != 0;
299 for (int i = 0; i < MAX_SYS_FILES; i++) {
300 const char* path = category.sysfiles[i].path;
301 bool req = category.sysfiles[i].required == REQ;
302 if (path != NULL) {
303 if (req) {
304 if (!fileExists(path)) {
305 return false;
306 } else {
307 ok = true;
308 }
309 } else {
310 ok |= fileExists(path);
311 }
312 }
313 }
314 return ok;
315}
316
317// Enable or disable overwriting of the kernel trace buffers. Disabling this
318// will cause tracing to stop once the trace buffers have filled up.
319static bool setTraceOverwriteEnable(bool enable)
320{
321 return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
322}
323
324// Enable or disable kernel tracing.
325static bool setTracingEnabled(bool enable)
326{
327 return setKernelOptionEnable(k_tracingOnPath, enable);
328}
329
330// Clear the contents of the kernel trace.
331static bool clearTrace()
332{
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700333 return truncateFile(k_tracePath);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800334}
335
336// Set the size of the kernel's trace buffer in kilobytes.
337static bool setTraceBufferSizeKB(int size)
338{
339 char str[32] = "1";
340 int len;
341 if (size < 1) {
342 size = 1;
343 }
344 snprintf(str, 32, "%d", size);
345 return writeStr(k_traceBufferSizePath, str);
346}
347
Colin Crossb1ce49b2014-08-20 14:28:47 -0700348// Read the trace_clock sysfs file and return true if it matches the requested
349// value. The trace_clock file format is:
350// local [global] counter uptime perf
351static bool isTraceClock(const char *mode)
352{
353 int fd = open(k_traceClockPath, O_RDONLY);
354 if (fd == -1) {
355 fprintf(stderr, "error opening %s: %s (%d)\n", k_traceClockPath,
356 strerror(errno), errno);
357 return false;
358 }
359
360 char buf[4097];
361 ssize_t n = read(fd, buf, 4096);
362 close(fd);
363 if (n == -1) {
364 fprintf(stderr, "error reading %s: %s (%d)\n", k_traceClockPath,
365 strerror(errno), errno);
366 return false;
367 }
368 buf[n] = '\0';
369
370 char *start = strchr(buf, '[');
371 if (start == NULL) {
372 return false;
373 }
374 start++;
375
376 char *end = strchr(start, ']');
377 if (end == NULL) {
378 return false;
379 }
380 *end = '\0';
381
382 return strcmp(mode, start) == 0;
383}
384
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800385// Enable or disable the kernel's use of the global clock. Disabling the global
386// clock will result in the kernel using a per-CPU local clock.
Colin Crossb1ce49b2014-08-20 14:28:47 -0700387// Any write to the trace_clock sysfs file will reset the buffer, so only
388// update it if the requested value is not the current value.
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800389static bool setGlobalClockEnable(bool enable)
390{
Colin Crossb1ce49b2014-08-20 14:28:47 -0700391 const char *clock = enable ? "global" : "local";
392
393 if (isTraceClock(clock)) {
394 return true;
395 }
396
397 return writeStr(k_traceClockPath, clock);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800398}
399
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700400static bool setPrintTgidEnableIfPresent(bool enable)
401{
402 if (fileExists(k_printTgidPath)) {
403 return setKernelOptionEnable(k_printTgidPath, enable);
404 }
405 return true;
406}
407
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800408// Poke all the binder-enabled processes in the system to get them to re-read
409// their system properties.
410static bool pokeBinderServices()
411{
412 sp<IServiceManager> sm = defaultServiceManager();
413 Vector<String16> services = sm->listServices();
414 for (size_t i = 0; i < services.size(); i++) {
415 sp<IBinder> obj = sm->checkService(services[i]);
416 if (obj != NULL) {
417 Parcel data;
418 if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
419 NULL, 0) != OK) {
420 if (false) {
421 // XXX: For some reason this fails on tablets trying to
422 // poke the "phone" service. It's not clear whether some
423 // are expected to fail.
424 String8 svc(services[i]);
425 fprintf(stderr, "error poking binder service %s\n",
426 svc.string());
427 return false;
428 }
429 }
430 }
431 }
432 return true;
433}
434
435// Set the trace tags that userland tracing uses, and poke the running
436// processes to pick up the new value.
437static bool setTagsProperty(uint64_t tags)
438{
439 char buf[64];
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700440 snprintf(buf, 64, "%#" PRIx64, tags);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800441 if (property_set(k_traceTagsProperty, buf) < 0) {
442 fprintf(stderr, "error setting trace tags system property\n");
443 return false;
444 }
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700445 return true;
446}
447
448// Set the system property that indicates which apps should perform
449// application-level tracing.
450static bool setAppCmdlineProperty(const char* cmdline)
451{
452 if (property_set(k_traceAppCmdlineProperty, cmdline) < 0) {
453 fprintf(stderr, "error setting trace app system property\n");
454 return false;
455 }
456 return true;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800457}
458
459// Disable all /sys/ enable files.
460static bool disableKernelTraceEvents() {
461 bool ok = true;
462 for (int i = 0; i < NELEM(k_categories); i++) {
463 const TracingCategory &c = k_categories[i];
464 for (int j = 0; j < MAX_SYS_FILES; j++) {
465 const char* path = c.sysfiles[j].path;
466 if (path != NULL && fileIsWritable(path)) {
467 ok &= setKernelOptionEnable(path, false);
468 }
469 }
470 }
471 return ok;
472}
473
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700474// Verify that the comma separated list of functions are being traced by the
475// kernel.
476static bool verifyKernelTraceFuncs(const char* funcs)
477{
478 int fd = open(k_ftraceFilterPath, O_RDONLY);
479 if (fd == -1) {
480 fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
481 strerror(errno), errno);
482 return false;
483 }
484
485 char buf[4097];
486 ssize_t n = read(fd, buf, 4096);
487 close(fd);
488 if (n == -1) {
489 fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath,
490 strerror(errno), errno);
491 return false;
492 }
493
494 buf[n] = '\0';
495 String8 funcList = String8::format("\n%s", buf);
496
497 // Make sure that every function listed in funcs is in the list we just
498 // read from the kernel.
499 bool ok = true;
500 char* myFuncs = strdup(funcs);
501 char* func = strtok(myFuncs, ",");
502 while (func) {
503 String8 fancyFunc = String8::format("\n%s\n", func);
504 bool found = funcList.find(fancyFunc.string(), 0) >= 0;
505 if (!found || func[0] == '\0') {
506 fprintf(stderr, "error: \"%s\" is not a valid kernel function "
507 "to trace.\n", func);
508 ok = false;
509 }
510 func = strtok(NULL, ",");
511 }
512 free(myFuncs);
513
514 return ok;
515}
516
517// Set the comma separated list of functions that the kernel is to trace.
518static bool setKernelTraceFuncs(const char* funcs)
519{
520 bool ok = true;
521
522 if (funcs == NULL || funcs[0] == '\0') {
523 // Disable kernel function tracing.
Jamie Gennis6f6f3f72013-03-27 15:50:30 -0700524 if (fileIsWritable(k_currentTracerPath)) {
525 ok &= writeStr(k_currentTracerPath, "nop");
526 }
527 if (fileIsWritable(k_ftraceFilterPath)) {
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700528 ok &= truncateFile(k_ftraceFilterPath);
529 }
530 } else {
531 // Enable kernel function tracing.
532 ok &= writeStr(k_currentTracerPath, "function_graph");
533 ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
534 ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
535 ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
536 ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
537
538 // Set the requested filter functions.
539 ok &= truncateFile(k_ftraceFilterPath);
540 char* myFuncs = strdup(funcs);
541 char* func = strtok(myFuncs, ",");
542 while (func) {
543 ok &= appendStr(k_ftraceFilterPath, func);
544 func = strtok(NULL, ",");
545 }
546 free(myFuncs);
547
548 // Verify that the set functions are being traced.
549 if (ok) {
550 ok &= verifyKernelTraceFuncs(funcs);
551 }
552 }
553
554 return ok;
555}
556
557// Set all the kernel tracing settings to the desired state for this trace
558// capture.
559static bool setUpTrace()
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800560{
561 bool ok = true;
562
563 // Set up the tracing options.
564 ok &= setTraceOverwriteEnable(g_traceOverwrite);
565 ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
566 ok &= setGlobalClockEnable(true);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700567 ok &= setPrintTgidEnableIfPresent(true);
568 ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800569
570 // Set up the tags property.
571 uint64_t tags = 0;
572 for (int i = 0; i < NELEM(k_categories); i++) {
573 if (g_categoryEnables[i]) {
574 const TracingCategory &c = k_categories[i];
575 tags |= c.tags;
576 }
577 }
578 ok &= setTagsProperty(tags);
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700579 ok &= setAppCmdlineProperty(g_debugAppCmdLine);
580 ok &= pokeBinderServices();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800581
582 // Disable all the sysfs enables. This is done as a separate loop from
583 // the enables to allow the same enable to exist in multiple categories.
584 ok &= disableKernelTraceEvents();
585
586 // Enable all the sysfs enables that are in an enabled category.
587 for (int i = 0; i < NELEM(k_categories); i++) {
588 if (g_categoryEnables[i]) {
589 const TracingCategory &c = k_categories[i];
590 for (int j = 0; j < MAX_SYS_FILES; j++) {
591 const char* path = c.sysfiles[j].path;
592 bool required = c.sysfiles[j].required == REQ;
593 if (path != NULL) {
594 if (fileIsWritable(path)) {
595 ok &= setKernelOptionEnable(path, true);
596 } else if (required) {
597 fprintf(stderr, "error writing file %s\n", path);
598 ok = false;
599 }
600 }
601 }
602 }
603 }
604
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800605 return ok;
606}
607
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700608// Reset all the kernel tracing settings to their default state.
609static void cleanUpTrace()
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800610{
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800611 // Disable all tracing that we're able to.
612 disableKernelTraceEvents();
613
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700614 // Reset the system properties.
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800615 setTagsProperty(0);
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700616 setAppCmdlineProperty("");
617 pokeBinderServices();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800618
619 // Set the options back to their defaults.
620 setTraceOverwriteEnable(true);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700621 setTraceBufferSizeKB(1);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800622 setGlobalClockEnable(false);
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700623 setPrintTgidEnableIfPresent(false);
624 setKernelTraceFuncs(NULL);
625}
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800626
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700627
628// Enable tracing in the kernel.
629static bool startTrace()
630{
631 return setTracingEnabled(true);
632}
633
634// Disable tracing in the kernel.
635static void stopTrace()
636{
637 setTracingEnabled(false);
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800638}
639
640// Read the current kernel trace and write it to stdout.
641static void dumpTrace()
642{
643 int traceFD = open(k_tracePath, O_RDWR);
644 if (traceFD == -1) {
645 fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
646 strerror(errno), errno);
647 return;
648 }
649
650 if (g_compress) {
651 z_stream zs;
652 uint8_t *in, *out;
653 int result, flush;
654
Elliott Hughes3da5d232015-01-25 08:35:20 -0800655 memset(&zs, 0, sizeof(zs));
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800656 result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
657 if (result != Z_OK) {
658 fprintf(stderr, "error initializing zlib: %d\n", result);
659 close(traceFD);
660 return;
661 }
662
663 const size_t bufSize = 64*1024;
664 in = (uint8_t*)malloc(bufSize);
665 out = (uint8_t*)malloc(bufSize);
666 flush = Z_NO_FLUSH;
667
668 zs.next_out = out;
669 zs.avail_out = bufSize;
670
671 do {
672
673 if (zs.avail_in == 0) {
674 // More input is needed.
675 result = read(traceFD, in, bufSize);
676 if (result < 0) {
677 fprintf(stderr, "error reading trace: %s (%d)\n",
678 strerror(errno), errno);
679 result = Z_STREAM_END;
680 break;
681 } else if (result == 0) {
682 flush = Z_FINISH;
683 } else {
684 zs.next_in = in;
685 zs.avail_in = result;
686 }
687 }
688
689 if (zs.avail_out == 0) {
690 // Need to write the output.
691 result = write(STDOUT_FILENO, out, bufSize);
692 if ((size_t)result < bufSize) {
693 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
694 strerror(errno), errno);
695 result = Z_STREAM_END; // skip deflate error message
696 zs.avail_out = bufSize; // skip the final write
697 break;
698 }
699 zs.next_out = out;
700 zs.avail_out = bufSize;
701 }
702
703 } while ((result = deflate(&zs, flush)) == Z_OK);
704
705 if (result != Z_STREAM_END) {
706 fprintf(stderr, "error deflating trace: %s\n", zs.msg);
707 }
708
709 if (zs.avail_out < bufSize) {
710 size_t bytes = bufSize - zs.avail_out;
711 result = write(STDOUT_FILENO, out, bytes);
712 if ((size_t)result < bytes) {
713 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
714 strerror(errno), errno);
715 }
716 }
717
718 result = deflateEnd(&zs);
719 if (result != Z_OK) {
720 fprintf(stderr, "error cleaning up zlib: %d\n", result);
721 }
722
723 free(in);
724 free(out);
725 } else {
726 ssize_t sent = 0;
727 while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
728 if (sent == -1) {
729 fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
730 errno);
731 }
732 }
733
734 close(traceFD);
735}
736
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700737static void handleSignal(int /*signo*/)
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800738{
739 if (!g_nohup) {
740 g_traceAborted = true;
741 }
742}
743
744static void registerSigHandler()
745{
746 struct sigaction sa;
747 sigemptyset(&sa.sa_mask);
748 sa.sa_flags = 0;
749 sa.sa_handler = handleSignal;
750 sigaction(SIGHUP, &sa, NULL);
751 sigaction(SIGINT, &sa, NULL);
752 sigaction(SIGQUIT, &sa, NULL);
753 sigaction(SIGTERM, &sa, NULL);
754}
755
756static bool setCategoryEnable(const char* name, bool enable)
757{
758 for (int i = 0; i < NELEM(k_categories); i++) {
759 const TracingCategory& c = k_categories[i];
760 if (strcmp(name, c.name) == 0) {
761 if (isCategorySupported(c)) {
762 g_categoryEnables[i] = enable;
763 return true;
764 } else {
765 if (isCategorySupportedForRoot(c)) {
766 fprintf(stderr, "error: category \"%s\" requires root "
767 "privileges.\n", name);
768 } else {
769 fprintf(stderr, "error: category \"%s\" is not supported "
770 "on this device.\n", name);
771 }
772 return false;
773 }
774 }
775 }
776 fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
777 return false;
778}
779
780static void listSupportedCategories()
781{
782 for (int i = 0; i < NELEM(k_categories); i++) {
783 const TracingCategory& c = k_categories[i];
784 if (isCategorySupported(c)) {
785 printf(" %10s - %s\n", c.name, c.longname);
786 }
787 }
788}
789
790// Print the command usage help to stderr.
791static void showHelp(const char *cmd)
792{
793 fprintf(stderr, "usage: %s [options] [categories...]\n", cmd);
794 fprintf(stderr, "options include:\n"
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700795 " -a appname enable app-level tracing for a comma "
796 "separated list of cmdlines\n"
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800797 " -b N use a trace buffer size of N KB\n"
798 " -c trace into a circular buffer\n"
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700799 " -k fname,... trace the listed kernel functions\n"
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800800 " -n ignore signals\n"
801 " -s N sleep for N seconds before tracing [default 0]\n"
802 " -t N trace for N seconds [defualt 5]\n"
803 " -z compress the trace dump\n"
804 " --async_start start circular trace and return immediatly\n"
805 " --async_dump dump the current contents of circular trace buffer\n"
806 " --async_stop stop tracing and dump the current contents of circular\n"
807 " trace buffer\n"
Jamie Gennis92573f12012-12-07 16:29:03 -0800808 " --list_categories\n"
809 " list the available tracing categories\n"
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800810 );
811}
812
813int main(int argc, char **argv)
814{
815 bool async = false;
816 bool traceStart = true;
817 bool traceStop = true;
818 bool traceDump = true;
819
820 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
821 showHelp(argv[0]);
822 exit(0);
823 }
824
825 for (;;) {
826 int ret;
827 int option_index = 0;
828 static struct option long_options[] = {
829 {"async_start", no_argument, 0, 0 },
830 {"async_stop", no_argument, 0, 0 },
831 {"async_dump", no_argument, 0, 0 },
832 {"list_categories", no_argument, 0, 0 },
833 { 0, 0, 0, 0 }
834 };
835
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700836 ret = getopt_long(argc, argv, "a:b:ck:ns:t:z",
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800837 long_options, &option_index);
838
839 if (ret < 0) {
840 for (int i = optind; i < argc; i++) {
841 if (!setCategoryEnable(argv[i], true)) {
842 fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
843 exit(1);
844 }
845 }
846 break;
847 }
848
849 switch(ret) {
Jamie Gennisf7f29c82013-03-27 15:50:58 -0700850 case 'a':
851 g_debugAppCmdLine = optarg;
852 break;
853
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800854 case 'b':
855 g_traceBufferSizeKB = atoi(optarg);
856 break;
857
858 case 'c':
859 g_traceOverwrite = true;
860 break;
861
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700862 case 'k':
863 g_kernelTraceFuncs = optarg;
Jamie Gennis6f6f3f72013-03-27 15:50:30 -0700864 break;
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700865
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800866 case 'n':
867 g_nohup = true;
Jamie Gennis6f6f3f72013-03-27 15:50:30 -0700868 break;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800869
870 case 's':
871 g_initialSleepSecs = atoi(optarg);
872 break;
873
874 case 't':
875 g_traceDurationSeconds = atoi(optarg);
876 break;
877
878 case 'z':
879 g_compress = true;
880 break;
881
882 case 0:
883 if (!strcmp(long_options[option_index].name, "async_start")) {
884 async = true;
885 traceStop = false;
886 traceDump = false;
887 g_traceOverwrite = true;
888 } else if (!strcmp(long_options[option_index].name, "async_stop")) {
889 async = true;
890 traceStop = false;
891 } else if (!strcmp(long_options[option_index].name, "async_dump")) {
892 async = true;
893 traceStart = false;
894 traceStop = false;
895 } else if (!strcmp(long_options[option_index].name, "list_categories")) {
896 listSupportedCategories();
897 exit(0);
898 }
Jamie Gennis6f6f3f72013-03-27 15:50:30 -0700899 break;
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800900
901 default:
902 fprintf(stderr, "\n");
903 showHelp(argv[0]);
904 exit(-1);
905 break;
906 }
907 }
908
909 registerSigHandler();
910
911 if (g_initialSleepSecs > 0) {
912 sleep(g_initialSleepSecs);
913 }
914
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700915 bool ok = true;
916 ok &= setUpTrace();
917 ok &= startTrace();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800918
919 if (ok && traceStart) {
920 printf("capturing trace...");
921 fflush(stdout);
922
923 // We clear the trace after starting it because tracing gets enabled for
924 // each CPU individually in the kernel. Having the beginning of the trace
925 // contain entries from only one CPU can cause "begin" entries without a
926 // matching "end" entry to show up if a task gets migrated from one CPU to
927 // another.
928 ok = clearTrace();
929
930 if (ok && !async) {
931 // Sleep to allow the trace to be captured.
932 struct timespec timeLeft;
933 timeLeft.tv_sec = g_traceDurationSeconds;
934 timeLeft.tv_nsec = 0;
935 do {
936 if (g_traceAborted) {
937 break;
938 }
939 } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
940 }
941 }
942
943 // Stop the trace and restore the default settings.
944 if (traceStop)
945 stopTrace();
946
947 if (ok && traceDump) {
948 if (!g_traceAborted) {
949 printf(" done\nTRACE:\n");
950 fflush(stdout);
951 dumpTrace();
952 } else {
953 printf("\ntrace aborted.\n");
954 fflush(stdout);
955 }
956 clearTrace();
957 } else if (!ok) {
958 fprintf(stderr, "unable to start tracing\n");
959 }
960
961 // Reset the trace buffer size to 1.
962 if (traceStop)
Jamie Gennise9b8cfb2013-03-12 16:00:10 -0700963 cleanUpTrace();
Jamie Gennis6eea6fb2012-12-07 14:03:07 -0800964
965 return g_traceAborted ? 1 : 0;
966}