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