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 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