1 /*
2 * Copyright (C) 2023-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 "hitrace_dump.h"
17
18 #include <algorithm>
19 #include <atomic>
20 #include <cinttypes>
21 #include <csignal>
22 #include <fstream>
23 #include <map>
24 #include <memory>
25 #include <mutex>
26 #include <set>
27 #include <sys/epoll.h>
28 #include <sys/file.h>
29 #include <sys/prctl.h>
30 #include <sys/stat.h>
31 #include <sys/wait.h>
32 #include <thread>
33 #include <unistd.h>
34 #include <unordered_map>
35 #include <functional>
36 #include <map>
37
38 #include "common_define.h"
39 #include "common_utils.h"
40 #include "dynamic_buffer.h"
41 #include "file_ageing_utils.h"
42 #include "hitrace_meter.h"
43 #include "hitrace_option/hitrace_option.h"
44 #include "hilog/log.h"
45 #include "parameters.h"
46 #include "securec.h"
47 #include "trace_dump_executor.h"
48 #include "trace_dump_pipe.h"
49 #include "trace_file_utils.h"
50 #include "trace_json_parser.h"
51
52 namespace OHOS {
53 namespace HiviewDFX {
54 namespace Hitrace {
55 #ifdef LOG_DOMAIN
56 #undef LOG_DOMAIN
57 #define LOG_DOMAIN 0xD002D33
58 #endif
59 #ifdef LOG_TAG
60 #undef LOG_TAG
61 #define LOG_TAG "HitraceDump"
62 #endif
63 namespace {
64 struct TraceParams {
65 std::vector<std::string> tags;
66 std::vector<std::string> tagGroups;
67 std::vector<std::string> filterPids;
68 std::string bufferSize;
69 std::string clockType;
70 std::string isOverWrite;
71 std::string outputFile;
72 int fileLimit;
73 int fileSize;
74 int appPid;
75 };
76
77 const int SAVED_CMDLINES_SIZE = 3072; // 3M
78 const int BYTE_PER_MB = 1024 * 1024;
79 constexpr int32_t MAX_RATIO_UNIT = 1000;
80 constexpr uint32_t DURATION_TOLERANCE = 100;
81 constexpr int DEFAULT_FULL_TRACE_LENGTH = 30;
82 constexpr uint64_t SNAPSHOT_MIN_REMAINING_SPACE = 300 * 1024 * 1024; // 300M
83 constexpr uint64_t DEFAULT_ASYNC_TRACE_SIZE = 50 * 1024 * 1024; // 50M
84 constexpr int HUNDRED_MILLISECONDS = 100 * 1000; // 100ms
85 constexpr int ASYNC_WAIT_EMPTY_LOOP_MS = 15 * 1000; // 15 seconds
86
87 std::atomic<pid_t> g_traceDumpTaskPid(-1);
88
89 std::mutex g_traceMutex;
90 bool g_serviceThreadIsStart = false;
91 uint64_t g_sysInitParamTags = 0;
92 uint8_t g_traceMode = TraceMode::CLOSE;
93 std::string g_traceRootPath;
94 uint64_t g_totalFileSizeLimit = 0;
95 uint64_t g_sliceMaxDuration = 0;
96 uint64_t g_traceStartTime = 0;
97 uint64_t g_traceEndTime = std::numeric_limits<uint64_t>::max(); // in nano seconds
98 uint64_t g_firstPageTimestamp = std::numeric_limits<uint64_t>::max();
99 uint64_t g_lastPageTimestamp = 0;
100 uint64_t g_utDestTraceStartTime = 0;
101 uint64_t g_utDestTraceEndTime = 0;
102 uint8_t g_dumpStatus(TraceErrorCode::UNSET);
103 std::vector<TraceFileInfo> g_traceFileVec{};
104
105 TraceParams g_currentTraceParams = {};
106
107 std::mutex g_traceRetAndCallbackMutex;
108 std::map<uint64_t, std::function<void(TraceRetInfo)>> g_callbacks;
109 std::map<uint64_t, TraceRetInfo> g_traceRetInfos;
110
111 const std::string TELEMETRY_APP_PARAM = "debug.hitrace.telemetry.app";
112
IsTraceOpen()113 bool IsTraceOpen()
114 {
115 return (g_traceMode & TraceMode::OPEN) != 0;
116 }
117
IsRecordOn()118 bool IsRecordOn()
119 {
120 return (g_traceMode & TraceMode::RECORD) != 0;
121 }
122
IsCacheOn()123 bool IsCacheOn()
124 {
125 return (g_traceMode & TraceMode::CACHE) != 0;
126 }
127
Split(const std::string & str,char delimiter)128 std::vector<std::string> Split(const std::string& str, char delimiter)
129 {
130 std::vector<std::string> res;
131 size_t startPos = 0;
132 for (size_t i = 0; i < str.size(); i++) {
133 if (str[i] == delimiter) {
134 res.push_back(str.substr(startPos, i - startPos));
135 startPos = i + 1;
136 }
137 }
138 if (startPos < str.size()) {
139 res.push_back(str.substr(startPos));
140 }
141 return res;
142 }
143
CheckTags(const std::vector<std::string> & tags,const std::map<std::string,TraceTag> & allTags)144 bool CheckTags(const std::vector<std::string>& tags, const std::map<std::string, TraceTag>& allTags)
145 {
146 for (const auto &tag : tags) {
147 if (allTags.find(tag) == allTags.end()) {
148 HILOG_ERROR(LOG_CORE, "CheckTags: %{public}s is not provided.", tag.c_str());
149 return false;
150 }
151 }
152 return true;
153 }
154
CheckTagGroup(const std::vector<std::string> & tagGroups,const std::map<std::string,std::vector<std::string>> & tagGroupTable)155 bool CheckTagGroup(const std::vector<std::string>& tagGroups,
156 const std::map<std::string, std::vector<std::string>>& tagGroupTable)
157 {
158 for (auto groupName : tagGroups) {
159 if (tagGroupTable.find(groupName) == tagGroupTable.end()) {
160 HILOG_ERROR(LOG_CORE, "CheckTagGroup: %{public}s is not provided.", groupName.c_str());
161 return false;
162 }
163 }
164 return true;
165 }
166
WriteStrToFileInner(const std::string & filename,const std::string & str)167 bool WriteStrToFileInner(const std::string& filename, const std::string& str)
168 {
169 std::ofstream out;
170 out.open(filename, std::ios::out);
171 if (out.fail()) {
172 HILOG_ERROR(LOG_CORE, "WriteStrToFile: %{public}s open failed.", filename.c_str());
173 return false;
174 }
175 out << str;
176 if (out.bad()) {
177 HILOG_ERROR(LOG_CORE, "WriteStrToFile: %{public}s write failed.", filename.c_str());
178 out.close();
179 return false;
180 }
181 out.flush();
182 out.close();
183 return true;
184 }
185
WriteStrToFile(const std::string & filename,const std::string & str)186 bool WriteStrToFile(const std::string& filename, const std::string& str)
187 {
188 if (access((g_traceRootPath + filename).c_str(), W_OK) < 0) {
189 HILOG_WARN(LOG_CORE, "WriteStrToFile: Failed to access %{public}s, errno(%{public}d).",
190 (g_traceRootPath + filename).c_str(), errno);
191 return false;
192 }
193 return WriteStrToFileInner(g_traceRootPath + filename, str);
194 }
195
SetTraceNodeStatus(const std::string & path,bool enabled)196 bool SetTraceNodeStatus(const std::string &path, bool enabled)
197 {
198 return WriteStrToFile(path, enabled ? "1" : "0");
199 }
200
TruncateFile(const std::string & path)201 void TruncateFile(const std::string& path)
202 {
203 int fd = creat((g_traceRootPath + path).c_str(), 0);
204 if (fd == -1) {
205 HILOG_ERROR(LOG_CORE, "TruncateFile: clear old trace failed.");
206 return;
207 }
208 close(fd);
209 return;
210 }
211
SetProperty(const std::string & property,const std::string & value)212 bool SetProperty(const std::string& property, const std::string& value)
213 {
214 bool result = OHOS::system::SetParameter(property, value);
215 if (!result) {
216 HILOG_ERROR(LOG_CORE, "SetProperty: set %{public}s failed.", value.c_str());
217 } else {
218 HILOG_INFO(LOG_CORE, "SetProperty: set %{public}s success.", value.c_str());
219 }
220 return result;
221 }
222
ClearFilterParam()223 void ClearFilterParam()
224 {
225 bool ok = true;
226 if (!OHOS::system::SetParameter(TELEMETRY_APP_PARAM, "")) {
227 HILOG_ERROR(LOG_CORE, "ClearFilterParam: clear param fail");
228 ok = false;
229 }
230 if (ClearFilterPid() != HITRACE_NO_ERROR) {
231 HILOG_ERROR(LOG_CORE, "ClearFilterParam: clear pid fail");
232 ok = false;
233 }
234
235 HILOG_INFO(LOG_CORE, "ClearFilterParam %{public}d.", ok);
236 }
237
238 // close all trace node
TraceInit(const std::map<std::string,TraceTag> & allTags)239 void TraceInit(const std::map<std::string, TraceTag>& allTags)
240 {
241 // close all ftrace events
242 for (auto it = allTags.begin(); it != allTags.end(); it++) {
243 if (it->second.type != 1) {
244 continue;
245 }
246 for (size_t i = 0; i < it->second.enablePath.size(); i++) {
247 if (!SetTraceNodeStatus(it->second.enablePath[i], false)) {
248 HILOG_ERROR(LOG_CORE, "TraceInit: SetTraceNodeStatus fail");
249 }
250 }
251 }
252 // close all user tags
253 SetProperty(TRACE_TAG_ENABLE_FLAGS, std::to_string(0));
254
255 // set buffer_size_kb 1
256 if (!WriteStrToFile("buffer_size_kb", "1")) {
257 HILOG_ERROR(LOG_CORE, "TraceInit: WriteStrToFile fail");
258 }
259
260 // close tracing_on
261 SetTraceNodeStatus(TRACING_ON_NODE, false);
262 }
263
264 // Open specific trace node
SetAllTags(const TraceParams & traceParams,const std::map<std::string,TraceTag> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable,std::vector<std::string> & tagFmts)265 void SetAllTags(const TraceParams& traceParams, const std::map<std::string, TraceTag>& allTags,
266 const std::map<std::string, std::vector<std::string>>& tagGroupTable,
267 std::vector<std::string>& tagFmts)
268 {
269 std::set<std::string> readyEnableTagList;
270 for (std::string tagName : traceParams.tags) {
271 readyEnableTagList.insert(tagName);
272 }
273
274 for (std::string groupName : traceParams.tagGroups) {
275 auto iter = tagGroupTable.find(groupName);
276 if (iter == tagGroupTable.end()) {
277 continue;
278 }
279 for (std::string tag : iter->second) {
280 readyEnableTagList.insert(tag);
281 }
282 }
283
284 uint64_t enabledUserTags = 0;
285 for (std::string tagName : readyEnableTagList) {
286 auto iter = allTags.find(tagName);
287 if (iter == allTags.end()) {
288 HILOG_ERROR(LOG_CORE, "tag<%{public}s> is invalid.", tagName.c_str());
289 continue;
290 }
291
292 if (iter->second.type == 0) {
293 enabledUserTags |= iter->second.tag;
294 }
295
296 if (iter->second.type == 1) {
297 for (const auto& path : iter->second.enablePath) {
298 if (!SetTraceNodeStatus(path, true)) {
299 HILOG_ERROR(LOG_CORE, "SetAllTags: SetTraceNodeStatus fail");
300 }
301 }
302 for (const auto& format : iter->second.formatPath) {
303 tagFmts.emplace_back(format);
304 }
305 }
306 }
307 SetProperty(TRACE_TAG_ENABLE_FLAGS, std::to_string(enabledUserTags));
308 }
309
SetClock(const std::string & clockType)310 void SetClock(const std::string& clockType)
311 {
312 const std::string traceClockPath = "trace_clock";
313 if (clockType.size() == 0) {
314 if (!WriteStrToFile(traceClockPath, "boot")) { // set default: boot
315 HILOG_ERROR(LOG_CORE, "SetClock: WriteStrToFile fail.");
316 }
317 return;
318 }
319 std::string allClocks = ReadFile(traceClockPath, g_traceRootPath);
320 if (allClocks.find(clockType) == std::string::npos) {
321 HILOG_ERROR(LOG_CORE, "SetClock: %{public}s is non-existent, set to boot", clockType.c_str());
322 if (!WriteStrToFile(traceClockPath, "boot")) { // set default: boot
323 HILOG_ERROR(LOG_CORE, "SetClock: WriteStrToFile fail.");
324 }
325 return;
326 }
327
328 allClocks.erase(allClocks.find_last_not_of(" \n") + 1);
329 allClocks.push_back(' ');
330
331 std::set<std::string> allClockTypes;
332 size_t curPos = 0;
333 for (size_t i = 0; i < allClocks.size(); i++) {
334 if (allClocks[i] == ' ') {
335 allClockTypes.insert(allClocks.substr(curPos, i - curPos));
336 curPos = i + 1;
337 }
338 }
339
340 std::string currentClockType;
341 for (auto i : allClockTypes) {
342 if (clockType.compare(i) == 0) {
343 HILOG_INFO(LOG_CORE, "SetClock: set clock %{public}s success.", clockType.c_str());
344 if (!WriteStrToFile(traceClockPath, clockType)) {
345 HILOG_ERROR(LOG_CORE, "SetClock: WriteStrToFile fail.");
346 }
347 return;
348 }
349 if (i[0] == '[') {
350 currentClockType = i;
351 }
352 }
353
354 const int marks = 2;
355 if (clockType.compare(currentClockType.substr(1, currentClockType.size() - marks)) == 0) {
356 HILOG_INFO(LOG_CORE, "SetClock: set clock %{public}s success.", clockType.c_str());
357 return;
358 }
359
360 HILOG_INFO(LOG_CORE, "SetClock: unknown %{public}s, change to default clock_type: boot.", clockType.c_str());
361 if (!WriteStrToFile(traceClockPath, "boot")) { // set default: boot
362 HILOG_ERROR(LOG_CORE, "SetClock: WriteStrToFile fail.");
363 }
364 return;
365 }
366
SetTraceSetting(const TraceParams & traceParams,const std::map<std::string,TraceTag> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable,std::vector<std::string> & tagFmts)367 bool SetTraceSetting(const TraceParams& traceParams, const std::map<std::string, TraceTag>& allTags,
368 const std::map<std::string, std::vector<std::string>>& tagGroupTable,
369 std::vector<std::string>& tagFmts)
370 {
371 AddFilterPids(traceParams.filterPids);
372 if (!traceParams.filterPids.empty()) {
373 TruncateFile("trace_pipe_raw");
374 }
375 TraceInit(allTags);
376
377 TruncateFile(TRACE_NODE);
378
379 SetAllTags(traceParams, allTags, tagGroupTable, tagFmts);
380
381 if (!WriteStrToFile("current_tracer", "nop")) {
382 HILOG_ERROR(LOG_CORE, "SetTraceSetting: WriteStrToFile fail.");
383 }
384 if (!WriteStrToFile("buffer_size_kb", traceParams.bufferSize)) {
385 HILOG_ERROR(LOG_CORE, "SetTraceSetting: WriteStrToFile fail.");
386 }
387
388 SetClock(traceParams.clockType);
389
390 if (traceParams.isOverWrite == "1") {
391 if (!WriteStrToFile("options/overwrite", "1")) {
392 HILOG_ERROR(LOG_CORE, "SetTraceSetting: WriteStrToFile fail.");
393 }
394 } else {
395 if (!WriteStrToFile("options/overwrite", "0")) {
396 HILOG_ERROR(LOG_CORE, "SetTraceSetting: WriteStrToFile fail.");
397 }
398 }
399
400 if (!WriteStrToFile("saved_cmdlines_size", std::to_string(SAVED_CMDLINES_SIZE))) {
401 HILOG_ERROR(LOG_CORE, "SetTraceSetting: WriteStrToFile fail.");
402 }
403 if (!WriteStrToFile("options/record-tgid", "1")) {
404 HILOG_ERROR(LOG_CORE, "SetTraceSetting: WriteStrToFile fail.");
405 }
406 if (!WriteStrToFile("options/record-cmd", "1")) {
407 HILOG_ERROR(LOG_CORE, "SetTraceSetting: WriteStrToFile fail.");
408 }
409 return true;
410 }
411
SetTimeIntervalBoundary(int inputMaxDuration,uint64_t utTraceEndTime)412 TraceErrorCode SetTimeIntervalBoundary(int inputMaxDuration, uint64_t utTraceEndTime)
413 {
414 uint64_t utNow = static_cast<uint64_t>(std::time(nullptr));
415 if (utTraceEndTime >= utNow) {
416 HILOG_WARN(LOG_CORE, "DumpTrace: Warning: traceEndTime is later than current time, set to current.");
417 utTraceEndTime = 0;
418 }
419 struct timespec bts = {0, 0};
420 clock_gettime(CLOCK_BOOTTIME, &bts);
421 uint64_t btNow = static_cast<uint64_t>(bts.tv_sec) + (static_cast<uint64_t>(bts.tv_nsec) != 0 ? 1 : 0);
422 uint64_t utBootTime = utNow - btNow;
423 if (utTraceEndTime == 0) {
424 g_traceEndTime = static_cast<uint64_t>(bts.tv_sec * S_TO_NS + bts.tv_nsec);
425 } else if (utTraceEndTime > utBootTime) {
426 // beware of input precision of seconds: add an extra second of tolerance
427 g_traceEndTime = (utTraceEndTime - utBootTime + 1) * S_TO_NS;
428 } else {
429 HILOG_ERROR(LOG_CORE,
430 "DumpTrace: traceEndTime:(%{public}" PRIu64 ") is earlier than boot_time:(%{public}" PRIu64 ").",
431 utTraceEndTime, utBootTime);
432 return OUT_OF_TIME;
433 }
434
435 uint64_t maxDuration = inputMaxDuration > 0 ? static_cast<uint64_t>(inputMaxDuration) + 1 : 0;
436 if (maxDuration > g_traceEndTime / S_TO_NS) {
437 HILOG_WARN(LOG_CORE, "maxDuration is larger than TraceEndTime boot clock.");
438 maxDuration = 0;
439 }
440 if (maxDuration > 0) {
441 g_traceStartTime = g_traceEndTime - maxDuration * S_TO_NS;
442 } else {
443 g_traceStartTime = 0;
444 }
445 return SUCCESS;
446 }
447
RestoreTimeIntervalBoundary()448 void RestoreTimeIntervalBoundary()
449 {
450 g_traceStartTime = 0;
451 g_traceEndTime = std::numeric_limits<uint64_t>::max();
452 }
453
GetTraceFileFromVec(const uint64_t & inputTraceStartTime,const uint64_t & inputTraceEndTime,std::vector<TraceFileInfo> & fileVec,std::vector<TraceFileInfo> & targetFiles)454 int32_t GetTraceFileFromVec(const uint64_t& inputTraceStartTime, const uint64_t& inputTraceEndTime,
455 std::vector<TraceFileInfo>& fileVec, std::vector<TraceFileInfo>& targetFiles)
456 {
457 int32_t coverDuration = 0;
458 uint64_t utTargetStartTimeMs = inputTraceStartTime * S_TO_MS;
459 uint64_t utTargetEndTimeMs = inputTraceEndTime * S_TO_MS;
460 for (auto it = fileVec.begin(); it != fileVec.end(); it++) {
461 if (access(it->filename.c_str(), F_OK) != 0) {
462 HILOG_ERROR(LOG_CORE, "GetTraceFileFromVec: %{public}s is not exist.", it->filename.c_str());
463 continue;
464 }
465 HILOG_INFO(LOG_CORE, "GetTraceFileFromVec: %{public}s, [%{public}" PRIu64 ", %{public}" PRIu64 "].",
466 it->filename.c_str(), it->traceStartTime, it->traceEndTime);
467 if (((it->traceEndTime >= utTargetStartTimeMs && it->traceStartTime <= utTargetEndTimeMs)) &&
468 (it->traceEndTime - it->traceStartTime < 2000 * S_TO_MS)) { // 2000 : max trace duration 2000s
469 targetFiles.push_back(*it);
470 coverDuration += static_cast<int32_t>(std::min(it->traceEndTime, utTargetEndTimeMs + DURATION_TOLERANCE) -
471 std::max(it->traceStartTime, utTargetStartTimeMs - DURATION_TOLERANCE));
472 }
473 }
474 return coverDuration;
475 }
476
SearchTraceFiles(const uint64_t & inputTraceStartTime,const uint64_t & inputTraceEndTime,TraceRetInfo & traceRetInfo)477 void SearchTraceFiles(const uint64_t& inputTraceStartTime, const uint64_t& inputTraceEndTime,
478 TraceRetInfo& traceRetInfo)
479 {
480 HILOG_INFO(LOG_CORE, "target trace time: [%{public}" PRIu64 ", %{public}" PRIu64 "].",
481 inputTraceStartTime, inputTraceEndTime);
482 uint64_t curTime = GetCurUnixTimeMs();
483 HILOG_INFO(LOG_CORE, "current time: %{public}" PRIu64 ".", curTime);
484 int32_t coverDuration = 0;
485 std::vector<TraceFileInfo> targetFiles;
486 coverDuration += GetTraceFileFromVec(inputTraceStartTime, inputTraceEndTime, g_traceFileVec, targetFiles);
487 auto inputCacheFiles = TraceDumpExecutor::GetInstance().GetCacheTraceFiles();
488 coverDuration += GetTraceFileFromVec(inputTraceStartTime, inputTraceEndTime, inputCacheFiles, targetFiles);
489 for (auto& file : targetFiles) {
490 if (file.filename.find(CACHE_FILE_PREFIX) != std::string::npos) {
491 file.filename = RenameCacheFile(file.filename);
492 auto it = std::find_if(inputCacheFiles.begin(), inputCacheFiles.end(),
493 [&file](const TraceFileInfo& cacheFile) {
494 return cacheFile.filename == file.filename;
495 });
496 if (it != inputCacheFiles.end()) {
497 g_traceFileVec.push_back(file);
498 }
499 }
500 traceRetInfo.outputFiles.push_back(file.filename);
501 traceRetInfo.fileSize += file.fileSize;
502 }
503 traceRetInfo.coverDuration += coverDuration;
504 }
505
ProcessCacheTask()506 void ProcessCacheTask()
507 {
508 const std::string threadName = "CacheTraceTask";
509 prctl(PR_SET_NAME, threadName.c_str());
510 struct TraceDumpParam param = {
511 TraceDumpType::TRACE_CACHE,
512 g_currentTraceParams.outputFile,
513 g_currentTraceParams.fileLimit,
514 g_currentTraceParams.fileSize,
515 0,
516 std::numeric_limits<uint64_t>::max()
517 };
518 if (!TraceDumpExecutor::GetInstance().StartCacheTraceLoop(param, g_totalFileSizeLimit, g_sliceMaxDuration)) {
519 HILOG_ERROR(LOG_CORE, "ProcessCacheTask: StartCacheTraceLoop failed.");
520 return;
521 }
522 HILOG_INFO(LOG_CORE, "ProcessCacheTask: trace cache thread exit.");
523 }
524
ProcessRecordTask()525 void ProcessRecordTask()
526 {
527 const std::string threadName = "RecordTraceTask";
528 prctl(PR_SET_NAME, threadName.c_str());
529 struct TraceDumpParam param = {
530 TraceDumpType::TRACE_RECORDING,
531 g_currentTraceParams.outputFile,
532 g_currentTraceParams.fileLimit,
533 g_currentTraceParams.fileSize,
534 0,
535 std::numeric_limits<uint64_t>::max()
536
537 };
538 TraceDumpExecutor::GetInstance().StartDumpTraceLoop(param);
539 }
540
SetProcessName(std::string & processName)541 void SetProcessName(std::string& processName)
542 {
543 if (processName.size() <= 0) {
544 return;
545 }
546
547 const int maxNameLen = 16;
548 std::string setName;
549 if (processName.size() > maxNameLen) {
550 setName = processName.substr(0, maxNameLen);
551 } else {
552 setName = processName;
553 }
554
555 prctl(PR_SET_NAME, setName.c_str(), nullptr, nullptr, nullptr);
556 HILOG_INFO(LOG_CORE, "New process: %{public}s.", setName.c_str());
557 }
558
TimeoutSignalHandler(int signum)559 void TimeoutSignalHandler(int signum)
560 {
561 if (signum == SIGUSR1) {
562 _exit(EXIT_SUCCESS);
563 } else if (signum == SIGCHLD) {
564 pid_t pid;
565 do {
566 pid = waitpid(-1, nullptr, WNOHANG);
567 } while (pid > 0);
568 }
569 }
570
EpollWaitforChildProcess(pid_t & pid,int & pipefd,std::string & reOutPath)571 bool EpollWaitforChildProcess(pid_t& pid, int& pipefd, std::string& reOutPath)
572 {
573 int epollfd = epoll_create1(0);
574 if (epollfd == -1) {
575 HILOG_ERROR(LOG_CORE, "epoll_create1 error.");
576 return false;
577 }
578
579 struct epoll_event event;
580 event.events = EPOLLIN;
581 event.data.fd = pipefd;
582 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, pipefd, &event) == -1) {
583 HILOG_ERROR(LOG_CORE, "epoll_ctl error.");
584 close(epollfd);
585 return false;
586 }
587
588 struct epoll_event events[1];
589 constexpr int waitTimeoutMs = 10000; // 10000ms = 10s
590 int numEvents = TEMP_FAILURE_RETRY(epoll_wait(epollfd, events, 1, waitTimeoutMs));
591 if (numEvents <= 0) {
592 if (numEvents == -1) {
593 HILOG_ERROR(LOG_CORE, "epoll_wait error, error: (%{public}s).", strerror(errno));
594 } else {
595 HILOG_ERROR(LOG_CORE, "epoll_wait timeout.");
596 }
597 if (waitpid(pid, nullptr, WNOHANG) <= 0) {
598 HILOG_ERROR(LOG_CORE, "kill timeout child process.");
599 kill(pid, SIGUSR1);
600 }
601 close(epollfd);
602 return false;
603 }
604 TraceDumpRet retVal;
605 read(pipefd, &retVal, sizeof(retVal));
606 HILOG_INFO(LOG_CORE,
607 "Epoll wait read : %{public}d, outputFile: %{public}s, [%{public}" PRIu64 ", %{public}" PRIu64 "].",
608 retVal.code, retVal.outputFile, retVal.traceStartTime, retVal.traceEndTime);
609 g_dumpStatus = retVal.code;
610 reOutPath = retVal.outputFile;
611 g_firstPageTimestamp = retVal.traceStartTime;
612 g_lastPageTimestamp = retVal.traceEndTime;
613
614 close(epollfd);
615 if (waitpid(pid, nullptr, 0) <= 0) {
616 HILOG_ERROR(LOG_CORE, "wait HitraceDump(%{public}d) exit failed, errno: (%{public}d)", pid, errno);
617 }
618 return true;
619 }
620
HandleDumpResult(std::string & reOutPath,TraceRetInfo & traceRetInfo)621 TraceErrorCode HandleDumpResult(std::string& reOutPath, TraceRetInfo& traceRetInfo)
622 {
623 SearchTraceFiles(g_utDestTraceStartTime, g_utDestTraceEndTime, traceRetInfo);
624 if (g_dumpStatus) {
625 if (remove(reOutPath.c_str()) == 0) {
626 HILOG_INFO(LOG_CORE, "Delete outpath:%{public}s success.", reOutPath.c_str());
627 } else {
628 HILOG_INFO(LOG_CORE, "Delete outpath:%{public}s failed.", reOutPath.c_str());
629 }
630 } else if (access(reOutPath.c_str(), F_OK) != 0) { // trace access error
631 HILOG_ERROR(LOG_CORE, "ProcessDump: write %{public}s failed.", reOutPath.c_str());
632 } else {
633 HILOG_INFO(LOG_CORE, "Output: %{public}s.", reOutPath.c_str());
634 TraceFileInfo traceFileInfo;
635 if (!SetFileInfo(true, reOutPath, g_firstPageTimestamp, g_lastPageTimestamp, traceFileInfo)) {
636 // trace rename error
637 HILOG_ERROR(LOG_CORE, "SetFileInfo: set %{public}s info failed.", reOutPath.c_str());
638 RemoveFile(reOutPath);
639 } else { // success
640 g_traceFileVec.push_back(traceFileInfo);
641 traceRetInfo.outputFiles.push_back(traceFileInfo.filename);
642 traceRetInfo.coverDuration +=
643 static_cast<int32_t>(traceFileInfo.traceEndTime - traceFileInfo.traceStartTime);
644 traceRetInfo.fileSize += traceFileInfo.fileSize;
645 }
646 }
647
648 if (traceRetInfo.outputFiles.empty()) {
649 return (g_dumpStatus != 0) ? static_cast<TraceErrorCode>(g_dumpStatus) : TraceErrorCode::FILE_ERROR;
650 }
651 return TraceErrorCode::SUCCESS;
652 }
653
HandleAsyncDumpResult(TraceDumpTask & task,TraceRetInfo & traceRetInfo)654 void HandleAsyncDumpResult(TraceDumpTask& task, TraceRetInfo& traceRetInfo)
655 {
656 SearchTraceFiles(g_utDestTraceStartTime, g_utDestTraceEndTime, traceRetInfo);
657 TraceFileInfo traceFileInfo;
658 if (task.code == TraceErrorCode::SUCCESS) {
659 if (!SetFileInfo(false, std::string(task.outputFile),
660 g_firstPageTimestamp, g_lastPageTimestamp, traceFileInfo)) {
661 // trace rename error
662 HILOG_ERROR(LOG_CORE, "SetFileInfo: set %{public}s info failed.", task.outputFile);
663 } else { // success
664 traceFileInfo.fileSize = task.fileSize;
665 g_traceFileVec.push_back(traceFileInfo);
666 traceRetInfo.outputFiles.push_back(traceFileInfo.filename);
667 traceRetInfo.coverDuration +=
668 static_cast<int32_t>(traceFileInfo.traceEndTime - traceFileInfo.traceStartTime);
669 traceRetInfo.fileSize += traceFileInfo.fileSize;
670 }
671 traceRetInfo.errorCode = task.code;
672 } else {
673 traceRetInfo.errorCode = traceRetInfo.outputFiles.empty() ? task.code : TraceErrorCode::SUCCESS;
674 }
675 if (task.isFileSizeOverLimit || traceRetInfo.fileSize > task.fileSizeLimit) {
676 traceRetInfo.isOverflowControl = true;
677 }
678 }
679
ProcessDumpSync(TraceRetInfo & traceRetInfo)680 TraceErrorCode ProcessDumpSync(TraceRetInfo& traceRetInfo)
681 {
682 auto taskCnt = TraceDumpExecutor::GetInstance().GetTraceDumpTaskCount();
683 if (GetRemainingSpace("/data") <= SNAPSHOT_MIN_REMAINING_SPACE + taskCnt * DEFAULT_ASYNC_TRACE_SIZE) {
684 HILOG_ERROR(LOG_CORE, "ProcessDumpSync: remaining space not enough");
685 return TraceErrorCode::FILE_ERROR;
686 }
687
688 int pipefd[2];
689 if (pipe(pipefd) == -1) {
690 HILOG_ERROR(LOG_CORE, "ProcessDumpSync: pipe creation error.");
691 return TraceErrorCode::PIPE_CREATE_ERROR;
692 }
693
694 g_dumpStatus = TraceErrorCode::UNSET;
695 /*Child process handles task, Father process wait.*/
696 pid_t pid = fork();
697 if (pid < 0) {
698 HILOG_ERROR(LOG_CORE, "fork error.");
699 return TraceErrorCode::FORK_ERROR;
700 } else if (pid == 0) {
701 signal(SIGUSR1, TimeoutSignalHandler);
702 close(pipefd[0]);
703 std::string processName = "HitraceDump";
704 SetProcessName(processName);
705 struct TraceDumpParam param = { TRACE_SNAPSHOT, "", 0, 0, g_traceStartTime, g_traceEndTime };
706 TraceDumpRet ret = TraceDumpExecutor::GetInstance().DumpTrace(param);
707 HILOG_INFO(LOG_CORE,
708 "TraceDumpRet : %{public}d, outputFile: %{public}s, [%{public}" PRIu64 ", %{public}" PRIu64 "].",
709 ret.code, ret.outputFile, ret.traceStartTime, ret.traceEndTime);
710 write(pipefd[1], &ret, sizeof(ret));
711 _exit(EXIT_SUCCESS);
712 } else {
713 close(pipefd[1]);
714 }
715
716 std::string reOutPath;
717 if (!EpollWaitforChildProcess(pid, pipefd[0], reOutPath)) {
718 close(pipefd[0]);
719 return TraceErrorCode::EPOLL_WAIT_ERROR;
720 }
721
722 close(pipefd[0]);
723 return HandleDumpResult(reOutPath, traceRetInfo);
724 }
725
LoadDumpRet(TraceRetInfo & ret,int32_t committedDuration)726 void LoadDumpRet(TraceRetInfo& ret, int32_t committedDuration)
727 {
728 ret.mode = g_traceMode;
729 committedDuration = committedDuration <= 0 ? DEFAULT_FULL_TRACE_LENGTH : committedDuration;
730 ret.coverRatio = ret.coverDuration / committedDuration;
731 ret.tags.reserve(g_currentTraceParams.tagGroups.size() + g_currentTraceParams.tags.size());
732 ret.tags.insert(ret.tags.end(), g_currentTraceParams.tagGroups.begin(), g_currentTraceParams.tagGroups.end());
733 ret.tags.insert(ret.tags.end(), g_currentTraceParams.tags.begin(), g_currentTraceParams.tags.end());
734 }
735
SanitizeRetInfo(TraceRetInfo & traceRetInfo)736 void SanitizeRetInfo(TraceRetInfo& traceRetInfo)
737 {
738 traceRetInfo.coverDuration =
739 std::min(traceRetInfo.coverDuration, static_cast<int>(DEFAULT_FULL_TRACE_LENGTH * S_TO_MS));
740 traceRetInfo.coverRatio = std::min(traceRetInfo.coverRatio, MAX_RATIO_UNIT);
741 }
742
WaitSyncDumpRetLoop(const pid_t pid,const std::shared_ptr<HitraceDumpPipe> pipe)743 TraceDumpTask WaitSyncDumpRetLoop(const pid_t pid, const std::shared_ptr<HitraceDumpPipe> pipe)
744 {
745 HILOG_INFO(LOG_CORE, "WaitSyncDumpRetLoop: start.");
746 TraceDumpTask task;
747 if (pipe->ReadSyncDumpRet(10, task)) { // 10 : 10 seconds
748 g_firstPageTimestamp = task.traceStartTime;
749 g_lastPageTimestamp = task.traceEndTime;
750 g_dumpStatus = task.code;
751 if (task.status == TraceDumpStatus::WRITE_DONE) {
752 task.status = TraceDumpStatus::FINISH;
753 TraceDumpExecutor::GetInstance().RemoveTraceDumpTask(task.time);
754 HILOG_INFO(LOG_CORE, "WaitSyncDumpRetLoop: task finished.");
755 } else {
756 HILOG_ERROR(LOG_CORE, "WaitSyncDumpRetLoop: task status is not FINISH.");
757 TraceDumpExecutor::GetInstance().UpdateTraceDumpTask(task);
758 }
759 } else {
760 task.code = TraceErrorCode::TRACE_TASK_DUMP_TIMEOUT;
761 TraceDumpExecutor::GetInstance().ClearTraceDumpTask();
762 kill(pid, SIGUSR1);
763 HILOG_WARN(LOG_CORE, "WaitSyncDumpRetLoop: wait timeout, clear task and kill dump process.");
764 }
765 HILOG_INFO(LOG_CORE, "WaitSyncDumpRetLoop: exit.");
766 return task;
767 }
768
WaitAsyncDumpRetLoop(const std::shared_ptr<HitraceDumpPipe> pipe)769 void WaitAsyncDumpRetLoop(const std::shared_ptr<HitraceDumpPipe> pipe)
770 {
771 HILOG_INFO(LOG_CORE, "WaitAsyncDumpRetLoop: start.");
772 int emptyLoopMs = 0;
773 do {
774 HILOG_INFO(LOG_CORE, "WaitAsyncDumpRetLoop: loop start.");
775 if (TraceDumpExecutor::GetInstance().IsTraceDumpTaskEmpty() && emptyLoopMs >= ASYNC_WAIT_EMPTY_LOOP_MS) {
776 HILOG_INFO(LOG_CORE, "WaitAsyncDumpRetLoop: task queue is empty.");
777 HitraceDumpPipe::ClearTraceDumpPipe();
778 break;
779 }
780 TraceDumpTask task;
781 if (!pipe->ReadAsyncDumpRet(1, task)) {
782 usleep(HUNDRED_MILLISECONDS);
783 emptyLoopMs += HUNDRED_MILLISECONDS / 1000; // 1000 : us to ms ratio
784 continue;
785 }
786 emptyLoopMs = 0;
787 if (task.status == TraceDumpStatus::WRITE_DONE) {
788 task.status = TraceDumpStatus::FINISH;
789 HILOG_INFO(LOG_CORE, "WaitAsyncDumpRetLoop: task finished.");
790 std::lock_guard<std::mutex> lock(g_traceRetAndCallbackMutex);
791 auto traceRetInfo = g_traceRetInfos[task.time];
792 traceRetInfo.fileSize = 0;
793 for (auto& file : traceRetInfo.outputFiles) {
794 traceRetInfo.fileSize += GetFileSize(file);
795 }
796 if (traceRetInfo.fileSize > task.fileSizeLimit) {
797 traceRetInfo.isOverflowControl = true;
798 }
799 if (g_callbacks[task.time] != nullptr) {
800 g_callbacks[task.time](traceRetInfo);
801 HILOG_INFO(LOG_CORE, "WaitAsyncDumpRetLoop: call callback func done, taskid[%{public}" PRIu64 "]",
802 task.time);
803 }
804 g_callbacks.erase(task.time);
805 g_traceRetInfos.erase(task.time);
806 } else {
807 HILOG_ERROR(LOG_CORE, "WaitAsyncDumpRetLoop: task status is not FINISH.");
808 }
809 TraceDumpExecutor::GetInstance().RemoveTraceDumpTask(task.time);
810 } while (true);
811 HILOG_INFO(LOG_CORE, "WaitAsyncDumpRetLoop: exit.");
812 }
813
SubmitTaskAndWaitReturn(const TraceDumpTask & task,const bool cloneAsyncThread,TraceRetInfo & traceRetInfo)814 TraceErrorCode SubmitTaskAndWaitReturn(const TraceDumpTask& task, const bool cloneAsyncThread,
815 TraceRetInfo& traceRetInfo)
816 {
817 TraceDumpExecutor::GetInstance().AddTraceDumpTask(task);
818 auto dumpPipe = std::make_shared<HitraceDumpPipe>(true);
819 if (!dumpPipe->SubmitTraceDumpTask(task)) {
820 return TraceErrorCode::TRACE_TASK_SUBMIT_ERROR;
821 }
822 auto taskRet = WaitSyncDumpRetLoop(g_traceDumpTaskPid.load(), dumpPipe);
823 HandleAsyncDumpResult(taskRet, traceRetInfo);
824 if (taskRet.status == TraceDumpStatus::FINISH) {
825 HILOG_INFO(LOG_CORE, "SubmitTaskAndWaitReturn: task finished.");
826 return traceRetInfo.errorCode;
827 } else if (taskRet.code != TraceErrorCode::TRACE_TASK_DUMP_TIMEOUT) {
828 HILOG_ERROR(LOG_CORE, "SubmitTaskAndWaitReturn: task status is not FINISH.");
829 if (cloneAsyncThread) {
830 std::thread asyncThread(WaitAsyncDumpRetLoop, std::move(dumpPipe));
831 asyncThread.detach();
832 }
833 return TraceErrorCode::ASYNC_DUMP;
834 }
835 return TraceErrorCode::TRACE_TASK_DUMP_TIMEOUT;
836 }
837
SetSigChldHandler()838 bool SetSigChldHandler()
839 {
840 struct sigaction sa;
841 sa.sa_handler = TimeoutSignalHandler;
842 sigemptyset(&sa.sa_mask);
843 sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
844 if (sigaction(SIGCHLD, &sa, nullptr) == -1) {
845 HILOG_ERROR(LOG_CORE, "ProcessDumpAsync: Failed to setup SIGCHLD handler.");
846 return false;
847 }
848 return true;
849 }
850
ProcessDumpAsync(const uint64_t taskid,const int64_t fileSizeLimit,TraceRetInfo & traceRetInfo)851 TraceErrorCode ProcessDumpAsync(const uint64_t taskid, const int64_t fileSizeLimit, TraceRetInfo& traceRetInfo)
852 {
853 auto taskCnt = TraceDumpExecutor::GetInstance().GetTraceDumpTaskCount();
854 if (GetRemainingSpace("/data") <= SNAPSHOT_MIN_REMAINING_SPACE + taskCnt * DEFAULT_ASYNC_TRACE_SIZE) {
855 HILOG_ERROR(LOG_CORE, "ProcessDumpAsync: remaining space not enough");
856 return TraceErrorCode::FILE_ERROR;
857 }
858 if (!SetSigChldHandler()) {
859 return TraceErrorCode::FORK_ERROR;
860 }
861
862 TraceDumpTask task = {
863 .time = taskid,
864 .traceStartTime = g_traceStartTime,
865 .traceEndTime = g_traceEndTime,
866 .fileSizeLimit = fileSizeLimit
867 };
868 HILOG_INFO(LOG_CORE, "ProcessDumpAsync: new task id[%{public}" PRIu64 "]", task.time);
869 if (taskCnt > 0) {
870 // must have a trace dump process running, just submit trace dump task, or need check child process is alive.
871 HILOG_INFO(LOG_CORE, "ProcessDumpAsync: task queue is not empty, do not fork new process.");
872 return SubmitTaskAndWaitReturn(task, false, traceRetInfo);
873 }
874 HitraceDumpPipe::ClearTraceDumpPipe();
875 if (!HitraceDumpPipe::InitTraceDumpPipe()) {
876 HILOG_ERROR(LOG_CORE, "ProcessDumpAsync: create fifo failed.");
877 return TraceErrorCode::PIPE_CREATE_ERROR;
878 }
879 pid_t pid = fork();
880 if (pid < 0) {
881 HILOG_ERROR(LOG_CORE, "ProcessDumpAsync: fork failed.");
882 return TraceErrorCode::FORK_ERROR;
883 }
884 if (pid == 0) {
885 signal(SIGUSR1, TimeoutSignalHandler);
886 std::string processName = "HitraceDumpAsync";
887 SetProcessName(processName);
888 // create loop read thread and loop write thread.
889 auto& traceDumpExecutor = TraceDumpExecutor::GetInstance();
890 std::thread loopReadThrad(&TraceDumpExecutor::ReadRawTraceLoop, std::ref(traceDumpExecutor));
891 std::thread loopWriteThread(&TraceDumpExecutor::WriteTraceLoop, std::ref(traceDumpExecutor));
892 traceDumpExecutor.TraceDumpTaskMonitor();
893 loopReadThrad.join();
894 loopWriteThread.join();
895 _exit(EXIT_SUCCESS);
896 }
897 g_traceDumpTaskPid.store(pid);
898 return SubmitTaskAndWaitReturn(task, true, traceRetInfo);
899 }
900
GetSysParamTags()901 uint64_t GetSysParamTags()
902 {
903 return OHOS::system::GetUintParameter<uint64_t>(TRACE_TAG_ENABLE_FLAGS, 0);
904 }
905
CheckParam()906 bool CheckParam()
907 {
908 uint64_t currentTags = GetSysParamTags();
909 if (currentTags == g_sysInitParamTags) {
910 return true;
911 }
912
913 if (currentTags == 0) {
914 HILOG_ERROR(LOG_CORE, "allowed tags are cleared, should restart.");
915 return false;
916 }
917 HILOG_ERROR(LOG_CORE, "trace is being used, should restart.");
918 return false;
919 }
920
921 /**
922 * SERVICE_MODE is running, check param and tracing_on.
923 */
CheckServiceRunning()924 bool CheckServiceRunning()
925 {
926 if (CheckParam() && IsTracingOn(g_traceRootPath)) {
927 return true;
928 }
929 return false;
930 }
931
CpuBufferBalanceTask()932 void CpuBufferBalanceTask()
933 {
934 g_serviceThreadIsStart = true;
935 const std::string threadName = "CpuBufferBalancer";
936 prctl(PR_SET_NAME, threadName.c_str());
937 HILOG_INFO(LOG_CORE, "CpuBufferBalanceTask: monitor thread start.");
938 const int intervalTime = 15;
939 while (IsTraceOpen() && CheckServiceRunning()) {
940 sleep(intervalTime);
941
942 const int cpuNums = GetCpuProcessors();
943 std::vector<int> result;
944 std::unique_ptr<DynamicBuffer> dynamicBuffer = std::make_unique<DynamicBuffer>(g_traceRootPath, cpuNums);
945 dynamicBuffer->CalculateBufferSize(result);
946
947 if (static_cast<int>(result.size()) != cpuNums) {
948 HILOG_ERROR(LOG_CORE, "CalculateAllNewBufferSize failed.");
949 break;
950 }
951
952 for (size_t i = 0; i < result.size(); i++) {
953 HILOG_DEBUG(LOG_CORE, "cpu%{public}zu set size %{public}d.", i, result[i]);
954 std::string path = "per_cpu/cpu" + std::to_string(i) + "/buffer_size_kb";
955 if (!WriteStrToFile(path, std::to_string(result[i]))) {
956 HILOG_ERROR(LOG_CORE, "CpuBufferBalanceTask: WriteStrToFile failed.");
957 }
958 }
959 }
960 HILOG_INFO(LOG_CORE, "CpuBufferBalanceTask: monitor thread exit.");
961 g_serviceThreadIsStart = false;
962 }
963
StartCpuBufferBalanceService()964 void StartCpuBufferBalanceService()
965 {
966 if (!IsHmKernel() && !g_serviceThreadIsStart) {
967 // open monitor thread
968 auto it = []() {
969 CpuBufferBalanceTask();
970 };
971 std::thread auxiliaryTask(it);
972 auxiliaryTask.detach();
973 }
974 }
975
PreWriteEventsFormat(const std::vector<std::string> & eventFormats)976 bool PreWriteEventsFormat(const std::vector<std::string>& eventFormats)
977 {
978 DelSavedEventsFormat();
979 const std::string savedEventsFormatPath = TRACE_FILE_DEFAULT_DIR + TRACE_SAVED_EVENTS_FORMAT;
980 int fd = open(savedEventsFormatPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
981 if (fd < 0) {
982 HILOG_ERROR(LOG_CORE, "PreWriteEventsFormat: open %{public}s failed.", savedEventsFormatPath.c_str());
983 return false;
984 }
985 for (auto& format : eventFormats) {
986 std::string srcPath = g_traceRootPath + format;
987 if (access(srcPath.c_str(), R_OK) != -1) {
988 WriteEventFile(srcPath, fd);
989 }
990 }
991 close(fd);
992 HILOG_INFO(LOG_CORE, "PreWriteEventsFormat end.");
993 return true;
994 }
995
HandleTraceOpen(const TraceParams & traceParams,const std::map<std::string,TraceTag> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable,std::vector<std::string> & tagFmts)996 TraceErrorCode HandleTraceOpen(const TraceParams& traceParams,
997 const std::map<std::string, TraceTag>& allTags,
998 const std::map<std::string, std::vector<std::string>>& tagGroupTable,
999 std::vector<std::string>& tagFmts)
1000 {
1001 if (!SetTraceSetting(traceParams, allTags, tagGroupTable, tagFmts)) {
1002 return TraceErrorCode::FILE_ERROR;
1003 }
1004 SetTraceNodeStatus(TRACING_ON_NODE, true);
1005 PreWriteEventsFormat(tagFmts);
1006 g_currentTraceParams = traceParams;
1007 return TraceErrorCode::SUCCESS;
1008 }
1009
HandleDefaultTraceOpen(const std::vector<std::string> & tagGroups)1010 TraceErrorCode HandleDefaultTraceOpen(const std::vector<std::string>& tagGroups)
1011 {
1012 TraceJsonParser& traceJsonParser = TraceJsonParser::Instance();
1013 const std::map<std::string, TraceTag>& allTags = traceJsonParser.GetAllTagInfos();
1014 const std::map<std::string, std::vector<std::string>>& tagGroupTable = traceJsonParser.GetTagGroups();
1015 std::vector<std::string> tagFmts = traceJsonParser.GetBaseFmtPath();
1016
1017 if (tagGroups.size() == 0 || !CheckTagGroup(tagGroups, tagGroupTable)) {
1018 HILOG_ERROR(LOG_CORE, "OpenTrace: TAG_ERROR.");
1019 return TAG_ERROR;
1020 }
1021
1022 TraceParams defaultTraceParams;
1023 defaultTraceParams.tagGroups = tagGroups;
1024 defaultTraceParams.bufferSize = std::to_string(traceJsonParser.GetSnapshotDefaultBufferSizeKb());
1025 defaultTraceParams.clockType = "boot";
1026 defaultTraceParams.isOverWrite = "1";
1027 defaultTraceParams.fileSize = DEFAULT_FILE_SIZE;
1028 return HandleTraceOpen(defaultTraceParams, allTags, tagGroupTable, tagFmts);
1029 }
1030
RemoveUnSpace(std::string str,std::string & args)1031 void RemoveUnSpace(std::string str, std::string& args)
1032 {
1033 int maxCircleTimes = 30;
1034 int curTimes = 0;
1035 const size_t symbolAndSpaceLen = 2;
1036 std::string strSpace = str + " ";
1037 while (curTimes < maxCircleTimes) {
1038 curTimes++;
1039 std::string::size_type index = args.find(strSpace);
1040 if (index != std::string::npos) {
1041 args.replace(index, symbolAndSpaceLen, str);
1042 } else {
1043 break;
1044 }
1045 }
1046 }
1047
SetCmdTraceIntParams(const std::string & traceParamsStr,int & traceParams)1048 void SetCmdTraceIntParams(const std::string& traceParamsStr, int& traceParams)
1049 {
1050 if (!OHOS::HiviewDFX::Hitrace::StringToInt(traceParamsStr, traceParams)) {
1051 traceParams = 0;
1052 return;
1053 }
1054 if (traceParams <= 0) {
1055 HILOG_WARN(LOG_CORE, "Illegal input, traceParams initialized to null.");
1056 traceParams = 0;
1057 }
1058 }
1059
SetDestTraceTimeAndDuration(int maxDuration,const uint64_t & utTraceEndTime)1060 void SetDestTraceTimeAndDuration(int maxDuration, const uint64_t& utTraceEndTime)
1061 {
1062 if (utTraceEndTime == 0) {
1063 time_t currentTime;
1064 time(¤tTime);
1065 g_utDestTraceEndTime = static_cast<uint64_t>(currentTime);
1066 } else {
1067 g_utDestTraceEndTime = utTraceEndTime;
1068 }
1069 if (maxDuration <= 0) {
1070 maxDuration = DEFAULT_FULL_TRACE_LENGTH;
1071 }
1072 if (g_utDestTraceEndTime <= static_cast<uint64_t>(maxDuration)) {
1073 g_utDestTraceStartTime = 1; // theoretical impossible value, to avoid overflow while minus tolerance 100ms
1074 } else {
1075 g_utDestTraceStartTime = g_utDestTraceEndTime - static_cast<uint64_t>(maxDuration);
1076 }
1077 HILOG_INFO(LOG_CORE, "g_utDestTraceStartTime:(%{public}" PRIu64 "), g_utDestTraceEndTime:(%{public}" PRIu64 ").",
1078 g_utDestTraceStartTime, g_utDestTraceEndTime);
1079 }
1080
1081 /**
1082 * args: tags:tag1,tags2... tagGroups:group1,group2... clockType:boot bufferSize:1024 overwrite:1 output:filename
1083 * traceParams: Save the above parameters
1084 */
ParseArgs(std::string args,TraceParams & traceParams,const std::map<std::string,TraceTag> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)1085 bool ParseArgs(std::string args, TraceParams& traceParams, const std::map<std::string, TraceTag>& allTags,
1086 const std::map<std::string, std::vector<std::string>>& tagGroupTable)
1087 {
1088 RemoveUnSpace(":", args);
1089 RemoveUnSpace(",", args);
1090 std::vector<std::string> argList = Split(args, ' ');
1091 for (std::string item : argList) {
1092 size_t pos = item.find(":");
1093 if (pos == std::string::npos) {
1094 HILOG_ERROR(LOG_CORE, "trace command line without colon appears: %{public}s, continue.", item.c_str());
1095 continue;
1096 }
1097 std::string itemName = item.substr(0, pos);
1098 if (itemName == "tags") {
1099 traceParams.tags = Split(item.substr(pos + 1), ',');
1100 } else if (itemName == "tagGroups") {
1101 traceParams.tagGroups = Split(item.substr(pos + 1), ',');
1102 } else if (itemName == "clockType") {
1103 traceParams.clockType = item.substr(pos + 1);
1104 } else if (itemName == "bufferSize") {
1105 traceParams.bufferSize = item.substr(pos + 1);
1106 } else if (itemName == "overwrite") {
1107 traceParams.isOverWrite = item.substr(pos + 1);
1108 } else if (itemName == "output") {
1109 traceParams.outputFile = item.substr(pos + 1);
1110 } else if (itemName == "fileSize") {
1111 std::string fileSizeStr = item.substr(pos + 1);
1112 SetCmdTraceIntParams(fileSizeStr, traceParams.fileSize);
1113 } else if (itemName == "fileLimit") {
1114 std::string fileLimitStr = item.substr(pos + 1);
1115 SetCmdTraceIntParams(fileLimitStr, traceParams.fileLimit);
1116 } else if (itemName == "appPid") {
1117 std::string pidStr = item.substr(pos + 1);
1118 SetCmdTraceIntParams(pidStr, traceParams.appPid);
1119 if (traceParams.appPid == 0) {
1120 HILOG_ERROR(LOG_CORE, "Illegal input, appPid(%{public}s) must be number and greater than 0.",
1121 pidStr.c_str());
1122 return false;
1123 }
1124 OHOS::system::SetParameter(TRACE_KEY_APP_PID, pidStr);
1125 } else if (itemName == "filterPids") {
1126 traceParams.filterPids = Split(item.substr(pos + 1), ',');
1127 } else {
1128 HILOG_ERROR(LOG_CORE, "Extra trace command line options appear when ParseArgs: %{public}s, return false.",
1129 itemName.c_str());
1130 return false;
1131 }
1132 }
1133 return CheckTags(traceParams.tags, allTags) && CheckTagGroup(traceParams.tagGroups, tagGroupTable);
1134 }
1135
WriteCpuFreqTrace()1136 void WriteCpuFreqTrace()
1137 {
1138 std::string freqsfmt = "cpu frequency: ";
1139 ReadCurrentCpuFrequencies(freqsfmt);
1140 HILOG_INFO(LOG_CORE, "hitracedump write trace(%{public}s)", freqsfmt.c_str());
1141 HITRACE_METER_NAME(HITRACE_TAG_OHOS, freqsfmt);
1142 }
1143
SetTotalFileSizeLimitAndSliceMaxDuration(const uint64_t & totalFileSize,const uint64_t & sliceMaxDuration)1144 void SetTotalFileSizeLimitAndSliceMaxDuration(const uint64_t& totalFileSize, const uint64_t& sliceMaxDuration)
1145 {
1146 if (totalFileSize == 0) {
1147 g_totalFileSizeLimit = DEFAULT_TOTAL_CACHE_FILE_SIZE * BYTE_PER_MB;
1148 } else {
1149 g_totalFileSizeLimit = totalFileSize * BYTE_PER_MB;
1150 }
1151 if (sliceMaxDuration == 0) {
1152 g_sliceMaxDuration = DEFAULT_TRACE_SLICE_DURATION;
1153 } else {
1154 g_sliceMaxDuration = sliceMaxDuration;
1155 }
1156 }
1157
GetFileInCache(TraceRetInfo & traceRetInfo)1158 void GetFileInCache(TraceRetInfo& traceRetInfo)
1159 {
1160 HILOG_INFO(LOG_CORE, "DumpTrace: Trace is caching, get cache file.");
1161 SearchTraceFiles(g_utDestTraceStartTime, g_utDestTraceEndTime, traceRetInfo);
1162 if (traceRetInfo.outputFiles.empty()) {
1163 HILOG_ERROR(LOG_CORE, "DumpTrace: Trace is caching, but failed to retrieve target trace file.");
1164 traceRetInfo.errorCode = OUT_OF_TIME;
1165 } else {
1166 for (const auto& file: traceRetInfo.outputFiles) {
1167 HILOG_INFO(LOG_CORE, "dumptrace file is %{public}s.", file.c_str());
1168 }
1169 traceRetInfo.errorCode = SUCCESS;
1170 }
1171 }
1172
CheckTraceDumpStatus(const int maxDuration,const uint64_t utTraceEndTime,TraceRetInfo & ret)1173 bool CheckTraceDumpStatus(const int maxDuration, const uint64_t utTraceEndTime, TraceRetInfo& ret)
1174 {
1175 if (!IsTraceOpen() || IsRecordOn()) {
1176 HILOG_ERROR(LOG_CORE, "CheckTraceDumpStatus: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1177 static_cast<uint32_t>(g_traceMode));
1178 ret.errorCode = WRONG_TRACE_MODE;
1179 return false;
1180 }
1181 if (maxDuration < 0) {
1182 HILOG_ERROR(LOG_CORE, "CheckTraceDumpStatus: Illegal input: maxDuration = %{public}d < 0.", maxDuration);
1183 ret.errorCode = INVALID_MAX_DURATION;
1184 return false;
1185 }
1186
1187 if (!CheckServiceRunning()) {
1188 HILOG_ERROR(LOG_CORE, "CheckTraceDumpStatus: TRACE_IS_OCCUPIED.");
1189 ret.errorCode = TRACE_IS_OCCUPIED;
1190 return false;
1191 }
1192 return true;
1193 }
1194 } // namespace
1195
1196 #ifdef HITRACE_UNITTEST
SetSysInitParamTags(uint64_t sysInitParamTags)1197 void SetSysInitParamTags(uint64_t sysInitParamTags)
1198 {
1199 g_sysInitParamTags = sysInitParamTags;
1200 }
1201
SetCheckParam()1202 bool SetCheckParam()
1203 {
1204 int ret = CheckParam();
1205 return ret;
1206 }
1207 #endif
1208
GetTraceMode()1209 uint8_t GetTraceMode()
1210 {
1211 std::lock_guard<std::mutex> lock(g_traceMutex);
1212 return g_traceMode;
1213 }
1214
OpenTrace(const std::vector<std::string> & tagGroups)1215 TraceErrorCode OpenTrace(const std::vector<std::string>& tagGroups)
1216 {
1217 std::lock_guard<std::mutex> lock(g_traceMutex);
1218 ClearFilterParam();
1219 if (g_traceMode != TraceMode::CLOSE) {
1220 HILOG_ERROR(LOG_CORE, "OpenTrace: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1221 static_cast<uint32_t>(g_traceMode));
1222 return WRONG_TRACE_MODE;
1223 }
1224 if (!IsTraceMounted(g_traceRootPath)) {
1225 HILOG_ERROR(LOG_CORE, "OpenTrace: TRACE_NOT_SUPPORTED.");
1226 return TRACE_NOT_SUPPORTED;
1227 }
1228
1229 TraceErrorCode ret = HandleDefaultTraceOpen(tagGroups);
1230 if (ret != SUCCESS) {
1231 HILOG_ERROR(LOG_CORE, "OpenTrace: failed.");
1232 return ret;
1233 }
1234 RefreshTraceVec(g_traceFileVec, TRACE_SNAPSHOT);
1235 std::vector<TraceFileInfo> cacheFileVec;
1236 RefreshTraceVec(cacheFileVec, TRACE_CACHE);
1237 ClearCacheTraceFileByDuration(cacheFileVec);
1238 g_sysInitParamTags = GetSysParamTags();
1239 g_traceMode = TraceMode::OPEN;
1240 HILOG_INFO(LOG_CORE, "OpenTrace: open by tag group success.");
1241 StartCpuBufferBalanceService();
1242 return ret;
1243 }
1244
OpenTrace(const std::string & args)1245 TraceErrorCode OpenTrace(const std::string& args)
1246 {
1247 std::lock_guard<std::mutex> lock(g_traceMutex);
1248 if (g_traceMode != TraceMode::CLOSE) {
1249 HILOG_ERROR(LOG_CORE, "OpenTrace: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1250 static_cast<uint32_t>(g_traceMode));
1251 return WRONG_TRACE_MODE;
1252 }
1253
1254 if (!IsTraceMounted(g_traceRootPath)) {
1255 HILOG_ERROR(LOG_CORE, "OpenTrace: TRACE_NOT_SUPPORTED.");
1256 return TRACE_NOT_SUPPORTED;
1257 }
1258
1259 TraceJsonParser& traceJsonParser = TraceJsonParser::Instance();
1260 const std::map<std::string, TraceTag>& allTags = traceJsonParser.GetAllTagInfos();
1261 const std::map<std::string, std::vector<std::string>>& tagGroupTable = traceJsonParser.GetTagGroups();
1262 std::vector<std::string> traceFormats = traceJsonParser.GetBaseFmtPath();
1263
1264 if (allTags.size() == 0 || tagGroupTable.size() == 0) {
1265 HILOG_ERROR(LOG_CORE, "OpenTrace: ParseTagInfo TAG_ERROR.");
1266 return TAG_ERROR;
1267 }
1268 // parse args
1269 TraceParams traceParams;
1270 if (!ParseArgs(args, traceParams, allTags, tagGroupTable)) {
1271 HILOG_ERROR(LOG_CORE, "OpenTrace: TAG_ERROR.");
1272 return TAG_ERROR;
1273 }
1274
1275 TraceErrorCode ret = HandleTraceOpen(traceParams, allTags, tagGroupTable, traceFormats);
1276 if (ret != SUCCESS) {
1277 HILOG_ERROR(LOG_CORE, "OpenTrace: open by args failed.");
1278 return FILE_ERROR;
1279 }
1280 g_sysInitParamTags = GetSysParamTags();
1281 g_traceMode = TraceMode::OPEN;
1282 HILOG_INFO(LOG_CORE, "OpenTrace: open by args success, args:%{public}s.", args.c_str());
1283 StartCpuBufferBalanceService();
1284 return ret;
1285 }
1286
CacheTraceOn(uint64_t totalFileSize,uint64_t sliceMaxDuration)1287 TraceErrorCode CacheTraceOn(uint64_t totalFileSize, uint64_t sliceMaxDuration)
1288 {
1289 std::lock_guard<std::mutex> lock(g_traceMutex);
1290 if (g_traceMode != TraceMode::OPEN) {
1291 HILOG_ERROR(LOG_CORE, "CacheTraceOn: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1292 static_cast<uint32_t>(g_traceMode));
1293 return WRONG_TRACE_MODE;
1294 }
1295 if (!TraceDumpExecutor::GetInstance().PreCheckDumpTraceLoopStatus()) {
1296 HILOG_ERROR(LOG_CORE, "CacheTraceOn: cache trace is dumping now.");
1297 return WRONG_TRACE_MODE;
1298 }
1299 SetTotalFileSizeLimitAndSliceMaxDuration(totalFileSize, sliceMaxDuration);
1300 auto it = []() {
1301 ProcessCacheTask();
1302 };
1303 std::thread task(it);
1304 task.detach();
1305 HILOG_INFO(LOG_CORE, "Caching trace on.");
1306 g_traceMode |= TraceMode::CACHE;
1307 return SUCCESS;
1308 }
1309
CacheTraceOff()1310 TraceErrorCode CacheTraceOff()
1311 {
1312 std::lock_guard<std::mutex> lock(g_traceMutex);
1313 if (g_traceMode != (TraceMode::OPEN | TraceMode::CACHE)) {
1314 HILOG_ERROR(LOG_CORE,
1315 "CacheTraceOff: WRONG_TRACE_MODE, current trace mode: %{public}u.", static_cast<uint32_t>(g_traceMode));
1316 return WRONG_TRACE_MODE;
1317 }
1318 TraceDumpExecutor::GetInstance().StopCacheTraceLoop();
1319 HILOG_INFO(LOG_CORE, "Caching trace off.");
1320 g_traceMode &= ~TraceMode::CACHE;
1321 return SUCCESS;
1322 }
1323
DumpTrace(int maxDuration,uint64_t utTraceEndTime)1324 TraceRetInfo DumpTrace(int maxDuration, uint64_t utTraceEndTime)
1325 {
1326 std::lock_guard<std::mutex> lock(g_traceMutex);
1327 TraceRetInfo ret;
1328 ret.mode = g_traceMode;
1329 if (!CheckTraceDumpStatus(maxDuration, utTraceEndTime, ret)) {
1330 return ret;
1331 }
1332 FileAgeingUtils::HandleAgeing(g_traceFileVec, TraceDumpType::TRACE_SNAPSHOT);
1333 HILOG_INFO(LOG_CORE, "DumpTrace start, target duration is %{public}d, target endtime is (%{public}" PRIu64 ").",
1334 maxDuration, utTraceEndTime);
1335 SetDestTraceTimeAndDuration(maxDuration, utTraceEndTime);
1336 int32_t committedDuration =
1337 std::min(DEFAULT_FULL_TRACE_LENGTH, static_cast<int32_t>(g_utDestTraceEndTime - g_utDestTraceStartTime));
1338 if (UNEXPECTANTLY(IsCacheOn())) {
1339 GetFileInCache(ret);
1340 LoadDumpRet(ret, committedDuration);
1341 SanitizeRetInfo(ret);
1342 return ret;
1343 }
1344
1345 ret.errorCode = SetTimeIntervalBoundary(maxDuration, utTraceEndTime);
1346 if (ret.errorCode != SUCCESS) {
1347 return ret;
1348 }
1349 g_firstPageTimestamp = UINT64_MAX;
1350 g_lastPageTimestamp = 0;
1351
1352 ret.errorCode = ProcessDumpSync(ret);
1353 LoadDumpRet(ret, committedDuration);
1354 RestoreTimeIntervalBoundary();
1355 SanitizeRetInfo(ret);
1356 HILOG_INFO(LOG_CORE, "DumpTrace with time limit done.");
1357 return ret;
1358 }
1359
DumpTraceAsync(int maxDuration,uint64_t utTraceEndTime,int64_t fileSizeLimit,std::function<void (TraceRetInfo)> asyncCallback)1360 TraceRetInfo DumpTraceAsync(int maxDuration, uint64_t utTraceEndTime, int64_t fileSizeLimit,
1361 std::function<void(TraceRetInfo)> asyncCallback)
1362 {
1363 std::lock_guard<std::mutex> lock(g_traceMutex);
1364 TraceRetInfo ret;
1365 ret.mode = g_traceMode;
1366 if (!CheckTraceDumpStatus(maxDuration, utTraceEndTime, ret)) {
1367 return ret;
1368 }
1369 FileAgeingUtils::HandleAgeing(g_traceFileVec, TraceDumpType::TRACE_SNAPSHOT);
1370
1371 HILOG_INFO(LOG_CORE, "DumpTraceAsync start, target duration is %{public}d, target endtime is %{public}" PRIu64 ".",
1372 maxDuration, utTraceEndTime);
1373 SetDestTraceTimeAndDuration(maxDuration, utTraceEndTime);
1374 int32_t committedDuration =
1375 std::min(DEFAULT_FULL_TRACE_LENGTH, static_cast<int32_t>(g_utDestTraceEndTime - g_utDestTraceStartTime));
1376 if (UNEXPECTANTLY(IsCacheOn())) {
1377 GetFileInCache(ret);
1378 LoadDumpRet(ret, committedDuration);
1379 SanitizeRetInfo(ret);
1380 if (asyncCallback != nullptr) {
1381 asyncCallback(ret);
1382 }
1383 return ret;
1384 }
1385 ret.errorCode = SetTimeIntervalBoundary(maxDuration, utTraceEndTime);
1386 if (ret.errorCode != SUCCESS) {
1387 return ret;
1388 }
1389 g_firstPageTimestamp = UINT64_MAX;
1390 g_lastPageTimestamp = 0;
1391 auto taskid = GetCurBootTime();
1392 std::unique_lock<std::mutex> retLck(g_traceRetAndCallbackMutex);
1393 g_callbacks[taskid] = asyncCallback;
1394 ret.errorCode = ProcessDumpAsync(taskid, fileSizeLimit, ret);
1395 if (ret.errorCode != TraceErrorCode::ASYNC_DUMP) {
1396 LoadDumpRet(ret, committedDuration);
1397 SanitizeRetInfo(ret);
1398 if (g_callbacks[taskid] != nullptr) {
1399 g_callbacks[taskid](ret);
1400 }
1401 g_callbacks.erase(taskid);
1402 } else {
1403 ret.errorCode = TraceErrorCode::SUCCESS;
1404 g_traceRetInfos[taskid] = ret;
1405 }
1406 retLck.unlock();
1407 RestoreTimeIntervalBoundary();
1408 HILOG_INFO(LOG_CORE, "DumpTraceAsync with time limit done. output file size: %{public}zu", ret.outputFiles.size());
1409 return ret;
1410 }
1411
RecordTraceOn()1412 TraceErrorCode RecordTraceOn()
1413 {
1414 std::lock_guard<std::mutex> lock(g_traceMutex);
1415 // check current trace status
1416 if (g_traceMode != TraceMode::OPEN) {
1417 HILOG_ERROR(LOG_CORE, "RecordTraceOn: WRONG_TRACE_MODE, current trace mode: %{public}u.",
1418 static_cast<uint32_t>(g_traceMode));
1419 return WRONG_TRACE_MODE;
1420 }
1421 if (!TraceDumpExecutor::GetInstance().PreCheckDumpTraceLoopStatus()) {
1422 HILOG_ERROR(LOG_CORE, "RecordTraceOn: record trace is dumping now.");
1423 return WRONG_TRACE_MODE;
1424 }
1425 auto it = []() {
1426 ProcessRecordTask();
1427 };
1428 std::thread task(it);
1429 task.detach();
1430 WriteCpuFreqTrace();
1431 HILOG_INFO(LOG_CORE, "Recording trace on.");
1432 g_traceMode |= TraceMode::RECORD;
1433 return SUCCESS;
1434 }
1435
RecordTraceOff()1436 TraceRetInfo RecordTraceOff()
1437 {
1438 std::lock_guard<std::mutex> lock(g_traceMutex);
1439 TraceRetInfo ret;
1440 // check current trace status
1441 if (!IsRecordOn()) {
1442 HILOG_ERROR(LOG_CORE, "RecordTraceOff: The current state is %{public}u, data exception.",
1443 static_cast<uint32_t>(g_traceMode));
1444 ret.errorCode = WRONG_TRACE_MODE;
1445 return ret;
1446 }
1447
1448 ret.outputFiles = TraceDumpExecutor::GetInstance().StopDumpTraceLoop();
1449 ret.errorCode = SUCCESS;
1450 HILOG_INFO(LOG_CORE, "Recording trace off.");
1451 g_traceMode &= ~TraceMode::RECORD;
1452 return ret;
1453 }
1454
CloseTrace()1455 TraceErrorCode CloseTrace()
1456 {
1457 std::lock_guard<std::mutex> lock(g_traceMutex);
1458 ClearFilterParam();
1459 HILOG_INFO(LOG_CORE, "CloseTrace start.");
1460 if (g_traceMode == TraceMode::CLOSE) {
1461 HILOG_INFO(LOG_CORE, "Trace has already been closed.");
1462 return SUCCESS;
1463 }
1464 if (IsRecordOn() || IsCacheOn()) {
1465 TraceDumpExecutor::GetInstance().StopDumpTraceLoop();
1466 }
1467 g_traceMode = TraceMode::CLOSE;
1468 OHOS::system::SetParameter(TRACE_KEY_APP_PID, "-1");
1469
1470 const std::map<std::string, TraceTag>& allTags = TraceJsonParser::Instance().GetAllTagInfos();
1471
1472 if (allTags.size() == 0) {
1473 HILOG_ERROR(LOG_CORE, "CloseTrace: ParseTagInfo TAG_ERROR.");
1474 return TAG_ERROR;
1475 }
1476
1477 TraceInit(allTags);
1478 TruncateFile(TRACE_NODE);
1479 HILOG_INFO(LOG_CORE, "CloseTrace done.");
1480 return SUCCESS;
1481 }
1482
SetTraceStatus(bool enable)1483 TraceErrorCode SetTraceStatus(bool enable)
1484 {
1485 HILOG_INFO(LOG_CORE, "SetTraceStatus %{public}d", enable);
1486 std::lock_guard<std::mutex> lock(g_traceMutex);
1487 if (g_traceRootPath.empty()) {
1488 if (!IsTraceMounted(g_traceRootPath)) {
1489 HILOG_ERROR(LOG_CORE, "SetTraceStatus: TRACE_NOT_SUPPORTED.");
1490 return TRACE_NOT_SUPPORTED;
1491 }
1492 }
1493
1494 if (!SetTraceNodeStatus(TRACING_ON_NODE, enable)) {
1495 return WRITE_TRACE_INFO_ERROR;
1496 };
1497
1498 return SUCCESS;
1499 }
1500 } // namespace Hitrace
1501 } // namespace HiviewDFX
1502 } // namespace OHOS
1503