1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <inttypes.h>
6 #include <signal.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include <memory>
12 #include <set>
13 #include <string>
14 #include <sstream>
15
16 #include "atrace_process_dump.h"
17 #include "logging.h"
18
19 namespace {
20
21 std::unique_ptr<AtraceProcessDump> g_prog;
22
ParseFullDumpConfig(const std::string & config,AtraceProcessDump * prog)23 void ParseFullDumpConfig(const std::string& config, AtraceProcessDump* prog) {
24 using FullDumpMode = AtraceProcessDump::FullDumpMode;
25 if (config == "all") {
26 prog->set_full_dump_mode(FullDumpMode::kAllProcesses);
27 } else if (config == "apps") {
28 prog->set_full_dump_mode(FullDumpMode::kAllJavaApps);
29 } else {
30 std::set<std::string> whitelist;
31 std::istringstream ss(config);
32 std::string entry;
33 while (std::getline(ss, entry, ',')) {
34 whitelist.insert(entry);
35 }
36 if (whitelist.empty())
37 return;
38 prog->set_full_dump_mode(FullDumpMode::kOnlyWhitelisted);
39 prog->set_full_dump_whitelist(whitelist);
40 }
41 }
42
43 } // namespace
44
main(int argc,char ** argv)45 int main(int argc, char** argv) {
46 if (argc == 2 && !strcmp(argv[1], "--echo-ts")) {
47 // Used by clock sync marker to correct the difference between
48 // Linux monotonic clocks on the device and host.
49 printf("%" PRIu64 "\n", time_utils::GetTimestamp());
50 return 0;
51 }
52
53 bool background = false;
54 int dump_interval_ms = 5000;
55 char out_file[PATH_MAX] = {};
56 bool dump_to_file = false;
57 int count = -1;
58
59 AtraceProcessDump* prog = new AtraceProcessDump();
60 g_prog = std::unique_ptr<AtraceProcessDump>(prog);
61
62 if (geteuid()) {
63 fprintf(stderr, "Must run as root\n");
64 exit(EXIT_FAILURE);
65 }
66
67 int opt;
68 while ((opt = getopt(argc, argv, "bm:gst:o:c:")) != -1) {
69 switch (opt) {
70 case 'b':
71 background = true;
72 break;
73 case 'm':
74 ParseFullDumpConfig(optarg, prog);
75 break;
76 case 'g':
77 prog->enable_graphics_stats();
78 break;
79 case 's':
80 prog->enable_print_smaps();
81 break;
82 case 't':
83 dump_interval_ms = atoi(optarg);
84 CHECK(dump_interval_ms > 0);
85 break;
86 case 'c':
87 count = atoi(optarg);
88 CHECK(count > 0);
89 break;
90 case 'o':
91 strncpy(out_file, optarg, sizeof(out_file));
92 dump_to_file = true;
93 break;
94 default:
95 fprintf(stderr,
96 "Usage: %s [-b] [-m full_dump_filter] [-g] [-s] "
97 "[-t dump_interval_ms] "
98 "[-c dumps_count] [-o out.json]\n",
99 argv[0]);
100 exit(EXIT_FAILURE);
101 }
102 }
103
104 prog->set_dump_count(count);
105 prog->SetDumpInterval(dump_interval_ms);
106
107 FILE* out_stream = stdout;
108 char tmp_file[PATH_MAX];
109 if (dump_to_file) {
110 unlink(out_file);
111 sprintf(tmp_file, "%s.tmp", out_file);
112 out_stream = fopen(tmp_file, "w");
113 CHECK(out_stream);
114 }
115
116 if (background) {
117 if (!dump_to_file) {
118 fprintf(stderr, "-b requires -o for output dump path.\n");
119 exit(EXIT_FAILURE);
120 }
121 printf("Continuing in background. kill -TERM to terminate the daemon.\n");
122 CHECK(daemon(0 /* nochdir */, 0 /* noclose */) == 0);
123 }
124
125 auto on_exit = [](int) { g_prog->Stop(); };
126 signal(SIGINT, on_exit);
127 signal(SIGTERM, on_exit);
128
129 prog->RunAndPrintJson(out_stream);
130 fclose(out_stream);
131
132 if (dump_to_file)
133 rename(tmp_file, out_file);
134 }
135