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