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