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 <atomic>
19 #include <cinttypes>
20 #include <csignal>
21 #include <fstream>
22 #include <map>
23 #include <memory>
24 #include <mutex>
25 #include <set>
26 #include <sys/epoll.h>
27 #include <sys/prctl.h>
28 #include <sys/sysinfo.h>
29 #include <sys/wait.h>
30 #include <thread>
31 #include <unistd.h>
32 
33 #include "common_utils.h"
34 #include "dynamic_buffer.h"
35 #include "hitrace_meter.h"
36 #include "hilog/log.h"
37 #include "hitrace_osal.h"
38 #include "parameters.h"
39 #include "securec.h"
40 #include "trace_utils.h"
41 
42 using namespace std;
43 using namespace OHOS::HiviewDFX::HitraceOsal;
44 using OHOS::HiviewDFX::HiLog;
45 
46 namespace OHOS {
47 namespace HiviewDFX {
48 namespace Hitrace {
49 
50 namespace {
51 
52 struct TraceParams {
53     std::vector<std::string> tags;
54     std::vector<std::string> tagGroups;
55     std::string bufferSize;
56     std::string clockType;
57     std::string isOverWrite;
58     std::string outputFile;
59     int fileLimit;
60     int fileSize;
61     int appPid;
62 };
63 
64 constexpr uint16_t MAGIC_NUMBER = 57161;
65 constexpr uint16_t VERSION_NUMBER = 1;
66 constexpr uint8_t FILE_RAW_TRACE = 0;
67 constexpr uint8_t HM_FILE_RAW_TRACE = 1;
68 constexpr int UNIT_TIME = 100000;
69 constexpr int ALIGNMENT_COEFFICIENT = 4;
70 
71 const int DEFAULT_BUFFER_SIZE = 12 * 1024;
72 const int DEFAULT_FILE_SIZE = 100 * 1024;
73 #ifdef DOUBLE_TRACEBUFFER_ENABLE
74 const int HM_DEFAULT_BUFFER_SIZE = 288 * 1024;
75 #else
76 const int HM_DEFAULT_BUFFER_SIZE = 144 * 1024;
77 #endif
78 const int SAVED_CMDLINES_SIZE = 3072; // 3M
79 const int KB_PER_MB = 1024;
80 const uint64_t S_TO_NS = 1000000000;
81 const int MAX_NEW_TRACE_FILE_LIMIT = 5;
82 const int JUDGE_FILE_EXIST = 10;  // Check whether the trace file exists every 10 times.
83 const int SNAPSHOT_FILE_MAX_COUNT = 20;
84 
85 const std::string DEFAULT_OUTPUT_DIR = "/data/log/hitrace/";
86 const std::string SAVED_EVENTS_FORMAT = "saved_events_format";
87 
88 struct alignas(ALIGNMENT_COEFFICIENT) TraceFileHeader {
89     uint16_t magicNumber {MAGIC_NUMBER};
90     uint8_t fileType {FILE_RAW_TRACE};
91     uint16_t versionNumber {VERSION_NUMBER};
92     uint32_t reserved {0};
93 };
94 
95 enum ContentType : uint8_t {
96     CONTENT_TYPE_DEFAULT = 0,
97     CONTENT_TYPE_EVENTS_FORMAT = 1,
98     CONTENT_TYPE_CMDLINES  = 2,
99     CONTENT_TYPE_TGIDS = 3,
100     CONTENT_TYPE_CPU_RAW = 4,
101     CONTENT_TYPE_HEADER_PAGE = 30,
102     CONTENT_TYPE_PRINTK_FORMATS = 31,
103     CONTENT_TYPE_KALLSYMS = 32
104 };
105 
106 struct alignas(ALIGNMENT_COEFFICIENT) TraceFileContentHeader {
107     uint8_t type = CONTENT_TYPE_DEFAULT;
108     uint32_t length = 0;
109 };
110 
111 struct PageHeader {
112     uint64_t timestamp = 0;
113     uint64_t size = 0;
114     uint8_t overwrite = 0;
115     uint8_t *startPos = nullptr;
116     uint8_t *endPos = nullptr;
117 };
118 
119 #ifndef PAGE_SIZE
120 constexpr size_t PAGE_SIZE = 4096;
121 #endif
122 
123 const int BUFFER_SIZE = 256 * PAGE_SIZE; // 1M
124 
125 std::atomic<bool> g_dumpFlag(false);
126 std::atomic<bool> g_dumpEnd(true);
127 std::mutex g_traceMutex;
128 
129 bool g_serviceThreadIsStart = false;
130 uint64_t g_sysInitParamTags = 0;
131 TraceMode g_traceMode = TraceMode::CLOSE;
132 std::string g_traceRootPath;
133 uint8_t g_buffer[BUFFER_SIZE] = {0};
134 std::vector<std::pair<std::string, int>> g_traceFilesTable;
135 std::vector<std::string> g_outputFilesForCmd;
136 int g_outputFileSize = 0;
137 int g_inputMaxDuration = 0;
138 uint64_t g_inputTraceEndTime = 0; // in nano seconds
139 int g_newTraceFileLimit = 0;
140 int g_writeFileLimit = 0;
141 bool g_needGenerateNewTraceFile = false;
142 uint64_t g_traceStartTime = 0;
143 uint64_t g_traceEndTime = std::numeric_limits<uint64_t>::max(); // in nano seconds
144 std::atomic<uint8_t> g_dumpStatus(TraceErrorCode::UNSET);
145 
146 TraceParams g_currentTraceParams = {};
147 
GetFilePath(const std::string &fileName)148 std::string GetFilePath(const std::string &fileName)
149 {
150     return g_traceRootPath + fileName;
151 }
152 
Split(const std::string &str, char delimiter)153 std::vector<std::string> Split(const std::string &str, char delimiter)
154 {
155     std::vector<std::string> res;
156     size_t startPos = 0;
157     for (size_t i = 0; i < str.size(); i++) {
158         if (str[i] == delimiter) {
159             res.push_back(str.substr(startPos, i - startPos));
160             startPos = i + 1;
161         }
162     }
163     if (startPos < str.size()) {
164         res.push_back(str.substr(startPos));
165     }
166     return res;
167 }
168 
IsTraceMounted()169 bool IsTraceMounted()
170 {
171     const std::string debugfsPath = "/sys/kernel/debug/tracing/";
172     const std::string tracefsPath = "/sys/kernel/tracing/";
173     if (access((debugfsPath + "trace_marker").c_str(), F_OK) != -1) {
174         g_traceRootPath = debugfsPath;
175         return true;
176     }
177     if (access((tracefsPath + "trace_marker").c_str(), F_OK) != -1) {
178         g_traceRootPath = tracefsPath;
179         return true;
180     }
181     HILOG_ERROR(LOG_CORE, "IsTraceMounted: Did not find trace folder");
182     return false;
183 }
184 
185 // Arch is 64bit when reserved = 0; Arch is 32bit when reserved = 1.
GetArchWordSize(TraceFileHeader& header)186 void GetArchWordSize(TraceFileHeader& header)
187 {
188     if (sizeof(void*) == sizeof(uint64_t)) {
189         header.reserved |= 0;
190     } else if (sizeof(void*) == sizeof(uint32_t)) {
191         header.reserved |= 1;
192     }
193     HILOG_INFO(LOG_CORE, "reserved with arch word info is %{public}d.", header.reserved);
194 }
195 
GetCpuNums(TraceFileHeader& header)196 void GetCpuNums(TraceFileHeader& header)
197 {
198     const int maxCpuNums = 24;
199     int cpuNums = GetCpuProcessors();
200     if (cpuNums > maxCpuNums || cpuNums <= 0) {
201         HILOG_ERROR(LOG_CORE, "error: cpu_number is %{public}d.", cpuNums);
202         return;
203     }
204     header.reserved |= (static_cast<uint64_t>(cpuNums) << 1);
205     HILOG_INFO(LOG_CORE, "reserved with cpu number info is %{public}d.", header.reserved);
206 }
207 
CheckTags(const std::vector<std::string> &tags, const std::map<std::string, TagCategory> &allTags)208 bool CheckTags(const std::vector<std::string> &tags, const std::map<std::string, TagCategory> &allTags)
209 {
210     for (const auto &tag : tags) {
211         if (allTags.find(tag) == allTags.end()) {
212             HILOG_ERROR(LOG_CORE, "CheckTags: %{public}s is not provided.", tag.c_str());
213             return false;
214         }
215     }
216     return true;
217 }
218 
CheckTagGroup(const std::vector<std::string> &tagGroups, const std::map<std::string, std::vector<std::string>> &tagGroupTable)219 bool CheckTagGroup(const std::vector<std::string> &tagGroups,
220                    const std::map<std::string, std::vector<std::string>> &tagGroupTable)
221 {
222     for (auto groupName : tagGroups) {
223         if (tagGroupTable.find(groupName) == tagGroupTable.end()) {
224             HILOG_ERROR(LOG_CORE, "CheckTagGroup: %{public}s is not provided.", groupName.c_str());
225             return false;
226         }
227     }
228     return true;
229 }
230 
WriteStrToFileInner(const std::string& filename, const std::string& str)231 bool WriteStrToFileInner(const std::string& filename, const std::string& str)
232 {
233     std::ofstream out;
234     out.open(filename, std::ios::out);
235     if (out.fail()) {
236         HILOG_ERROR(LOG_CORE, "WriteStrToFile: %{public}s open failed.", filename.c_str());
237         return false;
238     }
239     out << str;
240     if (out.bad()) {
241         HILOG_ERROR(LOG_CORE, "WriteStrToFile: %{public}s write failed.", filename.c_str());
242         out.close();
243         return false;
244     }
245     out.flush();
246     out.close();
247     return true;
248 }
249 
WriteStrToFile(const std::string& filename, const std::string& str)250 bool WriteStrToFile(const std::string& filename, const std::string& str)
251 {
252     if (access((g_traceRootPath + filename).c_str(), W_OK) < 0) {
253         HILOG_ERROR(LOG_CORE, "WriteStrToFile: Failed to access %{public}s, errno(%{public}d).",
254             (g_traceRootPath + filename).c_str(), errno);
255         return false;
256     }
257     return WriteStrToFileInner(g_traceRootPath + filename, str);
258 }
259 
SetTraceNodeStatus(const std::string &path, bool enabled)260 void SetTraceNodeStatus(const std::string &path, bool enabled)
261 {
262     WriteStrToFile(path, enabled ? "1" : "0");
263 }
264 
TruncateFile()265 void TruncateFile()
266 {
267     int fd = creat((g_traceRootPath + "trace").c_str(), 0);
268     if (fd == -1) {
269         HILOG_ERROR(LOG_CORE, "TruncateFile: clear old trace failed.");
270         return;
271     }
272     close(fd);
273     return;
274 }
275 
SetProperty(const std::string& property, const std::string& value)276 bool SetProperty(const std::string& property, const std::string& value)
277 {
278     bool result = OHOS::system::SetParameter(property, value);
279     if (!result) {
280         HILOG_ERROR(LOG_CORE, "SetProperty: set %{public}s failed.", value.c_str());
281     } else {
282         HILOG_INFO(LOG_CORE, "SetProperty: set %{public}s success.", value.c_str());
283     }
284     return result;
285 }
286 
287 // close all trace node
TraceInit(const std::map<std::string, TagCategory> &allTags)288 void TraceInit(const std::map<std::string, TagCategory> &allTags)
289 {
290     // close all ftrace events
291     for (auto it = allTags.begin(); it != allTags.end(); it++) {
292         if (it->second.type != 1) {
293             continue;
294         }
295         for (size_t i = 0; i < it->second.sysFiles.size(); i++) {
296             SetTraceNodeStatus(it->second.sysFiles[i], false);
297         }
298     }
299     // close all user tags
300     SetProperty("debug.hitrace.tags.enableflags", std::to_string(0));
301 
302     // set buffer_size_kb 1
303     WriteStrToFile("buffer_size_kb", "1");
304 
305     // close tracing_on
306     SetTraceNodeStatus("tracing_on", false);
307 }
308 
309 // Open specific trace node
SetAllTags(const TraceParams &traceParams, const std::map<std::string, TagCategory> &allTags, const std::map<std::string, std::vector<std::string>> &tagGroupTable)310 void SetAllTags(const TraceParams &traceParams, const std::map<std::string, TagCategory> &allTags,
311                 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
312 {
313     std::set<std::string> readyEnableTagList;
314     for (std::string tagName : traceParams.tags) {
315         readyEnableTagList.insert(tagName);
316     }
317 
318     // if set tagGroup, need to append default group
319     if (traceParams.tagGroups.size() > 0) {
320         auto iter = tagGroupTable.find("default");
321         if (iter == tagGroupTable.end()) {
322             HILOG_ERROR(LOG_CORE, "SetAllTags: default group is wrong.");
323         } else {
324             for (auto defaultTag : iter->second) {
325                 readyEnableTagList.insert(defaultTag);
326             }
327         }
328     }
329 
330     for (std::string groupName : traceParams.tagGroups) {
331         auto iter = tagGroupTable.find(groupName);
332         if (iter == tagGroupTable.end()) {
333             continue;
334         }
335         for (std::string tag : iter->second) {
336             readyEnableTagList.insert(tag);
337         }
338     }
339 
340     uint64_t enabledUserTags = 0;
341     for (std::string tagName : readyEnableTagList) {
342         auto iter = allTags.find(tagName);
343         if (iter == allTags.end()) {
344             HILOG_ERROR(LOG_CORE, "tag<%{public}s> is invalid.", tagName.c_str());
345             continue;
346         }
347 
348         if (iter->second.type == 0) {
349             enabledUserTags |= iter->second.tag;
350         }
351 
352         if (iter->second.type == 1) {
353             for (const auto& path : iter->second.sysFiles) {
354                 SetTraceNodeStatus(path, true);
355             }
356         }
357     }
358     SetProperty("debug.hitrace.tags.enableflags", std::to_string(enabledUserTags));
359 }
360 
ReadFileInner(const std::string& filename)361 std::string ReadFileInner(const std::string& filename)
362 {
363     std::string resolvedPath = CanonicalizeSpecPath(filename.c_str());
364     std::ifstream fileIn(resolvedPath.c_str());
365     if (!fileIn.is_open()) {
366         HILOG_ERROR(LOG_CORE, "ReadFile: %{public}s open failed.", filename.c_str());
367         return "";
368     }
369 
370     std::string str((std::istreambuf_iterator<char>(fileIn)), std::istreambuf_iterator<char>());
371     fileIn.close();
372     return str;
373 }
374 
ReadFile(const std::string& filename)375 std::string ReadFile(const std::string& filename)
376 {
377     std::string filePath = GetFilePath(filename);
378     return ReadFileInner(filePath);
379 }
380 
SetClock(const std::string& clockType)381 void SetClock(const std::string& clockType)
382 {
383     const std::string traceClockPath = "trace_clock";
384     if (clockType.size() == 0) {
385         WriteStrToFile(traceClockPath, "boot"); //set default: boot
386         return;
387     }
388     std::string allClocks = ReadFile(traceClockPath);
389     if (allClocks.find(clockType) == std::string::npos) {
390         HILOG_ERROR(LOG_CORE, "SetClock: %{public}s is non-existent, set to boot", clockType.c_str());
391         WriteStrToFile(traceClockPath, "boot"); // set default: boot
392         return;
393     }
394 
395     allClocks.erase(allClocks.find_last_not_of(" \n") + 1);
396     allClocks.push_back(' ');
397 
398     std::set<std::string> allClockTypes;
399     size_t curPos = 0;
400     for (size_t i = 0; i < allClocks.size(); i++) {
401         if (allClocks[i] == ' ') {
402             allClockTypes.insert(allClocks.substr(curPos, i - curPos));
403             curPos = i + 1;
404         }
405     }
406 
407     std::string currentClockType;
408     for (auto i : allClockTypes) {
409         if (clockType.compare(i) == 0) {
410             HILOG_INFO(LOG_CORE, "SetClock: set clock %{public}s success.", clockType.c_str());
411             WriteStrToFile(traceClockPath, clockType);
412             return;
413         }
414         if (i[0] == '[') {
415             currentClockType = i;
416         }
417     }
418 
419     const int marks = 2;
420     if (clockType.compare(currentClockType.substr(1, currentClockType.size() - marks)) == 0) {
421         HILOG_INFO(LOG_CORE, "SetClock: set clock %{public}s success.", clockType.c_str());
422         return;
423     }
424 
425     HILOG_INFO(LOG_CORE, "SetClock: unknown %{public}s, change to default clock_type: boot.", clockType.c_str());
426     WriteStrToFile(traceClockPath, "boot"); // set default: boot
427     return;
428 }
429 
SetTraceSetting(const TraceParams &traceParams, const std::map<std::string, TagCategory> &allTags, const std::map<std::string, std::vector<std::string>> &tagGroupTable)430 bool SetTraceSetting(const TraceParams &traceParams, const std::map<std::string, TagCategory> &allTags,
431                      const std::map<std::string, std::vector<std::string>> &tagGroupTable)
432 {
433     TraceInit(allTags);
434 
435     TruncateFile();
436 
437     SetAllTags(traceParams, allTags, tagGroupTable);
438 
439     WriteStrToFile("current_tracer", "nop");
440     WriteStrToFile("buffer_size_kb", traceParams.bufferSize);
441 
442     SetClock(traceParams.clockType);
443 
444     if (traceParams.isOverWrite == "1") {
445         WriteStrToFile("options/overwrite", "1");
446     } else {
447         WriteStrToFile("options/overwrite", "0");
448     }
449 
450     WriteStrToFile("saved_cmdlines_size", std::to_string(SAVED_CMDLINES_SIZE));
451     WriteStrToFile("options/record-tgid", "1");
452     WriteStrToFile("options/record-cmd", "1");
453     return true;
454 }
455 
CheckPage(uint8_t contentType, uint8_t *page)456 bool CheckPage(uint8_t contentType, uint8_t *page)
457 {
458     const int pageThreshold = PAGE_SIZE / 2;
459 
460     // Check raw_trace page size.
461     if (contentType >= CONTENT_TYPE_CPU_RAW && !IsHmKernel()) {
462         PageHeader *pageHeader = reinterpret_cast<PageHeader*>(&page);
463         if (pageHeader->size < static_cast<uint64_t>(pageThreshold)) {
464             return false;
465         }
466     }
467 
468     return true;
469 }
470 
CheckFileExist(const std::string &outputFile)471 bool CheckFileExist(const std::string &outputFile)
472 {
473     g_writeFileLimit++;
474     if (g_writeFileLimit > JUDGE_FILE_EXIST) {
475         g_writeFileLimit = 0;
476         if (access(outputFile.c_str(), F_OK) != 0) {
477             g_needGenerateNewTraceFile = true;
478             HILOG_INFO(LOG_CORE, "CheckFileExist access file:%{public}s failed, errno: %{public}d.",
479                 outputFile.c_str(), errno);
480             return false;
481         }
482     }
483     return true;
484 }
485 
SetTimeIntervalBoundary()486 void SetTimeIntervalBoundary()
487 {
488     if (g_inputMaxDuration > 0) {
489         if (g_inputTraceEndTime) {
490             g_traceStartTime = g_inputTraceEndTime - static_cast<uint64_t>(g_inputMaxDuration) * S_TO_NS;
491             g_traceEndTime = g_inputTraceEndTime;
492         } else {
493             struct timespec bts = {0, 0};
494             clock_gettime(CLOCK_BOOTTIME, &bts);
495             g_traceStartTime = static_cast<uint64_t>(bts.tv_sec * S_TO_NS + bts.tv_nsec) -
496                 static_cast<uint64_t>(g_inputMaxDuration) * S_TO_NS;
497             g_traceEndTime = std::numeric_limits<uint64_t>::max();
498         }
499     } else {
500         g_traceStartTime = 0;
501         g_traceEndTime = g_inputTraceEndTime > 0 ? g_inputTraceEndTime : std::numeric_limits<uint64_t>::max();
502     }
503     return;
504 }
505 
RestoreTimeIntervalBoundary()506 void RestoreTimeIntervalBoundary()
507 {
508     g_traceStartTime = 0;
509     g_traceEndTime = std::numeric_limits<uint64_t>::max();
510 }
511 
GetFileSizeThresholdAndTraceTime(bool &isCpuRaw, uint8_t contentType, uint64_t &traceStartTime, uint64_t &traceEndTime, int &fileSizeThreshold)512 void GetFileSizeThresholdAndTraceTime(bool &isCpuRaw, uint8_t contentType, uint64_t &traceStartTime,
513                                       uint64_t &traceEndTime, int &fileSizeThreshold)
514 {
515     isCpuRaw = contentType >= CONTENT_TYPE_CPU_RAW && contentType < CONTENT_TYPE_HEADER_PAGE;
516     if (isCpuRaw) {
517         traceStartTime = g_traceStartTime;
518         traceEndTime = g_traceEndTime;
519     }
520     if (g_currentTraceParams.fileSize != 0) {
521         fileSizeThreshold = g_currentTraceParams.fileSize * KB_PER_MB;
522     }
523 }
524 
525 bool IsWriteFileOverflow(const bool isCpuRaw, const int &outputFileSize, const ssize_t &writeLen,
526                          const int &fileSizeThreshold)
527 {
528     // attention: we only check file size threshold in CMD_MODE
529     if (!isCpuRaw || g_traceMode != TraceMode::CMD_MODE) {
530         return false;
531     }
532     if (outputFileSize + writeLen + static_cast<int>(sizeof(TraceFileContentHeader)) >= fileSizeThreshold) {
533         HILOG_ERROR(LOG_CORE, "Failed to write, current round write file size exceeds the file size limit.");
534         return true;
535     }
536     if (writeLen > INT_MAX - BUFFER_SIZE) {
537         HILOG_ERROR(LOG_CORE, "Failed to write, write file length is nearly overflow.");
538         return true;
539     }
540     return false;
541 }
542 
WriteFile(uint8_t contentType, const std::string &src, int outFd, const std::string &outputFile)543 bool WriteFile(uint8_t contentType, const std::string &src, int outFd, const std::string &outputFile)
544 {
545     std::string srcPath = CanonicalizeSpecPath(src.c_str());
546     int srcFd = open(srcPath.c_str(), O_RDONLY | O_NONBLOCK);
547     if (srcFd < 0) {
548         HILOG_ERROR(LOG_CORE, "WriteFile: open %{public}s failed.", src.c_str());
549         return false;
550     }
551     if (!CheckFileExist(outputFile)) {
552         HILOG_ERROR(LOG_CORE, "need generate new trace file, old file:%{public}s.", outputFile.c_str());
553         return false;
554     }
555     struct TraceFileContentHeader contentHeader;
556     contentHeader.type = contentType;
557     write(outFd, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
558     ssize_t writeLen = 0;
559     int count = 0;
560     const int maxCount = 2;
561 
562     uint64_t traceStartTime = 0;
563     uint64_t traceEndTime = std::numeric_limits<uint64_t>::max();
564     int fileSizeThreshold = DEFAULT_FILE_SIZE * KB_PER_MB;
565     bool isCpuRaw = false;
566     GetFileSizeThresholdAndTraceTime(isCpuRaw, contentType, traceStartTime, traceEndTime, fileSizeThreshold);
567     while (true) {
568         int bytes = 0;
569         bool endFlag = false;
570         /* Write 1M at a time */
571         while (bytes < BUFFER_SIZE) {
572             ssize_t readBytes = TEMP_FAILURE_RETRY(read(srcFd, g_buffer + bytes, PAGE_SIZE));
573             if (readBytes == 0) {
574                 endFlag = true;
575                 HILOG_DEBUG(LOG_CORE, "WriteFile: read %{public}s end.", src.c_str());
576                 break;
577             } else if (readBytes < 0) {
578                 endFlag = true;
579                 HILOG_DEBUG(LOG_CORE, "WriteFile: read %{public}s, data size: %{public}zd failed, errno: %{public}d.",
580                     src.c_str(), readBytes, errno);
581                 break;
582             }
583 
584             uint64_t pageTraceTime = 0;
585             if (memcpy_s(&pageTraceTime, sizeof(uint64_t), g_buffer + bytes, sizeof(uint64_t)) != EOK) {
586                 HILOG_ERROR(LOG_CORE, "Failed to memcpy g_buffer to pageTraceTime.");
587                 break;
588             }
589             if (traceEndTime < pageTraceTime) {
590                 endFlag = true;
591                 readBytes = 0;
592                 HILOG_INFO(LOG_CORE,
593                     "Current pageTraceTime:(%{public}" PRId64 ") is larger than traceEndTime:(%{public}" PRId64 ")",
594                     pageTraceTime, traceEndTime);
595                 break;
596             }
597 
598             if (pageTraceTime < traceStartTime) {
599                 continue;
600             }
601 
602             if (CheckPage(contentType, g_buffer + bytes) == false) {
603                 count++;
604             }
605             bytes += readBytes;
606             if (count >= maxCount) {
607                 endFlag = true;
608                 break;
609             }
610         }
611 
612         ssize_t writeRet = TEMP_FAILURE_RETRY(write(outFd, g_buffer, bytes));
613         if (writeRet < 0) {
614             HILOG_WARN(LOG_CORE, "WriteFile Fail, errno: %{public}d.", errno);
615         } else {
616             if (writeRet != static_cast<ssize_t>(bytes)) {
617                 HILOG_WARN(LOG_CORE, "Failed to write full info, writeLen: %{public}zd, FullLen: %{public}d.",
618                     writeRet, bytes);
619             }
620             writeLen += writeRet;
621         }
622 
623         if (IsWriteFileOverflow(isCpuRaw, g_outputFileSize, writeLen, fileSizeThreshold)) {
624             break;
625         }
626 
627         if (endFlag == true) {
628             break;
629         }
630     }
631     contentHeader.length = static_cast<uint32_t>(writeLen);
632     uint32_t offset = contentHeader.length + sizeof(contentHeader);
633     off_t pos = lseek(outFd, 0, SEEK_CUR);
634     lseek(outFd, pos - offset, SEEK_SET);
635     write(outFd, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
636     lseek(outFd, pos, SEEK_SET);
637     close(srcFd);
638     if (isCpuRaw) {
639         if (writeLen > 0) {
640             g_dumpStatus = TraceErrorCode::SUCCESS;
641         } else if (g_dumpStatus == TraceErrorCode::UNSET) {
642             g_dumpStatus = TraceErrorCode::OUT_OF_TIME;
643         }
644     }
645     g_outputFileSize += static_cast<int>(offset);
646     g_needGenerateNewTraceFile = false;
647     HILOG_INFO(LOG_CORE, "WriteFile end, path: %{public}s, byte: %{public}zd. g_writeFileLimit: %{public}d",
648         src.c_str(), writeLen, g_writeFileLimit);
649     return true;
650 }
651 
WriteEventFile(std::string &srcPath, int outFd)652 void WriteEventFile(std::string &srcPath, int outFd)
653 {
654     uint8_t buffer[PAGE_SIZE] = {0};
655     std::string srcSpecPath = CanonicalizeSpecPath(srcPath.c_str());
656     int srcFd = open(srcSpecPath.c_str(), O_RDONLY);
657     if (srcFd < 0) {
658         HILOG_ERROR(LOG_CORE, "WriteEventFile: open %{public}s failed.", srcPath.c_str());
659         return;
660     }
661     int64_t readLen = 0;
662     do {
663         int64_t len = read(srcFd, buffer, PAGE_SIZE);
664         if (len <= 0) {
665             break;
666         }
667         write(outFd, buffer, len);
668         readLen += len;
669     } while (true);
670     close(srcFd);
671     HILOG_INFO(LOG_CORE, "WriteEventFile end, path: %{public}s, data size: (%{public}" PRId64 ").",
672         srcPath.c_str(), static_cast<uint64_t>(readLen));
673 }
674 
WriteEventsFormat(int outFd, const std::string &outputFile)675 bool WriteEventsFormat(int outFd, const std::string &outputFile)
676 {
677     const std::string savedEventsFormatPath = DEFAULT_OUTPUT_DIR + SAVED_EVENTS_FORMAT;
678     if (access(savedEventsFormatPath.c_str(), F_OK) != -1) {
679         return WriteFile(CONTENT_TYPE_EVENTS_FORMAT, savedEventsFormatPath, outFd, outputFile);
680     }
681     std::string filePath = CanonicalizeSpecPath(savedEventsFormatPath.c_str());
682     int fd = open(filePath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
683     if (fd < 0) {
684         HILOG_ERROR(LOG_CORE, "WriteEventsFormat: open %{public}s failed.", savedEventsFormatPath.c_str());
685         return false;
686     }
687     const std::vector<std::string> priorityTracingCategory = {
688         "events/sched/sched_wakeup/format",
689         "events/sched/sched_switch/format",
690         "events/sched/sched_blocked_reason/format",
691         "events/power/cpu_frequency/format",
692         "events/power/clock_set_rate/format",
693         "events/power/cpu_frequency_limits/format",
694         "events/f2fs/f2fs_sync_file_enter/format",
695         "events/f2fs/f2fs_sync_file_exit/format",
696         "events/f2fs/f2fs_readpage/format",
697         "events/f2fs/f2fs_readpages/format",
698         "events/f2fs/f2fs_sync_fs/format",
699         "events/hmdfs/hmdfs_syncfs_enter/format",
700         "events/hmdfs/hmdfs_syncfs_exit/format",
701         "events/erofs/erofs_readpage/format",
702         "events/erofs/erofs_readpages/format",
703         "events/ext4/ext4_da_write_begin/format",
704         "events/ext4/ext4_da_write_end/format",
705         "events/ext4/ext4_sync_file_enter/format",
706         "events/ext4/ext4_sync_file_exit/format",
707         "events/block/block_bio_remap/format",
708         "events/block/block_rq_issue/format",
709         "events/block/block_rq_complete/format",
710         "events/block/block_rq_insert/format",
711         "events/dma_fence/dma_fence_emit/format",
712         "events/dma_fence/dma_fence_destroy/format",
713         "events/dma_fence/dma_fence_enable_signal/format",
714         "events/dma_fence/dma_fence_signaled/format",
715         "events/dma_fence/dma_fence_wait_end/format",
716         "events/dma_fence/dma_fence_wait_start/format",
717         "events/dma_fence/dma_fence_init/format",
718         "events/binder/binder_transaction/format",
719         "events/binder/binder_transaction_received/format",
720         "events/mmc/mmc_request_start/format",
721         "events/mmc/mmc_request_done/format",
722         "events/memory_bus/format",
723         "events/cpufreq_interactive/format",
724         "events/filemap/file_check_and_advance_wb_err/format",
725         "events/filemap/filemap_set_wb_err/format",
726         "events/filemap/mm_filemap_add_to_page_cache/format",
727         "events/filemap/mm_filemap_delete_from_page_cache/format",
728         "events/workqueue/workqueue_execute_end/format",
729         "events/workqueue/workqueue_execute_start/format",
730         "events/thermal_power_allocator/thermal_power_allocator/format",
731         "events/thermal_power_allocator/thermal_power_allocator_pid/format",
732         "events/ftrace/print/format",
733         "events/tracing_mark_write/tracing_mark_write/format",
734         "events/power/cpu_idle/format",
735         "events/power_kernel/cpu_idle/format",
736         "events/xacct/tracing_mark_write/format",
737         "events/ufs/ufshcd_command/format",
738         "events/irq/irq_handler_entry/format"
739     };
740     for (size_t i = 0; i < priorityTracingCategory.size(); i++) {
741         std::string srcPath = g_traceRootPath + priorityTracingCategory[i];
742         if (access(srcPath.c_str(), R_OK) != -1) {
743             WriteEventFile(srcPath, fd);
744         }
745     }
746     close(fd);
747     HILOG_INFO(LOG_CORE, "WriteEventsFormat end. path: %{public}s.", filePath.c_str());
748     return WriteFile(CONTENT_TYPE_EVENTS_FORMAT, filePath, outFd, outputFile);
749 }
750 
WriteHeaderPage(int outFd, const std::string &outputFile)751 bool WriteHeaderPage(int outFd, const std::string &outputFile)
752 {
753     if (IsHmKernel()) {
754         return true;
755     }
756     std::string headerPagePath = GetFilePath("events/header_page");
757     return WriteFile(CONTENT_TYPE_HEADER_PAGE, headerPagePath, outFd, outputFile);
758 }
759 
WritePrintkFormats(int outFd, const std::string &outputFile)760 bool WritePrintkFormats(int outFd, const std::string &outputFile)
761 {
762     if (IsHmKernel()) {
763         return true;
764     }
765     std::string printkFormatPath = GetFilePath("printk_formats");
766     return WriteFile(CONTENT_TYPE_PRINTK_FORMATS, printkFormatPath, outFd, outputFile);
767 }
768 
WriteKallsyms(int outFd)769 bool WriteKallsyms(int outFd)
770 {
771     /* not implement in hmkernel */
772     if (IsHmKernel()) {
773         return true;
774     }
775     /* not implement in linux */
776     return true;
777 }
778 
HmWriteCpuRawInner(int outFd, const std::string &outputFile)779 bool HmWriteCpuRawInner(int outFd, const std::string &outputFile)
780 {
781     uint8_t type = CONTENT_TYPE_CPU_RAW;
782     std::string src = g_traceRootPath + "/trace_pipe_raw";
783 
784     if (!WriteFile(type, src, outFd, outputFile)) {
785         return false;
786     }
787 
788     if (g_dumpStatus) {
789         HILOG_ERROR(LOG_CORE, "HmWriteCpuRawInner failed, errno: %{public}d.", static_cast<int>(g_dumpStatus.load()));
790         return false;
791     }
792 
793     return true;
794 }
795 
WriteCpuRawInner(int outFd, const std::string &outputFile)796 bool WriteCpuRawInner(int outFd, const std::string &outputFile)
797 {
798     int cpuNums = GetCpuProcessors();
799     uint8_t type = CONTENT_TYPE_CPU_RAW;
800     for (int i = 0; i < cpuNums; i++) {
801         std::string src = g_traceRootPath + "per_cpu/cpu" + std::to_string(i) + "/trace_pipe_raw";
802         if (!WriteFile(static_cast<uint8_t>(type + i), src, outFd, outputFile)) {
803             return false;
804         }
805     }
806     if (g_dumpStatus) {
807         HILOG_ERROR(LOG_CORE, "WriteCpuRawInner failed, errno: %{public}d.", static_cast<int>(g_dumpStatus.load()));
808         return false;
809     }
810     return true;
811 }
812 
WriteCpuRaw(int outFd, const std::string &outputFile)813 bool WriteCpuRaw(int outFd, const std::string &outputFile)
814 {
815     if (!IsHmKernel()) {
816         return WriteCpuRawInner(outFd, outputFile);
817     } else {
818         return HmWriteCpuRawInner(outFd, outputFile);
819     }
820 }
821 
WriteCmdlines(int outFd, const std::string &outputFile)822 bool WriteCmdlines(int outFd, const std::string &outputFile)
823 {
824     std::string cmdlinesPath = GetFilePath("saved_cmdlines");
825     return WriteFile(CONTENT_TYPE_CMDLINES, cmdlinesPath, outFd, outputFile);
826 }
827 
WriteTgids(int outFd, const std::string &outputFile)828 bool WriteTgids(int outFd, const std::string &outputFile)
829 {
830     std::string tgidsPath = GetFilePath("saved_tgids");
831     return WriteFile(CONTENT_TYPE_TGIDS, tgidsPath, outFd, outputFile);
832 }
833 
GenerateNewFile(int &outFd, std::string &outPath)834 bool GenerateNewFile(int &outFd, std::string &outPath)
835 {
836     if (access(outPath.c_str(), F_OK) == 0) {
837         return true;
838     }
839     std::string outputFileName = GenerateTraceFileName(false);
840     outPath = CanonicalizeSpecPath(outputFileName.c_str());
841     outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
842     if (outFd < 0) {
843         g_newTraceFileLimit++;
844         HILOG_ERROR(LOG_CORE, "open %{public}s failed, errno: %{public}d.", outPath.c_str(), errno);
845     }
846     if (g_newTraceFileLimit > MAX_NEW_TRACE_FILE_LIMIT) {
847         HILOG_ERROR(LOG_CORE, "create new trace file %{public}s limited.", outPath.c_str());
848         return false;
849     }
850     g_needGenerateNewTraceFile = true;
851     return true;
852 }
853 
DumpTraceLoop(const std::string &outputFileName, bool isLimited)854 bool DumpTraceLoop(const std::string &outputFileName, bool isLimited)
855 {
856     const int sleepTime = 1;
857     int fileSizeThreshold = DEFAULT_FILE_SIZE * KB_PER_MB;
858     if (g_currentTraceParams.fileSize != 0) {
859         fileSizeThreshold = g_currentTraceParams.fileSize * KB_PER_MB;
860     }
861     g_outputFileSize = 0;
862     std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
863     int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
864     if (outFd < 0) {
865         HILOG_ERROR(LOG_CORE, "open %{public}s failed, errno: %{public}d.", outPath.c_str(), errno);
866         return false;
867     }
868     MarkClockSync(g_traceRootPath);
869     struct TraceFileHeader header;
870     GetArchWordSize(header);
871     GetCpuNums(header);
872     if (IsHmKernel()) {
873         header.fileType = HM_FILE_RAW_TRACE;
874     }
875     do {
876         g_needGenerateNewTraceFile = false;
877         write(outFd, reinterpret_cast<char *>(&header), sizeof(header));
878         WriteEventsFormat(outFd, outPath);
879         while (g_dumpFlag) {
880             if (isLimited && g_outputFileSize > fileSizeThreshold) {
881                 break;
882             }
883             sleep(sleepTime);
884             if (!WriteCpuRaw(outFd, outPath)) {
885                 break;
886             }
887         }
888         WriteCmdlines(outFd, outPath);
889         WriteTgids(outFd, outPath);
890         WriteHeaderPage(outFd, outPath);
891         WritePrintkFormats(outFd, outPath);
892         WriteKallsyms(outFd);
893         if (!GenerateNewFile(outFd, outPath)) {
894             HILOG_INFO(LOG_CORE, "DumpTraceLoop access file:%{public}s failed, errno: %{public}d.",
895                 outPath.c_str(), errno);
896             return false;
897         }
898     } while (g_needGenerateNewTraceFile);
899     close(outFd);
900     return true;
901 }
902 
903 /**
904  * read trace data loop
905  * g_dumpFlag: true = open,false = close
906  * g_dumpEnd: true = end,false = not end
907  * if user has own output file, Output all data to the file specified by the user;
908  * if not, Then place all the result files in /data/log/hitrace/ and package them once in 96M.
909 */
ProcessDumpTask()910 void ProcessDumpTask()
911 {
912     g_dumpFlag = true;
913     g_dumpEnd = false;
914     g_outputFilesForCmd = {};
915     const std::string threadName = "TraceDumpTask";
916     prctl(PR_SET_NAME, threadName.c_str());
917     HILOG_INFO(LOG_CORE, "ProcessDumpTask: trace dump thread start.");
918 
919     // clear old record file before record tracing start.
920     DelSavedEventsFormat();
921     DelOldRecordTraceFile(g_currentTraceParams.fileLimit);
922 
923     if (g_currentTraceParams.fileSize == 0) {
924         std::string outputFileName = g_currentTraceParams.outputFile.empty() ?
925                                      GenerateTraceFileName(false) : g_currentTraceParams.outputFile;
926         if (DumpTraceLoop(outputFileName, false)) {
927             g_outputFilesForCmd.push_back(outputFileName);
928         }
929         g_dumpEnd = true;
930         return;
931     }
932 
933     while (g_dumpFlag) {
934         if (!IsRootVersion()) {
935             ClearOldTraceFile(g_outputFilesForCmd, g_currentTraceParams.fileLimit);
936         }
937         // Generate file name
938         std::string outputFileName = GenerateTraceFileName(false);
939         if (DumpTraceLoop(outputFileName, true)) {
940             g_outputFilesForCmd.push_back(outputFileName);
941         } else {
942             break;
943         }
944     }
945     HILOG_INFO(LOG_CORE, "ProcessDumpTask: trace dump thread exit.");
946     g_dumpEnd = true;
947 }
948 
SearchFromTable(std::vector<std::string> &outputFiles, int nowSec)949 void SearchFromTable(std::vector<std::string> &outputFiles, int nowSec)
950 {
951     const int maxInterval = 30;
952     const int agingTime = 30 * 60;
953 
954     for (auto iter = g_traceFilesTable.begin(); iter != g_traceFilesTable.end();) {
955         if (nowSec - iter->second >= agingTime) {
956             // delete outdated trace file
957             if (access(iter->first.c_str(), F_OK) == 0) {
958                 remove(iter->first.c_str());
959                 HILOG_INFO(LOG_CORE, "delete old %{public}s file success.", iter->first.c_str());
960             }
961             iter = g_traceFilesTable.erase(iter);
962             continue;
963         }
964 
965         if (nowSec - iter->second <= maxInterval) {
966             outputFiles.push_back(iter->first);
967         }
968         iter++;
969     }
970 }
971 
ReadRawTrace(std::string &outputFileName)972 bool ReadRawTrace(std::string &outputFileName)
973 {
974     // read trace data from /per_cpu/cpux/trace_pipe_raw
975     std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
976     int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
977     if (outFd < 0) {
978         return false;
979     }
980     struct TraceFileHeader header;
981     GetArchWordSize(header);
982     GetCpuNums(header);
983     if (IsHmKernel()) {
984         header.fileType = HM_FILE_RAW_TRACE;
985     }
986     write(outFd, reinterpret_cast<char*>(&header), sizeof(header));
987 
988     if (WriteEventsFormat(outFd, outPath) && WriteCpuRaw(outFd, outPath) &&
989         WriteCmdlines(outFd, outPath) && WriteTgids(outFd, outPath) &&
990         WriteHeaderPage(outFd, outPath) && WritePrintkFormats(outFd, outPath) &&
991         WriteKallsyms(outFd)) {
992         fsync(outFd);
993         close(outFd);
994         return true;
995     }
996     HILOG_ERROR(LOG_CORE, "ReadRawTrace failed.");
997     fsync(outFd);
998     close(outFd);
999     return false;
1000 }
1001 
SetProcessName(std::string& processName)1002 void SetProcessName(std::string& processName)
1003 {
1004     if (processName.size() <= 0) {
1005         return;
1006     }
1007 
1008     const int maxNameLen = 16;
1009     std::string setName;
1010     if (processName.size() > maxNameLen) {
1011         setName = processName.substr(0, maxNameLen);
1012     } else {
1013         setName = processName;
1014     }
1015 
1016     prctl(PR_SET_NAME, setName.c_str(), nullptr, nullptr, nullptr);
1017     HILOG_INFO(LOG_CORE, "New process: %{public}s.", setName.c_str());
1018 }
1019 
TimeoutSignalHandler(int signum)1020 void TimeoutSignalHandler(int signum)
1021 {
1022     if (signum == SIGUSR1) {
1023         _exit(EXIT_SUCCESS);
1024     }
1025 }
1026 
EpollWaitforChildProcess(pid_t &pid, int &pipefd)1027 bool EpollWaitforChildProcess(pid_t &pid, int &pipefd)
1028 {
1029     int epollfd = epoll_create1(0);
1030     if (epollfd == -1) {
1031         HILOG_ERROR(LOG_CORE, "epoll_create1 error.");
1032         return false;
1033     }
1034 
1035     struct epoll_event event;
1036     event.events = EPOLLIN;
1037     event.data.fd = pipefd;
1038     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, pipefd, &event) == -1) {
1039         HILOG_ERROR(LOG_CORE, "epoll_ctl error.");
1040         return false;
1041     }
1042 
1043     struct epoll_event events[1];
1044     constexpr int waitTimeoutMs = 10000; // 10000ms = 10s
1045     int numEvents = 0;
1046     do {
1047         numEvents = epoll_wait(epollfd, events, 1, waitTimeoutMs);
1048     } while (numEvents == -1 && errno == EINTR);
1049     if (numEvents == -1) {
1050         HILOG_ERROR(LOG_CORE, "epoll_wait error, error: (%{public}s).", strerror(errno));
1051         close(pipefd);
1052         close(epollfd);
1053         return false;
1054     } else if (numEvents == 0) {
1055         HILOG_ERROR(LOG_CORE, "epoll_wait timeout.");
1056         if (waitpid(pid, nullptr, WNOHANG) <= 0) {
1057             HILOG_ERROR(LOG_CORE, "kill timeout child process.");
1058             kill(pid, SIGUSR1);
1059         }
1060         close(pipefd);
1061         close(epollfd);
1062         return false;
1063     }
1064     read(pipefd, &g_dumpStatus, sizeof(g_dumpStatus));
1065     close(pipefd);
1066     close(epollfd);
1067     if (waitpid(pid, nullptr, 0) <= 0) {
1068         HILOG_ERROR(LOG_CORE, "wait HitraceDump(%{public}d) exit failed, errno: (%{public}d)", pid, errno);
1069     }
1070     return true;
1071 }
1072 
DumpTraceInner(std::vector<std::string> &outputFiles)1073 TraceErrorCode DumpTraceInner(std::vector<std::string> &outputFiles)
1074 {
1075     int pipefd[2];
1076     if (pipe(pipefd) == -1) {
1077         HILOG_ERROR(LOG_CORE, "pipe creation error.");
1078         return TraceErrorCode::SYSTEM_ERROR;
1079     }
1080 
1081     std::string outputFileName = GenerateTraceFileName();
1082     std::string reOutPath = CanonicalizeSpecPath(outputFileName.c_str());
1083     /*Child process handles task, Father process wait.*/
1084     pid_t pid = fork();
1085     if (pid < 0) {
1086         HILOG_ERROR(LOG_CORE, "fork error.");
1087         return TraceErrorCode::WRITE_TRACE_INFO_ERROR;
1088     } else if (pid == 0) {
1089         signal(SIGUSR1, TimeoutSignalHandler);
1090         close(pipefd[0]);
1091         std::string processName = "HitraceDump";
1092         SetProcessName(processName);
1093         MarkClockSync(g_traceRootPath);
1094         constexpr int waitTime = 10000; // 10ms
1095         usleep(waitTime);
1096         if (ReadRawTrace(reOutPath)) {
1097             g_dumpStatus = TraceErrorCode::SUCCESS;
1098         }
1099         if (!IsRootVersion()) {
1100             DelSnapshotTraceFile(false, SNAPSHOT_FILE_MAX_COUNT);
1101         }
1102         HILOG_DEBUG(LOG_CORE, "%{public}s exit.", processName.c_str());
1103         write(pipefd[1], &g_dumpStatus, sizeof(g_dumpStatus));
1104         _exit(EXIT_SUCCESS);
1105     } else {
1106         close(pipefd[1]);
1107     }
1108 
1109     if (!EpollWaitforChildProcess(pid, pipefd[0])) {
1110         return TraceErrorCode::SYSTEM_ERROR;
1111     }
1112 
1113     if (g_dumpStatus) {
1114         if (remove(reOutPath.c_str()) == 0) {
1115             HILOG_INFO(LOG_CORE, "Delete outpath:%{public}s success.", reOutPath.c_str());
1116         } else {
1117             HILOG_INFO(LOG_CORE, "Delete outpath:%{public}s failed.", reOutPath.c_str());
1118         }
1119         return static_cast<TraceErrorCode>(g_dumpStatus.load());
1120     }
1121 
1122     if (access(reOutPath.c_str(), F_OK) != 0) {
1123         HILOG_ERROR(LOG_CORE, "DumpTraceInner: write %{public}s failed.", outputFileName.c_str());
1124         return TraceErrorCode::WRITE_TRACE_INFO_ERROR;
1125     }
1126 
1127     HILOG_INFO(LOG_CORE, "Output: %{public}s.", reOutPath.c_str());
1128     struct timeval now = {0, 0};
1129     gettimeofday(&now, nullptr);
1130     int nowSec = now.tv_sec;
1131     SearchFromTable(outputFiles, nowSec);
1132     outputFiles.push_back(outputFileName);
1133     g_traceFilesTable.push_back({outputFileName, nowSec});
1134     return TraceErrorCode::SUCCESS;
1135 }
1136 
GetSysParamTags()1137 uint64_t GetSysParamTags()
1138 {
1139     return OHOS::system::GetUintParameter<uint64_t>("debug.hitrace.tags.enableflags", 0);
1140 }
1141 
RestartService()1142 void RestartService()
1143 {
1144     CloseTrace();
1145     const std::vector<std::string> tagGroups = {"scene_performance"};
1146     OpenTrace(tagGroups);
1147 }
1148 
CheckParam()1149 bool CheckParam()
1150 {
1151     uint64_t currentTags = GetSysParamTags();
1152     if (currentTags == g_sysInitParamTags) {
1153         return true;
1154     }
1155 
1156     if (currentTags == 0) {
1157         HILOG_ERROR(LOG_CORE, "tag is 0, restart it.");
1158         RestartService();
1159         return false;
1160     }
1161     HILOG_ERROR(LOG_CORE, "trace is being used, restart later.");
1162     return false;
1163 }
1164 
CheckTraceFile()1165 bool CheckTraceFile()
1166 {
1167     const std::string enable = "1";
1168     if (ReadFile("tracing_on").substr(0, enable.size()) == enable) {
1169         return true;
1170     }
1171     HILOG_ERROR(LOG_CORE, "tracing_on is 0, restart it.");
1172     RestartService();
1173     return false;
1174 }
1175 
1176 /**
1177  * SERVICE_MODE is running, check param and tracing_on.
1178 */
CheckServiceRunning()1179 bool CheckServiceRunning()
1180 {
1181     if (CheckParam() && CheckTraceFile()) {
1182         return true;
1183     }
1184     return false;
1185 }
1186 
MonitorServiceTask()1187 void MonitorServiceTask()
1188 {
1189     g_serviceThreadIsStart = true;
1190     const std::string threadName = "TraceMonitor";
1191     prctl(PR_SET_NAME, threadName.c_str());
1192     HILOG_INFO(LOG_CORE, "MonitorServiceTask: monitor thread start.");
1193     const int intervalTime = 15;
1194     while (true) {
1195         sleep(intervalTime);
1196         if (g_traceMode != TraceMode::SERVICE_MODE) {
1197             break;
1198         }
1199 
1200         if (!CheckServiceRunning()) {
1201             continue;
1202         }
1203 
1204         const int cpuNums = GetCpuProcessors();
1205         std::vector<int> result;
1206         std::unique_ptr<DynamicBuffer> dynamicBuffer = std::make_unique<DynamicBuffer>(g_traceRootPath, cpuNums);
1207         dynamicBuffer->CalculateBufferSize(result);
1208 
1209         if (static_cast<int>(result.size()) != cpuNums) {
1210             HILOG_ERROR(LOG_CORE, "CalculateAllNewBufferSize failed.");
1211             break;
1212         }
1213 
1214         for (size_t i = 0; i < result.size(); i++) {
1215             HILOG_DEBUG(LOG_CORE, "cpu%{public}zu set size %{public}d.", i, result[i]);
1216             std::string path = "per_cpu/cpu" + std::to_string(i) + "/buffer_size_kb";
1217             WriteStrToFile(path, std::to_string(result[i]));
1218         }
1219     }
1220     HILOG_INFO(LOG_CORE, "MonitorServiceTask: monitor thread exit.");
1221     g_serviceThreadIsStart = false;
1222 }
1223 
HandleTraceOpen(const TraceParams &traceParams, const std::map<std::string, TagCategory> &allTags, const std::map<std::string, std::vector<std::string>> &tagGroupTable)1224 TraceErrorCode HandleTraceOpen(const TraceParams &traceParams,
1225                                const std::map<std::string, TagCategory> &allTags,
1226                                const std::map<std::string, std::vector<std::string>> &tagGroupTable)
1227 {
1228     if (!SetTraceSetting(traceParams, allTags, tagGroupTable)) {
1229         return TraceErrorCode::FILE_ERROR;
1230     }
1231     SetTraceNodeStatus("tracing_on", true);
1232     g_currentTraceParams = traceParams;
1233     return TraceErrorCode::SUCCESS;
1234 }
1235 
HandleServiceTraceOpen(const std::vector<std::string> &tagGroups, const std::map<std::string, TagCategory> &allTags, const std::map<std::string, std::vector<std::string>> &tagGroupTable)1236 TraceErrorCode HandleServiceTraceOpen(const std::vector<std::string> &tagGroups,
1237                                       const std::map<std::string, TagCategory> &allTags,
1238                                       const std::map<std::string, std::vector<std::string>> &tagGroupTable)
1239 {
1240     TraceParams serviceTraceParams;
1241     serviceTraceParams.tagGroups = tagGroups;
1242     serviceTraceParams.bufferSize = std::to_string(DEFAULT_BUFFER_SIZE);
1243     if (IsHmKernel()) {
1244         serviceTraceParams.bufferSize = std::to_string(HM_DEFAULT_BUFFER_SIZE);
1245     }
1246     serviceTraceParams.clockType = "boot";
1247     serviceTraceParams.isOverWrite = "1";
1248     serviceTraceParams.fileSize = DEFAULT_FILE_SIZE;
1249     return HandleTraceOpen(serviceTraceParams, allTags, tagGroupTable);
1250 }
1251 
RemoveUnSpace(std::string str, std::string& args)1252 void RemoveUnSpace(std::string str, std::string& args)
1253 {
1254     int maxCircleTimes = 30;
1255     int curTimes = 0;
1256     const size_t symbolAndSpaceLen = 2;
1257     std::string strSpace = str + " ";
1258     while (curTimes < maxCircleTimes) {
1259         curTimes++;
1260         std::string::size_type index = args.find(strSpace);
1261         if (index != std::string::npos) {
1262             args.replace(index, symbolAndSpaceLen, str);
1263         } else {
1264             break;
1265         }
1266     }
1267 }
1268 
SetCmdTraceIntParams(const std::string &traceParamsStr, int &traceParams)1269 void SetCmdTraceIntParams(const std::string &traceParamsStr, int &traceParams)
1270 {
1271     if (traceParamsStr.empty() || !IsNumber(traceParamsStr)) {
1272         HILOG_WARN(LOG_CORE, "Illegal input, traceParams initialized to null.");
1273         traceParams = 0;
1274         return;
1275     }
1276     traceParams = std::stoi(traceParamsStr);
1277     if (traceParams <= 0) {
1278         HILOG_WARN(LOG_CORE, "Illegal input, traceParams initialized to null.");
1279         traceParams = 0;
1280     }
1281 }
1282 
1283 /**
1284  * args: tags:tag1,tags2... tagGroups:group1,group2... clockType:boot bufferSize:1024 overwrite:1 output:filename
1285  * cmdTraceParams:  Save the above parameters
1286 */
ParseArgs(const std::string &args, TraceParams &cmdTraceParams, const std::map<std::string, TagCategory> &allTags, const std::map<std::string, std::vector<std::string>> &tagGroupTable)1287 bool ParseArgs(const std::string &args, TraceParams &cmdTraceParams, const std::map<std::string, TagCategory> &allTags,
1288                const std::map<std::string, std::vector<std::string>> &tagGroupTable)
1289 {
1290     std::string userArgs = args;
1291     std::string str = ":";
1292     RemoveUnSpace(str, userArgs);
1293     str = ",";
1294     RemoveUnSpace(str, userArgs);
1295     std::vector<std::string> argList = Split(userArgs, ' ');
1296     for (std::string item : argList) {
1297         size_t pos = item.find(":");
1298         if (pos == std::string::npos) {
1299             HILOG_ERROR(LOG_CORE, "trace command line without colon appears: %{public}s, continue.", item.c_str());
1300             continue;
1301         }
1302         std::string itemName = item.substr(0, pos);
1303         if (itemName == "tags") {
1304             cmdTraceParams.tags = Split(item.substr(pos + 1), ',');
1305         } else if (itemName == "tagGroups") {
1306             cmdTraceParams.tagGroups = Split(item.substr(pos + 1), ',');
1307         } else if (itemName == "clockType") {
1308             cmdTraceParams.clockType = item.substr(pos + 1);
1309         } else if (itemName == "bufferSize") {
1310             cmdTraceParams.bufferSize = item.substr(pos + 1);
1311         } else if (itemName == "overwrite") {
1312             cmdTraceParams.isOverWrite = item.substr(pos + 1);
1313         } else if (itemName == "output") {
1314             cmdTraceParams.outputFile = item.substr(pos + 1);
1315         } else if (itemName == "fileSize") {
1316             std::string fileSizeStr = item.substr(pos + 1);
1317             SetCmdTraceIntParams(fileSizeStr, cmdTraceParams.fileSize);
1318         } else if (itemName == "fileLimit") {
1319             std::string fileLimitStr = item.substr(pos + 1);
1320             SetCmdTraceIntParams(fileLimitStr, cmdTraceParams.fileLimit);
1321         } else if (itemName == "appPid") {
1322             std::string pidStr = item.substr(pos + 1);
1323             SetCmdTraceIntParams(pidStr, cmdTraceParams.appPid);
1324             if (cmdTraceParams.appPid == 0) {
1325                 HILOG_ERROR(LOG_CORE, "Illegal input, appPid(%{public}s) must be number and greater than 0.",
1326                     pidStr.c_str());
1327                 return false;
1328             }
1329             OHOS::system::SetParameter("debug.hitrace.app_pid", pidStr);
1330         } else {
1331             HILOG_ERROR(LOG_CORE, "Extra trace command line options appear when ParseArgs: %{public}s, return false.",
1332                 itemName.c_str());
1333             return false;
1334         }
1335     }
1336     if (CheckTags(cmdTraceParams.tags, allTags) && CheckTagGroup(cmdTraceParams.tagGroups, tagGroupTable)) {
1337         return true;
1338     }
1339     return false;
1340 }
1341 
WriteCpuFreqTrace()1342 void WriteCpuFreqTrace()
1343 {
1344     std::string freqsfmt = "cpu frequency: ";
1345     ReadCurrentCpuFrequencies(freqsfmt);
1346     HILOG_INFO(LOG_CORE, "hitracedump write trace(%{public}s)", freqsfmt.c_str());
1347     HITRACE_METER_NAME(HITRACE_TAG_OHOS, freqsfmt);
1348 }
1349 } // namespace
1350 
1351 #ifdef HITRACE_UNITTEST
SetSysInitParamTags(uint64_t sysInitParamTags)1352 void SetSysInitParamTags(uint64_t sysInitParamTags)
1353 {
1354     g_sysInitParamTags = sysInitParamTags;
1355 }
1356 
SetCheckParam()1357 bool SetCheckParam()
1358 {
1359     int ret = CheckParam();
1360     return ret;
1361 }
1362 #endif
1363 
GetTraceMode()1364 TraceMode GetTraceMode()
1365 {
1366     return g_traceMode;
1367 }
1368 
OpenTrace(const std::vector<std::string> &tagGroups)1369 TraceErrorCode OpenTrace(const std::vector<std::string> &tagGroups)
1370 {
1371     if (g_traceMode != CLOSE) {
1372         HILOG_ERROR(LOG_CORE, "OpenTrace: CALL_ERROR, g_traceMode:%{public}d.", static_cast<int>(g_traceMode));
1373         return CALL_ERROR;
1374     }
1375     std::lock_guard<std::mutex> lock(g_traceMutex);
1376     if (!IsTraceMounted()) {
1377         HILOG_ERROR(LOG_CORE, "OpenTrace: TRACE_NOT_SUPPORTED.");
1378         return TRACE_NOT_SUPPORTED;
1379     }
1380 
1381     std::map<std::string, TagCategory> allTags;
1382     std::map<std::string, std::vector<std::string>> tagGroupTable;
1383     if (!ParseTagInfo(allTags, tagGroupTable)) {
1384         HILOG_ERROR(LOG_CORE, "OpenTrace: ParseTagInfo TAG_ERROR.");
1385         return TAG_ERROR;
1386     }
1387 
1388     if (tagGroups.size() == 0 || !CheckTagGroup(tagGroups, tagGroupTable)) {
1389         HILOG_ERROR(LOG_CORE, "OpenTrace: TAG_ERROR.");
1390         return TAG_ERROR;
1391     }
1392 
1393     TraceErrorCode ret = HandleServiceTraceOpen(tagGroups, allTags, tagGroupTable);
1394     if (ret != SUCCESS) {
1395         HILOG_ERROR(LOG_CORE, "OpenTrace: open fail.");
1396         return ret;
1397     }
1398     g_traceMode = SERVICE_MODE;
1399 
1400     DelSnapshotTraceFile();
1401     if (!IsHmKernel() && !g_serviceThreadIsStart) {
1402         // open SERVICE_MODE monitor thread
1403         auto it = []() {
1404             MonitorServiceTask();
1405         };
1406         std::thread auxiliaryTask(it);
1407         auxiliaryTask.detach();
1408     }
1409     g_sysInitParamTags = GetSysParamTags();
1410     HILOG_INFO(LOG_CORE, "OpenTrace: SERVICE_MODE open success.");
1411     return ret;
1412 }
1413 
OpenTrace(const std::string &args)1414 TraceErrorCode OpenTrace(const std::string &args)
1415 {
1416     std::lock_guard<std::mutex> lock(g_traceMutex);
1417     if (g_traceMode != CLOSE) {
1418         HILOG_ERROR(LOG_CORE, "OpenTrace: CALL_ERROR, g_traceMode:%{public}d.", static_cast<int>(g_traceMode));
1419         return CALL_ERROR;
1420     }
1421 
1422     if (!IsTraceMounted()) {
1423         HILOG_ERROR(LOG_CORE, "Hitrace OpenTrace: TRACE_NOT_SUPPORTED.");
1424         return TRACE_NOT_SUPPORTED;
1425     }
1426 
1427     std::map<std::string, TagCategory> allTags;
1428     std::map<std::string, std::vector<std::string>> tagGroupTable;
1429     if (!ParseTagInfo(allTags, tagGroupTable) || allTags.size() == 0 || tagGroupTable.size() == 0) {
1430         HILOG_ERROR(LOG_CORE, "Hitrace OpenTrace: ParseTagInfo TAG_ERROR.");
1431         return TAG_ERROR;
1432     }
1433     // parse args
1434     TraceParams cmdTraceParams;
1435     if (!ParseArgs(args, cmdTraceParams, allTags, tagGroupTable)) {
1436         HILOG_ERROR(LOG_CORE, "Hitrace OpenTrace: TAG_ERROR.");
1437         return TAG_ERROR;
1438     }
1439 
1440     TraceErrorCode ret = HandleTraceOpen(cmdTraceParams, allTags, tagGroupTable);
1441     if (ret != SUCCESS) {
1442         HILOG_ERROR(LOG_CORE, "Hitrace OpenTrace: CMD_MODE open failed.");
1443         return FILE_ERROR;
1444     }
1445     g_traceMode = CMD_MODE;
1446     HILOG_INFO(LOG_CORE, "Hitrace OpenTrace: CMD_MODE open success, args:%{public}s.", args.c_str());
1447     return ret;
1448 }
1449 
DumpTrace()1450 TraceRetInfo DumpTrace()
1451 {
1452     TraceRetInfo ret;
1453     HILOG_INFO(LOG_CORE, "DumpTrace start.");
1454     if (g_traceMode != SERVICE_MODE) {
1455         HILOG_ERROR(LOG_CORE, "DumpTrace: CALL_ERROR, g_traceMode:%{public}d.", static_cast<int>(g_traceMode));
1456         ret.errorCode = CALL_ERROR;
1457         return ret;
1458     }
1459 
1460     if (!CheckServiceRunning()) {
1461         HILOG_ERROR(LOG_CORE, "DumpTrace: TRACE_IS_OCCUPIED.");
1462         ret.errorCode = TRACE_IS_OCCUPIED;
1463         return ret;
1464     }
1465     std::lock_guard<std::mutex> lock(g_traceMutex);
1466     g_dumpStatus = TraceErrorCode::UNSET;
1467     SetTimeIntervalBoundary();
1468     ret.errorCode = DumpTraceInner(ret.outputFiles);
1469     RestoreTimeIntervalBoundary();
1470     HILOG_INFO(LOG_CORE, "DumpTrace done.");
1471     return ret;
1472 }
1473 
DumpTrace(int maxDuration, uint64_t traceEndTime)1474 TraceRetInfo DumpTrace(int maxDuration, uint64_t traceEndTime)
1475 {
1476     HILOG_INFO(LOG_CORE, "DumpTrace with timelimit start, timelimit is %{public}d, endtime is (%{public}" PRId64 ").",
1477         maxDuration, traceEndTime);
1478     TraceRetInfo ret;
1479     if (maxDuration < 0) {
1480         HILOG_ERROR(LOG_CORE, "DumpTrace: Illegal input.");
1481         ret.errorCode = CALL_ERROR;
1482         return ret;
1483     }
1484     {
1485         std::time_t now = std::time(nullptr);
1486         if (maxDuration > (now - 1)) {
1487             maxDuration = 0;
1488         }
1489         std::lock_guard<std::mutex> lock(g_traceMutex);
1490         if (traceEndTime > 0) {
1491             if (traceEndTime > static_cast<uint64_t>(now)) {
1492                 HILOG_WARN(LOG_CORE, "DumpTrace: Warning: traceEndTime is later than current time.");
1493             }
1494             struct sysinfo info;
1495             if (sysinfo(&info) != 0) {
1496                 HILOG_ERROR(LOG_CORE, "Get system info failed.");
1497                 ret.errorCode = UNKNOWN_ERROR;
1498                 return ret;
1499             }
1500             std::time_t boot_time = now - info.uptime;
1501             if (traceEndTime > static_cast<uint64_t>(boot_time)) {
1502                 // beware of input precision of seconds: add an extra second of tolerance
1503                 g_inputTraceEndTime = (traceEndTime - static_cast<uint64_t>(boot_time) + 1) * S_TO_NS;
1504             } else {
1505                 HILOG_ERROR(LOG_CORE,
1506                     "DumpTrace: traceEndTime:(%{public}" PRId64 ") is earlier than boot_time:(%{public}" PRId64 ").",
1507                     traceEndTime, static_cast<uint64_t>(boot_time));
1508                 ret.errorCode = OUT_OF_TIME;
1509                 return ret;
1510             }
1511             g_inputMaxDuration = maxDuration ? maxDuration + 1 : 0; // for precision tolerance
1512         } else {
1513             g_inputMaxDuration = maxDuration;
1514         }
1515     }
1516     ret = DumpTrace();
1517     {
1518         std::lock_guard<std::mutex> lock(g_traceMutex);
1519         g_inputMaxDuration = 0;
1520         g_inputTraceEndTime = 0;
1521     }
1522     HILOG_INFO(LOG_CORE, "DumpTrace with time limit done.");
1523     return ret;
1524 }
1525 
DumpTraceOn()1526 TraceErrorCode DumpTraceOn()
1527 {
1528     std::lock_guard<std::mutex> lock(g_traceMutex);
1529     // check current trace status
1530     if (g_traceMode != CMD_MODE) {
1531         HILOG_ERROR(LOG_CORE, "DumpTraceOn: CALL_ERROR, g_traceMode:%{public}d.", static_cast<int>(g_traceMode));
1532         return CALL_ERROR;
1533     }
1534 
1535     if (!g_dumpEnd) {
1536         HILOG_ERROR(LOG_CORE, "DumpTraceOn: CALL_ERROR, record trace is dumping now.");
1537         return CALL_ERROR;
1538     }
1539 
1540     // start task thread
1541     auto it = []() {
1542         ProcessDumpTask();
1543     };
1544     std::thread task(it);
1545     task.detach();
1546     WriteCpuFreqTrace();
1547     HILOG_INFO(LOG_CORE, "Recording trace on.");
1548     return SUCCESS;
1549 }
1550 
DumpTraceOff()1551 TraceRetInfo DumpTraceOff()
1552 {
1553     std::lock_guard<std::mutex> lock(g_traceMutex);
1554     TraceRetInfo ret;
1555     // check current trace status
1556     if (g_traceMode != CMD_MODE) {
1557         HILOG_ERROR(LOG_CORE, "DumpTraceOff: The current state is %{public}d, data exception.",
1558             static_cast<int>(g_traceMode));
1559         ret.errorCode = CALL_ERROR;
1560         ret.outputFiles = g_outputFilesForCmd;
1561         return ret;
1562     }
1563 
1564     g_dumpFlag = false;
1565     while (!g_dumpEnd) {
1566         usleep(UNIT_TIME);
1567         g_dumpFlag = false;
1568     }
1569     ret.errorCode = SUCCESS;
1570     ret.outputFiles = g_outputFilesForCmd;
1571     HILOG_INFO(LOG_CORE, "Recording trace off.");
1572     return ret;
1573 }
1574 
CloseTrace()1575 TraceErrorCode CloseTrace()
1576 {
1577     std::lock_guard<std::mutex> lock(g_traceMutex);
1578     HILOG_INFO(LOG_CORE, "CloseTrace start.");
1579     if (g_traceMode == CLOSE) {
1580         HILOG_INFO(LOG_CORE, "Trace already close.");
1581         return SUCCESS;
1582     }
1583 
1584     g_traceMode = CLOSE;
1585     // Waiting for the data drop task to end
1586     g_dumpFlag = false;
1587     while (!g_dumpEnd) {
1588         usleep(UNIT_TIME);
1589         g_dumpFlag = false;
1590     }
1591     OHOS::system::SetParameter("debug.hitrace.app_pid", "-1");
1592     std::map<std::string, TagCategory> allTags;
1593     std::map<std::string, std::vector<std::string>> tagGroupTable;
1594     if (!ParseTagInfo(allTags, tagGroupTable) || allTags.size() == 0 || tagGroupTable.size() == 0) {
1595         HILOG_ERROR(LOG_CORE, "CloseTrace: ParseTagInfo TAG_ERROR.");
1596         return TAG_ERROR;
1597     }
1598     TraceInit(allTags);
1599     TruncateFile();
1600     HILOG_INFO(LOG_CORE, "CloseTrace done.");
1601     return SUCCESS;
1602 }
1603 
GetTraceFilesTable()1604 std::vector<std::pair<std::string, int>> GetTraceFilesTable()
1605 {
1606     return g_traceFilesTable;
1607 }
1608 
SetTraceFilesTable(const std::vector<std::pair<std::string, int>>& traceFilesTable)1609 void SetTraceFilesTable(const std::vector<std::pair<std::string, int>>& traceFilesTable)
1610 {
1611     g_traceFilesTable = traceFilesTable;
1612 }
1613 } // Hitrace
1614 } // HiviewDFX
1615 } // OHOS
1616