• 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  #define LOG_TAG "atrace"
18 
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <getopt.h>
22 #include <inttypes.h>
23 #include <signal.h>
24 #include <stdarg.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/sendfile.h>
30 #include <time.h>
31 #include <unistd.h>
32 #include <zlib.h>
33 
34 #include <binder/IBinder.h>
35 #include <binder/IServiceManager.h>
36 #include <binder/Parcel.h>
37 
38 #include <cutils/properties.h>
39 
40 #include <utils/String8.h>
41 #include <utils/Timers.h>
42 #include <utils/Tokenizer.h>
43 #include <utils/Trace.h>
44 
45 using namespace android;
46 
47 #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
48 
49 #define MAX_SYS_FILES 10
50 #define MAX_PACKAGES 16
51 
52 const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
53 
54 const char* k_traceAppsNumberProperty = "debug.atrace.app_number";
55 const char* k_traceAppsPropertyTemplate = "debug.atrace.app_%d";
56 const char* k_coreServiceCategory = "core_services";
57 const char* k_coreServicesProp = "ro.atrace.core.services";
58 
59 typedef enum { OPT, REQ } requiredness  ;
60 
61 struct TracingCategory {
62     // The name identifying the category.
63     const char* name;
64 
65     // A longer description of the category.
66     const char* longname;
67 
68     // The userland tracing tags that the category enables.
69     uint64_t tags;
70 
71     // The fname==NULL terminated list of /sys/ files that the category
72     // enables.
73     struct {
74         // Whether the file must be writable in order to enable the tracing
75         // category.
76         requiredness required;
77 
78         // The path to the enable file.
79         const char* path;
80     } sysfiles[MAX_SYS_FILES];
81 };
82 
83 /* Tracing categories */
84 static const TracingCategory k_categories[] = {
85     { "gfx",        "Graphics",         ATRACE_TAG_GRAPHICS, { } },
86     { "input",      "Input",            ATRACE_TAG_INPUT, { } },
87     { "view",       "View System",      ATRACE_TAG_VIEW, { } },
88     { "webview",    "WebView",          ATRACE_TAG_WEBVIEW, { } },
89     { "wm",         "Window Manager",   ATRACE_TAG_WINDOW_MANAGER, { } },
90     { "am",         "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
91     { "sm",         "Sync Manager",     ATRACE_TAG_SYNC_MANAGER, { } },
92     { "audio",      "Audio",            ATRACE_TAG_AUDIO, { } },
93     { "video",      "Video",            ATRACE_TAG_VIDEO, { } },
94     { "camera",     "Camera",           ATRACE_TAG_CAMERA, { } },
95     { "hal",        "Hardware Modules", ATRACE_TAG_HAL, { } },
96     { "app",        "Application",      ATRACE_TAG_APP, { } },
97     { "res",        "Resource Loading", ATRACE_TAG_RESOURCES, { } },
98     { "dalvik",     "Dalvik VM",        ATRACE_TAG_DALVIK, { } },
99     { "rs",         "RenderScript",     ATRACE_TAG_RS, { } },
100     { "bionic",     "Bionic C Library", ATRACE_TAG_BIONIC, { } },
101     { "power",      "Power Management", ATRACE_TAG_POWER, { } },
102     { "pm",         "Package Manager",  ATRACE_TAG_PACKAGE_MANAGER, { } },
103     { "ss",         "System Server",    ATRACE_TAG_SYSTEM_SERVER, { } },
104     { "database",   "Database",         ATRACE_TAG_DATABASE, { } },
105     { k_coreServiceCategory, "Core services", 0, { } },
106     { "sched",      "CPU Scheduling",   0, {
107         { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
108         { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
109         { OPT,      "/sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable" },
110         { OPT,      "/sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable" },
111     } },
112     { "irq",        "IRQ Events",   0, {
113         { REQ,      "/sys/kernel/debug/tracing/events/irq/enable" },
114         { OPT,      "/sys/kernel/debug/tracing/events/ipi/enable" },
115     } },
116     { "freq",       "CPU Frequency",    0, {
117         { REQ,      "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
118         { OPT,      "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
119         { OPT,      "/sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable" },
120     } },
121     { "membus",     "Memory Bus Utilization", 0, {
122         { REQ,      "/sys/kernel/debug/tracing/events/memory_bus/enable" },
123     } },
124     { "idle",       "CPU Idle",         0, {
125         { REQ,      "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
126     } },
127     { "disk",       "Disk I/O",         0, {
128         { OPT,      "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable" },
129         { OPT,      "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable" },
130         { OPT,      "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable" },
131         { OPT,      "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable" },
132         { OPT,      "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable" },
133         { OPT,      "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable" },
134         { OPT,      "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
135         { OPT,      "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
136         { REQ,      "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
137         { REQ,      "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
138     } },
139     { "mmc",        "eMMC commands",    0, {
140         { REQ,      "/sys/kernel/debug/tracing/events/mmc/enable" },
141     } },
142     { "load",       "CPU Load",         0, {
143         { REQ,      "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
144     } },
145     { "sync",       "Synchronization",  0, {
146         { REQ,      "/sys/kernel/debug/tracing/events/sync/enable" },
147     } },
148     { "workq",      "Kernel Workqueues", 0, {
149         { REQ,      "/sys/kernel/debug/tracing/events/workqueue/enable" },
150     } },
151     { "memreclaim", "Kernel Memory Reclaim", 0, {
152         { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
153         { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
154         { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" },
155         { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" },
156     } },
157     { "regulators",  "Voltage and Current Regulators", 0, {
158         { REQ,      "/sys/kernel/debug/tracing/events/regulator/enable" },
159     } },
160     { "binder_driver", "Binder Kernel driver", 0, {
161         { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_transaction/enable" },
162         { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable" },
163     } },
164     { "binder_lock", "Binder global lock trace", 0, {
165         { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_lock/enable" },
166         { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_locked/enable" },
167         { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_unlock/enable" },
168     } },
169     { "pagecache",  "Page cache", 0, {
170         { REQ,      "/sys/kernel/debug/tracing/events/filemap/enable" },
171     } },
172 };
173 
174 /* Command line options */
175 static int g_traceDurationSeconds = 5;
176 static bool g_traceOverwrite = false;
177 static int g_traceBufferSizeKB = 2048;
178 static bool g_compress = false;
179 static bool g_nohup = false;
180 static int g_initialSleepSecs = 0;
181 static const char* g_categoriesFile = NULL;
182 static const char* g_kernelTraceFuncs = NULL;
183 static const char* g_debugAppCmdLine = "";
184 static const char* g_outputFile = nullptr;
185 
186 /* Global state */
187 static bool g_traceAborted = false;
188 static bool g_categoryEnables[NELEM(k_categories)] = {};
189 
190 /* Sys file paths */
191 static const char* k_traceClockPath =
192     "/sys/kernel/debug/tracing/trace_clock";
193 
194 static const char* k_traceBufferSizePath =
195     "/sys/kernel/debug/tracing/buffer_size_kb";
196 
197 static const char* k_tracingOverwriteEnablePath =
198     "/sys/kernel/debug/tracing/options/overwrite";
199 
200 static const char* k_currentTracerPath =
201     "/sys/kernel/debug/tracing/current_tracer";
202 
203 static const char* k_printTgidPath =
204     "/sys/kernel/debug/tracing/options/print-tgid";
205 
206 static const char* k_funcgraphAbsTimePath =
207     "/sys/kernel/debug/tracing/options/funcgraph-abstime";
208 
209 static const char* k_funcgraphCpuPath =
210     "/sys/kernel/debug/tracing/options/funcgraph-cpu";
211 
212 static const char* k_funcgraphProcPath =
213     "/sys/kernel/debug/tracing/options/funcgraph-proc";
214 
215 static const char* k_funcgraphFlatPath =
216     "/sys/kernel/debug/tracing/options/funcgraph-flat";
217 
218 static const char* k_funcgraphDurationPath =
219     "/sys/kernel/debug/tracing/options/funcgraph-duration";
220 
221 static const char* k_ftraceFilterPath =
222     "/sys/kernel/debug/tracing/set_ftrace_filter";
223 
224 static const char* k_tracingOnPath =
225     "/sys/kernel/debug/tracing/tracing_on";
226 
227 static const char* k_tracePath =
228     "/sys/kernel/debug/tracing/trace";
229 
230 static const char* k_traceStreamPath =
231     "/sys/kernel/debug/tracing/trace_pipe";
232 
233 static const char* k_traceMarkerPath =
234     "/sys/kernel/debug/tracing/trace_marker";
235 
236 // Check whether a file exists.
fileExists(const char * filename)237 static bool fileExists(const char* filename) {
238     return access(filename, F_OK) != -1;
239 }
240 
241 // Check whether a file is writable.
fileIsWritable(const char * filename)242 static bool fileIsWritable(const char* filename) {
243     return access(filename, W_OK) != -1;
244 }
245 
246 // Truncate a file.
truncateFile(const char * path)247 static bool truncateFile(const char* path)
248 {
249     // This uses creat rather than truncate because some of the debug kernel
250     // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
251     // calls to truncate, but they are cleared by calls to creat.
252     int traceFD = creat(path, 0);
253     if (traceFD == -1) {
254         fprintf(stderr, "error truncating %s: %s (%d)\n", path,
255             strerror(errno), errno);
256         return false;
257     }
258 
259     close(traceFD);
260 
261     return true;
262 }
263 
_writeStr(const char * filename,const char * str,int flags)264 static bool _writeStr(const char* filename, const char* str, int flags)
265 {
266     int fd = open(filename, flags);
267     if (fd == -1) {
268         fprintf(stderr, "error opening %s: %s (%d)\n", filename,
269                 strerror(errno), errno);
270         return false;
271     }
272 
273     bool ok = true;
274     ssize_t len = strlen(str);
275     if (write(fd, str, len) != len) {
276         fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
277                 strerror(errno), errno);
278         ok = false;
279     }
280 
281     close(fd);
282 
283     return ok;
284 }
285 
286 // Write a string to a file, returning true if the write was successful.
writeStr(const char * filename,const char * str)287 static bool writeStr(const char* filename, const char* str)
288 {
289     return _writeStr(filename, str, O_WRONLY);
290 }
291 
292 // Append a string to a file, returning true if the write was successful.
appendStr(const char * filename,const char * str)293 static bool appendStr(const char* filename, const char* str)
294 {
295     return _writeStr(filename, str, O_APPEND|O_WRONLY);
296 }
297 
writeClockSyncMarker()298 static void writeClockSyncMarker()
299 {
300   char buffer[128];
301   int len = 0;
302   int fd = open(k_traceMarkerPath, O_WRONLY);
303   if (fd == -1) {
304       fprintf(stderr, "error opening %s: %s (%d)\n", k_traceMarkerPath,
305               strerror(errno), errno);
306       return;
307   }
308   float now_in_seconds = systemTime(CLOCK_MONOTONIC) / 1000000000.0f;
309 
310   len = snprintf(buffer, 128, "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds);
311   if (write(fd, buffer, len) != len) {
312       fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno);
313   }
314 
315   int64_t realtime_in_ms = systemTime(CLOCK_REALTIME) / 1000000;
316   len = snprintf(buffer, 128, "trace_event_clock_sync: realtime_ts=%" PRId64 "\n", realtime_in_ms);
317   if (write(fd, buffer, len) != len) {
318       fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno);
319   }
320 
321   close(fd);
322 }
323 
324 // Enable or disable a kernel option by writing a "1" or a "0" into a /sys
325 // file.
setKernelOptionEnable(const char * filename,bool enable)326 static bool setKernelOptionEnable(const char* filename, bool enable)
327 {
328     return writeStr(filename, enable ? "1" : "0");
329 }
330 
331 // Check whether the category is supported on the device with the current
332 // rootness.  A category is supported only if all its required /sys/ files are
333 // writable and if enabling the category will enable one or more tracing tags
334 // or /sys/ files.
isCategorySupported(const TracingCategory & category)335 static bool isCategorySupported(const TracingCategory& category)
336 {
337     if (strcmp(category.name, k_coreServiceCategory) == 0) {
338         char value[PROPERTY_VALUE_MAX];
339         property_get(k_coreServicesProp, value, "");
340         return strlen(value) != 0;
341     }
342 
343     bool ok = category.tags != 0;
344     for (int i = 0; i < MAX_SYS_FILES; i++) {
345         const char* path = category.sysfiles[i].path;
346         bool req = category.sysfiles[i].required == REQ;
347         if (path != NULL) {
348             if (req) {
349                 if (!fileIsWritable(path)) {
350                     return false;
351                 } else {
352                     ok = true;
353                 }
354             } else {
355                 ok |= fileIsWritable(path);
356             }
357         }
358     }
359     return ok;
360 }
361 
362 // Check whether the category would be supported on the device if the user
363 // were root.  This function assumes that root is able to write to any file
364 // that exists.  It performs the same logic as isCategorySupported, but it
365 // uses file existance rather than writability in the /sys/ file checks.
isCategorySupportedForRoot(const TracingCategory & category)366 static bool isCategorySupportedForRoot(const TracingCategory& category)
367 {
368     bool ok = category.tags != 0;
369     for (int i = 0; i < MAX_SYS_FILES; i++) {
370         const char* path = category.sysfiles[i].path;
371         bool req = category.sysfiles[i].required == REQ;
372         if (path != NULL) {
373             if (req) {
374                 if (!fileExists(path)) {
375                     return false;
376                 } else {
377                     ok = true;
378                 }
379             } else {
380                 ok |= fileExists(path);
381             }
382         }
383     }
384     return ok;
385 }
386 
387 // Enable or disable overwriting of the kernel trace buffers.  Disabling this
388 // will cause tracing to stop once the trace buffers have filled up.
setTraceOverwriteEnable(bool enable)389 static bool setTraceOverwriteEnable(bool enable)
390 {
391     return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
392 }
393 
394 // Enable or disable kernel tracing.
setTracingEnabled(bool enable)395 static bool setTracingEnabled(bool enable)
396 {
397     return setKernelOptionEnable(k_tracingOnPath, enable);
398 }
399 
400 // Clear the contents of the kernel trace.
clearTrace()401 static bool clearTrace()
402 {
403     return truncateFile(k_tracePath);
404 }
405 
406 // Set the size of the kernel's trace buffer in kilobytes.
setTraceBufferSizeKB(int size)407 static bool setTraceBufferSizeKB(int size)
408 {
409     char str[32] = "1";
410     int len;
411     if (size < 1) {
412         size = 1;
413     }
414     snprintf(str, 32, "%d", size);
415     return writeStr(k_traceBufferSizePath, str);
416 }
417 
418 // Read the trace_clock sysfs file and return true if it matches the requested
419 // value.  The trace_clock file format is:
420 // local [global] counter uptime perf
isTraceClock(const char * mode)421 static bool isTraceClock(const char *mode)
422 {
423     int fd = open(k_traceClockPath, O_RDONLY);
424     if (fd == -1) {
425         fprintf(stderr, "error opening %s: %s (%d)\n", k_traceClockPath,
426             strerror(errno), errno);
427         return false;
428     }
429 
430     char buf[4097];
431     ssize_t n = read(fd, buf, 4096);
432     close(fd);
433     if (n == -1) {
434         fprintf(stderr, "error reading %s: %s (%d)\n", k_traceClockPath,
435             strerror(errno), errno);
436         return false;
437     }
438     buf[n] = '\0';
439 
440     char *start = strchr(buf, '[');
441     if (start == NULL) {
442         return false;
443     }
444     start++;
445 
446     char *end = strchr(start, ']');
447     if (end == NULL) {
448         return false;
449     }
450     *end = '\0';
451 
452     return strcmp(mode, start) == 0;
453 }
454 
455 // Enable or disable the kernel's use of the global clock.  Disabling the global
456 // clock will result in the kernel using a per-CPU local clock.
457 // Any write to the trace_clock sysfs file will reset the buffer, so only
458 // update it if the requested value is not the current value.
setGlobalClockEnable(bool enable)459 static bool setGlobalClockEnable(bool enable)
460 {
461     const char *clock = enable ? "global" : "local";
462 
463     if (isTraceClock(clock)) {
464         return true;
465     }
466 
467     return writeStr(k_traceClockPath, clock);
468 }
469 
setPrintTgidEnableIfPresent(bool enable)470 static bool setPrintTgidEnableIfPresent(bool enable)
471 {
472     if (fileExists(k_printTgidPath)) {
473         return setKernelOptionEnable(k_printTgidPath, enable);
474     }
475     return true;
476 }
477 
478 // Poke all the binder-enabled processes in the system to get them to re-read
479 // their system properties.
pokeBinderServices()480 static bool pokeBinderServices()
481 {
482     sp<IServiceManager> sm = defaultServiceManager();
483     Vector<String16> services = sm->listServices();
484     for (size_t i = 0; i < services.size(); i++) {
485         sp<IBinder> obj = sm->checkService(services[i]);
486         if (obj != NULL) {
487             Parcel data;
488             if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
489                     NULL, 0) != OK) {
490                 if (false) {
491                     // XXX: For some reason this fails on tablets trying to
492                     // poke the "phone" service.  It's not clear whether some
493                     // are expected to fail.
494                     String8 svc(services[i]);
495                     fprintf(stderr, "error poking binder service %s\n",
496                         svc.string());
497                     return false;
498                 }
499             }
500         }
501     }
502     return true;
503 }
504 
505 // Set the trace tags that userland tracing uses, and poke the running
506 // processes to pick up the new value.
setTagsProperty(uint64_t tags)507 static bool setTagsProperty(uint64_t tags)
508 {
509     char buf[PROPERTY_VALUE_MAX];
510     snprintf(buf, sizeof(buf), "%#" PRIx64, tags);
511     if (property_set(k_traceTagsProperty, buf) < 0) {
512         fprintf(stderr, "error setting trace tags system property\n");
513         return false;
514     }
515     return true;
516 }
517 
clearAppProperties()518 static void clearAppProperties()
519 {
520     char buf[PROPERTY_KEY_MAX];
521     for (int i = 0; i < MAX_PACKAGES; i++) {
522         snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
523         if (property_set(buf, "") < 0) {
524             fprintf(stderr, "failed to clear system property: %s\n", buf);
525         }
526     }
527     if (property_set(k_traceAppsNumberProperty, "") < 0) {
528         fprintf(stderr, "failed to clear system property: %s",
529               k_traceAppsNumberProperty);
530     }
531 }
532 
533 // Set the system property that indicates which apps should perform
534 // application-level tracing.
setAppCmdlineProperty(const char * cmdline)535 static bool setAppCmdlineProperty(const char* cmdline)
536 {
537     char buf[PROPERTY_KEY_MAX];
538     int i = 0;
539     const char* start = cmdline;
540     while (start != NULL) {
541         if (i == MAX_PACKAGES) {
542             fprintf(stderr, "error: only 16 packages could be traced at once\n");
543             clearAppProperties();
544             return false;
545         }
546         char* end = strchr(start, ',');
547         if (end != NULL) {
548             *end = '\0';
549             end++;
550         }
551         snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
552         if (property_set(buf, start) < 0) {
553             fprintf(stderr, "error setting trace app %d property to %s\n", i, buf);
554             clearAppProperties();
555             return false;
556         }
557         start = end;
558         i++;
559     }
560 
561     snprintf(buf, sizeof(buf), "%d", i);
562     if (property_set(k_traceAppsNumberProperty, buf) < 0) {
563         fprintf(stderr, "error setting trace app number property to %s\n", buf);
564         clearAppProperties();
565         return false;
566     }
567     return true;
568 }
569 
570 // Disable all /sys/ enable files.
disableKernelTraceEvents()571 static bool disableKernelTraceEvents() {
572     bool ok = true;
573     for (int i = 0; i < NELEM(k_categories); i++) {
574         const TracingCategory &c = k_categories[i];
575         for (int j = 0; j < MAX_SYS_FILES; j++) {
576             const char* path = c.sysfiles[j].path;
577             if (path != NULL && fileIsWritable(path)) {
578                 ok &= setKernelOptionEnable(path, false);
579             }
580         }
581     }
582     return ok;
583 }
584 
585 // Verify that the comma separated list of functions are being traced by the
586 // kernel.
verifyKernelTraceFuncs(const char * funcs)587 static bool verifyKernelTraceFuncs(const char* funcs)
588 {
589     int fd = open(k_ftraceFilterPath, O_RDONLY);
590     if (fd == -1) {
591         fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
592             strerror(errno), errno);
593         return false;
594     }
595 
596     char buf[4097];
597     ssize_t n = read(fd, buf, 4096);
598     close(fd);
599     if (n == -1) {
600         fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath,
601             strerror(errno), errno);
602         return false;
603     }
604 
605     buf[n] = '\0';
606     String8 funcList = String8::format("\n%s", buf);
607 
608     // Make sure that every function listed in funcs is in the list we just
609     // read from the kernel, except for wildcard inputs.
610     bool ok = true;
611     char* myFuncs = strdup(funcs);
612     char* func = strtok(myFuncs, ",");
613     while (func) {
614         if (!strchr(func, '*')) {
615             String8 fancyFunc = String8::format("\n%s\n", func);
616             bool found = funcList.find(fancyFunc.string(), 0) >= 0;
617             if (!found || func[0] == '\0') {
618                 fprintf(stderr, "error: \"%s\" is not a valid kernel function "
619                         "to trace.\n", func);
620                 ok = false;
621             }
622         }
623         func = strtok(NULL, ",");
624     }
625     free(myFuncs);
626 
627     return ok;
628 }
629 
630 // Set the comma separated list of functions that the kernel is to trace.
setKernelTraceFuncs(const char * funcs)631 static bool setKernelTraceFuncs(const char* funcs)
632 {
633     bool ok = true;
634 
635     if (funcs == NULL || funcs[0] == '\0') {
636         // Disable kernel function tracing.
637         if (fileIsWritable(k_currentTracerPath)) {
638             ok &= writeStr(k_currentTracerPath, "nop");
639         }
640         if (fileIsWritable(k_ftraceFilterPath)) {
641             ok &= truncateFile(k_ftraceFilterPath);
642         }
643     } else {
644         // Enable kernel function tracing.
645         ok &= writeStr(k_currentTracerPath, "function_graph");
646         ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
647         ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
648         ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
649         ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
650 
651         // Set the requested filter functions.
652         ok &= truncateFile(k_ftraceFilterPath);
653         char* myFuncs = strdup(funcs);
654         char* func = strtok(myFuncs, ",");
655         while (func) {
656             ok &= appendStr(k_ftraceFilterPath, func);
657             func = strtok(NULL, ",");
658         }
659         free(myFuncs);
660 
661         // Verify that the set functions are being traced.
662         if (ok) {
663             ok &= verifyKernelTraceFuncs(funcs);
664         }
665     }
666 
667     return ok;
668 }
669 
setCategoryEnable(const char * name,bool enable)670 static bool setCategoryEnable(const char* name, bool enable)
671 {
672     for (int i = 0; i < NELEM(k_categories); i++) {
673         const TracingCategory& c = k_categories[i];
674         if (strcmp(name, c.name) == 0) {
675             if (isCategorySupported(c)) {
676                 g_categoryEnables[i] = enable;
677                 return true;
678             } else {
679                 if (isCategorySupportedForRoot(c)) {
680                     fprintf(stderr, "error: category \"%s\" requires root "
681                             "privileges.\n", name);
682                 } else {
683                     fprintf(stderr, "error: category \"%s\" is not supported "
684                             "on this device.\n", name);
685                 }
686                 return false;
687             }
688         }
689     }
690     fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
691     return false;
692 }
693 
setCategoriesEnableFromFile(const char * categories_file)694 static bool setCategoriesEnableFromFile(const char* categories_file)
695 {
696     if (!categories_file) {
697         return true;
698     }
699     Tokenizer* tokenizer = NULL;
700     if (Tokenizer::open(String8(categories_file), &tokenizer) != NO_ERROR) {
701         return false;
702     }
703     bool ok = true;
704     while (!tokenizer->isEol()) {
705         String8 token = tokenizer->nextToken(" ");
706         if (token.isEmpty()) {
707             tokenizer->skipDelimiters(" ");
708             continue;
709         }
710         ok &= setCategoryEnable(token.string(), true);
711     }
712     delete tokenizer;
713     return ok;
714 }
715 
716 // Set all the kernel tracing settings to the desired state for this trace
717 // capture.
setUpTrace()718 static bool setUpTrace()
719 {
720     bool ok = true;
721 
722     // Set up the tracing options.
723     ok &= setCategoriesEnableFromFile(g_categoriesFile);
724     ok &= setTraceOverwriteEnable(g_traceOverwrite);
725     ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
726     ok &= setGlobalClockEnable(true);
727     ok &= setPrintTgidEnableIfPresent(true);
728     ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
729 
730     // Set up the tags property.
731     uint64_t tags = 0;
732     for (int i = 0; i < NELEM(k_categories); i++) {
733         if (g_categoryEnables[i]) {
734             const TracingCategory &c = k_categories[i];
735             tags |= c.tags;
736         }
737     }
738     ok &= setTagsProperty(tags);
739 
740     bool coreServicesTagEnabled = false;
741     for (int i = 0; i < NELEM(k_categories); i++) {
742         if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) {
743             coreServicesTagEnabled = g_categoryEnables[i];
744         }
745     }
746 
747     std::string packageList(g_debugAppCmdLine);
748     if (coreServicesTagEnabled) {
749         char value[PROPERTY_VALUE_MAX];
750         property_get(k_coreServicesProp, value, "");
751         if (!packageList.empty()) {
752             packageList += ",";
753         }
754         packageList += value;
755     }
756     ok &= setAppCmdlineProperty(packageList.data());
757     ok &= pokeBinderServices();
758 
759     // Disable all the sysfs enables.  This is done as a separate loop from
760     // the enables to allow the same enable to exist in multiple categories.
761     ok &= disableKernelTraceEvents();
762 
763     // Enable all the sysfs enables that are in an enabled category.
764     for (int i = 0; i < NELEM(k_categories); i++) {
765         if (g_categoryEnables[i]) {
766             const TracingCategory &c = k_categories[i];
767             for (int j = 0; j < MAX_SYS_FILES; j++) {
768                 const char* path = c.sysfiles[j].path;
769                 bool required = c.sysfiles[j].required == REQ;
770                 if (path != NULL) {
771                     if (fileIsWritable(path)) {
772                         ok &= setKernelOptionEnable(path, true);
773                     } else if (required) {
774                         fprintf(stderr, "error writing file %s\n", path);
775                         ok = false;
776                     }
777                 }
778             }
779         }
780     }
781 
782     return ok;
783 }
784 
785 // Reset all the kernel tracing settings to their default state.
cleanUpTrace()786 static void cleanUpTrace()
787 {
788     // Disable all tracing that we're able to.
789     disableKernelTraceEvents();
790 
791     // Reset the system properties.
792     setTagsProperty(0);
793     clearAppProperties();
794     pokeBinderServices();
795 
796     // Set the options back to their defaults.
797     setTraceOverwriteEnable(true);
798     setTraceBufferSizeKB(1);
799     setGlobalClockEnable(false);
800     setPrintTgidEnableIfPresent(false);
801     setKernelTraceFuncs(NULL);
802 }
803 
804 
805 // Enable tracing in the kernel.
startTrace()806 static bool startTrace()
807 {
808     return setTracingEnabled(true);
809 }
810 
811 // Disable tracing in the kernel.
stopTrace()812 static void stopTrace()
813 {
814     setTracingEnabled(false);
815 }
816 
817 // Read data from the tracing pipe and forward to stdout
streamTrace()818 static void streamTrace()
819 {
820     char trace_data[4096];
821     int traceFD = open(k_traceStreamPath, O_RDWR);
822     if (traceFD == -1) {
823         fprintf(stderr, "error opening %s: %s (%d)\n", k_traceStreamPath,
824                 strerror(errno), errno);
825         return;
826     }
827     while (!g_traceAborted) {
828         ssize_t bytes_read = read(traceFD, trace_data, 4096);
829         if (bytes_read > 0) {
830             write(STDOUT_FILENO, trace_data, bytes_read);
831             fflush(stdout);
832         } else {
833             if (!g_traceAborted) {
834                 fprintf(stderr, "read returned %zd bytes err %d (%s)\n",
835                         bytes_read, errno, strerror(errno));
836             }
837             break;
838         }
839     }
840 }
841 
842 // Read the current kernel trace and write it to stdout.
dumpTrace(int outFd)843 static void dumpTrace(int outFd)
844 {
845     ALOGI("Dumping trace");
846     int traceFD = open(k_tracePath, O_RDWR);
847     if (traceFD == -1) {
848         fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
849                 strerror(errno), errno);
850         return;
851     }
852 
853     if (g_compress) {
854         z_stream zs;
855         uint8_t *in, *out;
856         int result, flush;
857 
858         memset(&zs, 0, sizeof(zs));
859         result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
860         if (result != Z_OK) {
861             fprintf(stderr, "error initializing zlib: %d\n", result);
862             close(traceFD);
863             return;
864         }
865 
866         const size_t bufSize = 64*1024;
867         in = (uint8_t*)malloc(bufSize);
868         out = (uint8_t*)malloc(bufSize);
869         flush = Z_NO_FLUSH;
870 
871         zs.next_out = out;
872         zs.avail_out = bufSize;
873 
874         do {
875 
876             if (zs.avail_in == 0) {
877                 // More input is needed.
878                 result = read(traceFD, in, bufSize);
879                 if (result < 0) {
880                     fprintf(stderr, "error reading trace: %s (%d)\n",
881                             strerror(errno), errno);
882                     result = Z_STREAM_END;
883                     break;
884                 } else if (result == 0) {
885                     flush = Z_FINISH;
886                 } else {
887                     zs.next_in = in;
888                     zs.avail_in = result;
889                 }
890             }
891 
892             if (zs.avail_out == 0) {
893                 // Need to write the output.
894                 result = write(outFd, out, bufSize);
895                 if ((size_t)result < bufSize) {
896                     fprintf(stderr, "error writing deflated trace: %s (%d)\n",
897                             strerror(errno), errno);
898                     result = Z_STREAM_END; // skip deflate error message
899                     zs.avail_out = bufSize; // skip the final write
900                     break;
901                 }
902                 zs.next_out = out;
903                 zs.avail_out = bufSize;
904             }
905 
906         } while ((result = deflate(&zs, flush)) == Z_OK);
907 
908         if (result != Z_STREAM_END) {
909             fprintf(stderr, "error deflating trace: %s\n", zs.msg);
910         }
911 
912         if (zs.avail_out < bufSize) {
913             size_t bytes = bufSize - zs.avail_out;
914             result = write(outFd, out, bytes);
915             if ((size_t)result < bytes) {
916                 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
917                         strerror(errno), errno);
918             }
919         }
920 
921         result = deflateEnd(&zs);
922         if (result != Z_OK) {
923             fprintf(stderr, "error cleaning up zlib: %d\n", result);
924         }
925 
926         free(in);
927         free(out);
928     } else {
929         ssize_t sent = 0;
930         while ((sent = sendfile(outFd, traceFD, NULL, 64*1024*1024)) > 0);
931         if (sent == -1) {
932             fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
933                     errno);
934         }
935     }
936 
937     close(traceFD);
938 }
939 
handleSignal(int)940 static void handleSignal(int /*signo*/)
941 {
942     if (!g_nohup) {
943         g_traceAborted = true;
944     }
945 }
946 
registerSigHandler()947 static void registerSigHandler()
948 {
949     struct sigaction sa;
950     sigemptyset(&sa.sa_mask);
951     sa.sa_flags = 0;
952     sa.sa_handler = handleSignal;
953     sigaction(SIGHUP, &sa, NULL);
954     sigaction(SIGINT, &sa, NULL);
955     sigaction(SIGQUIT, &sa, NULL);
956     sigaction(SIGTERM, &sa, NULL);
957 }
958 
listSupportedCategories()959 static void listSupportedCategories()
960 {
961     for (int i = 0; i < NELEM(k_categories); i++) {
962         const TracingCategory& c = k_categories[i];
963         if (isCategorySupported(c)) {
964             printf("  %10s - %s\n", c.name, c.longname);
965         }
966     }
967 }
968 
969 // Print the command usage help to stderr.
showHelp(const char * cmd)970 static void showHelp(const char *cmd)
971 {
972     fprintf(stderr, "usage: %s [options] [categories...]\n", cmd);
973     fprintf(stderr, "options include:\n"
974                     "  -a appname      enable app-level tracing for a comma "
975                         "separated list of cmdlines\n"
976                     "  -b N            use a trace buffer size of N KB\n"
977                     "  -c              trace into a circular buffer\n"
978                     "  -f filename     use the categories written in a file as space-separated\n"
979                     "                    values in a line\n"
980                     "  -k fname,...    trace the listed kernel functions\n"
981                     "  -n              ignore signals\n"
982                     "  -s N            sleep for N seconds before tracing [default 0]\n"
983                     "  -t N            trace for N seconds [defualt 5]\n"
984                     "  -z              compress the trace dump\n"
985                     "  --async_start   start circular trace and return immediatly\n"
986                     "  --async_dump    dump the current contents of circular trace buffer\n"
987                     "  --async_stop    stop tracing and dump the current contents of circular\n"
988                     "                    trace buffer\n"
989                     "  --stream        stream trace to stdout as it enters the trace buffer\n"
990                     "                    Note: this can take significant CPU time, and is best\n"
991                     "                    used for measuring things that are not affected by\n"
992                     "                    CPU performance, like pagecache usage.\n"
993                     "  --list_categories\n"
994                     "                  list the available tracing categories\n"
995                     " -o filename      write the trace to the specified file instead\n"
996                     "                    of stdout.\n"
997             );
998 }
999 
main(int argc,char ** argv)1000 int main(int argc, char **argv)
1001 {
1002     bool async = false;
1003     bool traceStart = true;
1004     bool traceStop = true;
1005     bool traceDump = true;
1006     bool traceStream = false;
1007 
1008     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
1009         showHelp(argv[0]);
1010         exit(0);
1011     }
1012 
1013     for (;;) {
1014         int ret;
1015         int option_index = 0;
1016         static struct option long_options[] = {
1017             {"async_start",     no_argument, 0,  0 },
1018             {"async_stop",      no_argument, 0,  0 },
1019             {"async_dump",      no_argument, 0,  0 },
1020             {"list_categories", no_argument, 0,  0 },
1021             {"stream",          no_argument, 0,  0 },
1022             {           0,                0, 0,  0 }
1023         };
1024 
1025         ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:",
1026                           long_options, &option_index);
1027 
1028         if (ret < 0) {
1029             for (int i = optind; i < argc; i++) {
1030                 if (!setCategoryEnable(argv[i], true)) {
1031                     fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
1032                     exit(1);
1033                 }
1034             }
1035             break;
1036         }
1037 
1038         switch(ret) {
1039             case 'a':
1040                 g_debugAppCmdLine = optarg;
1041             break;
1042 
1043             case 'b':
1044                 g_traceBufferSizeKB = atoi(optarg);
1045             break;
1046 
1047             case 'c':
1048                 g_traceOverwrite = true;
1049             break;
1050 
1051             case 'f':
1052                 g_categoriesFile = optarg;
1053             break;
1054 
1055             case 'k':
1056                 g_kernelTraceFuncs = optarg;
1057             break;
1058 
1059             case 'n':
1060                 g_nohup = true;
1061             break;
1062 
1063             case 's':
1064                 g_initialSleepSecs = atoi(optarg);
1065             break;
1066 
1067             case 't':
1068                 g_traceDurationSeconds = atoi(optarg);
1069             break;
1070 
1071             case 'z':
1072                 g_compress = true;
1073             break;
1074 
1075             case 'o':
1076                 g_outputFile = optarg;
1077             break;
1078 
1079             case 0:
1080                 if (!strcmp(long_options[option_index].name, "async_start")) {
1081                     async = true;
1082                     traceStop = false;
1083                     traceDump = false;
1084                     g_traceOverwrite = true;
1085                 } else if (!strcmp(long_options[option_index].name, "async_stop")) {
1086                     async = true;
1087                     traceStart = false;
1088                 } else if (!strcmp(long_options[option_index].name, "async_dump")) {
1089                     async = true;
1090                     traceStart = false;
1091                     traceStop = false;
1092                 } else if (!strcmp(long_options[option_index].name, "stream")) {
1093                     traceStream = true;
1094                     traceDump = false;
1095                 } else if (!strcmp(long_options[option_index].name, "list_categories")) {
1096                     listSupportedCategories();
1097                     exit(0);
1098                 }
1099             break;
1100 
1101             default:
1102                 fprintf(stderr, "\n");
1103                 showHelp(argv[0]);
1104                 exit(-1);
1105             break;
1106         }
1107     }
1108 
1109     registerSigHandler();
1110 
1111     if (g_initialSleepSecs > 0) {
1112         sleep(g_initialSleepSecs);
1113     }
1114 
1115     bool ok = true;
1116     ok &= setUpTrace();
1117     ok &= startTrace();
1118 
1119     if (ok && traceStart) {
1120         if (!traceStream) {
1121             printf("capturing trace...");
1122             fflush(stdout);
1123         }
1124 
1125         // We clear the trace after starting it because tracing gets enabled for
1126         // each CPU individually in the kernel. Having the beginning of the trace
1127         // contain entries from only one CPU can cause "begin" entries without a
1128         // matching "end" entry to show up if a task gets migrated from one CPU to
1129         // another.
1130         ok = clearTrace();
1131 
1132         writeClockSyncMarker();
1133         if (ok && !async && !traceStream) {
1134             // Sleep to allow the trace to be captured.
1135             struct timespec timeLeft;
1136             timeLeft.tv_sec = g_traceDurationSeconds;
1137             timeLeft.tv_nsec = 0;
1138             do {
1139                 if (g_traceAborted) {
1140                     break;
1141                 }
1142             } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
1143         }
1144 
1145         if (traceStream) {
1146             streamTrace();
1147         }
1148     }
1149 
1150     // Stop the trace and restore the default settings.
1151     if (traceStop)
1152         stopTrace();
1153 
1154     if (ok && traceDump) {
1155         if (!g_traceAborted) {
1156             printf(" done\n");
1157             fflush(stdout);
1158             int outFd = STDOUT_FILENO;
1159             if (g_outputFile) {
1160                 outFd = open(g_outputFile, O_WRONLY | O_CREAT);
1161             }
1162             if (outFd == -1) {
1163                 printf("Failed to open '%s', err=%d", g_outputFile, errno);
1164             } else {
1165                 dprintf(outFd, "TRACE:\n");
1166                 dumpTrace(outFd);
1167                 if (g_outputFile) {
1168                     close(outFd);
1169                 }
1170             }
1171         } else {
1172             printf("\ntrace aborted.\n");
1173             fflush(stdout);
1174         }
1175         clearTrace();
1176     } else if (!ok) {
1177         fprintf(stderr, "unable to start tracing\n");
1178     }
1179 
1180     // Reset the trace buffer size to 1.
1181     if (traceStop)
1182         cleanUpTrace();
1183 
1184     return g_traceAborted ? 1 : 0;
1185 }
1186