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