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