• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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