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