1 /*
2 * Copyright (C) 2023 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 <map>
19 #include <atomic>
20 #include <fstream>
21 #include <set>
22 #include <thread>
23 #include <vector>
24 #include <string>
25
26 #include <unistd.h>
27 #include <cstdio>
28 #include <cstdlib>
29 #include <sys/time.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <fcntl.h>
33 #include <cinttypes>
34 #include <utility>
35 #include <dirent.h>
36
37 #include "cJSON.h"
38 #include "parameters.h"
39 #include "hilog/log.h"
40 #include "securec.h"
41
42
43 using OHOS::HiviewDFX::HiLog;
44 using OHOS::HiviewDFX::Hitrace::TraceErrorCode;
45 using OHOS::HiviewDFX::Hitrace::TraceRetInfo;
46 using OHOS::HiviewDFX::Hitrace::TraceMode;
47
48 namespace {
49
50 struct TagCategory {
51 std::string description;
52 uint64_t tag;
53 int type;
54 std::vector<std::string> sysFiles;
55 };
56
57 struct TraceParams {
58 std::vector<std::string> tags;
59 std::vector<std::string> tagGroups;
60 std::string bufferSize;
61 std::string clockType;
62 std::string isOverWrite;
63 std::string outputFile;
64 };
65
66 constexpr uint16_t MAGIC_NUMBER = 57161;
67 constexpr uint16_t VERSION_NUMBER = 1;
68 constexpr uint8_t FILE_RAW_TRACE = 0;
69 constexpr int UNIT_TIME = 100000;
70
71 const int DEFAULT_BUFFER_SIZE = 12 * 1024;
72 const int HIGHER_BUFFER_SIZE = 18 * 1024;
73 const int SAVED_CMDLINES_SIZE = 1024;
74
75 const std::string DEFAULT_OUTPUT_DIR = "/data/log/hitrace/";
76
77 struct TraceFileHeader {
78 uint16_t magicNumber {MAGIC_NUMBER};
79 uint8_t fileType {FILE_RAW_TRACE};
80 uint16_t versionNumber {VERSION_NUMBER};
81 uint32_t reserved {0};
82 };
83
84 enum ContentType : uint8_t {
85 CONTENT_TYPE_DEFAULT = 0,
86 CONTENT_TYPE_EVENTS_FORMAT = 1,
87 CONTENT_TYPE_CMDLINES = 2,
88 CONTENT_TYPE_TGIDS = 3,
89 CONTENT_TYPE_CPU_RAW = 4
90 };
91
92 struct TraceFileContentHeader {
93 uint8_t type = CONTENT_TYPE_DEFAULT;
94 uint32_t length = 0;
95 };
96
97 struct LastCpuInfo {
98 std::pair<uint64_t, uint64_t> idleAndTotal = {0, 0};
99 bool isNormal = true;
100 };
101
102 struct CpuStat {
103 int8_t cpuId = -1; // 总的为-1
104 uint64_t user = 0;
105 uint64_t nice = 0;
106 uint64_t system = 0;
107 uint64_t idle = 0;
108 uint64_t iowait = 0;
109 uint64_t irq = 0;
110 uint64_t softirq = 0;
111 uint64_t steal = 0;
112 uint64_t guest = 0;
113 uint64_t guestNice = 0;
114 };
115
116 struct PageHeader {
117 uint64_t timestamp = 0;
118 uint64_t size = 0;
119 uint8_t overwrite = 0;
120 uint8_t *startPos = nullptr;
121 uint8_t *endPos = nullptr;
122 };
123
124 #ifndef PAGE_SIZE
125 constexpr size_t PAGE_SIZE = 4096;
126 #endif
127
128 constexpr uint64_t HITRACE_TAG = 0xD002D33;
129 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HITRACE_TAG, "HitraceDump"};
130 std::atomic<bool> g_dumpFlag(false);
131 std::atomic<bool> g_dumpEnd(true);
132 bool g_monitor = false; // close service monitor for now
133 TraceMode g_traceMode = TraceMode::CLOSE;
134 std::string g_traceRootPath;
135 std::vector<std::pair<std::string, int>> g_traceFilesTable;
136 std::vector<std::string> g_outputFilesForCmd;
137
138 TraceParams g_currentTraceParams = {};
139
Split(const std::string & str,char delimiter)140 std::vector<std::string> Split(const std::string &str, char delimiter)
141 {
142 std::vector<std::string> res;
143 size_t startPos = 0;
144 for (size_t i = 0; i < str.size(); i++) {
145 if (str[i] == delimiter) {
146 res.push_back(str.substr(startPos, i - startPos));
147 startPos = i + 1;
148 }
149 }
150 if (startPos < str.size()) {
151 res.push_back(str.substr(startPos));
152 }
153 return res;
154 }
155
IsTraceMounted()156 bool IsTraceMounted()
157 {
158 const std::string debugfsPath = "/sys/kernel/debug/tracing/";
159 const std::string tracefsPath = "/sys/kernel/tracing/";
160 if (access((debugfsPath + "trace_marker").c_str(), F_OK) != -1) {
161 g_traceRootPath = debugfsPath;
162 return true;
163 }
164 if (access((tracefsPath + "trace_marker").c_str(), F_OK) != -1) {
165 g_traceRootPath = tracefsPath;
166 return true;
167 }
168 HiLog::Error(LABEL, "IsTraceMounted: Did not find trace folder");
169 return false;
170 }
171
172 // Arch is 64bit when reserved = 0; Arch is 32bit when reserved = 1.
GetArchWordSize(TraceFileHeader & header)173 void GetArchWordSize(TraceFileHeader& header)
174 {
175 if (sizeof(void*) == sizeof(uint64_t)) {
176 header.reserved = 0;
177 } else if (sizeof(void*) == sizeof(uint32_t)) {
178 header.reserved = 1;
179 }
180 HiLog::Info(LABEL, "Kernel bit is %{public}d.", header.reserved);
181 }
182
ParseJsonFromFile(const std::string & filePath)183 cJSON* ParseJsonFromFile(const std::string& filePath)
184 {
185 std::ifstream inFile(filePath, std::ios::in);
186 if (!inFile.is_open()) {
187 HiLog::Error(LABEL, "ParseJsonFromFile: %{pubilc}s is not existed.", filePath.c_str());
188 return nullptr;
189 }
190 std::string fileContent((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
191 cJSON* root = cJSON_Parse(fileContent.c_str());
192 if (root == nullptr) {
193 HiLog::Error(LABEL, "ParseJsonFromFile: %{pubilc}s is not in JSON format.", filePath.c_str());
194 }
195 inFile.close();
196 return root;
197 }
198
ParseTagCategory(cJSON * tagCategoryNode,std::map<std::string,TagCategory> & allTags)199 bool ParseTagCategory(cJSON* tagCategoryNode, std::map<std::string, TagCategory>& allTags)
200 {
201 cJSON* tags = nullptr;
202 cJSON_ArrayForEach(tags, tagCategoryNode) {
203 TagCategory tagCategory;
204 cJSON* description = cJSON_GetObjectItem(tags, "description");
205 if (description != nullptr) {
206 tagCategory.description = description->valuestring;
207 }
208 cJSON* tagOffset = cJSON_GetObjectItem(tags, "tag_offset");
209 if (tagOffset != nullptr) {
210 tagCategory.tag = 1ULL << tagOffset->valueint;
211 }
212 cJSON* type = cJSON_GetObjectItem(tags, "type");
213 if (type != nullptr) {
214 tagCategory.type = type->valueint;
215 }
216 cJSON* sysFiles = cJSON_GetObjectItem(tags, "sysFiles");
217 if (sysFiles != nullptr && cJSON_IsArray(sysFiles)) {
218 cJSON* sysFile = nullptr;
219 cJSON_ArrayForEach(sysFile, sysFiles) {
220 if (cJSON_IsString(sysFile)) {
221 tagCategory.sysFiles.push_back(sysFile->valuestring);
222 }
223 }
224 }
225 allTags.insert(std::pair<std::string, TagCategory>(tags->string, tagCategory));
226 }
227 return true;
228 }
229
ParseTagGroups(cJSON * tagGroupsNode,std::map<std::string,std::vector<std::string>> & tagGroupTable)230 bool ParseTagGroups(cJSON* tagGroupsNode, std::map<std::string, std::vector<std::string>> &tagGroupTable)
231 {
232 cJSON* tagGroup = nullptr;
233 cJSON_ArrayForEach(tagGroup, tagGroupsNode) {
234 std::string tagGroupName = tagGroup->string;
235 std::vector<std::string> tagList;
236 cJSON* tag = nullptr;
237 cJSON_ArrayForEach(tag, tagGroup) {
238 tagList.push_back(tag->valuestring);
239 }
240 tagGroupTable.insert(std::pair<std::string, std::vector<std::string>>(tagGroupName, tagList));
241 }
242 return true;
243 }
244
ParseTagInfo(std::map<std::string,TagCategory> & allTags,std::map<std::string,std::vector<std::string>> & tagGroupTable)245 bool ParseTagInfo(std::map<std::string, TagCategory> &allTags,
246 std::map<std::string, std::vector<std::string>> &tagGroupTable)
247 {
248 std::string traceUtilsPath = "/system/etc/hiview/hitrace_utils.json";
249 cJSON* root = ParseJsonFromFile(traceUtilsPath);
250 if (root == nullptr) {
251 return false;
252 }
253 cJSON* tagCategory = cJSON_GetObjectItem(root, "tag_category");
254 if (tagCategory == nullptr) {
255 HiLog::Error(LABEL, "ParseTagInfo: %{pubilc}s is not contain tag_category node.", traceUtilsPath.c_str());
256 cJSON_Delete(root);
257 return false;
258 }
259 if (!ParseTagCategory(tagCategory, allTags)) {
260 cJSON_Delete(root);
261 return false;
262 }
263 cJSON* tagGroups = cJSON_GetObjectItem(root, "tag_groups");
264 if (tagGroups == nullptr) {
265 HiLog::Error(LABEL, "ParseTagInfo: %{pubilc}s is not contain tag_groups node.", traceUtilsPath.c_str());
266 cJSON_Delete(root);
267 return false;
268 }
269 if (!ParseTagGroups(tagGroups, tagGroupTable)) {
270 cJSON_Delete(root);
271 return false;
272 }
273 cJSON_Delete(root);
274 HiLog::Info(LABEL, "ParseTagInfo: parse done.");
275 return true;
276 }
277
CheckTags(const std::vector<std::string> & tags,const std::map<std::string,TagCategory> & allTags)278 bool CheckTags(const std::vector<std::string> &tags, const std::map<std::string, TagCategory> &allTags)
279 {
280 for (auto tag : tags) {
281 if (allTags.find(tag) == allTags.end()) {
282 HiLog::Error(LABEL, "CheckTags: %{pubilc}s is not provided.", tag.c_str());
283 return false;
284 }
285 }
286 return true;
287 }
288
CheckTagGroup(const std::vector<std::string> & tagGroups,const std::map<std::string,std::vector<std::string>> & tagGroupTable)289 bool CheckTagGroup(const std::vector<std::string> &tagGroups,
290 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
291 {
292 for (auto groupName : tagGroups) {
293 if (tagGroupTable.find(groupName) == tagGroupTable.end()) {
294 HiLog::Error(LABEL, "CheckTagGroup: %{pubilc}s is not provided.", groupName.c_str());
295 return false;
296 }
297 }
298 return true;
299 }
300
WriteStrToFile(const std::string & filename,const std::string & str)301 bool WriteStrToFile(const std::string& filename, const std::string& str)
302 {
303 std::ofstream out;
304 out.open(g_traceRootPath + filename, std::ios::out);
305 if (out.fail()) {
306 HiLog::Error(LABEL, "WriteStrToFile: %{pubilc}s open failed.", filename.c_str());
307 return false;
308 }
309 out << str;
310 if (out.bad()) {
311 HiLog::Error(LABEL, "WriteStrToFile: %{pubilc}s write failed.", filename.c_str());
312 out.close();
313 return false;
314 }
315 out.flush();
316 out.close();
317 return true;
318 }
319
SetFtraceEnabled(const std::string & path,bool enabled)320 void SetFtraceEnabled(const std::string &path, bool enabled)
321 {
322 WriteStrToFile(path, enabled ? "1" : "0");
323 }
324
TruncateFile()325 void TruncateFile()
326 {
327 int fd = creat((g_traceRootPath + "trace").c_str(), 0);
328 if (fd == -1) {
329 HiLog::Error(LABEL, "TruncateFile: clear old trace failed.");
330 return;
331 }
332 close(fd);
333 return;
334 }
335
SetProperty(const std::string & property,const std::string & value)336 bool SetProperty(const std::string& property, const std::string& value)
337 {
338 bool result = OHOS::system::SetParameter(property, value);
339 if (!result) {
340 HiLog::Error(LABEL, "SetProperty: set %{pubilc}s failed.", value.c_str());
341 } else {
342 HiLog::Info(LABEL, "SetProperty: set %{pubilc}s success.", value.c_str());
343 }
344 return result;
345 }
346
TraceInit(const std::map<std::string,TagCategory> & allTags)347 void TraceInit(const std::map<std::string, TagCategory> &allTags)
348 {
349 // close all ftrace events
350 for (auto it = allTags.begin(); it != allTags.end(); it++) {
351 if (it->second.type != 1) {
352 continue;
353 }
354 for (size_t i = 0; i < it->second.sysFiles.size(); i++) {
355 SetFtraceEnabled(it->second.sysFiles[i], false);
356 }
357 }
358 // close all user tags
359 SetProperty("debug.hitrace.tags.enableflags", std::to_string(0));
360
361 // set buffer_size_kb 1
362 WriteStrToFile("buffer_size_kb", "1");
363
364 // close tracing_on
365 SetFtraceEnabled("tracing_on", false);
366 }
367
SetAllTags(const TraceParams & traceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)368 void SetAllTags(const TraceParams &traceParams, const std::map<std::string, TagCategory> &allTags,
369 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
370 {
371 std::set<std::string> readyEnableTagList;
372 for (std::string tagName : traceParams.tags) {
373 readyEnableTagList.insert(tagName);
374 }
375
376 // if set tagGroup, need to append default group
377 if (traceParams.tagGroups.size() > 0) {
378 auto iter = tagGroupTable.find("default");
379 if (iter == tagGroupTable.end()) {
380 HiLog::Error(LABEL, "SetAllTags: default group is wrong.");
381 } else {
382 for (auto defaultTag : iter->second) {
383 readyEnableTagList.insert(defaultTag);
384 }
385 }
386 }
387
388 for (std::string groupName : traceParams.tagGroups) {
389 auto iter = tagGroupTable.find(groupName);
390 if (iter == tagGroupTable.end()) {
391 continue;
392 }
393 for (std::string tag : iter->second) {
394 readyEnableTagList.insert(tag);
395 }
396 }
397
398 uint64_t enabledUserTags = 0;
399 for (std::string tagName : readyEnableTagList) {
400 auto iter = allTags.find(tagName);
401 if (iter == allTags.end()) {
402 continue;
403 }
404
405 if (iter->second.type == 0) {
406 enabledUserTags |= iter->second.tag;
407 }
408
409 if (iter->second.type == 1) {
410 for (const auto& path : iter->second.sysFiles) {
411 SetFtraceEnabled(path, true);
412 HiLog::Info(LABEL, "Ftrace Enabled: set %{pubilc}s success.", path.c_str());
413 }
414 }
415 }
416 SetProperty("debug.hitrace.tags.enableflags", std::to_string(enabledUserTags));
417 }
418
CanonicalizeSpecPath(const char * src)419 std::string CanonicalizeSpecPath(const char* src)
420 {
421 if (src == nullptr || strlen(src) >= PATH_MAX) {
422 HiLog::Error(LABEL, "CanonicalizeSpecPath: %{pubilc}s failed.", src);
423 return "";
424 }
425 char resolvedPath[PATH_MAX] = { 0 };
426 #if defined(_WIN32)
427 if (!_fullpath(resolvedPath, src, PATH_MAX)) {
428 return "";
429 }
430 #else
431 if (access(src, F_OK) == 0) {
432 if (realpath(src, resolvedPath) == nullptr) {
433 HiLog::Error(LABEL, "CanonicalizeSpecPath: realpath %{pubilc}s failed.", src);
434 return "";
435 }
436 } else {
437 std::string fileName(src);
438 if (fileName.find("..") == std::string::npos) {
439 if (sprintf_s(resolvedPath, PATH_MAX, "%s", src) == -1) {
440 HiLog::Error(LABEL, "CanonicalizeSpecPath: sprintf_s %{pubilc}s failed.", src);
441 return "";
442 }
443 } else {
444 HiLog::Error(LABEL, "CanonicalizeSpecPath: find .. src failed.");
445 return "";
446 }
447 }
448 #endif
449 std::string res(resolvedPath);
450 return res;
451 }
452
ReadFile(const std::string & filename)453 std::string ReadFile(const std::string& filename)
454 {
455 std::string resolvedPath = CanonicalizeSpecPath((g_traceRootPath + filename).c_str());
456 std::ifstream fileIn(resolvedPath.c_str());
457 if (!fileIn.is_open()) {
458 HiLog::Error(LABEL, "ReadFile: %{pubilc}s open failed.", filename.c_str());
459 return "";
460 }
461
462 std::string str((std::istreambuf_iterator<char>(fileIn)), std::istreambuf_iterator<char>());
463 fileIn.close();
464 return str;
465 }
466
SetClock(const std::string & clockType)467 void SetClock(const std::string& clockType)
468 {
469 const std::string traceClockPath = "trace_clock";
470 if (clockType.size() == 0) {
471 WriteStrToFile(traceClockPath, "boot"); //set default: boot
472 return;
473 }
474 std::string allClocks = ReadFile(traceClockPath);
475 if (allClocks.find(clockType) == std::string::npos) {
476 HiLog::Error(LABEL, "SetClock: %{pubilc}s is non-existent, set to boot", clockType.c_str());
477 WriteStrToFile(traceClockPath, "boot"); // set default: boot
478 return;
479 }
480
481 std::set<std::string> allClockTypes;
482 size_t curPos = 0;
483 for (size_t i = 0; i < allClocks.size(); i++) {
484 if (allClocks[i] == ' ') {
485 allClockTypes.insert(allClocks.substr(curPos, i - curPos));
486 curPos = i + 1;
487 }
488 }
489 std::string currentClockType;
490 for (auto i : allClockTypes) {
491 if (clockType.compare(i) == 0) {
492 HiLog::Info(LABEL, "SetClock: set clock %{public}s success.", clockType.c_str());
493 WriteStrToFile(traceClockPath, clockType);
494 return;
495 }
496 if (i[0] == '[') {
497 currentClockType = i;
498 }
499 }
500 if (currentClockType.size() == 0) {
501 HiLog::Info(LABEL, "SetClock: clockType is boot now.");
502 return;
503 }
504 const int marks = 2;
505 if (clockType.compare(currentClockType.substr(1, currentClockType.size() - marks)) == 0) {
506 HiLog::Info(LABEL, "SetClock: set clock %{public}s success.", clockType.c_str());
507 return;
508 }
509
510 HiLog::Info(LABEL, "SetClock: unknown %{public}s, change to default clock_type: boot.", clockType.c_str());
511 WriteStrToFile(traceClockPath, "boot"); // set default: boot
512 return;
513 }
514
SetTraceSetting(const TraceParams & traceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)515 bool SetTraceSetting(const TraceParams &traceParams, const std::map<std::string, TagCategory> &allTags,
516 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
517 {
518 TraceInit(allTags);
519
520 TruncateFile();
521
522 SetAllTags(traceParams, allTags, tagGroupTable);
523
524 WriteStrToFile("current_tracer", "nop");
525 WriteStrToFile("buffer_size_kb", traceParams.bufferSize);
526
527 SetClock(traceParams.clockType);
528
529 if (traceParams.isOverWrite == "1") {
530 WriteStrToFile("options/overwrite", "1");
531 } else {
532 WriteStrToFile("options/overwrite", "0");
533 }
534
535 WriteStrToFile("saved_cmdlines_size", std::to_string(SAVED_CMDLINES_SIZE));
536 WriteStrToFile("options/record-tgid", "1");
537 WriteStrToFile("options/record-cmd", "1");
538
539 if (traceParams.outputFile.size() > 0) {
540 const mode_t defaultMode = S_IRUSR | S_IWUSR | S_IRGRP;
541 int fd = creat(traceParams.outputFile.c_str(), defaultMode);
542 if (fd == -1) {
543 HiLog::Error(LABEL, "SetTraceSetting: create %{public}s failed.", traceParams.outputFile.c_str());
544 return false;
545 } else {
546 close(fd);
547 }
548 }
549 return true;
550 }
551
GetCpuProcessors()552 int GetCpuProcessors()
553 {
554 int processors = 0;
555 processors = sysconf(_SC_NPROCESSORS_ONLN);
556 return (processors == 0) ? 1 : processors;
557 }
558
GetFileSize(const std::string & fileName)559 size_t GetFileSize(const std::string &fileName)
560 {
561 if (fileName.empty()) {
562 return 0;
563 }
564 if (access(fileName.c_str(), 0) == -1) {
565 return 0;
566 }
567
568 struct stat statbuf;
569 stat(fileName.c_str(), &statbuf);
570 return statbuf.st_size;
571 }
572
WriteFile(uint8_t contentType,const std::string & src,int outFd)573 bool WriteFile(uint8_t contentType, const std::string &src, int outFd)
574 {
575 std::string srcPath = CanonicalizeSpecPath(src.c_str());
576 int srcFd = open(srcPath.c_str(), O_RDONLY | O_NONBLOCK);
577 if (srcFd < 0) {
578 HiLog::Error(LABEL, "WriteFile: open %{public}s failed.", src.c_str());
579 return false;
580 }
581 struct TraceFileContentHeader contentHeader;
582 contentHeader.type = contentType;
583 write(outFd, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
584 uint32_t readLen = 0;
585 uint8_t buffer[PAGE_SIZE] = {0};
586 const int maxReadSize = DEFAULT_BUFFER_SIZE * 1024;
587 const int pageThreshold = PAGE_SIZE / 2;
588 PageHeader *pageHeader = nullptr;
589 int count = 0;
590 const int maxCount = 2;
591 while (readLen < maxReadSize) {
592 ssize_t readBytes = TEMP_FAILURE_RETRY(read(srcFd, buffer, PAGE_SIZE));
593 if (readBytes <= 0) {
594 break;
595 }
596 write(outFd, buffer, readBytes);
597 readLen += readBytes;
598
599 // Check raw_trace page size.
600 if (contentType >= CONTENT_TYPE_CPU_RAW) {
601 pageHeader = reinterpret_cast<PageHeader*>(&buffer);
602 if (pageHeader->size < static_cast<uint64_t>(pageThreshold)) {
603 count++;
604 }
605 if (count >= maxCount) {
606 break;
607 }
608 }
609 }
610 contentHeader.length = readLen;
611 uint32_t offset = contentHeader.length + sizeof(contentHeader);
612 off_t pos = lseek(outFd, 0, SEEK_CUR);
613 lseek(outFd, pos - offset, SEEK_SET);
614 write(outFd, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
615 lseek(outFd, pos, SEEK_SET);
616 close(srcFd);
617 return true;
618 }
619
WriteEventFile(std::string & srcPath,int outFd)620 void WriteEventFile(std::string &srcPath, int outFd)
621 {
622 uint8_t buffer[PAGE_SIZE] = {0};
623 std::string srcSpecPath = CanonicalizeSpecPath(srcPath.c_str());
624 int srcFd = open(srcSpecPath.c_str(), O_RDONLY);
625 if (srcFd < 0) {
626 HiLog::Error(LABEL, "WriteEventsFormat: open %{public}s failed.", srcPath.c_str());
627 return;
628 }
629 do {
630 int len = read(srcFd, buffer, PAGE_SIZE);
631 if (len <= 0) {
632 break;
633 }
634 write(outFd, buffer, len);
635 } while (true);
636 close(srcFd);
637 }
638
WriteEventsFormat(int outFd)639 bool WriteEventsFormat(int outFd)
640 {
641 const std::string savedEventsFormatPath = DEFAULT_OUTPUT_DIR + "saved_events_format";
642 if (access(savedEventsFormatPath.c_str(), F_OK) != -1) {
643 return WriteFile(CONTENT_TYPE_EVENTS_FORMAT, savedEventsFormatPath, outFd);
644 }
645 std::string filePath = CanonicalizeSpecPath(savedEventsFormatPath.c_str());
646 int fd = open(filePath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
647 if (fd < 0) {
648 HiLog::Error(LABEL, "WriteEventsFormat: open %{public}s failed.", savedEventsFormatPath.c_str());
649 return false;
650 }
651 const std::vector<std::string> priorityTracingCategory = {
652 "events/sched/sched_waking/format",
653 "events/sched/sched_wakeup/format",
654 "events/sched/sched_switch/format",
655 "events/sched/sched_blocked_reason/format",
656 "events/power/cpu_frequency/format",
657 "events/power/clock_set_rate/format",
658 "events/power/cpu_frequency_limits/format",
659 "events/f2fs/f2fs_sync_file_enter/format",
660 "events/f2fs/f2fs_sync_file_exit/format",
661 "events/ext4/ext4_da_write_begin/format",
662 "events/ext4/ext4_da_write_end/format",
663 "events/ext4/ext4_sync_file_enter/format",
664 "events/ext4/ext4_sync_file_exit/format",
665 "events/block/block_rq_issue/format",
666 "events/block/block_rq_complete/format",
667 "events/binder/binder_transaction/format",
668 "events/binder/binder_transaction_received/format",
669 "events/ftrace/print/format",
670 };
671 for (size_t i = 0; i < priorityTracingCategory.size(); i++) {
672 std::string srcPath = g_traceRootPath + priorityTracingCategory[i];
673 WriteEventFile(srcPath, fd);
674 }
675 close(fd);
676 return WriteFile(CONTENT_TYPE_EVENTS_FORMAT, filePath, outFd);
677 }
678
WriteCpuRaw(int outFd)679 bool WriteCpuRaw(int outFd)
680 {
681 int cpuNums = GetCpuProcessors();
682 int ret = true;
683 uint8_t type = CONTENT_TYPE_CPU_RAW;
684 for (int i = 0; i < cpuNums; i++) {
685 std::string src = g_traceRootPath + "per_cpu/cpu" + std::to_string(i) + "/trace_pipe_raw";
686 if (!WriteFile(static_cast<uint8_t>(type + i), src, outFd)) {
687 ret = false;
688 break;
689 }
690 }
691 return ret;
692 }
693
WriteCmdlines(int outFd)694 bool WriteCmdlines(int outFd)
695 {
696 std::string cmdlinesPath = g_traceRootPath + "saved_cmdlines";
697 return WriteFile(CONTENT_TYPE_CMDLINES, cmdlinesPath, outFd);
698 }
699
WriteTgids(int outFd)700 bool WriteTgids(int outFd)
701 {
702 std::string tgidsPath = g_traceRootPath + "saved_tgids";
703 return WriteFile(CONTENT_TYPE_TGIDS, tgidsPath, outFd);
704 }
705
DumpTraceLoop(const std::string & outputFileName,bool isLimited)706 bool DumpTraceLoop(const std::string &outputFileName, bool isLimited)
707 {
708 const int sleepTime = 1;
709 const int fileSizeThreshold = 96 * 1024 * 1024;
710 std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
711 int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
712 if (outFd < 0) {
713 return false;
714 }
715 struct TraceFileHeader header;
716 GetArchWordSize(header);
717 write(outFd, reinterpret_cast<char*>(&header), sizeof(header));
718 WriteEventsFormat(outFd);
719 while (g_dumpFlag) {
720 if (isLimited && GetFileSize(outPath) > fileSizeThreshold) {
721 break;
722 }
723 sleep(sleepTime);
724 WriteCpuRaw(outFd);
725 }
726 WriteCmdlines(outFd);
727 WriteTgids(outFd);
728 close(outFd);
729 return true;
730 }
731
732 /**
733 * read trace data loop
734 * g_dumpFlag: true = open,false = close
735 * g_dumpEnd: true = end,false = not end
736 * if user has own output file, Output all data to the file specified by the user;
737 * if not, Then place all the result files in/data/local/tmp/and package them once in 96M.
738 */
ProcessDumpTask()739 void ProcessDumpTask()
740 {
741 g_dumpFlag = true;
742 g_dumpEnd = false;
743 g_outputFilesForCmd = {};
744 if (g_currentTraceParams.outputFile.size() > 0) {
745 if (DumpTraceLoop(g_currentTraceParams.outputFile, false)) {
746 g_outputFilesForCmd.push_back(g_currentTraceParams.outputFile);
747 }
748 g_dumpEnd = true;
749 return;
750 }
751
752 while (g_dumpFlag) {
753 // Generate file name
754 struct timeval now = {0, 0};
755 gettimeofday(&now, nullptr);
756 std::string outputFileName = "/data/local/tmp/trace_" + std::to_string(now.tv_sec) + ".sys";
757 if (DumpTraceLoop(outputFileName, true)) {
758 g_outputFilesForCmd.push_back(outputFileName);
759 }
760 }
761 g_dumpEnd = true;
762 }
763
SearchFromTable(std::vector<std::string> & outputFiles,int nowSec)764 void SearchFromTable(std::vector<std::string> &outputFiles, int nowSec)
765 {
766 const int maxInterval = 8;
767 const int agingTime = 30 * 60;
768
769 for (auto iter = g_traceFilesTable.begin(); iter != g_traceFilesTable.end();) {
770 if (nowSec - iter->second >= agingTime) {
771 // delete outdated trace file
772 if (access(iter->first.c_str(), F_OK) == 0) {
773 remove(iter->first.c_str());
774 HiLog::Info(LABEL, "delete old %{public}s file success.", iter->first.c_str());
775 }
776 iter = g_traceFilesTable.erase(iter);
777 continue;
778 }
779
780 if (nowSec - iter->second <= maxInterval) {
781 outputFiles.push_back(iter->first);
782 }
783 iter++;
784 }
785 }
786
ReadRawTrace(std::string & outputFileName)787 bool ReadRawTrace(std::string &outputFileName)
788 {
789 // read trace data from /per_cpu/cpux/trace_pipe_raw
790 std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
791 int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
792 if (outFd < 0) {
793 return false;
794 }
795 struct TraceFileHeader header;
796 GetArchWordSize(header);
797 write(outFd, reinterpret_cast<char*>(&header), sizeof(header));
798
799 if (WriteEventsFormat(outFd) && WriteCpuRaw(outFd) &&
800 WriteCmdlines(outFd) && WriteTgids(outFd)) {
801 close(outFd);
802 return true;
803 }
804 HiLog::Error(LABEL, "ReadRawTrace failed.");
805 close(outFd);
806 return false;
807 }
808
GenerateName()809 std::string GenerateName()
810 {
811 // eg: /data/log/hitrace/trace_localtime@monotime.sys
812 std::string name = DEFAULT_OUTPUT_DIR + "trace_";
813 // get localtime
814 time_t currentTime;
815 time(¤tTime);
816 struct tm timeInfo = {};
817 const int bufferSize = 16;
818 char timeStr[bufferSize] = {0};
819 if (localtime_r(¤tTime, &timeInfo) == nullptr) {
820 HiLog::Error(LABEL, "Get localtime failed.");
821 return "";
822 }
823 strftime(timeStr, bufferSize, "%Y%m%d%H%M%S", &timeInfo);
824 name += std::string(timeStr);
825 // get monotime
826 struct timespec mts = {0, 0};
827 clock_gettime(CLOCK_MONOTONIC, &mts);
828 name += "@" + std::to_string(mts.tv_sec) + "-" + std::to_string(mts.tv_nsec) + ".sys";
829 HiLog::Info(LABEL, "Generate trace name: %{public}s.", name.c_str());
830 return name;
831 }
832
DumpTraceInner(std::vector<std::string> & outputFiles)833 TraceErrorCode DumpTraceInner(std::vector<std::string> &outputFiles)
834 {
835 struct timeval now = {0, 0};
836 gettimeofday(&now, nullptr);
837 int nowSec = now.tv_sec;
838 if (!g_dumpEnd) {
839 const int maxSleepTime = 2 * 1000 * 1000 / UNIT_TIME; // 2s
840 int cur = 0;
841 while (!g_dumpEnd && cur < maxSleepTime) {
842 cur += 1;
843 usleep(UNIT_TIME);
844 }
845 SearchFromTable(outputFiles, nowSec);
846 if (outputFiles.size() == 0) {
847 return TraceErrorCode::WRITE_TRACE_INFO_ERROR;
848 }
849 return TraceErrorCode::SUCCESS;
850 }
851 g_dumpEnd = false;
852 std::string outputFileName = GenerateName();
853 std::string reOutPath = CanonicalizeSpecPath(outputFileName.c_str());
854 bool ret = ReadRawTrace(reOutPath);
855
856 SearchFromTable(outputFiles, nowSec);
857 if (ret) {
858 outputFiles.push_back(outputFileName);
859 g_traceFilesTable.push_back({outputFileName, nowSec});
860 } else {
861 HiLog::Error(LABEL, "DumpTraceInner: write %{public}s failed.", outputFileName.c_str());
862 g_dumpEnd = true;
863 return TraceErrorCode::WRITE_TRACE_INFO_ERROR;
864 }
865 g_dumpEnd = true;
866 return TraceErrorCode::SUCCESS;
867 }
868
AdjustInner(CpuStat & cpuStat,LastCpuInfo & lastCpuInfo,int i)869 void AdjustInner(CpuStat &cpuStat, LastCpuInfo &lastCpuInfo, int i)
870 {
871 const int cpuUsageThreshold = 80;
872 const int percentage = 100;
873 uint64_t totalCpuTime = cpuStat.user + cpuStat.nice + cpuStat.system + cpuStat.idle + cpuStat.iowait +
874 cpuStat.irq + cpuStat.softirq;
875 uint64_t cpuUsage = percentage - percentage * (cpuStat.idle - lastCpuInfo.idleAndTotal.first) /
876 (totalCpuTime - lastCpuInfo.idleAndTotal.second);
877 if (cpuUsage >= cpuUsageThreshold && lastCpuInfo.isNormal) {
878 std::string subPath = "per_cpu/cpu" + std::to_string(i) + "/buffer_size_kb";
879 WriteStrToFile(subPath, std::to_string(HIGHER_BUFFER_SIZE));
880 lastCpuInfo.isNormal = false;
881 }
882 if (!lastCpuInfo.isNormal && cpuUsage < cpuUsageThreshold) {
883 std::string subPath = "per_cpu/cpu" + std::to_string(i) + "/buffer_size_kb";
884 WriteStrToFile(subPath, std::to_string(DEFAULT_BUFFER_SIZE));
885 lastCpuInfo.isNormal = true;
886 }
887 lastCpuInfo.idleAndTotal.first = cpuStat.idle;
888 lastCpuInfo.idleAndTotal.second = totalCpuTime;
889 }
890
CpuTraceBufferSizeAdjust(std::vector<LastCpuInfo> & lastData,const int cpuNums)891 bool CpuTraceBufferSizeAdjust(std::vector<LastCpuInfo> &lastData, const int cpuNums)
892 {
893 std::ifstream statFile("/proc/stat");
894 if (!statFile.is_open()) {
895 HiLog::Error(LABEL, "CpuTraceBufferSizeAdjust: open /proc/stat failed.");
896 return false;
897 }
898 std::string data;
899 std::vector<CpuStat> cpuStats;
900
901 const int pos = 3;
902 const int formatNumber = 10;
903 while (std::getline(statFile, data)) {
904 if (data.substr(0, pos) == "cpu" && data[pos] != ' ') {
905 CpuStat cpuStat = {};
906 int ret = sscanf_s(data.c_str(), "%*s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", &cpuStat.user,
907 &cpuStat.nice, &cpuStat.system, &cpuStat.idle, &cpuStat.iowait, &cpuStat.irq,
908 &cpuStat.softirq, &cpuStat.steal, &cpuStat.guest, &cpuStat.guestNice);
909 if (ret != formatNumber) {
910 HiLog::Error(LABEL, "CpuTraceBufferSizeAdjust: format error.");
911 return false;
912 }
913 cpuStats.push_back(cpuStat);
914 }
915 }
916 statFile.close();
917 if (cpuNums != (int)cpuStats.size()) {
918 HiLog::Error(LABEL, "CpuTraceBufferSizeAdjust: read /proc/stat error.");
919 return false;
920 }
921 for (size_t i = 0; i < cpuStats.size(); i++) {
922 AdjustInner(cpuStats[i], lastData[i], i);
923 }
924 return true;
925 }
926
MonitorServiceTask()927 void MonitorServiceTask()
928 {
929 HiLog::Info(LABEL, "MonitorServiceTask: monitor thread start.");
930 const int maxServiceTimes = 3 * 1000 * 1000 / UNIT_TIME; // 3s
931 int curServiceTimes = 0;
932 const int cpuNums = GetCpuProcessors();
933 std::vector<LastCpuInfo> lastData;
934 for (int i = 0; i < cpuNums; i++) {
935 lastData.push_back({{0, 0}, true});
936 }
937
938 while (true) {
939 if (g_traceMode != TraceMode::SERVICE_MODE || !g_monitor) {
940 HiLog::Info(LABEL, "MonitorServiceTask: monitor thread exit because of g_monitor.");
941 break;
942 }
943 if (curServiceTimes >= maxServiceTimes) {
944 // trace ringbuffer dynamic tuning
945 if (!CpuTraceBufferSizeAdjust(lastData, cpuNums)) {
946 HiLog::Info(LABEL, "MonitorServiceTask: monitor thread exit.");
947 break;
948 }
949 curServiceTimes = 0;
950 } else {
951 curServiceTimes++;
952 }
953 usleep(UNIT_TIME);
954 }
955 }
956
MonitorCmdTask()957 void MonitorCmdTask()
958 {
959 int curCmdTimes = 0;
960 const int maxCmdTimes = 5 * 60 * 1000 * 1000 / UNIT_TIME; // 5min exit
961 HiLog::Info(LABEL, "MonitorCmdTask: monitor thread start.");
962 while (true) {
963 if (g_traceMode != TraceMode::CMD_MODE) {
964 HiLog::Info(LABEL, "MonitorCmdTask: monitor thread exit.");
965 return;
966 }
967
968 if (curCmdTimes >= maxCmdTimes) {
969 HiLog::Error(LABEL, "MonitorCmdTask: CMD_MODE Timeout exit.");
970 g_dumpFlag = false;
971 while (!g_dumpEnd) {
972 usleep(UNIT_TIME);
973 }
974 OHOS::HiviewDFX::Hitrace::CloseTrace();
975 break;
976 } else {
977 curCmdTimes++;
978 }
979 usleep(UNIT_TIME);
980 }
981 }
982
HandleTraceOpen(const TraceParams & traceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)983 TraceErrorCode HandleTraceOpen(const TraceParams &traceParams,
984 const std::map<std::string, TagCategory> &allTags,
985 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
986 {
987 if (!SetTraceSetting(traceParams, allTags, tagGroupTable)) {
988 return TraceErrorCode::FILE_ERROR;
989 }
990 SetFtraceEnabled("tracing_on", true);
991 g_currentTraceParams = traceParams;
992 return TraceErrorCode::SUCCESS;
993 }
994
HandleServiceTraceOpen(const std::vector<std::string> & tagGroups,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)995 TraceErrorCode HandleServiceTraceOpen(const std::vector<std::string> &tagGroups,
996 const std::map<std::string, TagCategory> &allTags,
997 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
998 {
999 TraceParams serviceTraceParams;
1000 serviceTraceParams.tagGroups = tagGroups;
1001 serviceTraceParams.bufferSize = std::to_string(DEFAULT_BUFFER_SIZE);
1002 serviceTraceParams.clockType = "boot";
1003 serviceTraceParams.isOverWrite = "1";
1004 return HandleTraceOpen(serviceTraceParams, allTags, tagGroupTable);
1005 }
1006
RemoveUnSpace(std::string str,std::string & args)1007 void RemoveUnSpace(std::string str, std::string& args)
1008 {
1009 int maxCircleTimes = 30;
1010 int curTimes = 0;
1011 const size_t symbolAndSpaceLen = 2;
1012 std::string strSpace = str + " ";
1013 while (curTimes < maxCircleTimes) {
1014 curTimes++;
1015 std::string::size_type index = args.find(strSpace);
1016 if (index != std::string::npos) {
1017 args.replace(index, symbolAndSpaceLen, str);
1018 } else {
1019 break;
1020 }
1021 }
1022 }
1023
1024 /**
1025 * args: tags:tag1,tags2... tagGroups:group1,group2... clockType:boot bufferSize:1024 overwrite:1 output:filename
1026 * cmdTraceParams: Save the above parameters
1027 */
ParseArgs(const std::string & args,TraceParams & cmdTraceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)1028 bool ParseArgs(const std::string &args, TraceParams &cmdTraceParams, const std::map<std::string, TagCategory> &allTags,
1029 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
1030 {
1031 std::string userArgs = args;
1032 std::string str = ":";
1033 RemoveUnSpace(str, userArgs);
1034 str = ",";
1035 RemoveUnSpace(str, userArgs);
1036 std::vector<std::string> argList = Split(userArgs, ' ');
1037 for (std::string item : argList) {
1038 size_t pos = item.find(":");
1039 if (pos == std::string::npos) {
1040 HiLog::Error(LABEL, "trace command line without colon appears: %{public}s, continue.", item.c_str());
1041 continue;
1042 }
1043 std::string itemName = item.substr(0, pos);
1044 if (itemName == "tags") {
1045 cmdTraceParams.tags = Split(item.substr(pos + 1), ',');
1046 } else if (itemName == "tagGroups") {
1047 cmdTraceParams.tagGroups = Split(item.substr(pos + 1), ',');
1048 } else if (itemName == "clockType") {
1049 cmdTraceParams.clockType = item.substr(pos + 1);
1050 } else if (itemName == "bufferSize") {
1051 cmdTraceParams.bufferSize = item.substr(pos + 1);
1052 } else if (itemName == "overwrite") {
1053 cmdTraceParams.isOverWrite = item.substr(pos + 1);
1054 } else if (itemName == "output") {
1055 cmdTraceParams.outputFile = item.substr(pos + 1);
1056 } else {
1057 HiLog::Error(LABEL, "Extra trace command line options appear when ParseArgs: %{public}s, return false.",
1058 itemName.c_str());
1059 return false;
1060 }
1061 }
1062 if (CheckTags(cmdTraceParams.tags, allTags) && CheckTagGroup(cmdTraceParams.tagGroups, tagGroupTable)) {
1063 return true;
1064 }
1065 return false;
1066 }
1067
1068 /**
1069 * When the SERVICE_MODE is started, clear the remaining trace files in the folder.
1070 */
ClearRemainingTrace()1071 void ClearRemainingTrace()
1072 {
1073 if (access(DEFAULT_OUTPUT_DIR.c_str(), F_OK) != 0) {
1074 return;
1075 }
1076 DIR* dirPtr = opendir(DEFAULT_OUTPUT_DIR.c_str());
1077 if (dirPtr == nullptr) {
1078 HiLog::Error(LABEL, "opendir failed.");
1079 return;
1080 }
1081 struct dirent* ptr = nullptr;
1082 while ((ptr = readdir(dirPtr)) != nullptr) {
1083 if (ptr->d_type == DT_REG) {
1084 std::string subFileName = DEFAULT_OUTPUT_DIR + std::string(ptr->d_name);
1085 if (remove(subFileName.c_str()) == 0) {
1086 HiLog::Info(LABEL, "Delete old trace file: %{public}s success.", subFileName.c_str());
1087 } else {
1088 HiLog::Error(LABEL, "Delete old trace file: %{public}s failed.", subFileName.c_str());
1089 }
1090 }
1091 }
1092 closedir(dirPtr);
1093 }
1094
1095 } // namespace
1096
1097 namespace OHOS {
1098 namespace HiviewDFX {
1099
1100 namespace Hitrace {
1101
GetTraceMode()1102 TraceMode GetTraceMode()
1103 {
1104 return g_traceMode;
1105 }
1106
OpenTrace(const std::vector<std::string> & tagGroups)1107 TraceErrorCode OpenTrace(const std::vector<std::string> &tagGroups)
1108 {
1109 if (!IsTraceMounted()) {
1110 HiLog::Error(LABEL, "OpenTrace: TRACE_NOT_SUPPORTED.");
1111 return TRACE_NOT_SUPPORTED;
1112 }
1113 std::map<std::string, TagCategory> allTags;
1114 std::map<std::string, std::vector<std::string>> tagGroupTable;
1115 if (!ParseTagInfo(allTags, tagGroupTable)) {
1116 HiLog::Error(LABEL, "OpenTrace: ParseTagInfo TAG_ERROR.");
1117 return TAG_ERROR;
1118 }
1119
1120 if (tagGroups.size() == 0 || !CheckTagGroup(tagGroups, tagGroupTable)) {
1121 HiLog::Error(LABEL, "OpenTrace: TAG_ERROR.");
1122 return TAG_ERROR;
1123 }
1124
1125 if (g_traceMode == CMD_MODE) {
1126 HiLog::Error(LABEL, "OpenTrace: TRACE_IS_OCCUPIED.");
1127 return TRACE_IS_OCCUPIED;
1128 }
1129
1130 if (g_traceMode == SERVICE_MODE) {
1131 HiLog::Error(LABEL, "OpenTrace: CALL_ERROR.");
1132 return CALL_ERROR;
1133 }
1134
1135 TraceErrorCode ret = HandleServiceTraceOpen(tagGroups, allTags, tagGroupTable);
1136 if (ret != SUCCESS) {
1137 HiLog::Error(LABEL, "OpenTrace: open fail.");
1138 return ret;
1139 }
1140 g_traceMode = SERVICE_MODE;
1141
1142 ClearRemainingTrace();
1143 // open SERVICE_MODE monitor thread
1144 std::thread auxiliaryTask(MonitorServiceTask);
1145 auxiliaryTask.detach();
1146 HiLog::Info(LABEL, "OpenTrace: SERVICE_MODE open success.");
1147 return ret;
1148 }
1149
OpenTrace(const std::string & args)1150 TraceErrorCode OpenTrace(const std::string &args)
1151 {
1152 if (!IsTraceMounted()) {
1153 HiLog::Error(LABEL, "Hitrace OpenTrace: TRACE_NOT_SUPPORTED.");
1154 return TRACE_NOT_SUPPORTED;
1155 }
1156 std::map<std::string, TagCategory> allTags;
1157 std::map<std::string, std::vector<std::string>> tagGroupTable;
1158 if (!ParseTagInfo(allTags, tagGroupTable) || allTags.size() == 0 || tagGroupTable.size() == 0) {
1159 HiLog::Error(LABEL, "Hitrace OpenTrace: ParseTagInfo TAG_ERROR.");
1160 return TAG_ERROR;
1161 }
1162 // parse args
1163 TraceParams cmdTraceParams;
1164 if (!ParseArgs(args, cmdTraceParams, allTags, tagGroupTable)) {
1165 HiLog::Error(LABEL, "Hitrace OpenTrace: TAG_ERROR.");
1166 return TAG_ERROR;
1167 }
1168
1169 if (g_traceMode != CLOSE) {
1170 HiLog::Error(LABEL, "Hitrace OpenTrace: CALL_ERROR.");
1171 return CALL_ERROR;
1172 }
1173
1174 TraceErrorCode ret = HandleTraceOpen(cmdTraceParams, allTags, tagGroupTable);
1175 if (ret != SUCCESS) {
1176 HiLog::Error(LABEL, "Hitrace OpenTrace: CMD_MODE open failed.");
1177 return FILE_ERROR;
1178 }
1179 g_traceMode = CMD_MODE;
1180 // open SERVICE_MODE monitor thread
1181 std::thread auxiliaryTask(MonitorCmdTask);
1182 auxiliaryTask.detach();
1183 HiLog::Info(LABEL, "Hitrace OpenTrace: CMD_MODE open success.");
1184 return ret;
1185 }
1186
DumpTrace()1187 TraceRetInfo DumpTrace()
1188 {
1189 TraceRetInfo ret;
1190 if (g_traceMode != SERVICE_MODE) {
1191 HiLog::Error(LABEL, "DumpTrace: CALL_ERROR.");
1192 ret.errorCode = CALL_ERROR;
1193 return ret;
1194 }
1195 ret.errorCode = DumpTraceInner(ret.outputFiles);
1196 return ret;
1197 }
1198
DumpTraceOn()1199 TraceErrorCode DumpTraceOn()
1200 {
1201 // check current trace status
1202 if (g_traceMode != CMD_MODE) {
1203 HiLog::Error(LABEL, "DumpTraceOn: CALL_ERROR.");
1204 return CALL_ERROR;
1205 }
1206
1207 // start task thread
1208 std::thread task(ProcessDumpTask);
1209 task.detach();
1210 HiLog::Info(LABEL, "DumpTraceOn: Dumping trace.");
1211 return SUCCESS;
1212 }
1213
DumpTraceOff()1214 TraceRetInfo DumpTraceOff()
1215 {
1216 TraceRetInfo ret;
1217 g_dumpFlag = false;
1218 const int waitTime = 10000;
1219 while (!g_dumpEnd) {
1220 usleep(waitTime);
1221 }
1222 ret.errorCode = SUCCESS;
1223 ret.outputFiles = g_outputFilesForCmd;
1224 HiLog::Info(LABEL, "DumpTraceOff: trace files generated success.");
1225 return ret;
1226 }
1227
CloseTrace()1228 TraceErrorCode CloseTrace()
1229 {
1230 if (g_traceMode == CLOSE) {
1231 HiLog::Error(LABEL, "CloseTrace: CALL_ERROR.");
1232 return CALL_ERROR;
1233 }
1234 std::map<std::string, TagCategory> allTags;
1235 std::map<std::string, std::vector<std::string>> tagGroupTable;
1236 if (!ParseTagInfo(allTags, tagGroupTable) || allTags.size() == 0 || tagGroupTable.size() == 0) {
1237 HiLog::Error(LABEL, "CloseTrace: ParseTagInfo TAG_ERROR.");
1238 return TAG_ERROR;
1239 }
1240 TraceInit(allTags);
1241 TruncateFile();
1242 g_traceMode = CLOSE;
1243 usleep(UNIT_TIME);
1244 return SUCCESS;
1245 }
1246
GetTraceFilesTable()1247 std::vector<std::pair<std::string, int>> GetTraceFilesTable()
1248 {
1249 return g_traceFilesTable;
1250 }
1251
SetTraceFilesTable(std::vector<std::pair<std::string,int>> & traceFilesTable)1252 void SetTraceFilesTable(std::vector<std::pair<std::string, int>>& traceFilesTable)
1253 {
1254 g_traceFilesTable = traceFilesTable;
1255 }
1256
1257 } // Hitrace
1258 } // HiviewDFX
1259 } // OHOS