• 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_dump_executor.h"
17 
18 #include <algorithm>
19 #include <securec.h>
20 #include <sys/prctl.h>
21 #include <sys/stat.h>
22 #include <thread>
23 #include <unistd.h>
24 
25 #include "common_define.h"
26 #include "common_utils.h"
27 #include "file_ageing_utils.h"
28 #include "hilog/log.h"
29 #include "trace_file_utils.h"
30 #include "trace_json_parser.h"
31 
32 namespace OHOS {
33 namespace HiviewDFX {
34 namespace Hitrace {
35 #ifdef LOG_DOMAIN
36 #undef LOG_DOMAIN
37 #define LOG_DOMAIN 0xD002D33
38 #endif
39 #ifdef LOG_TAG
40 #undef LOG_TAG
41 #define LOG_TAG "HitraceDumpExecutor"
42 #endif
43 namespace {
44 constexpr int BYTE_PER_KB = 1024;
45 constexpr int MAX_NEW_TRACE_FILE_LIMIT = 5;
46 #ifdef HITRACE_UNITTEST
47 constexpr int DEFAULT_CACHE_FILE_SIZE = 15 * 1024;
48 #else
49 constexpr int DEFAULT_CACHE_FILE_SIZE = 150 * 1024;
50 #endif
51 constexpr uint64_t SYNC_RETURN_TIMEOUT_NS = 5000000000; // 5s
52 constexpr int64_t ASYNC_DUMP_FILE_SIZE_ADDITION = 1024 * 1024; // 1MB
53 
54 static bool g_isRootVer = IsRootVersion();
55 
56 uint64_t g_sliceMaxDuration = 30; // 30 : 30 seconds as default cache trace slice duration
57 
58 // use for control status of trace dump loop.
59 std::atomic<bool> g_isDumpRunning(false);
60 std::atomic<bool> g_isDumpEnded(true);
61 std::atomic<bool> g_interruptCache(false);
62 std::atomic<bool> g_readFlag(true);
63 std::atomic<bool> g_writeFlag(true);
64 
FilterLoopTraceResult(const std::vector<TraceFileInfo> & looptraceFiles)65 std::vector<std::string> FilterLoopTraceResult(const std::vector<TraceFileInfo>& looptraceFiles)
66 {
67     std::vector<std::string> outputFiles = {};
68     for (const auto& output : looptraceFiles) {
69         if (output.isNewFile) {
70             outputFiles.emplace_back(output.filename);
71         }
72     }
73     return outputFiles;
74 }
75 
IsGenerateNewFile(std::shared_ptr<ITraceSource> traceSource,const TraceDumpType traceType,int & count)76 bool IsGenerateNewFile(std::shared_ptr<ITraceSource> traceSource, const TraceDumpType traceType, int& count)
77 {
78     if (access(traceSource->GetTraceFilePath().c_str(), F_OK) == 0) {
79         return false;
80     }
81     if (count > MAX_NEW_TRACE_FILE_LIMIT) {
82         HILOG_ERROR(LOG_CORE, "create new trace file limited.");
83         return false;
84     }
85     count++;
86     auto newFileName = GenerateTraceFileName(traceType);
87     traceSource->UpdateTraceFile(newFileName);
88     HILOG_INFO(LOG_CORE, "IsGenerateNewFile: update tracesource filename : %{public}s", newFileName.c_str());
89     return true;
90 }
91 
PreTraceContentDump(const TraceContentPtr & traceContentPtr)92 void PreTraceContentDump(const TraceContentPtr& traceContentPtr)
93 {
94     traceContentPtr.fileHdr->ResetCurrentFileSize();
95     if (!traceContentPtr.fileHdr->WriteTraceContent()) {
96         HILOG_INFO(LOG_CORE, "fileHdr WriteTraceContent failed.");
97     }
98     if (!traceContentPtr.baseInfo->WriteTraceContent()) {
99         HILOG_INFO(LOG_CORE, "baseInfo WriteTraceContent failed.");
100     }
101     if (!traceContentPtr.eventFmt->WriteTraceContent()) {
102         HILOG_INFO(LOG_CORE, "fileHdr WriteTraceContent failed.");
103     }
104 }
105 
AfterTraceContentDump(const TraceContentPtr & traceContentPtr)106 void AfterTraceContentDump(const TraceContentPtr& traceContentPtr)
107 {
108     if (!traceContentPtr.cmdLines->WriteTraceContent()) {
109         HILOG_INFO(LOG_CORE, "cmdLines WriteTraceContent failed.");
110     }
111     if (!traceContentPtr.tgids->WriteTraceContent()) {
112         HILOG_INFO(LOG_CORE, "tgids WriteTraceContent failed.");
113     }
114     if (!traceContentPtr.headerPage->WriteTraceContent()) {
115         HILOG_INFO(LOG_CORE, "headerPage WriteTraceContent failed.");
116     }
117     if (!traceContentPtr.printkFmt->WriteTraceContent()) {
118         HILOG_INFO(LOG_CORE, "printkFmt WriteTraceContent failed.");
119     }
120 }
121 }
122 
CreateTraceContentPtr(std::shared_ptr<ITraceSource> traceSource,const TraceDumpRequest & request,TraceContentPtr & contentPtr)123 bool ITraceDumpStrategy::CreateTraceContentPtr(std::shared_ptr<ITraceSource> traceSource,
124     const TraceDumpRequest& request, TraceContentPtr& contentPtr)
125 {
126     contentPtr.fileHdr = traceSource->GetTraceFileHeader();
127     if (contentPtr.fileHdr == nullptr) {
128         HILOG_ERROR(LOG_CORE, "CreateTraceContentPtr: GetTraceFileHeader failed.");
129         return false;
130     }
131     contentPtr.baseInfo = traceSource->GetTraceBaseInfo();
132     if (contentPtr.baseInfo == nullptr) {
133         HILOG_ERROR(LOG_CORE, "CreateTraceContentPtr: GetTraceBaseInfo failed.");
134         return false;
135     }
136     contentPtr.eventFmt = traceSource->GetTraceEventFmt();
137     if (contentPtr.eventFmt == nullptr) {
138         HILOG_ERROR(LOG_CORE, "CreateTraceContentPtr: GetTraceEventFmt failed.");
139         return false;
140     }
141     contentPtr.cpuRaw = traceSource->GetTraceCpuRaw(request);
142     if (contentPtr.cpuRaw == nullptr) {
143         HILOG_ERROR(LOG_CORE, "CreateTraceContentPtr: GetTraceCpuRaw failed.");
144         return false;
145     }
146     contentPtr.cmdLines = traceSource->GetTraceCmdLines();
147     if (contentPtr.cmdLines == nullptr) {
148         HILOG_ERROR(LOG_CORE, "CreateTraceContentPtr: GetTraceCmdLines failed.");
149         return false;
150     }
151     contentPtr.tgids = traceSource->GetTraceTgids();
152     if (contentPtr.tgids == nullptr) {
153         HILOG_ERROR(LOG_CORE, "CreateTraceContentPtr: GetTraceTgids failed.");
154         return false;
155     }
156     contentPtr.headerPage = traceSource->GetTraceHeaderPage();
157     if (contentPtr.headerPage == nullptr) {
158         HILOG_ERROR(LOG_CORE, "CreateTraceContentPtr: GetTraceHeaderPage failed.");
159         return false;
160     }
161     contentPtr.printkFmt = traceSource->GetTracePrintkFmt();
162     if (contentPtr.printkFmt == nullptr) {
163         HILOG_ERROR(LOG_CORE, "CreateTraceContentPtr: GetTracePrintkFmt failed.");
164         return false;
165     }
166     return true;
167 }
168 
Execute(std::shared_ptr<ITraceSource> traceSource,const TraceDumpRequest & request)169 TraceDumpRet SnapshotTraceDumpStrategy::Execute(std::shared_ptr<ITraceSource> traceSource,
170     const TraceDumpRequest& request)
171 {
172     struct TraceContentPtr traceContentPtr;
173     if (!CreateTraceContentPtr(traceSource, request, traceContentPtr)) {
174         HILOG_ERROR(LOG_CORE, "SnapshotTraceDumpStrategy: CreateTraceContentPtr failed.");
175         return {TraceErrorCode::WRITE_TRACE_INFO_ERROR, "", 0, 0};
176     }
177     PreTraceContentDump(traceContentPtr);
178     if (!traceContentPtr.cpuRaw->WriteTraceContent()) {
179         return {traceContentPtr.cpuRaw->GetDumpStatus(), "", 0, 0};
180     }
181     AfterTraceContentDump(traceContentPtr);
182 
183     auto traceFile = traceContentPtr.cpuRaw->GetTraceFilePath();
184     TraceDumpRet ret = {
185         .code = traceContentPtr.cpuRaw->GetDumpStatus(),
186         .traceStartTime = traceContentPtr.cpuRaw->GetFirstPageTimeStamp(),
187         .traceEndTime = traceContentPtr.cpuRaw->GetLastPageTimeStamp(),
188     };
189     if (strncpy_s(ret.outputFile, TRACE_FILE_LEN, traceFile.c_str(), TRACE_FILE_LEN - 1) != 0) {
190         HILOG_ERROR(LOG_CORE, "SnapshotTraceDumpStrategy: strncpy_s failed.");
191     }
192 
193     return ret;
194 }
195 
ProcessTraceContent(std::shared_ptr<ITraceSource> traceSource,const TraceDumpRequest & request,TraceContentPtr & traceContentPtr,TraceProcessResult & result)196 bool RecordTraceDumpStrategy::ProcessTraceContent(std::shared_ptr<ITraceSource> traceSource,
197     const TraceDumpRequest& request, TraceContentPtr& traceContentPtr, TraceProcessResult& result)
198 {
199     while (g_isDumpRunning.load()) {
200         sleep(1);
201         auto updatedRequest = request;
202         updatedRequest.traceEndTime = GetCurBootTime();
203         traceContentPtr.cpuRaw = traceSource->GetTraceCpuRaw(updatedRequest);
204         if (!traceContentPtr.cpuRaw->WriteTraceContent()) {
205             return false;
206         }
207         if (traceContentPtr.cpuRaw->IsOverFlow()) {
208             HILOG_INFO(LOG_CORE, "RecordTraceDumpStrategy: write trace content overflow.");
209             break;
210         }
211         result.code = traceContentPtr.cpuRaw->GetDumpStatus();
212         result.traceFile = traceContentPtr.cpuRaw->GetTraceFilePath();
213         result.traceStartTime = traceContentPtr.cpuRaw->GetFirstPageTimeStamp();
214         result.traceEndTime = traceContentPtr.cpuRaw->GetLastPageTimeStamp();
215     }
216     return true;
217 }
218 
Execute(std::shared_ptr<ITraceSource> traceSource,const TraceDumpRequest & request)219 TraceDumpRet RecordTraceDumpStrategy::Execute(std::shared_ptr<ITraceSource> traceSource,
220     const TraceDumpRequest& request)
221 {
222     int newFileCount = 1;
223     TraceProcessResult result = {};
224     do {
225         struct TraceContentPtr traceContentPtr;
226         if (!CreateTraceContentPtr(traceSource, request, traceContentPtr)) {
227             HILOG_ERROR(LOG_CORE, "RecordTraceDumpStrategy: CreateTraceContentPtr failed.");
228             return {TraceErrorCode::WRITE_TRACE_INFO_ERROR, "", 0, 0};
229         }
230         PreTraceContentDump(traceContentPtr);
231         if (!ProcessTraceContent(traceSource, request, traceContentPtr, result)) {
232             if (!IsGenerateNewFile(traceSource, TraceDumpType::TRACE_RECORDING, newFileCount)) {
233                 HILOG_ERROR(LOG_CORE, "RecordTraceDumpStrategy: write raw trace content failed.");
234                 break;
235             }
236             continue;
237         }
238         AfterTraceContentDump(traceContentPtr);
239     } while (IsGenerateNewFile(traceSource, TraceDumpType::TRACE_RECORDING, newFileCount));
240 
241     TraceDumpRet ret = {
242         .code = result.code,
243         .traceStartTime = result.traceStartTime,
244         .traceEndTime = result.traceEndTime,
245     };
246     if (strncpy_s(ret.outputFile, TRACE_FILE_LEN, result.traceFile.c_str(), TRACE_FILE_LEN - 1) != 0) {
247         HILOG_ERROR(LOG_CORE, "RecordTraceDumpStrategy: strncpy_s failed.");
248     }
249     return ret;
250 }
251 
ProcessTraceContent(std::shared_ptr<ITraceSource> traceSource,const TraceDumpRequest & request,TraceContentPtr & traceContentPtr,TraceProcessResult & result,uint64_t & sliceDuration)252 bool CacheTraceDumpStrategy::ProcessTraceContent(std::shared_ptr<ITraceSource> traceSource,
253     const TraceDumpRequest& request, TraceContentPtr& traceContentPtr, TraceProcessResult& result,
254     uint64_t& sliceDuration)
255 {
256     while (g_isDumpRunning.load()) {
257         struct timespec bts = {0, 0};
258         clock_gettime(CLOCK_BOOTTIME, &bts);
259         uint64_t startTime = static_cast<uint64_t>(bts.tv_sec * S_TO_NS + bts.tv_nsec);
260         sleep(1);
261         if (!traceContentPtr.cpuRaw->WriteTraceContent()) {
262             return false;
263         }
264         clock_gettime(CLOCK_BOOTTIME, &bts);
265         uint64_t endTime = static_cast<uint64_t>(bts.tv_sec * S_TO_NS + bts.tv_nsec);
266         uint64_t timeDiff = (endTime - startTime) / S_TO_NS;
267         result.code = traceContentPtr.cpuRaw->GetDumpStatus();
268         result.traceFile = traceContentPtr.cpuRaw->GetTraceFilePath();
269         result.traceStartTime = traceContentPtr.cpuRaw->GetFirstPageTimeStamp();
270         result.traceEndTime = traceContentPtr.cpuRaw->GetLastPageTimeStamp();
271         sliceDuration += timeDiff;
272         if (sliceDuration >= g_sliceMaxDuration || g_interruptCache.load()) {
273             sliceDuration = 0;
274             break;
275         }
276     }
277     return true;
278 }
279 
Execute(std::shared_ptr<ITraceSource> traceSource,const TraceDumpRequest & request)280 TraceDumpRet CacheTraceDumpStrategy::Execute(std::shared_ptr<ITraceSource> traceSource,
281     const TraceDumpRequest& request)
282 {
283     int newFileCount = 1;
284     TraceProcessResult result = {};
285     uint64_t sliceDuration = 0;
286     do {
287         struct TraceContentPtr traceContentPtr;
288         if (!CreateTraceContentPtr(traceSource, request, traceContentPtr)) {
289             return {TraceErrorCode::WRITE_TRACE_INFO_ERROR, "", 0, 0};
290         }
291         PreTraceContentDump(traceContentPtr);
292         if (!ProcessTraceContent(traceSource, request, traceContentPtr, result, sliceDuration)) {
293             if (!IsGenerateNewFile(traceSource, TraceDumpType::TRACE_CACHE, newFileCount)) {
294                 HILOG_ERROR(LOG_CORE, "CacheTraceDumpStrategy: write raw trace content failed.");
295                 break;
296             }
297             continue;
298         }
299         AfterTraceContentDump(traceContentPtr);
300     } while (IsGenerateNewFile(traceSource, TraceDumpType::TRACE_CACHE, newFileCount));
301 
302     TraceDumpRet ret = {
303         .code = result.code,
304         .traceStartTime = result.traceStartTime,
305         .traceEndTime = result.traceEndTime,
306     };
307     if (strncpy_s(ret.outputFile, TRACE_FILE_LEN, result.traceFile.c_str(), TRACE_FILE_LEN - 1) != 0) {
308         HILOG_ERROR(LOG_CORE, "CacheTraceDumpStrategy: strncpy_s failed.");
309     }
310     return ret;
311 }
312 
Execute(std::shared_ptr<ITraceSource> traceSource,const TraceDumpRequest & request)313 TraceDumpRet AsyncTraceReadStrategy::Execute(std::shared_ptr<ITraceSource> traceSource, const TraceDumpRequest& request)
314 {
315     auto cpuRawRead = traceSource->GetTraceCpuRawRead(request);
316     if (!cpuRawRead->WriteTraceContent()) {
317         return {cpuRawRead->GetDumpStatus(), "", 0, 0};
318     }
319 
320     TraceDumpRet ret = {
321         .code = cpuRawRead->GetDumpStatus(),
322         .fileSize = static_cast<int64_t>(TraceBufferManager::GetInstance().GetTaskTotalUsedBytes(request.taskId)),
323         .traceStartTime = cpuRawRead->GetFirstPageTimeStamp(),
324         .traceEndTime = cpuRawRead->GetLastPageTimeStamp(),
325     };
326     auto tracefile = GenerateTraceFileNameByTraceTime(request.type, ret.traceStartTime, ret.traceEndTime);
327     if (strncpy_s(ret.outputFile, TRACE_FILE_LEN, tracefile.c_str(), TRACE_FILE_LEN - 1) != 0) {
328         HILOG_ERROR(LOG_CORE, "AsyncTraceReadStrategy: strncpy_s failed.");
329     }
330     HILOG_INFO(LOG_CORE, "AsyncTraceReadStrategy: trace file : %{public}s, file size : %{public}" PRId64,
331         ret.outputFile, ret.fileSize);
332     return ret;
333 }
334 
Execute(std::shared_ptr<ITraceSource> traceSource,const TraceDumpRequest & request)335 TraceDumpRet AsyncTraceWriteStrategy::Execute(std::shared_ptr<ITraceSource> traceSource,
336     const TraceDumpRequest& request)
337 {
338     struct TraceContentPtr traceContentPtr;
339     if (!CreateTraceContentPtr(traceSource, request, traceContentPtr)) {
340         HILOG_ERROR(LOG_CORE, "AsyncTraceWriteStrategy: CreateTraceContentPtr failed.");
341         return {TraceErrorCode::WRITE_TRACE_INFO_ERROR, "", 0, 0};
342     }
343     PreTraceContentDump(traceContentPtr);
344     auto cpuRawWrite = traceSource->GetTraceCpuRawWrite(request.taskId);
345     if (!cpuRawWrite->WriteTraceContent()) {
346         return {TraceErrorCode::FILE_ERROR, "", 0, 0};
347     }
348     AfterTraceContentDump(traceContentPtr);
349     TraceDumpRet ret = {
350         .code = TraceErrorCode::SUCCESS
351     };
352     return ret;
353 }
354 
TraceDumpExecutor()355 TraceDumpExecutor::TraceDumpExecutor()
356 {
357     if (!IsTraceMounted(tracefsDir_)) {
358         HILOG_ERROR(LOG_CORE, "TraceDumpExecutor: Trace is not mounted.");
359     }
360 }
361 
PreCheckDumpTraceLoopStatus()362 bool TraceDumpExecutor::PreCheckDumpTraceLoopStatus()
363 {
364     if (!g_isDumpEnded.load()) {
365         return false;
366     }
367     g_isDumpRunning.store(true);
368     g_isDumpEnded.store(false);
369     return true;
370 }
371 
StartDumpTraceLoop(const TraceDumpParam & param)372 bool TraceDumpExecutor::StartDumpTraceLoop(const TraceDumpParam& param)
373 {
374     {
375         std::lock_guard<std::mutex> lck(traceFileMutex_);
376         loopTraceFiles_.clear();
377         GetTraceFilesInDir(loopTraceFiles_, TraceDumpType::TRACE_RECORDING);
378         FileAgeingUtils::HandleAgeing(loopTraceFiles_, TraceDumpType::TRACE_RECORDING);
379     }
380 
381     if (param.fileSize == 0 && g_isRootVer) {
382         std::string traceFile = param.outputFile.empty() ? GenerateTraceFileName(param.type) : param.outputFile;
383         if (DoDumpTraceLoop(param, traceFile, false)) {
384             std::lock_guard<std::mutex> lck(traceFileMutex_);
385             loopTraceFiles_.emplace_back(traceFile);
386         }
387         g_isDumpEnded.store(true);
388         g_isDumpRunning.store(false);
389         return true;
390     }
391 
392     while (g_isDumpRunning.load()) {
393         FileAgeingUtils::HandleAgeing(loopTraceFiles_, param.type);
394         std::string traceFile = GenerateTraceFileName(param.type);
395         if (DoDumpTraceLoop(param, traceFile, true)) {
396             std::lock_guard<std::mutex> lck(traceFileMutex_);
397             loopTraceFiles_.emplace_back(traceFile);
398         } else {
399             break;
400         }
401     }
402     g_isDumpEnded.store(true);
403     g_isDumpRunning.store(false);
404     return true;
405 }
406 
StopDumpTraceLoop()407 std::vector<std::string> TraceDumpExecutor::StopDumpTraceLoop()
408 {
409     g_isDumpRunning.store(false);
410     while (!g_isDumpEnded.load()) {
411         std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 100 : 100ms
412         g_isDumpRunning.store(false);
413     }
414 
415     std::lock_guard<std::mutex> lck(traceFileMutex_);
416     return FilterLoopTraceResult(loopTraceFiles_);
417 }
418 
StartCacheTraceLoop(const TraceDumpParam & param,uint64_t totalFileSize,uint64_t sliceMaxDuration)419 bool TraceDumpExecutor::StartCacheTraceLoop(const TraceDumpParam& param,
420     uint64_t totalFileSize, uint64_t sliceMaxDuration)
421 {
422     g_sliceMaxDuration = sliceMaxDuration;
423     while (g_isDumpRunning.load()) {
424         auto traceFile = GenerateTraceFileName(param.type);
425         if (DoDumpTraceLoop(param, traceFile, true)) {
426             std::lock_guard<std::mutex> cacheLock(traceFileMutex_);
427             ClearCacheTraceFileBySize(cacheTraceFiles_, totalFileSize);
428             HILOG_INFO(LOG_CORE, "ProcessCacheTask: save cache file.");
429         } else {
430             break;
431         }
432     }
433     g_isDumpEnded.store(true);
434     return true;
435 }
436 
StopCacheTraceLoop()437 void TraceDumpExecutor::StopCacheTraceLoop()
438 {
439     g_isDumpRunning.store(false);
440     while (!g_isDumpEnded.load()) {
441         std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 100 : 100ms
442         g_isDumpRunning.store(false);
443     }
444 }
445 
DumpTrace(const TraceDumpParam & param)446 TraceDumpRet TraceDumpExecutor::DumpTrace(const TraceDumpParam& param)
447 {
448     MarkClockSync(tracefsDir_);
449     constexpr int waitTime = 10000; // 10ms
450     usleep(waitTime);
451     const std::string traceFile = GenerateTraceFileName(param.type);
452     return DumpTraceInner(param, traceFile);
453 }
454 
GetCacheTraceFiles()455 std::vector<TraceFileInfo> TraceDumpExecutor::GetCacheTraceFiles()
456 {
457     g_interruptCache.store(true);
458     std::vector<TraceFileInfo> cacheFiles;
459     {
460         std::lock_guard<std::mutex> lock(traceFileMutex_);
461         cacheFiles = cacheTraceFiles_;
462         g_interruptCache.store(false);
463     }
464     return cacheFiles;
465 }
466 
ReadRawTraceLoop()467 void TraceDumpExecutor::ReadRawTraceLoop()
468 {
469     const std::string threadName = "ReadRawTraceLoop";
470     prctl(PR_SET_NAME, threadName.c_str());
471     HILOG_INFO(LOG_CORE, "ReadRawTraceLoop start.");
472     while (g_readFlag.load()) {
473         TraceDumpTask currentTask;
474         bool hasTask = false;
475         {
476             std::unique_lock<std::mutex> lck(taskQueueMutex_);
477             readCondVar_.wait(lck, [this]() {
478                 return !g_readFlag.load() ||
479                     std::any_of(traceDumpTaskVec_.begin(), traceDumpTaskVec_.end(), [](const TraceDumpTask& task) {
480                         return task.status == TraceDumpStatus::START && task.code == TraceErrorCode::UNSET;
481                     });
482             });
483             if (!g_readFlag.load()) {
484                 break;
485             }
486             auto it = std::find_if(traceDumpTaskVec_.begin(), traceDumpTaskVec_.end(), [](const TraceDumpTask& task) {
487                 return task.status == TraceDumpStatus::START && task.code == TraceErrorCode::UNSET;
488             });
489             if (it != traceDumpTaskVec_.end()) {
490                 currentTask = *it;
491                 hasTask = true;
492             }
493         }
494         if (hasTask) {
495             HILOG_INFO(LOG_CORE, "ReadRawTraceLoop : start read trace of taskid[%{public}" PRIu64 "]",
496                 currentTask.time);
497             if (!DoReadRawTrace(currentTask)) {
498                 HILOG_WARN(LOG_CORE, "ReadRawTraceLoop : do read raw trace failed, taskid[%{public}" PRIu64 "]",
499                     currentTask.time);
500             } else {
501                 HILOG_INFO(LOG_CORE, "ReadRawTraceLoop : read raw trace done, taskid[%{public}" PRIu64 "]",
502                     currentTask.time);
503                 writeCondVar_.notify_one();
504             }
505         }
506     }
507     HILOG_INFO(LOG_CORE, "ReadRawTraceLoop end.");
508 }
509 
WriteTraceLoop()510 void TraceDumpExecutor::WriteTraceLoop()
511 {
512     const std::string threadName = "WriteTraceLoop";
513     prctl(PR_SET_NAME, threadName.c_str());
514     HILOG_INFO(LOG_CORE, "WriteTraceLoop start.");
515     while (g_writeFlag.load()) {
516         TraceDumpTask currentTask;
517         bool hasTask = false;
518         {
519             std::unique_lock<std::mutex> lck(taskQueueMutex_);
520             writeCondVar_.wait(lck, [this]() {
521                 return !g_writeFlag.load() ||
522                     std::any_of(traceDumpTaskVec_.begin(), traceDumpTaskVec_.end(), [](const TraceDumpTask& task) {
523                         return task.status == TraceDumpStatus::READ_DONE || task.status == TraceDumpStatus::WAIT_WRITE;
524                     });
525             });
526             if (!g_writeFlag.load()) {
527                 break;
528             }
529             auto it = std::find_if(traceDumpTaskVec_.begin(), traceDumpTaskVec_.end(), [](const TraceDumpTask& task) {
530                 return task.status == TraceDumpStatus::READ_DONE || task.status == TraceDumpStatus::WAIT_WRITE;
531             });
532             if (it != traceDumpTaskVec_.end()) {
533                 currentTask = *it;
534                 hasTask = true;
535             }
536         }
537         if (hasTask) {
538             HILOG_INFO(LOG_CORE, "WriteTraceLoop : start write trace of taskid[%{public}" PRIu64 "]", currentTask.time);
539             if (!DoWriteRawTrace(currentTask)) {
540                 HILOG_WARN(LOG_CORE, "WriteTraceLoop : do write raw trace failed, taskid[%{public}" PRIu64 "]",
541                     currentTask.time);
542             } else {
543                 HILOG_INFO(LOG_CORE, "WriteTraceLoop : write raw trace done, taskid[%{public}" PRIu64 "]",
544                     currentTask.time);
545             }
546         }
547     }
548     HILOG_INFO(LOG_CORE, "WriteTraceLoop end.");
549 }
550 
ProcessNewTask(std::shared_ptr<HitraceDumpPipe> & dumpPipe,int & sleepCnt)551 void TraceDumpExecutor::ProcessNewTask(std::shared_ptr<HitraceDumpPipe>& dumpPipe, int& sleepCnt)
552 {
553     TraceDumpTask newTask;
554     if (dumpPipe->ReadTraceTask(200, newTask)) { // 200 : 200ms
555         std::lock_guard<std::mutex> lck(taskQueueMutex_);
556         traceDumpTaskVec_.push_back(newTask);
557         readCondVar_.notify_one();
558         sleepCnt = 0;
559     }
560 }
561 
DoProcessTraceDumpTask(std::shared_ptr<HitraceDumpPipe> & dumpPipe,TraceDumpTask & task,std::vector<TraceDumpTask> & completedTasks)562 void TraceDumpExecutor::DoProcessTraceDumpTask(std::shared_ptr<HitraceDumpPipe>& dumpPipe, TraceDumpTask& task,
563     std::vector<TraceDumpTask>& completedTasks)
564 {
565     uint64_t curBootTime = GetCurBootTime();
566     if (task.status == TraceDumpStatus::WRITE_DONE) {
567         if (task.hasSyncReturn && dumpPipe->WriteAsyncReturn(task)) { // Async return
568             completedTasks.push_back(task);
569         } else if (!task.hasSyncReturn && dumpPipe->WriteSyncReturn(task)) { // Sync return
570             task.hasSyncReturn = true;
571             if (curBootTime - task.time <= SYNC_RETURN_TIMEOUT_NS) {
572                 completedTasks.push_back(task);
573             }
574         }
575     } else if (task.status == TraceDumpStatus::READ_DONE) {
576         if (task.code != TraceErrorCode::SUCCESS) {
577             task.status = TraceDumpStatus::WRITE_DONE;
578             auto writeRet = false;
579             if (!task.hasSyncReturn) {
580                 writeRet = dumpPipe->WriteSyncReturn(task);
581             } else {
582                 writeRet = dumpPipe->WriteAsyncReturn(task);
583             }
584             if (writeRet) {
585                 completedTasks.push_back(task);
586             }
587         } else if (!task.hasSyncReturn && curBootTime - task.time > SYNC_RETURN_TIMEOUT_NS) { // write trace timeout
588             if (dumpPipe->WriteSyncReturn(task)) {
589                 task.hasSyncReturn = true;
590                 task.status = TraceDumpStatus::WAIT_WRITE;
591                 writeCondVar_.notify_one();
592             }
593         }
594     }
595 }
596 
TraceDumpTaskMonitor()597 void TraceDumpExecutor::TraceDumpTaskMonitor()
598 {
599     auto dumpPipe = std::make_shared<HitraceDumpPipe>(false);
600     int sleepCnt = 0;
601     while (true) {
602         std::vector<TraceDumpTask> completedTasks;
603         {
604             std::lock_guard<std::mutex> lck(taskQueueMutex_);
605             for (auto& task : traceDumpTaskVec_) {
606                 DoProcessTraceDumpTask(dumpPipe, task, completedTasks);
607             }
608             // Remove completed tasks
609             for (const auto& task : completedTasks) {
610                 auto it = std::remove_if(traceDumpTaskVec_.begin(), traceDumpTaskVec_.end(),
611                     [&task](const TraceDumpTask& t) { return t.time == task.time; });
612                 traceDumpTaskVec_.erase(it, traceDumpTaskVec_.end());
613             }
614             if (!traceDumpTaskVec_.empty()) {
615                 sleepCnt = 0;
616             }
617         }
618         // Check for new tasks
619         ProcessNewTask(dumpPipe, sleepCnt);
620         sleep(1);
621         sleepCnt++;
622         if (sleepCnt >= 15 && IsTraceDumpTaskEmpty()) { // 15 : similar to 15 seconds
623             HILOG_INFO(LOG_CORE, "TraceDumpTaskMonitor : no task, dump process exit.");
624             g_readFlag.store(false);
625             g_writeFlag.store(false);
626             readCondVar_.notify_all();
627             writeCondVar_.notify_all();
628             break;
629         }
630     }
631 }
632 
RemoveTraceDumpTask(const uint64_t time)633 void TraceDumpExecutor::RemoveTraceDumpTask(const uint64_t time)
634 {
635     std::lock_guard<std::mutex> lck(taskQueueMutex_);
636     auto it = std::remove_if(traceDumpTaskVec_.begin(), traceDumpTaskVec_.end(),
637         [time](const TraceDumpTask& task) { return task.time == time; });
638     if (it != traceDumpTaskVec_.end()) {
639         traceDumpTaskVec_.erase(it, traceDumpTaskVec_.end());
640         HILOG_INFO(LOG_CORE, "EraseTraceDumpTask: task removed from task list.");
641     } else {
642         HILOG_WARN(LOG_CORE, "EraseTraceDumpTask: task not found in task list.");
643     }
644 }
645 
UpdateTraceDumpTask(const TraceDumpTask & task)646 bool TraceDumpExecutor::UpdateTraceDumpTask(const TraceDumpTask& task)
647 {
648     std::lock_guard<std::mutex> lck(taskQueueMutex_);
649     for (auto& dumpTask : traceDumpTaskVec_) {
650         if (dumpTask.time == task.time) {
651             // attention: avoid updating hasSyncReturn field, it is only used in monitor thread.
652             dumpTask.code = task.code;
653             dumpTask.status = task.status;
654             dumpTask.fileSize = task.fileSize;
655             dumpTask.traceStartTime = task.traceStartTime;
656             dumpTask.traceEndTime = task.traceEndTime;
657             if (strcpy_s(dumpTask.outputFile, sizeof(dumpTask.outputFile), task.outputFile) != 0) {
658                 HILOG_ERROR(LOG_CORE, "UpdateTraceDumpTask: strcpy_s failed.");
659             }
660             HILOG_INFO(LOG_CORE, "UpdateTraceDumpTask: task id: %{public}" PRIu64 ", status: %{public}hhu, "
661                 "file: %{public}s, filesize: %{public}" PRId64 ".",
662                 task.time, task.status, task.outputFile, task.fileSize);
663             return true;
664         }
665     }
666     HILOG_WARN(LOG_CORE, "UpdateTraceDumpTask: task[%{public}" PRIu64 "] not found in lists.", task.time);
667     return false;
668 }
669 
AddTraceDumpTask(const TraceDumpTask & task)670 void TraceDumpExecutor::AddTraceDumpTask(const TraceDumpTask& task)
671 {
672     std::lock_guard<std::mutex> lck(taskQueueMutex_);
673     traceDumpTaskVec_.emplace_back(task);
674     readCondVar_.notify_one();
675     HILOG_INFO(LOG_CORE, "AddTraceDumpTask: task added to the list.");
676 }
677 
ClearTraceDumpTask()678 void TraceDumpExecutor::ClearTraceDumpTask()
679 {
680     std::lock_guard<std::mutex> lck(taskQueueMutex_);
681     traceDumpTaskVec_.clear();
682 }
683 
IsTraceDumpTaskEmpty()684 bool TraceDumpExecutor::IsTraceDumpTaskEmpty()
685 {
686     std::lock_guard<std::mutex> lck(taskQueueMutex_);
687     return traceDumpTaskVec_.empty();
688 }
689 
GetTraceDumpTaskCount()690 size_t TraceDumpExecutor::GetTraceDumpTaskCount()
691 {
692     std::lock_guard<std::mutex> lck(taskQueueMutex_);
693     return traceDumpTaskVec_.size();
694 }
695 
696 #ifdef HITRACE_UNITTEST
ClearCacheTraceFiles()697 void TraceDumpExecutor::ClearCacheTraceFiles()
698 {
699     std::lock_guard<std::mutex> lck(traceFileMutex_);
700     cacheTraceFiles_.clear();
701 }
702 #endif
703 
SetTraceDumpStrategy(std::unique_ptr<ITraceDumpStrategy> strategy)704 void TraceDumpExecutor::SetTraceDumpStrategy(std::unique_ptr<ITraceDumpStrategy> strategy)
705 {
706     dumpStrategy_ = std::move(strategy);
707 }
708 
ExecuteDumpTrace(std::shared_ptr<ITraceSource> traceSource,const TraceDumpRequest & request)709 TraceDumpRet TraceDumpExecutor::ExecuteDumpTrace(std::shared_ptr<ITraceSource> traceSource,
710     const TraceDumpRequest& request)
711 {
712     if (dumpStrategy_ == nullptr) {
713         HILOG_ERROR(LOG_CORE, "ExecuteDumpTrace : No write strategy set!");
714         return { TraceErrorCode::FILE_ERROR, "", 0, 0 }; // todo
715     }
716     return dumpStrategy_->Execute(traceSource, request);
717 }
718 
DoDumpTraceLoop(const TraceDumpParam & param,std::string & traceFile,bool isLimited)719 bool TraceDumpExecutor::DoDumpTraceLoop(const TraceDumpParam& param, std::string& traceFile, bool isLimited)
720 {
721     if (tracefsDir_.empty()) {
722         HILOG_ERROR(LOG_CORE, "DumpTrace : Trace fs path is empty.");
723         return false;
724     }
725     MarkClockSync(tracefsDir_);
726     int fileSizeThreshold = param.type == TraceDumpType::TRACE_CACHE ?
727         DEFAULT_CACHE_FILE_SIZE * BYTE_PER_KB : DEFAULT_FILE_SIZE * BYTE_PER_KB;
728     if (param.fileSize != 0) {
729         fileSizeThreshold = param.fileSize * BYTE_PER_KB;
730     }
731     std::shared_ptr<ITraceSource> traceSource = nullptr;
732     if (IsHmKernel()) {
733         traceSource = std::make_shared<TraceSourceHM>(tracefsDir_, traceFile);
734     } else {
735         traceSource = std::make_shared<TraceSourceLinux>(tracefsDir_, traceFile);
736     }
737     if (param.type == TraceDumpType::TRACE_RECORDING) {
738         SetTraceDumpStrategy(std::make_unique<RecordTraceDumpStrategy>());
739     } else {
740         SetTraceDumpStrategy(std::make_unique<CacheTraceDumpStrategy>());
741     }
742 
743     TraceDumpRequest request = { param.type, fileSizeThreshold, isLimited, param.traceStartTime, param.traceEndTime };
744 
745     std::lock_guard<std::mutex> lck(traceFileMutex_);
746     auto dumpRet = ExecuteDumpTrace(traceSource, request);
747     HILOG_INFO(LOG_CORE, "DoDumpTraceLoop: ExecuteDumpTrace done, errorcode: %{public}d, tracefile: %{public}s",
748         static_cast<uint8_t>(dumpRet.code), dumpRet.outputFile);
749     if (dumpRet.code != TraceErrorCode::SUCCESS) {
750         HILOG_ERROR(LOG_CORE, "DoDumpTraceLoop : Execute loop trace dump failed.");
751         return false;
752     }
753     traceFile = traceSource->GetTraceFilePath();
754     if (param.type == TraceDumpType::TRACE_CACHE) {
755         TraceFileInfo traceFileInfo;
756         if (!SetFileInfo(true, traceFile, dumpRet.traceStartTime, dumpRet.traceEndTime, traceFileInfo)) {
757             RemoveFile(traceFile);
758             return false;
759         }
760         traceFile = traceFileInfo.filename;
761         cacheTraceFiles_.emplace_back(traceFileInfo);
762     }
763     if (access(traceFile.c_str(), F_OK) == -1) {
764         HILOG_ERROR(LOG_CORE, "DoDumpTraceLoop : Trace file (%{public}s) not found.", traceFile.c_str());
765         return false;
766     }
767     return true;
768 }
769 
DumpTraceInner(const TraceDumpParam & param,const std::string & traceFile)770 TraceDumpRet TraceDumpExecutor::DumpTraceInner(const TraceDumpParam& param, const std::string& traceFile)
771 {
772     std::shared_ptr<ITraceSource> traceSource = nullptr;
773     if (tracefsDir_.empty()) {
774         HILOG_ERROR(LOG_CORE, "DumpTrace : Trace fs path is empty.");
775         return { TraceErrorCode::TRACE_NOT_SUPPORTED, "", 0, 0 }; // todo
776     }
777     if (IsHmKernel()) {
778         traceSource = std::make_shared<TraceSourceHM>(tracefsDir_, traceFile);
779     } else {
780         traceSource = std::make_shared<TraceSourceLinux>(tracefsDir_, traceFile);
781     }
782 
783     TraceDumpRequest request = {
784         param.type,
785         0,
786         false,
787         param.traceStartTime,
788         param.traceEndTime
789     };
790 
791     SetTraceDumpStrategy(std::make_unique<SnapshotTraceDumpStrategy>());
792     return ExecuteDumpTrace(traceSource, request);
793 }
794 
DoReadRawTrace(TraceDumpTask & task)795 bool TraceDumpExecutor::DoReadRawTrace(TraceDumpTask& task)
796 {
797     std::shared_ptr<ITraceSource> traceSource = nullptr;
798     if (tracefsDir_.empty()) {
799         HILOG_ERROR(LOG_CORE, "DoReadRawTrace : Trace fs path is empty.");
800         task.code = TraceErrorCode::TRACE_NOT_SUPPORTED;
801         return false;
802     }
803     if (IsHmKernel()) {
804         traceSource = std::make_shared<TraceSourceHM>(tracefsDir_, "");
805     } else {
806         traceSource = std::make_shared<TraceSourceLinux>(tracefsDir_, "");
807     }
808 
809     TraceDumpRequest request = {
810         TraceDumpType::TRACE_SNAPSHOT,
811         0,
812         false,
813         task.traceStartTime,
814         task.traceEndTime,
815         task.time
816     };
817     SetTraceDumpStrategy(std::make_unique<AsyncTraceReadStrategy>());
818     auto ret = ExecuteDumpTrace(traceSource, request);
819     task.code = ret.code;
820     task.fileSize = ret.fileSize + ASYNC_DUMP_FILE_SIZE_ADDITION;
821     if (strncpy_s(task.outputFile, TRACE_FILE_LEN, ret.outputFile, TRACE_FILE_LEN - 1) != 0) {
822         HILOG_ERROR(LOG_CORE, "DoReadRawTrace: strncpy_s failed.");
823     }
824     task.status = TraceDumpStatus::READ_DONE;
825     if (task.code == TraceErrorCode::SUCCESS && task.fileSize > task.fileSizeLimit) {
826         task.isFileSizeOverLimit = true;
827     }
828 #ifdef HITRACE_ASYNC_READ_TIMEOUT_TEST
829     sleep(10); // 10 : sleep 10 seconds to construct a timeout task
830 #endif
831     if (!UpdateTraceDumpTask(task)) {
832         HILOG_ERROR(LOG_CORE, "DoReadRawTrace: update trace dump task failed.");
833         return false;
834     }
835     return task.code == TraceErrorCode::SUCCESS;
836 }
837 
DoWriteRawTrace(TraceDumpTask & task)838 bool TraceDumpExecutor::DoWriteRawTrace(TraceDumpTask& task)
839 {
840     std::shared_ptr<ITraceSource> traceSource = nullptr;
841     if (tracefsDir_.empty()) {
842         HILOG_ERROR(LOG_CORE, "DoWriteRawTrace : Trace fs path is empty.");
843         task.code = TraceErrorCode::TRACE_NOT_SUPPORTED;
844         return false;
845     }
846     if (IsHmKernel()) {
847         traceSource = std::make_shared<TraceSourceHM>(tracefsDir_, task.outputFile);
848     } else {
849         traceSource = std::make_shared<TraceSourceLinux>(tracefsDir_, task.outputFile);
850     }
851 
852     TraceDumpRequest request = {
853         TraceDumpType::TRACE_SNAPSHOT,
854         0,
855         false,
856         task.traceStartTime,
857         task.traceEndTime,
858         task.time
859     };
860     SetTraceDumpStrategy(std::make_unique<AsyncTraceWriteStrategy>());
861     auto ret = ExecuteDumpTrace(traceSource, request);
862     task.code = ret.code;
863     task.fileSize = static_cast<int64_t>(GetFileSize(std::string(task.outputFile)));
864     task.status = TraceDumpStatus::WRITE_DONE;
865     if (task.code == TraceErrorCode::SUCCESS && task.fileSize > task.fileSizeLimit) {
866         task.isFileSizeOverLimit = true;
867     }
868 #ifdef HITRACE_ASYNC_WRITE_TIMEOUT_TEST
869     sleep(10); // 10 : sleep 10 seconds to construct a timeout task
870 #endif
871     if (!UpdateTraceDumpTask(task)) {
872         HILOG_ERROR(LOG_CORE, "DoWriteRawTrace: update trace dump task failed.");
873         return false;
874     }
875     return task.code == TraceErrorCode::SUCCESS;
876 }
877 } // namespace Hitrace
878 } // namespace HiviewDFX
879 } // namespace OHOS