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 <time.h>
30 #include <unistd.h>
31 #include <zlib.h>
32 
33 #include <fstream>
34 #include <memory>
35 
36 #include <binder/IBinder.h>
37 #include <binder/IServiceManager.h>
38 #include <binder/Parcel.h>
39 
40 #include <android/hardware/atrace/1.0/IAtraceDevice.h>
41 #include <android/hidl/manager/1.0/IServiceManager.h>
42 #include <hidl/ServiceManagement.h>
43 
44 #include <pdx/default_transport/service_utility.h>
45 #include <utils/String8.h>
46 #include <utils/Timers.h>
47 #include <utils/Tokenizer.h>
48 #include <utils/Trace.h>
49 #include <android-base/file.h>
50 #include <android-base/macros.h>
51 #include <android-base/properties.h>
52 #include <android-base/strings.h>
53 #include <android-base/stringprintf.h>
54 
55 using namespace android;
56 using pdx::default_transport::ServiceUtility;
57 using hardware::hidl_vec;
58 using hardware::hidl_string;
59 using hardware::Return;
60 using hardware::atrace::V1_0::IAtraceDevice;
61 using hardware::atrace::V1_0::Status;
62 using hardware::atrace::V1_0::toString;
63 
64 using std::string;
65 
66 #define MAX_SYS_FILES 13
67 
68 const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
69 const char* k_userInitiatedTraceProperty = "debug.atrace.user_initiated";
70 
71 const char* k_traceAppsNumberProperty = "debug.atrace.app_number";
72 const char* k_traceAppsPropertyTemplate = "debug.atrace.app_%d";
73 const char* k_coreServiceCategory = "core_services";
74 const char* k_pdxServiceCategory = "pdx";
75 const char* k_coreServicesProp = "ro.atrace.core.services";
76 
77 const char* kVendorCategoriesPath = "/vendor/etc/atrace/atrace_categories.txt";
78 
79 typedef enum { OPT, REQ } requiredness;
80 
81 struct TracingCategory {
82     // The name identifying the category.
83     const char* name;
84 
85     // A longer description of the category.
86     const char* longname;
87 
88     // The userland tracing tags that the category enables.
89     uint64_t tags;
90 
91     // The fname==NULL terminated list of /sys/ files that the category
92     // enables.
93     struct {
94         // Whether the file must be writable in order to enable the tracing
95         // category.
96         requiredness required;
97 
98         // The path to the enable file.
99         const char* path;
100     } sysfiles[MAX_SYS_FILES];
101 };
102 
103 /* Tracing categories */
104 static const TracingCategory k_categories[] = {
105     { "gfx",        "Graphics",                 ATRACE_TAG_GRAPHICS, {
106         { OPT,      "events/gpu_mem/gpu_mem_total/enable" },
107     } },
108     { "input",      "Input",                    ATRACE_TAG_INPUT, { } },
109     { "view",       "View System",              ATRACE_TAG_VIEW, { } },
110     { "webview",    "WebView",                  ATRACE_TAG_WEBVIEW, { } },
111     { "wm",         "Window Manager",           ATRACE_TAG_WINDOW_MANAGER, { } },
112     { "am",         "Activity Manager",         ATRACE_TAG_ACTIVITY_MANAGER, { } },
113     { "sm",         "Sync Manager",             ATRACE_TAG_SYNC_MANAGER, { } },
114     { "audio",      "Audio",                    ATRACE_TAG_AUDIO, { } },
115     { "video",      "Video",                    ATRACE_TAG_VIDEO, { } },
116     { "camera",     "Camera",                   ATRACE_TAG_CAMERA, { } },
117     { "hal",        "Hardware Modules",         ATRACE_TAG_HAL, { } },
118     { "res",        "Resource Loading",         ATRACE_TAG_RESOURCES, { } },
119     { "dalvik",     "Dalvik VM",                ATRACE_TAG_DALVIK, { } },
120     { "rs",         "RenderScript",             ATRACE_TAG_RS, { } },
121     { "bionic",     "Bionic C Library",         ATRACE_TAG_BIONIC, { } },
122     { "power",      "Power Management",         ATRACE_TAG_POWER, { } },
123     { "pm",         "Package Manager",          ATRACE_TAG_PACKAGE_MANAGER, { } },
124     { "ss",         "System Server",            ATRACE_TAG_SYSTEM_SERVER, { } },
125     { "database",   "Database",                 ATRACE_TAG_DATABASE, { } },
126     { "network",    "Network",                  ATRACE_TAG_NETWORK, { } },
127     { "adb",        "ADB",                      ATRACE_TAG_ADB, { } },
128     { "vibrator",   "Vibrator",                 ATRACE_TAG_VIBRATOR, { } },
129     { "aidl",       "AIDL calls",               ATRACE_TAG_AIDL, { } },
130     { "nnapi",      "NNAPI",                    ATRACE_TAG_NNAPI, { } },
131     { "rro",        "Runtime Resource Overlay", ATRACE_TAG_RRO, { } },
132     { k_coreServiceCategory, "Core services", 0, { } },
133     { k_pdxServiceCategory, "PDX services", 0, { } },
134     { "sched",      "CPU Scheduling",   0, {
135         { REQ,      "events/sched/sched_switch/enable" },
136         { REQ,      "events/sched/sched_wakeup/enable" },
137         { OPT,      "events/sched/sched_waking/enable" },
138         { OPT,      "events/sched/sched_blocked_reason/enable" },
139         { OPT,      "events/sched/sched_cpu_hotplug/enable" },
140         { OPT,      "events/sched/sched_pi_setprio/enable" },
141         { OPT,      "events/sched/sched_process_exit/enable" },
142         { OPT,      "events/cgroup/enable" },
143         { OPT,      "events/oom/oom_score_adj_update/enable" },
144         { OPT,      "events/task/task_rename/enable" },
145         { OPT,      "events/task/task_newtask/enable" },
146     } },
147     { "irq",        "IRQ Events",   0, {
148         { REQ,      "events/irq/enable" },
149         { OPT,      "events/ipi/enable" },
150     } },
151     { "irqoff",     "IRQ-disabled code section tracing", 0, {
152         { REQ,      "events/preemptirq/irq_enable/enable" },
153         { REQ,      "events/preemptirq/irq_disable/enable" },
154     } },
155     { "preemptoff", "Preempt-disabled code section tracing", 0, {
156         { REQ,      "events/preemptirq/preempt_enable/enable" },
157         { REQ,      "events/preemptirq/preempt_disable/enable" },
158     } },
159     { "i2c",        "I2C Events",   0, {
160         { REQ,      "events/i2c/enable" },
161         { REQ,      "events/i2c/i2c_read/enable" },
162         { REQ,      "events/i2c/i2c_write/enable" },
163         { REQ,      "events/i2c/i2c_result/enable" },
164         { REQ,      "events/i2c/i2c_reply/enable" },
165         { OPT,      "events/i2c/smbus_read/enable" },
166         { OPT,      "events/i2c/smbus_write/enable" },
167         { OPT,      "events/i2c/smbus_result/enable" },
168         { OPT,      "events/i2c/smbus_reply/enable" },
169     } },
170     { "freq",       "CPU Frequency",    0, {
171         { REQ,      "events/power/cpu_frequency/enable" },
172         { OPT,      "events/power/clock_set_rate/enable" },
173         { OPT,      "events/power/clock_disable/enable" },
174         { OPT,      "events/power/clock_enable/enable" },
175         { OPT,      "events/clk/clk_set_rate/enable" },
176         { OPT,      "events/clk/clk_disable/enable" },
177         { OPT,      "events/clk/clk_enable/enable" },
178         { OPT,      "events/power/cpu_frequency_limits/enable" },
179         { OPT,      "events/power/suspend_resume/enable" },
180         { OPT,      "events/cpuhp/cpuhp_enter/enable" },
181         { OPT,      "events/cpuhp/cpuhp_exit/enable" },
182         { OPT,      "events/cpuhp/cpuhp_pause/enable" },
183     } },
184     { "membus",     "Memory Bus Utilization", 0, {
185         { REQ,      "events/memory_bus/enable" },
186     } },
187     { "idle",       "CPU Idle",         0, {
188         { REQ,      "events/power/cpu_idle/enable" },
189     } },
190     { "disk",       "Disk I/O",         0, {
191         { OPT,      "events/f2fs/f2fs_sync_file_enter/enable" },
192         { OPT,      "events/f2fs/f2fs_sync_file_exit/enable" },
193         { OPT,      "events/f2fs/f2fs_write_begin/enable" },
194         { OPT,      "events/f2fs/f2fs_write_end/enable" },
195         { OPT,      "events/f2fs/f2fs_iostat/enable" },
196         { OPT,      "events/f2fs/f2fs_iostat_latency/enable" },
197         { OPT,      "events/ext4/ext4_da_write_begin/enable" },
198         { OPT,      "events/ext4/ext4_da_write_end/enable" },
199         { OPT,      "events/ext4/ext4_sync_file_enter/enable" },
200         { OPT,      "events/ext4/ext4_sync_file_exit/enable" },
201         { OPT,      "events/block/block_bio_queue/enable" },
202         { OPT,      "events/block/block_bio_complete/enable" },
203         { OPT,      "events/ufs/ufshcd_command/enable" },
204     } },
205     { "mmc",        "eMMC commands",    0, {
206         { REQ,      "events/mmc/enable" },
207     } },
208     { "load",       "CPU Load",         0, {
209         { REQ,      "events/cpufreq_interactive/enable" },
210     } },
211     { "sync",       "Synchronization",  0, {
212         // linux kernel < 4.9
213         { OPT,      "events/sync/enable" },
214         // linux kernel == 4.9.x
215         { OPT,      "events/fence/enable" },
216         // linux kernel > 4.9
217         { OPT,      "events/dma_fence/enable" },
218     } },
219     { "workq",      "Kernel Workqueues", 0, {
220         { REQ,      "events/workqueue/enable" },
221     } },
222     { "memreclaim", "Kernel Memory Reclaim", 0, {
223         { REQ,      "events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
224         { REQ,      "events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
225         { REQ,      "events/vmscan/mm_vmscan_kswapd_wake/enable" },
226         { REQ,      "events/vmscan/mm_vmscan_kswapd_sleep/enable" },
227         { OPT,      "events/lowmemorykiller/enable" },
228     } },
229     { "regulators",  "Voltage and Current Regulators", 0, {
230         { REQ,      "events/regulator/enable" },
231     } },
232     { "binder_driver", "Binder Kernel driver", 0, {
233         { REQ,      "events/binder/binder_transaction/enable" },
234         { REQ,      "events/binder/binder_transaction_received/enable" },
235         { REQ,      "events/binder/binder_transaction_alloc_buf/enable" },
236         { OPT,      "events/binder/binder_set_priority/enable" },
237     } },
238     { "binder_lock", "Binder global lock trace", 0, {
239         { OPT,      "events/binder/binder_lock/enable" },
240         { OPT,      "events/binder/binder_locked/enable" },
241         { OPT,      "events/binder/binder_unlock/enable" },
242     } },
243     { "pagecache",  "Page cache", 0, {
244         { REQ,      "events/filemap/enable" },
245     } },
246     { "memory",  "Memory", 0, {
247         { OPT,      "events/mm_event/mm_event_record/enable" },
248         { OPT,      "events/synthetic/rss_stat_throttled/enable" },
249         { OPT,      "events/kmem/ion_heap_grow/enable" },
250         { OPT,      "events/kmem/ion_heap_shrink/enable" },
251         { OPT,      "events/ion/ion_stat/enable" },
252         { OPT,      "events/gpu_mem/gpu_mem_total/enable" },
253         { OPT,      "events/fastrpc/fastrpc_dma_stat/enable" },
254     } },
255     { "thermal",  "Thermal event", ATRACE_TAG_THERMAL, {
256         { REQ,      "events/thermal/thermal_temperature/enable" },
257         { OPT,      "events/thermal/cdev_update/enable" },
258     } },
259 };
260 
261 // A category in the vendor categories file.
262 struct TracingVendorFileCategory {
263     // The name identifying the category.
264     std::string name;
265 
266     // If the category is enabled through command.
267     bool enabled = false;
268 
269     // Paths to the ftrace enable files (relative to g_traceFolder).
270     std::vector<std::string> ftrace_enable_paths;
271 };
272 
273 // A category in the vendor HIDL HAL.
274 struct TracingVendorHalCategory {
275     // The name identifying the category.
276     std::string name;
277 
278     // A longer description of the category.
279     std::string description;
280 
281     // If the category is enabled through command.
282     bool enabled;
283 
TracingVendorHalCategoryTracingVendorHalCategory284     TracingVendorHalCategory(string&& name, string&& description, bool enabled)
285           : name(std::move(name)), description(std::move(description)), enabled(enabled) {}
286 };
287 
288 /* Command line options */
289 static int g_traceDurationSeconds = 5;
290 static bool g_traceOverwrite = false;
291 static int g_traceBufferSizeKB = 2048;
292 static bool g_compress = false;
293 static bool g_nohup = false;
294 static int g_initialSleepSecs = 0;
295 static const char* g_categoriesFile = nullptr;
296 static const char* g_kernelTraceFuncs = nullptr;
297 static const char* g_debugAppCmdLine = "";
298 static const char* g_outputFile = nullptr;
299 
300 /* Global state */
301 static bool g_tracePdx = false;
302 static bool g_traceAborted = false;
303 static bool g_categoryEnables[arraysize(k_categories)] = {};
304 static std::string g_traceFolder;
305 static std::vector<TracingVendorFileCategory> g_vendorFileCategories;
306 static sp<IAtraceDevice> g_atraceHal;
307 static std::vector<TracingVendorHalCategory> g_vendorHalCategories;
308 
309 /* Sys file paths */
310 static const char* k_traceClockPath =
311     "trace_clock";
312 
313 static const char* k_traceBufferSizePath =
314     "buffer_size_kb";
315 
316 static const char* k_tracingOverwriteEnablePath =
317     "options/overwrite";
318 
319 static const char* k_currentTracerPath =
320     "current_tracer";
321 
322 static const char* k_printTgidPath =
323     "options/print-tgid";
324 
325 static const char* k_recordTgidPath =
326     "options/record-tgid";
327 
328 static const char* k_funcgraphAbsTimePath =
329     "options/funcgraph-abstime";
330 
331 static const char* k_funcgraphCpuPath =
332     "options/funcgraph-cpu";
333 
334 static const char* k_funcgraphProcPath =
335     "options/funcgraph-proc";
336 
337 static const char* k_ftraceFilterPath =
338     "set_ftrace_filter";
339 
340 static const char* k_tracingOnPath =
341     "tracing_on";
342 
343 static const char* k_tracePath =
344     "trace";
345 
346 static const char* k_traceStreamPath =
347     "trace_pipe";
348 
349 static const char* k_traceMarkerPath =
350     "trace_marker";
351 
352 // Check whether a file exists.
fileExists(const char * filename)353 static bool fileExists(const char* filename) {
354     return access((g_traceFolder + filename).c_str(), F_OK) != -1;
355 }
356 
357 // Check whether a file is writable.
fileIsWritable(const char * filename)358 static bool fileIsWritable(const char* filename) {
359     return access((g_traceFolder + filename).c_str(), W_OK) != -1;
360 }
361 
362 // Truncate a file.
truncateFile(const char * path)363 static bool truncateFile(const char* path)
364 {
365     // This uses creat rather than truncate because some of the debug kernel
366     // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
367     // calls to truncate, but they are cleared by calls to creat.
368     int traceFD = creat((g_traceFolder + path).c_str(), 0);
369     if (traceFD == -1) {
370         fprintf(stderr, "error truncating %s: %s (%d)\n", (g_traceFolder + path).c_str(),
371             strerror(errno), errno);
372         return false;
373     }
374 
375     close(traceFD);
376 
377     return true;
378 }
379 
_writeStr(const char * filename,const char * str,int flags)380 static bool _writeStr(const char* filename, const char* str, int flags)
381 {
382     std::string fullFilename = g_traceFolder + filename;
383     int fd = open(fullFilename.c_str(), flags);
384     if (fd == -1) {
385         fprintf(stderr, "error opening %s: %s (%d)\n", fullFilename.c_str(),
386                 strerror(errno), errno);
387         return false;
388     }
389 
390     bool ok = true;
391     ssize_t len = strlen(str);
392     if (write(fd, str, len) != len) {
393         fprintf(stderr, "error writing to %s: %s (%d)\n", fullFilename.c_str(),
394                 strerror(errno), errno);
395         ok = false;
396     }
397 
398     close(fd);
399 
400     return ok;
401 }
402 
403 // Write a string to a file, returning true if the write was successful.
writeStr(const char * filename,const char * str)404 static bool writeStr(const char* filename, const char* str)
405 {
406     return _writeStr(filename, str, O_WRONLY);
407 }
408 
409 // Append a string to a file, returning true if the write was successful.
appendStr(const char * filename,const char * str)410 static bool appendStr(const char* filename, const char* str)
411 {
412     return _writeStr(filename, str, O_APPEND|O_WRONLY);
413 }
414 
writeClockSyncMarker()415 static void writeClockSyncMarker()
416 {
417   char buffer[128];
418   int len = 0;
419   int fd = open((g_traceFolder + k_traceMarkerPath).c_str(), O_WRONLY);
420   if (fd == -1) {
421       fprintf(stderr, "error opening %s: %s (%d)\n", k_traceMarkerPath,
422               strerror(errno), errno);
423       return;
424   }
425   float now_in_seconds = systemTime(CLOCK_MONOTONIC) / 1000000000.0f;
426 
427   len = snprintf(buffer, 128, "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds);
428   if (write(fd, buffer, len) != len) {
429       fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno);
430   }
431 
432   int64_t realtime_in_ms = systemTime(CLOCK_REALTIME) / 1000000;
433   len = snprintf(buffer, 128, "trace_event_clock_sync: realtime_ts=%" PRId64 "\n", realtime_in_ms);
434   if (write(fd, buffer, len) != len) {
435       fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno);
436   }
437 
438   close(fd);
439 }
440 
441 // Enable or disable a kernel option by writing a "1" or a "0" into a /sys
442 // file.
setKernelOptionEnable(const char * filename,bool enable)443 static bool setKernelOptionEnable(const char* filename, bool enable)
444 {
445     return writeStr(filename, enable ? "1" : "0");
446 }
447 
448 // Check whether the category is supported on the device with the current
449 // rootness.  A category is supported only if all its required /sys/ files are
450 // writable and if enabling the category will enable one or more tracing tags
451 // or /sys/ files.
isCategorySupported(const TracingCategory & category)452 static bool isCategorySupported(const TracingCategory& category)
453 {
454     if (strcmp(category.name, k_coreServiceCategory) == 0) {
455         return !android::base::GetProperty(k_coreServicesProp, "").empty();
456     }
457 
458     if (strcmp(category.name, k_pdxServiceCategory) == 0) {
459         return true;
460     }
461 
462     bool ok = category.tags != 0;
463     for (int i = 0; i < MAX_SYS_FILES; i++) {
464         const char* path = category.sysfiles[i].path;
465         bool req = category.sysfiles[i].required == REQ;
466         if (path != nullptr) {
467             if (fileIsWritable(path)) {
468                 ok = true;
469             } else if (req) {
470                 return false;
471             }
472         }
473     }
474     return ok;
475 }
476 
477 // Check whether the category would be supported on the device if the user
478 // were root.  This function assumes that root is able to write to any file
479 // that exists.  It performs the same logic as isCategorySupported, but it
480 // uses file existence rather than writability in the /sys/ file checks.
isCategorySupportedForRoot(const TracingCategory & category)481 static bool isCategorySupportedForRoot(const TracingCategory& category)
482 {
483     bool ok = category.tags != 0;
484     for (int i = 0; i < MAX_SYS_FILES; i++) {
485         const char* path = category.sysfiles[i].path;
486         bool req = category.sysfiles[i].required == REQ;
487         if (path != nullptr) {
488             if (req) {
489                 if (!fileExists(path)) {
490                     return false;
491                 } else {
492                     ok = true;
493                 }
494             } else {
495                 ok |= fileExists(path);
496             }
497         }
498     }
499     return ok;
500 }
501 
502 // Enable or disable overwriting of the kernel trace buffers.  Disabling this
503 // will cause tracing to stop once the trace buffers have filled up.
setTraceOverwriteEnable(bool enable)504 static bool setTraceOverwriteEnable(bool enable)
505 {
506     return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
507 }
508 
509 // Set the user initiated trace property
setUserInitiatedTraceProperty(bool enable)510 static bool setUserInitiatedTraceProperty(bool enable)
511 {
512     if (!android::base::SetProperty(k_userInitiatedTraceProperty, enable ? "1" : "")) {
513         fprintf(stderr, "error setting user initiated strace system property\n");
514         return false;
515     }
516     return true;
517 }
518 
519 // Enable or disable kernel tracing.
setTracingEnabled(bool enable)520 static bool setTracingEnabled(bool enable)
521 {
522     return setKernelOptionEnable(k_tracingOnPath, enable);
523 }
524 
525 // Clear the contents of the kernel trace.
clearTrace()526 static bool clearTrace()
527 {
528     return truncateFile(k_tracePath);
529 }
530 
531 // Set the size of the kernel's trace buffer in kilobytes.
setTraceBufferSizeKB(int size)532 static bool setTraceBufferSizeKB(int size)
533 {
534     char str[32] = "1";
535     if (size < 1) {
536         size = 1;
537     }
538     snprintf(str, 32, "%d", size);
539     return writeStr(k_traceBufferSizePath, str);
540 }
541 
542 // Set the clock to the best available option while tracing. Use 'boot' if it's
543 // available; otherwise, use 'mono'. If neither are available use 'global'.
544 // Any write to the trace_clock sysfs file will reset the buffer, so only
545 // update it if the requested value is not the current value.
setClock()546 static bool setClock()
547 {
548     std::ifstream clockFile((g_traceFolder + k_traceClockPath).c_str(), O_RDONLY);
549     std::string clockStr((std::istreambuf_iterator<char>(clockFile)),
550         std::istreambuf_iterator<char>());
551 
552     std::string newClock;
553     if (clockStr.find("boot") != std::string::npos) {
554         newClock = "boot";
555     } else if (clockStr.find("mono") != std::string::npos) {
556         newClock = "mono";
557     } else {
558         newClock = "global";
559     }
560 
561     size_t begin = clockStr.find('[') + 1;
562     size_t end = clockStr.find(']');
563     if (newClock.compare(0, std::string::npos, clockStr, begin, end-begin) == 0) {
564         return true;
565     }
566     return writeStr(k_traceClockPath, newClock.c_str());
567 }
568 
setPrintTgidEnableIfPresent(bool enable)569 static bool setPrintTgidEnableIfPresent(bool enable)
570 {
571     // Pre-4.13 this was options/print-tgid as an android-specific option.
572     // In 4.13+ this is an upstream option called options/record-tgid
573     // Both options produce the same ftrace format change
574     if (fileExists(k_printTgidPath)) {
575         return setKernelOptionEnable(k_printTgidPath, enable);
576     }
577     if (fileExists(k_recordTgidPath)) {
578         return setKernelOptionEnable(k_recordTgidPath, enable);
579     }
580     return true;
581 }
582 
583 // Set the trace tags that userland tracing uses, and poke the running
584 // processes to pick up the new value.
setTagsProperty(uint64_t tags)585 static bool setTagsProperty(uint64_t tags)
586 {
587     std::string value = android::base::StringPrintf("%#" PRIx64, tags);
588     if (!android::base::SetProperty(k_traceTagsProperty, value)) {
589         fprintf(stderr, "error setting trace tags system property\n");
590         return false;
591     }
592     return true;
593 }
594 
clearAppProperties()595 static void clearAppProperties()
596 {
597     if (!android::base::SetProperty(k_traceAppsNumberProperty, "")) {
598         fprintf(stderr, "failed to clear system property: %s",
599               k_traceAppsNumberProperty);
600     }
601 }
602 
603 // Set the system property that indicates which apps should perform
604 // application-level tracing.
setAppCmdlineProperty(char * cmdline)605 static bool setAppCmdlineProperty(char* cmdline)
606 {
607     int i = 0;
608     char* start = cmdline;
609     while (start != nullptr) {
610         char* end = strchr(start, ',');
611         if (end != nullptr) {
612             *end = '\0';
613             end++;
614         }
615         std::string key = android::base::StringPrintf(k_traceAppsPropertyTemplate, i);
616         if (!android::base::SetProperty(key, start)) {
617             fprintf(stderr, "error setting trace app %d property to %s\n", i, key.c_str());
618             clearAppProperties();
619             return false;
620         }
621         start = end;
622         i++;
623     }
624 
625     std::string value = android::base::StringPrintf("%d", i);
626     if (!android::base::SetProperty(k_traceAppsNumberProperty, value)) {
627         fprintf(stderr, "error setting trace app number property to %s\n", value.c_str());
628         clearAppProperties();
629         return false;
630     }
631     return true;
632 }
633 
634 // Disable all /sys/ enable files.
disableKernelTraceEvents()635 static bool disableKernelTraceEvents() {
636     bool ok = true;
637     for (size_t i = 0; i < arraysize(k_categories); i++) {
638         const TracingCategory &c = k_categories[i];
639         for (int j = 0; j < MAX_SYS_FILES; j++) {
640             const char* path = c.sysfiles[j].path;
641             if (path != nullptr && fileIsWritable(path)) {
642                 ok &= setKernelOptionEnable(path, false);
643             }
644         }
645     }
646     for (const TracingVendorFileCategory& c : g_vendorFileCategories) {
647         for (const std::string& path : c.ftrace_enable_paths) {
648             if (fileIsWritable(path.c_str())) {
649                 ok &= setKernelOptionEnable(path.c_str(), false);
650             }
651         }
652     }
653     return ok;
654 }
655 
656 // Verify that the comma separated list of functions are being traced by the
657 // kernel.
verifyKernelTraceFuncs(const char * funcs)658 static bool verifyKernelTraceFuncs(const char* funcs)
659 {
660     std::string buf;
661     if (!android::base::ReadFileToString(g_traceFolder + k_ftraceFilterPath, &buf)) {
662          fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
663             strerror(errno), errno);
664          return false;
665     }
666 
667     String8 funcList = String8::format("\n%s",buf.c_str());
668 
669     // Make sure that every function listed in funcs is in the list we just
670     // read from the kernel, except for wildcard inputs.
671     bool ok = true;
672     char* myFuncs = strdup(funcs);
673     char* func = strtok(myFuncs, ",");
674     while (func) {
675         if (!strchr(func, '*')) {
676             String8 fancyFunc = String8::format("\n%s\n", func);
677             bool found = funcList.find(fancyFunc.c_str(), 0) >= 0;
678             if (!found || func[0] == '\0') {
679                 fprintf(stderr, "error: \"%s\" is not a valid kernel function "
680                         "to trace.\n", func);
681                 ok = false;
682             }
683         }
684         func = strtok(nullptr, ",");
685     }
686     free(myFuncs);
687     return ok;
688 }
689 
690 // Set the comma separated list of functions that the kernel is to trace.
setKernelTraceFuncs(const char * funcs)691 static bool setKernelTraceFuncs(const char* funcs)
692 {
693     bool ok = true;
694 
695     if (funcs == nullptr || funcs[0] == '\0') {
696         // Disable kernel function tracing.
697         if (fileIsWritable(k_currentTracerPath)) {
698             ok &= writeStr(k_currentTracerPath, "nop");
699         }
700         if (fileIsWritable(k_ftraceFilterPath)) {
701             ok &= truncateFile(k_ftraceFilterPath);
702         }
703     } else {
704         // Enable kernel function tracing.
705         ok &= writeStr(k_currentTracerPath, "function_graph");
706         ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
707         ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
708         ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
709 
710         // Set the requested filter functions.
711         ok &= truncateFile(k_ftraceFilterPath);
712         char* myFuncs = strdup(funcs);
713         char* func = strtok(myFuncs, ",");
714         while (func) {
715             ok &= appendStr(k_ftraceFilterPath, func);
716             func = strtok(nullptr, ",");
717         }
718         free(myFuncs);
719 
720         // Verify that the set functions are being traced.
721         if (ok) {
722             ok &= verifyKernelTraceFuncs(funcs);
723         }
724     }
725 
726     return ok;
727 }
728 
setCategoryEnable(const char * name)729 static bool setCategoryEnable(const char* name)
730 {
731     bool vendor_found = false;
732     for (auto& c : g_vendorFileCategories) {
733         if (strcmp(name, c.name.c_str()) == 0) {
734             c.enabled = true;
735             vendor_found = true;
736         }
737     }
738     for (auto& c : g_vendorHalCategories) {
739         if (strcmp(name, c.name.c_str()) == 0) {
740             c.enabled = true;
741             vendor_found = true;
742         }
743     }
744     for (size_t i = 0; i < arraysize(k_categories); i++) {
745         const TracingCategory& c = k_categories[i];
746         if (strcmp(name, c.name) == 0) {
747             if (isCategorySupported(c)) {
748                 g_categoryEnables[i] = true;
749                 return true;
750             } else {
751                 if (isCategorySupportedForRoot(c)) {
752                     fprintf(stderr, "error: category \"%s\" requires root "
753                             "privileges.\n", name);
754                 } else {
755                     fprintf(stderr, "error: category \"%s\" is not supported "
756                             "on this device.\n", name);
757                 }
758                 return false;
759             }
760         }
761     }
762     if (vendor_found) {
763         return true;
764     }
765     fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
766     return false;
767 }
768 
setCategoriesEnableFromFile(const char * categories_file)769 static bool setCategoriesEnableFromFile(const char* categories_file)
770 {
771     if (!categories_file) {
772         return true;
773     }
774     Tokenizer* tokenizer = nullptr;
775     if (Tokenizer::open(String8(categories_file), &tokenizer) != NO_ERROR) {
776         return false;
777     }
778     bool ok = true;
779     while (!tokenizer->isEol()) {
780         String8 token = tokenizer->nextToken(" ");
781         if (token.empty()) {
782             tokenizer->skipDelimiters(" ");
783             continue;
784         }
785         ok &= setCategoryEnable(token.c_str());
786     }
787     delete tokenizer;
788     return ok;
789 }
790 
setUpUserspaceTracing()791 static bool setUpUserspaceTracing()
792 {
793     bool ok = true;
794 
795     // Set up the tags property.
796     uint64_t tags = 0;
797     for (size_t i = 0; i < arraysize(k_categories); i++) {
798         if (g_categoryEnables[i]) {
799             const TracingCategory &c = k_categories[i];
800             tags |= c.tags;
801         }
802     }
803 
804     bool coreServicesTagEnabled = false;
805     for (size_t i = 0; i < arraysize(k_categories); i++) {
806         if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) {
807             coreServicesTagEnabled = g_categoryEnables[i];
808         }
809 
810         // Set whether to poke PDX services in this session.
811         if (strcmp(k_categories[i].name, k_pdxServiceCategory) == 0) {
812             g_tracePdx = g_categoryEnables[i];
813         }
814     }
815 
816     std::string packageList(g_debugAppCmdLine);
817     if (coreServicesTagEnabled) {
818         if (!packageList.empty()) {
819             packageList += ",";
820         }
821         packageList += android::base::GetProperty(k_coreServicesProp, "");
822     }
823     ok &= setAppCmdlineProperty(&packageList[0]);
824     ok &= setTagsProperty(tags);
825     if (g_tracePdx) {
826         ok &= ServiceUtility::PokeServices();
827     }
828 
829     return ok;
830 }
831 
cleanUpUserspaceTracing()832 static void cleanUpUserspaceTracing()
833 {
834     setTagsProperty(0);
835     clearAppProperties();
836 
837     if (g_tracePdx) {
838         ServiceUtility::PokeServices();
839     }
840 }
841 
842 
843 // Set all the kernel tracing settings to the desired state for this trace
844 // capture.
setUpKernelTracing()845 static bool setUpKernelTracing()
846 {
847     bool ok = true;
848 
849     ok &= setUserInitiatedTraceProperty(true);
850 
851     // Set up the tracing options.
852     ok &= setCategoriesEnableFromFile(g_categoriesFile);
853     ok &= setTraceOverwriteEnable(g_traceOverwrite);
854     ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
855     ok &= setClock();
856     ok &= setPrintTgidEnableIfPresent(true);
857     ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
858 
859     // Disable all the sysfs enables.  This is done as a separate loop from
860     // the enables to allow the same enable to exist in multiple categories.
861     ok &= disableKernelTraceEvents();
862 
863     // Enable all the sysfs enables that are in an enabled category.
864     for (size_t i = 0; i < arraysize(k_categories); i++) {
865         if (g_categoryEnables[i]) {
866             const TracingCategory &c = k_categories[i];
867             for (int j = 0; j < MAX_SYS_FILES; j++) {
868                 const char* path = c.sysfiles[j].path;
869                 bool required = c.sysfiles[j].required == REQ;
870                 if (path != nullptr) {
871                     if (fileIsWritable(path)) {
872                         ok &= setKernelOptionEnable(path, true);
873                     } else if (required) {
874                         fprintf(stderr, "error writing file %s\n", path);
875                         ok = false;
876                     }
877                 }
878             }
879         }
880     }
881 
882     for (const TracingVendorFileCategory& c : g_vendorFileCategories) {
883         if (c.enabled) {
884             for (const std::string& path : c.ftrace_enable_paths) {
885                 if (fileIsWritable(path.c_str())) {
886                     ok &= setKernelOptionEnable(path.c_str(), true);
887                 }
888             }
889         }
890     }
891 
892     return ok;
893 }
894 
895 // Reset all the kernel tracing settings to their default state.
cleanUpKernelTracing()896 static void cleanUpKernelTracing()
897 {
898     // Disable all tracing that we're able to.
899     disableKernelTraceEvents();
900 
901     // Set the options back to their defaults.
902     setTraceOverwriteEnable(true);
903     setTraceBufferSizeKB(1);
904     setPrintTgidEnableIfPresent(false);
905     setKernelTraceFuncs(nullptr);
906     setUserInitiatedTraceProperty(false);
907 }
908 
909 // Enable tracing in the kernel.
startTrace()910 static bool startTrace()
911 {
912     return setTracingEnabled(true);
913 }
914 
915 // Disable tracing in the kernel.
stopTrace()916 static void stopTrace()
917 {
918     setTracingEnabled(false);
919 }
920 
921 // Read data from the tracing pipe and forward to stdout
streamTrace()922 static void streamTrace()
923 {
924     char trace_data[4096];
925     int traceFD = open((g_traceFolder + k_traceStreamPath).c_str(), O_RDWR);
926     if (traceFD == -1) {
927         fprintf(stderr, "error opening %s: %s (%d)\n", k_traceStreamPath,
928                 strerror(errno), errno);
929         return;
930     }
931     while (!g_traceAborted) {
932         ssize_t bytes_read = read(traceFD, trace_data, 4096);
933         if (bytes_read > 0) {
934             write(STDOUT_FILENO, trace_data, bytes_read);
935             fflush(stdout);
936         } else {
937             if (!g_traceAborted) {
938                 fprintf(stderr, "read returned %zd bytes err %d (%s)\n",
939                         bytes_read, errno, strerror(errno));
940             }
941             break;
942         }
943     }
944 }
945 
946 // Read the current kernel trace and write it to stdout.
dumpTrace(int outFd)947 static void dumpTrace(int outFd)
948 {
949     ALOGI("Dumping trace");
950     int traceFD = open((g_traceFolder + k_tracePath).c_str(), O_RDWR);
951     if (traceFD == -1) {
952         fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
953                 strerror(errno), errno);
954         return;
955     }
956 
957     if (g_compress) {
958         z_stream zs;
959         memset(&zs, 0, sizeof(zs));
960 
961         int result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
962         if (result != Z_OK) {
963             fprintf(stderr, "error initializing zlib: %d\n", result);
964             close(traceFD);
965             return;
966         }
967 
968         constexpr size_t bufSize = 64*1024;
969         std::unique_ptr<uint8_t> in(new uint8_t[bufSize]);
970         std::unique_ptr<uint8_t> out(new uint8_t[bufSize]);
971         if (!in || !out) {
972             fprintf(stderr, "couldn't allocate buffers\n");
973             close(traceFD);
974             return;
975         }
976 
977         int flush = Z_NO_FLUSH;
978 
979         zs.next_out = reinterpret_cast<Bytef*>(out.get());
980         zs.avail_out = bufSize;
981 
982         do {
983 
984             if (zs.avail_in == 0) {
985                 // More input is needed.
986                 result = read(traceFD, in.get(), bufSize);
987                 if (result < 0) {
988                     fprintf(stderr, "error reading trace: %s (%d)\n",
989                             strerror(errno), errno);
990                     result = Z_STREAM_END;
991                     break;
992                 } else if (result == 0) {
993                     flush = Z_FINISH;
994                 } else {
995                     zs.next_in = reinterpret_cast<Bytef*>(in.get());
996                     zs.avail_in = result;
997                 }
998             }
999 
1000             if (zs.avail_out == 0) {
1001                 // Need to write the output.
1002                 result = write(outFd, out.get(), bufSize);
1003                 if ((size_t)result < bufSize) {
1004                     fprintf(stderr, "error writing deflated trace: %s (%d)\n",
1005                             strerror(errno), errno);
1006                     result = Z_STREAM_END; // skip deflate error message
1007                     zs.avail_out = bufSize; // skip the final write
1008                     break;
1009                 }
1010                 zs.next_out = reinterpret_cast<Bytef*>(out.get());
1011                 zs.avail_out = bufSize;
1012             }
1013 
1014         } while ((result = deflate(&zs, flush)) == Z_OK);
1015 
1016         if (result != Z_STREAM_END) {
1017             fprintf(stderr, "error deflating trace: %s\n", zs.msg);
1018         }
1019 
1020         if (zs.avail_out < bufSize) {
1021             size_t bytes = bufSize - zs.avail_out;
1022             result = write(outFd, out.get(), bytes);
1023             if ((size_t)result < bytes) {
1024                 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
1025                         strerror(errno), errno);
1026             }
1027         }
1028 
1029         result = deflateEnd(&zs);
1030         if (result != Z_OK) {
1031             fprintf(stderr, "error cleaning up zlib: %d\n", result);
1032         }
1033     } else {
1034         char buf[4096];
1035         ssize_t rc;
1036         while ((rc = TEMP_FAILURE_RETRY(read(traceFD, buf, sizeof(buf)))) > 0) {
1037             if (!android::base::WriteFully(outFd, buf, rc)) {
1038                 fprintf(stderr, "error writing trace: %s\n", strerror(errno));
1039                 break;
1040             }
1041         }
1042         if (rc == -1) {
1043             fprintf(stderr, "error dumping trace: %s\n", strerror(errno));
1044         }
1045     }
1046 
1047     close(traceFD);
1048 }
1049 
handleSignal(int)1050 static void handleSignal(int /*signo*/)
1051 {
1052     if (!g_nohup) {
1053         g_traceAborted = true;
1054     }
1055 }
1056 
registerSigHandler()1057 static void registerSigHandler()
1058 {
1059     struct sigaction sa;
1060     sigemptyset(&sa.sa_mask);
1061     sa.sa_flags = 0;
1062     sa.sa_handler = handleSignal;
1063     sigaction(SIGHUP, &sa, nullptr);
1064     sigaction(SIGINT, &sa, nullptr);
1065     sigaction(SIGQUIT, &sa, nullptr);
1066     sigaction(SIGTERM, &sa, nullptr);
1067 }
1068 
listSupportedCategories()1069 static void listSupportedCategories()
1070 {
1071     for (size_t i = 0; i < arraysize(k_categories); i++) {
1072         const TracingCategory& c = k_categories[i];
1073         if (isCategorySupported(c)) {
1074             printf("  %10s - %s\n", c.name, c.longname);
1075         }
1076     }
1077     for (const auto& c : g_vendorFileCategories) {
1078         printf("  %10s - (VENDOR)\n", c.name.c_str());
1079     }
1080     for (const auto& c : g_vendorHalCategories) {
1081         printf("  %10s - %s (HAL)\n", c.name.c_str(), c.description.c_str());
1082     }
1083 }
1084 
1085 // Print the command usage help to stderr.
showHelp(const char * cmd)1086 static void showHelp(const char *cmd)
1087 {
1088     fprintf(stderr, "usage: %s [options] [categories...]\n", cmd);
1089     fprintf(stderr, "options include:\n"
1090                     "  -a appname      enable app-level tracing for a comma "
1091                         "separated list of cmdlines; * is a wildcard matching any process\n"
1092                     "  -b N            use a trace buffer size of N KB\n"
1093                     "  -c              trace into a circular buffer\n"
1094                     "  -f filename     use the categories written in a file as space-separated\n"
1095                     "                    values in a line\n"
1096                     "  -k fname,...    trace the listed kernel functions\n"
1097                     "  -n              ignore signals\n"
1098                     "  -s N            sleep for N seconds before tracing [default 0]\n"
1099                     "  -t N            trace for N seconds [default 5]\n"
1100                     "  -z              compress the trace dump\n"
1101                     "  --async_start   start circular trace and return immediately\n"
1102                     "  --async_dump    dump the current contents of circular trace buffer\n"
1103                     "  --async_stop    stop tracing and dump the current contents of circular\n"
1104                     "                    trace buffer\n"
1105                     "  --stream        stream trace to stdout as it enters the trace buffer\n"
1106                     "                    Note: this can take significant CPU time, and is best\n"
1107                     "                    used for measuring things that are not affected by\n"
1108                     "                    CPU performance, like pagecache usage.\n"
1109                     "  --list_categories\n"
1110                     "                  list the available tracing categories\n"
1111                     " -o filename      write the trace to the specified file instead\n"
1112                     "                    of stdout.\n"
1113             );
1114 }
1115 
findTraceFiles()1116 bool findTraceFiles()
1117 {
1118     static const std::string debugfs_path = "/sys/kernel/debug/tracing/";
1119     static const std::string tracefs_path = "/sys/kernel/tracing/";
1120     static const std::string trace_file = "trace_marker";
1121 
1122     bool tracefs = access((tracefs_path + trace_file).c_str(), F_OK) != -1;
1123     bool debugfs = access((debugfs_path + trace_file).c_str(), F_OK) != -1;
1124 
1125     if (!tracefs && !debugfs) {
1126         fprintf(stderr, "Error: Did not find trace folder\n");
1127         return false;
1128     }
1129 
1130     if (tracefs) {
1131         g_traceFolder = tracefs_path;
1132     } else {
1133         g_traceFolder = debugfs_path;
1134     }
1135 
1136     return true;
1137 }
1138 
initVendorCategoriesFromFile()1139 void initVendorCategoriesFromFile() {
1140     std::ifstream is(kVendorCategoriesPath);
1141     for (std::string line; std::getline(is, line);) {
1142         if (line.empty()) {
1143             continue;
1144         }
1145         if (android::base::StartsWith(line, ' ') || android::base::StartsWith(line, '\t')) {
1146             if (g_vendorFileCategories.empty()) {
1147                 fprintf(stderr, "Malformed vendor categories file\n");
1148                 exit(1);
1149                 return;
1150             }
1151             std::string_view path = std::string_view(line).substr(1);
1152             while (android::base::StartsWith(path, ' ') || android::base::StartsWith(path, '\t')) {
1153                 path.remove_prefix(1);
1154             }
1155             if (path.empty()) {
1156                 continue;
1157             }
1158             std::string enable_path = "events/";
1159             enable_path += path;
1160             enable_path += "/enable";
1161             g_vendorFileCategories.back().ftrace_enable_paths.push_back(std::move(enable_path));
1162         } else {
1163             TracingVendorFileCategory cat;
1164             cat.name = line;
1165             g_vendorFileCategories.push_back(std::move(cat));
1166         }
1167     }
1168 }
1169 
initVendorCategoriesFromHal()1170 void initVendorCategoriesFromHal() {
1171     g_atraceHal = IAtraceDevice::getService();
1172 
1173     if (g_atraceHal == nullptr) {
1174         // No atrace HAL
1175         return;
1176     }
1177 
1178     Return<void> ret = g_atraceHal->listCategories([](const auto& list) {
1179         g_vendorHalCategories.reserve(list.size());
1180         for (const auto& category : list) {
1181             g_vendorHalCategories.emplace_back(category.name, category.description, false);
1182         }
1183     });
1184     if (!ret.isOk()) {
1185         fprintf(stderr, "calling atrace HAL failed: %s\n", ret.description().c_str());
1186     }
1187 }
1188 
initVendorCategories()1189 void initVendorCategories() {
1190     // If kVendorCategoriesPath exists on the filesystem, do not use the HAL.
1191     if (access(kVendorCategoriesPath, F_OK) != -1) {
1192         initVendorCategoriesFromFile();
1193     } else {
1194         initVendorCategoriesFromHal();
1195     }
1196 }
1197 
setUpVendorTracingWithHal()1198 static bool setUpVendorTracingWithHal() {
1199     if (g_atraceHal == nullptr) {
1200         // No atrace HAL
1201         return true;
1202     }
1203 
1204     std::vector<hidl_string> categories;
1205     for (const auto& c : g_vendorHalCategories) {
1206         if (c.enabled) {
1207             categories.emplace_back(c.name);
1208         }
1209     }
1210 
1211     if (!categories.size()) {
1212         return true;
1213     }
1214 
1215     auto ret = g_atraceHal->enableCategories(categories);
1216     if (!ret.isOk()) {
1217         fprintf(stderr, "calling atrace HAL failed: %s\n", ret.description().c_str());
1218         return false;
1219     } else if (ret != Status::SUCCESS) {
1220         fprintf(stderr, "calling atrace HAL failed: %s\n", toString(ret).c_str());
1221         return false;
1222     }
1223     return true;
1224 }
1225 
cleanUpVendorTracingWithHal()1226 static bool cleanUpVendorTracingWithHal() {
1227     if (g_atraceHal == nullptr) {
1228         // No atrace HAL
1229         return true;
1230     }
1231 
1232     if (!g_vendorHalCategories.size()) {
1233         // No vendor HAL categories
1234         return true;
1235     }
1236 
1237     auto ret = g_atraceHal->disableAllCategories();
1238     if (!ret.isOk()) {
1239         fprintf(stderr, "calling atrace HAL failed: %s\n", ret.description().c_str());
1240         return false;
1241     } else if (ret != Status::SUCCESS) {
1242         fprintf(stderr, "calling atrace HAL failed: %s\n", toString(ret).c_str());
1243         return false;
1244     }
1245     return true;
1246 }
1247 
main(int argc,char ** argv)1248 int main(int argc, char **argv)
1249 {
1250     bool async = false;
1251     bool traceStart = true;
1252     bool traceStop = true;
1253     bool traceDump = true;
1254     bool traceStream = false;
1255     bool onlyUserspace = false;
1256 
1257     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
1258         showHelp(argv[0]);
1259         exit(0);
1260     }
1261 
1262     if (!findTraceFiles()) {
1263         fprintf(stderr, "No trace folder found\n");
1264         exit(-1);
1265     }
1266 
1267     initVendorCategories();
1268 
1269     for (;;) {
1270         int ret;
1271         int option_index = 0;
1272         static struct option long_options[] = {
1273             {"async_start",       no_argument, nullptr,  0 },
1274             {"async_stop",        no_argument, nullptr,  0 },
1275             {"async_dump",        no_argument, nullptr,  0 },
1276             {"only_userspace",    no_argument, nullptr,  0 },
1277             {"list_categories",   no_argument, nullptr,  0 },
1278             {"stream",            no_argument, nullptr,  0 },
1279             {nullptr,                       0, nullptr,  0 }
1280         };
1281 
1282         ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:",
1283                           long_options, &option_index);
1284 
1285         if (ret < 0) {
1286             for (int i = optind; i < argc; i++) {
1287                 setCategoryEnable(argv[i]);
1288             }
1289             break;
1290         }
1291 
1292         switch(ret) {
1293             case 'a':
1294                 g_debugAppCmdLine = optarg;
1295             break;
1296 
1297             case 'b':
1298                 g_traceBufferSizeKB = atoi(optarg);
1299             break;
1300 
1301             case 'c':
1302                 g_traceOverwrite = true;
1303             break;
1304 
1305             case 'f':
1306                 g_categoriesFile = optarg;
1307             break;
1308 
1309             case 'k':
1310                 g_kernelTraceFuncs = optarg;
1311             break;
1312 
1313             case 'n':
1314                 g_nohup = true;
1315             break;
1316 
1317             case 's':
1318                 g_initialSleepSecs = atoi(optarg);
1319             break;
1320 
1321             case 't':
1322                 g_traceDurationSeconds = atoi(optarg);
1323             break;
1324 
1325             case 'z':
1326                 g_compress = true;
1327             break;
1328 
1329             case 'o':
1330                 g_outputFile = optarg;
1331             break;
1332 
1333             case 0:
1334                 if (!strcmp(long_options[option_index].name, "async_start")) {
1335                     async = true;
1336                     traceStop = false;
1337                     traceDump = false;
1338                     g_traceOverwrite = true;
1339                 } else if (!strcmp(long_options[option_index].name, "async_stop")) {
1340                     async = true;
1341                     traceStart = false;
1342                 } else if (!strcmp(long_options[option_index].name, "async_dump")) {
1343                     async = true;
1344                     traceStart = false;
1345                     traceStop = false;
1346                 } else if (!strcmp(long_options[option_index].name, "only_userspace")) {
1347                     onlyUserspace = true;
1348                 } else if (!strcmp(long_options[option_index].name, "stream")) {
1349                     traceStream = true;
1350                     traceDump = false;
1351                 } else if (!strcmp(long_options[option_index].name, "list_categories")) {
1352                     listSupportedCategories();
1353                     exit(0);
1354                 }
1355             break;
1356 
1357             default:
1358                 fprintf(stderr, "\n");
1359                 showHelp(argv[0]);
1360                 exit(-1);
1361             break;
1362         }
1363     }
1364 
1365     if (onlyUserspace) {
1366         if (!async || !(traceStart || traceStop)) {
1367             fprintf(stderr, "--only_userspace can only be used with "
1368                     "--async_start or --async_stop\n");
1369             exit(1);
1370         }
1371     }
1372 
1373     registerSigHandler();
1374 
1375     if (g_initialSleepSecs > 0) {
1376         sleep(g_initialSleepSecs);
1377     }
1378 
1379     bool ok = true;
1380 
1381     if (traceStart) {
1382         ok &= setUpUserspaceTracing();
1383     }
1384 
1385     if (ok && traceStart && !onlyUserspace) {
1386         ok &= setUpKernelTracing();
1387         ok &= setUpVendorTracingWithHal();
1388         ok &= startTrace();
1389     }
1390 
1391     if (ok && traceStart) {
1392 
1393         if (!traceStream && !onlyUserspace) {
1394             printf("capturing trace...");
1395             fflush(stdout);
1396         }
1397 
1398         // We clear the trace after starting it because tracing gets enabled for
1399         // each CPU individually in the kernel. Having the beginning of the trace
1400         // contain entries from only one CPU can cause "begin" entries without a
1401         // matching "end" entry to show up if a task gets migrated from one CPU to
1402         // another.
1403         if (!onlyUserspace) {
1404             ok = clearTrace();
1405             writeClockSyncMarker();
1406         }
1407         if (ok && !async && !traceStream) {
1408             // Sleep to allow the trace to be captured.
1409             struct timespec timeLeft;
1410             timeLeft.tv_sec = g_traceDurationSeconds;
1411             timeLeft.tv_nsec = 0;
1412             do {
1413                 if (g_traceAborted) {
1414                     break;
1415                 }
1416             } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
1417         }
1418 
1419         if (traceStream) {
1420             streamTrace();
1421         }
1422     }
1423 
1424     // Stop the trace and restore the default settings.
1425     if (traceStop && !onlyUserspace)
1426         stopTrace();
1427 
1428     if (ok && traceDump && !onlyUserspace) {
1429         if (!g_traceAborted) {
1430             printf(" done\n");
1431             fflush(stdout);
1432             int outFd = STDOUT_FILENO;
1433             if (g_outputFile) {
1434                 outFd = open(g_outputFile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1435             }
1436             if (outFd == -1) {
1437                 printf("Failed to open '%s', err=%d", g_outputFile, errno);
1438             } else {
1439                 dprintf(outFd, "TRACE:\n");
1440                 dumpTrace(outFd);
1441                 if (g_outputFile) {
1442                     close(outFd);
1443                 }
1444             }
1445         } else {
1446             printf("\ntrace aborted.\n");
1447             fflush(stdout);
1448         }
1449         clearTrace();
1450     } else if (!ok) {
1451         fprintf(stderr, "unable to start tracing\n");
1452     }
1453 
1454     // Reset the trace buffer size to 1.
1455     if (traceStop) {
1456         cleanUpUserspaceTracing();
1457         if (!onlyUserspace) {
1458             cleanUpVendorTracingWithHal();
1459             cleanUpKernelTracing();
1460         }
1461     }
1462 
1463     return g_traceAborted ? 1 : 0;
1464 }
1465