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 <algorithm>
19 #include <atomic>
20 #include <cinttypes>
21 #include <csignal>
22 #include <fstream>
23 #include <map>
24 #include <memory>
25 #include <mutex>
26 #include <set>
27 #include <sys/epoll.h>
28 #include <sys/prctl.h>
29 #include <sys/sysinfo.h>
30 #include <sys/wait.h>
31 #include <thread>
32 #include <unistd.h>
33
34 #include "common_define.h"
35 #include "common_utils.h"
36 #include "dynamic_buffer.h"
37 #include "hitrace_meter.h"
38 #include "hilog/log.h"
39 #include "parameters.h"
40 #include "securec.h"
41 #include "trace_file_utils.h"
42 #include "trace_json_parser.h"
43
44 namespace OHOS {
45 namespace HiviewDFX {
46 namespace Hitrace {
47 #ifdef LOG_DOMAIN
48 #undef LOG_DOMAIN
49 #define LOG_DOMAIN 0xD002D33
50 #endif
51 #ifdef LOG_TAG
52 #undef LOG_TAG
53 #define LOG_TAG "HitraceDump"
54 #endif
55 namespace {
56
57 struct TraceParams {
58 std::vector<std::string> tags;
59 std::vector<std::string> tagGroups;
60 std::string bufferSize;
61 std::string clockType;
62 std::string isOverWrite;
63 std::string outputFile;
64 int fileLimit;
65 int fileSize;
66 int appPid;
67 };
68
69 constexpr uint16_t MAGIC_NUMBER = 57161;
70 constexpr uint16_t VERSION_NUMBER = 1;
71 constexpr uint8_t FILE_RAW_TRACE = 0;
72 constexpr uint8_t HM_FILE_RAW_TRACE = 1;
73 constexpr uint64_t CACHE_TRACE_LOOP_SLEEP_TIME = 1;
74 constexpr int UNIT_TIME = 100000;
75 constexpr int ALIGNMENT_COEFFICIENT = 4;
76 constexpr int RECORD_LOOP_SLEEP = 1;
77
78 const int DEFAULT_BUFFER_SIZE = 12 * 1024;
79 const int DEFAULT_FILE_SIZE = 100 * 1024;
80 #ifdef HITRACE_UNITTEST
81 const int DEFAULT_CACHE_FILE_SIZE = 15 * 1024;
82 #else
83 const int DEFAULT_CACHE_FILE_SIZE = 150 * 1024;
84 #endif
85 #if defined(SNAPSHOT_TRACEBUFFER_SIZE) && (SNAPSHOT_TRACEBUFFER_SIZE != 0)
86 const int HM_DEFAULT_BUFFER_SIZE = SNAPSHOT_TRACEBUFFER_SIZE;
87 #else
88 const int HM_DEFAULT_BUFFER_SIZE = 144 * 1024;
89 #endif
90 const int SAVED_CMDLINES_SIZE = 3072; // 3M
91 const int BYTE_PER_KB = 1024;
92 const int BYTE_PER_MB = 1024 * 1024;
93 constexpr uint64_t S_TO_NS = 1000000000;
94 constexpr uint64_t S_TO_MS = 1000;
95 constexpr int32_t MAX_RATIO_UNIT = 1000;
96 const int MAX_NEW_TRACE_FILE_LIMIT = 5;
97 const int JUDGE_FILE_EXIST = 10; // Check whether the trace file exists every 10 times.
98 #if defined(SNAPSHOT_FILE_LIMIT) && (SNAPSHOT_FILE_LIMIT != 0)
99 const int SNAPSHOT_FILE_MAX_COUNT = SNAPSHOT_FILE_LIMIT;
100 #else
101 const int SNAPSHOT_FILE_MAX_COUNT = 20;
102 #endif
103
104 constexpr int DEFAULT_FULL_TRACE_LENGTH = 30;
105
106 struct alignas(ALIGNMENT_COEFFICIENT) TraceFileHeader {
107 uint16_t magicNumber {MAGIC_NUMBER};
108 uint8_t fileType {FILE_RAW_TRACE};
109 uint16_t versionNumber {VERSION_NUMBER};
110 uint32_t reserved {0};
111 };
112
113 enum ContentType : uint8_t {
114 CONTENT_TYPE_DEFAULT = 0,
115 CONTENT_TYPE_EVENTS_FORMAT = 1,
116 CONTENT_TYPE_CMDLINES = 2,
117 CONTENT_TYPE_TGIDS = 3,
118 CONTENT_TYPE_CPU_RAW = 4,
119 CONTENT_TYPE_HEADER_PAGE = 30,
120 CONTENT_TYPE_PRINTK_FORMATS = 31,
121 CONTENT_TYPE_KALLSYMS = 32
122 };
123
124 struct alignas(ALIGNMENT_COEFFICIENT) TraceFileContentHeader {
125 uint8_t type = CONTENT_TYPE_DEFAULT;
126 uint32_t length = 0;
127 };
128
129 struct PageHeader {
130 uint64_t timestamp = 0;
131 uint64_t size = 0;
132 uint8_t overwrite = 0;
133 uint8_t *startPos = nullptr;
134 uint8_t *endPos = nullptr;
135 };
136
137 struct ChildProcessRet {
138 uint8_t dumpStatus;
139 uint64_t traceStartTime;
140 uint64_t traceEndTime;
141 };
142
143 #ifndef PAGE_SIZE
144 constexpr size_t PAGE_SIZE = 4096;
145 #endif
146
147 const int BUFFER_SIZE = 256 * PAGE_SIZE; // 1M
148
149 std::atomic<bool> g_recordFlag(false);
150 std::atomic<bool> g_recordEnd(true);
151 std::atomic<bool> g_cacheFlag(false);
152 std::atomic<bool> g_cacheEnd(true);
153 std::mutex g_traceMutex;
154 std::mutex g_cacheTraceMutex;
155 std::mutex g_recordingOutputMutex;
156
157 bool g_serviceThreadIsStart = false;
158 uint64_t g_sysInitParamTags = 0;
159 uint8_t g_traceMode = TraceMode::CLOSE;
160 std::string g_traceRootPath;
161 uint8_t g_buffer[BUFFER_SIZE] = {0};
162 std::vector<std::pair<std::string, int>> g_traceFilesTable;
163 std::vector<std::string> g_recordingOutput;
164 int g_outputFileSize = 0;
165 int g_newTraceFileLimit = 0;
166 int g_writeFileLimit = 0;
167 bool g_needGenerateNewTraceFile = false;
168 bool g_needLimitFileSize = true;
169 uint64_t g_totalFileSizeLimit = 0;
170 uint64_t g_sliceMaxDuration = 0;
171 uint64_t g_traceStartTime = 0;
172 uint64_t g_traceEndTime = std::numeric_limits<uint64_t>::max(); // in nano seconds
173 uint64_t g_firstPageTimestamp = std::numeric_limits<uint64_t>::max();
174 uint64_t g_lastPageTimestamp = 0;
175 uint64_t g_utDestTraceStartTime = 0;
176 uint64_t g_utDestTraceEndTime = 0;
177 std::atomic<uint8_t> g_dumpStatus(TraceErrorCode::UNSET);
178 std::vector<TraceFileInfo> g_traceFileVec{};
179 std::vector<TraceFileInfo> g_cacheFileVec{};
180
181 TraceParams g_currentTraceParams = {};
182 std::shared_ptr<TraceJsonParser> g_traceJsonParser = nullptr;
183 std::atomic<uint8_t> g_interruptDump(0);
184
IsTraceOpen()185 bool IsTraceOpen()
186 {
187 return (g_traceMode & TraceMode::OPEN) != 0;
188 }
189
IsRecordOn()190 bool IsRecordOn()
191 {
192 return (g_traceMode & TraceMode::RECORD) != 0;
193 }
194
IsCacheOn()195 bool IsCacheOn()
196 {
197 return (g_traceMode & TraceMode::CACHE) != 0;
198 }
199
GetCurBootTime()200 uint64_t GetCurBootTime()
201 {
202 struct timespec bts = {0, 0};
203 clock_gettime(CLOCK_BOOTTIME, &bts);
204 return static_cast<uint64_t>(bts.tv_sec * S_TO_NS + bts.tv_nsec);
205 }
206
Split(const std::string & str,char delimiter)207 std::vector<std::string> Split(const std::string& str, char delimiter)
208 {
209 std::vector<std::string> res;
210 size_t startPos = 0;
211 for (size_t i = 0; i < str.size(); i++) {
212 if (str[i] == delimiter) {
213 res.push_back(str.substr(startPos, i - startPos));
214 startPos = i + 1;
215 }
216 }
217 if (startPos < str.size()) {
218 res.push_back(str.substr(startPos));
219 }
220 return res;
221 }
222
223 // Arch is 64bit when reserved = 0; Arch is 32bit when reserved = 1.
GetArchWordSize(TraceFileHeader & header)224 void GetArchWordSize(TraceFileHeader& header)
225 {
226 if (sizeof(void*) == sizeof(uint64_t)) {
227 header.reserved |= 0;
228 } else if (sizeof(void*) == sizeof(uint32_t)) {
229 header.reserved |= 1;
230 }
231 HILOG_INFO(LOG_CORE, "reserved with arch word info is %{public}d.", header.reserved);
232 }
233
GetCpuNums(TraceFileHeader & header)234 void GetCpuNums(TraceFileHeader& header)
235 {
236 const int maxCpuNums = 24;
237 int cpuNums = GetCpuProcessors();
238 if (cpuNums > maxCpuNums || cpuNums <= 0) {
239 HILOG_ERROR(LOG_CORE, "error: cpu_number is %{public}d.", cpuNums);
240 return;
241 }
242 header.reserved |= (static_cast<uint64_t>(cpuNums) << 1);
243 HILOG_INFO(LOG_CORE, "reserved with cpu number info is %{public}d.", header.reserved);
244 }
245
GenerateTraceHeaderContent()246 TraceFileHeader GenerateTraceHeaderContent()
247 {
248 TraceFileHeader header;
249 GetArchWordSize(header);
250 GetCpuNums(header);
251 if (IsHmKernel()) {
252 header.fileType = HM_FILE_RAW_TRACE;
253 }
254 return header;
255 }
256
CheckTags(const std::vector<std::string> & tags,const std::map<std::string,TraceTag> & allTags)257 bool CheckTags(const std::vector<std::string>& tags, const std::map<std::string, TraceTag>& allTags)
258 {
259 for (const auto &tag : tags) {
260 if (allTags.find(tag) == allTags.end()) {
261 HILOG_ERROR(LOG_CORE, "CheckTags: %{public}s is not provided.", tag.c_str());
262 return false;
263 }
264 }
265 return true;
266 }
267
CheckTagGroup(const std::vector<std::string> & tagGroups,const std::map<std::string,std::vector<std::string>> & tagGroupTable)268 bool CheckTagGroup(const std::vector<std::string>& tagGroups,
269 const std::map<std::string, std::vector<std::string>>& tagGroupTable)
270 {
271 for (auto groupName : tagGroups) {
272 if (tagGroupTable.find(groupName) == tagGroupTable.end()) {
273 HILOG_ERROR(LOG_CORE, "CheckTagGroup: %{public}s is not provided.", groupName.c_str());
274 return false;
275 }
276 }
277 return true;
278 }
279
WriteStrToFileInner(const std::string & filename,const std::string & str)280 bool WriteStrToFileInner(const std::string& filename, const std::string& str)
281 {
282 std::ofstream out;
283 out.open(filename, std::ios::out);
284 if (out.fail()) {
285 HILOG_ERROR(LOG_CORE, "WriteStrToFile: %{public}s open failed.", filename.c_str());
286 return false;
287 }
288 out << str;
289 if (out.bad()) {
290 HILOG_ERROR(LOG_CORE, "WriteStrToFile: %{public}s write failed.", filename.c_str());
291 out.close();
292 return false;
293 }
294 out.flush();
295 out.close();
296 return true;
297 }
298
WriteStrToFile(const std::string & filename,const std::string & str)299 bool WriteStrToFile(const std::string& filename, const std::string& str)
300 {
301 if (access((g_traceRootPath + filename).c_str(), W_OK) < 0) {
302 HILOG_WARN(LOG_CORE, "WriteStrToFile: Failed to access %{public}s, errno(%{public}d).",
303 (g_traceRootPath + filename).c_str(), errno);
304 return false;
305 }
306 return WriteStrToFileInner(g_traceRootPath + filename, str);
307 }
308
SetTraceNodeStatus(const std::string & path,bool enabled)309 void SetTraceNodeStatus(const std::string &path, bool enabled)
310 {
311 WriteStrToFile(path, enabled ? "1" : "0");
312 }
313
TruncateFile()314 void TruncateFile()
315 {
316 int fd = creat((g_traceRootPath + TRACE_NODE).c_str(), 0);
317 if (fd == -1) {
318 HILOG_ERROR(LOG_CORE, "TruncateFile: clear old trace failed.");
319 return;
320 }
321 close(fd);
322 return;
323 }
324
SetProperty(const std::string & property,const std::string & value)325 bool SetProperty(const std::string& property, const std::string& value)
326 {
327 bool result = OHOS::system::SetParameter(property, value);
328 if (!result) {
329 HILOG_ERROR(LOG_CORE, "SetProperty: set %{public}s failed.", value.c_str());
330 } else {
331 HILOG_INFO(LOG_CORE, "SetProperty: set %{public}s success.", value.c_str());
332 }
333 return result;
334 }
335
336 // close all trace node
TraceInit(const std::map<std::string,TraceTag> & allTags)337 void TraceInit(const std::map<std::string, TraceTag>& allTags)
338 {
339 // close all ftrace events
340 for (auto it = allTags.begin(); it != allTags.end(); it++) {
341 if (it->second.type != 1) {
342 continue;
343 }
344 for (size_t i = 0; i < it->second.enablePath.size(); i++) {
345 SetTraceNodeStatus(it->second.enablePath[i], false);
346 }
347 }
348 // close all user tags
349 SetProperty(TRACE_TAG_ENABLE_FLAGS, std::to_string(0));
350
351 // set buffer_size_kb 1
352 WriteStrToFile("buffer_size_kb", "1");
353
354 // close tracing_on
355 SetTraceNodeStatus(TRACING_ON_NODE, false);
356 }
357
358 // Open specific trace node
SetAllTags(const TraceParams & traceParams,const std::map<std::string,TraceTag> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable,std::vector<std::string> & tagFmts)359 void SetAllTags(const TraceParams& traceParams, const std::map<std::string, TraceTag>& allTags,
360 const std::map<std::string, std::vector<std::string>>& tagGroupTable,
361 std::vector<std::string>& tagFmts)
362 {
363 std::set<std::string> readyEnableTagList;
364 for (std::string tagName : traceParams.tags) {
365 readyEnableTagList.insert(tagName);
366 }
367
368 for (std::string groupName : traceParams.tagGroups) {
369 auto iter = tagGroupTable.find(groupName);
370 if (iter == tagGroupTable.end()) {
371 continue;
372 }
373 for (std::string tag : iter->second) {
374 readyEnableTagList.insert(tag);
375 }
376 }
377
378 uint64_t enabledUserTags = 0;
379 for (std::string tagName : readyEnableTagList) {
380 auto iter = allTags.find(tagName);
381 if (iter == allTags.end()) {
382 HILOG_ERROR(LOG_CORE, "tag<%{public}s> is invalid.", tagName.c_str());
383 continue;
384 }
385
386 if (iter->second.type == 0) {
387 enabledUserTags |= iter->second.tag;
388 }
389
390 if (iter->second.type == 1) {
391 for (const auto& path : iter->second.enablePath) {
392 SetTraceNodeStatus(path, true);
393 }
394 for (const auto& format : iter->second.formatPath) {
395 tagFmts.emplace_back(format);
396 }
397 }
398 }
399 SetProperty(TRACE_TAG_ENABLE_FLAGS, std::to_string(enabledUserTags));
400 }
401
SetClock(const std::string & clockType)402 void SetClock(const std::string& clockType)
403 {
404 const std::string traceClockPath = "trace_clock";
405 if (clockType.size() == 0) {
406 WriteStrToFile(traceClockPath, "boot"); //set default: boot
407 return;
408 }
409 std::string allClocks = ReadFile(traceClockPath, g_traceRootPath);
410 if (allClocks.find(clockType) == std::string::npos) {
411 HILOG_ERROR(LOG_CORE, "SetClock: %{public}s is non-existent, set to boot", clockType.c_str());
412 WriteStrToFile(traceClockPath, "boot"); // set default: boot
413 return;
414 }
415
416 allClocks.erase(allClocks.find_last_not_of(" \n") + 1);
417 allClocks.push_back(' ');
418
419 std::set<std::string> allClockTypes;
420 size_t curPos = 0;
421 for (size_t i = 0; i < allClocks.size(); i++) {
422 if (allClocks[i] == ' ') {
423 allClockTypes.insert(allClocks.substr(curPos, i - curPos));
424 curPos = i + 1;
425 }
426 }
427
428 std::string currentClockType;
429 for (auto i : allClockTypes) {
430 if (clockType.compare(i) == 0) {
431 HILOG_INFO(LOG_CORE, "SetClock: set clock %{public}s success.", clockType.c_str());
432 WriteStrToFile(traceClockPath, clockType);
433 return;
434 }
435 if (i[0] == '[') {
436 currentClockType = i;
437 }
438 }
439
440 const int marks = 2;
441 if (clockType.compare(currentClockType.substr(1, currentClockType.size() - marks)) == 0) {
442 HILOG_INFO(LOG_CORE, "SetClock: set clock %{public}s success.", clockType.c_str());
443 return;
444 }
445
446 HILOG_INFO(LOG_CORE, "SetClock: unknown %{public}s, change to default clock_type: boot.", clockType.c_str());
447 WriteStrToFile(traceClockPath, "boot"); // set default: boot
448 return;
449 }
450
SetTraceSetting(const TraceParams & traceParams,const std::map<std::string,TraceTag> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable,std::vector<std::string> & tagFmts)451 bool SetTraceSetting(const TraceParams& traceParams, const std::map<std::string, TraceTag>& allTags,
452 const std::map<std::string, std::vector<std::string>>& tagGroupTable,
453 std::vector<std::string>& tagFmts)
454 {
455 TraceInit(allTags);
456
457 TruncateFile();
458
459 SetAllTags(traceParams, allTags, tagGroupTable, tagFmts);
460
461 WriteStrToFile("current_tracer", "nop");
462 WriteStrToFile("buffer_size_kb", traceParams.bufferSize);
463
464 SetClock(traceParams.clockType);
465
466 if (traceParams.isOverWrite == "1") {
467 WriteStrToFile("options/overwrite", "1");
468 } else {
469 WriteStrToFile("options/overwrite", "0");
470 }
471
472 WriteStrToFile("saved_cmdlines_size", std::to_string(SAVED_CMDLINES_SIZE));
473 WriteStrToFile("options/record-tgid", "1");
474 WriteStrToFile("options/record-cmd", "1");
475 return true;
476 }
477
CheckPage(uint8_t contentType,uint8_t * page)478 bool CheckPage(uint8_t contentType, uint8_t* page)
479 {
480 const int pageThreshold = PAGE_SIZE / 2;
481
482 // Check raw_trace page size.
483 if (contentType >= CONTENT_TYPE_CPU_RAW && !IsHmKernel()) {
484 PageHeader *pageHeader = reinterpret_cast<PageHeader*>(&page);
485 if (pageHeader->size < static_cast<uint64_t>(pageThreshold)) {
486 return false;
487 }
488 }
489
490 return true;
491 }
492
CheckFileExist(const std::string & outputFile)493 bool CheckFileExist(const std::string& outputFile)
494 {
495 g_writeFileLimit++;
496 if (g_writeFileLimit > JUDGE_FILE_EXIST) {
497 g_writeFileLimit = 0;
498 if (access(outputFile.c_str(), F_OK) != 0) {
499 g_needGenerateNewTraceFile = true;
500 HILOG_INFO(LOG_CORE, "CheckFileExist access file:%{public}s failed, errno: %{public}d.",
501 outputFile.c_str(), errno);
502 return false;
503 }
504 }
505 return true;
506 }
507
SetTimeIntervalBoundary(int inputMaxDuration,uint64_t utTraceEndTime)508 TraceErrorCode SetTimeIntervalBoundary(int inputMaxDuration, uint64_t utTraceEndTime)
509 {
510 if (inputMaxDuration < 0) {
511 HILOG_ERROR(LOG_CORE, "DumpTrace: Illegal input: maxDuration = %d < 0.", inputMaxDuration);
512 return INVALID_MAX_DURATION;
513 }
514
515 uint64_t utNow = static_cast<uint64_t>(std::time(nullptr));
516 if (utTraceEndTime >= utNow) {
517 HILOG_WARN(LOG_CORE, "DumpTrace: Warning: traceEndTime is later than current time, set to current.");
518 utTraceEndTime = 0;
519 }
520 struct timespec bts = {0, 0};
521 clock_gettime(CLOCK_BOOTTIME, &bts);
522 uint64_t btNow = static_cast<uint64_t>(bts.tv_sec) + (static_cast<uint64_t>(bts.tv_nsec) != 0 ? 1 : 0);
523 uint64_t utBootTime = utNow - btNow;
524 if (utTraceEndTime == 0) {
525 g_traceEndTime = static_cast<uint64_t>(bts.tv_sec * S_TO_NS + bts.tv_nsec);
526 } else if (utTraceEndTime > utBootTime) {
527 // beware of input precision of seconds: add an extra second of tolerance
528 g_traceEndTime = (utTraceEndTime - utBootTime + 1) * S_TO_NS;
529 } else {
530 HILOG_ERROR(LOG_CORE,
531 "DumpTrace: traceEndTime:(%{public}" PRIu64 ") is earlier than boot_time:(%{public}" PRIu64 ").",
532 utTraceEndTime, utBootTime);
533 return OUT_OF_TIME;
534 }
535
536 uint64_t maxDuration = inputMaxDuration > 0 ? static_cast<uint64_t>(inputMaxDuration) + 1 : 0;
537 if (maxDuration > g_traceEndTime / S_TO_NS) {
538 HILOG_WARN(LOG_CORE, "maxDuration is larger than TraceEndTime boot clock.");
539 maxDuration = 0;
540 }
541 if (maxDuration > 0) {
542 g_traceStartTime = g_traceEndTime - maxDuration * S_TO_NS;
543 } else {
544 g_traceStartTime = 0;
545 }
546 return SUCCESS;
547 }
548
RestoreTimeIntervalBoundary()549 void RestoreTimeIntervalBoundary()
550 {
551 g_traceStartTime = 0;
552 g_traceEndTime = std::numeric_limits<uint64_t>::max();
553 }
554
GetFileSizeThresholdAndTraceTime(bool & isCpuRaw,uint8_t contentType,uint64_t & traceStartTime,uint64_t & traceEndTime,int & fileSizeThreshold)555 void GetFileSizeThresholdAndTraceTime(bool &isCpuRaw, uint8_t contentType, uint64_t &traceStartTime,
556 uint64_t &traceEndTime, int &fileSizeThreshold)
557 {
558 isCpuRaw = contentType >= CONTENT_TYPE_CPU_RAW && contentType < CONTENT_TYPE_HEADER_PAGE;
559 if (isCpuRaw) {
560 traceStartTime = g_traceStartTime;
561 traceEndTime = g_traceEndTime;
562 HILOG_INFO(LOG_CORE, "traceStartTime:(%{public}" PRIu64 "), traceEndTime:(%{public}" PRIu64 ").",
563 traceStartTime, traceEndTime);
564 }
565 if (g_cacheFlag.load()) {
566 fileSizeThreshold = DEFAULT_CACHE_FILE_SIZE * BYTE_PER_KB;
567 return;
568 }
569 if (g_currentTraceParams.fileSize != 0) {
570 fileSizeThreshold = g_currentTraceParams.fileSize * BYTE_PER_KB;
571 }
572 }
573
IsWriteFileOverflow(const bool isCpuRaw,const int & outputFileSize,const ssize_t & writeLen,const int & fileSizeThreshold)574 bool IsWriteFileOverflow(const bool isCpuRaw, const int &outputFileSize, const ssize_t& writeLen,
575 const int& fileSizeThreshold)
576 {
577 // attention: we only check file size threshold in CMD_MODE
578 if (!isCpuRaw || (!IsRecordOn() && !IsCacheOn()) || !g_needLimitFileSize) {
579 return false;
580 }
581 if (outputFileSize + writeLen + static_cast<int>(sizeof(TraceFileContentHeader)) >= fileSizeThreshold) {
582 HILOG_ERROR(LOG_CORE, "Failed to write, current round write file size exceeds the file size limit.");
583 return true;
584 }
585 if (writeLen > INT_MAX - BUFFER_SIZE) {
586 HILOG_ERROR(LOG_CORE, "Failed to write, write file length is nearly overflow.");
587 return true;
588 }
589 return false;
590 }
591
WriteFile(uint8_t contentType,const std::string & src,int outFd,const std::string & outputFile)592 bool WriteFile(uint8_t contentType, const std::string& src, int outFd, const std::string& outputFile)
593 {
594 std::string srcPath = CanonicalizeSpecPath(src.c_str());
595 int srcFd = open(srcPath.c_str(), O_RDONLY | O_NONBLOCK);
596 if (srcFd < 0) {
597 HILOG_ERROR(LOG_CORE, "WriteFile: open %{public}s failed.", src.c_str());
598 return false;
599 }
600 if (!CheckFileExist(outputFile)) {
601 HILOG_ERROR(LOG_CORE, "need generate new trace file, old file:%{public}s.", outputFile.c_str());
602 return false;
603 }
604 struct TraceFileContentHeader contentHeader;
605 contentHeader.type = contentType;
606 write(outFd, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
607 ssize_t writeLen = 0;
608 int count = 0;
609 const int maxCount = 2;
610
611 uint64_t traceStartTime = 0;
612 uint64_t traceEndTime = std::numeric_limits<uint64_t>::max();
613 int fileSizeThreshold = DEFAULT_FILE_SIZE * BYTE_PER_KB;
614 bool isCpuRaw = false;
615 GetFileSizeThresholdAndTraceTime(isCpuRaw, contentType, traceStartTime, traceEndTime, fileSizeThreshold);
616 bool printFirstPageTime = false;
617 while (true) {
618 int bytes = 0;
619 bool endFlag = false;
620 /* Write 1M at a time */
621 while (bytes <= (BUFFER_SIZE - static_cast<int>(PAGE_SIZE))) {
622 ssize_t readBytes = TEMP_FAILURE_RETRY(read(srcFd, g_buffer + bytes, PAGE_SIZE));
623 if (readBytes == 0) {
624 endFlag = true;
625 HILOG_DEBUG(LOG_CORE, "WriteFile: read %{public}s end.", src.c_str());
626 break;
627 } else if (readBytes < 0) {
628 endFlag = true;
629 HILOG_DEBUG(LOG_CORE, "WriteFile: read %{public}s, data size: %{public}zd failed, errno: %{public}d.",
630 src.c_str(), readBytes, errno);
631 break;
632 }
633
634 uint64_t pageTraceTime = 0;
635 if (memcpy_s(&pageTraceTime, sizeof(uint64_t), g_buffer + bytes, sizeof(uint64_t)) != EOK) {
636 HILOG_ERROR(LOG_CORE, "Failed to memcpy g_buffer to pageTraceTime.");
637 break;
638 }
639 if (traceEndTime < pageTraceTime) {
640 endFlag = true;
641 bytes += (printFirstPageTime == true ? readBytes : 0);
642 HILOG_INFO(LOG_CORE,
643 "Current pageTraceTime:(%{public}" PRIu64 ") is larger than traceEndTime:(%{public}" PRIu64 ")",
644 pageTraceTime, traceEndTime);
645 break;
646 }
647 if (pageTraceTime < traceStartTime) {
648 continue;
649 }
650 if (isCpuRaw) {
651 g_lastPageTimestamp = std::max(pageTraceTime, g_lastPageTimestamp);
652 if (UNEXPECTANTLY(!printFirstPageTime)) {
653 HILOG_INFO(LOG_CORE, "first page trace time:(%{public}" PRIu64 ")", pageTraceTime);
654 printFirstPageTime = true;
655 g_firstPageTimestamp = std::min(g_firstPageTimestamp, pageTraceTime);
656 }
657 }
658
659 if (CheckPage(contentType, g_buffer + bytes) == false) {
660 count++;
661 }
662 bytes += readBytes;
663 if (count >= maxCount) {
664 endFlag = true;
665 break;
666 }
667 }
668
669 ssize_t writeRet = TEMP_FAILURE_RETRY(write(outFd, g_buffer, bytes));
670 if (writeRet < 0) {
671 HILOG_WARN(LOG_CORE, "WriteFile Fail, errno: %{public}d.", errno);
672 } else {
673 if (writeRet != static_cast<ssize_t>(bytes)) {
674 HILOG_WARN(LOG_CORE, "Failed to write full info, writeLen: %{public}zd, FullLen: %{public}d.",
675 writeRet, bytes);
676 }
677 writeLen += writeRet;
678 }
679
680 if (IsWriteFileOverflow(isCpuRaw, g_outputFileSize, writeLen, fileSizeThreshold)) {
681 HILOG_WARN(LOG_CORE, "Write file over flow, fileZise: %{public}d, writeLen: %{public}zd, "
682 "FullLen: %{public}d.", g_outputFileSize, writeRet, bytes);
683 break;
684 }
685
686 if (endFlag == true) {
687 break;
688 }
689 }
690 contentHeader.length = static_cast<uint32_t>(writeLen);
691 uint32_t offset = contentHeader.length + sizeof(contentHeader);
692 off_t pos = lseek(outFd, 0, SEEK_CUR);
693 lseek(outFd, pos - offset, SEEK_SET);
694 write(outFd, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
695 lseek(outFd, pos, SEEK_SET);
696 close(srcFd);
697 if (isCpuRaw) {
698 if (writeLen > 0) {
699 g_dumpStatus = TraceErrorCode::SUCCESS;
700 } else if (g_dumpStatus == TraceErrorCode::UNSET) {
701 g_dumpStatus = TraceErrorCode::OUT_OF_TIME;
702 }
703 }
704 g_outputFileSize += static_cast<int>(offset);
705 g_needGenerateNewTraceFile = false;
706 HILOG_INFO(LOG_CORE, "WriteFile end, path: %{public}s, byte: %{public}zd. g_writeFileLimit: %{public}d",
707 src.c_str(), writeLen, g_writeFileLimit);
708 return true;
709 }
710
WriteEventFile(std::string & srcPath,int outFd)711 void WriteEventFile(std::string& srcPath, int outFd)
712 {
713 uint8_t buffer[PAGE_SIZE] = {0};
714 std::string srcSpecPath = CanonicalizeSpecPath(srcPath.c_str());
715 int srcFd = open(srcSpecPath.c_str(), O_RDONLY);
716 if (srcFd < 0) {
717 HILOG_ERROR(LOG_CORE, "WriteEventFile: open %{public}s failed.", srcPath.c_str());
718 return;
719 }
720 int64_t readLen = 0;
721 do {
722 int64_t len = read(srcFd, buffer, PAGE_SIZE);
723 if (len <= 0) {
724 break;
725 }
726 write(outFd, buffer, len);
727 readLen += len;
728 } while (true);
729 close(srcFd);
730 HILOG_INFO(LOG_CORE, "WriteEventFile end, path: %{public}s, data size: (%{public}" PRIu64 ").",
731 srcPath.c_str(), static_cast<uint64_t>(readLen));
732 }
733
WriteEventsFormat(int outFd,const std::string & outputFile)734 bool WriteEventsFormat(int outFd, const std::string& outputFile)
735 {
736 const std::string savedEventsFormatPath = TRACE_FILE_DEFAULT_DIR + TRACE_SAVED_EVENTS_FORMAT;
737 if (access(savedEventsFormatPath.c_str(), F_OK) != -1) {
738 return WriteFile(CONTENT_TYPE_EVENTS_FORMAT, savedEventsFormatPath, outFd, outputFile);
739 }
740
741 // write all trace formats into TRACE_SAVED_EVENTS_FORMAT file.
742 int fd = open(savedEventsFormatPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
743 if (fd < 0) {
744 HILOG_ERROR(LOG_CORE, "WriteEventsFormat: open %{public}s failed.", savedEventsFormatPath.c_str());
745 return false;
746 }
747 if (g_traceJsonParser == nullptr) {
748 g_traceJsonParser = std::make_shared<TraceJsonParser>();
749 }
750 if (!g_traceJsonParser->ParseTraceJson(PARSE_TRACE_FORMAT_INFO)) {
751 HILOG_ERROR(LOG_CORE, "WriteEventsFormat: Failed to parse trace format infos.");
752 close(fd);
753 return false;
754 }
755 auto allTags = g_traceJsonParser->GetAllTagInfos();
756 auto traceFormats = g_traceJsonParser->GetBaseFmtPath();
757 for (auto& tag : allTags) {
758 for (auto& fmt : tag.second.formatPath) {
759 traceFormats.emplace_back(fmt);
760 }
761 }
762 for (auto& traceFmt : traceFormats) {
763 std::string srcPath = g_traceRootPath + traceFmt;
764 if (access(srcPath.c_str(), R_OK) != -1) {
765 WriteEventFile(srcPath, fd);
766 }
767 }
768 close(fd);
769 HILOG_INFO(LOG_CORE, "WriteEventsFormat end. path: %{public}s.", savedEventsFormatPath.c_str());
770 return WriteFile(CONTENT_TYPE_EVENTS_FORMAT, savedEventsFormatPath, outFd, outputFile);
771 }
772
WriteHeaderPage(int outFd,const std::string & outputFile)773 bool WriteHeaderPage(int outFd, const std::string& outputFile)
774 {
775 if (IsHmKernel()) {
776 return true;
777 }
778 std::string headerPagePath = GetFilePath("events/header_page", g_traceRootPath);
779 return WriteFile(CONTENT_TYPE_HEADER_PAGE, headerPagePath, outFd, outputFile);
780 }
781
WritePrintkFormats(int outFd,const std::string & outputFile)782 bool WritePrintkFormats(int outFd, const std::string &outputFile)
783 {
784 if (IsHmKernel()) {
785 return true;
786 }
787 std::string printkFormatPath = GetFilePath("printk_formats", g_traceRootPath);
788 return WriteFile(CONTENT_TYPE_PRINTK_FORMATS, printkFormatPath, outFd, outputFile);
789 }
790
WriteKallsyms(int outFd)791 bool WriteKallsyms(int outFd)
792 {
793 /* not implement in hmkernel */
794 if (IsHmKernel()) {
795 return true;
796 }
797 /* not implement in linux */
798 return true;
799 }
800
HmWriteCpuRawInner(int outFd,const std::string & outputFile)801 bool HmWriteCpuRawInner(int outFd, const std::string& outputFile)
802 {
803 uint8_t type = CONTENT_TYPE_CPU_RAW;
804 std::string src = g_traceRootPath + "/trace_pipe_raw";
805
806 if (!WriteFile(type, src, outFd, outputFile)) {
807 return false;
808 }
809
810 if (g_dumpStatus) {
811 HILOG_ERROR(LOG_CORE, "HmWriteCpuRawInner failed, errno: %{public}d.", static_cast<int>(g_dumpStatus.load()));
812 return false;
813 }
814
815 return true;
816 }
817
WriteCpuRawInner(int outFd,const std::string & outputFile)818 bool WriteCpuRawInner(int outFd, const std::string& outputFile)
819 {
820 int cpuNums = GetCpuProcessors();
821 uint8_t type = CONTENT_TYPE_CPU_RAW;
822 for (int i = 0; i < cpuNums; i++) {
823 std::string src = g_traceRootPath + "per_cpu/cpu" + std::to_string(i) + "/trace_pipe_raw";
824 if (!WriteFile(static_cast<uint8_t>(type + i), src, outFd, outputFile)) {
825 return false;
826 }
827 }
828 if (g_dumpStatus) {
829 HILOG_ERROR(LOG_CORE, "WriteCpuRawInner failed, errno: %{public}d.", static_cast<int>(g_dumpStatus.load()));
830 return false;
831 }
832 return true;
833 }
834
WriteCpuRaw(int outFd,const std::string & outputFile)835 bool WriteCpuRaw(int outFd, const std::string& outputFile)
836 {
837 if (!IsHmKernel()) {
838 return WriteCpuRawInner(outFd, outputFile);
839 } else {
840 return HmWriteCpuRawInner(outFd, outputFile);
841 }
842 }
843
WriteCmdlines(int outFd,const std::string & outputFile)844 bool WriteCmdlines(int outFd, const std::string& outputFile)
845 {
846 std::string cmdlinesPath = GetFilePath("saved_cmdlines", g_traceRootPath);
847 return WriteFile(CONTENT_TYPE_CMDLINES, cmdlinesPath, outFd, outputFile);
848 }
849
WriteTgids(int outFd,const std::string & outputFile)850 bool WriteTgids(int outFd, const std::string& outputFile)
851 {
852 std::string tgidsPath = GetFilePath("saved_tgids", g_traceRootPath);
853 return WriteFile(CONTENT_TYPE_TGIDS, tgidsPath, outFd, outputFile);
854 }
855
GenerateNewFile(int & outFd,std::string & outPath,const TRACE_TYPE traceType)856 bool GenerateNewFile(int& outFd, std::string& outPath, const TRACE_TYPE traceType)
857 {
858 if (access(outPath.c_str(), F_OK) == 0) {
859 return true;
860 }
861 std::string outputFileName = GenerateTraceFileName(traceType);
862 outPath = CanonicalizeSpecPath(outputFileName.c_str());
863 outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
864 if (outFd < 0) {
865 g_newTraceFileLimit++;
866 HILOG_ERROR(LOG_CORE, "open %{public}s failed, errno: %{public}d.", outPath.c_str(), errno);
867 }
868 if (g_newTraceFileLimit > MAX_NEW_TRACE_FILE_LIMIT) {
869 HILOG_ERROR(LOG_CORE, "create new trace file %{public}s limited.", outPath.c_str());
870 return false;
871 }
872 g_needGenerateNewTraceFile = true;
873 return true;
874 }
875
SetFileInfo(const std::string outPath,const uint64_t & firstPageTimestamp,const uint64_t & lastPageTimestamp,TraceFileInfo & traceFileInfo)876 bool SetFileInfo(const std::string outPath, const uint64_t& firstPageTimestamp,
877 const uint64_t& lastPageTimestamp, TraceFileInfo& traceFileInfo)
878 {
879 std::string newFileName;
880 if (!RenameTraceFile(outPath, newFileName, firstPageTimestamp, lastPageTimestamp)) {
881 HILOG_INFO(LOG_CORE, "rename failed, outPath: %{public}s.", outPath.c_str());
882 return false;
883 }
884 time_t firstPageTime = 0;
885 time_t lastPageTime = 0;
886 if (!ConvertPageTraceTimeToUtTime(firstPageTimestamp, firstPageTime) ||
887 !ConvertPageTraceTimeToUtTime(lastPageTimestamp, lastPageTime)) {
888 return false;
889 }
890 uint64_t traceFileSize = 0;
891 if (!GetFileSize(newFileName, traceFileSize)) {
892 return false;
893 }
894 traceFileInfo.filename = newFileName;
895 traceFileInfo.traceStartTime = static_cast<uint64_t>(firstPageTime);
896 traceFileInfo.traceEndTime = static_cast<uint64_t>(lastPageTime);
897 traceFileInfo.fileSize = traceFileSize;
898 return true;
899 }
900
GetTraceFileFromVec(const uint64_t & inputTraceStartTime,const uint64_t & inputTraceEndTime,std::vector<TraceFileInfo> & fileVec,std::vector<std::string> & outputFiles)901 void GetTraceFileFromVec(const uint64_t& inputTraceStartTime, const uint64_t& inputTraceEndTime,
902 std::vector<TraceFileInfo>& fileVec, std::vector<std::string>& outputFiles)
903 {
904 for (auto it = fileVec.begin(); it != fileVec.end(); it++) {
905 HILOG_INFO(LOG_CORE, "GetTraceFileFromVec: %{public}s, [(%{public}" PRIu64 ", %{public}" PRIu64 "].",
906 (*it).filename.c_str(), (*it).traceStartTime, (*it).traceEndTime);
907 if ((((*it).traceStartTime >= inputTraceStartTime && (*it).traceStartTime <= inputTraceEndTime) ||
908 ((*it).traceEndTime >= inputTraceStartTime && (*it).traceEndTime <= inputTraceEndTime) ||
909 ((*it).traceStartTime <= inputTraceStartTime && (*it).traceEndTime >= inputTraceEndTime)) &&
910 ((*it).traceEndTime - (*it).traceStartTime < 2000)) { // 2000 : max trace duration 2000s
911 outputFiles.push_back((*it).filename);
912 HILOG_INFO(LOG_CORE, "Put file: %{public}s into outputFiles.", (*it).filename.c_str());
913 }
914 }
915 }
916
SearchTraceFiles(const uint64_t & inputTraceStartTime,const uint64_t & inputTraceEndTime,std::vector<std::string> & outputFiles)917 void SearchTraceFiles(const uint64_t& inputTraceStartTime, const uint64_t& inputTraceEndTime,
918 std::vector<std::string>& outputFiles)
919 {
920 GetTraceFileFromVec(inputTraceStartTime, inputTraceEndTime, g_cacheFileVec, outputFiles);
921 GetTraceFileFromVec(inputTraceStartTime, inputTraceEndTime, g_traceFileVec, outputFiles);
922 }
923
CacheTraceLoop(const std::string & outputFileName)924 bool CacheTraceLoop(const std::string &outputFileName)
925 {
926 std::lock_guard<std::mutex> lock(g_cacheTraceMutex);
927 int fileSizeThreshold = DEFAULT_CACHE_FILE_SIZE * BYTE_PER_KB;
928 g_firstPageTimestamp = UINT64_MAX;
929 g_lastPageTimestamp = 0;
930 g_outputFileSize = 0;
931 std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
932 int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
933 if (outFd < 0) {
934 HILOG_ERROR(LOG_CORE, "open %{public}s failed, errno: %{public}d.", outPath.c_str(), errno);
935 return false;
936 }
937 MarkClockSync(g_traceRootPath);
938 struct TraceFileHeader header = GenerateTraceHeaderContent();
939 uint64_t sliceDuration = 0;
940 do {
941 g_needGenerateNewTraceFile = false;
942 ssize_t writeRet = TEMP_FAILURE_RETRY(write(outFd, reinterpret_cast<char *>(&header), sizeof(header)));
943 if (writeRet < 0) {
944 HILOG_WARN(LOG_CORE, "Failed to write trace file header, errno: %{public}s, headerLen: %{public}zu.",
945 strerror(errno), sizeof(header));
946 close(outFd);
947 return false;
948 }
949 WriteEventsFormat(outFd, outPath);
950 while (g_cacheFlag.load()) {
951 if (g_outputFileSize > fileSizeThreshold) {
952 break;
953 }
954 struct timespec bts = {0, 0};
955 clock_gettime(CLOCK_BOOTTIME, &bts);
956 uint64_t startTime = static_cast<uint64_t>(bts.tv_sec * S_TO_NS + bts.tv_nsec);
957 sleep(CACHE_TRACE_LOOP_SLEEP_TIME);
958 if (!WriteCpuRaw(outFd, outPath)) {
959 break;
960 }
961 clock_gettime(CLOCK_BOOTTIME, &bts);
962 uint64_t endTime = static_cast<uint64_t>(bts.tv_sec * S_TO_NS + bts.tv_nsec);
963 uint64_t timeDiff = (endTime - startTime) / S_TO_NS;
964 sliceDuration += timeDiff;
965 if (sliceDuration >= g_sliceMaxDuration || g_interruptDump.load() == 1) {
966 sliceDuration = 0;
967 break;
968 }
969 }
970 WriteCmdlines(outFd, outPath);
971 WriteTgids(outFd, outPath);
972 WriteHeaderPage(outFd, outPath);
973 WritePrintkFormats(outFd, outPath);
974 WriteKallsyms(outFd);
975 if (!GenerateNewFile(outFd, outPath, TRACE_CACHE)) {
976 HILOG_INFO(LOG_CORE, "CacheTraceLoop access file:%{public}s failed, errno: %{public}d.",
977 outPath.c_str(), errno);
978 close(outFd);
979 return false;
980 }
981 } while (g_needGenerateNewTraceFile);
982 close(outFd);
983 TraceFileInfo traceFileInfo;
984 if (!SetFileInfo(outPath, g_firstPageTimestamp, g_lastPageTimestamp, traceFileInfo)) {
985 RemoveFile(outPath);
986 return false;
987 }
988 g_cacheFileVec.push_back(traceFileInfo);
989 return true;
990 }
991
ProcessCacheTask()992 void ProcessCacheTask()
993 {
994 const std::string threadName = "CacheTraceTask";
995 prctl(PR_SET_NAME, threadName.c_str());
996 while (g_cacheFlag.load()) {
997 std::string outputFileName = GenerateTraceFileName(TRACE_CACHE);
998 if (CacheTraceLoop(outputFileName)) {
999 ClearCacheTraceFileBySize(g_cacheFileVec, g_totalFileSizeLimit);
1000 HILOG_INFO(LOG_CORE, "ProcessCacheTask: save cache file.");
1001 } else {
1002 break;
1003 }
1004 }
1005 g_cacheEnd.store(true);
1006 HILOG_INFO(LOG_CORE, "ProcessCacheTask: trace cache thread exit.");
1007 }
1008
RecordTraceLoop(const std::string & outputFileName,bool isLimited)1009 bool RecordTraceLoop(const std::string& outputFileName, bool isLimited)
1010 {
1011 g_outputFileSize = 0;
1012 std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
1013 int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
1014 if (outFd < 0) {
1015 HILOG_ERROR(LOG_CORE, "open %{public}s failed, errno: %{public}d.", outPath.c_str(), errno);
1016 return false;
1017 }
1018 int fileSizeThreshold = DEFAULT_FILE_SIZE * BYTE_PER_KB;
1019 if (g_currentTraceParams.fileSize != 0) {
1020 fileSizeThreshold = g_currentTraceParams.fileSize * BYTE_PER_KB;
1021 }
1022 MarkClockSync(g_traceRootPath);
1023 struct TraceFileHeader header = GenerateTraceHeaderContent();
1024 do {
1025 g_needGenerateNewTraceFile = false;
1026 ssize_t writeRet = TEMP_FAILURE_RETRY(write(outFd, reinterpret_cast<char *>(&header), sizeof(header)));
1027 if (writeRet < 0) {
1028 HILOG_WARN(LOG_CORE, "Failed to write trace file header, errno: %{public}s, headerLen: %{public}zu.",
1029 strerror(errno), sizeof(header));
1030 close(outFd);
1031 return false;
1032 }
1033 WriteEventsFormat(outFd, outPath);
1034 while (g_recordFlag.load()) {
1035 if (isLimited && g_outputFileSize > fileSizeThreshold) {
1036 break;
1037 }
1038 sleep(RECORD_LOOP_SLEEP);
1039 g_traceEndTime = GetCurBootTime();
1040 if (!WriteCpuRaw(outFd, outPath)) {
1041 break;
1042 }
1043 }
1044 WriteCmdlines(outFd, outPath);
1045 WriteTgids(outFd, outPath);
1046 WriteHeaderPage(outFd, outPath);
1047 WritePrintkFormats(outFd, outPath);
1048 WriteKallsyms(outFd);
1049 if (!GenerateNewFile(outFd, outPath, TRACE_RECORDING)) {
1050 HILOG_INFO(LOG_CORE, "RecordTraceLoop access file:%{public}s failed, errno: %{public}d.",
1051 outPath.c_str(), errno);
1052 close(outFd);
1053 return false;
1054 }
1055 } while (g_needGenerateNewTraceFile);
1056 close(outFd);
1057 g_traceEndTime = std::numeric_limits<uint64_t>::max();
1058 return true;
1059 }
1060
1061 /**
1062 * read trace data loop
1063 * g_recordFlag: true = open,false = close
1064 * g_recordEnd: true = end,false = not end
1065 * if user has own output file, Output all data to the file specified by the user;
1066 * if not, Then place all the result files in /data/log/hitrace/ and package them once in 96M.
1067 */
ProcessRecordTask()1068 void ProcessRecordTask()
1069 {
1070 {
1071 std::lock_guard<std::mutex> lock(g_recordingOutputMutex);
1072 g_recordingOutput = {};
1073 }
1074 const std::string threadName = "TraceDumpTask";
1075 prctl(PR_SET_NAME, threadName.c_str());
1076 HILOG_INFO(LOG_CORE, "ProcessRecordTask: trace dump thread start.");
1077
1078 if (!IsRootVersion()) {
1079 // clear old record file before record tracing start.
1080 DelOldRecordTraceFile(g_currentTraceParams.fileLimit);
1081 }
1082
1083 // if input filesize = 0, trace file should not be cut in root version.
1084 if (g_currentTraceParams.fileSize == 0 && IsRootVersion()) {
1085 g_needLimitFileSize = false;
1086 std::string outputFileName = g_currentTraceParams.outputFile.empty() ?
1087 GenerateTraceFileName(TRACE_RECORDING) : g_currentTraceParams.outputFile;
1088 if (RecordTraceLoop(outputFileName, g_needLimitFileSize)) {
1089 std::lock_guard<std::mutex> lock(g_recordingOutputMutex);
1090 g_recordingOutput.push_back(outputFileName);
1091 }
1092 g_recordEnd.store(true);
1093 g_needLimitFileSize = true;
1094 return;
1095 }
1096
1097 while (g_recordFlag.load()) {
1098 if (!IsRootVersion()) {
1099 std::lock_guard<std::mutex> lock(g_recordingOutputMutex);
1100 ClearOldTraceFile(g_recordingOutput, g_currentTraceParams.fileLimit);
1101 }
1102 // Generate file name
1103 std::string outputFileName = GenerateTraceFileName(TRACE_RECORDING);
1104 if (RecordTraceLoop(outputFileName, true)) {
1105 std::lock_guard<std::mutex> lock(g_recordingOutputMutex);
1106 g_recordingOutput.push_back(outputFileName);
1107 } else {
1108 break;
1109 }
1110 }
1111 HILOG_INFO(LOG_CORE, "ProcessRecordTask: trace dump thread exit.");
1112 g_recordEnd.store(true);
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 = GenerateTraceHeaderContent();
1124 ssize_t writeRet = TEMP_FAILURE_RETRY(write(outFd, reinterpret_cast<char*>(&header), sizeof(header)));
1125 if (writeRet < 0) {
1126 HILOG_WARN(LOG_CORE, "Failed to write trace file header, errno: %{public}s, headerLen: %{public}zu.",
1127 strerror(errno), sizeof(header));
1128 close(outFd);
1129 return false;
1130 }
1131
1132 if (WriteEventsFormat(outFd, outPath) && WriteCpuRaw(outFd, outPath) &&
1133 WriteCmdlines(outFd, outPath) && WriteTgids(outFd, outPath) &&
1134 WriteHeaderPage(outFd, outPath) && WritePrintkFormats(outFd, outPath) &&
1135 WriteKallsyms(outFd)) {
1136 fsync(outFd);
1137 close(outFd);
1138 return true;
1139 }
1140 HILOG_ERROR(LOG_CORE, "ReadRawTrace failed.");
1141 fsync(outFd);
1142 close(outFd);
1143 return false;
1144 }
1145
SetProcessName(std::string & processName)1146 void SetProcessName(std::string& processName)
1147 {
1148 if (processName.size() <= 0) {
1149 return;
1150 }
1151
1152 const int maxNameLen = 16;
1153 std::string setName;
1154 if (processName.size() > maxNameLen) {
1155 setName = processName.substr(0, maxNameLen);
1156 } else {
1157 setName = processName;
1158 }
1159
1160 prctl(PR_SET_NAME, setName.c_str(), nullptr, nullptr, nullptr);
1161 HILOG_INFO(LOG_CORE, "New process: %{public}s.", setName.c_str());
1162 }
1163
TimeoutSignalHandler(int signum)1164 void TimeoutSignalHandler(int signum)
1165 {
1166 if (signum == SIGUSR1) {
1167 _exit(EXIT_SUCCESS);
1168 }
1169 }
1170
EpollWaitforChildProcess(pid_t & pid,int & pipefd)1171 bool EpollWaitforChildProcess(pid_t& pid, int& pipefd)
1172 {
1173 int epollfd = epoll_create1(0);
1174 if (epollfd == -1) {
1175 HILOG_ERROR(LOG_CORE, "epoll_create1 error.");
1176 return false;
1177 }
1178
1179 struct epoll_event event;
1180 event.events = EPOLLIN;
1181 event.data.fd = pipefd;
1182 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, pipefd, &event) == -1) {
1183 HILOG_ERROR(LOG_CORE, "epoll_ctl error.");
1184 return false;
1185 }
1186
1187 struct epoll_event events[1];
1188 constexpr int waitTimeoutMs = 10000; // 10000ms = 10s
1189 int numEvents = TEMP_FAILURE_RETRY(epoll_wait(epollfd, events, 1, waitTimeoutMs));
1190 if (numEvents <= 0) {
1191 if (numEvents == -1) {
1192 HILOG_ERROR(LOG_CORE, "epoll_wait error, error: (%{public}s).", strerror(errno));
1193 } else {
1194 HILOG_ERROR(LOG_CORE, "epoll_wait timeout.");
1195 }
1196 if (waitpid(pid, nullptr, WNOHANG) <= 0) {
1197 HILOG_ERROR(LOG_CORE, "kill timeout child process.");
1198 kill(pid, SIGUSR1);
1199 }
1200 close(pipefd);
1201 close(epollfd);
1202 return false;
1203 }
1204 ChildProcessRet retVal;
1205 read(pipefd, &retVal, sizeof(retVal));
1206 g_dumpStatus = retVal.dumpStatus;
1207 g_firstPageTimestamp = retVal.traceStartTime;
1208 g_lastPageTimestamp = retVal.traceEndTime;
1209
1210 close(pipefd);
1211 close(epollfd);
1212 if (waitpid(pid, nullptr, 0) <= 0) {
1213 HILOG_ERROR(LOG_CORE, "wait HitraceDump(%{public}d) exit failed, errno: (%{public}d)", pid, errno);
1214 }
1215 return true;
1216 }
1217
DumpTraceInner(std::vector<std::string> & outputFiles)1218 TraceErrorCode DumpTraceInner(std::vector<std::string>& outputFiles)
1219 {
1220 int pipefd[2];
1221 if (pipe(pipefd) == -1) {
1222 HILOG_ERROR(LOG_CORE, "pipe creation error.");
1223 return TraceErrorCode::PIPE_CREATE_ERROR;
1224 }
1225
1226 std::string outputFileName = GenerateTraceFileName(TRACE_SNAPSHOT);
1227 std::string reOutPath = CanonicalizeSpecPath(outputFileName.c_str());
1228 g_dumpStatus = TraceErrorCode::UNSET;
1229 /*Child process handles task, Father process wait.*/
1230 pid_t pid = fork();
1231 if (pid < 0) {
1232 HILOG_ERROR(LOG_CORE, "fork error.");
1233 return TraceErrorCode::FORK_ERROR;
1234 } else if (pid == 0) {
1235 signal(SIGUSR1, TimeoutSignalHandler);
1236 close(pipefd[0]);
1237 std::string processName = "HitraceDump";
1238 SetProcessName(processName);
1239 MarkClockSync(g_traceRootPath);
1240 constexpr int waitTime = 10000; // 10ms
1241 usleep(waitTime);
1242 if (ReadRawTrace(reOutPath)) {
1243 g_dumpStatus = TraceErrorCode::SUCCESS;
1244 }
1245 HILOG_DEBUG(LOG_CORE, "%{public}s exit.", processName.c_str());
1246 ChildProcessRet retVal;
1247 retVal.dumpStatus = g_dumpStatus;
1248 retVal.traceStartTime = g_firstPageTimestamp;
1249 retVal.traceEndTime = g_lastPageTimestamp;
1250 write(pipefd[1], &retVal, sizeof(retVal));
1251 _exit(EXIT_SUCCESS);
1252 } else {
1253 close(pipefd[1]);
1254 }
1255
1256 if (!EpollWaitforChildProcess(pid, pipefd[0])) {
1257 return TraceErrorCode::EPOLL_WAIT_ERROR;
1258 }
1259
1260 SearchTraceFiles(g_utDestTraceStartTime, g_utDestTraceEndTime, outputFiles);
1261 if (g_dumpStatus) { // trace generation error
1262 if (remove(reOutPath.c_str()) == 0) {
1263 HILOG_INFO(LOG_CORE, "Delete outpath:%{public}s success.", reOutPath.c_str());
1264 } else {
1265 HILOG_INFO(LOG_CORE, "Delete outpath:%{public}s failed.", reOutPath.c_str());
1266 }
1267 } else if (access(reOutPath.c_str(), F_OK) != 0) { // trace access error
1268 HILOG_ERROR(LOG_CORE, "DumpTraceInner: write %{public}s failed.", outputFileName.c_str());
1269 } else {
1270 HILOG_INFO(LOG_CORE, "Output: %{public}s.", reOutPath.c_str());
1271 TraceFileInfo traceFileInfo;
1272 if (!SetFileInfo(reOutPath, g_firstPageTimestamp, g_lastPageTimestamp, traceFileInfo)) {
1273 // trace rename error
1274 HILOG_ERROR(LOG_CORE, "SetFileInfo: set %{public}s info failed.", reOutPath.c_str());
1275 RemoveFile(reOutPath);
1276 } else { // success
1277 g_traceFileVec.push_back(traceFileInfo);
1278 outputFiles.push_back(traceFileInfo.filename);
1279 }
1280 }
1281 if (g_traceJsonParser == nullptr) {
1282 g_traceJsonParser = std::make_shared<TraceJsonParser>();
1283 }
1284 if (!g_traceJsonParser->ParseTraceJson(TRACE_SNAPSHOT_FILE_AGE)) {
1285 HILOG_WARN(LOG_CORE, "DumpTraceInner: Failed to parse TRACE_SNAPSHOT_FILE_AGE.");
1286 }
1287 if ((!IsRootVersion()) || g_traceJsonParser->GetSnapShotFileAge()) {
1288 DelSnapshotTraceFile(SNAPSHOT_FILE_MAX_COUNT, g_traceFileVec);
1289 }
1290
1291 if (outputFiles.empty()) {
1292 return (g_dumpStatus != 0) ? static_cast<TraceErrorCode>(g_dumpStatus.load()) : TraceErrorCode::FILE_ERROR;
1293 }
1294 return TraceErrorCode::SUCCESS;
1295 }
1296
GetSysParamTags()1297 uint64_t GetSysParamTags()
1298 {
1299 return OHOS::system::GetUintParameter<uint64_t>(TRACE_TAG_ENABLE_FLAGS, 0);
1300 }
1301
CheckParam()1302 bool CheckParam()
1303 {
1304 uint64_t currentTags = GetSysParamTags();
1305 if (currentTags == g_sysInitParamTags) {
1306 return true;
1307 }
1308
1309 if (currentTags == 0) {
1310 HILOG_ERROR(LOG_CORE, "allowed tags are cleared, should restart.");
1311 return false;
1312 }
1313 HILOG_ERROR(LOG_CORE, "trace is being used, should restart.");
1314 return false;
1315 }
1316
1317 /**
1318 * SERVICE_MODE is running, check param and tracing_on.
1319 */
CheckServiceRunning()1320 bool CheckServiceRunning()
1321 {
1322 if (CheckParam() && IsTracingOn(g_traceRootPath)) {
1323 return true;
1324 }
1325 return false;
1326 }
1327
CpuBufferBalanceTask()1328 void CpuBufferBalanceTask()
1329 {
1330 g_serviceThreadIsStart = true;
1331 const std::string threadName = "CpuBufferBalancer";
1332 prctl(PR_SET_NAME, threadName.c_str());
1333 HILOG_INFO(LOG_CORE, "CpuBufferBalanceTask: monitor thread start.");
1334 const int intervalTime = 15;
1335 while (IsTraceOpen() && CheckServiceRunning()) {
1336 sleep(intervalTime);
1337
1338 const int cpuNums = GetCpuProcessors();
1339 std::vector<int> result;
1340 std::unique_ptr<DynamicBuffer> dynamicBuffer = std::make_unique<DynamicBuffer>(g_traceRootPath, cpuNums);
1341 dynamicBuffer->CalculateBufferSize(result);
1342
1343 if (static_cast<int>(result.size()) != cpuNums) {
1344 HILOG_ERROR(LOG_CORE, "CalculateAllNewBufferSize failed.");
1345 break;
1346 }
1347
1348 for (size_t i = 0; i < result.size(); i++) {
1349 HILOG_DEBUG(LOG_CORE, "cpu%{public}zu set size %{public}d.", i, result[i]);
1350 std::string path = "per_cpu/cpu" + std::to_string(i) + "/buffer_size_kb";
1351 WriteStrToFile(path, std::to_string(result[i]));
1352 }
1353 }
1354 HILOG_INFO(LOG_CORE, "CpuBufferBalanceTask: monitor thread exit.");
1355 g_serviceThreadIsStart = false;
1356 }
1357
StartCpuBufferBalanceService()1358 void StartCpuBufferBalanceService()
1359 {
1360 if (!IsHmKernel() && !g_serviceThreadIsStart) {
1361 // open monitor thread
1362 auto it = []() {
1363 CpuBufferBalanceTask();
1364 };
1365 std::thread auxiliaryTask(it);
1366 auxiliaryTask.detach();
1367 }
1368 }
1369
PreWriteEventsFormat(const std::vector<std::string> & eventFormats)1370 bool PreWriteEventsFormat(const std::vector<std::string>& eventFormats)
1371 {
1372 DelSavedEventsFormat();
1373 const std::string savedEventsFormatPath = TRACE_FILE_DEFAULT_DIR + TRACE_SAVED_EVENTS_FORMAT;
1374 int fd = open(savedEventsFormatPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
1375 if (fd < 0) {
1376 HILOG_ERROR(LOG_CORE, "PreWriteEventsFormat: open %{public}s failed.", savedEventsFormatPath.c_str());
1377 return false;
1378 }
1379 for (auto& format : eventFormats) {
1380 std::string srcPath = g_traceRootPath + format;
1381 if (access(srcPath.c_str(), R_OK) != -1) {
1382 WriteEventFile(srcPath, fd);
1383 }
1384 }
1385 close(fd);
1386 HILOG_INFO(LOG_CORE, "PreWriteEventsFormat end.");
1387 return true;
1388 }
1389
HandleTraceOpen(const TraceParams & traceParams,const std::map<std::string,TraceTag> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable,std::vector<std::string> & tagFmts)1390 TraceErrorCode HandleTraceOpen(const TraceParams& traceParams,
1391 const std::map<std::string, TraceTag>& allTags,
1392 const std::map<std::string, std::vector<std::string>>& tagGroupTable,
1393 std::vector<std::string>& tagFmts)
1394 {
1395 if (!SetTraceSetting(traceParams, allTags, tagGroupTable, tagFmts)) {
1396 return TraceErrorCode::FILE_ERROR;
1397 }
1398 SetTraceNodeStatus(TRACING_ON_NODE, true);
1399 PreWriteEventsFormat(tagFmts);
1400 g_currentTraceParams = traceParams;
1401 return TraceErrorCode::SUCCESS;
1402 }
1403
HandleDefaultTraceOpen(const std::vector<std::string> & tagGroups)1404 TraceErrorCode HandleDefaultTraceOpen(const std::vector<std::string>& tagGroups)
1405 {
1406 if (g_traceJsonParser == nullptr) {
1407 g_traceJsonParser = std::make_shared<TraceJsonParser>();
1408 }
1409 if (!g_traceJsonParser->ParseTraceJson(PARSE_ALL_INFO)) {
1410 HILOG_ERROR(LOG_CORE, "WriteEventsFormat: Failed to parse trace tag total infos.");
1411 return FILE_ERROR;
1412 }
1413 auto allTags = g_traceJsonParser->GetAllTagInfos();
1414 auto tagGroupTable = g_traceJsonParser->GetTagGroups();
1415 auto tagFmts = g_traceJsonParser->GetBaseFmtPath();
1416 auto custBufSz = g_traceJsonParser->GetSnapShotBufSzKb();
1417
1418 if (tagGroups.size() == 0 || !CheckTagGroup(tagGroups, tagGroupTable)) {
1419 HILOG_ERROR(LOG_CORE, "OpenTrace: TAG_ERROR.");
1420 return TAG_ERROR;
1421 }
1422
1423 TraceParams defaultTraceParams;
1424 defaultTraceParams.tagGroups = tagGroups;
1425 // attention: the buffer size value in the configuration file is preferred to set.
1426 if (custBufSz > 0) {
1427 defaultTraceParams.bufferSize = std::to_string(custBufSz);
1428 } else {
1429 int traceBufSz = IsHmKernel() ? HM_DEFAULT_BUFFER_SIZE : DEFAULT_BUFFER_SIZE;
1430 defaultTraceParams.bufferSize = std::to_string(traceBufSz);
1431 }
1432 defaultTraceParams.clockType = "boot";
1433 defaultTraceParams.isOverWrite = "1";
1434 defaultTraceParams.fileSize = DEFAULT_FILE_SIZE;
1435 return HandleTraceOpen(defaultTraceParams, allTags, tagGroupTable, tagFmts);
1436 }
1437
RemoveUnSpace(std::string str,std::string & args)1438 void RemoveUnSpace(std::string str, std::string& args)
1439 {
1440 int maxCircleTimes = 30;
1441 int curTimes = 0;
1442 const size_t symbolAndSpaceLen = 2;
1443 std::string strSpace = str + " ";
1444 while (curTimes < maxCircleTimes) {
1445 curTimes++;
1446 std::string::size_type index = args.find(strSpace);
1447 if (index != std::string::npos) {
1448 args.replace(index, symbolAndSpaceLen, str);
1449 } else {
1450 break;
1451 }
1452 }
1453 }
1454
SetCmdTraceIntParams(const std::string & traceParamsStr,int & traceParams)1455 void SetCmdTraceIntParams(const std::string& traceParamsStr, int& traceParams)
1456 {
1457 if (!OHOS::HiviewDFX::Hitrace::StringToInt(traceParamsStr, traceParams)) {
1458 traceParams = 0;
1459 return;
1460 }
1461 if (traceParams <= 0) {
1462 HILOG_WARN(LOG_CORE, "Illegal input, traceParams initialized to null.");
1463 traceParams = 0;
1464 }
1465 }
1466
SetDestTraceTimeAndDuration(int maxDuration,const uint64_t & utTraceEndTime)1467 void SetDestTraceTimeAndDuration(int maxDuration, const uint64_t& utTraceEndTime)
1468 {
1469 if (utTraceEndTime == 0) {
1470 time_t currentTime;
1471 time(¤tTime);
1472 g_utDestTraceEndTime = static_cast<uint64_t>(currentTime);
1473 } else {
1474 g_utDestTraceEndTime = utTraceEndTime;
1475 }
1476 if (maxDuration == 0) {
1477 maxDuration = DEFAULT_FULL_TRACE_LENGTH;
1478 }
1479 if (g_utDestTraceEndTime < static_cast<uint64_t>(maxDuration)) {
1480 g_utDestTraceStartTime = 0;
1481 } else {
1482 g_utDestTraceStartTime = g_utDestTraceEndTime - static_cast<uint64_t>(maxDuration);
1483 }
1484 HILOG_INFO(LOG_CORE, "g_utDestTraceStartTime:(%{public}" PRIu64 "), g_utDestTraceEndTime:(%{public}" PRIu64 ").",
1485 g_utDestTraceStartTime, g_utDestTraceEndTime);
1486 }
1487
1488 /**
1489 * args: tags:tag1,tags2... tagGroups:group1,group2... clockType:boot bufferSize:1024 overwrite:1 output:filename
1490 * traceParams: Save the above parameters
1491 */
ParseArgs(const std::string & args,TraceParams & traceParams,const std::map<std::string,TraceTag> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)1492 bool ParseArgs(const std::string& args, TraceParams& traceParams, const std::map<std::string, TraceTag>& allTags,
1493 const std::map<std::string, std::vector<std::string>>& tagGroupTable)
1494 {
1495 std::string userArgs = args;
1496 std::string str = ":";
1497 RemoveUnSpace(str, userArgs);
1498 str = ",";
1499 RemoveUnSpace(str, userArgs);
1500 std::vector<std::string> argList = Split(userArgs, ' ');
1501 for (std::string item : argList) {
1502 size_t pos = item.find(":");
1503 if (pos == std::string::npos) {
1504 HILOG_ERROR(LOG_CORE, "trace command line without colon appears: %{public}s, continue.", item.c_str());
1505 continue;
1506 }
1507 std::string itemName = item.substr(0, pos);
1508 if (itemName == "tags") {
1509 traceParams.tags = Split(item.substr(pos + 1), ',');
1510 } else if (itemName == "tagGroups") {
1511 traceParams.tagGroups = Split(item.substr(pos + 1), ',');
1512 } else if (itemName == "clockType") {
1513 traceParams.clockType = item.substr(pos + 1);
1514 } else if (itemName == "bufferSize") {
1515 traceParams.bufferSize = item.substr(pos + 1);
1516 } else if (itemName == "overwrite") {
1517 traceParams.isOverWrite = item.substr(pos + 1);
1518 } else if (itemName == "output") {
1519 traceParams.outputFile = item.substr(pos + 1);
1520 } else if (itemName == "fileSize") {
1521 std::string fileSizeStr = item.substr(pos + 1);
1522 SetCmdTraceIntParams(fileSizeStr, traceParams.fileSize);
1523 } else if (itemName == "fileLimit") {
1524 std::string fileLimitStr = item.substr(pos + 1);
1525 SetCmdTraceIntParams(fileLimitStr, traceParams.fileLimit);
1526 } else if (itemName == "appPid") {
1527 std::string pidStr = item.substr(pos + 1);
1528 SetCmdTraceIntParams(pidStr, traceParams.appPid);
1529 if (traceParams.appPid == 0) {
1530 HILOG_ERROR(LOG_CORE, "Illegal input, appPid(%{public}s) must be number and greater than 0.",
1531 pidStr.c_str());
1532 return false;
1533 }
1534 OHOS::system::SetParameter(TRACE_KEY_APP_PID, pidStr);
1535 } else {
1536 HILOG_ERROR(LOG_CORE, "Extra trace command line options appear when ParseArgs: %{public}s, return false.",
1537 itemName.c_str());
1538 return false;
1539 }
1540 }
1541 return CheckTags(traceParams.tags, allTags) && CheckTagGroup(traceParams.tagGroups, tagGroupTable);
1542 }
1543
WriteCpuFreqTrace()1544 void WriteCpuFreqTrace()
1545 {
1546 std::string freqsfmt = "cpu frequency: ";
1547 ReadCurrentCpuFrequencies(freqsfmt);
1548 HILOG_INFO(LOG_CORE, "hitracedump write trace(%{public}s)", freqsfmt.c_str());
1549 HITRACE_METER_NAME(HITRACE_TAG_OHOS, freqsfmt);
1550 }
1551
SetTotalFileSizeLimitAndSliceMaxDuration(const uint64_t & totalFileSize,const uint64_t & sliceMaxDuration)1552 void SetTotalFileSizeLimitAndSliceMaxDuration(const uint64_t& totalFileSize, const uint64_t& sliceMaxDuration)
1553 {
1554 if (totalFileSize == 0) {
1555 g_totalFileSizeLimit = DEFAULT_TOTAL_CACHE_FILE_SIZE * BYTE_PER_MB;
1556 } else {
1557 g_totalFileSizeLimit = totalFileSize * BYTE_PER_MB;
1558 }
1559 if (sliceMaxDuration == 0) {
1560 g_sliceMaxDuration = DEFAULT_TRACE_SLICE_DURATION;
1561 } else {
1562 g_sliceMaxDuration = sliceMaxDuration;
1563 }
1564 }
1565
GetFileInCache(TraceRetInfo & traceRetInfo)1566 void GetFileInCache(TraceRetInfo& traceRetInfo)
1567 {
1568 g_interruptDump.store(1);
1569 HILOG_INFO(LOG_CORE, "DumpTrace: Trace is caching, get cache file.");
1570 std::lock_guard<std::mutex> lock(g_cacheTraceMutex);
1571 SearchTraceFiles(g_utDestTraceStartTime, g_utDestTraceEndTime, traceRetInfo.outputFiles);
1572 if (traceRetInfo.outputFiles.empty()) {
1573 HILOG_ERROR(LOG_CORE, "DumpTrace: Trace is caching, search file failed.");
1574 traceRetInfo.errorCode = OUT_OF_TIME;
1575 } else {
1576 for (const auto& file: traceRetInfo.outputFiles) {
1577 HILOG_INFO(LOG_CORE, "dumptrace file is %{public}s.", file.c_str());
1578 }
1579 traceRetInfo.errorCode = SUCCESS;
1580 }
1581 g_interruptDump.store(0);
1582 }
1583 } // namespace
1584
1585 #ifdef HITRACE_UNITTEST
SetSysInitParamTags(uint64_t sysInitParamTags)1586 void SetSysInitParamTags(uint64_t sysInitParamTags)
1587 {
1588 g_sysInitParamTags = sysInitParamTags;
1589 }
1590
SetCheckParam()1591 bool SetCheckParam()
1592 {
1593 int ret = CheckParam();
1594 return ret;
1595 }
1596 #endif
1597
GetTraceMode()1598 uint8_t GetTraceMode()
1599 {
1600 std::lock_guard<std::mutex> lock(g_traceMutex);
1601 return g_traceMode;
1602 }
1603
OpenTrace(const std::vector<std::string> & tagGroups)1604 TraceErrorCode OpenTrace(const std::vector<std::string>& tagGroups)
1605 {
1606 std::lock_guard<std::mutex> lock(g_traceMutex);
1607 if (g_traceMode != TraceMode::CLOSE) {
1608 HILOG_ERROR(LOG_CORE, "OpenTrace: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1609 static_cast<uint32_t>(g_traceMode));
1610 return WRONG_TRACE_MODE;
1611 }
1612 if (!IsTraceMounted(g_traceRootPath)) {
1613 HILOG_ERROR(LOG_CORE, "OpenTrace: TRACE_NOT_SUPPORTED.");
1614 return TRACE_NOT_SUPPORTED;
1615 }
1616
1617 TraceErrorCode ret = HandleDefaultTraceOpen(tagGroups);
1618 if (ret != SUCCESS) {
1619 HILOG_ERROR(LOG_CORE, "OpenTrace: failed.");
1620 return ret;
1621 }
1622 if (!g_traceJsonParser->ParseTraceJson(TRACE_SNAPSHOT_FILE_AGE)) {
1623 HILOG_WARN(LOG_CORE, "OpenTrace: Failed to parse TRACE_SNAPSHOT_FILE_AGE.");
1624 }
1625 RefreshTraceVec(g_traceFileVec, TRACE_SNAPSHOT);
1626 RefreshTraceVec(g_cacheFileVec, TRACE_CACHE);
1627 {
1628 std::lock_guard<std::mutex> cacheLock(g_cacheTraceMutex);
1629 ClearCacheTraceFileByDuration(g_cacheFileVec);
1630 }
1631 g_sysInitParamTags = GetSysParamTags();
1632 g_traceMode = TraceMode::OPEN;
1633 HILOG_INFO(LOG_CORE, "OpenTrace: open by tag group success.");
1634 StartCpuBufferBalanceService();
1635 return ret;
1636 }
1637
OpenTrace(const std::string & args)1638 TraceErrorCode OpenTrace(const std::string& args)
1639 {
1640 std::lock_guard<std::mutex> lock(g_traceMutex);
1641 if (g_traceMode != TraceMode::CLOSE) {
1642 HILOG_ERROR(LOG_CORE, "OpenTrace: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1643 static_cast<uint32_t>(g_traceMode));
1644 return WRONG_TRACE_MODE;
1645 }
1646
1647 if (!IsTraceMounted(g_traceRootPath)) {
1648 HILOG_ERROR(LOG_CORE, "OpenTrace: TRACE_NOT_SUPPORTED.");
1649 return TRACE_NOT_SUPPORTED;
1650 }
1651
1652 if (g_traceJsonParser == nullptr) {
1653 g_traceJsonParser = std::make_shared<TraceJsonParser>();
1654 }
1655 if (!g_traceJsonParser->ParseTraceJson(PARSE_TRACE_GROUP_INFO)) {
1656 HILOG_ERROR(LOG_CORE, "WriteEventsFormat: Failed to parse trace tag format and group infos.");
1657 return FILE_ERROR;
1658 }
1659 auto allTags = g_traceJsonParser->GetAllTagInfos();
1660 auto tagGroupTable = g_traceJsonParser->GetTagGroups();
1661 auto traceFormats = g_traceJsonParser->GetBaseFmtPath();
1662
1663 if (allTags.size() == 0 || tagGroupTable.size() == 0) {
1664 HILOG_ERROR(LOG_CORE, "OpenTrace: ParseTagInfo TAG_ERROR.");
1665 return TAG_ERROR;
1666 }
1667 // parse args
1668 TraceParams traceParams;
1669 if (!ParseArgs(args, traceParams, allTags, tagGroupTable)) {
1670 HILOG_ERROR(LOG_CORE, "OpenTrace: TAG_ERROR.");
1671 return TAG_ERROR;
1672 }
1673
1674 TraceErrorCode ret = HandleTraceOpen(traceParams, allTags, tagGroupTable, traceFormats);
1675 if (ret != SUCCESS) {
1676 HILOG_ERROR(LOG_CORE, "OpenTrace: open by args failed.");
1677 return FILE_ERROR;
1678 }
1679 g_sysInitParamTags = GetSysParamTags();
1680 g_traceMode = TraceMode::OPEN;
1681 HILOG_INFO(LOG_CORE, "OpenTrace: open by args success, args:%{public}s.", args.c_str());
1682 StartCpuBufferBalanceService();
1683 return ret;
1684 }
1685
CacheTraceOn(uint64_t totalFileSize,uint64_t sliceMaxDuration)1686 TraceErrorCode CacheTraceOn(uint64_t totalFileSize, uint64_t sliceMaxDuration)
1687 {
1688 std::lock_guard<std::mutex> lock(g_traceMutex);
1689 if (g_traceMode != TraceMode::OPEN) {
1690 HILOG_ERROR(LOG_CORE, "CacheTraceOn: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1691 static_cast<uint32_t>(g_traceMode));
1692 return WRONG_TRACE_MODE;
1693 }
1694 if (!g_cacheEnd.load()) {
1695 HILOG_ERROR(LOG_CORE, "CacheTraceOn: cache trace is dumping now.");
1696 return WRONG_TRACE_MODE;
1697 }
1698
1699 SetTotalFileSizeLimitAndSliceMaxDuration(totalFileSize, sliceMaxDuration);
1700 g_cacheFlag.store(true);
1701 g_cacheEnd.store(false);
1702 auto it = []() {
1703 ProcessCacheTask();
1704 };
1705 std::thread task(it);
1706 task.detach();
1707 HILOG_INFO(LOG_CORE, "Caching trace on.");
1708 g_traceMode |= TraceMode::CACHE;
1709 return SUCCESS;
1710 }
1711
CacheTraceOff()1712 TraceErrorCode CacheTraceOff()
1713 {
1714 std::lock_guard<std::mutex> lock(g_traceMutex);
1715 if (g_traceMode != (TraceMode::OPEN | TraceMode::CACHE)) {
1716 HILOG_ERROR(LOG_CORE,
1717 "CacheTraceOff: WRONG_TRACE_MODE, current trace mode: %{public}u.", static_cast<uint32_t>(g_traceMode));
1718 return WRONG_TRACE_MODE;
1719 }
1720 g_cacheFlag.store(false);
1721 while (!g_cacheEnd.load()) {
1722 g_cacheFlag.store(false);
1723 usleep(UNIT_TIME);
1724 }
1725 HILOG_INFO(LOG_CORE, "Caching trace off.");
1726 g_traceMode &= ~TraceMode::CACHE;
1727 return SUCCESS;
1728 }
1729
DumpTrace(int maxDuration,uint64_t utTraceEndTime)1730 TraceRetInfo DumpTrace(int maxDuration, uint64_t utTraceEndTime)
1731 {
1732 std::lock_guard<std::mutex> lock(g_traceMutex);
1733 if (!IsTraceOpen() || IsRecordOn()) {
1734 HILOG_ERROR(LOG_CORE, "DumpTrace: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1735 static_cast<uint32_t>(g_traceMode));
1736 TraceRetInfo ret;
1737 ret.errorCode = WRONG_TRACE_MODE;
1738 return ret;
1739 }
1740 HILOG_INFO(LOG_CORE, "DumpTrace start, target duration is %{public}d, target endtime is (%{public}" PRIu64 ").",
1741 maxDuration, utTraceEndTime);
1742 TraceRetInfo ret;
1743
1744 if (!CheckServiceRunning()) {
1745 HILOG_ERROR(LOG_CORE, "DumpTrace: TRACE_IS_OCCUPIED.");
1746 ret.errorCode = TRACE_IS_OCCUPIED;
1747 return ret;
1748 }
1749 SetDestTraceTimeAndDuration(maxDuration, utTraceEndTime);
1750 if (UNEXPECTANTLY(IsCacheOn())) {
1751 GetFileInCache(ret);
1752 return ret;
1753 }
1754
1755 ret.errorCode = SetTimeIntervalBoundary(maxDuration, utTraceEndTime);
1756 if (ret.errorCode != SUCCESS) {
1757 return ret;
1758 }
1759 g_firstPageTimestamp = UINT64_MAX;
1760 g_lastPageTimestamp = 0;
1761
1762 uint32_t committedDuration = static_cast<uint32_t>(maxDuration == 0 ? DEFAULT_FULL_TRACE_LENGTH :
1763 std::min(maxDuration, DEFAULT_FULL_TRACE_LENGTH));
1764 ret.errorCode = DumpTraceInner(ret.outputFiles);
1765 if (g_traceEndTime <= g_firstPageTimestamp) {
1766 ret.coverRatio = 0;
1767 } else {
1768 ret.coverDuration = static_cast<int32_t>(std::min((g_traceEndTime - g_firstPageTimestamp) *
1769 S_TO_MS / S_TO_NS, committedDuration * S_TO_MS));
1770 ret.coverRatio = static_cast<int32_t>((g_traceEndTime - g_firstPageTimestamp) *
1771 MAX_RATIO_UNIT / S_TO_NS / committedDuration);
1772 }
1773 if (ret.coverRatio > MAX_RATIO_UNIT) {
1774 ret.coverRatio = MAX_RATIO_UNIT;
1775 }
1776 ret.tags.reserve(g_currentTraceParams.tagGroups.size() + g_currentTraceParams.tags.size());
1777 ret.tags.insert(ret.tags.end(), g_currentTraceParams.tagGroups.begin(), g_currentTraceParams.tagGroups.end());
1778 ret.tags.insert(ret.tags.end(), g_currentTraceParams.tags.begin(), g_currentTraceParams.tags.end());
1779 RestoreTimeIntervalBoundary();
1780 HILOG_INFO(LOG_CORE, "DumpTrace with time limit done.");
1781 return ret;
1782 }
1783
RecordTraceOn()1784 TraceErrorCode RecordTraceOn()
1785 {
1786 std::lock_guard<std::mutex> lock(g_traceMutex);
1787 // check current trace status
1788 if (g_traceMode != TraceMode::OPEN) {
1789 HILOG_ERROR(LOG_CORE, "RecordTraceOn: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1790 static_cast<uint32_t>(g_traceMode));
1791 return WRONG_TRACE_MODE;
1792 }
1793
1794 if (!g_recordEnd.load()) {
1795 HILOG_ERROR(LOG_CORE, "RecordTraceOn: WRONG_TRACE_MODE, record trace is dumping now.");
1796 return WRONG_TRACE_MODE;
1797 }
1798
1799 // start task thread
1800 g_recordFlag.store(true);
1801 g_recordEnd.store(false);
1802 auto it = []() {
1803 ProcessRecordTask();
1804 };
1805 std::thread task(it);
1806 task.detach();
1807 WriteCpuFreqTrace();
1808 HILOG_INFO(LOG_CORE, "Recording trace on.");
1809 g_traceMode |= TraceMode::RECORD;
1810 return SUCCESS;
1811 }
1812
RecordTraceOff()1813 TraceRetInfo RecordTraceOff()
1814 {
1815 std::lock_guard<std::mutex> lock(g_traceMutex);
1816 TraceRetInfo ret;
1817 // check current trace status
1818 if (!IsRecordOn()) {
1819 HILOG_ERROR(LOG_CORE, "RecordTraceOff: The current state is %{public}u, data exception.",
1820 static_cast<uint32_t>(g_traceMode));
1821 ret.errorCode = WRONG_TRACE_MODE;
1822
1823 std::lock_guard<std::mutex> lock(g_recordingOutputMutex);
1824 ret.outputFiles = g_recordingOutput;
1825 return ret;
1826 }
1827
1828 g_recordFlag.store(false);
1829 while (!g_recordEnd.load()) {
1830 usleep(UNIT_TIME);
1831 g_recordFlag.store(false);
1832 }
1833 ret.errorCode = SUCCESS;
1834
1835 std::lock_guard<std::mutex> outputFileslock(g_recordingOutputMutex);
1836 ret.outputFiles = g_recordingOutput;
1837 HILOG_INFO(LOG_CORE, "Recording trace off.");
1838 g_traceMode &= ~TraceMode::RECORD;
1839 return ret;
1840 }
1841
CloseTrace()1842 TraceErrorCode CloseTrace()
1843 {
1844 std::lock_guard<std::mutex> lock(g_traceMutex);
1845 HILOG_INFO(LOG_CORE, "CloseTrace start.");
1846 if (g_traceMode == TraceMode::CLOSE) {
1847 HILOG_INFO(LOG_CORE, "Trace has already been closed.");
1848 return SUCCESS;
1849 }
1850 if (IsRecordOn()) {
1851 g_recordFlag.store(false);
1852 while (!g_recordEnd.load()) {
1853 usleep(UNIT_TIME);
1854 g_recordFlag.store(false);
1855 }
1856 }
1857 if (IsCacheOn()) {
1858 g_cacheFlag.store(false);
1859 while (!g_cacheEnd.load()) {
1860 usleep(UNIT_TIME);
1861 g_cacheFlag.store(false);
1862 }
1863 }
1864 g_traceMode = TraceMode::CLOSE;
1865 OHOS::system::SetParameter(TRACE_KEY_APP_PID, "-1");
1866
1867 if (g_traceJsonParser == nullptr) {
1868 g_traceJsonParser = std::make_shared<TraceJsonParser>();
1869 }
1870 if (!g_traceJsonParser->ParseTraceJson(PARSE_TRACE_ENABLE_INFO)) {
1871 HILOG_ERROR(LOG_CORE, "WriteEventsFormat: Failed to parse trace tag enable infos.");
1872 return FILE_ERROR;
1873 }
1874 auto allTags = g_traceJsonParser->GetAllTagInfos();
1875 if (allTags.size() == 0) {
1876 HILOG_ERROR(LOG_CORE, "CloseTrace: ParseTagInfo TAG_ERROR.");
1877 return TAG_ERROR;
1878 }
1879
1880 TraceInit(allTags);
1881 TruncateFile();
1882 HILOG_INFO(LOG_CORE, "CloseTrace done.");
1883 return SUCCESS;
1884 }
1885
GetTraceFilesTable()1886 std::vector<std::pair<std::string, int>> GetTraceFilesTable()
1887 {
1888 return g_traceFilesTable;
1889 }
1890
SetTraceFilesTable(const std::vector<std::pair<std::string,int>> & traceFilesTable)1891 void SetTraceFilesTable(const std::vector<std::pair<std::string, int>>& traceFilesTable)
1892 {
1893 g_traceFilesTable = traceFilesTable;
1894 }
1895 } // namespace Hitrace
1896 } // namespace HiviewDFX
1897 } // namespace OHOS
1898