• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "hitrace_dump.h"
17 
18 #include <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             close(outFd);
1037             return false;
1038         }
1039     } while (g_needGenerateNewTraceFile);
1040     close(outFd);
1041     return true;
1042 }
1043 
1044 /**
1045  * read trace data loop
1046  * g_dumpFlag: true = open,false = close
1047  * g_dumpEnd: true = end,false = not end
1048  * if user has own output file, Output all data to the file specified by the user;
1049  * if not, Then place all the result files in /data/log/hitrace/ and package them once in 96M.
1050 */
ProcessDumpTask()1051 void ProcessDumpTask()
1052 {
1053     g_dumpFlag = true;
1054     g_dumpEnd = false;
1055     g_outputFilesForCmd = {};
1056     const std::string threadName = "TraceDumpTask";
1057     prctl(PR_SET_NAME, threadName.c_str());
1058     HILOG_INFO(LOG_CORE, "ProcessDumpTask: trace dump thread start.");
1059 
1060     // clear old record file before record tracing start.
1061     DelSavedEventsFormat();
1062     if (!IsRootVersion()) {
1063         DelOldRecordTraceFile(g_currentTraceParams.fileLimit);
1064     }
1065 
1066     if (g_currentTraceParams.fileSize.empty()) {
1067         std::string outputFileName = g_currentTraceParams.outputFile.empty() ?
1068                                      GenerateTraceFileName(false) : g_currentTraceParams.outputFile;
1069         if (DumpTraceLoop(outputFileName, false)) {
1070             g_outputFilesForCmd.push_back(outputFileName);
1071         }
1072         g_dumpEnd = true;
1073         return;
1074     }
1075 
1076     while (g_dumpFlag) {
1077         if (!IsRootVersion()) {
1078             ClearOldTraceFile(g_outputFilesForCmd, g_currentTraceParams.fileLimit);
1079         }
1080         // Generate file name
1081         std::string outputFileName = GenerateTraceFileName(false);
1082         if (DumpTraceLoop(outputFileName, true)) {
1083             g_outputFilesForCmd.push_back(outputFileName);
1084         } else {
1085             break;
1086         }
1087     }
1088     HILOG_INFO(LOG_CORE, "ProcessDumpTask: trace dump thread exit.");
1089     g_dumpEnd = true;
1090 }
1091 
SearchFromTable(std::vector<std::string> & outputFiles,int nowSec)1092 void SearchFromTable(std::vector<std::string> &outputFiles, int nowSec)
1093 {
1094     const int maxInterval = 30;
1095     const int agingTime = 30 * 60;
1096 
1097     for (auto iter = g_traceFilesTable.begin(); iter != g_traceFilesTable.end();) {
1098         if (nowSec - iter->second >= agingTime) {
1099             // delete outdated trace file
1100             if (access(iter->first.c_str(), F_OK) == 0) {
1101                 remove(iter->first.c_str());
1102                 HILOG_INFO(LOG_CORE, "delete old %{public}s file success.", iter->first.c_str());
1103             }
1104             iter = g_traceFilesTable.erase(iter);
1105             continue;
1106         }
1107 
1108         if (nowSec - iter->second <= maxInterval) {
1109             outputFiles.push_back(iter->first);
1110         }
1111         iter++;
1112     }
1113 }
1114 
ReadRawTrace(std::string & outputFileName)1115 bool ReadRawTrace(std::string &outputFileName)
1116 {
1117     // read trace data from /per_cpu/cpux/trace_pipe_raw
1118     std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
1119     int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
1120     if (outFd < 0) {
1121         return false;
1122     }
1123     struct TraceFileHeader header;
1124     GetArchWordSize(header);
1125     GetCpuNums(header);
1126     if (IsHmKernel()) {
1127         header.fileType = HM_FILE_RAW_TRACE;
1128     }
1129     write(outFd, reinterpret_cast<char*>(&header), sizeof(header));
1130 
1131     if (WriteEventsFormat(outFd, outPath) && WriteCpuRaw(outFd, outPath) &&
1132         WriteCmdlines(outFd, outPath) && WriteTgids(outFd, outPath) &&
1133         WriteHeaderPage(outFd, outPath) && WritePrintkFormats(outFd, outPath) &&
1134         WriteKallsyms(outFd)) {
1135         fsync(outFd);
1136         close(outFd);
1137         return true;
1138     }
1139     HILOG_ERROR(LOG_CORE, "ReadRawTrace failed.");
1140     fsync(outFd);
1141     close(outFd);
1142     return false;
1143 }
1144 
WaitPidTimeout(pid_t pid,const int timeoutUsec)1145 bool WaitPidTimeout(pid_t pid, const int timeoutUsec)
1146 {
1147     int delayTime = timeoutUsec;
1148     while (delayTime > 0) {
1149         usleep(UNIT_TIME);
1150         delayTime -= UNIT_TIME;
1151         int status = 0;
1152         int ret = waitpid(pid, &status, WNOHANG);
1153         if (ret == pid) {
1154             HILOG_INFO(LOG_CORE, "wait pid(%{public}d) exit success.", pid);
1155             return true;
1156         } else if (ret < 0) {
1157             HILOG_ERROR(LOG_CORE, "wait pid(%{public}d) exit failed, status: %{public}d.", pid, status);
1158             return false;
1159         }
1160         HILOG_DEBUG(LOG_CORE, "grasping trace, pid(%{public}d), ret(%{public}d).", pid, ret);
1161     }
1162     HILOG_ERROR(LOG_CORE, "wait pid(%{public}d) %{public}d us timeout.", pid, timeoutUsec);
1163     return false;
1164 }
1165 
SetProcessName(std::string & processName)1166 void SetProcessName(std::string& processName)
1167 {
1168     if (processName.size() <= 0) {
1169         return;
1170     }
1171 
1172     const int maxNameLen = 16;
1173     std::string setName;
1174     if (processName.size() > maxNameLen) {
1175         setName = processName.substr(0, maxNameLen);
1176     } else {
1177         setName = processName;
1178     }
1179 
1180     prctl(PR_SET_NAME, setName.c_str(), nullptr, nullptr, nullptr);
1181     HILOG_INFO(LOG_CORE, "New process: %{public}s.", setName.c_str());
1182 }
1183 
DumpTraceInner(std::vector<std::string> & outputFiles)1184 TraceErrorCode DumpTraceInner(std::vector<std::string> &outputFiles)
1185 {
1186     g_dumpEnd = false;
1187     std::string outputFileName = GenerateTraceFileName();
1188     std::string reOutPath = CanonicalizeSpecPath(outputFileName.c_str());
1189 
1190     /*Child process handles task, Father process wait.*/
1191     pid_t pid = fork();
1192     if (pid < 0) {
1193         HILOG_ERROR(LOG_CORE, "fork error.");
1194         g_dumpEnd = true;
1195         return TraceErrorCode::WRITE_TRACE_INFO_ERROR;
1196     }
1197     bool ret = false;
1198     if (pid == 0) {
1199         std::string processName = "HitraceDump";
1200         SetProcessName(processName);
1201         MarkClockSync(g_traceRootPath);
1202         const int waitTime = 10000; // 10ms
1203         usleep(waitTime);
1204         ReadRawTrace(reOutPath);
1205         if (!IsRootVersion()) {
1206             DelSnapshotTraceFile(false, SNAPSHOT_FILE_MAX_COUNT);
1207         }
1208         HILOG_DEBUG(LOG_CORE, "%{public}s exit.", processName.c_str());
1209         _exit(EXIT_SUCCESS);
1210     } else {
1211         const int timeoutUsec = 10000000; // 10s
1212         bool isTrue = WaitPidTimeout(pid, timeoutUsec);
1213         if (isTrue && access(reOutPath.c_str(), F_OK) == 0) {
1214             HILOG_INFO(LOG_CORE, "Output: %{public}s.", reOutPath.c_str());
1215             ret = true;
1216         } else {
1217             HILOG_ERROR(LOG_CORE, "Output error: %{public}s.", reOutPath.c_str());
1218         }
1219     }
1220 
1221     struct timeval now = {0, 0};
1222     gettimeofday(&now, nullptr);
1223     int nowSec = now.tv_sec;
1224     SearchFromTable(outputFiles, nowSec);
1225     if (ret) {
1226         outputFiles.push_back(outputFileName);
1227         g_traceFilesTable.push_back({outputFileName, nowSec});
1228     } else {
1229         HILOG_ERROR(LOG_CORE, "DumpTraceInner: write %{public}s failed.", outputFileName.c_str());
1230         g_dumpEnd = true;
1231         return TraceErrorCode::WRITE_TRACE_INFO_ERROR;
1232     }
1233     g_dumpEnd = true;
1234     return TraceErrorCode::SUCCESS;
1235 }
1236 
GetSysParamTags()1237 uint64_t GetSysParamTags()
1238 {
1239     return OHOS::system::GetUintParameter<uint64_t>("debug.hitrace.tags.enableflags", 0);
1240 }
1241 
RestartService()1242 void RestartService()
1243 {
1244     CloseTrace();
1245     const std::vector<std::string> tagGroups = {"scene_performance"};
1246     OpenTrace(tagGroups);
1247 }
1248 
CheckParam()1249 bool CheckParam()
1250 {
1251     uint64_t currentTags = GetSysParamTags();
1252     if (currentTags == g_sysInitParamTags) {
1253         return true;
1254     }
1255 
1256     if (currentTags == 0) {
1257         HILOG_ERROR(LOG_CORE, "tag is 0, restart it.");
1258         RestartService();
1259         return false;
1260     }
1261     HILOG_ERROR(LOG_CORE, "trace is being used, restart later.");
1262     return false;
1263 }
1264 
CheckTraceFile()1265 bool CheckTraceFile()
1266 {
1267     const std::string enable = "1";
1268     if (ReadFile("tracing_on").substr(0, enable.size()) == enable) {
1269         return true;
1270     }
1271     HILOG_ERROR(LOG_CORE, "tracing_on is 0, restart it.");
1272     RestartService();
1273     return false;
1274 }
1275 
1276 /**
1277  * SERVICE_MODE is running, check param and tracing_on.
1278 */
CheckServiceRunning()1279 bool CheckServiceRunning()
1280 {
1281     if (CheckParam() && CheckTraceFile()) {
1282         return true;
1283     }
1284     return false;
1285 }
1286 
MonitorServiceTask()1287 void MonitorServiceTask()
1288 {
1289     g_serviceThreadIsStart = true;
1290     const std::string threadName = "TraceMonitor";
1291     prctl(PR_SET_NAME, threadName.c_str());
1292     HILOG_INFO(LOG_CORE, "MonitorServiceTask: monitor thread start.");
1293     const int intervalTime = 15;
1294     while (true) {
1295         sleep(intervalTime);
1296         if (g_traceMode != TraceMode::SERVICE_MODE) {
1297             break;
1298         }
1299 
1300         if (!CheckServiceRunning()) {
1301             continue;
1302         }
1303 
1304         const int cpuNums = GetCpuProcessors();
1305         std::vector<int> result;
1306         std::unique_ptr<DynamicBuffer> dynamicBuffer = std::make_unique<DynamicBuffer>(g_traceRootPath, cpuNums);
1307         dynamicBuffer->CalculateBufferSize(result);
1308 
1309         if (static_cast<int>(result.size()) != cpuNums) {
1310             HILOG_ERROR(LOG_CORE, "CalculateAllNewBufferSize failed.");
1311             break;
1312         }
1313 
1314         for (size_t i = 0; i < result.size(); i++) {
1315             HILOG_DEBUG(LOG_CORE, "cpu%{public}zu set size %{public}d.", i, result[i]);
1316             std::string path = "per_cpu/cpu" + std::to_string(i) + "/buffer_size_kb";
1317             WriteStrToFile(path, std::to_string(result[i]));
1318         }
1319     }
1320     HILOG_INFO(LOG_CORE, "MonitorServiceTask: monitor thread exit.");
1321     g_serviceThreadIsStart = false;
1322 }
1323 
HandleTraceOpen(const TraceParams & traceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)1324 TraceErrorCode HandleTraceOpen(const TraceParams &traceParams,
1325                                const std::map<std::string, TagCategory> &allTags,
1326                                const std::map<std::string, std::vector<std::string>> &tagGroupTable)
1327 {
1328     if (!SetTraceSetting(traceParams, allTags, tagGroupTable)) {
1329         return TraceErrorCode::FILE_ERROR;
1330     }
1331     SetTraceNodeStatus("tracing_on", true);
1332     g_currentTraceParams = traceParams;
1333     return TraceErrorCode::SUCCESS;
1334 }
1335 
HandleServiceTraceOpen(const std::vector<std::string> & tagGroups,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)1336 TraceErrorCode HandleServiceTraceOpen(const std::vector<std::string> &tagGroups,
1337                                       const std::map<std::string, TagCategory> &allTags,
1338                                       const std::map<std::string, std::vector<std::string>> &tagGroupTable)
1339 {
1340     TraceParams serviceTraceParams;
1341     serviceTraceParams.tagGroups = tagGroups;
1342     serviceTraceParams.bufferSize = std::to_string(DEFAULT_BUFFER_SIZE);
1343     if (IsHmKernel()) {
1344         serviceTraceParams.bufferSize = std::to_string(HM_DEFAULT_BUFFER_SIZE);
1345     }
1346     serviceTraceParams.clockType = "boot";
1347     serviceTraceParams.isOverWrite = "1";
1348     serviceTraceParams.fileSize = std::to_string(DEFAULT_FILE_SIZE);
1349     return HandleTraceOpen(serviceTraceParams, allTags, tagGroupTable);
1350 }
1351 
RemoveUnSpace(std::string str,std::string & args)1352 void RemoveUnSpace(std::string str, std::string& args)
1353 {
1354     int maxCircleTimes = 30;
1355     int curTimes = 0;
1356     const size_t symbolAndSpaceLen = 2;
1357     std::string strSpace = str + " ";
1358     while (curTimes < maxCircleTimes) {
1359         curTimes++;
1360         std::string::size_type index = args.find(strSpace);
1361         if (index != std::string::npos) {
1362             args.replace(index, symbolAndSpaceLen, str);
1363         } else {
1364             break;
1365         }
1366     }
1367 }
1368 
1369 /**
1370  * args: tags:tag1,tags2... tagGroups:group1,group2... clockType:boot bufferSize:1024 overwrite:1 output:filename
1371  * cmdTraceParams:  Save the above parameters
1372 */
ParseArgs(const std::string & args,TraceParams & cmdTraceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)1373 bool ParseArgs(const std::string &args, TraceParams &cmdTraceParams, const std::map<std::string, TagCategory> &allTags,
1374                const std::map<std::string, std::vector<std::string>> &tagGroupTable)
1375 {
1376     std::string userArgs = args;
1377     std::string str = ":";
1378     RemoveUnSpace(str, userArgs);
1379     str = ",";
1380     RemoveUnSpace(str, userArgs);
1381     std::vector<std::string> argList = Split(userArgs, ' ');
1382     for (std::string item : argList) {
1383         size_t pos = item.find(":");
1384         if (pos == std::string::npos) {
1385             HILOG_ERROR(LOG_CORE, "trace command line without colon appears: %{public}s, continue.", item.c_str());
1386             continue;
1387         }
1388         std::string itemName = item.substr(0, pos);
1389         if (itemName == "tags") {
1390             cmdTraceParams.tags = Split(item.substr(pos + 1), ',');
1391         } else if (itemName == "tagGroups") {
1392             cmdTraceParams.tagGroups = Split(item.substr(pos + 1), ',');
1393         } else if (itemName == "clockType") {
1394             cmdTraceParams.clockType = item.substr(pos + 1);
1395         } else if (itemName == "bufferSize") {
1396             cmdTraceParams.bufferSize = item.substr(pos + 1);
1397         } else if (itemName == "overwrite") {
1398             cmdTraceParams.isOverWrite = item.substr(pos + 1);
1399         } else if (itemName == "output") {
1400             cmdTraceParams.outputFile = item.substr(pos + 1);
1401         } else if (itemName == "fileSize") {
1402             cmdTraceParams.fileSize = item.substr(pos + 1);
1403         } else if (itemName == "fileLimit") {
1404             cmdTraceParams.fileLimit = item.substr(pos + 1);
1405         } else if (itemName == "appPid") {
1406             std::string pidStr = item.substr(pos + 1);
1407             if (!IsNumber(pidStr)) {
1408                 HILOG_ERROR(LOG_CORE, "Illegal input, appPid(%{public}s) must be number.", pidStr.c_str());
1409                 return false;
1410             }
1411             int appPid = std::stoi(pidStr);
1412             if (appPid <= 0) {
1413                 HILOG_ERROR(LOG_CORE, "Illegal input, appPid(%{public}d) must be greater than 0.", appPid);
1414                 return false;
1415             }
1416             OHOS::system::SetParameter("debug.hitrace.app_pid", pidStr);
1417         } else {
1418             HILOG_ERROR(LOG_CORE, "Extra trace command line options appear when ParseArgs: %{public}s, return false.",
1419                 itemName.c_str());
1420             return false;
1421         }
1422     }
1423     if (CheckTags(cmdTraceParams.tags, allTags) && CheckTagGroup(cmdTraceParams.tagGroups, tagGroupTable)) {
1424         return true;
1425     }
1426     return false;
1427 }
1428 } // namespace
1429 
1430 #ifdef HITRACE_UNITTEST
SetSysInitParamTags(uint64_t sysInitParamTags)1431 void SetSysInitParamTags(uint64_t sysInitParamTags)
1432 {
1433     g_sysInitParamTags = sysInitParamTags;
1434 }
1435 
SetCheckParam()1436 bool SetCheckParam()
1437 {
1438     int ret = CheckParam();
1439     return ret;
1440 }
1441 #endif
1442 
GetTraceMode()1443 TraceMode GetTraceMode()
1444 {
1445     return g_traceMode;
1446 }
1447 
OpenTrace(const std::vector<std::string> & tagGroups)1448 TraceErrorCode OpenTrace(const std::vector<std::string> &tagGroups)
1449 {
1450     if (g_traceMode != CLOSE) {
1451         HILOG_ERROR(LOG_CORE, "OpenTrace: CALL_ERROR, g_traceMode:%{public}d.", static_cast<int>(g_traceMode));
1452         return CALL_ERROR;
1453     }
1454     std::lock_guard<std::mutex> lock(g_traceMutex);
1455     if (!IsTraceMounted()) {
1456         HILOG_ERROR(LOG_CORE, "OpenTrace: TRACE_NOT_SUPPORTED.");
1457         return TRACE_NOT_SUPPORTED;
1458     }
1459 
1460     std::map<std::string, TagCategory> allTags;
1461     std::map<std::string, std::vector<std::string>> tagGroupTable;
1462     if (!ParseTagInfo(allTags, tagGroupTable)) {
1463         HILOG_ERROR(LOG_CORE, "OpenTrace: ParseTagInfo TAG_ERROR.");
1464         return TAG_ERROR;
1465     }
1466 
1467     if (tagGroups.size() == 0 || !CheckTagGroup(tagGroups, tagGroupTable)) {
1468         HILOG_ERROR(LOG_CORE, "OpenTrace: TAG_ERROR.");
1469         return TAG_ERROR;
1470     }
1471 
1472     TraceErrorCode ret = HandleServiceTraceOpen(tagGroups, allTags, tagGroupTable);
1473     if (ret != SUCCESS) {
1474         HILOG_ERROR(LOG_CORE, "OpenTrace: open fail.");
1475         return ret;
1476     }
1477     g_traceMode = SERVICE_MODE;
1478 
1479     DelSnapshotTraceFile();
1480     if (!IsHmKernel() && !g_serviceThreadIsStart) {
1481         // open SERVICE_MODE monitor thread
1482         auto it = []() {
1483             MonitorServiceTask();
1484         };
1485         std::thread auxiliaryTask(it);
1486         auxiliaryTask.detach();
1487     }
1488     g_sysInitParamTags = GetSysParamTags();
1489     HILOG_INFO(LOG_CORE, "OpenTrace: SERVICE_MODE open success.");
1490     return ret;
1491 }
1492 
OpenTrace(const std::string & args)1493 TraceErrorCode OpenTrace(const std::string &args)
1494 {
1495     std::lock_guard<std::mutex> lock(g_traceMutex);
1496     if (g_traceMode != CLOSE) {
1497         HILOG_ERROR(LOG_CORE, "OpenTrace: CALL_ERROR, g_traceMode:%{public}d.", static_cast<int>(g_traceMode));
1498         return CALL_ERROR;
1499     }
1500 
1501     if (!IsTraceMounted()) {
1502         HILOG_ERROR(LOG_CORE, "Hitrace OpenTrace: TRACE_NOT_SUPPORTED.");
1503         return TRACE_NOT_SUPPORTED;
1504     }
1505 
1506     std::map<std::string, TagCategory> allTags;
1507     std::map<std::string, std::vector<std::string>> tagGroupTable;
1508     if (!ParseTagInfo(allTags, tagGroupTable) || allTags.size() == 0 || tagGroupTable.size() == 0) {
1509         HILOG_ERROR(LOG_CORE, "Hitrace OpenTrace: ParseTagInfo TAG_ERROR.");
1510         return TAG_ERROR;
1511     }
1512     // parse args
1513     TraceParams cmdTraceParams;
1514     if (!ParseArgs(args, cmdTraceParams, allTags, tagGroupTable)) {
1515         HILOG_ERROR(LOG_CORE, "Hitrace OpenTrace: TAG_ERROR.");
1516         return TAG_ERROR;
1517     }
1518 
1519     TraceErrorCode ret = HandleTraceOpen(cmdTraceParams, allTags, tagGroupTable);
1520     if (ret != SUCCESS) {
1521         HILOG_ERROR(LOG_CORE, "Hitrace OpenTrace: CMD_MODE open failed.");
1522         return FILE_ERROR;
1523     }
1524     g_traceMode = CMD_MODE;
1525     HILOG_INFO(LOG_CORE, "Hitrace OpenTrace: CMD_MODE open success, args:%{public}s.", args.c_str());
1526     return ret;
1527 }
1528 
DumpTrace()1529 TraceRetInfo DumpTrace()
1530 {
1531     TraceRetInfo ret;
1532     HILOG_INFO(LOG_CORE, "DumpTrace start.");
1533     if (g_traceMode != SERVICE_MODE) {
1534         HILOG_ERROR(LOG_CORE, "DumpTrace: CALL_ERROR, g_traceMode:%{public}d.", static_cast<int>(g_traceMode));
1535         ret.errorCode = CALL_ERROR;
1536         return ret;
1537     }
1538 
1539     if (!CheckServiceRunning()) {
1540         HILOG_ERROR(LOG_CORE, "DumpTrace: TRACE_IS_OCCUPIED.");
1541         ret.errorCode = TRACE_IS_OCCUPIED;
1542         return ret;
1543     }
1544     std::lock_guard<std::mutex> lock(g_traceMutex);
1545     ret.errorCode = DumpTraceInner(ret.outputFiles);
1546     HILOG_INFO(LOG_CORE, "DumpTrace done.");
1547     return ret;
1548 }
1549 
DumpTrace(int timeLimit)1550 TraceRetInfo DumpTrace(int timeLimit)
1551 {
1552     HILOG_INFO(LOG_CORE, "DumpTrace with time limit start, time limit is %{public}d.", timeLimit);
1553     TraceRetInfo ret;
1554     if (timeLimit <= 0) {
1555         HILOG_ERROR(LOG_CORE, "DumpTrace: Illegal input.");
1556         ret.errorCode = CALL_ERROR;
1557         return ret;
1558     }
1559     {
1560         std::lock_guard<std::mutex> lock(g_traceMutex);
1561         g_timeLimit = timeLimit;
1562     }
1563     ret = DumpTrace();
1564     {
1565         std::lock_guard<std::mutex> lock(g_traceMutex);
1566         g_timeLimit = 0;
1567     }
1568     HILOG_INFO(LOG_CORE, "DumpTrace with time limit done.");
1569     return ret;
1570 }
1571 
DumpTraceOn()1572 TraceErrorCode DumpTraceOn()
1573 {
1574     std::lock_guard<std::mutex> lock(g_traceMutex);
1575     // check current trace status
1576     if (g_traceMode != CMD_MODE) {
1577         HILOG_ERROR(LOG_CORE, "DumpTraceOn: CALL_ERROR, g_traceMode:%{public}d.", static_cast<int>(g_traceMode));
1578         return CALL_ERROR;
1579     }
1580 
1581     if (!g_dumpEnd) {
1582         HILOG_ERROR(LOG_CORE, "DumpTraceOn: CALL_ERROR, record trace is dumping now.");
1583         return CALL_ERROR;
1584     }
1585 
1586     // start task thread
1587     auto it = []() {
1588         ProcessDumpTask();
1589     };
1590     std::thread task(it);
1591     task.detach();
1592     HILOG_INFO(LOG_CORE, "Recording trace on.");
1593     return SUCCESS;
1594 }
1595 
DumpTraceOff()1596 TraceRetInfo DumpTraceOff()
1597 {
1598     std::lock_guard<std::mutex> lock(g_traceMutex);
1599     TraceRetInfo ret;
1600     // check current trace status
1601     if (g_traceMode != CMD_MODE) {
1602         HILOG_ERROR(LOG_CORE, "DumpTraceOff: The current state is %{public}d, data exception.",
1603             static_cast<int>(g_traceMode));
1604         ret.errorCode = CALL_ERROR;
1605         ret.outputFiles = g_outputFilesForCmd;
1606         return ret;
1607     }
1608 
1609     g_dumpFlag = false;
1610     while (!g_dumpEnd) {
1611         usleep(UNIT_TIME);
1612         g_dumpFlag = false;
1613     }
1614     ret.errorCode = SUCCESS;
1615     ret.outputFiles = g_outputFilesForCmd;
1616     HILOG_INFO(LOG_CORE, "Recording trace off.");
1617     return ret;
1618 }
1619 
CloseTrace()1620 TraceErrorCode CloseTrace()
1621 {
1622     std::lock_guard<std::mutex> lock(g_traceMutex);
1623     HILOG_INFO(LOG_CORE, "CloseTrace start.");
1624     if (g_traceMode == CLOSE) {
1625         HILOG_INFO(LOG_CORE, "Trace already close.");
1626         return SUCCESS;
1627     }
1628 
1629     g_traceMode = CLOSE;
1630     // Waiting for the data drop task to end
1631     g_dumpFlag = false;
1632     while (!g_dumpEnd) {
1633         usleep(UNIT_TIME);
1634         g_dumpFlag = false;
1635     }
1636     OHOS::system::SetParameter("debug.hitrace.app_pid", "-1");
1637     std::map<std::string, TagCategory> allTags;
1638     std::map<std::string, std::vector<std::string>> tagGroupTable;
1639     if (!ParseTagInfo(allTags, tagGroupTable) || allTags.size() == 0 || tagGroupTable.size() == 0) {
1640         HILOG_ERROR(LOG_CORE, "CloseTrace: ParseTagInfo TAG_ERROR.");
1641         return TAG_ERROR;
1642     }
1643     TraceInit(allTags);
1644     TruncateFile();
1645     HILOG_INFO(LOG_CORE, "CloseTrace done.");
1646     return SUCCESS;
1647 }
1648 
GetTraceFilesTable()1649 std::vector<std::pair<std::string, int>> GetTraceFilesTable()
1650 {
1651     return g_traceFilesTable;
1652 }
1653 
SetTraceFilesTable(const std::vector<std::pair<std::string,int>> & traceFilesTable)1654 void SetTraceFilesTable(const std::vector<std::pair<std::string, int>>& traceFilesTable)
1655 {
1656     g_traceFilesTable = traceFilesTable;
1657 }
1658 
1659 } // Hitrace
1660 } // HiviewDFX
1661 } // OHOS
1662