• 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 <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 #if 0
317 // TODO: Re-enable after stabilization
318 static const char* k_traceCmdlineSizePath =
319     "saved_cmdlines_size";
320 #endif
321 
322 static const char* k_tracingOverwriteEnablePath =
323     "options/overwrite";
324 
325 static const char* k_currentTracerPath =
326     "current_tracer";
327 
328 static const char* k_printTgidPath =
329     "options/print-tgid";
330 
331 static const char* k_recordTgidPath =
332     "options/record-tgid";
333 
334 static const char* k_funcgraphAbsTimePath =
335     "options/funcgraph-abstime";
336 
337 static const char* k_funcgraphCpuPath =
338     "options/funcgraph-cpu";
339 
340 static const char* k_funcgraphProcPath =
341     "options/funcgraph-proc";
342 
343 static const char* k_ftraceFilterPath =
344     "set_ftrace_filter";
345 
346 static const char* k_tracingOnPath =
347     "tracing_on";
348 
349 static const char* k_tracePath =
350     "trace";
351 
352 static const char* k_traceStreamPath =
353     "trace_pipe";
354 
355 static const char* k_traceMarkerPath =
356     "trace_marker";
357 
358 // Check whether a file exists.
fileExists(const char * filename)359 static bool fileExists(const char* filename) {
360     return access((g_traceFolder + filename).c_str(), F_OK) != -1;
361 }
362 
363 // Check whether a file is writable.
fileIsWritable(const char * filename)364 static bool fileIsWritable(const char* filename) {
365     return access((g_traceFolder + filename).c_str(), W_OK) != -1;
366 }
367 
368 // Truncate a file.
truncateFile(const char * path)369 static bool truncateFile(const char* path)
370 {
371     // This uses creat rather than truncate because some of the debug kernel
372     // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
373     // calls to truncate, but they are cleared by calls to creat.
374     int traceFD = creat((g_traceFolder + path).c_str(), 0);
375     if (traceFD == -1) {
376         fprintf(stderr, "error truncating %s: %s (%d)\n", (g_traceFolder + path).c_str(),
377             strerror(errno), errno);
378         return false;
379     }
380 
381     close(traceFD);
382 
383     return true;
384 }
385 
_writeStr(const char * filename,const char * str,int flags)386 static bool _writeStr(const char* filename, const char* str, int flags)
387 {
388     std::string fullFilename = g_traceFolder + filename;
389     int fd = open(fullFilename.c_str(), flags);
390     if (fd == -1) {
391         fprintf(stderr, "error opening %s: %s (%d)\n", fullFilename.c_str(),
392                 strerror(errno), errno);
393         return false;
394     }
395 
396     bool ok = true;
397     ssize_t len = strlen(str);
398     if (write(fd, str, len) != len) {
399         fprintf(stderr, "error writing to %s: %s (%d)\n", fullFilename.c_str(),
400                 strerror(errno), errno);
401         ok = false;
402     }
403 
404     close(fd);
405 
406     return ok;
407 }
408 
409 // Write a string to a file, returning true if the write was successful.
writeStr(const char * filename,const char * str)410 static bool writeStr(const char* filename, const char* str)
411 {
412     return _writeStr(filename, str, O_WRONLY);
413 }
414 
415 // Append a string to a file, returning true if the write was successful.
appendStr(const char * filename,const char * str)416 static bool appendStr(const char* filename, const char* str)
417 {
418     return _writeStr(filename, str, O_APPEND|O_WRONLY);
419 }
420 
writeClockSyncMarker()421 static void writeClockSyncMarker()
422 {
423   char buffer[128];
424   int len = 0;
425   int fd = open((g_traceFolder + k_traceMarkerPath).c_str(), O_WRONLY);
426   if (fd == -1) {
427       fprintf(stderr, "error opening %s: %s (%d)\n", k_traceMarkerPath,
428               strerror(errno), errno);
429       return;
430   }
431   float now_in_seconds = systemTime(CLOCK_MONOTONIC) / 1000000000.0f;
432 
433   len = snprintf(buffer, 128, "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds);
434   if (write(fd, buffer, len) != len) {
435       fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno);
436   }
437 
438   int64_t realtime_in_ms = systemTime(CLOCK_REALTIME) / 1000000;
439   len = snprintf(buffer, 128, "trace_event_clock_sync: realtime_ts=%" PRId64 "\n", realtime_in_ms);
440   if (write(fd, buffer, len) != len) {
441       fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno);
442   }
443 
444   close(fd);
445 }
446 
447 // Enable or disable a kernel option by writing a "1" or a "0" into a /sys
448 // file.
setKernelOptionEnable(const char * filename,bool enable)449 static bool setKernelOptionEnable(const char* filename, bool enable)
450 {
451     return writeStr(filename, enable ? "1" : "0");
452 }
453 
454 // Check whether the category is supported on the device with the current
455 // rootness.  A category is supported only if all its required /sys/ files are
456 // writable and if enabling the category will enable one or more tracing tags
457 // or /sys/ files.
isCategorySupported(const TracingCategory & category)458 static bool isCategorySupported(const TracingCategory& category)
459 {
460     if (strcmp(category.name, k_coreServiceCategory) == 0) {
461         return !android::base::GetProperty(k_coreServicesProp, "").empty();
462     }
463 
464     if (strcmp(category.name, k_pdxServiceCategory) == 0) {
465         return true;
466     }
467 
468     bool ok = category.tags != 0;
469     for (int i = 0; i < MAX_SYS_FILES; i++) {
470         const char* path = category.sysfiles[i].path;
471         bool req = category.sysfiles[i].required == REQ;
472         if (path != nullptr) {
473             if (fileIsWritable(path)) {
474                 ok = true;
475             } else if (req) {
476                 return false;
477             }
478         }
479     }
480     return ok;
481 }
482 
483 // Check whether the category would be supported on the device if the user
484 // were root.  This function assumes that root is able to write to any file
485 // that exists.  It performs the same logic as isCategorySupported, but it
486 // uses file existence rather than writability in the /sys/ file checks.
isCategorySupportedForRoot(const TracingCategory & category)487 static bool isCategorySupportedForRoot(const TracingCategory& category)
488 {
489     bool ok = category.tags != 0;
490     for (int i = 0; i < MAX_SYS_FILES; i++) {
491         const char* path = category.sysfiles[i].path;
492         bool req = category.sysfiles[i].required == REQ;
493         if (path != nullptr) {
494             if (req) {
495                 if (!fileExists(path)) {
496                     return false;
497                 } else {
498                     ok = true;
499                 }
500             } else {
501                 ok |= fileExists(path);
502             }
503         }
504     }
505     return ok;
506 }
507 
508 // Enable or disable overwriting of the kernel trace buffers.  Disabling this
509 // will cause tracing to stop once the trace buffers have filled up.
setTraceOverwriteEnable(bool enable)510 static bool setTraceOverwriteEnable(bool enable)
511 {
512     return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
513 }
514 
515 // Set the user initiated trace property
setUserInitiatedTraceProperty(bool enable)516 static bool setUserInitiatedTraceProperty(bool enable)
517 {
518     if (!android::base::SetProperty(k_userInitiatedTraceProperty, enable ? "1" : "")) {
519         fprintf(stderr, "error setting user initiated strace system property\n");
520         return false;
521     }
522     return true;
523 }
524 
525 // Enable or disable kernel tracing.
setTracingEnabled(bool enable)526 static bool setTracingEnabled(bool enable)
527 {
528     return setKernelOptionEnable(k_tracingOnPath, enable);
529 }
530 
531 // Clear the contents of the kernel trace.
clearTrace()532 static bool clearTrace()
533 {
534     return truncateFile(k_tracePath);
535 }
536 
537 // Set the size of the kernel's trace buffer in kilobytes.
setTraceBufferSizeKB(int size)538 static bool setTraceBufferSizeKB(int size)
539 {
540     char str[32] = "1";
541     if (size < 1) {
542         size = 1;
543     }
544     snprintf(str, 32, "%d", size);
545     return writeStr(k_traceBufferSizePath, str);
546 }
547 
548 #if 0
549 // TODO: Re-enable after stabilization
550 // Set the default size of cmdline hashtable
551 static bool setCmdlineSize()
552 {
553     if (fileExists(k_traceCmdlineSizePath)) {
554         return writeStr(k_traceCmdlineSizePath, "8192");
555     }
556     return true;
557 }
558 #endif
559 
560 // Set the clock to the best available option while tracing. Use 'boot' if it's
561 // available; otherwise, use 'mono'. If neither are available use 'global'.
562 // Any write to the trace_clock sysfs file will reset the buffer, so only
563 // update it if the requested value is not the current value.
setClock()564 static bool setClock()
565 {
566     std::ifstream clockFile((g_traceFolder + k_traceClockPath).c_str(), O_RDONLY);
567     std::string clockStr((std::istreambuf_iterator<char>(clockFile)),
568         std::istreambuf_iterator<char>());
569 
570     std::string newClock;
571     if (clockStr.find("boot") != std::string::npos) {
572         newClock = "boot";
573     } else if (clockStr.find("mono") != std::string::npos) {
574         newClock = "mono";
575     } else {
576         newClock = "global";
577     }
578 
579     size_t begin = clockStr.find('[') + 1;
580     size_t end = clockStr.find(']');
581     if (newClock.compare(0, std::string::npos, clockStr, begin, end-begin) == 0) {
582         return true;
583     }
584     return writeStr(k_traceClockPath, newClock.c_str());
585 }
586 
setPrintTgidEnableIfPresent(bool enable)587 static bool setPrintTgidEnableIfPresent(bool enable)
588 {
589     // Pre-4.13 this was options/print-tgid as an android-specific option.
590     // In 4.13+ this is an upstream option called options/record-tgid
591     // Both options produce the same ftrace format change
592     if (fileExists(k_printTgidPath)) {
593         return setKernelOptionEnable(k_printTgidPath, enable);
594     }
595     if (fileExists(k_recordTgidPath)) {
596         return setKernelOptionEnable(k_recordTgidPath, enable);
597     }
598     return true;
599 }
600 
601 // Set the trace tags that userland tracing uses, and poke the running
602 // processes to pick up the new value.
setTagsProperty(uint64_t tags)603 static bool setTagsProperty(uint64_t tags)
604 {
605     std::string value = android::base::StringPrintf("%#" PRIx64, tags);
606     if (!android::base::SetProperty(k_traceTagsProperty, value)) {
607         fprintf(stderr, "error setting trace tags system property\n");
608         return false;
609     }
610     return true;
611 }
612 
clearAppProperties()613 static void clearAppProperties()
614 {
615     if (!android::base::SetProperty(k_traceAppsNumberProperty, "")) {
616         fprintf(stderr, "failed to clear system property: %s",
617               k_traceAppsNumberProperty);
618     }
619 }
620 
621 // Set the system property that indicates which apps should perform
622 // application-level tracing.
setAppCmdlineProperty(char * cmdline)623 static bool setAppCmdlineProperty(char* cmdline)
624 {
625     int i = 0;
626     char* start = cmdline;
627     while (start != nullptr) {
628         char* end = strchr(start, ',');
629         if (end != nullptr) {
630             *end = '\0';
631             end++;
632         }
633         std::string key = android::base::StringPrintf(k_traceAppsPropertyTemplate, i);
634         if (!android::base::SetProperty(key, start)) {
635             fprintf(stderr, "error setting trace app %d property to %s\n", i, key.c_str());
636             clearAppProperties();
637             return false;
638         }
639         start = end;
640         i++;
641     }
642 
643     std::string value = android::base::StringPrintf("%d", i);
644     if (!android::base::SetProperty(k_traceAppsNumberProperty, value)) {
645         fprintf(stderr, "error setting trace app number property to %s\n", value.c_str());
646         clearAppProperties();
647         return false;
648     }
649     return true;
650 }
651 
652 // Disable all /sys/ enable files.
disableKernelTraceEvents()653 static bool disableKernelTraceEvents() {
654     bool ok = true;
655     for (size_t i = 0; i < arraysize(k_categories); i++) {
656         const TracingCategory &c = k_categories[i];
657         for (int j = 0; j < MAX_SYS_FILES; j++) {
658             const char* path = c.sysfiles[j].path;
659             if (path != nullptr && fileIsWritable(path)) {
660                 ok &= setKernelOptionEnable(path, false);
661             }
662         }
663     }
664     for (const TracingVendorFileCategory& c : g_vendorFileCategories) {
665         for (const std::string& path : c.ftrace_enable_paths) {
666             if (fileIsWritable(path.c_str())) {
667                 ok &= setKernelOptionEnable(path.c_str(), false);
668             }
669         }
670     }
671     return ok;
672 }
673 
674 // Verify that the comma separated list of functions are being traced by the
675 // kernel.
verifyKernelTraceFuncs(const char * funcs)676 static bool verifyKernelTraceFuncs(const char* funcs)
677 {
678     std::string buf;
679     if (!android::base::ReadFileToString(g_traceFolder + k_ftraceFilterPath, &buf)) {
680          fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
681             strerror(errno), errno);
682          return false;
683     }
684 
685     String8 funcList = String8::format("\n%s",buf.c_str());
686 
687     // Make sure that every function listed in funcs is in the list we just
688     // read from the kernel, except for wildcard inputs.
689     bool ok = true;
690     char* myFuncs = strdup(funcs);
691     char* func = strtok(myFuncs, ",");
692     while (func) {
693         if (!strchr(func, '*')) {
694             String8 fancyFunc = String8::format("\n%s\n", func);
695             bool found = funcList.find(fancyFunc.string(), 0) >= 0;
696             if (!found || func[0] == '\0') {
697                 fprintf(stderr, "error: \"%s\" is not a valid kernel function "
698                         "to trace.\n", func);
699                 ok = false;
700             }
701         }
702         func = strtok(nullptr, ",");
703     }
704     free(myFuncs);
705     return ok;
706 }
707 
708 // Set the comma separated list of functions that the kernel is to trace.
setKernelTraceFuncs(const char * funcs)709 static bool setKernelTraceFuncs(const char* funcs)
710 {
711     bool ok = true;
712 
713     if (funcs == nullptr || funcs[0] == '\0') {
714         // Disable kernel function tracing.
715         if (fileIsWritable(k_currentTracerPath)) {
716             ok &= writeStr(k_currentTracerPath, "nop");
717         }
718         if (fileIsWritable(k_ftraceFilterPath)) {
719             ok &= truncateFile(k_ftraceFilterPath);
720         }
721     } else {
722         // Enable kernel function tracing.
723         ok &= writeStr(k_currentTracerPath, "function_graph");
724         ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
725         ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
726         ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
727 
728         // Set the requested filter functions.
729         ok &= truncateFile(k_ftraceFilterPath);
730         char* myFuncs = strdup(funcs);
731         char* func = strtok(myFuncs, ",");
732         while (func) {
733             ok &= appendStr(k_ftraceFilterPath, func);
734             func = strtok(nullptr, ",");
735         }
736         free(myFuncs);
737 
738         // Verify that the set functions are being traced.
739         if (ok) {
740             ok &= verifyKernelTraceFuncs(funcs);
741         }
742     }
743 
744     return ok;
745 }
746 
setCategoryEnable(const char * name)747 static bool setCategoryEnable(const char* name)
748 {
749     bool vendor_found = false;
750     for (auto& c : g_vendorFileCategories) {
751         if (strcmp(name, c.name.c_str()) == 0) {
752             c.enabled = true;
753             vendor_found = true;
754         }
755     }
756     for (auto& c : g_vendorHalCategories) {
757         if (strcmp(name, c.name.c_str()) == 0) {
758             c.enabled = true;
759             vendor_found = true;
760         }
761     }
762     for (size_t i = 0; i < arraysize(k_categories); i++) {
763         const TracingCategory& c = k_categories[i];
764         if (strcmp(name, c.name) == 0) {
765             if (isCategorySupported(c)) {
766                 g_categoryEnables[i] = true;
767                 return true;
768             } else {
769                 if (isCategorySupportedForRoot(c)) {
770                     fprintf(stderr, "error: category \"%s\" requires root "
771                             "privileges.\n", name);
772                 } else {
773                     fprintf(stderr, "error: category \"%s\" is not supported "
774                             "on this device.\n", name);
775                 }
776                 return false;
777             }
778         }
779     }
780     if (vendor_found) {
781         return true;
782     }
783     fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
784     return false;
785 }
786 
setCategoriesEnableFromFile(const char * categories_file)787 static bool setCategoriesEnableFromFile(const char* categories_file)
788 {
789     if (!categories_file) {
790         return true;
791     }
792     Tokenizer* tokenizer = nullptr;
793     if (Tokenizer::open(String8(categories_file), &tokenizer) != NO_ERROR) {
794         return false;
795     }
796     bool ok = true;
797     while (!tokenizer->isEol()) {
798         String8 token = tokenizer->nextToken(" ");
799         if (token.isEmpty()) {
800             tokenizer->skipDelimiters(" ");
801             continue;
802         }
803         ok &= setCategoryEnable(token.string());
804     }
805     delete tokenizer;
806     return ok;
807 }
808 
setUpUserspaceTracing()809 static bool setUpUserspaceTracing()
810 {
811     bool ok = true;
812 
813     // Set up the tags property.
814     uint64_t tags = 0;
815     for (size_t i = 0; i < arraysize(k_categories); i++) {
816         if (g_categoryEnables[i]) {
817             const TracingCategory &c = k_categories[i];
818             tags |= c.tags;
819         }
820     }
821 
822     bool coreServicesTagEnabled = false;
823     for (size_t i = 0; i < arraysize(k_categories); i++) {
824         if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) {
825             coreServicesTagEnabled = g_categoryEnables[i];
826         }
827 
828         // Set whether to poke PDX services in this session.
829         if (strcmp(k_categories[i].name, k_pdxServiceCategory) == 0) {
830             g_tracePdx = g_categoryEnables[i];
831         }
832     }
833 
834     std::string packageList(g_debugAppCmdLine);
835     if (coreServicesTagEnabled) {
836         if (!packageList.empty()) {
837             packageList += ",";
838         }
839         packageList += android::base::GetProperty(k_coreServicesProp, "");
840     }
841     ok &= setAppCmdlineProperty(&packageList[0]);
842     ok &= setTagsProperty(tags);
843     if (g_tracePdx) {
844         ok &= ServiceUtility::PokeServices();
845     }
846 
847     return ok;
848 }
849 
cleanUpUserspaceTracing()850 static void cleanUpUserspaceTracing()
851 {
852     setTagsProperty(0);
853     clearAppProperties();
854 
855     if (g_tracePdx) {
856         ServiceUtility::PokeServices();
857     }
858 }
859 
860 
861 // Set all the kernel tracing settings to the desired state for this trace
862 // capture.
setUpKernelTracing()863 static bool setUpKernelTracing()
864 {
865     bool ok = true;
866 
867     ok &= setUserInitiatedTraceProperty(true);
868 
869     // Set up the tracing options.
870     ok &= setCategoriesEnableFromFile(g_categoriesFile);
871     ok &= setTraceOverwriteEnable(g_traceOverwrite);
872     ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
873     // TODO: Re-enable after stabilization
874     //ok &= setCmdlineSize();
875     ok &= setClock();
876     ok &= setPrintTgidEnableIfPresent(true);
877     ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
878 
879     // Disable all the sysfs enables.  This is done as a separate loop from
880     // the enables to allow the same enable to exist in multiple categories.
881     ok &= disableKernelTraceEvents();
882 
883     // Enable all the sysfs enables that are in an enabled category.
884     for (size_t i = 0; i < arraysize(k_categories); i++) {
885         if (g_categoryEnables[i]) {
886             const TracingCategory &c = k_categories[i];
887             for (int j = 0; j < MAX_SYS_FILES; j++) {
888                 const char* path = c.sysfiles[j].path;
889                 bool required = c.sysfiles[j].required == REQ;
890                 if (path != nullptr) {
891                     if (fileIsWritable(path)) {
892                         ok &= setKernelOptionEnable(path, true);
893                     } else if (required) {
894                         fprintf(stderr, "error writing file %s\n", path);
895                         ok = false;
896                     }
897                 }
898             }
899         }
900     }
901 
902     for (const TracingVendorFileCategory& c : g_vendorFileCategories) {
903         if (c.enabled) {
904             for (const std::string& path : c.ftrace_enable_paths) {
905                 if (fileIsWritable(path.c_str())) {
906                     ok &= setKernelOptionEnable(path.c_str(), true);
907                 }
908             }
909         }
910     }
911 
912     return ok;
913 }
914 
915 // Reset all the kernel tracing settings to their default state.
cleanUpKernelTracing()916 static void cleanUpKernelTracing()
917 {
918     // Disable all tracing that we're able to.
919     disableKernelTraceEvents();
920 
921     // Set the options back to their defaults.
922     setTraceOverwriteEnable(true);
923     setTraceBufferSizeKB(1);
924     setPrintTgidEnableIfPresent(false);
925     setKernelTraceFuncs(nullptr);
926     setUserInitiatedTraceProperty(false);
927 }
928 
929 // Enable tracing in the kernel.
startTrace()930 static bool startTrace()
931 {
932     return setTracingEnabled(true);
933 }
934 
935 // Disable tracing in the kernel.
stopTrace()936 static void stopTrace()
937 {
938     setTracingEnabled(false);
939 }
940 
941 // Read data from the tracing pipe and forward to stdout
streamTrace()942 static void streamTrace()
943 {
944     char trace_data[4096];
945     int traceFD = open((g_traceFolder + k_traceStreamPath).c_str(), O_RDWR);
946     if (traceFD == -1) {
947         fprintf(stderr, "error opening %s: %s (%d)\n", k_traceStreamPath,
948                 strerror(errno), errno);
949         return;
950     }
951     while (!g_traceAborted) {
952         ssize_t bytes_read = read(traceFD, trace_data, 4096);
953         if (bytes_read > 0) {
954             write(STDOUT_FILENO, trace_data, bytes_read);
955             fflush(stdout);
956         } else {
957             if (!g_traceAborted) {
958                 fprintf(stderr, "read returned %zd bytes err %d (%s)\n",
959                         bytes_read, errno, strerror(errno));
960             }
961             break;
962         }
963     }
964 }
965 
966 // Read the current kernel trace and write it to stdout.
dumpTrace(int outFd)967 static void dumpTrace(int outFd)
968 {
969     ALOGI("Dumping trace");
970     int traceFD = open((g_traceFolder + k_tracePath).c_str(), O_RDWR);
971     if (traceFD == -1) {
972         fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
973                 strerror(errno), errno);
974         return;
975     }
976 
977     if (g_compress) {
978         z_stream zs;
979         memset(&zs, 0, sizeof(zs));
980 
981         int result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
982         if (result != Z_OK) {
983             fprintf(stderr, "error initializing zlib: %d\n", result);
984             close(traceFD);
985             return;
986         }
987 
988         constexpr size_t bufSize = 64*1024;
989         std::unique_ptr<uint8_t> in(new uint8_t[bufSize]);
990         std::unique_ptr<uint8_t> out(new uint8_t[bufSize]);
991         if (!in || !out) {
992             fprintf(stderr, "couldn't allocate buffers\n");
993             close(traceFD);
994             return;
995         }
996 
997         int flush = Z_NO_FLUSH;
998 
999         zs.next_out = reinterpret_cast<Bytef*>(out.get());
1000         zs.avail_out = bufSize;
1001 
1002         do {
1003 
1004             if (zs.avail_in == 0) {
1005                 // More input is needed.
1006                 result = read(traceFD, in.get(), bufSize);
1007                 if (result < 0) {
1008                     fprintf(stderr, "error reading trace: %s (%d)\n",
1009                             strerror(errno), errno);
1010                     result = Z_STREAM_END;
1011                     break;
1012                 } else if (result == 0) {
1013                     flush = Z_FINISH;
1014                 } else {
1015                     zs.next_in = reinterpret_cast<Bytef*>(in.get());
1016                     zs.avail_in = result;
1017                 }
1018             }
1019 
1020             if (zs.avail_out == 0) {
1021                 // Need to write the output.
1022                 result = write(outFd, out.get(), bufSize);
1023                 if ((size_t)result < bufSize) {
1024                     fprintf(stderr, "error writing deflated trace: %s (%d)\n",
1025                             strerror(errno), errno);
1026                     result = Z_STREAM_END; // skip deflate error message
1027                     zs.avail_out = bufSize; // skip the final write
1028                     break;
1029                 }
1030                 zs.next_out = reinterpret_cast<Bytef*>(out.get());
1031                 zs.avail_out = bufSize;
1032             }
1033 
1034         } while ((result = deflate(&zs, flush)) == Z_OK);
1035 
1036         if (result != Z_STREAM_END) {
1037             fprintf(stderr, "error deflating trace: %s\n", zs.msg);
1038         }
1039 
1040         if (zs.avail_out < bufSize) {
1041             size_t bytes = bufSize - zs.avail_out;
1042             result = write(outFd, out.get(), bytes);
1043             if ((size_t)result < bytes) {
1044                 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
1045                         strerror(errno), errno);
1046             }
1047         }
1048 
1049         result = deflateEnd(&zs);
1050         if (result != Z_OK) {
1051             fprintf(stderr, "error cleaning up zlib: %d\n", result);
1052         }
1053     } else {
1054         char buf[4096];
1055         ssize_t rc;
1056         while ((rc = TEMP_FAILURE_RETRY(read(traceFD, buf, sizeof(buf)))) > 0) {
1057             if (!android::base::WriteFully(outFd, buf, rc)) {
1058                 fprintf(stderr, "error writing trace: %s\n", strerror(errno));
1059                 break;
1060             }
1061         }
1062         if (rc == -1) {
1063             fprintf(stderr, "error dumping trace: %s\n", strerror(errno));
1064         }
1065     }
1066 
1067     close(traceFD);
1068 }
1069 
handleSignal(int)1070 static void handleSignal(int /*signo*/)
1071 {
1072     if (!g_nohup) {
1073         g_traceAborted = true;
1074     }
1075 }
1076 
registerSigHandler()1077 static void registerSigHandler()
1078 {
1079     struct sigaction sa;
1080     sigemptyset(&sa.sa_mask);
1081     sa.sa_flags = 0;
1082     sa.sa_handler = handleSignal;
1083     sigaction(SIGHUP, &sa, nullptr);
1084     sigaction(SIGINT, &sa, nullptr);
1085     sigaction(SIGQUIT, &sa, nullptr);
1086     sigaction(SIGTERM, &sa, nullptr);
1087 }
1088 
listSupportedCategories()1089 static void listSupportedCategories()
1090 {
1091     for (size_t i = 0; i < arraysize(k_categories); i++) {
1092         const TracingCategory& c = k_categories[i];
1093         if (isCategorySupported(c)) {
1094             printf("  %10s - %s\n", c.name, c.longname);
1095         }
1096     }
1097     for (const auto& c : g_vendorFileCategories) {
1098         printf("  %10s - (VENDOR)\n", c.name.c_str());
1099     }
1100     for (const auto& c : g_vendorHalCategories) {
1101         printf("  %10s - %s (HAL)\n", c.name.c_str(), c.description.c_str());
1102     }
1103 }
1104 
1105 // Print the command usage help to stderr.
showHelp(const char * cmd)1106 static void showHelp(const char *cmd)
1107 {
1108     fprintf(stderr, "usage: %s [options] [categories...]\n", cmd);
1109     fprintf(stderr, "options include:\n"
1110                     "  -a appname      enable app-level tracing for a comma "
1111                         "separated list of cmdlines; * is a wildcard matching any process\n"
1112                     "  -b N            use a trace buffer size of N KB\n"
1113                     "  -c              trace into a circular buffer\n"
1114                     "  -f filename     use the categories written in a file as space-separated\n"
1115                     "                    values in a line\n"
1116                     "  -k fname,...    trace the listed kernel functions\n"
1117                     "  -n              ignore signals\n"
1118                     "  -s N            sleep for N seconds before tracing [default 0]\n"
1119                     "  -t N            trace for N seconds [default 5]\n"
1120                     "  -z              compress the trace dump\n"
1121                     "  --async_start   start circular trace and return immediately\n"
1122                     "  --async_dump    dump the current contents of circular trace buffer\n"
1123                     "  --async_stop    stop tracing and dump the current contents of circular\n"
1124                     "                    trace buffer\n"
1125                     "  --stream        stream trace to stdout as it enters the trace buffer\n"
1126                     "                    Note: this can take significant CPU time, and is best\n"
1127                     "                    used for measuring things that are not affected by\n"
1128                     "                    CPU performance, like pagecache usage.\n"
1129                     "  --list_categories\n"
1130                     "                  list the available tracing categories\n"
1131                     " -o filename      write the trace to the specified file instead\n"
1132                     "                    of stdout.\n"
1133             );
1134 }
1135 
findTraceFiles()1136 bool findTraceFiles()
1137 {
1138     static const std::string debugfs_path = "/sys/kernel/debug/tracing/";
1139     static const std::string tracefs_path = "/sys/kernel/tracing/";
1140     static const std::string trace_file = "trace_marker";
1141 
1142     bool tracefs = access((tracefs_path + trace_file).c_str(), F_OK) != -1;
1143     bool debugfs = access((debugfs_path + trace_file).c_str(), F_OK) != -1;
1144 
1145     if (!tracefs && !debugfs) {
1146         fprintf(stderr, "Error: Did not find trace folder\n");
1147         return false;
1148     }
1149 
1150     if (tracefs) {
1151         g_traceFolder = tracefs_path;
1152     } else {
1153         g_traceFolder = debugfs_path;
1154     }
1155 
1156     return true;
1157 }
1158 
initVendorCategoriesFromFile()1159 void initVendorCategoriesFromFile() {
1160     std::ifstream is(kVendorCategoriesPath);
1161     for (std::string line; std::getline(is, line);) {
1162         if (line.empty()) {
1163             continue;
1164         }
1165         if (android::base::StartsWith(line, ' ') || android::base::StartsWith(line, '\t')) {
1166             if (g_vendorFileCategories.empty()) {
1167                 fprintf(stderr, "Malformed vendor categories file\n");
1168                 exit(1);
1169                 return;
1170             }
1171             std::string_view path = std::string_view(line).substr(1);
1172             while (android::base::StartsWith(path, ' ') || android::base::StartsWith(path, '\t')) {
1173                 path.remove_prefix(1);
1174             }
1175             if (path.empty()) {
1176                 continue;
1177             }
1178             std::string enable_path = "events/";
1179             enable_path += path;
1180             enable_path += "/enable";
1181             g_vendorFileCategories.back().ftrace_enable_paths.push_back(std::move(enable_path));
1182         } else {
1183             TracingVendorFileCategory cat;
1184             cat.name = line;
1185             g_vendorFileCategories.push_back(std::move(cat));
1186         }
1187     }
1188 }
1189 
initVendorCategoriesFromHal()1190 void initVendorCategoriesFromHal() {
1191     g_atraceHal = IAtraceDevice::getService();
1192 
1193     if (g_atraceHal == nullptr) {
1194         // No atrace HAL
1195         return;
1196     }
1197 
1198     Return<void> ret = g_atraceHal->listCategories([](const auto& list) {
1199         g_vendorHalCategories.reserve(list.size());
1200         for (const auto& category : list) {
1201             g_vendorHalCategories.emplace_back(category.name, category.description, false);
1202         }
1203     });
1204     if (!ret.isOk()) {
1205         fprintf(stderr, "calling atrace HAL failed: %s\n", ret.description().c_str());
1206     }
1207 }
1208 
initVendorCategories()1209 void initVendorCategories() {
1210     // If kVendorCategoriesPath exists on the filesystem, do not use the HAL.
1211     if (access(kVendorCategoriesPath, F_OK) != -1) {
1212         initVendorCategoriesFromFile();
1213     } else {
1214         initVendorCategoriesFromHal();
1215     }
1216 }
1217 
setUpVendorTracingWithHal()1218 static bool setUpVendorTracingWithHal() {
1219     if (g_atraceHal == nullptr) {
1220         // No atrace HAL
1221         return true;
1222     }
1223 
1224     std::vector<hidl_string> categories;
1225     for (const auto& c : g_vendorHalCategories) {
1226         if (c.enabled) {
1227             categories.emplace_back(c.name);
1228         }
1229     }
1230 
1231     if (!categories.size()) {
1232         return true;
1233     }
1234 
1235     auto ret = g_atraceHal->enableCategories(categories);
1236     if (!ret.isOk()) {
1237         fprintf(stderr, "calling atrace HAL failed: %s\n", ret.description().c_str());
1238         return false;
1239     } else if (ret != Status::SUCCESS) {
1240         fprintf(stderr, "calling atrace HAL failed: %s\n", toString(ret).c_str());
1241         return false;
1242     }
1243     return true;
1244 }
1245 
cleanUpVendorTracingWithHal()1246 static bool cleanUpVendorTracingWithHal() {
1247     if (g_atraceHal == nullptr) {
1248         // No atrace HAL
1249         return true;
1250     }
1251 
1252     if (!g_vendorHalCategories.size()) {
1253         // No vendor HAL categories
1254         return true;
1255     }
1256 
1257     auto ret = g_atraceHal->disableAllCategories();
1258     if (!ret.isOk()) {
1259         fprintf(stderr, "calling atrace HAL failed: %s\n", ret.description().c_str());
1260         return false;
1261     } else if (ret != Status::SUCCESS) {
1262         fprintf(stderr, "calling atrace HAL failed: %s\n", toString(ret).c_str());
1263         return false;
1264     }
1265     return true;
1266 }
1267 
main(int argc,char ** argv)1268 int main(int argc, char **argv)
1269 {
1270     bool async = false;
1271     bool traceStart = true;
1272     bool traceStop = true;
1273     bool traceDump = true;
1274     bool traceStream = false;
1275     bool onlyUserspace = false;
1276 
1277     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
1278         showHelp(argv[0]);
1279         exit(0);
1280     }
1281 
1282     if (!findTraceFiles()) {
1283         fprintf(stderr, "No trace folder found\n");
1284         exit(-1);
1285     }
1286 
1287     initVendorCategories();
1288 
1289     for (;;) {
1290         int ret;
1291         int option_index = 0;
1292         static struct option long_options[] = {
1293             {"async_start",       no_argument, nullptr,  0 },
1294             {"async_stop",        no_argument, nullptr,  0 },
1295             {"async_dump",        no_argument, nullptr,  0 },
1296             {"only_userspace",    no_argument, nullptr,  0 },
1297             {"list_categories",   no_argument, nullptr,  0 },
1298             {"stream",            no_argument, nullptr,  0 },
1299             {nullptr,                       0, nullptr,  0 }
1300         };
1301 
1302         ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:",
1303                           long_options, &option_index);
1304 
1305         if (ret < 0) {
1306             for (int i = optind; i < argc; i++) {
1307                 setCategoryEnable(argv[i]);
1308             }
1309             break;
1310         }
1311 
1312         switch(ret) {
1313             case 'a':
1314                 g_debugAppCmdLine = optarg;
1315             break;
1316 
1317             case 'b':
1318                 g_traceBufferSizeKB = atoi(optarg);
1319             break;
1320 
1321             case 'c':
1322                 g_traceOverwrite = true;
1323             break;
1324 
1325             case 'f':
1326                 g_categoriesFile = optarg;
1327             break;
1328 
1329             case 'k':
1330                 g_kernelTraceFuncs = optarg;
1331             break;
1332 
1333             case 'n':
1334                 g_nohup = true;
1335             break;
1336 
1337             case 's':
1338                 g_initialSleepSecs = atoi(optarg);
1339             break;
1340 
1341             case 't':
1342                 g_traceDurationSeconds = atoi(optarg);
1343             break;
1344 
1345             case 'z':
1346                 g_compress = true;
1347             break;
1348 
1349             case 'o':
1350                 g_outputFile = optarg;
1351             break;
1352 
1353             case 0:
1354                 if (!strcmp(long_options[option_index].name, "async_start")) {
1355                     async = true;
1356                     traceStop = false;
1357                     traceDump = false;
1358                     g_traceOverwrite = true;
1359                 } else if (!strcmp(long_options[option_index].name, "async_stop")) {
1360                     async = true;
1361                     traceStart = false;
1362                 } else if (!strcmp(long_options[option_index].name, "async_dump")) {
1363                     async = true;
1364                     traceStart = false;
1365                     traceStop = false;
1366                 } else if (!strcmp(long_options[option_index].name, "only_userspace")) {
1367                     onlyUserspace = true;
1368                 } else if (!strcmp(long_options[option_index].name, "stream")) {
1369                     traceStream = true;
1370                     traceDump = false;
1371                 } else if (!strcmp(long_options[option_index].name, "list_categories")) {
1372                     listSupportedCategories();
1373                     exit(0);
1374                 }
1375             break;
1376 
1377             default:
1378                 fprintf(stderr, "\n");
1379                 showHelp(argv[0]);
1380                 exit(-1);
1381             break;
1382         }
1383     }
1384 
1385     if (onlyUserspace) {
1386         if (!async || !(traceStart || traceStop)) {
1387             fprintf(stderr, "--only_userspace can only be used with "
1388                     "--async_start or --async_stop\n");
1389             exit(1);
1390         }
1391     }
1392 
1393     registerSigHandler();
1394 
1395     if (g_initialSleepSecs > 0) {
1396         sleep(g_initialSleepSecs);
1397     }
1398 
1399     bool ok = true;
1400 
1401     if (traceStart) {
1402         ok &= setUpUserspaceTracing();
1403     }
1404 
1405     if (ok && traceStart && !onlyUserspace) {
1406         ok &= setUpKernelTracing();
1407         ok &= setUpVendorTracingWithHal();
1408         ok &= startTrace();
1409     }
1410 
1411     if (ok && traceStart) {
1412 
1413         if (!traceStream && !onlyUserspace) {
1414             printf("capturing trace...");
1415             fflush(stdout);
1416         }
1417 
1418         // We clear the trace after starting it because tracing gets enabled for
1419         // each CPU individually in the kernel. Having the beginning of the trace
1420         // contain entries from only one CPU can cause "begin" entries without a
1421         // matching "end" entry to show up if a task gets migrated from one CPU to
1422         // another.
1423         if (!onlyUserspace) {
1424             ok = clearTrace();
1425             writeClockSyncMarker();
1426         }
1427         if (ok && !async && !traceStream) {
1428             // Sleep to allow the trace to be captured.
1429             struct timespec timeLeft;
1430             timeLeft.tv_sec = g_traceDurationSeconds;
1431             timeLeft.tv_nsec = 0;
1432             do {
1433                 if (g_traceAborted) {
1434                     break;
1435                 }
1436             } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
1437         }
1438 
1439         if (traceStream) {
1440             streamTrace();
1441         }
1442     }
1443 
1444     // Stop the trace and restore the default settings.
1445     if (traceStop && !onlyUserspace)
1446         stopTrace();
1447 
1448     if (ok && traceDump && !onlyUserspace) {
1449         if (!g_traceAborted) {
1450             printf(" done\n");
1451             fflush(stdout);
1452             int outFd = STDOUT_FILENO;
1453             if (g_outputFile) {
1454                 outFd = open(g_outputFile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1455             }
1456             if (outFd == -1) {
1457                 printf("Failed to open '%s', err=%d", g_outputFile, errno);
1458             } else {
1459                 dprintf(outFd, "TRACE:\n");
1460                 dumpTrace(outFd);
1461                 if (g_outputFile) {
1462                     close(outFd);
1463                 }
1464             }
1465         } else {
1466             printf("\ntrace aborted.\n");
1467             fflush(stdout);
1468         }
1469         clearTrace();
1470     } else if (!ok) {
1471         fprintf(stderr, "unable to start tracing\n");
1472     }
1473 
1474     // Reset the trace buffer size to 1.
1475     if (traceStop) {
1476         cleanUpUserspaceTracing();
1477         if (!onlyUserspace) {
1478             cleanUpVendorTracingWithHal();
1479             cleanUpKernelTracing();
1480         }
1481     }
1482 
1483     return g_traceAborted ? 1 : 0;
1484 }
1485