• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 "hitrace_dump.h"
17 
18 #include <map>
19 #include <atomic>
20 #include <fstream>
21 #include <set>
22 #include <thread>
23 #include <vector>
24 #include <string>
25 
26 #include <unistd.h>
27 #include <cstdio>
28 #include <cstdlib>
29 #include <sys/time.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <fcntl.h>
33 #include <cinttypes>
34 #include <utility>
35 #include <dirent.h>
36 
37 #include "cJSON.h"
38 #include "parameters.h"
39 #include "hilog/log.h"
40 #include "securec.h"
41 
42 
43 using OHOS::HiviewDFX::HiLog;
44 using OHOS::HiviewDFX::Hitrace::TraceErrorCode;
45 using OHOS::HiviewDFX::Hitrace::TraceRetInfo;
46 using OHOS::HiviewDFX::Hitrace::TraceMode;
47 
48 namespace {
49 
50 struct TagCategory {
51     std::string description;
52     uint64_t tag;
53     int type;
54     std::vector<std::string> sysFiles;
55 };
56 
57 struct TraceParams {
58     std::vector<std::string> tags;
59     std::vector<std::string> tagGroups;
60     std::string bufferSize;
61     std::string clockType;
62     std::string isOverWrite;
63     std::string outputFile;
64 };
65 
66 constexpr uint16_t MAGIC_NUMBER = 57161;
67 constexpr uint16_t VERSION_NUMBER = 1;
68 constexpr uint8_t FILE_RAW_TRACE = 0;
69 constexpr int UNIT_TIME = 100000;
70 
71 const int DEFAULT_BUFFER_SIZE = 12 * 1024;
72 const int HIGHER_BUFFER_SIZE = 18 * 1024;
73 const int SAVED_CMDLINES_SIZE = 1024;
74 
75 const std::string DEFAULT_OUTPUT_DIR = "/data/log/hitrace/";
76 
77 struct TraceFileHeader {
78     uint16_t magicNumber {MAGIC_NUMBER};
79     uint8_t fileType {FILE_RAW_TRACE};
80     uint16_t versionNumber {VERSION_NUMBER};
81     uint32_t reserved {0};
82 };
83 
84 enum ContentType : uint8_t {
85     CONTENT_TYPE_DEFAULT = 0,
86     CONTENT_TYPE_EVENTS_FORMAT = 1,
87     CONTENT_TYPE_CMDLINES  = 2,
88     CONTENT_TYPE_TGIDS = 3,
89     CONTENT_TYPE_CPU_RAW = 4
90 };
91 
92 struct TraceFileContentHeader {
93     uint8_t type = CONTENT_TYPE_DEFAULT;
94     uint32_t length = 0;
95 };
96 
97 struct LastCpuInfo {
98     std::pair<uint64_t, uint64_t> idleAndTotal = {0, 0};
99     bool isNormal = true;
100 };
101 
102 struct CpuStat {
103     int8_t cpuId = -1; // 总的为-1
104     uint64_t user = 0;
105     uint64_t nice = 0;
106     uint64_t system = 0;
107     uint64_t idle = 0;
108     uint64_t iowait = 0;
109     uint64_t irq = 0;
110     uint64_t softirq = 0;
111     uint64_t steal = 0;
112     uint64_t guest = 0;
113     uint64_t guestNice = 0;
114 };
115 
116 struct PageHeader {
117     uint64_t timestamp = 0;
118     uint64_t size = 0;
119     uint8_t overwrite = 0;
120     uint8_t *startPos = nullptr;
121     uint8_t *endPos = nullptr;
122 };
123 
124 #ifndef PAGE_SIZE
125 constexpr size_t PAGE_SIZE = 4096;
126 #endif
127 
128 constexpr uint64_t HITRACE_TAG = 0xD002D33;
129 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HITRACE_TAG, "HitraceDump"};
130 std::atomic<bool> g_dumpFlag(false);
131 std::atomic<bool> g_dumpEnd(true);
132 bool g_monitor = false; // close service monitor for now
133 TraceMode g_traceMode = TraceMode::CLOSE;
134 std::string g_traceRootPath;
135 std::vector<std::pair<std::string, int>> g_traceFilesTable;
136 std::vector<std::string> g_outputFilesForCmd;
137 
138 TraceParams g_currentTraceParams = {};
139 
Split(const std::string & str,char delimiter)140 std::vector<std::string> Split(const std::string &str, char delimiter)
141 {
142     std::vector<std::string> res;
143     size_t startPos = 0;
144     for (size_t i = 0; i < str.size(); i++) {
145         if (str[i] == delimiter) {
146             res.push_back(str.substr(startPos, i - startPos));
147             startPos = i + 1;
148         }
149     }
150     if (startPos < str.size()) {
151         res.push_back(str.substr(startPos));
152     }
153     return res;
154 }
155 
IsTraceMounted()156 bool IsTraceMounted()
157 {
158     const std::string debugfsPath = "/sys/kernel/debug/tracing/";
159     const std::string tracefsPath = "/sys/kernel/tracing/";
160     if (access((debugfsPath + "trace_marker").c_str(), F_OK) != -1) {
161         g_traceRootPath = debugfsPath;
162         return true;
163     }
164     if (access((tracefsPath + "trace_marker").c_str(), F_OK) != -1) {
165         g_traceRootPath = tracefsPath;
166         return true;
167     }
168     HiLog::Error(LABEL, "IsTraceMounted: Did not find trace folder");
169     return false;
170 }
171 
172 // Arch is 64bit when reserved = 0; Arch is 32bit when reserved = 1.
GetArchWordSize(TraceFileHeader & header)173 void GetArchWordSize(TraceFileHeader& header)
174 {
175     if (sizeof(void*) == sizeof(uint64_t)) {
176         header.reserved = 0;
177     } else if (sizeof(void*) == sizeof(uint32_t)) {
178         header.reserved = 1;
179     }
180     HiLog::Info(LABEL, "Kernel bit is %{public}d.", header.reserved);
181 }
182 
ParseJsonFromFile(const std::string & filePath)183 cJSON* ParseJsonFromFile(const std::string& filePath)
184 {
185     std::ifstream inFile(filePath, std::ios::in);
186     if (!inFile.is_open()) {
187         HiLog::Error(LABEL, "ParseJsonFromFile: %{pubilc}s is not existed.", filePath.c_str());
188         return nullptr;
189     }
190     std::string fileContent((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
191     cJSON* root = cJSON_Parse(fileContent.c_str());
192     if (root == nullptr) {
193         HiLog::Error(LABEL, "ParseJsonFromFile: %{pubilc}s is not in JSON format.", filePath.c_str());
194     }
195     inFile.close();
196     return root;
197 }
198 
ParseTagCategory(cJSON * tagCategoryNode,std::map<std::string,TagCategory> & allTags)199 bool ParseTagCategory(cJSON* tagCategoryNode, std::map<std::string, TagCategory>& allTags)
200 {
201     cJSON* tags = nullptr;
202     cJSON_ArrayForEach(tags, tagCategoryNode) {
203         TagCategory tagCategory;
204         cJSON* description = cJSON_GetObjectItem(tags, "description");
205         if (description != nullptr) {
206             tagCategory.description = description->valuestring;
207         }
208         cJSON* tagOffset = cJSON_GetObjectItem(tags, "tag_offset");
209         if (tagOffset != nullptr) {
210             tagCategory.tag = 1ULL << tagOffset->valueint;
211         }
212         cJSON* type = cJSON_GetObjectItem(tags, "type");
213         if (type != nullptr) {
214             tagCategory.type = type->valueint;
215         }
216         cJSON* sysFiles = cJSON_GetObjectItem(tags, "sysFiles");
217         if (sysFiles != nullptr && cJSON_IsArray(sysFiles)) {
218             cJSON* sysFile = nullptr;
219             cJSON_ArrayForEach(sysFile, sysFiles) {
220                 if (cJSON_IsString(sysFile)) {
221                     tagCategory.sysFiles.push_back(sysFile->valuestring);
222                 }
223             }
224         }
225         allTags.insert(std::pair<std::string, TagCategory>(tags->string, tagCategory));
226     }
227     return true;
228 }
229 
ParseTagGroups(cJSON * tagGroupsNode,std::map<std::string,std::vector<std::string>> & tagGroupTable)230 bool ParseTagGroups(cJSON* tagGroupsNode, std::map<std::string, std::vector<std::string>> &tagGroupTable)
231 {
232     cJSON* tagGroup = nullptr;
233     cJSON_ArrayForEach(tagGroup, tagGroupsNode) {
234         std::string tagGroupName = tagGroup->string;
235         std::vector<std::string> tagList;
236         cJSON* tag = nullptr;
237         cJSON_ArrayForEach(tag, tagGroup) {
238             tagList.push_back(tag->valuestring);
239         }
240         tagGroupTable.insert(std::pair<std::string, std::vector<std::string>>(tagGroupName, tagList));
241     }
242     return true;
243 }
244 
ParseTagInfo(std::map<std::string,TagCategory> & allTags,std::map<std::string,std::vector<std::string>> & tagGroupTable)245 bool ParseTagInfo(std::map<std::string, TagCategory> &allTags,
246                   std::map<std::string, std::vector<std::string>> &tagGroupTable)
247 {
248     std::string traceUtilsPath = "/system/etc/hiview/hitrace_utils.json";
249     cJSON* root = ParseJsonFromFile(traceUtilsPath);
250     if (root == nullptr) {
251         return false;
252     }
253     cJSON* tagCategory = cJSON_GetObjectItem(root, "tag_category");
254     if (tagCategory == nullptr) {
255         HiLog::Error(LABEL, "ParseTagInfo: %{pubilc}s is not contain tag_category node.", traceUtilsPath.c_str());
256         cJSON_Delete(root);
257         return false;
258     }
259     if (!ParseTagCategory(tagCategory, allTags)) {
260         cJSON_Delete(root);
261         return false;
262     }
263     cJSON* tagGroups = cJSON_GetObjectItem(root, "tag_groups");
264     if (tagGroups == nullptr) {
265         HiLog::Error(LABEL, "ParseTagInfo: %{pubilc}s is not contain tag_groups node.", traceUtilsPath.c_str());
266         cJSON_Delete(root);
267         return false;
268     }
269     if (!ParseTagGroups(tagGroups, tagGroupTable)) {
270         cJSON_Delete(root);
271         return false;
272     }
273     cJSON_Delete(root);
274     HiLog::Info(LABEL, "ParseTagInfo: parse done.");
275     return true;
276 }
277 
CheckTags(const std::vector<std::string> & tags,const std::map<std::string,TagCategory> & allTags)278 bool CheckTags(const std::vector<std::string> &tags, const std::map<std::string, TagCategory> &allTags)
279 {
280     for (auto tag : tags) {
281         if (allTags.find(tag) == allTags.end()) {
282             HiLog::Error(LABEL, "CheckTags: %{pubilc}s is not provided.", tag.c_str());
283             return false;
284         }
285     }
286     return true;
287 }
288 
CheckTagGroup(const std::vector<std::string> & tagGroups,const std::map<std::string,std::vector<std::string>> & tagGroupTable)289 bool CheckTagGroup(const std::vector<std::string> &tagGroups,
290                    const std::map<std::string, std::vector<std::string>> &tagGroupTable)
291 {
292     for (auto groupName : tagGroups) {
293         if (tagGroupTable.find(groupName) == tagGroupTable.end()) {
294             HiLog::Error(LABEL, "CheckTagGroup: %{pubilc}s is not provided.", groupName.c_str());
295             return false;
296         }
297     }
298     return true;
299 }
300 
WriteStrToFile(const std::string & filename,const std::string & str)301 bool WriteStrToFile(const std::string& filename, const std::string& str)
302 {
303     std::ofstream out;
304     out.open(g_traceRootPath + filename, std::ios::out);
305     if (out.fail()) {
306         HiLog::Error(LABEL, "WriteStrToFile: %{pubilc}s open failed.", filename.c_str());
307         return false;
308     }
309     out << str;
310     if (out.bad()) {
311         HiLog::Error(LABEL, "WriteStrToFile: %{pubilc}s write failed.", filename.c_str());
312         out.close();
313         return false;
314     }
315     out.flush();
316     out.close();
317     return true;
318 }
319 
SetFtraceEnabled(const std::string & path,bool enabled)320 void SetFtraceEnabled(const std::string &path, bool enabled)
321 {
322     WriteStrToFile(path, enabled ? "1" : "0");
323 }
324 
TruncateFile()325 void TruncateFile()
326 {
327     int fd = creat((g_traceRootPath + "trace").c_str(), 0);
328     if (fd == -1) {
329         HiLog::Error(LABEL, "TruncateFile: clear old trace failed.");
330         return;
331     }
332     close(fd);
333     return;
334 }
335 
SetProperty(const std::string & property,const std::string & value)336 bool SetProperty(const std::string& property, const std::string& value)
337 {
338     bool result = OHOS::system::SetParameter(property, value);
339     if (!result) {
340         HiLog::Error(LABEL, "SetProperty: set %{pubilc}s failed.", value.c_str());
341     } else {
342         HiLog::Info(LABEL, "SetProperty: set %{pubilc}s success.", value.c_str());
343     }
344     return result;
345 }
346 
TraceInit(const std::map<std::string,TagCategory> & allTags)347 void TraceInit(const std::map<std::string, TagCategory> &allTags)
348 {
349     // close all ftrace events
350     for (auto it = allTags.begin(); it != allTags.end(); it++) {
351         if (it->second.type != 1) {
352             continue;
353         }
354         for (size_t i = 0; i < it->second.sysFiles.size(); i++) {
355             SetFtraceEnabled(it->second.sysFiles[i], false);
356         }
357     }
358     // close all user tags
359     SetProperty("debug.hitrace.tags.enableflags", std::to_string(0));
360 
361     // set buffer_size_kb 1
362     WriteStrToFile("buffer_size_kb", "1");
363 
364     // close tracing_on
365     SetFtraceEnabled("tracing_on", false);
366 }
367 
SetAllTags(const TraceParams & traceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)368 void SetAllTags(const TraceParams &traceParams, const std::map<std::string, TagCategory> &allTags,
369                 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
370 {
371     std::set<std::string> readyEnableTagList;
372     for (std::string tagName : traceParams.tags) {
373         readyEnableTagList.insert(tagName);
374     }
375 
376     // if set tagGroup, need to append default group
377     if (traceParams.tagGroups.size() > 0) {
378         auto iter = tagGroupTable.find("default");
379         if (iter == tagGroupTable.end()) {
380             HiLog::Error(LABEL, "SetAllTags: default group is wrong.");
381         } else {
382             for (auto defaultTag : iter->second) {
383                 readyEnableTagList.insert(defaultTag);
384             }
385         }
386     }
387 
388     for (std::string groupName : traceParams.tagGroups) {
389         auto iter = tagGroupTable.find(groupName);
390         if (iter == tagGroupTable.end()) {
391             continue;
392         }
393         for (std::string tag : iter->second) {
394             readyEnableTagList.insert(tag);
395         }
396     }
397 
398     uint64_t enabledUserTags = 0;
399     for (std::string tagName : readyEnableTagList) {
400         auto iter = allTags.find(tagName);
401         if (iter == allTags.end()) {
402             continue;
403         }
404 
405         if (iter->second.type == 0) {
406             enabledUserTags |= iter->second.tag;
407         }
408 
409         if (iter->second.type == 1) {
410             for (const auto& path : iter->second.sysFiles) {
411                 SetFtraceEnabled(path, true);
412                 HiLog::Info(LABEL, "Ftrace Enabled: set %{pubilc}s success.", path.c_str());
413             }
414         }
415     }
416     SetProperty("debug.hitrace.tags.enableflags", std::to_string(enabledUserTags));
417 }
418 
CanonicalizeSpecPath(const char * src)419 std::string CanonicalizeSpecPath(const char* src)
420 {
421     if (src == nullptr || strlen(src) >= PATH_MAX) {
422         HiLog::Error(LABEL, "CanonicalizeSpecPath: %{pubilc}s failed.", src);
423         return "";
424     }
425     char resolvedPath[PATH_MAX] = { 0 };
426 #if defined(_WIN32)
427     if (!_fullpath(resolvedPath, src, PATH_MAX)) {
428         return "";
429     }
430 #else
431     if (access(src, F_OK) == 0) {
432         if (realpath(src, resolvedPath) == nullptr) {
433             HiLog::Error(LABEL, "CanonicalizeSpecPath: realpath %{pubilc}s failed.", src);
434             return "";
435         }
436     } else {
437         std::string fileName(src);
438         if (fileName.find("..") == std::string::npos) {
439             if (sprintf_s(resolvedPath, PATH_MAX, "%s", src) == -1) {
440                 HiLog::Error(LABEL, "CanonicalizeSpecPath: sprintf_s %{pubilc}s failed.", src);
441                 return "";
442             }
443         } else {
444             HiLog::Error(LABEL, "CanonicalizeSpecPath: find .. src failed.");
445             return "";
446         }
447     }
448 #endif
449     std::string res(resolvedPath);
450     return res;
451 }
452 
ReadFile(const std::string & filename)453 std::string ReadFile(const std::string& filename)
454 {
455     std::string resolvedPath = CanonicalizeSpecPath((g_traceRootPath + filename).c_str());
456     std::ifstream fileIn(resolvedPath.c_str());
457     if (!fileIn.is_open()) {
458         HiLog::Error(LABEL, "ReadFile: %{pubilc}s open failed.", filename.c_str());
459         return "";
460     }
461 
462     std::string str((std::istreambuf_iterator<char>(fileIn)), std::istreambuf_iterator<char>());
463     fileIn.close();
464     return str;
465 }
466 
SetClock(const std::string & clockType)467 void SetClock(const std::string& clockType)
468 {
469     const std::string traceClockPath = "trace_clock";
470     if (clockType.size() == 0) {
471         WriteStrToFile(traceClockPath, "boot"); //set default: boot
472         return;
473     }
474     std::string allClocks = ReadFile(traceClockPath);
475     if (allClocks.find(clockType) == std::string::npos) {
476         HiLog::Error(LABEL, "SetClock: %{pubilc}s is non-existent, set to boot", clockType.c_str());
477         WriteStrToFile(traceClockPath, "boot"); // set default: boot
478         return;
479     }
480 
481     std::set<std::string> allClockTypes;
482     size_t curPos = 0;
483     for (size_t i = 0; i < allClocks.size(); i++) {
484         if (allClocks[i] == ' ') {
485             allClockTypes.insert(allClocks.substr(curPos, i - curPos));
486             curPos = i + 1;
487         }
488     }
489     std::string currentClockType;
490     for (auto i : allClockTypes) {
491         if (clockType.compare(i) == 0) {
492             HiLog::Info(LABEL, "SetClock: set clock %{public}s success.", clockType.c_str());
493             WriteStrToFile(traceClockPath, clockType);
494             return;
495         }
496         if (i[0] == '[') {
497             currentClockType = i;
498         }
499     }
500     if (currentClockType.size() == 0) {
501         HiLog::Info(LABEL, "SetClock: clockType is boot now.");
502         return;
503     }
504     const int marks = 2;
505     if (clockType.compare(currentClockType.substr(1, currentClockType.size() - marks)) == 0) {
506         HiLog::Info(LABEL, "SetClock: set clock %{public}s success.", clockType.c_str());
507         return;
508     }
509 
510     HiLog::Info(LABEL, "SetClock: unknown %{public}s, change to default clock_type: boot.", clockType.c_str());
511     WriteStrToFile(traceClockPath, "boot"); // set default: boot
512     return;
513 }
514 
SetTraceSetting(const TraceParams & traceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)515 bool SetTraceSetting(const TraceParams &traceParams, const std::map<std::string, TagCategory> &allTags,
516                      const std::map<std::string, std::vector<std::string>> &tagGroupTable)
517 {
518     TraceInit(allTags);
519 
520     TruncateFile();
521 
522     SetAllTags(traceParams, allTags, tagGroupTable);
523 
524     WriteStrToFile("current_tracer", "nop");
525     WriteStrToFile("buffer_size_kb", traceParams.bufferSize);
526 
527     SetClock(traceParams.clockType);
528 
529     if (traceParams.isOverWrite == "1") {
530         WriteStrToFile("options/overwrite", "1");
531     } else {
532         WriteStrToFile("options/overwrite", "0");
533     }
534 
535     WriteStrToFile("saved_cmdlines_size", std::to_string(SAVED_CMDLINES_SIZE));
536     WriteStrToFile("options/record-tgid", "1");
537     WriteStrToFile("options/record-cmd", "1");
538 
539     if (traceParams.outputFile.size() > 0) {
540         const mode_t defaultMode = S_IRUSR | S_IWUSR | S_IRGRP;
541         int fd = creat(traceParams.outputFile.c_str(), defaultMode);
542         if (fd == -1) {
543             HiLog::Error(LABEL, "SetTraceSetting: create %{public}s failed.", traceParams.outputFile.c_str());
544             return false;
545         } else {
546             close(fd);
547         }
548     }
549     return true;
550 }
551 
GetCpuProcessors()552 int GetCpuProcessors()
553 {
554     int processors = 0;
555     processors = sysconf(_SC_NPROCESSORS_ONLN);
556     return (processors == 0) ? 1 : processors;
557 }
558 
GetFileSize(const std::string & fileName)559 size_t GetFileSize(const std::string &fileName)
560 {
561     if (fileName.empty()) {
562         return 0;
563     }
564     if (access(fileName.c_str(), 0) == -1) {
565         return 0;
566     }
567 
568     struct stat statbuf;
569     stat(fileName.c_str(), &statbuf);
570     return statbuf.st_size;
571 }
572 
WriteFile(uint8_t contentType,const std::string & src,int outFd)573 bool WriteFile(uint8_t contentType, const std::string &src, int outFd)
574 {
575     std::string srcPath = CanonicalizeSpecPath(src.c_str());
576     int srcFd = open(srcPath.c_str(), O_RDONLY | O_NONBLOCK);
577     if (srcFd < 0) {
578         HiLog::Error(LABEL, "WriteFile: open %{public}s failed.", src.c_str());
579         return false;
580     }
581     struct TraceFileContentHeader contentHeader;
582     contentHeader.type = contentType;
583     write(outFd, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
584     uint32_t readLen = 0;
585     uint8_t buffer[PAGE_SIZE] = {0};
586     const int maxReadSize = DEFAULT_BUFFER_SIZE * 1024;
587     const int pageThreshold = PAGE_SIZE / 2;
588     PageHeader *pageHeader = nullptr;
589     int count = 0;
590     const int maxCount = 2;
591     while (readLen < maxReadSize) {
592         ssize_t readBytes = TEMP_FAILURE_RETRY(read(srcFd, buffer, PAGE_SIZE));
593         if (readBytes <= 0) {
594             break;
595         }
596         write(outFd, buffer, readBytes);
597         readLen += readBytes;
598 
599         // Check raw_trace page size.
600         if (contentType >= CONTENT_TYPE_CPU_RAW) {
601             pageHeader = reinterpret_cast<PageHeader*>(&buffer);
602             if (pageHeader->size < static_cast<uint64_t>(pageThreshold)) {
603                 count++;
604             }
605             if (count >= maxCount) {
606                 break;
607             }
608         }
609     }
610     contentHeader.length = readLen;
611     uint32_t offset = contentHeader.length + sizeof(contentHeader);
612     off_t pos = lseek(outFd, 0, SEEK_CUR);
613     lseek(outFd, pos - offset, SEEK_SET);
614     write(outFd, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
615     lseek(outFd, pos, SEEK_SET);
616     close(srcFd);
617     return true;
618 }
619 
WriteEventFile(std::string & srcPath,int outFd)620 void WriteEventFile(std::string &srcPath, int outFd)
621 {
622     uint8_t buffer[PAGE_SIZE] = {0};
623     std::string srcSpecPath = CanonicalizeSpecPath(srcPath.c_str());
624     int srcFd = open(srcSpecPath.c_str(), O_RDONLY);
625     if (srcFd < 0) {
626         HiLog::Error(LABEL, "WriteEventsFormat: open %{public}s failed.", srcPath.c_str());
627         return;
628     }
629     do {
630         int len = read(srcFd, buffer, PAGE_SIZE);
631         if (len <= 0) {
632             break;
633         }
634         write(outFd, buffer, len);
635     } while (true);
636     close(srcFd);
637 }
638 
WriteEventsFormat(int outFd)639 bool WriteEventsFormat(int outFd)
640 {
641     const std::string savedEventsFormatPath = DEFAULT_OUTPUT_DIR + "saved_events_format";
642     if (access(savedEventsFormatPath.c_str(), F_OK) != -1) {
643         return WriteFile(CONTENT_TYPE_EVENTS_FORMAT, savedEventsFormatPath, outFd);
644     }
645     std::string filePath = CanonicalizeSpecPath(savedEventsFormatPath.c_str());
646     int fd = open(filePath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
647     if (fd < 0) {
648         HiLog::Error(LABEL, "WriteEventsFormat: open %{public}s failed.", savedEventsFormatPath.c_str());
649         return false;
650     }
651     const std::vector<std::string> priorityTracingCategory = {
652         "events/sched/sched_waking/format",
653         "events/sched/sched_wakeup/format",
654         "events/sched/sched_switch/format",
655         "events/sched/sched_blocked_reason/format",
656         "events/power/cpu_frequency/format",
657         "events/power/clock_set_rate/format",
658         "events/power/cpu_frequency_limits/format",
659         "events/f2fs/f2fs_sync_file_enter/format",
660         "events/f2fs/f2fs_sync_file_exit/format",
661         "events/ext4/ext4_da_write_begin/format",
662         "events/ext4/ext4_da_write_end/format",
663         "events/ext4/ext4_sync_file_enter/format",
664         "events/ext4/ext4_sync_file_exit/format",
665         "events/block/block_rq_issue/format",
666         "events/block/block_rq_complete/format",
667         "events/binder/binder_transaction/format",
668         "events/binder/binder_transaction_received/format",
669         "events/ftrace/print/format",
670     };
671     for (size_t i = 0; i < priorityTracingCategory.size(); i++) {
672         std::string srcPath = g_traceRootPath + priorityTracingCategory[i];
673         WriteEventFile(srcPath, fd);
674     }
675     close(fd);
676     return WriteFile(CONTENT_TYPE_EVENTS_FORMAT, filePath, outFd);
677 }
678 
WriteCpuRaw(int outFd)679 bool WriteCpuRaw(int outFd)
680 {
681     int cpuNums = GetCpuProcessors();
682     int ret = true;
683     uint8_t type = CONTENT_TYPE_CPU_RAW;
684     for (int i = 0; i < cpuNums; i++) {
685         std::string src = g_traceRootPath + "per_cpu/cpu" + std::to_string(i) + "/trace_pipe_raw";
686         if (!WriteFile(static_cast<uint8_t>(type + i), src, outFd)) {
687             ret = false;
688             break;
689         }
690     }
691     return ret;
692 }
693 
WriteCmdlines(int outFd)694 bool WriteCmdlines(int outFd)
695 {
696     std::string cmdlinesPath = g_traceRootPath + "saved_cmdlines";
697     return WriteFile(CONTENT_TYPE_CMDLINES, cmdlinesPath, outFd);
698 }
699 
WriteTgids(int outFd)700 bool WriteTgids(int outFd)
701 {
702     std::string tgidsPath = g_traceRootPath + "saved_tgids";
703     return WriteFile(CONTENT_TYPE_TGIDS, tgidsPath, outFd);
704 }
705 
DumpTraceLoop(const std::string & outputFileName,bool isLimited)706 bool DumpTraceLoop(const std::string &outputFileName, bool isLimited)
707 {
708     const int sleepTime = 1;
709     const int fileSizeThreshold = 96 * 1024 * 1024;
710     std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
711     int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
712     if (outFd < 0) {
713         return false;
714     }
715     struct TraceFileHeader header;
716     GetArchWordSize(header);
717     write(outFd, reinterpret_cast<char*>(&header), sizeof(header));
718     WriteEventsFormat(outFd);
719     while (g_dumpFlag) {
720         if (isLimited && GetFileSize(outPath) > fileSizeThreshold) {
721             break;
722         }
723         sleep(sleepTime);
724         WriteCpuRaw(outFd);
725     }
726     WriteCmdlines(outFd);
727     WriteTgids(outFd);
728     close(outFd);
729     return true;
730 }
731 
732 /**
733  * read trace data loop
734  * g_dumpFlag: true = open,false = close
735  * g_dumpEnd: true = end,false = not end
736  * if user has own output file, Output all data to the file specified by the user;
737  * if not, Then place all the result files in/data/local/tmp/and package them once in 96M.
738 */
ProcessDumpTask()739 void ProcessDumpTask()
740 {
741     g_dumpFlag = true;
742     g_dumpEnd = false;
743     g_outputFilesForCmd = {};
744     if (g_currentTraceParams.outputFile.size() > 0) {
745         if (DumpTraceLoop(g_currentTraceParams.outputFile, false)) {
746             g_outputFilesForCmd.push_back(g_currentTraceParams.outputFile);
747         }
748         g_dumpEnd = true;
749         return;
750     }
751 
752     while (g_dumpFlag) {
753         // Generate file name
754         struct timeval now = {0, 0};
755         gettimeofday(&now, nullptr);
756         std::string outputFileName = "/data/local/tmp/trace_" + std::to_string(now.tv_sec) + ".sys";
757         if (DumpTraceLoop(outputFileName, true)) {
758             g_outputFilesForCmd.push_back(outputFileName);
759         }
760     }
761     g_dumpEnd = true;
762 }
763 
SearchFromTable(std::vector<std::string> & outputFiles,int nowSec)764 void SearchFromTable(std::vector<std::string> &outputFiles, int nowSec)
765 {
766     const int maxInterval = 8;
767     const int agingTime = 30 * 60;
768 
769     for (auto iter = g_traceFilesTable.begin(); iter != g_traceFilesTable.end();) {
770         if (nowSec - iter->second >= agingTime) {
771             // delete outdated trace file
772             if (access(iter->first.c_str(), F_OK) == 0) {
773                 remove(iter->first.c_str());
774                 HiLog::Info(LABEL, "delete old %{public}s file success.", iter->first.c_str());
775             }
776             iter = g_traceFilesTable.erase(iter);
777             continue;
778         }
779 
780         if (nowSec - iter->second <= maxInterval) {
781             outputFiles.push_back(iter->first);
782         }
783         iter++;
784     }
785 }
786 
ReadRawTrace(std::string & outputFileName)787 bool ReadRawTrace(std::string &outputFileName)
788 {
789     // read trace data from /per_cpu/cpux/trace_pipe_raw
790     std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
791     int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
792     if (outFd < 0) {
793         return false;
794     }
795     struct TraceFileHeader header;
796     GetArchWordSize(header);
797     write(outFd, reinterpret_cast<char*>(&header), sizeof(header));
798 
799     if (WriteEventsFormat(outFd) && WriteCpuRaw(outFd) &&
800         WriteCmdlines(outFd) && WriteTgids(outFd)) {
801         close(outFd);
802         return true;
803     }
804     HiLog::Error(LABEL, "ReadRawTrace failed.");
805     close(outFd);
806     return false;
807 }
808 
GenerateName()809 std::string GenerateName()
810 {
811     // eg: /data/log/hitrace/trace_localtime@monotime.sys
812     std::string name = DEFAULT_OUTPUT_DIR + "trace_";
813     // get localtime
814     time_t currentTime;
815     time(&currentTime);
816     struct tm timeInfo = {};
817     const int bufferSize = 16;
818     char timeStr[bufferSize] = {0};
819     if (localtime_r(&currentTime, &timeInfo) == nullptr) {
820         HiLog::Error(LABEL, "Get localtime failed.");
821         return "";
822     }
823     strftime(timeStr, bufferSize, "%Y%m%d%H%M%S", &timeInfo);
824     name += std::string(timeStr);
825     // get monotime
826     struct timespec mts = {0, 0};
827     clock_gettime(CLOCK_MONOTONIC, &mts);
828     name += "@" + std::to_string(mts.tv_sec) + "-" + std::to_string(mts.tv_nsec) + ".sys";
829     HiLog::Info(LABEL, "Generate trace name: %{public}s.", name.c_str());
830     return name;
831 }
832 
DumpTraceInner(std::vector<std::string> & outputFiles)833 TraceErrorCode DumpTraceInner(std::vector<std::string> &outputFiles)
834 {
835     struct timeval now = {0, 0};
836     gettimeofday(&now, nullptr);
837     int nowSec = now.tv_sec;
838     if (!g_dumpEnd) {
839         const int maxSleepTime = 2 * 1000 * 1000 / UNIT_TIME; // 2s
840         int cur = 0;
841         while (!g_dumpEnd && cur < maxSleepTime) {
842             cur += 1;
843             usleep(UNIT_TIME);
844         }
845         SearchFromTable(outputFiles, nowSec);
846         if (outputFiles.size() == 0) {
847             return TraceErrorCode::WRITE_TRACE_INFO_ERROR;
848         }
849         return TraceErrorCode::SUCCESS;
850     }
851     g_dumpEnd = false;
852     std::string outputFileName = GenerateName();
853     std::string reOutPath = CanonicalizeSpecPath(outputFileName.c_str());
854     bool ret = ReadRawTrace(reOutPath);
855 
856     SearchFromTable(outputFiles, nowSec);
857     if (ret) {
858         outputFiles.push_back(outputFileName);
859         g_traceFilesTable.push_back({outputFileName, nowSec});
860     } else {
861         HiLog::Error(LABEL, "DumpTraceInner: write %{public}s failed.", outputFileName.c_str());
862         g_dumpEnd = true;
863         return TraceErrorCode::WRITE_TRACE_INFO_ERROR;
864     }
865     g_dumpEnd = true;
866     return TraceErrorCode::SUCCESS;
867 }
868 
AdjustInner(CpuStat & cpuStat,LastCpuInfo & lastCpuInfo,int i)869 void AdjustInner(CpuStat &cpuStat, LastCpuInfo &lastCpuInfo, int i)
870 {
871     const int cpuUsageThreshold = 80;
872     const int percentage = 100;
873     uint64_t totalCpuTime = cpuStat.user + cpuStat.nice + cpuStat.system + cpuStat.idle + cpuStat.iowait +
874                             cpuStat.irq + cpuStat.softirq;
875     uint64_t cpuUsage = percentage - percentage * (cpuStat.idle - lastCpuInfo.idleAndTotal.first) /
876                         (totalCpuTime - lastCpuInfo.idleAndTotal.second);
877     if (cpuUsage >= cpuUsageThreshold && lastCpuInfo.isNormal) {
878         std::string subPath = "per_cpu/cpu" + std::to_string(i) + "/buffer_size_kb";
879         WriteStrToFile(subPath, std::to_string(HIGHER_BUFFER_SIZE));
880         lastCpuInfo.isNormal = false;
881     }
882     if (!lastCpuInfo.isNormal && cpuUsage < cpuUsageThreshold) {
883         std::string subPath = "per_cpu/cpu" + std::to_string(i) + "/buffer_size_kb";
884         WriteStrToFile(subPath, std::to_string(DEFAULT_BUFFER_SIZE));
885         lastCpuInfo.isNormal = true;
886     }
887     lastCpuInfo.idleAndTotal.first = cpuStat.idle;
888     lastCpuInfo.idleAndTotal.second = totalCpuTime;
889 }
890 
CpuTraceBufferSizeAdjust(std::vector<LastCpuInfo> & lastData,const int cpuNums)891 bool CpuTraceBufferSizeAdjust(std::vector<LastCpuInfo> &lastData, const int cpuNums)
892 {
893     std::ifstream statFile("/proc/stat");
894     if (!statFile.is_open()) {
895         HiLog::Error(LABEL, "CpuTraceBufferSizeAdjust: open /proc/stat failed.");
896         return false;
897     }
898     std::string data;
899     std::vector<CpuStat> cpuStats;
900 
901     const int pos = 3;
902     const int formatNumber = 10;
903     while (std::getline(statFile, data)) {
904         if (data.substr(0, pos) == "cpu" && data[pos] != ' ') {
905             CpuStat cpuStat = {};
906             int ret = sscanf_s(data.c_str(), "%*s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", &cpuStat.user,
907                                &cpuStat.nice, &cpuStat.system, &cpuStat.idle, &cpuStat.iowait, &cpuStat.irq,
908                                &cpuStat.softirq, &cpuStat.steal, &cpuStat.guest, &cpuStat.guestNice);
909             if (ret != formatNumber) {
910                 HiLog::Error(LABEL, "CpuTraceBufferSizeAdjust: format error.");
911                 return false;
912             }
913             cpuStats.push_back(cpuStat);
914         }
915     }
916     statFile.close();
917     if (cpuNums != (int)cpuStats.size()) {
918         HiLog::Error(LABEL, "CpuTraceBufferSizeAdjust: read /proc/stat error.");
919         return false;
920     }
921     for (size_t i = 0; i < cpuStats.size(); i++) {
922         AdjustInner(cpuStats[i], lastData[i], i);
923     }
924     return true;
925 }
926 
MonitorServiceTask()927 void MonitorServiceTask()
928 {
929     HiLog::Info(LABEL, "MonitorServiceTask: monitor thread start.");
930     const int maxServiceTimes = 3 * 1000 * 1000 / UNIT_TIME; // 3s
931     int curServiceTimes = 0;
932     const int cpuNums = GetCpuProcessors();
933     std::vector<LastCpuInfo> lastData;
934     for (int i = 0; i < cpuNums; i++) {
935         lastData.push_back({{0, 0}, true});
936     }
937 
938     while (true) {
939         if (g_traceMode != TraceMode::SERVICE_MODE || !g_monitor) {
940             HiLog::Info(LABEL, "MonitorServiceTask: monitor thread exit because of g_monitor.");
941             break;
942         }
943         if (curServiceTimes >= maxServiceTimes) {
944             // trace ringbuffer dynamic tuning
945             if (!CpuTraceBufferSizeAdjust(lastData, cpuNums)) {
946                 HiLog::Info(LABEL, "MonitorServiceTask: monitor thread exit.");
947                 break;
948             }
949             curServiceTimes = 0;
950         } else {
951             curServiceTimes++;
952         }
953         usleep(UNIT_TIME);
954     }
955 }
956 
MonitorCmdTask()957 void MonitorCmdTask()
958 {
959     int curCmdTimes = 0;
960     const int maxCmdTimes = 5 * 60 * 1000 * 1000 / UNIT_TIME; // 5min exit
961     HiLog::Info(LABEL, "MonitorCmdTask: monitor thread start.");
962     while (true) {
963         if (g_traceMode != TraceMode::CMD_MODE) {
964             HiLog::Info(LABEL, "MonitorCmdTask: monitor thread exit.");
965             return;
966         }
967 
968         if (curCmdTimes >= maxCmdTimes) {
969             HiLog::Error(LABEL, "MonitorCmdTask: CMD_MODE Timeout exit.");
970             g_dumpFlag = false;
971             while (!g_dumpEnd) {
972                 usleep(UNIT_TIME);
973             }
974             OHOS::HiviewDFX::Hitrace::CloseTrace();
975             break;
976         } else {
977             curCmdTimes++;
978         }
979         usleep(UNIT_TIME);
980     }
981 }
982 
HandleTraceOpen(const TraceParams & traceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)983 TraceErrorCode HandleTraceOpen(const TraceParams &traceParams,
984                                const std::map<std::string, TagCategory> &allTags,
985                                const std::map<std::string, std::vector<std::string>> &tagGroupTable)
986 {
987     if (!SetTraceSetting(traceParams, allTags, tagGroupTable)) {
988         return TraceErrorCode::FILE_ERROR;
989     }
990     SetFtraceEnabled("tracing_on", true);
991     g_currentTraceParams = traceParams;
992     return TraceErrorCode::SUCCESS;
993 }
994 
HandleServiceTraceOpen(const std::vector<std::string> & tagGroups,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)995 TraceErrorCode HandleServiceTraceOpen(const std::vector<std::string> &tagGroups,
996                                       const std::map<std::string, TagCategory> &allTags,
997                                       const std::map<std::string, std::vector<std::string>> &tagGroupTable)
998 {
999     TraceParams serviceTraceParams;
1000     serviceTraceParams.tagGroups = tagGroups;
1001     serviceTraceParams.bufferSize = std::to_string(DEFAULT_BUFFER_SIZE);
1002     serviceTraceParams.clockType = "boot";
1003     serviceTraceParams.isOverWrite = "1";
1004     return HandleTraceOpen(serviceTraceParams, allTags, tagGroupTable);
1005 }
1006 
RemoveUnSpace(std::string str,std::string & args)1007 void RemoveUnSpace(std::string str, std::string& args)
1008 {
1009     int maxCircleTimes = 30;
1010     int curTimes = 0;
1011     const size_t symbolAndSpaceLen = 2;
1012     std::string strSpace = str + " ";
1013     while (curTimes < maxCircleTimes) {
1014         curTimes++;
1015         std::string::size_type index = args.find(strSpace);
1016         if (index != std::string::npos) {
1017             args.replace(index, symbolAndSpaceLen, str);
1018         } else {
1019             break;
1020         }
1021     }
1022 }
1023 
1024 /**
1025  * args:  tags:tag1,tags2... tagGroups:group1,group2... clockType:boot bufferSize:1024 overwrite:1 output:filename
1026  * cmdTraceParams:  Save the above parameters
1027 */
ParseArgs(const std::string & args,TraceParams & cmdTraceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)1028 bool ParseArgs(const std::string &args, TraceParams &cmdTraceParams, const std::map<std::string, TagCategory> &allTags,
1029                const std::map<std::string, std::vector<std::string>> &tagGroupTable)
1030 {
1031     std::string userArgs = args;
1032     std::string str = ":";
1033     RemoveUnSpace(str, userArgs);
1034     str = ",";
1035     RemoveUnSpace(str, userArgs);
1036     std::vector<std::string> argList = Split(userArgs, ' ');
1037     for (std::string item : argList) {
1038         size_t pos = item.find(":");
1039         if (pos == std::string::npos) {
1040             HiLog::Error(LABEL, "trace command line without colon appears: %{public}s, continue.", item.c_str());
1041             continue;
1042         }
1043         std::string itemName = item.substr(0, pos);
1044         if (itemName == "tags") {
1045             cmdTraceParams.tags = Split(item.substr(pos + 1), ',');
1046         } else if (itemName == "tagGroups") {
1047             cmdTraceParams.tagGroups = Split(item.substr(pos + 1), ',');
1048         } else if (itemName == "clockType") {
1049             cmdTraceParams.clockType = item.substr(pos + 1);
1050         } else if (itemName == "bufferSize") {
1051             cmdTraceParams.bufferSize = item.substr(pos + 1);
1052         } else if (itemName == "overwrite") {
1053             cmdTraceParams.isOverWrite = item.substr(pos + 1);
1054         } else if (itemName == "output") {
1055             cmdTraceParams.outputFile = item.substr(pos + 1);
1056         } else {
1057             HiLog::Error(LABEL, "Extra trace command line options appear when ParseArgs: %{public}s, return false.",
1058                 itemName.c_str());
1059             return false;
1060         }
1061     }
1062     if (CheckTags(cmdTraceParams.tags, allTags) && CheckTagGroup(cmdTraceParams.tagGroups, tagGroupTable)) {
1063         return true;
1064     }
1065     return false;
1066 }
1067 
1068 /**
1069  * When the SERVICE_MODE is started, clear the remaining trace files in the folder.
1070 */
ClearRemainingTrace()1071 void ClearRemainingTrace()
1072 {
1073     if (access(DEFAULT_OUTPUT_DIR.c_str(), F_OK) != 0) {
1074         return;
1075     }
1076     DIR* dirPtr = opendir(DEFAULT_OUTPUT_DIR.c_str());
1077     if (dirPtr == nullptr) {
1078         HiLog::Error(LABEL, "opendir failed.");
1079         return;
1080     }
1081     struct dirent* ptr = nullptr;
1082     while ((ptr = readdir(dirPtr)) != nullptr) {
1083         if (ptr->d_type == DT_REG) {
1084             std::string subFileName = DEFAULT_OUTPUT_DIR + std::string(ptr->d_name);
1085             if (remove(subFileName.c_str()) == 0) {
1086                 HiLog::Info(LABEL, "Delete old trace file: %{public}s success.", subFileName.c_str());
1087             } else {
1088                 HiLog::Error(LABEL, "Delete old trace file: %{public}s failed.", subFileName.c_str());
1089             }
1090         }
1091     }
1092     closedir(dirPtr);
1093 }
1094 
1095 } // namespace
1096 
1097 namespace OHOS {
1098 namespace HiviewDFX {
1099 
1100 namespace Hitrace {
1101 
GetTraceMode()1102 TraceMode GetTraceMode()
1103 {
1104     return g_traceMode;
1105 }
1106 
OpenTrace(const std::vector<std::string> & tagGroups)1107 TraceErrorCode OpenTrace(const std::vector<std::string> &tagGroups)
1108 {
1109     if (!IsTraceMounted()) {
1110         HiLog::Error(LABEL, "OpenTrace: TRACE_NOT_SUPPORTED.");
1111         return TRACE_NOT_SUPPORTED;
1112     }
1113     std::map<std::string, TagCategory> allTags;
1114     std::map<std::string, std::vector<std::string>> tagGroupTable;
1115     if (!ParseTagInfo(allTags, tagGroupTable)) {
1116         HiLog::Error(LABEL, "OpenTrace: ParseTagInfo TAG_ERROR.");
1117         return TAG_ERROR;
1118     }
1119 
1120     if (tagGroups.size() == 0 || !CheckTagGroup(tagGroups, tagGroupTable)) {
1121         HiLog::Error(LABEL, "OpenTrace: TAG_ERROR.");
1122         return TAG_ERROR;
1123     }
1124 
1125     if (g_traceMode == CMD_MODE) {
1126         HiLog::Error(LABEL, "OpenTrace: TRACE_IS_OCCUPIED.");
1127         return TRACE_IS_OCCUPIED;
1128     }
1129 
1130     if (g_traceMode == SERVICE_MODE) {
1131         HiLog::Error(LABEL, "OpenTrace: CALL_ERROR.");
1132         return CALL_ERROR;
1133     }
1134 
1135     TraceErrorCode ret = HandleServiceTraceOpen(tagGroups, allTags, tagGroupTable);
1136     if (ret != SUCCESS) {
1137         HiLog::Error(LABEL, "OpenTrace: open fail.");
1138         return ret;
1139     }
1140     g_traceMode = SERVICE_MODE;
1141 
1142     ClearRemainingTrace();
1143     // open SERVICE_MODE monitor thread
1144     std::thread auxiliaryTask(MonitorServiceTask);
1145     auxiliaryTask.detach();
1146     HiLog::Info(LABEL, "OpenTrace: SERVICE_MODE open success.");
1147     return ret;
1148 }
1149 
OpenTrace(const std::string & args)1150 TraceErrorCode OpenTrace(const std::string &args)
1151 {
1152     if (!IsTraceMounted()) {
1153         HiLog::Error(LABEL, "Hitrace OpenTrace: TRACE_NOT_SUPPORTED.");
1154         return TRACE_NOT_SUPPORTED;
1155     }
1156     std::map<std::string, TagCategory> allTags;
1157     std::map<std::string, std::vector<std::string>> tagGroupTable;
1158     if (!ParseTagInfo(allTags, tagGroupTable) || allTags.size() == 0 || tagGroupTable.size() == 0) {
1159         HiLog::Error(LABEL, "Hitrace OpenTrace: ParseTagInfo TAG_ERROR.");
1160         return TAG_ERROR;
1161     }
1162     // parse args
1163     TraceParams cmdTraceParams;
1164     if (!ParseArgs(args, cmdTraceParams, allTags, tagGroupTable)) {
1165         HiLog::Error(LABEL, "Hitrace OpenTrace: TAG_ERROR.");
1166         return TAG_ERROR;
1167     }
1168 
1169     if (g_traceMode != CLOSE) {
1170         HiLog::Error(LABEL, "Hitrace OpenTrace: CALL_ERROR.");
1171         return CALL_ERROR;
1172     }
1173 
1174     TraceErrorCode ret = HandleTraceOpen(cmdTraceParams, allTags, tagGroupTable);
1175     if (ret != SUCCESS) {
1176         HiLog::Error(LABEL, "Hitrace OpenTrace: CMD_MODE open failed.");
1177         return FILE_ERROR;
1178     }
1179     g_traceMode = CMD_MODE;
1180     // open SERVICE_MODE monitor thread
1181     std::thread auxiliaryTask(MonitorCmdTask);
1182     auxiliaryTask.detach();
1183     HiLog::Info(LABEL, "Hitrace OpenTrace: CMD_MODE open success.");
1184     return ret;
1185 }
1186 
DumpTrace()1187 TraceRetInfo DumpTrace()
1188 {
1189     TraceRetInfo ret;
1190     if (g_traceMode != SERVICE_MODE) {
1191         HiLog::Error(LABEL, "DumpTrace: CALL_ERROR.");
1192         ret.errorCode = CALL_ERROR;
1193         return ret;
1194     }
1195     ret.errorCode = DumpTraceInner(ret.outputFiles);
1196     return ret;
1197 }
1198 
DumpTraceOn()1199 TraceErrorCode DumpTraceOn()
1200 {
1201     // check current trace status
1202     if (g_traceMode != CMD_MODE) {
1203         HiLog::Error(LABEL, "DumpTraceOn: CALL_ERROR.");
1204         return CALL_ERROR;
1205     }
1206 
1207     // start task thread
1208     std::thread task(ProcessDumpTask);
1209     task.detach();
1210     HiLog::Info(LABEL, "DumpTraceOn: Dumping trace.");
1211     return SUCCESS;
1212 }
1213 
DumpTraceOff()1214 TraceRetInfo DumpTraceOff()
1215 {
1216     TraceRetInfo ret;
1217     g_dumpFlag = false;
1218     const int waitTime = 10000;
1219     while (!g_dumpEnd) {
1220         usleep(waitTime);
1221     }
1222     ret.errorCode = SUCCESS;
1223     ret.outputFiles = g_outputFilesForCmd;
1224     HiLog::Info(LABEL, "DumpTraceOff: trace files generated success.");
1225     return ret;
1226 }
1227 
CloseTrace()1228 TraceErrorCode CloseTrace()
1229 {
1230     if (g_traceMode == CLOSE) {
1231         HiLog::Error(LABEL, "CloseTrace: CALL_ERROR.");
1232         return CALL_ERROR;
1233     }
1234     std::map<std::string, TagCategory> allTags;
1235     std::map<std::string, std::vector<std::string>> tagGroupTable;
1236     if (!ParseTagInfo(allTags, tagGroupTable) || allTags.size() == 0 || tagGroupTable.size() == 0) {
1237         HiLog::Error(LABEL, "CloseTrace: ParseTagInfo TAG_ERROR.");
1238         return TAG_ERROR;
1239     }
1240     TraceInit(allTags);
1241     TruncateFile();
1242     g_traceMode = CLOSE;
1243     usleep(UNIT_TIME);
1244     return SUCCESS;
1245 }
1246 
GetTraceFilesTable()1247 std::vector<std::pair<std::string, int>> GetTraceFilesTable()
1248 {
1249     return g_traceFilesTable;
1250 }
1251 
SetTraceFilesTable(std::vector<std::pair<std::string,int>> & traceFilesTable)1252 void SetTraceFilesTable(std::vector<std::pair<std::string, int>>& traceFilesTable)
1253 {
1254     g_traceFilesTable = traceFilesTable;
1255 }
1256 
1257 } // Hitrace
1258 } // HiviewDFX
1259 } // OHOS