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