• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <cinttypes>
17 #include <csignal>
18 #include <cstdio>
19 #include <ctime>
20 #include <fstream>
21 #include <regex>
22 #include <sstream>
23 #include <string>
24 #include <vector>
25 #include <map>
26 #include <fcntl.h>
27 #include <getopt.h>
28 #include <sys/stat.h>
29 #include <thread>
30 #include <unistd.h>
31 #include <zlib.h>
32 #include "hitrace_meter.h"
33 #include "bytrace_osal.h"
34 #include "securec.h"
35 
36 using namespace std;
37 using namespace OHOS::Developtools::BytraceOsal;
38 
39 namespace {
40 struct option g_longOptions[] = {
41     { "buffer_size",       required_argument, nullptr, 0 },
42     { "trace_clock",       required_argument, nullptr, 0 },
43     { "help",              no_argument,       nullptr, 0 },
44     { "output",            required_argument, nullptr, 0 },
45     { "time",              required_argument, nullptr, 0 }, // used to specify the time (in seconds) for trace to run.
46     { "trace_begin",       no_argument,       nullptr, 0 },
47     { "trace_finish",      no_argument,       nullptr, 0 },
48     { "trace_finish_nodump",      no_argument,       nullptr, 0 },
49     { "trace_dump",        no_argument,       nullptr, 0 },
50     { "list_categories",   no_argument,       nullptr, 0 },
51     { "overwrite",         no_argument,       nullptr, 0 },
52     { nullptr,             0,                 nullptr, 0 },
53 };
54 // char range
55 const unsigned int CHUNK_SIZE = 65536;
56 const int BLOCK_SIZE = 4096;
57 const int SHELL_UID = 2000;
58 const int WAIT_MILLISECONDS = 10;
59 const int SAVED_CMDLINES_SIZE = 1024;
60 
61 const string TRACE_TAG_PROPERTY = "debug.hitrace.tags.enableflags";
62 
63 // various operating paths of ftrace
64 const string TRACING_ON_PATH = "tracing_on";
65 const string TRACE_PATH = "trace";
66 const string TRACE_MARKER_PATH = "trace_marker";
67 const string BUFFER_SIZE_PATH = "buffer_size_kb";
68 const string CURRENT_TRACER_PATH = "current_tracer";
69 const string TRACE_CLOCK_PATH = "trace_clock";
70 const string OVER_WRITE_PATH = "options/overwrite";
71 const string RECORD_TGID_PATH = "options/record-tgid";
72 const string SAVED_CMDLINES_PATH = "saved_cmdlines_size";
73 
74 // support customization of some parameters
75 
76 const int MIN_BUFFER_SIZE = 256;
77 const int MAX_BUFFER_SIZE = 307200; // 300 MB
78 constexpr unsigned int MAX_OUTPUT_LEN = 255;
79 const int PAGE_SIZE_KB = 4; // 4 KB
80 int g_traceDuration = 5; // g_traceDuration
81 int g_bufferSizeKB = 2048;
82 string g_clock = "boot";
83 bool g_overwrite = true;
84 string g_outputFile;
85 bool g_compress = false;
86 
87 string g_traceRootPath; // g_traceRootPath
88 
89 const unsigned int START_NONE = 0;
90 const unsigned int START_NORMAL = 1;
91 const unsigned int START_ASYNC = 2;
92 unsigned int g_traceStart = START_NORMAL;
93 bool g_traceStop = true;
94 bool g_traceDump = true;
95 
96 map<string, TagCategory> g_tagMap; // stored tags
97 vector<uint64_t> g_userEnabledTags;
98 vector<string> g_kernelEnabledPaths;
99 }
100 
IsTraceMounted()101 static bool IsTraceMounted()
102 {
103     const string debugfsPath = "/sys/kernel/debug/tracing/";
104     const string tracefsPath = "/sys/kernel/tracing/";
105     // find debugfsPath first
106     if (access((debugfsPath + TRACE_MARKER_PATH).c_str(), F_OK) != -1) {
107         g_traceRootPath = debugfsPath;
108         return true;
109     }
110     if (access((tracefsPath + TRACE_MARKER_PATH).c_str(), F_OK) != -1) {
111         g_traceRootPath = tracefsPath;
112         return true;
113     }
114 
115     (void)fprintf(stderr, "Error: Did not find trace folder.\n"); // can't find trace folder
116     return false;
117 }
118 
IsFileExit(const string & filename)119 static bool IsFileExit(const string& filename)
120 {
121     return access((g_traceRootPath + filename).c_str(), F_OK) != -1; // verify if the file exists
122 }
123 
IsWritableFile(const string & filename)124 static bool IsWritableFile(const string& filename)
125 {
126     return access((g_traceRootPath + filename).c_str(), W_OK) != -1; // verify if the file writable
127 }
128 
WriteStrToFile(const string & filename,const std::string & str)129 static bool WriteStrToFile(const string& filename, const std::string& str)
130 {
131     ofstream out;
132     out.open(g_traceRootPath + filename, ios::out);
133     if (out.fail()) {
134         // can't open the file
135         fprintf(stderr, "Error: Did not open %s\n", filename.c_str());
136         return false;
137     }
138     out << str;
139     if (out.bad()) {
140         fprintf(stderr, "Error: Did not write %s\n", filename.c_str());
141         out.close();
142         return false;
143     }
144     // release resources
145     out.flush();
146     out.close();
147     return true;
148 }
149 
SetFtraceEnabled(const string & path,bool enabled)150 static bool SetFtraceEnabled(const string& path, bool enabled)
151 {
152     return WriteStrToFile(path, enabled ? "1" : "0"); // write 1 or 0 to file
153 }
154 
IsTagSupported(const string & name)155 static bool IsTagSupported(const string& name)
156 {
157     auto it = g_tagMap.find(name);
158     if (it == g_tagMap.end()) {
159         // can't find item from map
160         return false;
161     }
162 
163     TagCategory tagCategory = it->second;
164     if (tagCategory.type != KERNEL) {
165         g_userEnabledTags.push_back(tagCategory.tag);
166         return true;
167     }
168 
169     bool findPath = false;
170     for (int i = 0; i < MAX_SYS_FILES; i++) {
171         const string path = tagCategory.sysfiles[i].path;
172         if (path.size() == 0) {
173             continue;
174         }
175         if (IsWritableFile(path)) {
176             g_kernelEnabledPaths.push_back(path);
177             findPath = true;
178         } else if (IsFileExit(path)) {
179             fprintf(stderr, "Warning: category \"%s\" requires root privileges.\n", name.c_str());
180         }
181     }
182     return findPath;
183 }
184 
CanonicalizeSpecPath(const char * src)185 static string CanonicalizeSpecPath(const char* src)
186 {
187     // PATH_MAX is 4096, defined in linux/limits.h
188     if (src == nullptr || strlen(src) >= PATH_MAX) {
189         fprintf(stderr, "Error: CanonicalizeSpecPath %s failed\n", src);
190         return "";
191     }
192     char resolvedPath[PATH_MAX] = { 0 };
193 #if defined(_WIN32)
194     if (!_fullpath(resolvedPath, src, PATH_MAX)) {
195         fprintf(stderr, "Error: _fullpath %s failed\n", src);
196         return "";
197     }
198 #else
199     if (access(src, F_OK) == 0) {
200         // function to find the absolute path of a file in the directory
201         if (realpath(src, resolvedPath) == nullptr) {
202             fprintf(stderr, "Error: realpath %s failed\n", src);
203             return "";
204         }
205     } else {
206         // trace_clock file doesn't exist
207         string fileName(src);
208         if (fileName.find("..") == string::npos) {
209             if (sprintf_s(resolvedPath, PATH_MAX, "%s", src) == -1) {
210                 fprintf(stderr, "Error: sprintf_s %s failed\n", src);
211                 return "";
212             }
213         } else {
214             // find file failed
215             fprintf(stderr, "Error: find .. %s failed\n", src);
216             return "";
217         }
218     }
219 #endif
220     string res(resolvedPath);
221     return res; // return the string
222 }
223 
ReadFile(const string & filename)224 static string ReadFile(const string& filename)
225 {
226     // standardize file paths
227     string resolvedPath = CanonicalizeSpecPath((g_traceRootPath + filename).c_str());
228     ifstream fin(resolvedPath.c_str());
229     if (!fin.is_open()) {
230         fprintf(stderr, "open file: %s failed!\n", (g_traceRootPath + filename).c_str());
231         return "";
232     }
233 
234     string str((istreambuf_iterator<char>(fin)), istreambuf_iterator<char>());
235     // close a file handle
236     fin.close();
237     return str;
238 }
239 
SetBufferSize(int bufferSize)240 static bool SetBufferSize(int bufferSize)
241 {
242     if (!WriteStrToFile(CURRENT_TRACER_PATH, "nop")) {
243         // process for current_tracer file does not have permission
244         fprintf(stderr, "Error: write \"nop\" to %s\n", CURRENT_TRACER_PATH.c_str());
245     }
246     return WriteStrToFile(BUFFER_SIZE_PATH, to_string(bufferSize));
247 }
248 
SetClock(const string & timeclock)249 static bool SetClock(const string& timeclock)
250 {
251     string allClocks = ReadFile(TRACE_CLOCK_PATH);
252     size_t begin = allClocks.find("[");
253     size_t end = allClocks.find("]");
254     string newClock;
255     // if the clock to be set is the same as the existing clock, it will not be set
256     if (begin != string::npos && end != string::npos &&
257         timeclock.compare(0, timeclock.size(), allClocks, begin + 1, end - begin - 1) == 0) {
258         return true;
259     } else if (allClocks.find(timeclock) != string::npos) {
260         newClock = timeclock;
261     } else if (allClocks.find("boot") != string::npos) {
262         // boot: This is the boot clock (CLOCK_BOOTTIME) and is based on the fast monotonic clock,
263         newClock = "boot";
264     } else if (allClocks.find("mono") != string::npos) {
265         // mono: uses the fast monotonic clock (CLOCK_MONOTONIC)
266         // which is monotonic and is subject to NTP rate adjustments.
267         newClock = "mono";
268     } else if (allClocks.find("global") != string::npos) {
269         newClock = "global";
270     } else {
271         fprintf(stderr, "You can set trace clock in %s\n", allClocks.c_str());
272         return false;
273     }
274     if (newClock.size() != 0) {
275         return WriteStrToFile(TRACE_CLOCK_PATH, newClock);
276     }
277     return true;
278 }
279 
SetOverWriteEnable(bool enabled)280 static bool SetOverWriteEnable(bool enabled)
281 {
282     return SetFtraceEnabled(OVER_WRITE_PATH, enabled);
283 }
284 
SetTgidEnable(bool enabled)285 static bool SetTgidEnable(bool enabled)
286 {
287     return SetFtraceEnabled(RECORD_TGID_PATH, enabled);
288 }
289 
SetCmdLinesSize(int cmdLinesSize)290 static bool SetCmdLinesSize(int cmdLinesSize)
291 {
292     return WriteStrToFile(SAVED_CMDLINES_PATH, std::to_string(cmdLinesSize));
293 }
294 
DisableAllFtraceEvents()295 static bool DisableAllFtraceEvents()
296 {
297     bool isTrue = true;
298     // DisableAllFtraceEvents
299     for (auto it = g_tagMap.begin(); it != g_tagMap.end(); ++it) {
300         TagCategory tag = it->second;
301         if (tag.type != KERNEL) {
302             continue;
303         }
304         for (int i = 0; i < MAX_SYS_FILES; i++) {
305             const string path = tag.sysfiles[i].path;
306             if ((path.size() > 0) && IsWritableFile(path)) {
307                 isTrue = isTrue && SetFtraceEnabled(path, false); // set false to ftraceEnabled
308             }
309         }
310     }
311     return isTrue;
312 }
313 
SetProperty(const string & property,const string & value)314 static bool SetProperty(const string& property, const string& value)
315 {
316     // set the system property
317     return SetPropertyInner(property, value);
318 }
319 
SetTraceTagsEnabled(uint64_t tags)320 static bool SetTraceTagsEnabled(uint64_t tags)
321 {
322     string value = to_string(tags);
323     return SetProperty(TRACE_TAG_PROPERTY, value);
324 }
325 
RefreshServices()326 static bool RefreshServices()
327 {
328     bool res = false;
329     // refresh binderServices
330     res = RefreshBinderServices();
331     if (!res) {
332         return res;
333     }
334     res = RefreshHalServices();
335     return res;
336 }
337 
SetUserSpaceSettings()338 static bool SetUserSpaceSettings()
339 {
340     // set userSpace settings
341     uint64_t enabledTags = 0;
342     for (auto tag: g_userEnabledTags) {
343         enabledTags |= tag;
344     }
345     return SetTraceTagsEnabled(enabledTags) && RefreshServices();
346 }
347 
ClearUserSpaceSettings()348 static bool ClearUserSpaceSettings()
349 {
350     // clear userSpace settings
351     return SetTraceTagsEnabled(0) && RefreshServices();
352 }
353 
SetKernelSpaceSettings()354 static bool SetKernelSpaceSettings()
355 {
356     // set kernelSpace settings
357     if (!(SetBufferSize(g_bufferSizeKB) && SetClock(g_clock) &&
358         SetOverWriteEnable(g_overwrite) && SetTgidEnable(true) && SetCmdLinesSize(SAVED_CMDLINES_SIZE))) {
359         fprintf(stderr, "Set trace kernel settings failed.\n");
360         return false;
361     }
362     if (DisableAllFtraceEvents() == false) {
363         fprintf(stderr, "Pre-clear kernel tracers failed.\n");
364         return false; // pre-clear kernel tracers failed
365     }
366     for (const auto& path : g_kernelEnabledPaths) {
367         SetFtraceEnabled(path, true);
368     }
369     return true;
370 }
371 
ClearKernelSpaceSettings()372 static bool ClearKernelSpaceSettings()
373 {
374     // clear kernelSpace settings
375     return DisableAllFtraceEvents() && SetOverWriteEnable(true) && SetBufferSize(1) && SetClock("boot");
376 }
377 
ShowListCategory()378 static void ShowListCategory()
379 {
380     printf("  %18s   description:\n", "tagName:");
381     for (auto it = g_tagMap.begin(); it != g_tagMap.end(); ++it) {
382         string key = it->first; // show categorys
383         TagCategory tag = it->second;
384         if (IsTagSupported(key)) {
385             printf("  %18s - %s\n", tag.name.c_str(), tag.description.c_str());
386         }
387     }
388 }
389 
ShowHelp(const string & cmd)390 static void ShowHelp(const string& cmd)
391 {
392     printf("usage: %s [options] [categories...]\n", cmd.c_str());
393     printf("options include:\n"
394            "  -b N               Sets the size of the buffer (KB) for storing and reading traces. The default \n"
395            "                     buffer size is 2048 KB.\n"
396            "  --buffer_size N    Like \"-b N\".\n"
397            "  -l                 Lists available bytrace categories.\n"
398            "  --list_categories  Like \"-l\".\n"
399            "  -t N               Sets the bytrace running duration in seconds (5s by default), which depends on \n"
400            "                     the time required for analysis.\n"
401            "  --time N           Like \"-t N\".\n"
402            "  --trace_clock clock\n"
403            "                     Sets the type of the clock for adding a timestamp to a trace, which can be\n"
404            "                     boot (default), global, mono, uptime, or perf.\n"
405            "  --trace_begin      Starts capturing traces.\n"
406            "  --trace_dump       Dumps traces to a specified path (stdout by default).\n"
407            "  --trace_finish     Stops capturing traces and dumps traces to a specified path (stdout by default).\n"
408            "  --trace_finish_nodump\n"
409            "                     Stops capturing traces and not dumps traces.\n"
410            "  --overwrite        Sets the action to take when the buffer is full. If this option is used,\n"
411            "                     the latest traces are discarded; if this option is not used (default setting),\n"
412            "                     the earliest traces are discarded.\n"
413            "  -o filename        Specifies the name of the target file (stdout by default).\n"
414            "  --output filename\n"
415            "                     Like \"-o filename\".\n"
416            "  -z                 Compresses a captured trace.\n"
417     );
418 }
419 
420 template <typename T>
StrToNum(const std::string & sString,T & tX)421 inline bool StrToNum(const std::string& sString, T &tX)
422 {
423     // str to num
424     std::istringstream iStream(sString);
425     return (iStream >> tX) ? true : false;
426 }
427 
ParseControlOpt(int optionIndex,bool & isTrue)428 static bool ParseControlOpt(int optionIndex, bool& isTrue)
429 {
430     if (!strcmp(g_longOptions[optionIndex].name, "trace_begin")) {
431         g_traceStart = START_ASYNC;
432         g_traceStop = false;
433         g_traceDump = false;
434         return true;
435     } else if (!strcmp(g_longOptions[optionIndex].name, "trace_finish")) {
436         g_traceStart = START_NONE;
437         g_traceStop = true;
438         g_traceDump = true;
439         return true;
440     } else if (!strcmp(g_longOptions[optionIndex].name, "trace_finish_nodump")) {
441         g_traceStart = START_NONE;
442         g_traceStop = true;
443         g_traceDump = false;
444         return true;
445     } else if (!strcmp(g_longOptions[optionIndex].name, "trace_dump")) {
446         g_traceStart = START_NONE;
447         g_traceStop = false;
448         g_traceDump = true;
449         return true;
450     } else if (!strcmp(g_longOptions[optionIndex].name, "list_categories")) {
451         ShowListCategory();
452         isTrue = false;
453         return true;
454     }
455     return false;
456 }
457 
ParseBufferSizeOpt(int optionIndex,bool & isTrue)458 static bool ParseBufferSizeOpt(int optionIndex, bool& isTrue)
459 {
460     if (!strcmp(g_longOptions[optionIndex].name, "buffer_size")) {
461         if (!StrToNum(optarg, g_bufferSizeKB)) {
462             fprintf(stderr, "Error: buffer size is illegal input. eg: \"--buffer_size 1024\"\n");
463             isTrue = false;
464         } else if (g_bufferSizeKB < MIN_BUFFER_SIZE || g_bufferSizeKB > MAX_BUFFER_SIZE) {
465             fprintf(stderr, "Error: buffer size must be from 256 KB to 300 MB. eg: \"--buffer_size 1024\"\n");
466             isTrue = false;
467         }
468         g_bufferSizeKB = g_bufferSizeKB / PAGE_SIZE_KB * PAGE_SIZE_KB;
469         return true;
470     }
471     return false;
472 }
473 
ParseTraceClockOpt(int optionIndex,bool & isTrue)474 static bool ParseTraceClockOpt(int optionIndex, bool& isTrue)
475 {
476     if (!strcmp(g_longOptions[optionIndex].name, "trace_clock")) {
477         regex re("[a-zA-Z]{4,6}");
478         if (regex_match(optarg, re)) {
479             g_clock = optarg;
480         } else {
481             fprintf(stderr, "Error: \"--trace_clock\" is illegal input. eg: \"--trace_clock boot\"\n");
482             isTrue = false;
483         }
484         return true;
485     } else if (!strcmp(g_longOptions[optionIndex].name, "overwrite")) {
486         g_overwrite = false;
487         return true;
488     }
489     return false;
490 }
491 
ParseOutputOpt(int optionIndex,bool & isTrue)492 static bool ParseOutputOpt(int optionIndex, bool& isTrue)
493 {
494     if (!strcmp(g_longOptions[optionIndex].name, "output")) {
495         struct stat buf;
496         size_t len = strnlen(optarg, MAX_OUTPUT_LEN);
497         if (len == MAX_OUTPUT_LEN || len < 1 || (stat(optarg, &buf) == 0 && (buf.st_mode & S_IFDIR))) {
498             fprintf(stderr, "Error: output file is illegal\n");
499             isTrue = false;
500         } else {
501             g_outputFile = optarg;
502         }
503         return true;
504     }
505     return false;
506 }
507 
ParseHelpTimeOpt(const string & cmd,int optionIndex,bool & isTrue)508 static void ParseHelpTimeOpt(const string& cmd, int optionIndex, bool& isTrue)
509 {
510     if (!strcmp(g_longOptions[optionIndex].name, "help")) {
511         ShowHelp(cmd);
512         isTrue = false;
513     } else if (!strcmp(g_longOptions[optionIndex].name, "time")) {
514         if (!StrToNum(optarg, g_traceDuration)) {
515             fprintf(stderr, "Error: the time is illegal input. eg: \"--time 5\"\n");
516             isTrue = false;
517         } else if (g_traceDuration < 1) {
518             fprintf(stderr, "Error: \"-t %s\" to be greater than zero. eg: \"--time 5\"\n", optarg);
519             isTrue = false;
520         }
521     }
522 }
523 
ParseLongOpt(const string & cmd,int optionIndex,bool & isTrue)524 static void ParseLongOpt(const string& cmd, int optionIndex, bool& isTrue)
525 {
526     bool isFinish = ParseControlOpt(optionIndex, isTrue);
527     if (isFinish) {
528         return;
529     }
530     isFinish = ParseBufferSizeOpt(optionIndex, isTrue);
531     if (isFinish) {
532         return;
533     }
534     isFinish = ParseTraceClockOpt(optionIndex, isTrue);
535     if (isFinish) {
536         return;
537     }
538     isFinish = ParseOutputOpt(optionIndex, isTrue);
539     if (isFinish) {
540         return;
541     }
542     ParseHelpTimeOpt(cmd, optionIndex, isTrue);
543 }
544 
ParseBOpt(int opt,bool & isTrue)545 static bool ParseBOpt(int opt, bool& isTrue)
546 {
547     if (opt == 'b') {
548         if (!StrToNum(optarg, g_bufferSizeKB)) {
549             fprintf(stderr, "Error: buffer size is illegal input. eg: \"--buffer_size 1024\"\n");
550             isTrue = false;
551         } else if (g_bufferSizeKB < MIN_BUFFER_SIZE || g_bufferSizeKB > MAX_BUFFER_SIZE) {
552             fprintf(stderr, "Error: buffer size must be from 256 KB to 300 MB. eg: \"--buffer_size 1024\"\n");
553             isTrue = false;
554         }
555         g_bufferSizeKB = g_bufferSizeKB / PAGE_SIZE_KB * PAGE_SIZE_KB;
556         return true;
557     }
558     return false;
559 }
560 
ParseHltOpt(int opt,char ** argv,bool & isTrue)561 static bool ParseHltOpt(int opt, char** argv, bool& isTrue)
562 {
563     if (opt == 'h') {
564         ShowHelp(argv[0]);
565         isTrue = false;
566         return true;
567     } else if (opt == 'l') {
568         ShowListCategory();
569         isTrue = false;
570         return true;
571     } else if (opt == 't') {
572         if (!StrToNum(optarg, g_traceDuration)) {
573             fprintf(stderr, "Error: the time is illegal input. eg: \"--time 5\"\n");
574             isTrue = false;
575         } else if (g_traceDuration < 1) {
576             fprintf(stderr, "Error: \"-t %s\" to be greater than zero. eg: \"--time 5\"\n", optarg);
577             isTrue = false;
578         }
579         return true;
580     }
581     return false;
582 }
583 
ParseOzOpt(int opt,char ** argv,bool & isTrue)584 static bool ParseOzOpt(int opt, char** argv, bool& isTrue)
585 {
586     if (opt == 'o') {
587         struct stat buf;
588         size_t len = strnlen(optarg, MAX_OUTPUT_LEN);
589         if (len == MAX_OUTPUT_LEN || len < 1 || (stat(optarg, &buf) == 0 && (buf.st_mode & S_IFDIR))) {
590             fprintf(stderr, "Error: output file is illegal\n");
591             isTrue = false;
592         } else {
593             g_outputFile = optarg;
594         }
595         return true;
596     } else if (opt == 'z') {
597         g_compress = true;
598         return true;
599     }
600     return false;
601 }
602 
ParseDefaultOpt(int opt,char ** argv,int optIndex,bool & isTrue)603 static void ParseDefaultOpt(int opt, char** argv, int optIndex, bool& isTrue)
604 {
605     if (opt == 0) {
606         ParseLongOpt(argv[0], optIndex, isTrue);
607     } else {
608         ShowHelp(argv[0]);
609         isTrue = false;
610     }
611 }
612 
ParseOpt(int opt,char ** argv,int optIndex)613 static bool ParseOpt(int opt, char** argv, int optIndex)
614 {
615     bool isTrue = true;
616     bool isFinish = ParseBOpt(opt, isTrue);
617     if (isFinish) {
618         return isTrue;
619     }
620     isFinish = ParseHltOpt(opt, argv, isTrue);
621     if (isFinish) {
622         return isTrue;
623     }
624     isFinish = ParseOzOpt(opt, argv, isTrue);
625     if (isFinish) {
626         return isTrue;
627     }
628     ParseDefaultOpt(opt, argv, optIndex, isTrue);
629     return isTrue;
630 }
631 
IsInvalidOpt(int argc,char ** argv)632 static void IsInvalidOpt(int argc, char** argv)
633 {
634     for (int i = optind; i < argc; i++) {
635         if (!IsTagSupported(argv[i])) {
636             fprintf(stderr, "Error: \"%s\" is not support category on this device\n", argv[i]);
637             // tag is not support, exit
638             exit(-1);
639         }
640     }
641 }
642 
HandleOpt(int argc,char ** argv)643 static bool HandleOpt(int argc, char** argv)
644 {
645     // handle opt
646     bool isTrue = true;
647     int opt = 0;
648     int optionIndex = 0;
649     string shortOption = "b:c:hlo:t:z";
650     int argcSize = argc;
651     while (isTrue && argcSize-- > 0) {
652         opt = getopt_long(argc, argv, shortOption.c_str(), g_longOptions, &optionIndex);
653         if (opt < 0) {
654             IsInvalidOpt(argc, argv);
655             break;
656         }
657         isTrue = ParseOpt(opt, argv, optionIndex); // parse Opt
658     }
659     return isTrue;
660 }
661 
TruncateFile(const string & path)662 static bool TruncateFile(const string& path)
663 {
664     // rebuild file
665     int fd = creat((g_traceRootPath + path).c_str(), 0);
666     if (fd == -1) {
667         fprintf(stderr, "Error: clear %s, errno: %d\n", (g_traceRootPath + path).c_str(), errno);
668         return false;
669     }
670     close(fd);
671     fd = -1;
672     return true;
673 }
674 
ClearTrace()675 static bool ClearTrace()
676 {
677     // truncate file
678     return TruncateFile(TRACE_PATH);
679 }
680 
StartTrace()681 static bool StartTrace()
682 {
683     // set trace_on 1
684     if (!SetFtraceEnabled(TRACING_ON_PATH, true)) {
685         return false;
686     }
687     ClearTrace();
688     printf("capturing trace...\n");
689     fflush(stdout);
690     return true;
691 }
692 
WaitForTraceDone(void)693 static void WaitForTraceDone(void)
694 {
695     // wait for traceDone
696     struct timespec ts = {0, 0};
697     ts.tv_sec = g_traceDuration;
698     ts.tv_nsec = 0;
699     while ((nanosleep(&ts, &ts) == -1) && (errno == EINTR)) {}
700 }
701 
StopTrace()702 static bool StopTrace()
703 {
704     return SetFtraceEnabled(TRACING_ON_PATH, false);
705 }
706 
DumpCompressedTrace(int traceFd,int outFd)707 static void DumpCompressedTrace(int traceFd, int outFd)
708 {
709     // dump compressedTrace
710     z_stream zs { nullptr };
711     int flush = Z_NO_FLUSH;
712     ssize_t bytesWritten;
713     ssize_t bytesRead;
714     if (memset_s(&zs, sizeof(zs), 0, sizeof(zs)) != 0) {
715         fprintf(stderr, "Error: zip stream buffer init failed\n");
716         return;
717     }
718     // begin deflate init
719     int ret = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
720     if (ret != Z_OK) {
721         fprintf(stderr, "Error: initializing zlib: %d\n", ret);
722         return;
723     }
724     std::unique_ptr<uint8_t[]>  in = std::make_unique<uint8_t[]>(CHUNK_SIZE);
725     std::unique_ptr<uint8_t[]>  out = std::make_unique<uint8_t[]>(CHUNK_SIZE);
726     if (!in || !out) {
727         fprintf(stderr, "Error: couldn't allocate buffers\n");
728         return;
729     }
730     zs.next_out = reinterpret_cast<Bytef*>(out.get());
731     zs.avail_out = CHUNK_SIZE;
732 
733     do {
734         // no flush
735         if (zs.avail_in == 0 && flush == Z_NO_FLUSH) {
736             bytesRead = TEMP_FAILURE_RETRY(read(traceFd, in.get(), CHUNK_SIZE));
737             if (bytesRead == 0) {
738                 flush = Z_FINISH;
739             } else if (bytesRead == -1) {
740                 fprintf(stderr, "Error: reading trace, errno: %d\n", errno);
741                 break;
742             } else {
743                 zs.next_in = reinterpret_cast<Bytef*>(in.get());
744                 zs.avail_in = bytesRead;
745             }
746         }
747         if (zs.avail_out == 0) {
748             bytesWritten = TEMP_FAILURE_RETRY(write(outFd, out.get(), CHUNK_SIZE));
749             if (bytesWritten < CHUNK_SIZE) {
750                 fprintf(stderr, "Error: writing deflated trace, errno: %d\n", errno);
751                 break;
752             }
753             zs.next_out = reinterpret_cast<Bytef*>(out.get());
754             zs.avail_out = CHUNK_SIZE;
755         }
756         // deflate
757         ret = deflate(&zs, flush);
758         if (flush == Z_FINISH && ret == Z_STREAM_END) {
759             size_t have = CHUNK_SIZE - zs.avail_out;
760             bytesWritten = TEMP_FAILURE_RETRY(write(outFd, out.get(), have));
761             if (static_cast<size_t>(bytesWritten) < have) {
762                 fprintf(stderr, "Error: writing deflated trace, errno: %d\n", errno);
763             }
764             break;
765         } else if (ret != Z_OK) {
766             if (ret == Z_ERRNO) {
767                 fprintf(stderr, "Error: deflate failed with errno %d\n", errno);
768             } else {
769                 fprintf(stderr, "Error: deflate failed return %d\n", ret);
770             }
771             break;
772         }
773     } while (ret == Z_OK);
774 
775     // deflate end
776     ret = deflateEnd(&zs);
777     if (ret != Z_OK) {
778         fprintf(stderr, "error cleaning up zlib: %d\n", ret);
779     }
780 }
781 
DumpTrace(int outFd,const string & path)782 static void DumpTrace(int outFd, const string& path)
783 {
784     // standardize file paths
785     string resolvedPath = CanonicalizeSpecPath((g_traceRootPath + path).c_str());
786     int traceFd = open(resolvedPath.c_str(), O_RDWR);
787     if (traceFd == -1) {
788         fprintf(stderr, "error opening %s, errno: %d\n", path.c_str(), errno);
789         return;
790     }
791     ssize_t bytesWritten;
792     ssize_t bytesRead;
793     if (g_compress) {
794         // dump and compress trace
795         DumpCompressedTrace(traceFd, outFd);
796     } else {
797         char buffer[BLOCK_SIZE];
798         do {
799             bytesRead = TEMP_FAILURE_RETRY(read(traceFd, buffer, BLOCK_SIZE));
800             if ((bytesRead == 0) || (bytesRead == -1)) {
801                 break;
802             }
803             bytesWritten = TEMP_FAILURE_RETRY(write(outFd, buffer, bytesRead));
804         } while (bytesWritten > 0);
805     }
806     // close fd
807     close(traceFd);
808 }
809 
MarkOthersClockSync()810 static bool MarkOthersClockSync()
811 {
812     constexpr unsigned int bufferSize = 128; // buffer size
813     char buffer[bufferSize] = { 0 };
814     // standardize file paths
815     string resolvedPath = CanonicalizeSpecPath((g_traceRootPath + TRACE_MARKER_PATH).c_str());
816     int fd = open(resolvedPath.c_str(), O_WRONLY);
817     if (fd == -1) {
818         fprintf(stderr, "Error: opening %s, errno: %d\n", TRACE_MARKER_PATH.c_str(), errno);
819         return false;
820     }
821 
822     struct timespec mts = {0, 0};
823     struct timespec rts = {0, 0};
824     if (clock_gettime(CLOCK_REALTIME, &rts) == -1) { // get timestamp from 1970s
825         fprintf(stderr, "Error: get realtime, errno: %d\n", errno);
826         close(fd);
827         return false;
828     } else if (clock_gettime(CLOCK_MONOTONIC, &mts) == -1) { // get timestamp from machine startup
829         fprintf(stderr, "Error: get parent_ts, errno: %d\n", errno);
830         close(fd);
831         return false;
832     }
833     constexpr unsigned int nanoSeconds = 1000000000; // seconds converted to nanoseconds
834     constexpr unsigned int nanoToMill = 1000000; // millisecond converted to nanoseconds
835     constexpr float nanoToSecond = 1000000000.0f; // consistent with the ftrace timestamp format
836     int len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1,
837         "trace_event_clock_sync: realtime_ts=%" PRId64 "\n",
838         static_cast<int64_t>((rts.tv_sec * nanoSeconds + rts.tv_nsec) / nanoToMill));
839     if (len < 0) { // entering data into buffer error
840         fprintf(stderr, "Error: entering data into buffer, errno: %d\n", errno);
841         close(fd);
842         return false;
843     }
844     if (write(fd, buffer, len) < 0) {
845         fprintf(stderr, "Warning: writing clock sync marker, errno: %d\n", errno);
846         fprintf(stderr, "the buffer is not enough, please increase the buffer\n");
847     }
848     len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "trace_event_clock_sync: parent_ts=%f\n",
849         static_cast<float>(((static_cast<float>(mts.tv_sec)) * nanoSeconds + mts.tv_nsec) / nanoToSecond));
850     if (len < 0) { // entering data into buffer error
851         fprintf(stderr, "Error: entering data into buffer, errno: %d\n", errno);
852         close(fd);
853         return false;
854     }
855     if (write(fd, buffer, len) < 0) {
856         fprintf(stderr, "Warning: writing clock sync marker, errno: %d\n", errno);
857         fprintf(stderr, "the buffer is not enough, please increase the buffer\n");
858     }
859     close(fd);
860     return true;
861 }
862 
InitDiskSupportTags()863 static void InitDiskSupportTags()
864 {
865     // disk support tags
866     g_tagMap["disk"] = { "disk", "Disk I/O", 0, KERNEL, {
867         { "events/f2fs/f2fs_sync_file_enter/enable" },
868         { "events/f2fs/f2fs_sync_file_exit/enable" },
869         { "events/f2fs/f2fs_write_begin/enable" },
870         { "events/f2fs/f2fs_write_end/enable" },
871         { "events/ext4/ext4_da_write_begin/enable" },
872         { "events/ext4/ext4_da_write_end/enable" },
873         { "events/ext4/ext4_sync_file_enter/enable" },
874         { "events/ext4/ext4_sync_file_exit/enable" },
875         { "events/block/block_rq_issue/enable" },
876         { "events/block/block_rq_complete/enable" },
877     }};
878     g_tagMap["mmc"] = { "mmc", "eMMC commands", 0, KERNEL, {
879         { "events/mmc/enable" },
880     }};
881     g_tagMap["ufs"] = { "ufs", "UFS commands", 0, KERNEL, {
882         { "events/ufs/enable" },
883     }};
884 }
885 
InitHardwareSupportTags()886 static void InitHardwareSupportTags()
887 {
888     // hardware support tags
889     g_tagMap["irq"] = { "irq", "IRQ Events", 0, KERNEL, {
890         { "events/irq/enable" },
891         { "events/ipi/enable" },
892     }};
893     g_tagMap["irqoff"] = { "irqoff", "IRQ-disabled code section tracing", 0, KERNEL, {
894         { "events/preemptirq/irq_enable/enable" },
895         { "events/preemptirq/irq_disable/enable" },
896     }};
897     InitDiskSupportTags();
898     g_tagMap["i2c"] = { "i2c", "I2C Events", 0, KERNEL, {
899         { "events/i2c/enable" },
900         { "events/i2c/i2c_read/enable" },
901         { "events/i2c/i2c_write/enable" },
902         { "events/i2c/i2c_result/enable" },
903         { "events/i2c/i2c_reply/enable" },
904         { "events/i2c/smbus_read/enable" },
905         { "events/i2c/smbus_write/enable" },
906         { "events/i2c/smbus_result/enable" },
907         { "events/i2c/smbus_reply/enable" },
908     }};
909     g_tagMap["regulators"] = { "regulators", "Voltage and Current Regulators", 0, KERNEL, {
910         { "events/regulator/enable" },
911     }};
912     g_tagMap["membus"] = { "membus", "Memory Bus Utilization", 0, KERNEL, {
913         { "events/memory_bus/enable" },
914     }};
915 }
916 
InitCpuSupportTags()917 static void InitCpuSupportTags()
918 {
919     // cpu support tags
920     g_tagMap["freq"] = { "freq", "CPU Frequency", 0, KERNEL, {
921         { "events/power/cpu_frequency/enable" },
922         { "events/power/clock_set_rate/enable" },
923         { "events/power/clock_disable/enable" },
924         { "events/power/clock_enable/enable" },
925         { "events/clk/clk_set_rate/enable" },
926         { "events/clk/clk_disable/enable" },
927         { "events/clk/clk_enable/enable" },
928         { "events/power/cpu_frequency_limits/enable" },
929     }};
930     g_tagMap["idle"] = { "idle", "CPU Idle", 0, KERNEL, {
931         { "events/power/cpu_idle/enable" },
932     }};
933     g_tagMap["load"] = { "load", "CPU Load", 0, KERNEL, {
934         { "events/cpufreq_interactive/enable" },
935     }};
936 }
937 
InitKernelSupportTags()938 static void InitKernelSupportTags()
939 {
940     // kernel support tags
941     g_tagMap["sched"] = { "sched", "CPU Scheduling", 0, KERNEL, {
942         { "events/sched/sched_switch/enable" },
943         { "events/sched/sched_wakeup/enable" },
944         { "events/sched/sched_wakeup_new/enable" },
945         { "events/sched/sched_waking/enable" },
946         { "events/sched/sched_blocked_reason/enable" },
947         { "events/sched/sched_pi_setprio/enable" },
948         { "events/sched/sched_process_exit/enable" },
949         { "events/cgroup/enable" },
950         { "events/oom/oom_score_adj_update/enable" },
951         { "events/task/task_newtask/enable" },
952         { "events/task/task_rename/enable" },
953     }};
954     g_tagMap["preemptoff"] = { "preemptoff", "Preempt-disabled code section tracing", 0, KERNEL, {
955         { "events/preemptirq/preempt_enable/enable" },
956         { "events/preemptirq/preempt_disable/enable" },
957     }};
958 
959     g_tagMap["binder"] = { "binder", "Binder kernel Info", 0, KERNEL, {
960         { "events/binder/binder_transaction/enable" },
961         { "events/binder/binder_transaction_received/enable" },
962         { "events/binder/binder_transaction_alloc_buf/enable" },
963         { "events/binder/binder_set_priority/enable" },
964         { "events/binder/binder_lock/enable" },
965         { "events/binder/binder_unlock/enable" },
966         { "events/binder/binder_locked/enable" },
967     }};
968 
969     g_tagMap["sync"] = { "sync", "Synchronization", 0, KERNEL, {
970         // linux kernel > 4.9
971         { "events/dma_fence/enable" },
972     }};
973     g_tagMap["workq"] = { "workq", "Kernel Workqueues", 0, KERNEL, {
974         { "events/workqueue/enable" },
975     }};
976     g_tagMap["memreclaim"] = { "memreclaim", "Kernel Memory Reclaim", 0, KERNEL, {
977         { "events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
978         { "events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
979         { "events/vmscan/mm_vmscan_kswapd_wake/enable" },
980         { "events/vmscan/mm_vmscan_kswapd_sleep/enable" },
981         { "events/lowmemorykiller/enable" },
982     }};
983     g_tagMap["pagecache"] = { "pagecache", "Page cache", 0, KERNEL, {
984         { "events/filemap/enable" },
985     }};
986     g_tagMap["memory"] = { "memory", "Memory", 0, KERNEL, {
987         { "events/kmem/rss_stat/enable" },
988         { "events/kmem/ion_heap_shrink/enable" },
989         { "events/kmem/ion_heap_grow/enable" },
990     }};
991     InitCpuSupportTags();
992     InitHardwareSupportTags();
993 }
994 
InitOtherUserTags()995 static void InitOtherUserTags()
996 {
997     g_tagMap["dhfwk"] = { "dhfwk", "Distributed Hardware FWK", HITRACE_TAG_DISTRIBUTED_HARDWARE_FWK, USER, {}};
998     g_tagMap["account"] = { "account", "Account Manager", HITRACE_TAG_ACCOUNT_MANAGER, USER, {}};
999     g_tagMap["daudio"] = { "daudio", "Distributed Audio", HITRACE_TAG_DISTRIBUTED_AUDIO, USER, {}};
1000     g_tagMap["dscreen"] = { "dscreen", "Distributed Screen", HITRACE_TAG_DISTRIBUTED_SCREEN, USER, {}};
1001     g_tagMap["dcamera"] = { "dcamera", "Distributed Camera", HITRACE_TAG_DISTRIBUTED_CAMERA, USER, {}};
1002     g_tagMap["dinput"] = { "dinput", "Distributed Input", HITRACE_TAG_DISTRIBUTED_INPUT, USER, {}};
1003     g_tagMap["devicemanager"] = { "devicemanager", "Device Manager", HITRACE_TAG_DEVICE_MANAGER, USER, {}};
1004     g_tagMap["deviceprofile"] = { "deviceprofile", "Device Profile", HITRACE_TAG_DEVICE_PROFILE, USER, {}};
1005     g_tagMap["dsched"] = { "dsched", "Distributed Schedule", HITRACE_TAG_DISTRIBUTED_SCHEDULE, USER, {}};
1006     g_tagMap["huks"] = { "huks", "Universal KeyStore", HITRACE_TAG_HUKS, USER, {}};
1007     g_tagMap["dlpcre"] = { "dlpcre", "Dlp Credential Service", HITRACE_TAG_DLP_CREDENTIAL, USER, {}};
1008     g_tagMap["app"] = { "app", "APP Module", HITRACE_TAG_APP, USER, {}};
1009     g_tagMap["samgr"] = { "samgr", "samgr", HITRACE_TAG_SAMGR, USER, {}};
1010     g_tagMap["zbinder"] = { "zbinder", "OpenHarmony binder communication", 0, KERNEL, {
1011         { "events/zbinder/enable" },
1012     }};
1013     g_tagMap["gresource"] = { "gresource", "Global Resource Manager", HITRACE_TAG_GLOBAL_RESMGR, USER, {}};
1014     g_tagMap["power"] = { "power", "Power Manager", HITRACE_TAG_POWER, USER, {}};
1015     g_tagMap["filemanagement"] = { "filemanagement", "filemanagement", HITRACE_TAG_FILEMANAGEMENT, USER, {}};
1016     g_tagMap["dslm"] = {"dslm", "device security level", HITRACE_TAG_DLSM, USER, {}};
1017     g_tagMap["nweb"] = {"nweb", "NWEB Module", HITRACE_TAG_NWEB, USER, {}};
1018     g_tagMap["useriam"] = {"useriam", "useriam", HITRACE_TAG_USERIAM, USER, {}};
1019     g_tagMap["net"] = {"net", "net", HITRACE_TAG_NET, USER, {}};
1020     g_tagMap["accesscontrol"] = {"accesscontrol", "Access Control Module", HITRACE_TAG_ACCESS_CONTROL, USER, {}};
1021     g_tagMap["interconn"] = {"interconn", "Interconnection subsystem", HITRACE_TAG_INTERCONNECTION, USER, {}};
1022     g_tagMap["commonlibrary"] = {"commonlibrary", "Commonlibrary subsystem", HITRACE_TAG_COMMONLIBRARY, USER, {}};
1023     g_tagMap["musl"] = {"musl", "Musl Module", HITRACE_TAG_MUSL, USER, {}};
1024     g_tagMap["ffrt"] = {"ffrt", "Ffrt Tasks", HITRACE_TAG_FFRT, USER, {}};
1025 }
1026 
InitAllSupportTags()1027 static void InitAllSupportTags()
1028 {
1029     // OHOS
1030     g_tagMap["ability"] = { "ability", "Ability Manager", HITRACE_TAG_ABILITY_MANAGER, USER, {}};
1031     g_tagMap["ohos"] = { "ohos", "OpenHarmony", HITRACE_TAG_OHOS, USER, {}};
1032     g_tagMap["zcamera"] = { "zcamera", "OpenHarmony Camera Module", HITRACE_TAG_ZCAMERA, USER, {}};
1033     g_tagMap["zmedia"] = { "zmedia", "OpenHarmony Media Module", HITRACE_TAG_ZMEDIA, USER, {}};
1034     g_tagMap["zimage"] = { "zimage", "OpenHarmony Image Module", HITRACE_TAG_ZIMAGE, USER, {}};
1035     g_tagMap["zaudio"] = { "zaudio", "OpenHarmony Audio Module", HITRACE_TAG_ZAUDIO, USER, {}};
1036     g_tagMap["distributeddatamgr"] = { "distributeddatamgr", "Distributed Data Manager",
1037         HITRACE_TAG_DISTRIBUTEDDATA, USER, {}};
1038     g_tagMap["mdfs"] = { "mdfs", "Mobile Distributed File System", HITRACE_TAG_MDFS, USER, {}};
1039     g_tagMap["graphic"] = { "graphic", "Graphic Module", HITRACE_TAG_GRAPHIC_AGP, USER, {}};
1040     g_tagMap["ace"] = { "ace", "ACE development framework", HITRACE_TAG_ACE, USER, {}};
1041     g_tagMap["notification"] = { "notification", "Notification Module", HITRACE_TAG_NOTIFICATION, USER, {}};
1042     g_tagMap["multimodalinput"] = { "multimodalinput", "Multimodal Input Module",
1043         HITRACE_TAG_MULTIMODALINPUT, USER, {}};
1044     g_tagMap["misc"] = { "misc", "Misc Module", HITRACE_TAG_MISC, USER, {}};
1045     g_tagMap["sensors"] = { "sensors", "Sensors Module", HITRACE_TAG_SENSORS, USER, {}};
1046     g_tagMap["msdp"] = { "msdp", "Multimodal Sensor Data Platform", HITRACE_TAG_MSDP, USER, {}};
1047     g_tagMap["dsoftbus"] = { "dsoftbus", "Distributed Softbus", HITRACE_TAG_DSOFTBUS, USER, {}};
1048     g_tagMap["rpc"] = { "rpc", "RPC and IPC", HITRACE_TAG_RPC, USER, {}};
1049     g_tagMap["ark"] = { "ark", "ARK Module", HITRACE_TAG_ARK, USER, {}};
1050     g_tagMap["window"] = { "window", "Window Manager", HITRACE_TAG_WINDOW_MANAGER, USER, {}};
1051     g_tagMap["accessibility"] = { "accessibility", "Accessibility Manager",
1052         HITRACE_TAG_ACCESSIBILITY_MANAGER, USER, {}};
1053     InitOtherUserTags();
1054 
1055     // Kernel os
1056     InitKernelSupportTags();
1057 }
1058 
InterruptExit(int signo)1059 static void InterruptExit(int signo)
1060 {
1061     _exit(-1);
1062 }
1063 
DumpTrace(bool & isTrue)1064 static void DumpTrace(bool& isTrue)
1065 {
1066     if (isTrue && g_traceDump) {
1067         int outFd = STDOUT_FILENO;
1068         if (g_outputFile.size() > 0) {
1069             printf("write trace to %s\n", g_outputFile.c_str());
1070             string resolvedPath = CanonicalizeSpecPath(g_outputFile.c_str());
1071             outFd = open(resolvedPath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1072         }
1073         if (outFd == -1) {
1074             fprintf(stderr, "Failed to open file '%s', err=%d", g_outputFile.c_str(), errno);
1075             isTrue = false;
1076         } else {
1077             dprintf(outFd, "TRACE:\n");
1078             DumpTrace(outFd, TRACE_PATH);
1079             if (outFd != STDOUT_FILENO) {
1080                 close(outFd);
1081                 outFd = -1;
1082             }
1083         }
1084         ClearTrace();
1085     }
1086 }
1087 
main(int argc,char ** argv)1088 int main(int argc, char **argv)
1089 {
1090     setgid(SHELL_UID);
1091     (void)signal(SIGKILL, InterruptExit);
1092     (void)signal(SIGINT, InterruptExit);
1093 
1094     if (!IsTraceMounted()) {
1095         exit(-1);
1096     }
1097 
1098     InitAllSupportTags();
1099 
1100     if (!HandleOpt(argc, argv)) {
1101         exit(-1);
1102     }
1103 
1104     if (g_traceStart != START_NONE) {
1105         if (!SetKernelSpaceSettings()) {
1106             ClearKernelSpaceSettings();
1107             exit(-1);
1108         }
1109     }
1110 
1111     bool isTrue = true;
1112     if (g_traceStart != START_NONE) {
1113         isTrue = isTrue && StartTrace();
1114         if (!SetUserSpaceSettings()) {
1115             ClearKernelSpaceSettings();
1116             ClearUserSpaceSettings();
1117             exit(-1);
1118         }
1119         if (g_traceStart == START_ASYNC) {
1120             return isTrue ? 0 : -1;
1121         }
1122         WaitForTraceDone();
1123     }
1124 
1125     // following is dump and stop handling
1126     isTrue = isTrue && MarkOthersClockSync();
1127 
1128     if (g_traceStop) {
1129         // clear user tags first and sleep a little to let apps already be notified.
1130         ClearUserSpaceSettings();
1131         std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_MILLISECONDS));
1132         isTrue = isTrue && StopTrace();
1133     }
1134     DumpTrace(isTrue);
1135     if (g_traceStop) {
1136         // clear kernel setting including clock type after dump(MUST) and tracing_on is off.
1137         ClearKernelSpaceSettings();
1138     }
1139     return isTrue ? 0 : -1;
1140 }
1141