1 /*
2 * Copyright (C) 2025 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 "trace_content.h"
17
18 #include <dirent.h>
19 #include <fcntl.h>
20 #include <fstream>
21 #include <hilog/log.h>
22 #include <string>
23 #include <unistd.h>
24
25 #include "common_define.h"
26 #include "common_utils.h"
27 #include "securec.h"
28 #include "trace_file_utils.h"
29 #include "trace_json_parser.h"
30
31 namespace OHOS {
32 namespace HiviewDFX {
33 namespace Hitrace {
34 #ifdef LOG_DOMAIN
35 #undef LOG_DOMAIN
36 #define LOG_DOMAIN 0xD002D33
37 #endif
38 #ifdef LOG_TAG
39 #undef LOG_TAG
40 #define LOG_TAG "HitraceSource"
41 #endif
42 namespace {
43 constexpr int KB_PER_MB = 1024;
44 constexpr int JUDGE_FILE_EXIST = 10; // Check whether the trace file exists every 10 times.
45 constexpr int BUFFER_SIZE = 256 * PAGE_SIZE; // 1M
46 constexpr uint8_t HM_FILE_RAW_TRACE = 1;
47
48 /**
49 * @note If the async trace dump mode is performed in parallel with other modes,
50 * the following variables are required to be thread isolated.
51 */
52 thread_local int g_writeFileLimit = 0;
53 thread_local int g_outputFileSize = 0;
54 thread_local uint8_t g_buffer[BUFFER_SIZE] = { 0 };
55
PreWriteAllTraceEventsFormat(const int fd,const std::string & tracefsPath)56 static void PreWriteAllTraceEventsFormat(const int fd, const std::string& tracefsPath)
57 {
58 const TraceJsonParser& traceJsonParser = TraceJsonParser::Instance();
59 const std::map<std::string, TraceTag>& allTags = traceJsonParser.GetAllTagInfos();
60 std::vector<std::string> traceFormats = traceJsonParser.GetBaseFmtPath();
61 for (auto& tag : allTags) {
62 for (auto& fmt : tag.second.formatPath) {
63 traceFormats.emplace_back(fmt);
64 }
65 }
66 for (auto& traceFmt : traceFormats) {
67 std::string srcPath = tracefsPath + traceFmt;
68 if (access(srcPath.c_str(), R_OK) != -1) {
69 WriteEventFile(srcPath, fd);
70 }
71 }
72 }
73
IsCurrentTracePageValid(const uint64_t pageTraceTime,const uint64_t traceStartTime,const uint64_t traceEndTime)74 static int IsCurrentTracePageValid(const uint64_t pageTraceTime, const uint64_t traceStartTime,
75 const uint64_t traceEndTime)
76 {
77 if (pageTraceTime > traceEndTime) { // need stop read, but should keep current page.
78 HILOG_INFO(LOG_CORE,
79 "Current pageTraceTime(%{public}" PRIu64 ") is larger than traceEndTime(%{public}" PRIu64 ")",
80 pageTraceTime, traceEndTime);
81 return -1;
82 }
83 if (pageTraceTime < traceStartTime) { // skip current 4K data caused of target trace range is not reached.
84 return 0; // just skip
85 }
86 return 1; // hit.
87 }
88 }
89
ITraceContent(const int fd,const std::string & tracefsPath,const std::string & traceFilePath,const bool ishm)90 ITraceContent::ITraceContent(const int fd,
91 const std::string& tracefsPath,
92 const std::string& traceFilePath,
93 const bool ishm)
94 : traceFileFd_(fd), tracefsPath_(tracefsPath), traceFilePath_(traceFilePath), isHm_(ishm)
95 {
96 traceSourceFd_ = -1;
97 }
98
~ITraceContent()99 ITraceContent::~ITraceContent()
100 {
101 if (traceSourceFd_ != -1) {
102 close(traceSourceFd_);
103 }
104 }
105
WriteTraceData(const uint8_t contentType)106 bool ITraceContent::WriteTraceData(const uint8_t contentType)
107 {
108 if (traceSourceFd_ < 0) {
109 HILOG_ERROR(LOG_CORE, "WriteTraceData: trace source fd is illegal.");
110 return false;
111 }
112 if (!IsFileExist()) {
113 HILOG_ERROR(LOG_CORE, "WriteTraceData: trace file (%{public}s) not found.", traceFilePath_.c_str());
114 return false;
115 }
116 TraceFileContentHeader contentHeader;
117 if (!DoWriteTraceContentHeader(contentHeader, contentType)) {
118 return false;
119 }
120 ssize_t writeLen = 0;
121 int pageChkFailedTime = 0;
122 while (true) {
123 int bytes = 0;
124 bool endFlag = false;
125 /* Write 1M at a time */
126 while (bytes <= (BUFFER_SIZE - static_cast<int>(PAGE_SIZE))) {
127 ssize_t readBytes = TEMP_FAILURE_RETRY(read(traceSourceFd_, g_buffer + bytes, PAGE_SIZE));
128 if (readBytes <= 0) {
129 endFlag = true;
130 HILOG_DEBUG(LOG_CORE, "WriteTraceData: read raw trace done, size(%{public}zd), err(%{public}s).",
131 readBytes, strerror(errno));
132 break;
133 }
134 if (!CheckPage(g_buffer + bytes)) {
135 pageChkFailedTime++;
136 }
137 bytes += readBytes;
138 if (pageChkFailedTime >= 2) { // 2 : check failed times threshold
139 endFlag = true;
140 break;
141 }
142 }
143 DoWriteTraceData(g_buffer, bytes, writeLen);
144 if (endFlag) {
145 break;
146 }
147 }
148 UpdateTraceContentHeader(contentHeader, static_cast<uint32_t>(writeLen));
149 HILOG_INFO(LOG_CORE, "WriteTraceData end, type: %{public}d, byte: %{public}zd. g_writeFileLimit: %{public}d",
150 contentType, writeLen, g_writeFileLimit);
151 return true;
152 }
153
DoWriteTraceData(const uint8_t * buffer,const int bytes,ssize_t & writeLen)154 void ITraceContent::DoWriteTraceData(const uint8_t* buffer, const int bytes, ssize_t& writeLen)
155 {
156 if (buffer == nullptr) {
157 HILOG_ERROR(LOG_CORE, "DoWriteTraceData: buffer is nullptr!");
158 return;
159 }
160 ssize_t writeRet = TEMP_FAILURE_RETRY(write(traceFileFd_, buffer, bytes));
161 if (writeRet < 0) {
162 HILOG_ERROR(LOG_CORE, "DoWriteTraceData: write failed, err(%{public}s)", strerror(errno));
163 } else {
164 if (writeRet != static_cast<ssize_t>(bytes)) {
165 HILOG_WARN(LOG_CORE, "DoWriteTraceData: not write all done, writeLen(%{public}zd), FullLen(%{public}d)",
166 writeRet, bytes);
167 }
168 writeLen += writeRet;
169 }
170 }
171
DoWriteTraceContentHeader(TraceFileContentHeader & contentHeader,const uint8_t contentType)172 bool ITraceContent::DoWriteTraceContentHeader(TraceFileContentHeader& contentHeader, const uint8_t contentType)
173 {
174 contentHeader.type = contentType;
175 ssize_t writeRet = TEMP_FAILURE_RETRY(write(traceFileFd_, reinterpret_cast<char *>(&contentHeader),
176 sizeof(contentHeader)));
177 if (writeRet <= 0) {
178 HILOG_ERROR(LOG_CORE, "DoWriteTraceContentHeader: failed to write content header, err(%{public}s)",
179 strerror(errno));
180 return false;
181 }
182 return true;
183 }
184
UpdateTraceContentHeader(struct TraceFileContentHeader & contentHeader,const uint32_t writeLen)185 void ITraceContent::UpdateTraceContentHeader(struct TraceFileContentHeader& contentHeader, const uint32_t writeLen)
186 {
187 contentHeader.length = writeLen;
188 uint32_t offset = contentHeader.length + sizeof(contentHeader);
189 off_t pos = lseek(traceFileFd_, 0, SEEK_CUR);
190 lseek(traceFileFd_, pos - offset, SEEK_SET);
191 write(traceFileFd_, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
192 lseek(traceFileFd_, pos, SEEK_SET);
193 g_outputFileSize += static_cast<int>(offset);
194 }
195
IsFileExist()196 bool ITraceContent::IsFileExist()
197 {
198 // 每10次数据段写入,检查一次文件是否存在
199 g_writeFileLimit++;
200 if (g_writeFileLimit > JUDGE_FILE_EXIST) {
201 g_writeFileLimit = 0;
202 if (access(traceFilePath_.c_str(), F_OK) != 0) {
203 HILOG_WARN(LOG_CORE, "IsFileExist access file:%{public}s failed, errno: %{public}d.",
204 traceFilePath_.c_str(), errno);
205 return false;
206 }
207 }
208 return true;
209 }
210
CheckPage(uint8_t * page)211 bool ITraceContent::CheckPage(uint8_t* page)
212 {
213 if (isHm_) {
214 return true;
215 }
216 const int pageThreshold = PAGE_SIZE / 2; // pageThreshold = 2kB
217 PageHeader *pageHeader = reinterpret_cast<PageHeader*>(&page);
218 if (pageHeader->size < static_cast<uint64_t>(pageThreshold)) {
219 return false;
220 }
221 return true;
222 }
223
GetCurrentFileSize()224 int ITraceContent::GetCurrentFileSize()
225 {
226 return g_outputFileSize;
227 }
228
ResetCurrentFileSize()229 void ITraceContent::ResetCurrentFileSize()
230 {
231 g_outputFileSize = 0;
232 }
233
WriteProcessLists(ssize_t & writeLen)234 void ITraceContent::WriteProcessLists(ssize_t& writeLen)
235 {
236 std::string result;
237 DIR* procDir = opendir("/proc");
238 if (procDir == nullptr) {
239 HILOG_ERROR(LOG_CORE, "WriteProcessLists: open /proc failed, errno: %{public}d.", errno);
240 return;
241 }
242 int bytes = 0;
243 struct dirent* entry;
244 while ((entry = readdir(procDir)) != nullptr) {
245 if (entry->d_type != DT_DIR || std::string(entry->d_name) == "." || std::string(entry->d_name) == "..") {
246 continue;
247 }
248 std::string dirName(entry->d_name);
249 if (!std::all_of(dirName.begin(), dirName.end(), ::isdigit)) {
250 continue;
251 }
252 std::string statusPath = CanonicalizeSpecPath(std::string("/proc/" + dirName + "/status").c_str());
253 std::ifstream statusFile(statusPath);
254 if (!statusFile.is_open()) {
255 continue;
256 }
257 std::string line;
258 std::string processName;
259 while (std::getline(statusFile, line)) {
260 if (line.find("Name:") != std::string::npos) {
261 processName = line.substr(line.find(":") + 1);
262 break;
263 }
264 }
265 if (processName.empty()) {
266 continue;
267 }
268 result = dirName + " " + processName + "\n";
269 if (memcpy_s(g_buffer + bytes, BUFFER_SIZE - bytes, result.c_str(), result.length()) != EOK) {
270 HILOG_ERROR(LOG_CORE, "WriteProcessLists: failed to memcpy result to g_buffer.");
271 continue;
272 }
273 bytes += static_cast<int>(result.length());
274 if (bytes <= BUFFER_SIZE - static_cast<int>(PAGE_SIZE)) {
275 continue;
276 }
277 DoWriteTraceData(g_buffer, bytes, writeLen);
278 bytes = 0;
279 }
280 if (bytes > 0) {
281 DoWriteTraceData(g_buffer, bytes, writeLen);
282 }
283 closedir(procDir);
284 }
285
InitTraceFileHdr(TraceFileHeader & fileHdr)286 bool ITraceFileHdrContent::InitTraceFileHdr(TraceFileHeader& fileHdr)
287 {
288 if (sizeof(void*) == sizeof(uint64_t)) {
289 fileHdr.reserved |= 0;
290 } else if (sizeof(void*) == sizeof(uint32_t)) {
291 fileHdr.reserved |= 1;
292 }
293 HILOG_INFO(LOG_CORE, "InitTraceFileHdr: reserved with arch word info is %{public}d.", fileHdr.reserved);
294 const int maxCpuNums = 24;
295 int cpuNums = GetCpuProcessors();
296 if (cpuNums > maxCpuNums || cpuNums <= 0) {
297 HILOG_ERROR(LOG_CORE, "InitTraceFileHdr error: cpu_number is %{public}d.", cpuNums);
298 return false;
299 }
300 fileHdr.reserved |= (static_cast<uint64_t>(cpuNums) << 1);
301 HILOG_INFO(LOG_CORE, "InitTraceFileHdr: reserved with cpu number info is %{public}d.", fileHdr.reserved);
302 return true;
303 }
304
WriteTraceContent()305 bool TraceFileHdrLinux::WriteTraceContent()
306 {
307 TraceFileHeader header;
308 if (!InitTraceFileHdr(header)) {
309 return false;
310 }
311 ssize_t writeRet = TEMP_FAILURE_RETRY(write(traceFileFd_, reinterpret_cast<char*>(&header), sizeof(header)));
312 if (writeRet < 0) {
313 HILOG_ERROR(LOG_CORE, "Failed to write trace file header, errno: %{public}s, headerLen: %{public}zu.",
314 strerror(errno), sizeof(header));
315 return false;
316 }
317 return true;
318 }
319
WriteTraceContent()320 bool TraceFileHdrHM::WriteTraceContent()
321 {
322 TraceFileHeader header;
323 if (!InitTraceFileHdr(header)) {
324 return false;
325 }
326 header.fileType = HM_FILE_RAW_TRACE;
327 ssize_t writeRet = TEMP_FAILURE_RETRY(write(traceFileFd_, reinterpret_cast<char*>(&header), sizeof(header)));
328 if (writeRet < 0) {
329 HILOG_ERROR(LOG_CORE, "Failed to write trace file header, errno: %{public}s, headerLen: %{public}zu.",
330 strerror(errno), sizeof(header));
331 return false;
332 }
333 return true;
334 }
335
WriteTraceContent()336 bool TraceBaseInfoContent::WriteTraceContent()
337 {
338 struct TraceFileContentHeader contentHeader;
339 contentHeader.type = CONTENT_TYPE_BASE_INFO;
340 ssize_t writeRet = write(traceFileFd_, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
341 if (writeRet < 0) {
342 HILOG_WARN(LOG_CORE, "Write BaseInfo contentHeader failed, errno: %{public}d.", errno);
343 return false;
344 }
345 auto writeLen = WriteKernelVersion();
346 writeLen += WriteUnixTimeMs();
347 writeLen += WriteBootTimeMs();
348 UpdateTraceContentHeader(contentHeader, writeLen);
349 return true;
350 }
351
WriteKeyValue(const std::string & key,const std::string & value)352 ssize_t TraceBaseInfoContent::WriteKeyValue(const std::string& key, const std::string& value)
353 {
354 if (key.empty() || value.empty()) {
355 HILOG_ERROR(LOG_CORE, "WriteKeyValue: key or value is empty.");
356 return 0;
357 }
358 std::string keyValue = key + ": " + value + "\n";
359 ssize_t writeRet = write(traceFileFd_, keyValue.data(), keyValue.size());
360 if (writeRet < 0) {
361 HILOG_WARN(LOG_CORE, "Write Key %{public}s Value %{public}s failed, errno: %{public}d.",
362 key.c_str(), value.c_str(), errno);
363 return 0;
364 } else {
365 return writeRet;
366 }
367 }
368
WriteKernelVersion()369 ssize_t TraceBaseInfoContent::WriteKernelVersion()
370 {
371 std::string kernelVersion = GetKernelVersion();
372 HILOG_INFO(LOG_CORE, "WriteKernelVersion : current version %{public}s", kernelVersion.c_str());
373 return WriteKeyValue("KERNEL_VERSION", kernelVersion);
374 }
375
WriteUnixTimeMs()376 ssize_t TraceBaseInfoContent::WriteUnixTimeMs()
377 {
378 uint64_t unixTimeMs = GetCurUnixTimeMs();
379 HILOG_INFO(LOG_CORE, "WriteUnixTimeMs : current time %{public}" PRIu64, unixTimeMs);
380 std::string timeStr = std::to_string(unixTimeMs);
381 return WriteKeyValue("UNIX_TIME_MS", timeStr);
382 }
383
WriteBootTimeMs()384 ssize_t TraceBaseInfoContent::WriteBootTimeMs()
385 {
386 uint64_t bootTimeMs = GetCurBootTime() / MS_TO_NS;
387 HILOG_INFO(LOG_CORE, "WriteBootTimeMs : current time %{public}" PRIu64, bootTimeMs);
388 std::string timeStr = std::to_string(bootTimeMs);
389 return WriteKeyValue("BOOT_TIME_MS", timeStr);
390 }
391
TraceEventFmtContent(const int fd,const std::string & tracefsPath,const std::string & traceFilePath,const bool ishm)392 TraceEventFmtContent::TraceEventFmtContent(const int fd,
393 const std::string& tracefsPath,
394 const std::string& traceFilePath,
395 const bool ishm)
396 : ITraceContent(fd, tracefsPath, traceFilePath, ishm)
397 {
398 const std::string savedEventsFormatPath = TRACE_FILE_DEFAULT_DIR + TRACE_SAVED_EVENTS_FORMAT;
399 bool hasPreWrotten = true;
400 if (access(savedEventsFormatPath.c_str(), F_OK) != -1) {
401 traceSourceFd_ = open(savedEventsFormatPath.c_str(), O_RDONLY | O_NONBLOCK);
402 } else {
403 traceSourceFd_ = open(savedEventsFormatPath.c_str(),
404 O_CREAT | O_RDWR | O_TRUNC | O_NONBLOCK, 0644); // 0644:-rw-r--r--
405 hasPreWrotten = false;
406 }
407 if (traceSourceFd_ < 0) {
408 HILOG_ERROR(LOG_CORE, "TraceEventFmtContent: open %{public}s failed.", savedEventsFormatPath.c_str());
409 }
410 if (!hasPreWrotten && traceFileFd_ >= 0) {
411 PreWriteAllTraceEventsFormat(traceSourceFd_, tracefsPath_);
412 (void)lseek(traceFileFd_, 0, SEEK_SET);
413 }
414 }
415
WriteTraceContent()416 bool TraceEventFmtContent::WriteTraceContent()
417 {
418 return WriteTraceData(CONTENT_TYPE_EVENTS_FORMAT);
419 }
420
TraceCmdLinesContent(const int fd,const std::string & tracefsPath,const std::string & traceFilePath,const bool ishm)421 TraceCmdLinesContent::TraceCmdLinesContent(const int fd,
422 const std::string& tracefsPath,
423 const std::string& traceFilePath,
424 const bool ishm)
425 : ITraceContent(fd, tracefsPath, traceFilePath, ishm)
426 {
427 const std::string cmdlinesPath = tracefsPath_ + "saved_cmdlines";
428 traceSourceFd_ = open(cmdlinesPath.c_str(), O_RDONLY | O_NONBLOCK);
429 if (traceSourceFd_ < 0) {
430 HILOG_ERROR(LOG_CORE, "TraceCmdLinesContent: open %{public}s failed.", cmdlinesPath.c_str());
431 }
432 }
433
WriteTraceContent()434 bool TraceCmdLinesContent::WriteTraceContent()
435 {
436 return WriteTraceData(CONTENT_TYPE_CMDLINES);
437 }
438
TraceTgidsContent(const int fd,const std::string & tracefsPath,const std::string & traceFilePath,const bool ishm)439 TraceTgidsContent::TraceTgidsContent(const int fd, const std::string& tracefsPath, const std::string& traceFilePath,
440 const bool ishm)
441 : ITraceContent(fd, tracefsPath, traceFilePath, ishm)
442 {
443 const std::string tgidsPath = tracefsPath_ + "saved_tgids";
444 traceSourceFd_ = open(tgidsPath.c_str(), O_RDONLY | O_NONBLOCK);
445 if (traceSourceFd_ < 0) {
446 HILOG_ERROR(LOG_CORE, "TraceTgidsContent: open %{public}s failed.", tgidsPath.c_str());
447 }
448 }
449
WriteTraceContent()450 bool TraceTgidsContent::WriteTraceContent()
451 {
452 return WriteTraceData(CONTENT_TYPE_TGIDS);
453 }
454
WriteTracePipeRawData(const std::string & srcPath,const int cpuIdx)455 bool ITraceCpuRawContent::WriteTracePipeRawData(const std::string& srcPath, const int cpuIdx)
456 {
457 if (!IsFileExist()) {
458 HILOG_ERROR(LOG_CORE, "WriteTracePipeRawData: trace file (%{public}s) not found.", traceFilePath_.c_str());
459 return false;
460 }
461 std::string path = CanonicalizeSpecPath(srcPath.c_str());
462 auto rawTraceFd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
463 if (rawTraceFd < 0) {
464 HILOG_ERROR(LOG_CORE, "WriteTracePipeRawData: open %{public}s failed.", srcPath.c_str());
465 return false;
466 }
467 struct TraceFileContentHeader rawtraceHdr;
468 if (!DoWriteTraceContentHeader(rawtraceHdr, CONTENT_TYPE_CPU_RAW + cpuIdx)) {
469 close(rawTraceFd);
470 return false;
471 }
472 ssize_t writeLen = 0;
473 int pageChkFailedTime = 0;
474 bool printFirstPageTime = false; // attention: update first page time in every WriteTracePipeRawData calling.
475 while (true) {
476 int bytes = 0;
477 bool endFlag = false;
478 ReadTracePipeRawLoop(rawTraceFd, bytes, endFlag, pageChkFailedTime, printFirstPageTime);
479 DoWriteTraceData(g_buffer, bytes, writeLen);
480 if (IsWriteFileOverflow(g_outputFileSize, writeLen,
481 request_.fileSize != 0 ? request_.fileSize : DEFAULT_FILE_SIZE * KB_PER_MB)) {
482 isOverFlow_ = true;
483 break;
484 }
485 if (endFlag) {
486 break;
487 }
488 }
489 UpdateTraceContentHeader(rawtraceHdr, static_cast<uint32_t>(writeLen));
490 if (writeLen > 0) {
491 dumpStatus_ = TraceErrorCode::SUCCESS;
492 } else if (dumpStatus_ == TraceErrorCode::UNSET) {
493 dumpStatus_ = TraceErrorCode::OUT_OF_TIME;
494 }
495 HILOG_INFO(LOG_CORE, "WriteTracePipeRawData end, path: %{public}s, byte: %{public}zd. g_writeFileLimit: %{public}d",
496 srcPath.c_str(), writeLen, g_writeFileLimit);
497 close(rawTraceFd);
498 return true;
499 }
500
ReadTracePipeRawLoop(const int srcFd,int & bytes,bool & endFlag,int & pageChkFailedTime,bool & printFirstPageTime)501 void ITraceCpuRawContent::ReadTracePipeRawLoop(const int srcFd,
502 int& bytes, bool& endFlag, int& pageChkFailedTime, bool& printFirstPageTime)
503 {
504 while (bytes <= (BUFFER_SIZE - static_cast<int>(PAGE_SIZE))) {
505 ssize_t readBytes = TEMP_FAILURE_RETRY(read(srcFd, g_buffer + bytes, PAGE_SIZE));
506 if (readBytes <= 0) {
507 endFlag = true;
508 HILOG_DEBUG(LOG_CORE, "ReadTracePipeRawLoop: read raw trace done, size(%{public}zd), err(%{public}s).",
509 readBytes, strerror(errno));
510 break;
511 }
512 uint64_t pageTraceTime = 0;
513 if (memcpy_s(&pageTraceTime, sizeof(pageTraceTime), g_buffer + bytes, sizeof(uint64_t)) != EOK) {
514 HILOG_ERROR(LOG_CORE, "ReadTracePipeRawLoop: failed to memcpy g_buffer to pageTraceTime.");
515 break;
516 }
517 // attention : only capture target duration trace data
518 int pageValid = IsCurrentTracePageValid(pageTraceTime, request_.traceStartTime, request_.traceEndTime);
519 if (pageValid < 0) {
520 endFlag = true;
521 bytes += (printFirstPageTime ? readBytes : 0);
522 break;
523 } else if (pageValid == 0) {
524 continue;
525 }
526
527 lastPageTimeStamp_ = std::max(lastPageTimeStamp_, pageTraceTime);
528 if (UNEXPECTANTLY(!printFirstPageTime)) {
529 HILOG_INFO(LOG_CORE, "ReadTracePipeRawLoop: First page trace time(%{public}" PRIu64 ")", pageTraceTime);
530 printFirstPageTime = true;
531 firstPageTimeStamp_ = std::min(firstPageTimeStamp_, pageTraceTime);
532 }
533
534 if (!CheckPage(g_buffer + bytes)) {
535 pageChkFailedTime++;
536 }
537 bytes += readBytes;
538 if (pageChkFailedTime >= 2) { // 2 : check failed times threshold
539 endFlag = true;
540 break;
541 }
542 }
543 }
544
IsWriteFileOverflow(const int outputFileSize,const ssize_t writeLen,const int fileSizeThreshold)545 bool ITraceCpuRawContent::IsWriteFileOverflow(const int outputFileSize, const ssize_t writeLen,
546 const int fileSizeThreshold)
547 {
548 // attention: we only check file size threshold in CMD/CACHE mode if need.
549 if ((request_.type != TraceDumpType::TRACE_RECORDING && request_.type != TraceDumpType::TRACE_CACHE) ||
550 !request_.limitFileSz) {
551 return false;
552 }
553 if (outputFileSize + writeLen + static_cast<int>(sizeof(TraceFileContentHeader)) >= fileSizeThreshold) {
554 HILOG_ERROR(LOG_CORE, "Failed to write, current round write file size exceeds the file size limit(%{public}d).",
555 fileSizeThreshold);
556 return true;
557 }
558 if (writeLen > INT_MAX - BUFFER_SIZE) {
559 HILOG_ERROR(LOG_CORE, "Failed to write, write file length is nearly overflow.");
560 return true;
561 }
562 return false;
563 }
564
IsOverFlow()565 bool ITraceCpuRawContent::IsOverFlow()
566 {
567 return isOverFlow_;
568 }
569
WriteTraceContent()570 bool TraceCpuRawLinux::WriteTraceContent()
571 {
572 int cpuNums = GetCpuProcessors();
573 for (int cpuIdx = 0; cpuIdx < cpuNums; cpuIdx++) {
574 std::string srcPath = tracefsPath_ + "per_cpu/cpu" + std::to_string(cpuIdx) + "/trace_pipe_raw";
575 if (!WriteTracePipeRawData(srcPath, cpuIdx)) {
576 return false;
577 }
578 }
579 if (dumpStatus_ != TraceErrorCode::SUCCESS) {
580 HILOG_ERROR(LOG_CORE, "TraceCpuRawLinux WriteTraceContent failed, dump status: %{public}hhu.", dumpStatus_);
581 return false;
582 }
583 return true;
584 }
585
WriteTraceContent()586 bool TraceCpuRawHM::WriteTraceContent()
587 {
588 std::string srcPath = tracefsPath_ + "/trace_pipe_raw";
589 if (!WriteTracePipeRawData(srcPath, 0)) { // 0 : hongmeng kernel only has one cpu trace raw pipe
590 return false;
591 }
592 if (dumpStatus_ != TraceErrorCode::SUCCESS) {
593 HILOG_ERROR(LOG_CORE, "TraceCpuRawHM WriteTraceContent failed, dump status: %{public}hhu.", dumpStatus_);
594 return false;
595 }
596 return true;
597 }
598
CopyTracePipeRawLoop(const int srcFd,const int cpu,ssize_t & writeLen,int & pageChkFailedTime,bool & printFirstPageTime)599 bool ITraceCpuRawRead::CopyTracePipeRawLoop(const int srcFd, const int cpu, ssize_t& writeLen,
600 int& pageChkFailedTime, bool& printFirstPageTime)
601 {
602 const size_t bufferSz = TraceBufferManager::GetInstance().GetBlockSize();
603 auto buffer = TraceBufferManager::GetInstance().AllocateBlock(request_.taskId, cpu);
604 if (buffer == nullptr) {
605 HILOG_ERROR(LOG_CORE, "CopyTracePipeRawLoop: Failed to allocate memory block.");
606 return true;
607 }
608 bool isStopRead = false;
609 ssize_t blockReadSz = 0;
610 uint8_t pageBuffer[PAGE_SIZE] = {};
611 while (blockReadSz <= static_cast<ssize_t>(bufferSz - PAGE_SIZE)) {
612 ssize_t readBytes = TEMP_FAILURE_RETRY(read(srcFd, pageBuffer, PAGE_SIZE));
613 if (readBytes <= 0) {
614 HILOG_DEBUG(LOG_CORE, "CopyTracePipeRawLoop: read raw trace done, size(%{public}zd), err(%{public}s).",
615 readBytes, strerror(errno));
616 break;
617 }
618 uint64_t pageTraceTime = 0;
619 if (memcpy_s(&pageTraceTime, sizeof(pageTraceTime), pageBuffer, sizeof(uint64_t)) != EOK) {
620 HILOG_ERROR(LOG_CORE, "CopyTracePipeRawLoop: failed to memcpy pagebuffer to pageTraceTime.");
621 break;
622 }
623 // attention : only capture target duration trace data
624 int pageValid = IsCurrentTracePageValid(pageTraceTime, request_.traceStartTime, request_.traceEndTime);
625 if (pageValid < 0) {
626 isStopRead = true;
627 blockReadSz += (printFirstPageTime ? readBytes : 0);
628 buffer->Append(pageBuffer, readBytes);
629 break;
630 } else if (pageValid == 0) {
631 continue;
632 }
633 lastPageTimeStamp_ = std::max(lastPageTimeStamp_, pageTraceTime);
634 if (UNEXPECTANTLY(!printFirstPageTime)) {
635 HILOG_INFO(LOG_CORE, "CopyTracePipeRawLoop: First page trace time(%{public}" PRIu64 ")", pageTraceTime);
636 printFirstPageTime = true;
637 firstPageTimeStamp_ = std::min(firstPageTimeStamp_, pageTraceTime);
638 }
639 if (!CheckPage(pageBuffer)) {
640 pageChkFailedTime++;
641 }
642 blockReadSz += readBytes;
643 buffer->Append(pageBuffer, readBytes);
644 if (pageChkFailedTime >= 2) { // 2 : check failed times threshold
645 isStopRead = true;
646 break;
647 }
648 }
649 writeLen += blockReadSz;
650 return isStopRead;
651 }
652
CacheTracePipeRawData(const std::string & srcPath,const int cpuIdx)653 bool ITraceCpuRawRead::CacheTracePipeRawData(const std::string& srcPath, const int cpuIdx)
654 {
655 std::string path = CanonicalizeSpecPath(srcPath.c_str());
656 auto rawTraceFd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
657 if (rawTraceFd < 0) {
658 HILOG_ERROR(LOG_CORE, "CacheTracePipeRawData: open %{public}s failed.", srcPath.c_str());
659 return false;
660 }
661 ssize_t writeLen = 0;
662 int pageChkFailedTime = 0;
663 bool printFirstPageTime = false; // attention: update first page time in every WriteTracePipeRawData calling.
664 while (true) {
665 if (CopyTracePipeRawLoop(rawTraceFd, cpuIdx, writeLen, pageChkFailedTime, printFirstPageTime)) {
666 break;
667 }
668 }
669 if (writeLen > 0) {
670 dumpStatus_ = TraceErrorCode::SUCCESS;
671 } else if (dumpStatus_ == TraceErrorCode::UNSET) {
672 dumpStatus_ = TraceErrorCode::OUT_OF_TIME;
673 }
674 HILOG_INFO(LOG_CORE, "CacheTracePipeRawData end, path: %{public}s, byte: %{public}zd", srcPath.c_str(), writeLen);
675 close(rawTraceFd);
676 return true;
677 }
678
WriteTraceContent()679 bool TraceCpuRawReadLinux::WriteTraceContent()
680 {
681 int cpuNums = GetCpuProcessors();
682 for (int cpuIdx = 0; cpuIdx < cpuNums; cpuIdx++) {
683 std::string srcPath = tracefsPath_ + "per_cpu/cpu" + std::to_string(cpuIdx) + "/trace_pipe_raw";
684 if (!CacheTracePipeRawData(srcPath, cpuIdx)) {
685 return false;
686 }
687 }
688 if (dumpStatus_ != TraceErrorCode::SUCCESS) {
689 HILOG_ERROR(LOG_CORE, "TraceCpuRawReadLinux WriteTraceContent failed, dump status: %{public}hhu.", dumpStatus_);
690 TraceBufferManager::GetInstance().ReleaseTaskBlocks(request_.taskId);
691 return false;
692 }
693 return true;
694 }
695
WriteTraceContent()696 bool TraceCpuRawReadHM::WriteTraceContent()
697 {
698 std::string srcPath = tracefsPath_ + "/trace_pipe_raw";
699 if (!CacheTracePipeRawData(srcPath, 0)) { // 0 : hongmeng kernel only has one cpu trace raw pipe
700 return false;
701 }
702 if (dumpStatus_ != TraceErrorCode::SUCCESS) {
703 HILOG_ERROR(LOG_CORE, "TraceCpuRawReadHM WriteTraceContent failed, dump status: %{public}hhu.", dumpStatus_);
704 TraceBufferManager::GetInstance().ReleaseTaskBlocks(request_.taskId);
705 return false;
706 }
707 return true;
708 }
709
WriteTraceContent()710 bool TraceCpuRawWriteLinux::WriteTraceContent()
711 {
712 if (!IsFileExist()) {
713 HILOG_ERROR(LOG_CORE, "TraceCpuRawWriteLinux::WriteTraceContent trace file (%{public}s) not found.",
714 traceFilePath_.c_str());
715 return false;
716 }
717 int prevCpu = -1;
718 ssize_t writeLen = 0;
719 struct TraceFileContentHeader rawHeader;
720 auto buffers = TraceBufferManager::GetInstance().GetTaskBuffers(taskId_);
721 for (auto& bufItem : buffers) {
722 int cpuIdx = bufItem->cpu;
723 if (cpuIdx != prevCpu) {
724 writeLen = 0;
725 if (!DoWriteTraceContentHeader(rawHeader, CONTENT_TYPE_CPU_RAW + cpuIdx)) {
726 return false;
727 }
728 }
729 DoWriteTraceData(bufItem->data.data(), bufItem->usedBytes, writeLen); // attention: maybe write null data.
730 UpdateTraceContentHeader(rawHeader, static_cast<uint32_t>(writeLen));
731 }
732 TraceBufferManager::GetInstance().ReleaseTaskBlocks(taskId_);
733 HILOG_INFO(LOG_CORE, "TraceCpuRawWriteLinux::WriteTraceContent write len %{public}zd", writeLen);
734 return true;
735 }
736
WriteTraceContent()737 bool TraceCpuRawWriteHM::WriteTraceContent()
738 {
739 if (!IsFileExist()) {
740 HILOG_ERROR(LOG_CORE, "TraceCpuRawWriteHM::WriteTraceContent trace file (%{public}s) not found.",
741 traceFilePath_.c_str());
742 return false;
743 }
744 struct TraceFileContentHeader rawHeader;
745 if (!DoWriteTraceContentHeader(rawHeader, CONTENT_TYPE_CPU_RAW)) {
746 return false;
747 }
748 ssize_t writeLen = 0;
749 auto buffers = TraceBufferManager::GetInstance().GetTaskBuffers(taskId_);
750 for (auto& bufItem : buffers) {
751 DoWriteTraceData(bufItem->data.data(), bufItem->usedBytes, writeLen); // attention: maybe write null data.
752 }
753 UpdateTraceContentHeader(rawHeader, static_cast<uint32_t>(writeLen));
754 TraceBufferManager::GetInstance().ReleaseTaskBlocks(taskId_);
755 return true;
756 }
757
TraceHeaderPageLinux(const int fd,const std::string & tracefsPath,const std::string & traceFilePath)758 TraceHeaderPageLinux::TraceHeaderPageLinux(const int fd,
759 const std::string& tracefsPath, const std::string& traceFilePath)
760 : ITraceHeaderPageContent(fd, tracefsPath, traceFilePath, false)
761 {
762 const std::string headerPagePath = tracefsPath_ + "events/header_page";
763 traceSourceFd_ = open(headerPagePath.c_str(), O_RDONLY | O_NONBLOCK);
764 if (traceSourceFd_ < 0) {
765 HILOG_ERROR(LOG_CORE, "TraceHeaderPageLinux: open %{public}s failed.", headerPagePath.c_str());
766 }
767 }
768
WriteTraceContent()769 bool TraceHeaderPageLinux::WriteTraceContent()
770 {
771 return WriteTraceData(CONTENT_TYPE_HEADER_PAGE);
772 }
773
WriteTraceContent()774 bool TraceHeaderPageHM::WriteTraceContent()
775 {
776 return true;
777 }
778
TracePrintkFmtLinux(const int fd,const std::string & tracefsPath,const std::string & traceFilePath)779 TracePrintkFmtLinux::TracePrintkFmtLinux(const int fd,
780 const std::string& tracefsPath, const std::string& traceFilePath)
781 : ITracePrintkFmtContent(fd, tracefsPath, traceFilePath, false)
782 {
783 const std::string printkFormatPath = tracefsPath_ + "printk_formats";
784 traceSourceFd_ = open(printkFormatPath.c_str(), O_RDONLY | O_NONBLOCK);
785 if (traceSourceFd_ < 0) {
786 HILOG_ERROR(LOG_CORE, "TracePrintkFmtLinux: open %{public}s failed.", printkFormatPath.c_str());
787 }
788 }
789
WriteTraceContent()790 bool TracePrintkFmtLinux::WriteTraceContent()
791 {
792 return WriteTraceData(CONTENT_TYPE_PRINTK_FORMATS);
793 }
794
WriteTraceContent()795 bool TracePrintkFmtHM::WriteTraceContent()
796 {
797 return true;
798 }
799 } // namespace Hitrace
800 } // namespace HiviewDFX
801 } // namespace OHOS