• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023-2024 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 <algorithm>
19 #include <atomic>
20 #include <cinttypes>
21 #include <csignal>
22 #include <fstream>
23 #include <map>
24 #include <memory>
25 #include <mutex>
26 #include <set>
27 #include <sys/epoll.h>
28 #include <sys/prctl.h>
29 #include <sys/sysinfo.h>
30 #include <sys/wait.h>
31 #include <thread>
32 #include <unistd.h>
33 
34 #include "common_define.h"
35 #include "common_utils.h"
36 #include "dynamic_buffer.h"
37 #include "hitrace_meter.h"
38 #include "hilog/log.h"
39 #include "parameters.h"
40 #include "securec.h"
41 #include "trace_file_utils.h"
42 #include "trace_json_parser.h"
43 
44 namespace OHOS {
45 namespace HiviewDFX {
46 namespace Hitrace {
47 #ifdef LOG_DOMAIN
48 #undef LOG_DOMAIN
49 #define LOG_DOMAIN 0xD002D33
50 #endif
51 #ifdef LOG_TAG
52 #undef LOG_TAG
53 #define LOG_TAG "HitraceDump"
54 #endif
55 namespace {
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     int fileLimit;
65     int fileSize;
66     int appPid;
67 };
68 
69 constexpr uint16_t MAGIC_NUMBER = 57161;
70 constexpr uint16_t VERSION_NUMBER = 1;
71 constexpr uint8_t FILE_RAW_TRACE = 0;
72 constexpr uint8_t HM_FILE_RAW_TRACE = 1;
73 constexpr uint64_t CACHE_TRACE_LOOP_SLEEP_TIME = 1;
74 constexpr int UNIT_TIME = 100000;
75 constexpr int ALIGNMENT_COEFFICIENT = 4;
76 constexpr int RECORD_LOOP_SLEEP = 1;
77 
78 const int DEFAULT_BUFFER_SIZE = 12 * 1024;
79 const int DEFAULT_FILE_SIZE = 100 * 1024;
80 #ifdef HITRACE_UNITTEST
81 const int DEFAULT_CACHE_FILE_SIZE = 15 * 1024;
82 #else
83 const int DEFAULT_CACHE_FILE_SIZE = 150 * 1024;
84 #endif
85 #if defined(SNAPSHOT_TRACEBUFFER_SIZE) && (SNAPSHOT_TRACEBUFFER_SIZE != 0)
86 const int HM_DEFAULT_BUFFER_SIZE = SNAPSHOT_TRACEBUFFER_SIZE;
87 #else
88 const int HM_DEFAULT_BUFFER_SIZE = 144 * 1024;
89 #endif
90 const int SAVED_CMDLINES_SIZE = 3072; // 3M
91 const int BYTE_PER_KB = 1024;
92 const int BYTE_PER_MB = 1024 * 1024;
93 constexpr uint64_t S_TO_NS = 1000000000;
94 constexpr uint64_t S_TO_MS = 1000;
95 constexpr int32_t MAX_RATIO_UNIT = 1000;
96 const int MAX_NEW_TRACE_FILE_LIMIT = 5;
97 const int JUDGE_FILE_EXIST = 10;  // Check whether the trace file exists every 10 times.
98 #if defined(SNAPSHOT_FILE_LIMIT) && (SNAPSHOT_FILE_LIMIT != 0)
99 const int SNAPSHOT_FILE_MAX_COUNT = SNAPSHOT_FILE_LIMIT;
100 #else
101 const int SNAPSHOT_FILE_MAX_COUNT = 20;
102 #endif
103 
104 constexpr int DEFAULT_FULL_TRACE_LENGTH = 30;
105 
106 struct alignas(ALIGNMENT_COEFFICIENT) TraceFileHeader {
107     uint16_t magicNumber {MAGIC_NUMBER};
108     uint8_t fileType {FILE_RAW_TRACE};
109     uint16_t versionNumber {VERSION_NUMBER};
110     uint32_t reserved {0};
111 };
112 
113 enum ContentType : uint8_t {
114     CONTENT_TYPE_DEFAULT = 0,
115     CONTENT_TYPE_EVENTS_FORMAT = 1,
116     CONTENT_TYPE_CMDLINES  = 2,
117     CONTENT_TYPE_TGIDS = 3,
118     CONTENT_TYPE_CPU_RAW = 4,
119     CONTENT_TYPE_HEADER_PAGE = 30,
120     CONTENT_TYPE_PRINTK_FORMATS = 31,
121     CONTENT_TYPE_KALLSYMS = 32
122 };
123 
124 struct alignas(ALIGNMENT_COEFFICIENT) TraceFileContentHeader {
125     uint8_t type = CONTENT_TYPE_DEFAULT;
126     uint32_t length = 0;
127 };
128 
129 struct PageHeader {
130     uint64_t timestamp = 0;
131     uint64_t size = 0;
132     uint8_t overwrite = 0;
133     uint8_t *startPos = nullptr;
134     uint8_t *endPos = nullptr;
135 };
136 
137 struct ChildProcessRet {
138     uint8_t dumpStatus;
139     uint64_t traceStartTime;
140     uint64_t traceEndTime;
141 };
142 
143 #ifndef PAGE_SIZE
144 constexpr size_t PAGE_SIZE = 4096;
145 #endif
146 
147 const int BUFFER_SIZE = 256 * PAGE_SIZE; // 1M
148 
149 std::atomic<bool> g_recordFlag(false);
150 std::atomic<bool> g_recordEnd(true);
151 std::atomic<bool> g_cacheFlag(false);
152 std::atomic<bool> g_cacheEnd(true);
153 std::mutex g_traceMutex;
154 std::mutex g_cacheTraceMutex;
155 std::mutex g_recordingOutputMutex;
156 
157 bool g_serviceThreadIsStart = false;
158 uint64_t g_sysInitParamTags = 0;
159 uint8_t g_traceMode = TraceMode::CLOSE;
160 std::string g_traceRootPath;
161 uint8_t g_buffer[BUFFER_SIZE] = {0};
162 std::vector<std::pair<std::string, int>> g_traceFilesTable;
163 std::vector<std::string> g_recordingOutput;
164 int g_outputFileSize = 0;
165 int g_newTraceFileLimit = 0;
166 int g_writeFileLimit = 0;
167 bool g_needGenerateNewTraceFile = false;
168 bool g_needLimitFileSize = true;
169 uint64_t g_totalFileSizeLimit = 0;
170 uint64_t g_sliceMaxDuration = 0;
171 uint64_t g_traceStartTime = 0;
172 uint64_t g_traceEndTime = std::numeric_limits<uint64_t>::max(); // in nano seconds
173 uint64_t g_firstPageTimestamp = std::numeric_limits<uint64_t>::max();
174 uint64_t g_lastPageTimestamp = 0;
175 uint64_t g_utDestTraceStartTime = 0;
176 uint64_t g_utDestTraceEndTime = 0;
177 std::atomic<uint8_t> g_dumpStatus(TraceErrorCode::UNSET);
178 std::vector<TraceFileInfo> g_traceFileVec{};
179 std::vector<TraceFileInfo> g_cacheFileVec{};
180 
181 TraceParams g_currentTraceParams = {};
182 std::shared_ptr<TraceJsonParser> g_traceJsonParser = nullptr;
183 std::atomic<uint8_t> g_interruptDump(0);
184 
IsTraceOpen()185 bool IsTraceOpen()
186 {
187     return (g_traceMode & TraceMode::OPEN) != 0;
188 }
189 
IsRecordOn()190 bool IsRecordOn()
191 {
192     return (g_traceMode & TraceMode::RECORD) != 0;
193 }
194 
IsCacheOn()195 bool IsCacheOn()
196 {
197     return (g_traceMode & TraceMode::CACHE) != 0;
198 }
199 
GetCurBootTime()200 uint64_t GetCurBootTime()
201 {
202     struct timespec bts = {0, 0};
203     clock_gettime(CLOCK_BOOTTIME, &bts);
204     return static_cast<uint64_t>(bts.tv_sec * S_TO_NS + bts.tv_nsec);
205 }
206 
Split(const std::string & str,char delimiter)207 std::vector<std::string> Split(const std::string& str, char delimiter)
208 {
209     std::vector<std::string> res;
210     size_t startPos = 0;
211     for (size_t i = 0; i < str.size(); i++) {
212         if (str[i] == delimiter) {
213             res.push_back(str.substr(startPos, i - startPos));
214             startPos = i + 1;
215         }
216     }
217     if (startPos < str.size()) {
218         res.push_back(str.substr(startPos));
219     }
220     return res;
221 }
222 
223 // Arch is 64bit when reserved = 0; Arch is 32bit when reserved = 1.
GetArchWordSize(TraceFileHeader & header)224 void GetArchWordSize(TraceFileHeader& header)
225 {
226     if (sizeof(void*) == sizeof(uint64_t)) {
227         header.reserved |= 0;
228     } else if (sizeof(void*) == sizeof(uint32_t)) {
229         header.reserved |= 1;
230     }
231     HILOG_INFO(LOG_CORE, "reserved with arch word info is %{public}d.", header.reserved);
232 }
233 
GetCpuNums(TraceFileHeader & header)234 void GetCpuNums(TraceFileHeader& header)
235 {
236     const int maxCpuNums = 24;
237     int cpuNums = GetCpuProcessors();
238     if (cpuNums > maxCpuNums || cpuNums <= 0) {
239         HILOG_ERROR(LOG_CORE, "error: cpu_number is %{public}d.", cpuNums);
240         return;
241     }
242     header.reserved |= (static_cast<uint64_t>(cpuNums) << 1);
243     HILOG_INFO(LOG_CORE, "reserved with cpu number info is %{public}d.", header.reserved);
244 }
245 
GenerateTraceHeaderContent()246 TraceFileHeader GenerateTraceHeaderContent()
247 {
248     TraceFileHeader header;
249     GetArchWordSize(header);
250     GetCpuNums(header);
251     if (IsHmKernel()) {
252         header.fileType = HM_FILE_RAW_TRACE;
253     }
254     return header;
255 }
256 
CheckTags(const std::vector<std::string> & tags,const std::map<std::string,TraceTag> & allTags)257 bool CheckTags(const std::vector<std::string>& tags, const std::map<std::string, TraceTag>& allTags)
258 {
259     for (const auto &tag : tags) {
260         if (allTags.find(tag) == allTags.end()) {
261             HILOG_ERROR(LOG_CORE, "CheckTags: %{public}s is not provided.", tag.c_str());
262             return false;
263         }
264     }
265     return true;
266 }
267 
CheckTagGroup(const std::vector<std::string> & tagGroups,const std::map<std::string,std::vector<std::string>> & tagGroupTable)268 bool CheckTagGroup(const std::vector<std::string>& tagGroups,
269                    const std::map<std::string, std::vector<std::string>>& tagGroupTable)
270 {
271     for (auto groupName : tagGroups) {
272         if (tagGroupTable.find(groupName) == tagGroupTable.end()) {
273             HILOG_ERROR(LOG_CORE, "CheckTagGroup: %{public}s is not provided.", groupName.c_str());
274             return false;
275         }
276     }
277     return true;
278 }
279 
WriteStrToFileInner(const std::string & filename,const std::string & str)280 bool WriteStrToFileInner(const std::string& filename, const std::string& str)
281 {
282     std::ofstream out;
283     out.open(filename, std::ios::out);
284     if (out.fail()) {
285         HILOG_ERROR(LOG_CORE, "WriteStrToFile: %{public}s open failed.", filename.c_str());
286         return false;
287     }
288     out << str;
289     if (out.bad()) {
290         HILOG_ERROR(LOG_CORE, "WriteStrToFile: %{public}s write failed.", filename.c_str());
291         out.close();
292         return false;
293     }
294     out.flush();
295     out.close();
296     return true;
297 }
298 
WriteStrToFile(const std::string & filename,const std::string & str)299 bool WriteStrToFile(const std::string& filename, const std::string& str)
300 {
301     if (access((g_traceRootPath + filename).c_str(), W_OK) < 0) {
302         HILOG_WARN(LOG_CORE, "WriteStrToFile: Failed to access %{public}s, errno(%{public}d).",
303             (g_traceRootPath + filename).c_str(), errno);
304         return false;
305     }
306     return WriteStrToFileInner(g_traceRootPath + filename, str);
307 }
308 
SetTraceNodeStatus(const std::string & path,bool enabled)309 void SetTraceNodeStatus(const std::string &path, bool enabled)
310 {
311     WriteStrToFile(path, enabled ? "1" : "0");
312 }
313 
TruncateFile()314 void TruncateFile()
315 {
316     int fd = creat((g_traceRootPath + TRACE_NODE).c_str(), 0);
317     if (fd == -1) {
318         HILOG_ERROR(LOG_CORE, "TruncateFile: clear old trace failed.");
319         return;
320     }
321     close(fd);
322     return;
323 }
324 
SetProperty(const std::string & property,const std::string & value)325 bool SetProperty(const std::string& property, const std::string& value)
326 {
327     bool result = OHOS::system::SetParameter(property, value);
328     if (!result) {
329         HILOG_ERROR(LOG_CORE, "SetProperty: set %{public}s failed.", value.c_str());
330     } else {
331         HILOG_INFO(LOG_CORE, "SetProperty: set %{public}s success.", value.c_str());
332     }
333     return result;
334 }
335 
336 // close all trace node
TraceInit(const std::map<std::string,TraceTag> & allTags)337 void TraceInit(const std::map<std::string, TraceTag>& allTags)
338 {
339     // close all ftrace events
340     for (auto it = allTags.begin(); it != allTags.end(); it++) {
341         if (it->second.type != 1) {
342             continue;
343         }
344         for (size_t i = 0; i < it->second.enablePath.size(); i++) {
345             SetTraceNodeStatus(it->second.enablePath[i], false);
346         }
347     }
348     // close all user tags
349     SetProperty(TRACE_TAG_ENABLE_FLAGS, std::to_string(0));
350 
351     // set buffer_size_kb 1
352     WriteStrToFile("buffer_size_kb", "1");
353 
354     // close tracing_on
355     SetTraceNodeStatus(TRACING_ON_NODE, false);
356 }
357 
358 // Open specific trace node
SetAllTags(const TraceParams & traceParams,const std::map<std::string,TraceTag> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable,std::vector<std::string> & tagFmts)359 void SetAllTags(const TraceParams& traceParams, const std::map<std::string, TraceTag>& allTags,
360                 const std::map<std::string, std::vector<std::string>>& tagGroupTable,
361                 std::vector<std::string>& tagFmts)
362 {
363     std::set<std::string> readyEnableTagList;
364     for (std::string tagName : traceParams.tags) {
365         readyEnableTagList.insert(tagName);
366     }
367 
368     for (std::string groupName : traceParams.tagGroups) {
369         auto iter = tagGroupTable.find(groupName);
370         if (iter == tagGroupTable.end()) {
371             continue;
372         }
373         for (std::string tag : iter->second) {
374             readyEnableTagList.insert(tag);
375         }
376     }
377 
378     uint64_t enabledUserTags = 0;
379     for (std::string tagName : readyEnableTagList) {
380         auto iter = allTags.find(tagName);
381         if (iter == allTags.end()) {
382             HILOG_ERROR(LOG_CORE, "tag<%{public}s> is invalid.", tagName.c_str());
383             continue;
384         }
385 
386         if (iter->second.type == 0) {
387             enabledUserTags |= iter->second.tag;
388         }
389 
390         if (iter->second.type == 1) {
391             for (const auto& path : iter->second.enablePath) {
392                 SetTraceNodeStatus(path, true);
393             }
394             for (const auto& format : iter->second.formatPath) {
395                 tagFmts.emplace_back(format);
396             }
397         }
398     }
399     SetProperty(TRACE_TAG_ENABLE_FLAGS, std::to_string(enabledUserTags));
400 }
401 
SetClock(const std::string & clockType)402 void SetClock(const std::string& clockType)
403 {
404     const std::string traceClockPath = "trace_clock";
405     if (clockType.size() == 0) {
406         WriteStrToFile(traceClockPath, "boot"); //set default: boot
407         return;
408     }
409     std::string allClocks = ReadFile(traceClockPath, g_traceRootPath);
410     if (allClocks.find(clockType) == std::string::npos) {
411         HILOG_ERROR(LOG_CORE, "SetClock: %{public}s is non-existent, set to boot", clockType.c_str());
412         WriteStrToFile(traceClockPath, "boot"); // set default: boot
413         return;
414     }
415 
416     allClocks.erase(allClocks.find_last_not_of(" \n") + 1);
417     allClocks.push_back(' ');
418 
419     std::set<std::string> allClockTypes;
420     size_t curPos = 0;
421     for (size_t i = 0; i < allClocks.size(); i++) {
422         if (allClocks[i] == ' ') {
423             allClockTypes.insert(allClocks.substr(curPos, i - curPos));
424             curPos = i + 1;
425         }
426     }
427 
428     std::string currentClockType;
429     for (auto i : allClockTypes) {
430         if (clockType.compare(i) == 0) {
431             HILOG_INFO(LOG_CORE, "SetClock: set clock %{public}s success.", clockType.c_str());
432             WriteStrToFile(traceClockPath, clockType);
433             return;
434         }
435         if (i[0] == '[') {
436             currentClockType = i;
437         }
438     }
439 
440     const int marks = 2;
441     if (clockType.compare(currentClockType.substr(1, currentClockType.size() - marks)) == 0) {
442         HILOG_INFO(LOG_CORE, "SetClock: set clock %{public}s success.", clockType.c_str());
443         return;
444     }
445 
446     HILOG_INFO(LOG_CORE, "SetClock: unknown %{public}s, change to default clock_type: boot.", clockType.c_str());
447     WriteStrToFile(traceClockPath, "boot"); // set default: boot
448     return;
449 }
450 
SetTraceSetting(const TraceParams & traceParams,const std::map<std::string,TraceTag> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable,std::vector<std::string> & tagFmts)451 bool SetTraceSetting(const TraceParams& traceParams, const std::map<std::string, TraceTag>& allTags,
452                      const std::map<std::string, std::vector<std::string>>& tagGroupTable,
453                      std::vector<std::string>& tagFmts)
454 {
455     TraceInit(allTags);
456 
457     TruncateFile();
458 
459     SetAllTags(traceParams, allTags, tagGroupTable, tagFmts);
460 
461     WriteStrToFile("current_tracer", "nop");
462     WriteStrToFile("buffer_size_kb", traceParams.bufferSize);
463 
464     SetClock(traceParams.clockType);
465 
466     if (traceParams.isOverWrite == "1") {
467         WriteStrToFile("options/overwrite", "1");
468     } else {
469         WriteStrToFile("options/overwrite", "0");
470     }
471 
472     WriteStrToFile("saved_cmdlines_size", std::to_string(SAVED_CMDLINES_SIZE));
473     WriteStrToFile("options/record-tgid", "1");
474     WriteStrToFile("options/record-cmd", "1");
475     return true;
476 }
477 
CheckPage(uint8_t contentType,uint8_t * page)478 bool CheckPage(uint8_t contentType, uint8_t* page)
479 {
480     const int pageThreshold = PAGE_SIZE / 2;
481 
482     // Check raw_trace page size.
483     if (contentType >= CONTENT_TYPE_CPU_RAW && !IsHmKernel()) {
484         PageHeader *pageHeader = reinterpret_cast<PageHeader*>(&page);
485         if (pageHeader->size < static_cast<uint64_t>(pageThreshold)) {
486             return false;
487         }
488     }
489 
490     return true;
491 }
492 
CheckFileExist(const std::string & outputFile)493 bool CheckFileExist(const std::string& outputFile)
494 {
495     g_writeFileLimit++;
496     if (g_writeFileLimit > JUDGE_FILE_EXIST) {
497         g_writeFileLimit = 0;
498         if (access(outputFile.c_str(), F_OK) != 0) {
499             g_needGenerateNewTraceFile = true;
500             HILOG_INFO(LOG_CORE, "CheckFileExist access file:%{public}s failed, errno: %{public}d.",
501                 outputFile.c_str(), errno);
502             return false;
503         }
504     }
505     return true;
506 }
507 
SetTimeIntervalBoundary(int inputMaxDuration,uint64_t utTraceEndTime)508 TraceErrorCode SetTimeIntervalBoundary(int inputMaxDuration, uint64_t utTraceEndTime)
509 {
510     if (inputMaxDuration < 0) {
511         HILOG_ERROR(LOG_CORE, "DumpTrace: Illegal input: maxDuration = %d < 0.", inputMaxDuration);
512         return INVALID_MAX_DURATION;
513     }
514 
515     uint64_t utNow = static_cast<uint64_t>(std::time(nullptr));
516     if (utTraceEndTime >= utNow) {
517         HILOG_WARN(LOG_CORE, "DumpTrace: Warning: traceEndTime is later than current time, set to current.");
518         utTraceEndTime = 0;
519     }
520     struct timespec bts = {0, 0};
521     clock_gettime(CLOCK_BOOTTIME, &bts);
522     uint64_t btNow = static_cast<uint64_t>(bts.tv_sec) + (static_cast<uint64_t>(bts.tv_nsec) != 0 ? 1 : 0);
523     uint64_t utBootTime = utNow - btNow;
524     if (utTraceEndTime == 0) {
525         g_traceEndTime = static_cast<uint64_t>(bts.tv_sec * S_TO_NS + bts.tv_nsec);
526     } else if (utTraceEndTime > utBootTime) {
527         // beware of input precision of seconds: add an extra second of tolerance
528         g_traceEndTime = (utTraceEndTime - utBootTime + 1) * S_TO_NS;
529     } else {
530         HILOG_ERROR(LOG_CORE,
531             "DumpTrace: traceEndTime:(%{public}" PRIu64 ") is earlier than boot_time:(%{public}" PRIu64 ").",
532             utTraceEndTime, utBootTime);
533         return OUT_OF_TIME;
534     }
535 
536     uint64_t maxDuration = inputMaxDuration > 0 ? static_cast<uint64_t>(inputMaxDuration) + 1 : 0;
537     if (maxDuration > g_traceEndTime / S_TO_NS) {
538         HILOG_WARN(LOG_CORE, "maxDuration is larger than TraceEndTime boot clock.");
539         maxDuration = 0;
540     }
541     if (maxDuration > 0) {
542         g_traceStartTime = g_traceEndTime - maxDuration * S_TO_NS;
543     } else {
544         g_traceStartTime = 0;
545     }
546     return SUCCESS;
547 }
548 
RestoreTimeIntervalBoundary()549 void RestoreTimeIntervalBoundary()
550 {
551     g_traceStartTime = 0;
552     g_traceEndTime = std::numeric_limits<uint64_t>::max();
553 }
554 
GetFileSizeThresholdAndTraceTime(bool & isCpuRaw,uint8_t contentType,uint64_t & traceStartTime,uint64_t & traceEndTime,int & fileSizeThreshold)555 void GetFileSizeThresholdAndTraceTime(bool &isCpuRaw, uint8_t contentType, uint64_t &traceStartTime,
556                                       uint64_t &traceEndTime, int &fileSizeThreshold)
557 {
558     isCpuRaw = contentType >= CONTENT_TYPE_CPU_RAW && contentType < CONTENT_TYPE_HEADER_PAGE;
559     if (isCpuRaw) {
560         traceStartTime = g_traceStartTime;
561         traceEndTime = g_traceEndTime;
562         HILOG_INFO(LOG_CORE, "traceStartTime:(%{public}" PRIu64 "), traceEndTime:(%{public}" PRIu64 ").",
563             traceStartTime, traceEndTime);
564     }
565     if (g_cacheFlag.load()) {
566         fileSizeThreshold = DEFAULT_CACHE_FILE_SIZE * BYTE_PER_KB;
567         return;
568     }
569     if (g_currentTraceParams.fileSize != 0) {
570         fileSizeThreshold = g_currentTraceParams.fileSize * BYTE_PER_KB;
571     }
572 }
573 
IsWriteFileOverflow(const bool isCpuRaw,const int & outputFileSize,const ssize_t & writeLen,const int & fileSizeThreshold)574 bool IsWriteFileOverflow(const bool isCpuRaw, const int &outputFileSize, const ssize_t& writeLen,
575                          const int& fileSizeThreshold)
576 {
577     // attention: we only check file size threshold in CMD_MODE
578     if (!isCpuRaw || (!IsRecordOn() && !IsCacheOn()) || !g_needLimitFileSize) {
579         return false;
580     }
581     if (outputFileSize + writeLen + static_cast<int>(sizeof(TraceFileContentHeader)) >= fileSizeThreshold) {
582         HILOG_ERROR(LOG_CORE, "Failed to write, current round write file size exceeds the file size limit.");
583         return true;
584     }
585     if (writeLen > INT_MAX - BUFFER_SIZE) {
586         HILOG_ERROR(LOG_CORE, "Failed to write, write file length is nearly overflow.");
587         return true;
588     }
589     return false;
590 }
591 
WriteFile(uint8_t contentType,const std::string & src,int outFd,const std::string & outputFile)592 bool WriteFile(uint8_t contentType, const std::string& src, int outFd, const std::string& outputFile)
593 {
594     std::string srcPath = CanonicalizeSpecPath(src.c_str());
595     int srcFd = open(srcPath.c_str(), O_RDONLY | O_NONBLOCK);
596     if (srcFd < 0) {
597         HILOG_ERROR(LOG_CORE, "WriteFile: open %{public}s failed.", src.c_str());
598         return false;
599     }
600     if (!CheckFileExist(outputFile)) {
601         HILOG_ERROR(LOG_CORE, "need generate new trace file, old file:%{public}s.", outputFile.c_str());
602         return false;
603     }
604     struct TraceFileContentHeader contentHeader;
605     contentHeader.type = contentType;
606     write(outFd, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
607     ssize_t writeLen = 0;
608     int count = 0;
609     const int maxCount = 2;
610 
611     uint64_t traceStartTime = 0;
612     uint64_t traceEndTime = std::numeric_limits<uint64_t>::max();
613     int fileSizeThreshold = DEFAULT_FILE_SIZE * BYTE_PER_KB;
614     bool isCpuRaw = false;
615     GetFileSizeThresholdAndTraceTime(isCpuRaw, contentType, traceStartTime, traceEndTime, fileSizeThreshold);
616     bool printFirstPageTime = false;
617     while (true) {
618         int bytes = 0;
619         bool endFlag = false;
620         /* Write 1M at a time */
621         while (bytes <= (BUFFER_SIZE - static_cast<int>(PAGE_SIZE))) {
622             ssize_t readBytes = TEMP_FAILURE_RETRY(read(srcFd, g_buffer + bytes, PAGE_SIZE));
623             if (readBytes == 0) {
624                 endFlag = true;
625                 HILOG_DEBUG(LOG_CORE, "WriteFile: read %{public}s end.", src.c_str());
626                 break;
627             } else if (readBytes < 0) {
628                 endFlag = true;
629                 HILOG_DEBUG(LOG_CORE, "WriteFile: read %{public}s, data size: %{public}zd failed, errno: %{public}d.",
630                     src.c_str(), readBytes, errno);
631                 break;
632             }
633 
634             uint64_t pageTraceTime = 0;
635             if (memcpy_s(&pageTraceTime, sizeof(uint64_t), g_buffer + bytes, sizeof(uint64_t)) != EOK) {
636                 HILOG_ERROR(LOG_CORE, "Failed to memcpy g_buffer to pageTraceTime.");
637                 break;
638             }
639             if (traceEndTime < pageTraceTime) {
640                 endFlag = true;
641                 bytes += (printFirstPageTime == true ? readBytes : 0);
642                 HILOG_INFO(LOG_CORE,
643                     "Current pageTraceTime:(%{public}" PRIu64 ") is larger than traceEndTime:(%{public}" PRIu64 ")",
644                     pageTraceTime, traceEndTime);
645                 break;
646             }
647             if (pageTraceTime < traceStartTime) {
648                 continue;
649             }
650             if (isCpuRaw) {
651                 g_lastPageTimestamp = std::max(pageTraceTime, g_lastPageTimestamp);
652                 if (UNEXPECTANTLY(!printFirstPageTime)) {
653                     HILOG_INFO(LOG_CORE, "first page trace time:(%{public}" PRIu64 ")", pageTraceTime);
654                     printFirstPageTime = true;
655                     g_firstPageTimestamp = std::min(g_firstPageTimestamp, pageTraceTime);
656                 }
657             }
658 
659             if (CheckPage(contentType, g_buffer + bytes) == false) {
660                 count++;
661             }
662             bytes += readBytes;
663             if (count >= maxCount) {
664                 endFlag = true;
665                 break;
666             }
667         }
668 
669         ssize_t writeRet = TEMP_FAILURE_RETRY(write(outFd, g_buffer, bytes));
670         if (writeRet < 0) {
671             HILOG_WARN(LOG_CORE, "WriteFile Fail, errno: %{public}d.", errno);
672         } else {
673             if (writeRet != static_cast<ssize_t>(bytes)) {
674                 HILOG_WARN(LOG_CORE, "Failed to write full info, writeLen: %{public}zd, FullLen: %{public}d.",
675                     writeRet, bytes);
676             }
677             writeLen += writeRet;
678         }
679 
680         if (IsWriteFileOverflow(isCpuRaw, g_outputFileSize, writeLen, fileSizeThreshold)) {
681             HILOG_WARN(LOG_CORE, "Write file over flow, fileZise: %{public}d, writeLen: %{public}zd, "
682                 "FullLen: %{public}d.", g_outputFileSize, writeRet, bytes);
683             break;
684         }
685 
686         if (endFlag == true) {
687             break;
688         }
689     }
690     contentHeader.length = static_cast<uint32_t>(writeLen);
691     uint32_t offset = contentHeader.length + sizeof(contentHeader);
692     off_t pos = lseek(outFd, 0, SEEK_CUR);
693     lseek(outFd, pos - offset, SEEK_SET);
694     write(outFd, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
695     lseek(outFd, pos, SEEK_SET);
696     close(srcFd);
697     if (isCpuRaw) {
698         if (writeLen > 0) {
699             g_dumpStatus = TraceErrorCode::SUCCESS;
700         } else if (g_dumpStatus == TraceErrorCode::UNSET) {
701             g_dumpStatus = TraceErrorCode::OUT_OF_TIME;
702         }
703     }
704     g_outputFileSize += static_cast<int>(offset);
705     g_needGenerateNewTraceFile = false;
706     HILOG_INFO(LOG_CORE, "WriteFile end, path: %{public}s, byte: %{public}zd. g_writeFileLimit: %{public}d",
707         src.c_str(), writeLen, g_writeFileLimit);
708     return true;
709 }
710 
WriteEventFile(std::string & srcPath,int outFd)711 void WriteEventFile(std::string& srcPath, int outFd)
712 {
713     uint8_t buffer[PAGE_SIZE] = {0};
714     std::string srcSpecPath = CanonicalizeSpecPath(srcPath.c_str());
715     int srcFd = open(srcSpecPath.c_str(), O_RDONLY);
716     if (srcFd < 0) {
717         HILOG_ERROR(LOG_CORE, "WriteEventFile: open %{public}s failed.", srcPath.c_str());
718         return;
719     }
720     int64_t readLen = 0;
721     do {
722         int64_t len = read(srcFd, buffer, PAGE_SIZE);
723         if (len <= 0) {
724             break;
725         }
726         write(outFd, buffer, len);
727         readLen += len;
728     } while (true);
729     close(srcFd);
730     HILOG_INFO(LOG_CORE, "WriteEventFile end, path: %{public}s, data size: (%{public}" PRIu64 ").",
731         srcPath.c_str(), static_cast<uint64_t>(readLen));
732 }
733 
WriteEventsFormat(int outFd,const std::string & outputFile)734 bool WriteEventsFormat(int outFd, const std::string& outputFile)
735 {
736     const std::string savedEventsFormatPath = TRACE_FILE_DEFAULT_DIR + TRACE_SAVED_EVENTS_FORMAT;
737     if (access(savedEventsFormatPath.c_str(), F_OK) != -1) {
738         return WriteFile(CONTENT_TYPE_EVENTS_FORMAT, savedEventsFormatPath, outFd, outputFile);
739     }
740 
741     // write all trace formats into TRACE_SAVED_EVENTS_FORMAT file.
742     int fd = open(savedEventsFormatPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
743     if (fd < 0) {
744         HILOG_ERROR(LOG_CORE, "WriteEventsFormat: open %{public}s failed.", savedEventsFormatPath.c_str());
745         return false;
746     }
747     if (g_traceJsonParser == nullptr) {
748         g_traceJsonParser = std::make_shared<TraceJsonParser>();
749     }
750     if (!g_traceJsonParser->ParseTraceJson(PARSE_TRACE_FORMAT_INFO)) {
751         HILOG_ERROR(LOG_CORE, "WriteEventsFormat: Failed to parse trace format infos.");
752         close(fd);
753         return false;
754     }
755     auto allTags = g_traceJsonParser->GetAllTagInfos();
756     auto traceFormats = g_traceJsonParser->GetBaseFmtPath();
757     for (auto& tag : allTags) {
758         for (auto& fmt : tag.second.formatPath) {
759             traceFormats.emplace_back(fmt);
760         }
761     }
762     for (auto& traceFmt : traceFormats) {
763         std::string srcPath = g_traceRootPath + traceFmt;
764         if (access(srcPath.c_str(), R_OK) != -1) {
765             WriteEventFile(srcPath, fd);
766         }
767     }
768     close(fd);
769     HILOG_INFO(LOG_CORE, "WriteEventsFormat end. path: %{public}s.", savedEventsFormatPath.c_str());
770     return WriteFile(CONTENT_TYPE_EVENTS_FORMAT, savedEventsFormatPath, outFd, outputFile);
771 }
772 
WriteHeaderPage(int outFd,const std::string & outputFile)773 bool WriteHeaderPage(int outFd, const std::string& outputFile)
774 {
775     if (IsHmKernel()) {
776         return true;
777     }
778     std::string headerPagePath = GetFilePath("events/header_page", g_traceRootPath);
779     return WriteFile(CONTENT_TYPE_HEADER_PAGE, headerPagePath, outFd, outputFile);
780 }
781 
WritePrintkFormats(int outFd,const std::string & outputFile)782 bool WritePrintkFormats(int outFd, const std::string &outputFile)
783 {
784     if (IsHmKernel()) {
785         return true;
786     }
787     std::string printkFormatPath = GetFilePath("printk_formats", g_traceRootPath);
788     return WriteFile(CONTENT_TYPE_PRINTK_FORMATS, printkFormatPath, outFd, outputFile);
789 }
790 
WriteKallsyms(int outFd)791 bool WriteKallsyms(int outFd)
792 {
793     /* not implement in hmkernel */
794     if (IsHmKernel()) {
795         return true;
796     }
797     /* not implement in linux */
798     return true;
799 }
800 
HmWriteCpuRawInner(int outFd,const std::string & outputFile)801 bool HmWriteCpuRawInner(int outFd, const std::string& outputFile)
802 {
803     uint8_t type = CONTENT_TYPE_CPU_RAW;
804     std::string src = g_traceRootPath + "/trace_pipe_raw";
805 
806     if (!WriteFile(type, src, outFd, outputFile)) {
807         return false;
808     }
809 
810     if (g_dumpStatus) {
811         HILOG_ERROR(LOG_CORE, "HmWriteCpuRawInner failed, errno: %{public}d.", static_cast<int>(g_dumpStatus.load()));
812         return false;
813     }
814 
815     return true;
816 }
817 
WriteCpuRawInner(int outFd,const std::string & outputFile)818 bool WriteCpuRawInner(int outFd, const std::string& outputFile)
819 {
820     int cpuNums = GetCpuProcessors();
821     uint8_t type = CONTENT_TYPE_CPU_RAW;
822     for (int i = 0; i < cpuNums; i++) {
823         std::string src = g_traceRootPath + "per_cpu/cpu" + std::to_string(i) + "/trace_pipe_raw";
824         if (!WriteFile(static_cast<uint8_t>(type + i), src, outFd, outputFile)) {
825             return false;
826         }
827     }
828     if (g_dumpStatus) {
829         HILOG_ERROR(LOG_CORE, "WriteCpuRawInner failed, errno: %{public}d.", static_cast<int>(g_dumpStatus.load()));
830         return false;
831     }
832     return true;
833 }
834 
WriteCpuRaw(int outFd,const std::string & outputFile)835 bool WriteCpuRaw(int outFd, const std::string& outputFile)
836 {
837     if (!IsHmKernel()) {
838         return WriteCpuRawInner(outFd, outputFile);
839     } else {
840         return HmWriteCpuRawInner(outFd, outputFile);
841     }
842 }
843 
WriteCmdlines(int outFd,const std::string & outputFile)844 bool WriteCmdlines(int outFd, const std::string& outputFile)
845 {
846     std::string cmdlinesPath = GetFilePath("saved_cmdlines", g_traceRootPath);
847     return WriteFile(CONTENT_TYPE_CMDLINES, cmdlinesPath, outFd, outputFile);
848 }
849 
WriteTgids(int outFd,const std::string & outputFile)850 bool WriteTgids(int outFd, const std::string& outputFile)
851 {
852     std::string tgidsPath = GetFilePath("saved_tgids", g_traceRootPath);
853     return WriteFile(CONTENT_TYPE_TGIDS, tgidsPath, outFd, outputFile);
854 }
855 
GenerateNewFile(int & outFd,std::string & outPath,const TRACE_TYPE traceType)856 bool GenerateNewFile(int& outFd, std::string& outPath, const TRACE_TYPE traceType)
857 {
858     if (access(outPath.c_str(), F_OK) == 0) {
859         return true;
860     }
861     std::string outputFileName = GenerateTraceFileName(traceType);
862     outPath = CanonicalizeSpecPath(outputFileName.c_str());
863     outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
864     if (outFd < 0) {
865         g_newTraceFileLimit++;
866         HILOG_ERROR(LOG_CORE, "open %{public}s failed, errno: %{public}d.", outPath.c_str(), errno);
867     }
868     if (g_newTraceFileLimit > MAX_NEW_TRACE_FILE_LIMIT) {
869         HILOG_ERROR(LOG_CORE, "create new trace file %{public}s limited.", outPath.c_str());
870         return false;
871     }
872     g_needGenerateNewTraceFile = true;
873     return true;
874 }
875 
SetFileInfo(const std::string outPath,const uint64_t & firstPageTimestamp,const uint64_t & lastPageTimestamp,TraceFileInfo & traceFileInfo)876 bool SetFileInfo(const std::string outPath, const uint64_t& firstPageTimestamp,
877     const uint64_t& lastPageTimestamp, TraceFileInfo& traceFileInfo)
878 {
879     std::string newFileName;
880     if (!RenameTraceFile(outPath, newFileName, firstPageTimestamp, lastPageTimestamp)) {
881         HILOG_INFO(LOG_CORE, "rename failed, outPath: %{public}s.", outPath.c_str());
882         return false;
883     }
884     time_t firstPageTime = 0;
885     time_t lastPageTime = 0;
886     if (!ConvertPageTraceTimeToUtTime(firstPageTimestamp, firstPageTime) ||
887         !ConvertPageTraceTimeToUtTime(lastPageTimestamp, lastPageTime)) {
888         return false;
889     }
890     uint64_t traceFileSize = 0;
891     if (!GetFileSize(newFileName, traceFileSize)) {
892         return false;
893     }
894     traceFileInfo.filename = newFileName;
895     traceFileInfo.traceStartTime = static_cast<uint64_t>(firstPageTime);
896     traceFileInfo.traceEndTime = static_cast<uint64_t>(lastPageTime);
897     traceFileInfo.fileSize = traceFileSize;
898     return true;
899 }
900 
GetTraceFileFromVec(const uint64_t & inputTraceStartTime,const uint64_t & inputTraceEndTime,std::vector<TraceFileInfo> & fileVec,std::vector<std::string> & outputFiles)901 void GetTraceFileFromVec(const uint64_t& inputTraceStartTime, const uint64_t& inputTraceEndTime,
902     std::vector<TraceFileInfo>& fileVec, std::vector<std::string>& outputFiles)
903 {
904     for (auto it = fileVec.begin(); it != fileVec.end(); it++) {
905         HILOG_INFO(LOG_CORE, "GetTraceFileFromVec: %{public}s, [(%{public}" PRIu64 ", %{public}" PRIu64 "].",
906             (*it).filename.c_str(), (*it).traceStartTime, (*it).traceEndTime);
907         if ((((*it).traceStartTime >= inputTraceStartTime && (*it).traceStartTime <= inputTraceEndTime) ||
908              ((*it).traceEndTime >= inputTraceStartTime && (*it).traceEndTime <= inputTraceEndTime) ||
909              ((*it).traceStartTime <= inputTraceStartTime && (*it).traceEndTime >= inputTraceEndTime)) &&
910              ((*it).traceEndTime - (*it).traceStartTime < 2000)) { // 2000 : max trace duration 2000s
911             outputFiles.push_back((*it).filename);
912             HILOG_INFO(LOG_CORE, "Put file: %{public}s into outputFiles.", (*it).filename.c_str());
913         }
914     }
915 }
916 
SearchTraceFiles(const uint64_t & inputTraceStartTime,const uint64_t & inputTraceEndTime,std::vector<std::string> & outputFiles)917 void SearchTraceFiles(const uint64_t& inputTraceStartTime, const uint64_t& inputTraceEndTime,
918     std::vector<std::string>& outputFiles)
919 {
920     GetTraceFileFromVec(inputTraceStartTime, inputTraceEndTime, g_cacheFileVec, outputFiles);
921     GetTraceFileFromVec(inputTraceStartTime, inputTraceEndTime, g_traceFileVec, outputFiles);
922 }
923 
CacheTraceLoop(const std::string & outputFileName)924 bool CacheTraceLoop(const std::string &outputFileName)
925 {
926     std::lock_guard<std::mutex> lock(g_cacheTraceMutex);
927     int fileSizeThreshold = DEFAULT_CACHE_FILE_SIZE * BYTE_PER_KB;
928     g_firstPageTimestamp = UINT64_MAX;
929     g_lastPageTimestamp = 0;
930     g_outputFileSize = 0;
931     std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
932     int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
933     if (outFd < 0) {
934         HILOG_ERROR(LOG_CORE, "open %{public}s failed, errno: %{public}d.", outPath.c_str(), errno);
935         return false;
936     }
937     MarkClockSync(g_traceRootPath);
938     struct TraceFileHeader header = GenerateTraceHeaderContent();
939     uint64_t sliceDuration = 0;
940     do {
941         g_needGenerateNewTraceFile = false;
942         ssize_t writeRet = TEMP_FAILURE_RETRY(write(outFd, reinterpret_cast<char *>(&header), sizeof(header)));
943         if (writeRet < 0) {
944             HILOG_WARN(LOG_CORE, "Failed to write trace file header, errno: %{public}s, headerLen: %{public}zu.",
945                 strerror(errno), sizeof(header));
946             close(outFd);
947             return false;
948         }
949         WriteEventsFormat(outFd, outPath);
950         while (g_cacheFlag.load()) {
951             if (g_outputFileSize > fileSizeThreshold) {
952                 break;
953             }
954             struct timespec bts = {0, 0};
955             clock_gettime(CLOCK_BOOTTIME, &bts);
956             uint64_t startTime = static_cast<uint64_t>(bts.tv_sec * S_TO_NS + bts.tv_nsec);
957             sleep(CACHE_TRACE_LOOP_SLEEP_TIME);
958             if (!WriteCpuRaw(outFd, outPath)) {
959                 break;
960             }
961             clock_gettime(CLOCK_BOOTTIME, &bts);
962             uint64_t endTime = static_cast<uint64_t>(bts.tv_sec * S_TO_NS + bts.tv_nsec);
963             uint64_t timeDiff = (endTime - startTime) / S_TO_NS;
964             sliceDuration += timeDiff;
965             if (sliceDuration >= g_sliceMaxDuration || g_interruptDump.load() == 1) {
966                 sliceDuration = 0;
967                 break;
968             }
969         }
970         WriteCmdlines(outFd, outPath);
971         WriteTgids(outFd, outPath);
972         WriteHeaderPage(outFd, outPath);
973         WritePrintkFormats(outFd, outPath);
974         WriteKallsyms(outFd);
975         if (!GenerateNewFile(outFd, outPath, TRACE_CACHE)) {
976             HILOG_INFO(LOG_CORE, "CacheTraceLoop access file:%{public}s failed, errno: %{public}d.",
977                 outPath.c_str(), errno);
978             close(outFd);
979             return false;
980         }
981     } while (g_needGenerateNewTraceFile);
982     close(outFd);
983     TraceFileInfo traceFileInfo;
984     if (!SetFileInfo(outPath, g_firstPageTimestamp, g_lastPageTimestamp, traceFileInfo)) {
985         RemoveFile(outPath);
986         return false;
987     }
988     g_cacheFileVec.push_back(traceFileInfo);
989     return true;
990 }
991 
ProcessCacheTask()992 void ProcessCacheTask()
993 {
994     const std::string threadName = "CacheTraceTask";
995     prctl(PR_SET_NAME, threadName.c_str());
996     while (g_cacheFlag.load()) {
997         std::string outputFileName = GenerateTraceFileName(TRACE_CACHE);
998         if (CacheTraceLoop(outputFileName)) {
999             ClearCacheTraceFileBySize(g_cacheFileVec, g_totalFileSizeLimit);
1000             HILOG_INFO(LOG_CORE, "ProcessCacheTask: save cache file.");
1001         } else {
1002             break;
1003         }
1004     }
1005     g_cacheEnd.store(true);
1006     HILOG_INFO(LOG_CORE, "ProcessCacheTask: trace cache thread exit.");
1007 }
1008 
RecordTraceLoop(const std::string & outputFileName,bool isLimited)1009 bool RecordTraceLoop(const std::string& outputFileName, bool isLimited)
1010 {
1011     g_outputFileSize = 0;
1012     std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
1013     int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
1014     if (outFd < 0) {
1015         HILOG_ERROR(LOG_CORE, "open %{public}s failed, errno: %{public}d.", outPath.c_str(), errno);
1016         return false;
1017     }
1018     int fileSizeThreshold = DEFAULT_FILE_SIZE * BYTE_PER_KB;
1019     if (g_currentTraceParams.fileSize != 0) {
1020         fileSizeThreshold = g_currentTraceParams.fileSize * BYTE_PER_KB;
1021     }
1022     MarkClockSync(g_traceRootPath);
1023     struct TraceFileHeader header = GenerateTraceHeaderContent();
1024     do {
1025         g_needGenerateNewTraceFile = false;
1026         ssize_t writeRet = TEMP_FAILURE_RETRY(write(outFd, reinterpret_cast<char *>(&header), sizeof(header)));
1027         if (writeRet < 0) {
1028             HILOG_WARN(LOG_CORE, "Failed to write trace file header, errno: %{public}s, headerLen: %{public}zu.",
1029                 strerror(errno), sizeof(header));
1030             close(outFd);
1031             return false;
1032         }
1033         WriteEventsFormat(outFd, outPath);
1034         while (g_recordFlag.load()) {
1035             if (isLimited && g_outputFileSize > fileSizeThreshold) {
1036                 break;
1037             }
1038             sleep(RECORD_LOOP_SLEEP);
1039             g_traceEndTime = GetCurBootTime();
1040             if (!WriteCpuRaw(outFd, outPath)) {
1041                 break;
1042             }
1043         }
1044         WriteCmdlines(outFd, outPath);
1045         WriteTgids(outFd, outPath);
1046         WriteHeaderPage(outFd, outPath);
1047         WritePrintkFormats(outFd, outPath);
1048         WriteKallsyms(outFd);
1049         if (!GenerateNewFile(outFd, outPath, TRACE_RECORDING)) {
1050             HILOG_INFO(LOG_CORE, "RecordTraceLoop access file:%{public}s failed, errno: %{public}d.",
1051                 outPath.c_str(), errno);
1052             close(outFd);
1053             return false;
1054         }
1055     } while (g_needGenerateNewTraceFile);
1056     close(outFd);
1057     g_traceEndTime = std::numeric_limits<uint64_t>::max();
1058     return true;
1059 }
1060 
1061 /**
1062  * read trace data loop
1063  * g_recordFlag: true = open,false = close
1064  * g_recordEnd: true = end,false = not end
1065  * if user has own output file, Output all data to the file specified by the user;
1066  * if not, Then place all the result files in /data/log/hitrace/ and package them once in 96M.
1067 */
ProcessRecordTask()1068 void ProcessRecordTask()
1069 {
1070     {
1071         std::lock_guard<std::mutex> lock(g_recordingOutputMutex);
1072         g_recordingOutput = {};
1073     }
1074     const std::string threadName = "TraceDumpTask";
1075     prctl(PR_SET_NAME, threadName.c_str());
1076     HILOG_INFO(LOG_CORE, "ProcessRecordTask: trace dump thread start.");
1077 
1078     if (!IsRootVersion()) {
1079         // clear old record file before record tracing start.
1080         DelOldRecordTraceFile(g_currentTraceParams.fileLimit);
1081     }
1082 
1083     // if input filesize = 0, trace file should not be cut in root version.
1084     if (g_currentTraceParams.fileSize == 0 && IsRootVersion()) {
1085         g_needLimitFileSize = false;
1086         std::string outputFileName = g_currentTraceParams.outputFile.empty() ?
1087                                      GenerateTraceFileName(TRACE_RECORDING) : g_currentTraceParams.outputFile;
1088         if (RecordTraceLoop(outputFileName, g_needLimitFileSize)) {
1089             std::lock_guard<std::mutex> lock(g_recordingOutputMutex);
1090             g_recordingOutput.push_back(outputFileName);
1091         }
1092         g_recordEnd.store(true);
1093         g_needLimitFileSize = true;
1094         return;
1095     }
1096 
1097     while (g_recordFlag.load()) {
1098         if (!IsRootVersion()) {
1099             std::lock_guard<std::mutex> lock(g_recordingOutputMutex);
1100             ClearOldTraceFile(g_recordingOutput, g_currentTraceParams.fileLimit);
1101         }
1102         // Generate file name
1103         std::string outputFileName = GenerateTraceFileName(TRACE_RECORDING);
1104         if (RecordTraceLoop(outputFileName, true)) {
1105             std::lock_guard<std::mutex> lock(g_recordingOutputMutex);
1106             g_recordingOutput.push_back(outputFileName);
1107         } else {
1108             break;
1109         }
1110     }
1111     HILOG_INFO(LOG_CORE, "ProcessRecordTask: trace dump thread exit.");
1112     g_recordEnd.store(true);
1113 }
1114 
ReadRawTrace(std::string & outputFileName)1115 bool ReadRawTrace(std::string& outputFileName)
1116 {
1117     // read trace data from /per_cpu/cpux/trace_pipe_raw
1118     std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
1119     int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
1120     if (outFd < 0) {
1121         return false;
1122     }
1123     struct TraceFileHeader header = GenerateTraceHeaderContent();
1124     ssize_t writeRet = TEMP_FAILURE_RETRY(write(outFd, reinterpret_cast<char*>(&header), sizeof(header)));
1125     if (writeRet < 0) {
1126         HILOG_WARN(LOG_CORE, "Failed to write trace file header, errno: %{public}s, headerLen: %{public}zu.",
1127             strerror(errno), sizeof(header));
1128         close(outFd);
1129         return false;
1130     }
1131 
1132     if (WriteEventsFormat(outFd, outPath) && WriteCpuRaw(outFd, outPath) &&
1133         WriteCmdlines(outFd, outPath) && WriteTgids(outFd, outPath) &&
1134         WriteHeaderPage(outFd, outPath) && WritePrintkFormats(outFd, outPath) &&
1135         WriteKallsyms(outFd)) {
1136         fsync(outFd);
1137         close(outFd);
1138         return true;
1139     }
1140     HILOG_ERROR(LOG_CORE, "ReadRawTrace failed.");
1141     fsync(outFd);
1142     close(outFd);
1143     return false;
1144 }
1145 
SetProcessName(std::string & processName)1146 void SetProcessName(std::string& processName)
1147 {
1148     if (processName.size() <= 0) {
1149         return;
1150     }
1151 
1152     const int maxNameLen = 16;
1153     std::string setName;
1154     if (processName.size() > maxNameLen) {
1155         setName = processName.substr(0, maxNameLen);
1156     } else {
1157         setName = processName;
1158     }
1159 
1160     prctl(PR_SET_NAME, setName.c_str(), nullptr, nullptr, nullptr);
1161     HILOG_INFO(LOG_CORE, "New process: %{public}s.", setName.c_str());
1162 }
1163 
TimeoutSignalHandler(int signum)1164 void TimeoutSignalHandler(int signum)
1165 {
1166     if (signum == SIGUSR1) {
1167         _exit(EXIT_SUCCESS);
1168     }
1169 }
1170 
EpollWaitforChildProcess(pid_t & pid,int & pipefd)1171 bool EpollWaitforChildProcess(pid_t& pid, int& pipefd)
1172 {
1173     int epollfd = epoll_create1(0);
1174     if (epollfd == -1) {
1175         HILOG_ERROR(LOG_CORE, "epoll_create1 error.");
1176         return false;
1177     }
1178 
1179     struct epoll_event event;
1180     event.events = EPOLLIN;
1181     event.data.fd = pipefd;
1182     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, pipefd, &event) == -1) {
1183         HILOG_ERROR(LOG_CORE, "epoll_ctl error.");
1184         return false;
1185     }
1186 
1187     struct epoll_event events[1];
1188     constexpr int waitTimeoutMs = 10000; // 10000ms = 10s
1189     int numEvents = TEMP_FAILURE_RETRY(epoll_wait(epollfd, events, 1, waitTimeoutMs));
1190     if (numEvents <= 0) {
1191         if (numEvents == -1) {
1192             HILOG_ERROR(LOG_CORE, "epoll_wait error, error: (%{public}s).", strerror(errno));
1193         } else {
1194             HILOG_ERROR(LOG_CORE, "epoll_wait timeout.");
1195         }
1196         if (waitpid(pid, nullptr, WNOHANG) <= 0) {
1197             HILOG_ERROR(LOG_CORE, "kill timeout child process.");
1198             kill(pid, SIGUSR1);
1199         }
1200         close(pipefd);
1201         close(epollfd);
1202         return false;
1203     }
1204     ChildProcessRet retVal;
1205     read(pipefd, &retVal, sizeof(retVal));
1206     g_dumpStatus = retVal.dumpStatus;
1207     g_firstPageTimestamp = retVal.traceStartTime;
1208     g_lastPageTimestamp = retVal.traceEndTime;
1209 
1210     close(pipefd);
1211     close(epollfd);
1212     if (waitpid(pid, nullptr, 0) <= 0) {
1213         HILOG_ERROR(LOG_CORE, "wait HitraceDump(%{public}d) exit failed, errno: (%{public}d)", pid, errno);
1214     }
1215     return true;
1216 }
1217 
DumpTraceInner(std::vector<std::string> & outputFiles)1218 TraceErrorCode DumpTraceInner(std::vector<std::string>& outputFiles)
1219 {
1220     int pipefd[2];
1221     if (pipe(pipefd) == -1) {
1222         HILOG_ERROR(LOG_CORE, "pipe creation error.");
1223         return TraceErrorCode::PIPE_CREATE_ERROR;
1224     }
1225 
1226     std::string outputFileName = GenerateTraceFileName(TRACE_SNAPSHOT);
1227     std::string reOutPath = CanonicalizeSpecPath(outputFileName.c_str());
1228     g_dumpStatus = TraceErrorCode::UNSET;
1229     /*Child process handles task, Father process wait.*/
1230     pid_t pid = fork();
1231     if (pid < 0) {
1232         HILOG_ERROR(LOG_CORE, "fork error.");
1233         return TraceErrorCode::FORK_ERROR;
1234     } else if (pid == 0) {
1235         signal(SIGUSR1, TimeoutSignalHandler);
1236         close(pipefd[0]);
1237         std::string processName = "HitraceDump";
1238         SetProcessName(processName);
1239         MarkClockSync(g_traceRootPath);
1240         constexpr int waitTime = 10000; // 10ms
1241         usleep(waitTime);
1242         if (ReadRawTrace(reOutPath)) {
1243             g_dumpStatus = TraceErrorCode::SUCCESS;
1244         }
1245         HILOG_DEBUG(LOG_CORE, "%{public}s exit.", processName.c_str());
1246         ChildProcessRet retVal;
1247         retVal.dumpStatus = g_dumpStatus;
1248         retVal.traceStartTime = g_firstPageTimestamp;
1249         retVal.traceEndTime = g_lastPageTimestamp;
1250         write(pipefd[1], &retVal, sizeof(retVal));
1251         _exit(EXIT_SUCCESS);
1252     } else {
1253         close(pipefd[1]);
1254     }
1255 
1256     if (!EpollWaitforChildProcess(pid, pipefd[0])) {
1257         return TraceErrorCode::EPOLL_WAIT_ERROR;
1258     }
1259 
1260     SearchTraceFiles(g_utDestTraceStartTime, g_utDestTraceEndTime, outputFiles);
1261     if (g_dumpStatus) { // trace generation error
1262         if (remove(reOutPath.c_str()) == 0) {
1263             HILOG_INFO(LOG_CORE, "Delete outpath:%{public}s success.", reOutPath.c_str());
1264         } else {
1265             HILOG_INFO(LOG_CORE, "Delete outpath:%{public}s failed.", reOutPath.c_str());
1266         }
1267     } else if (access(reOutPath.c_str(), F_OK) != 0) { // trace access error
1268         HILOG_ERROR(LOG_CORE, "DumpTraceInner: write %{public}s failed.", outputFileName.c_str());
1269     } else {
1270         HILOG_INFO(LOG_CORE, "Output: %{public}s.", reOutPath.c_str());
1271         TraceFileInfo traceFileInfo;
1272         if (!SetFileInfo(reOutPath, g_firstPageTimestamp, g_lastPageTimestamp, traceFileInfo)) {
1273             // trace rename error
1274             HILOG_ERROR(LOG_CORE, "SetFileInfo: set %{public}s info failed.", reOutPath.c_str());
1275             RemoveFile(reOutPath);
1276         } else { // success
1277             g_traceFileVec.push_back(traceFileInfo);
1278             outputFiles.push_back(traceFileInfo.filename);
1279         }
1280     }
1281     if (g_traceJsonParser == nullptr) {
1282         g_traceJsonParser = std::make_shared<TraceJsonParser>();
1283     }
1284     if (!g_traceJsonParser->ParseTraceJson(TRACE_SNAPSHOT_FILE_AGE)) {
1285         HILOG_WARN(LOG_CORE, "DumpTraceInner: Failed to parse TRACE_SNAPSHOT_FILE_AGE.");
1286     }
1287     if ((!IsRootVersion()) || g_traceJsonParser->GetSnapShotFileAge()) {
1288         DelSnapshotTraceFile(SNAPSHOT_FILE_MAX_COUNT, g_traceFileVec);
1289     }
1290 
1291     if (outputFiles.empty()) {
1292         return (g_dumpStatus != 0) ? static_cast<TraceErrorCode>(g_dumpStatus.load()) : TraceErrorCode::FILE_ERROR;
1293     }
1294     return TraceErrorCode::SUCCESS;
1295 }
1296 
GetSysParamTags()1297 uint64_t GetSysParamTags()
1298 {
1299     return OHOS::system::GetUintParameter<uint64_t>(TRACE_TAG_ENABLE_FLAGS, 0);
1300 }
1301 
CheckParam()1302 bool CheckParam()
1303 {
1304     uint64_t currentTags = GetSysParamTags();
1305     if (currentTags == g_sysInitParamTags) {
1306         return true;
1307     }
1308 
1309     if (currentTags == 0) {
1310         HILOG_ERROR(LOG_CORE, "allowed tags are cleared, should restart.");
1311         return false;
1312     }
1313     HILOG_ERROR(LOG_CORE, "trace is being used, should restart.");
1314     return false;
1315 }
1316 
1317 /**
1318  * SERVICE_MODE is running, check param and tracing_on.
1319 */
CheckServiceRunning()1320 bool CheckServiceRunning()
1321 {
1322     if (CheckParam() && IsTracingOn(g_traceRootPath)) {
1323         return true;
1324     }
1325     return false;
1326 }
1327 
CpuBufferBalanceTask()1328 void CpuBufferBalanceTask()
1329 {
1330     g_serviceThreadIsStart = true;
1331     const std::string threadName = "CpuBufferBalancer";
1332     prctl(PR_SET_NAME, threadName.c_str());
1333     HILOG_INFO(LOG_CORE, "CpuBufferBalanceTask: monitor thread start.");
1334     const int intervalTime = 15;
1335     while (IsTraceOpen() && CheckServiceRunning()) {
1336         sleep(intervalTime);
1337 
1338         const int cpuNums = GetCpuProcessors();
1339         std::vector<int> result;
1340         std::unique_ptr<DynamicBuffer> dynamicBuffer = std::make_unique<DynamicBuffer>(g_traceRootPath, cpuNums);
1341         dynamicBuffer->CalculateBufferSize(result);
1342 
1343         if (static_cast<int>(result.size()) != cpuNums) {
1344             HILOG_ERROR(LOG_CORE, "CalculateAllNewBufferSize failed.");
1345             break;
1346         }
1347 
1348         for (size_t i = 0; i < result.size(); i++) {
1349             HILOG_DEBUG(LOG_CORE, "cpu%{public}zu set size %{public}d.", i, result[i]);
1350             std::string path = "per_cpu/cpu" + std::to_string(i) + "/buffer_size_kb";
1351             WriteStrToFile(path, std::to_string(result[i]));
1352         }
1353     }
1354     HILOG_INFO(LOG_CORE, "CpuBufferBalanceTask: monitor thread exit.");
1355     g_serviceThreadIsStart = false;
1356 }
1357 
StartCpuBufferBalanceService()1358 void StartCpuBufferBalanceService()
1359 {
1360     if (!IsHmKernel() && !g_serviceThreadIsStart) {
1361         // open monitor thread
1362         auto it = []() {
1363             CpuBufferBalanceTask();
1364         };
1365         std::thread auxiliaryTask(it);
1366         auxiliaryTask.detach();
1367     }
1368 }
1369 
PreWriteEventsFormat(const std::vector<std::string> & eventFormats)1370 bool PreWriteEventsFormat(const std::vector<std::string>& eventFormats)
1371 {
1372     DelSavedEventsFormat();
1373     const std::string savedEventsFormatPath = TRACE_FILE_DEFAULT_DIR + TRACE_SAVED_EVENTS_FORMAT;
1374     int fd = open(savedEventsFormatPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
1375     if (fd < 0) {
1376         HILOG_ERROR(LOG_CORE, "PreWriteEventsFormat: open %{public}s failed.", savedEventsFormatPath.c_str());
1377         return false;
1378     }
1379     for (auto& format : eventFormats) {
1380         std::string srcPath = g_traceRootPath + format;
1381         if (access(srcPath.c_str(), R_OK) != -1) {
1382             WriteEventFile(srcPath, fd);
1383         }
1384     }
1385     close(fd);
1386     HILOG_INFO(LOG_CORE, "PreWriteEventsFormat end.");
1387     return true;
1388 }
1389 
HandleTraceOpen(const TraceParams & traceParams,const std::map<std::string,TraceTag> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable,std::vector<std::string> & tagFmts)1390 TraceErrorCode HandleTraceOpen(const TraceParams& traceParams,
1391                                const std::map<std::string, TraceTag>& allTags,
1392                                const std::map<std::string, std::vector<std::string>>& tagGroupTable,
1393                                std::vector<std::string>& tagFmts)
1394 {
1395     if (!SetTraceSetting(traceParams, allTags, tagGroupTable, tagFmts)) {
1396         return TraceErrorCode::FILE_ERROR;
1397     }
1398     SetTraceNodeStatus(TRACING_ON_NODE, true);
1399     PreWriteEventsFormat(tagFmts);
1400     g_currentTraceParams = traceParams;
1401     return TraceErrorCode::SUCCESS;
1402 }
1403 
HandleDefaultTraceOpen(const std::vector<std::string> & tagGroups)1404 TraceErrorCode HandleDefaultTraceOpen(const std::vector<std::string>& tagGroups)
1405 {
1406     if (g_traceJsonParser == nullptr) {
1407         g_traceJsonParser = std::make_shared<TraceJsonParser>();
1408     }
1409     if (!g_traceJsonParser->ParseTraceJson(PARSE_ALL_INFO)) {
1410         HILOG_ERROR(LOG_CORE, "WriteEventsFormat: Failed to parse trace tag total infos.");
1411         return FILE_ERROR;
1412     }
1413     auto allTags = g_traceJsonParser->GetAllTagInfos();
1414     auto tagGroupTable = g_traceJsonParser->GetTagGroups();
1415     auto tagFmts = g_traceJsonParser->GetBaseFmtPath();
1416     auto custBufSz = g_traceJsonParser->GetSnapShotBufSzKb();
1417 
1418     if (tagGroups.size() == 0 || !CheckTagGroup(tagGroups, tagGroupTable)) {
1419         HILOG_ERROR(LOG_CORE, "OpenTrace: TAG_ERROR.");
1420         return TAG_ERROR;
1421     }
1422 
1423     TraceParams defaultTraceParams;
1424     defaultTraceParams.tagGroups = tagGroups;
1425     // attention: the buffer size value in the configuration file is preferred to set.
1426     if (custBufSz > 0) {
1427         defaultTraceParams.bufferSize = std::to_string(custBufSz);
1428     } else {
1429         int traceBufSz = IsHmKernel() ? HM_DEFAULT_BUFFER_SIZE : DEFAULT_BUFFER_SIZE;
1430         defaultTraceParams.bufferSize = std::to_string(traceBufSz);
1431     }
1432     defaultTraceParams.clockType = "boot";
1433     defaultTraceParams.isOverWrite = "1";
1434     defaultTraceParams.fileSize = DEFAULT_FILE_SIZE;
1435     return HandleTraceOpen(defaultTraceParams, allTags, tagGroupTable, tagFmts);
1436 }
1437 
RemoveUnSpace(std::string str,std::string & args)1438 void RemoveUnSpace(std::string str, std::string& args)
1439 {
1440     int maxCircleTimes = 30;
1441     int curTimes = 0;
1442     const size_t symbolAndSpaceLen = 2;
1443     std::string strSpace = str + " ";
1444     while (curTimes < maxCircleTimes) {
1445         curTimes++;
1446         std::string::size_type index = args.find(strSpace);
1447         if (index != std::string::npos) {
1448             args.replace(index, symbolAndSpaceLen, str);
1449         } else {
1450             break;
1451         }
1452     }
1453 }
1454 
SetCmdTraceIntParams(const std::string & traceParamsStr,int & traceParams)1455 void SetCmdTraceIntParams(const std::string& traceParamsStr, int& traceParams)
1456 {
1457     if (!OHOS::HiviewDFX::Hitrace::StringToInt(traceParamsStr, traceParams)) {
1458         traceParams = 0;
1459         return;
1460     }
1461     if (traceParams <= 0) {
1462         HILOG_WARN(LOG_CORE, "Illegal input, traceParams initialized to null.");
1463         traceParams = 0;
1464     }
1465 }
1466 
SetDestTraceTimeAndDuration(int maxDuration,const uint64_t & utTraceEndTime)1467 void SetDestTraceTimeAndDuration(int maxDuration, const uint64_t& utTraceEndTime)
1468 {
1469     if (utTraceEndTime == 0) {
1470         time_t currentTime;
1471         time(&currentTime);
1472         g_utDestTraceEndTime = static_cast<uint64_t>(currentTime);
1473     } else {
1474         g_utDestTraceEndTime = utTraceEndTime;
1475     }
1476     if (maxDuration == 0) {
1477         maxDuration = DEFAULT_FULL_TRACE_LENGTH;
1478     }
1479     if (g_utDestTraceEndTime < static_cast<uint64_t>(maxDuration)) {
1480         g_utDestTraceStartTime = 0;
1481     } else {
1482         g_utDestTraceStartTime = g_utDestTraceEndTime - static_cast<uint64_t>(maxDuration);
1483     }
1484     HILOG_INFO(LOG_CORE, "g_utDestTraceStartTime:(%{public}" PRIu64 "), g_utDestTraceEndTime:(%{public}" PRIu64 ").",
1485         g_utDestTraceStartTime, g_utDestTraceEndTime);
1486 }
1487 
1488 /**
1489  * args: tags:tag1,tags2... tagGroups:group1,group2... clockType:boot bufferSize:1024 overwrite:1 output:filename
1490  * traceParams:  Save the above parameters
1491 */
ParseArgs(const std::string & args,TraceParams & traceParams,const std::map<std::string,TraceTag> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)1492 bool ParseArgs(const std::string& args, TraceParams& traceParams, const std::map<std::string, TraceTag>& allTags,
1493                const std::map<std::string, std::vector<std::string>>& tagGroupTable)
1494 {
1495     std::string userArgs = args;
1496     std::string str = ":";
1497     RemoveUnSpace(str, userArgs);
1498     str = ",";
1499     RemoveUnSpace(str, userArgs);
1500     std::vector<std::string> argList = Split(userArgs, ' ');
1501     for (std::string item : argList) {
1502         size_t pos = item.find(":");
1503         if (pos == std::string::npos) {
1504             HILOG_ERROR(LOG_CORE, "trace command line without colon appears: %{public}s, continue.", item.c_str());
1505             continue;
1506         }
1507         std::string itemName = item.substr(0, pos);
1508         if (itemName == "tags") {
1509             traceParams.tags = Split(item.substr(pos + 1), ',');
1510         } else if (itemName == "tagGroups") {
1511             traceParams.tagGroups = Split(item.substr(pos + 1), ',');
1512         } else if (itemName == "clockType") {
1513             traceParams.clockType = item.substr(pos + 1);
1514         } else if (itemName == "bufferSize") {
1515             traceParams.bufferSize = item.substr(pos + 1);
1516         } else if (itemName == "overwrite") {
1517             traceParams.isOverWrite = item.substr(pos + 1);
1518         } else if (itemName == "output") {
1519             traceParams.outputFile = item.substr(pos + 1);
1520         } else if (itemName == "fileSize") {
1521             std::string fileSizeStr = item.substr(pos + 1);
1522             SetCmdTraceIntParams(fileSizeStr, traceParams.fileSize);
1523         } else if (itemName == "fileLimit") {
1524             std::string fileLimitStr = item.substr(pos + 1);
1525             SetCmdTraceIntParams(fileLimitStr, traceParams.fileLimit);
1526         } else if (itemName == "appPid") {
1527             std::string pidStr = item.substr(pos + 1);
1528             SetCmdTraceIntParams(pidStr, traceParams.appPid);
1529             if (traceParams.appPid == 0) {
1530                 HILOG_ERROR(LOG_CORE, "Illegal input, appPid(%{public}s) must be number and greater than 0.",
1531                     pidStr.c_str());
1532                 return false;
1533             }
1534             OHOS::system::SetParameter(TRACE_KEY_APP_PID, pidStr);
1535         } else {
1536             HILOG_ERROR(LOG_CORE, "Extra trace command line options appear when ParseArgs: %{public}s, return false.",
1537                 itemName.c_str());
1538             return false;
1539         }
1540     }
1541     return CheckTags(traceParams.tags, allTags) && CheckTagGroup(traceParams.tagGroups, tagGroupTable);
1542 }
1543 
WriteCpuFreqTrace()1544 void WriteCpuFreqTrace()
1545 {
1546     std::string freqsfmt = "cpu frequency: ";
1547     ReadCurrentCpuFrequencies(freqsfmt);
1548     HILOG_INFO(LOG_CORE, "hitracedump write trace(%{public}s)", freqsfmt.c_str());
1549     HITRACE_METER_NAME(HITRACE_TAG_OHOS, freqsfmt);
1550 }
1551 
SetTotalFileSizeLimitAndSliceMaxDuration(const uint64_t & totalFileSize,const uint64_t & sliceMaxDuration)1552 void SetTotalFileSizeLimitAndSliceMaxDuration(const uint64_t& totalFileSize, const uint64_t& sliceMaxDuration)
1553 {
1554     if (totalFileSize == 0) {
1555         g_totalFileSizeLimit = DEFAULT_TOTAL_CACHE_FILE_SIZE * BYTE_PER_MB;
1556     } else {
1557         g_totalFileSizeLimit = totalFileSize * BYTE_PER_MB;
1558     }
1559     if (sliceMaxDuration == 0) {
1560         g_sliceMaxDuration = DEFAULT_TRACE_SLICE_DURATION;
1561     } else {
1562         g_sliceMaxDuration = sliceMaxDuration;
1563     }
1564 }
1565 
GetFileInCache(TraceRetInfo & traceRetInfo)1566 void GetFileInCache(TraceRetInfo& traceRetInfo)
1567 {
1568     g_interruptDump.store(1);
1569     HILOG_INFO(LOG_CORE, "DumpTrace: Trace is caching, get cache file.");
1570     std::lock_guard<std::mutex> lock(g_cacheTraceMutex);
1571     SearchTraceFiles(g_utDestTraceStartTime, g_utDestTraceEndTime, traceRetInfo.outputFiles);
1572     if (traceRetInfo.outputFiles.empty()) {
1573         HILOG_ERROR(LOG_CORE, "DumpTrace: Trace is caching, search file failed.");
1574         traceRetInfo.errorCode = OUT_OF_TIME;
1575     } else {
1576         for (const auto& file: traceRetInfo.outputFiles) {
1577             HILOG_INFO(LOG_CORE, "dumptrace file is %{public}s.", file.c_str());
1578         }
1579         traceRetInfo.errorCode = SUCCESS;
1580     }
1581     g_interruptDump.store(0);
1582 }
1583 } // namespace
1584 
1585 #ifdef HITRACE_UNITTEST
SetSysInitParamTags(uint64_t sysInitParamTags)1586 void SetSysInitParamTags(uint64_t sysInitParamTags)
1587 {
1588     g_sysInitParamTags = sysInitParamTags;
1589 }
1590 
SetCheckParam()1591 bool SetCheckParam()
1592 {
1593     int ret = CheckParam();
1594     return ret;
1595 }
1596 #endif
1597 
GetTraceMode()1598 uint8_t GetTraceMode()
1599 {
1600     std::lock_guard<std::mutex> lock(g_traceMutex);
1601     return g_traceMode;
1602 }
1603 
OpenTrace(const std::vector<std::string> & tagGroups)1604 TraceErrorCode OpenTrace(const std::vector<std::string>& tagGroups)
1605 {
1606     std::lock_guard<std::mutex> lock(g_traceMutex);
1607     if (g_traceMode != TraceMode::CLOSE) {
1608         HILOG_ERROR(LOG_CORE, "OpenTrace: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1609             static_cast<uint32_t>(g_traceMode));
1610         return WRONG_TRACE_MODE;
1611     }
1612     if (!IsTraceMounted(g_traceRootPath)) {
1613         HILOG_ERROR(LOG_CORE, "OpenTrace: TRACE_NOT_SUPPORTED.");
1614         return TRACE_NOT_SUPPORTED;
1615     }
1616 
1617     TraceErrorCode ret = HandleDefaultTraceOpen(tagGroups);
1618     if (ret != SUCCESS) {
1619         HILOG_ERROR(LOG_CORE, "OpenTrace: failed.");
1620         return ret;
1621     }
1622     if (!g_traceJsonParser->ParseTraceJson(TRACE_SNAPSHOT_FILE_AGE)) {
1623         HILOG_WARN(LOG_CORE, "OpenTrace: Failed to parse TRACE_SNAPSHOT_FILE_AGE.");
1624     }
1625     RefreshTraceVec(g_traceFileVec, TRACE_SNAPSHOT);
1626     RefreshTraceVec(g_cacheFileVec, TRACE_CACHE);
1627     {
1628         std::lock_guard<std::mutex> cacheLock(g_cacheTraceMutex);
1629         ClearCacheTraceFileByDuration(g_cacheFileVec);
1630     }
1631     g_sysInitParamTags = GetSysParamTags();
1632     g_traceMode = TraceMode::OPEN;
1633     HILOG_INFO(LOG_CORE, "OpenTrace: open by tag group success.");
1634     StartCpuBufferBalanceService();
1635     return ret;
1636 }
1637 
OpenTrace(const std::string & args)1638 TraceErrorCode OpenTrace(const std::string& args)
1639 {
1640     std::lock_guard<std::mutex> lock(g_traceMutex);
1641     if (g_traceMode != TraceMode::CLOSE) {
1642         HILOG_ERROR(LOG_CORE, "OpenTrace: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1643             static_cast<uint32_t>(g_traceMode));
1644         return WRONG_TRACE_MODE;
1645     }
1646 
1647     if (!IsTraceMounted(g_traceRootPath)) {
1648         HILOG_ERROR(LOG_CORE, "OpenTrace: TRACE_NOT_SUPPORTED.");
1649         return TRACE_NOT_SUPPORTED;
1650     }
1651 
1652     if (g_traceJsonParser == nullptr) {
1653         g_traceJsonParser = std::make_shared<TraceJsonParser>();
1654     }
1655     if (!g_traceJsonParser->ParseTraceJson(PARSE_TRACE_GROUP_INFO)) {
1656         HILOG_ERROR(LOG_CORE, "WriteEventsFormat: Failed to parse trace tag format and group infos.");
1657         return FILE_ERROR;
1658     }
1659     auto allTags = g_traceJsonParser->GetAllTagInfos();
1660     auto tagGroupTable = g_traceJsonParser->GetTagGroups();
1661     auto traceFormats = g_traceJsonParser->GetBaseFmtPath();
1662 
1663     if (allTags.size() == 0 || tagGroupTable.size() == 0) {
1664         HILOG_ERROR(LOG_CORE, "OpenTrace: ParseTagInfo TAG_ERROR.");
1665         return TAG_ERROR;
1666     }
1667     // parse args
1668     TraceParams traceParams;
1669     if (!ParseArgs(args, traceParams, allTags, tagGroupTable)) {
1670         HILOG_ERROR(LOG_CORE, "OpenTrace: TAG_ERROR.");
1671         return TAG_ERROR;
1672     }
1673 
1674     TraceErrorCode ret = HandleTraceOpen(traceParams, allTags, tagGroupTable, traceFormats);
1675     if (ret != SUCCESS) {
1676         HILOG_ERROR(LOG_CORE, "OpenTrace: open by args failed.");
1677         return FILE_ERROR;
1678     }
1679     g_sysInitParamTags = GetSysParamTags();
1680     g_traceMode = TraceMode::OPEN;
1681     HILOG_INFO(LOG_CORE, "OpenTrace: open by args success, args:%{public}s.", args.c_str());
1682     StartCpuBufferBalanceService();
1683     return ret;
1684 }
1685 
CacheTraceOn(uint64_t totalFileSize,uint64_t sliceMaxDuration)1686 TraceErrorCode CacheTraceOn(uint64_t totalFileSize, uint64_t sliceMaxDuration)
1687 {
1688     std::lock_guard<std::mutex> lock(g_traceMutex);
1689     if (g_traceMode != TraceMode::OPEN) {
1690         HILOG_ERROR(LOG_CORE, "CacheTraceOn: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1691             static_cast<uint32_t>(g_traceMode));
1692         return WRONG_TRACE_MODE;
1693     }
1694     if (!g_cacheEnd.load()) {
1695         HILOG_ERROR(LOG_CORE, "CacheTraceOn: cache trace is dumping now.");
1696         return WRONG_TRACE_MODE;
1697     }
1698 
1699     SetTotalFileSizeLimitAndSliceMaxDuration(totalFileSize, sliceMaxDuration);
1700     g_cacheFlag.store(true);
1701     g_cacheEnd.store(false);
1702     auto it = []() {
1703         ProcessCacheTask();
1704     };
1705     std::thread task(it);
1706     task.detach();
1707     HILOG_INFO(LOG_CORE, "Caching trace on.");
1708     g_traceMode |= TraceMode::CACHE;
1709     return SUCCESS;
1710 }
1711 
CacheTraceOff()1712 TraceErrorCode CacheTraceOff()
1713 {
1714     std::lock_guard<std::mutex> lock(g_traceMutex);
1715     if (g_traceMode != (TraceMode::OPEN | TraceMode::CACHE)) {
1716         HILOG_ERROR(LOG_CORE,
1717             "CacheTraceOff: WRONG_TRACE_MODE, current trace mode: %{public}u.", static_cast<uint32_t>(g_traceMode));
1718         return WRONG_TRACE_MODE;
1719     }
1720     g_cacheFlag.store(false);
1721     while (!g_cacheEnd.load()) {
1722         g_cacheFlag.store(false);
1723         usleep(UNIT_TIME);
1724     }
1725     HILOG_INFO(LOG_CORE, "Caching trace off.");
1726     g_traceMode &= ~TraceMode::CACHE;
1727     return SUCCESS;
1728 }
1729 
DumpTrace(int maxDuration,uint64_t utTraceEndTime)1730 TraceRetInfo DumpTrace(int maxDuration, uint64_t utTraceEndTime)
1731 {
1732     std::lock_guard<std::mutex> lock(g_traceMutex);
1733     if (!IsTraceOpen() || IsRecordOn()) {
1734         HILOG_ERROR(LOG_CORE, "DumpTrace: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1735             static_cast<uint32_t>(g_traceMode));
1736         TraceRetInfo ret;
1737         ret.errorCode = WRONG_TRACE_MODE;
1738         return ret;
1739     }
1740     HILOG_INFO(LOG_CORE, "DumpTrace start, target duration is %{public}d, target endtime is (%{public}" PRIu64 ").",
1741         maxDuration, utTraceEndTime);
1742     TraceRetInfo ret;
1743 
1744     if (!CheckServiceRunning()) {
1745         HILOG_ERROR(LOG_CORE, "DumpTrace: TRACE_IS_OCCUPIED.");
1746         ret.errorCode = TRACE_IS_OCCUPIED;
1747         return ret;
1748     }
1749     SetDestTraceTimeAndDuration(maxDuration, utTraceEndTime);
1750     if (UNEXPECTANTLY(IsCacheOn())) {
1751         GetFileInCache(ret);
1752         return ret;
1753     }
1754 
1755     ret.errorCode = SetTimeIntervalBoundary(maxDuration, utTraceEndTime);
1756     if (ret.errorCode != SUCCESS) {
1757         return ret;
1758     }
1759     g_firstPageTimestamp = UINT64_MAX;
1760     g_lastPageTimestamp = 0;
1761 
1762     uint32_t committedDuration = static_cast<uint32_t>(maxDuration == 0 ? DEFAULT_FULL_TRACE_LENGTH :
1763         std::min(maxDuration, DEFAULT_FULL_TRACE_LENGTH));
1764     ret.errorCode = DumpTraceInner(ret.outputFiles);
1765     if (g_traceEndTime <= g_firstPageTimestamp) {
1766         ret.coverRatio = 0;
1767     } else {
1768         ret.coverDuration = static_cast<int32_t>(std::min((g_traceEndTime - g_firstPageTimestamp) *
1769             S_TO_MS / S_TO_NS, committedDuration * S_TO_MS));
1770         ret.coverRatio = static_cast<int32_t>((g_traceEndTime - g_firstPageTimestamp) *
1771             MAX_RATIO_UNIT / S_TO_NS / committedDuration);
1772     }
1773     if (ret.coverRatio > MAX_RATIO_UNIT) {
1774         ret.coverRatio = MAX_RATIO_UNIT;
1775     }
1776     ret.tags.reserve(g_currentTraceParams.tagGroups.size() + g_currentTraceParams.tags.size());
1777     ret.tags.insert(ret.tags.end(), g_currentTraceParams.tagGroups.begin(), g_currentTraceParams.tagGroups.end());
1778     ret.tags.insert(ret.tags.end(), g_currentTraceParams.tags.begin(), g_currentTraceParams.tags.end());
1779     RestoreTimeIntervalBoundary();
1780     HILOG_INFO(LOG_CORE, "DumpTrace with time limit done.");
1781     return ret;
1782 }
1783 
RecordTraceOn()1784 TraceErrorCode RecordTraceOn()
1785 {
1786     std::lock_guard<std::mutex> lock(g_traceMutex);
1787     // check current trace status
1788     if (g_traceMode != TraceMode::OPEN) {
1789         HILOG_ERROR(LOG_CORE, "RecordTraceOn: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1790             static_cast<uint32_t>(g_traceMode));
1791         return WRONG_TRACE_MODE;
1792     }
1793 
1794     if (!g_recordEnd.load()) {
1795         HILOG_ERROR(LOG_CORE, "RecordTraceOn: WRONG_TRACE_MODE, record trace is dumping now.");
1796         return WRONG_TRACE_MODE;
1797     }
1798 
1799     // start task thread
1800     g_recordFlag.store(true);
1801     g_recordEnd.store(false);
1802     auto it = []() {
1803         ProcessRecordTask();
1804     };
1805     std::thread task(it);
1806     task.detach();
1807     WriteCpuFreqTrace();
1808     HILOG_INFO(LOG_CORE, "Recording trace on.");
1809     g_traceMode |= TraceMode::RECORD;
1810     return SUCCESS;
1811 }
1812 
RecordTraceOff()1813 TraceRetInfo RecordTraceOff()
1814 {
1815     std::lock_guard<std::mutex> lock(g_traceMutex);
1816     TraceRetInfo ret;
1817     // check current trace status
1818     if (!IsRecordOn()) {
1819         HILOG_ERROR(LOG_CORE, "RecordTraceOff: The current state is %{public}u, data exception.",
1820             static_cast<uint32_t>(g_traceMode));
1821         ret.errorCode = WRONG_TRACE_MODE;
1822 
1823         std::lock_guard<std::mutex> lock(g_recordingOutputMutex);
1824         ret.outputFiles = g_recordingOutput;
1825         return ret;
1826     }
1827 
1828     g_recordFlag.store(false);
1829     while (!g_recordEnd.load()) {
1830         usleep(UNIT_TIME);
1831         g_recordFlag.store(false);
1832     }
1833     ret.errorCode = SUCCESS;
1834 
1835     std::lock_guard<std::mutex> outputFileslock(g_recordingOutputMutex);
1836     ret.outputFiles = g_recordingOutput;
1837     HILOG_INFO(LOG_CORE, "Recording trace off.");
1838     g_traceMode &= ~TraceMode::RECORD;
1839     return ret;
1840 }
1841 
CloseTrace()1842 TraceErrorCode CloseTrace()
1843 {
1844     std::lock_guard<std::mutex> lock(g_traceMutex);
1845     HILOG_INFO(LOG_CORE, "CloseTrace start.");
1846     if (g_traceMode == TraceMode::CLOSE) {
1847         HILOG_INFO(LOG_CORE, "Trace has already been closed.");
1848         return SUCCESS;
1849     }
1850     if (IsRecordOn()) {
1851         g_recordFlag.store(false);
1852         while (!g_recordEnd.load()) {
1853             usleep(UNIT_TIME);
1854             g_recordFlag.store(false);
1855         }
1856     }
1857     if (IsCacheOn()) {
1858         g_cacheFlag.store(false);
1859         while (!g_cacheEnd.load()) {
1860             usleep(UNIT_TIME);
1861             g_cacheFlag.store(false);
1862         }
1863     }
1864     g_traceMode = TraceMode::CLOSE;
1865     OHOS::system::SetParameter(TRACE_KEY_APP_PID, "-1");
1866 
1867     if (g_traceJsonParser == nullptr) {
1868         g_traceJsonParser = std::make_shared<TraceJsonParser>();
1869     }
1870     if (!g_traceJsonParser->ParseTraceJson(PARSE_TRACE_ENABLE_INFO)) {
1871         HILOG_ERROR(LOG_CORE, "WriteEventsFormat: Failed to parse trace tag enable infos.");
1872         return FILE_ERROR;
1873     }
1874     auto allTags = g_traceJsonParser->GetAllTagInfos();
1875     if (allTags.size() == 0) {
1876         HILOG_ERROR(LOG_CORE, "CloseTrace: ParseTagInfo TAG_ERROR.");
1877         return TAG_ERROR;
1878     }
1879 
1880     TraceInit(allTags);
1881     TruncateFile();
1882     HILOG_INFO(LOG_CORE, "CloseTrace done.");
1883     return SUCCESS;
1884 }
1885 
GetTraceFilesTable()1886 std::vector<std::pair<std::string, int>> GetTraceFilesTable()
1887 {
1888     return g_traceFilesTable;
1889 }
1890 
SetTraceFilesTable(const std::vector<std::pair<std::string,int>> & traceFilesTable)1891 void SetTraceFilesTable(const std::vector<std::pair<std::string, int>>& traceFilesTable)
1892 {
1893     g_traceFilesTable = traceFilesTable;
1894 }
1895 } // namespace Hitrace
1896 } // namespace HiviewDFX
1897 } // namespace OHOS
1898