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(¤tTime, &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