1 /*
2 * Copyright (C) 2023-2024 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 #include "hitrace_osal.h"
18 #include "common_utils.h"
19 #include "dynamic_buffer.h"
20
21 #include <map>
22 #include <atomic>
23 #include <fstream>
24 #include <set>
25 #include <thread>
26 #include <mutex>
27 #include <vector>
28 #include <string>
29 #include <memory>
30 #include <filesystem>
31 #include <unistd.h>
32 #include <cstdio>
33 #include <cstdlib>
34 #include <sys/file.h>
35 #include <sys/time.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <fcntl.h>
39 #include <sys/prctl.h>
40 #include <sys/wait.h>
41 #include <cinttypes>
42 #include <utility>
43 #include <dirent.h>
44
45 #include "cJSON.h"
46 #include "parameters.h"
47 #include "hilog/log.h"
48 #include "securec.h"
49
50 using namespace std;
51 using namespace OHOS::HiviewDFX::HitraceOsal;
52 using OHOS::HiviewDFX::HiLog;
53
54 namespace OHOS {
55 namespace HiviewDFX {
56 namespace Hitrace {
57
58 namespace {
59
60 struct TraceParams {
61 std::vector<std::string> tags;
62 std::vector<std::string> tagGroups;
63 std::string bufferSize;
64 std::string clockType;
65 std::string isOverWrite;
66 std::string outputFile;
67 std::string fileSize;
68 std::string fileLimit;
69 std::string appPid;
70 };
71
72 constexpr uint16_t MAGIC_NUMBER = 57161;
73 constexpr uint16_t VERSION_NUMBER = 1;
74 constexpr uint8_t FILE_RAW_TRACE = 0;
75 constexpr uint8_t HM_FILE_RAW_TRACE = 1;
76 constexpr int UNIT_TIME = 100000;
77 constexpr int ALIGNMENT_COEFFICIENT = 4;
78
79 const int DEFAULT_BUFFER_SIZE = 12 * 1024;
80 const int DEFAULT_FILE_SIZE = 100 * 1024;
81 #ifdef DOUBLE_TRACEBUFFER_ENABLE
82 const int HM_DEFAULT_BUFFER_SIZE = 288 * 1024;
83 #else
84 const int HM_DEFAULT_BUFFER_SIZE = 144 * 1024;
85 #endif
86 const int SAVED_CMDLINES_SIZE = 3072; // 3M
87 const int KB_PER_MB = 1024;
88 const int S_TO_NS = 1000000000;
89 const int MAX_NEW_TRACE_FILE_LIMIT = 5;
90 const int JUDGE_FILE_EXIST = 10; // Check whether the trace file exists every 10 times.
91
92 const std::string DEFAULT_OUTPUT_DIR = "/data/log/hitrace/";
93 const std::string SNAPSHOT_PREFIX = "trace_";
94 const std::string RECORDING_PREFIX = "record_trace_";
95 const std::string SAVED_EVENTS_FORMAT = "saved_events_format";
96
97 struct alignas(ALIGNMENT_COEFFICIENT) TraceFileHeader {
98 uint16_t magicNumber {MAGIC_NUMBER};
99 uint8_t fileType {FILE_RAW_TRACE};
100 uint16_t versionNumber {VERSION_NUMBER};
101 uint32_t reserved {0};
102 };
103
104 enum ContentType : uint8_t {
105 CONTENT_TYPE_DEFAULT = 0,
106 CONTENT_TYPE_EVENTS_FORMAT = 1,
107 CONTENT_TYPE_CMDLINES = 2,
108 CONTENT_TYPE_TGIDS = 3,
109 CONTENT_TYPE_CPU_RAW = 4,
110 CONTENT_TYPE_HEADER_PAGE = 30,
111 CONTENT_TYPE_PRINTK_FORMATS = 31,
112 CONTENT_TYPE_KALLSYMS = 32
113 };
114
115 struct alignas(ALIGNMENT_COEFFICIENT) TraceFileContentHeader {
116 uint8_t type = CONTENT_TYPE_DEFAULT;
117 uint32_t length = 0;
118 };
119
120 struct PageHeader {
121 uint64_t timestamp = 0;
122 uint64_t size = 0;
123 uint8_t overwrite = 0;
124 uint8_t *startPos = nullptr;
125 uint8_t *endPos = nullptr;
126 };
127
128 #ifndef PAGE_SIZE
129 constexpr size_t PAGE_SIZE = 4096;
130 #endif
131
132 const int BUFFER_SIZE = 256 * PAGE_SIZE; // 1M
133
134 std::atomic<bool> g_dumpFlag(false);
135 std::atomic<bool> g_dumpEnd(true);
136 std::mutex g_traceMutex;
137
138 bool g_serviceThreadIsStart = false;
139 uint64_t g_sysInitParamTags = 0;
140 TraceMode g_traceMode = TraceMode::CLOSE;
141 std::string g_traceRootPath;
142 uint8_t g_buffer[BUFFER_SIZE] = {0};
143 std::vector<std::pair<std::string, int>> g_traceFilesTable;
144 std::vector<std::string> g_outputFilesForCmd;
145 int g_outputFileSize = 0;
146 int g_timeLimit = 0;
147 int g_newTraceFileLimit = 0;
148 int g_writeFileLimit = 0;
149 bool g_needGenerateNewTraceFile = false;
150
151 TraceParams g_currentTraceParams = {};
152
GetFilePath(const std::string & fileName)153 std::string GetFilePath(const std::string &fileName)
154 {
155 return g_traceRootPath + fileName;
156 }
157
Split(const std::string & str,char delimiter)158 std::vector<std::string> Split(const std::string &str, char delimiter)
159 {
160 std::vector<std::string> res;
161 size_t startPos = 0;
162 for (size_t i = 0; i < str.size(); i++) {
163 if (str[i] == delimiter) {
164 res.push_back(str.substr(startPos, i - startPos));
165 startPos = i + 1;
166 }
167 }
168 if (startPos < str.size()) {
169 res.push_back(str.substr(startPos));
170 }
171 return res;
172 }
173
IsTraceMounted()174 bool IsTraceMounted()
175 {
176 const std::string debugfsPath = "/sys/kernel/debug/tracing/";
177 const std::string tracefsPath = "/sys/kernel/tracing/";
178 if (access((debugfsPath + "trace_marker").c_str(), F_OK) != -1) {
179 g_traceRootPath = debugfsPath;
180 return true;
181 }
182 if (access((tracefsPath + "trace_marker").c_str(), F_OK) != -1) {
183 g_traceRootPath = tracefsPath;
184 return true;
185 }
186 HILOG_ERROR(LOG_CORE, "IsTraceMounted: Did not find trace folder");
187 return false;
188 }
189
190 // Arch is 64bit when reserved = 0; Arch is 32bit when reserved = 1.
GetArchWordSize(TraceFileHeader & header)191 void GetArchWordSize(TraceFileHeader& header)
192 {
193 if (sizeof(void*) == sizeof(uint64_t)) {
194 header.reserved |= 0;
195 } else if (sizeof(void*) == sizeof(uint32_t)) {
196 header.reserved |= 1;
197 }
198 HILOG_INFO(LOG_CORE, "reserved with arch word info is %{public}d.", header.reserved);
199 }
200
201
GetCpuProcessors()202 int GetCpuProcessors()
203 {
204 int processors = 0;
205 processors = sysconf(_SC_NPROCESSORS_CONF);
206 return (processors == 0) ? 1 : processors;
207 }
208
GetCpuNums(TraceFileHeader & header)209 void GetCpuNums(TraceFileHeader& header)
210 {
211 const int maxCpuNums = 24;
212 int cpuNums = GetCpuProcessors();
213 if (cpuNums > maxCpuNums || cpuNums <= 0) {
214 HILOG_ERROR(LOG_CORE, "error: cpu_number is %{public}d.", cpuNums);
215 return;
216 }
217 header.reserved |= (static_cast<uint64_t>(cpuNums) << 1);
218 HILOG_INFO(LOG_CORE, "reserved with cpu number info is %{public}d.", header.reserved);
219 }
220
CheckTags(const std::vector<std::string> & tags,const std::map<std::string,TagCategory> & allTags)221 bool CheckTags(const std::vector<std::string> &tags, const std::map<std::string, TagCategory> &allTags)
222 {
223 for (const auto &tag : tags) {
224 if (allTags.find(tag) == allTags.end()) {
225 HILOG_ERROR(LOG_CORE, "CheckTags: %{public}s is not provided.", tag.c_str());
226 return false;
227 }
228 }
229 return true;
230 }
231
CheckTagGroup(const std::vector<std::string> & tagGroups,const std::map<std::string,std::vector<std::string>> & tagGroupTable)232 bool CheckTagGroup(const std::vector<std::string> &tagGroups,
233 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
234 {
235 for (auto groupName : tagGroups) {
236 if (tagGroupTable.find(groupName) == tagGroupTable.end()) {
237 HILOG_ERROR(LOG_CORE, "CheckTagGroup: %{public}s is not provided.", groupName.c_str());
238 return false;
239 }
240 }
241 return true;
242 }
243
WriteStrToFileInner(const std::string & filename,const std::string & str)244 bool WriteStrToFileInner(const std::string& filename, const std::string& str)
245 {
246 std::ofstream out;
247 out.open(filename, std::ios::out);
248 if (out.fail()) {
249 HILOG_ERROR(LOG_CORE, "WriteStrToFile: %{public}s open failed.", filename.c_str());
250 return false;
251 }
252 out << str;
253 if (out.bad()) {
254 HILOG_ERROR(LOG_CORE, "WriteStrToFile: %{public}s write failed.", filename.c_str());
255 out.close();
256 return false;
257 }
258 out.flush();
259 out.close();
260 return true;
261 }
262
WriteStrToFile(const std::string & filename,const std::string & str)263 bool WriteStrToFile(const std::string& filename, const std::string& str)
264 {
265 if (access((g_traceRootPath + filename).c_str(), W_OK) < 0) {
266 HILOG_ERROR(LOG_CORE, "WriteStrToFile: Failed to access %{public}s, errno(%{public}d).",
267 (g_traceRootPath + filename).c_str(), errno);
268 return false;
269 }
270 return WriteStrToFileInner(g_traceRootPath + filename, str);
271 }
272
SetTraceNodeStatus(const std::string & path,bool enabled)273 void SetTraceNodeStatus(const std::string &path, bool enabled)
274 {
275 WriteStrToFile(path, enabled ? "1" : "0");
276 }
277
TruncateFile()278 void TruncateFile()
279 {
280 int fd = creat((g_traceRootPath + "trace").c_str(), 0);
281 if (fd == -1) {
282 HILOG_ERROR(LOG_CORE, "TruncateFile: clear old trace failed.");
283 return;
284 }
285 close(fd);
286 return;
287 }
288
SetProperty(const std::string & property,const std::string & value)289 bool SetProperty(const std::string& property, const std::string& value)
290 {
291 bool result = OHOS::system::SetParameter(property, value);
292 if (!result) {
293 HILOG_ERROR(LOG_CORE, "SetProperty: set %{public}s failed.", value.c_str());
294 } else {
295 HILOG_INFO(LOG_CORE, "SetProperty: set %{public}s success.", value.c_str());
296 }
297 return result;
298 }
299
300 // close all trace node
TraceInit(const std::map<std::string,TagCategory> & allTags)301 void TraceInit(const std::map<std::string, TagCategory> &allTags)
302 {
303 // close all ftrace events
304 for (auto it = allTags.begin(); it != allTags.end(); it++) {
305 if (it->second.type != 1) {
306 continue;
307 }
308 for (size_t i = 0; i < it->second.sysFiles.size(); i++) {
309 SetTraceNodeStatus(it->second.sysFiles[i], false);
310 }
311 }
312 // close all user tags
313 SetProperty("debug.hitrace.tags.enableflags", std::to_string(0));
314
315 // set buffer_size_kb 1
316 WriteStrToFile("buffer_size_kb", "1");
317
318 // close tracing_on
319 SetTraceNodeStatus("tracing_on", false);
320 }
321
322 // Open specific trace node
SetAllTags(const TraceParams & traceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)323 void SetAllTags(const TraceParams &traceParams, const std::map<std::string, TagCategory> &allTags,
324 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
325 {
326 std::set<std::string> readyEnableTagList;
327 for (std::string tagName : traceParams.tags) {
328 readyEnableTagList.insert(tagName);
329 }
330
331 // if set tagGroup, need to append default group
332 if (traceParams.tagGroups.size() > 0) {
333 auto iter = tagGroupTable.find("default");
334 if (iter == tagGroupTable.end()) {
335 HILOG_ERROR(LOG_CORE, "SetAllTags: default group is wrong.");
336 } else {
337 for (auto defaultTag : iter->second) {
338 readyEnableTagList.insert(defaultTag);
339 }
340 }
341 }
342
343 for (std::string groupName : traceParams.tagGroups) {
344 auto iter = tagGroupTable.find(groupName);
345 if (iter == tagGroupTable.end()) {
346 continue;
347 }
348 for (std::string tag : iter->second) {
349 readyEnableTagList.insert(tag);
350 }
351 }
352
353 uint64_t enabledUserTags = 0;
354 for (std::string tagName : readyEnableTagList) {
355 auto iter = allTags.find(tagName);
356 if (iter == allTags.end()) {
357 HILOG_ERROR(LOG_CORE, "tag<%{public}s> is invalid.", tagName.c_str());
358 continue;
359 }
360
361 if (iter->second.type == 0) {
362 enabledUserTags |= iter->second.tag;
363 }
364
365 if (iter->second.type == 1) {
366 for (const auto& path : iter->second.sysFiles) {
367 SetTraceNodeStatus(path, true);
368 }
369 }
370 }
371 SetProperty("debug.hitrace.tags.enableflags", std::to_string(enabledUserTags));
372 }
373
ReadFileInner(const std::string & filename)374 std::string ReadFileInner(const std::string& filename)
375 {
376 std::string resolvedPath = CanonicalizeSpecPath(filename.c_str());
377 std::ifstream fileIn(resolvedPath.c_str());
378 if (!fileIn.is_open()) {
379 HILOG_ERROR(LOG_CORE, "ReadFile: %{public}s open failed.", filename.c_str());
380 return "";
381 }
382
383 std::string str((std::istreambuf_iterator<char>(fileIn)), std::istreambuf_iterator<char>());
384 fileIn.close();
385 return str;
386 }
387
ReadFile(const std::string & filename)388 std::string ReadFile(const std::string& filename)
389 {
390 std::string filePath = GetFilePath(filename);
391 return ReadFileInner(filePath);
392 }
393
SetClock(const std::string & clockType)394 void SetClock(const std::string& clockType)
395 {
396 const std::string traceClockPath = "trace_clock";
397 if (clockType.size() == 0) {
398 WriteStrToFile(traceClockPath, "boot"); //set default: boot
399 return;
400 }
401 std::string allClocks = ReadFile(traceClockPath);
402 if (allClocks.find(clockType) == std::string::npos) {
403 HILOG_ERROR(LOG_CORE, "SetClock: %{public}s is non-existent, set to boot", clockType.c_str());
404 WriteStrToFile(traceClockPath, "boot"); // set default: boot
405 return;
406 }
407
408 allClocks.erase(allClocks.find_last_not_of(" \n") + 1);
409 allClocks.push_back(' ');
410
411 std::set<std::string> allClockTypes;
412 size_t curPos = 0;
413 for (size_t i = 0; i < allClocks.size(); i++) {
414 if (allClocks[i] == ' ') {
415 allClockTypes.insert(allClocks.substr(curPos, i - curPos));
416 curPos = i + 1;
417 }
418 }
419
420 std::string currentClockType;
421 for (auto i : allClockTypes) {
422 if (clockType.compare(i) == 0) {
423 HILOG_INFO(LOG_CORE, "SetClock: set clock %{public}s success.", clockType.c_str());
424 WriteStrToFile(traceClockPath, clockType);
425 return;
426 }
427 if (i[0] == '[') {
428 currentClockType = i;
429 }
430 }
431
432 const int marks = 2;
433 if (clockType.compare(currentClockType.substr(1, currentClockType.size() - marks)) == 0) {
434 HILOG_INFO(LOG_CORE, "SetClock: set clock %{public}s success.", clockType.c_str());
435 return;
436 }
437
438 HILOG_INFO(LOG_CORE, "SetClock: unknown %{public}s, change to default clock_type: boot.", clockType.c_str());
439 WriteStrToFile(traceClockPath, "boot"); // set default: boot
440 return;
441 }
442
SetTraceSetting(const TraceParams & traceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)443 bool SetTraceSetting(const TraceParams &traceParams, const std::map<std::string, TagCategory> &allTags,
444 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
445 {
446 TraceInit(allTags);
447
448 TruncateFile();
449
450 SetAllTags(traceParams, allTags, tagGroupTable);
451
452 WriteStrToFile("current_tracer", "nop");
453 WriteStrToFile("buffer_size_kb", traceParams.bufferSize);
454
455 SetClock(traceParams.clockType);
456
457 if (traceParams.isOverWrite == "1") {
458 WriteStrToFile("options/overwrite", "1");
459 } else {
460 WriteStrToFile("options/overwrite", "0");
461 }
462
463 WriteStrToFile("saved_cmdlines_size", std::to_string(SAVED_CMDLINES_SIZE));
464 WriteStrToFile("options/record-tgid", "1");
465 WriteStrToFile("options/record-cmd", "1");
466 return true;
467 }
468
CheckPage(uint8_t contentType,uint8_t * page)469 bool CheckPage(uint8_t contentType, uint8_t *page)
470 {
471 const int pageThreshold = PAGE_SIZE / 2;
472
473 // Check raw_trace page size.
474 if (contentType >= CONTENT_TYPE_CPU_RAW && !IsHmKernel()) {
475 PageHeader *pageHeader = reinterpret_cast<PageHeader*>(&page);
476 if (pageHeader->size < static_cast<uint64_t>(pageThreshold)) {
477 return false;
478 }
479 }
480
481 return true;
482 }
483
GenerateName(bool isSnapshot=true)484 std::string GenerateName(bool isSnapshot = true)
485 {
486 // eg: /data/log/hitrace/trace_localtime@boottime.sys
487 std::string name = DEFAULT_OUTPUT_DIR;
488
489 if (isSnapshot) {
490 name += SNAPSHOT_PREFIX;
491 } else {
492 name += RECORDING_PREFIX;
493 }
494
495 // get localtime
496 time_t currentTime;
497 time(¤tTime);
498 struct tm timeInfo = {};
499 const int bufferSize = 16;
500 char timeStr[bufferSize] = {0};
501 if (localtime_r(¤tTime, &timeInfo) == nullptr) {
502 HILOG_ERROR(LOG_CORE, "Get localtime failed.");
503 return "";
504 }
505 strftime(timeStr, bufferSize, "%Y%m%d%H%M%S", &timeInfo);
506 name += std::string(timeStr);
507 // get boottime
508 struct timespec bts = {0, 0};
509 clock_gettime(CLOCK_BOOTTIME, &bts);
510 name += "@" + std::to_string(bts.tv_sec) + "-" + std::to_string(bts.tv_nsec) + ".sys";
511
512 struct timespec mts = {0, 0};
513 clock_gettime(CLOCK_MONOTONIC, &mts);
514 HILOG_INFO(LOG_CORE, "output trace: %{public}s, boot_time(%{public}" PRId64 "), mono_time(%{public}" PRId64 ").",
515 name.c_str(), static_cast<int64_t>(bts.tv_sec), static_cast<int64_t>(mts.tv_sec));
516 return name;
517 }
518
CheckFileExist(const std::string & outputFile)519 bool CheckFileExist(const std::string &outputFile)
520 {
521 g_writeFileLimit++;
522 if (g_writeFileLimit > JUDGE_FILE_EXIST) {
523 g_writeFileLimit = 0;
524 if (access(outputFile.c_str(), F_OK) != 0) {
525 g_needGenerateNewTraceFile = true;
526 HILOG_INFO(LOG_CORE, "CheckFileExist access file:%{public}s failed, errno: %{public}d.",
527 outputFile.c_str(), errno);
528 return false;
529 }
530 }
531 return true;
532 }
533
IsWriteFileOverflow(const int & outputFileSize,const ssize_t & writeLen,const int & fileSizeThreshold)534 bool IsWriteFileOverflow(const int &outputFileSize, const ssize_t &writeLen, const int &fileSizeThreshold)
535 {
536 // attention: we only check file size threshold in CMD_MODE
537 if (g_traceMode != TraceMode::CMD_MODE) {
538 return false;
539 }
540 if (outputFileSize + writeLen + static_cast<int>(sizeof(TraceFileContentHeader)) >= fileSizeThreshold) {
541 HILOG_ERROR(LOG_CORE, "Failed to write, current round write file size exceeds the file size limit.");
542 return true;
543 }
544 if (writeLen > INT_MAX - BUFFER_SIZE) {
545 HILOG_ERROR(LOG_CORE, "Failed to write, write file length is nearly overflow.");
546 return true;
547 }
548 return false;
549 }
550
WriteFile(uint8_t contentType,const std::string & src,int outFd,const std::string & outputFile)551 bool WriteFile(uint8_t contentType, const std::string &src, int outFd, const std::string &outputFile)
552 {
553 std::string srcPath = CanonicalizeSpecPath(src.c_str());
554 int srcFd = open(srcPath.c_str(), O_RDONLY | O_NONBLOCK);
555 if (srcFd < 0) {
556 HILOG_ERROR(LOG_CORE, "WriteFile: open %{public}s failed.", src.c_str());
557 return false;
558 }
559 if (!CheckFileExist(outputFile)) {
560 HILOG_ERROR(LOG_CORE, "need generate new trace file, old file:%{public}s.", outputFile.c_str());
561 return false;
562 }
563 struct TraceFileContentHeader contentHeader;
564 contentHeader.type = contentType;
565 write(outFd, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
566 ssize_t writeLen = 0;
567 int count = 0;
568 const int maxCount = 2;
569 struct timespec bts = {0, 0};
570 int64_t traceStartTime = 0;
571
572 if ((contentType == CONTENT_TYPE_CPU_RAW) && (g_timeLimit > 0)) {
573 clock_gettime(CLOCK_BOOTTIME, &bts);
574 traceStartTime = bts.tv_sec * S_TO_NS + bts.tv_nsec - g_timeLimit * S_TO_NS;
575 }
576 int fileSizeThreshold = DEFAULT_FILE_SIZE * KB_PER_MB;
577 if (!g_currentTraceParams.fileSize.empty()) {
578 fileSizeThreshold = std::stoi(g_currentTraceParams.fileSize) * KB_PER_MB;
579 }
580
581 while (true) {
582 int bytes = 0;
583 bool endFlag = false;
584 /* Write 1M at a time */
585 while (bytes < BUFFER_SIZE) {
586 ssize_t readBytes = TEMP_FAILURE_RETRY(read(srcFd, g_buffer + bytes, PAGE_SIZE));
587 if (readBytes == 0) {
588 endFlag = true;
589 HILOG_DEBUG(LOG_CORE, "WriteFile: read %{public}s end.", src.c_str());
590 break;
591 }
592
593 if (readBytes < 0) {
594 endFlag = true;
595 HILOG_ERROR(LOG_CORE, "WriteFile: read %{public}s, data size: %{public}zd failed, errno: %{public}d.",
596 src.c_str(), readBytes, errno);
597 break;
598 }
599
600 if (traceStartTime > 0) {
601 uint64_t traceTime = *(reinterpret_cast<uint64_t *>(g_buffer));
602 if (traceTime < static_cast<uint64_t>(traceStartTime)) {
603 continue;
604 }
605 }
606 if (CheckPage(contentType, g_buffer + bytes) == false) {
607 count++;
608 }
609 bytes += readBytes;
610 if (count >= maxCount) {
611 endFlag = true;
612 break;
613 }
614 }
615
616 ssize_t writeRet = TEMP_FAILURE_RETRY(write(outFd, g_buffer, bytes));
617 if (writeRet < 0) {
618 HILOG_WARN(LOG_CORE, "WriteFile Fail, errno: %{public}d.", errno);
619 } else {
620 if (writeRet != static_cast<ssize_t>(bytes)) {
621 HILOG_WARN(LOG_CORE, "Failed to write full info, writeLen: %{public}zd, FullLen: %{public}d.",
622 writeRet, bytes);
623 }
624 writeLen += writeRet;
625 }
626
627 if (contentType == CONTENT_TYPE_CPU_RAW && IsWriteFileOverflow(g_outputFileSize, writeLen, fileSizeThreshold)) {
628 break;
629 }
630
631 if (endFlag == true) {
632 break;
633 }
634 }
635 contentHeader.length = static_cast<uint32_t>(writeLen);
636 uint32_t offset = contentHeader.length + sizeof(contentHeader);
637 off_t pos = lseek(outFd, 0, SEEK_CUR);
638 lseek(outFd, pos - offset, SEEK_SET);
639 write(outFd, reinterpret_cast<char *>(&contentHeader), sizeof(contentHeader));
640 lseek(outFd, pos, SEEK_SET);
641 close(srcFd);
642 g_outputFileSize += static_cast<int>(offset);
643 g_needGenerateNewTraceFile = false;
644 HILOG_INFO(LOG_CORE, "WriteFile end, path: %{public}s, byte: %{public}zd. g_writeFileLimit: %{public}d",
645 src.c_str(), writeLen, g_writeFileLimit);
646 return true;
647 }
648
WriteEventFile(std::string & srcPath,int outFd)649 void WriteEventFile(std::string &srcPath, int outFd)
650 {
651 uint8_t buffer[PAGE_SIZE] = {0};
652 std::string srcSpecPath = CanonicalizeSpecPath(srcPath.c_str());
653 int srcFd = open(srcSpecPath.c_str(), O_RDONLY);
654 if (srcFd < 0) {
655 HILOG_ERROR(LOG_CORE, "WriteEventFile: open %{public}s failed.", srcPath.c_str());
656 return;
657 }
658 ssize_t readLen = 0;
659 do {
660 ssize_t len = read(srcFd, buffer, PAGE_SIZE);
661 if (len <= 0) {
662 break;
663 }
664 write(outFd, buffer, len);
665 readLen += len;
666 } while (true);
667 close(srcFd);
668 HILOG_INFO(LOG_CORE, "WriteEventFile end, path: %{public}s, data size: %{public}zd.", srcPath.c_str(), readLen);
669 }
670
WriteEventsFormat(int outFd,const std::string & outputFile)671 bool WriteEventsFormat(int outFd, const std::string &outputFile)
672 {
673 const std::string savedEventsFormatPath = DEFAULT_OUTPUT_DIR + SAVED_EVENTS_FORMAT;
674 if (access(savedEventsFormatPath.c_str(), F_OK) != -1) {
675 return WriteFile(CONTENT_TYPE_EVENTS_FORMAT, savedEventsFormatPath, outFd, outputFile);
676 }
677 std::string filePath = CanonicalizeSpecPath(savedEventsFormatPath.c_str());
678 int fd = open(filePath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
679 if (fd < 0) {
680 HILOG_ERROR(LOG_CORE, "WriteEventsFormat: open %{public}s failed.", savedEventsFormatPath.c_str());
681 return false;
682 }
683 const std::vector<std::string> priorityTracingCategory = {
684 "events/sched/sched_wakeup/format",
685 "events/sched/sched_switch/format",
686 "events/sched/sched_blocked_reason/format",
687 "events/power/cpu_frequency/format",
688 "events/power/clock_set_rate/format",
689 "events/power/cpu_frequency_limits/format",
690 "events/f2fs/f2fs_sync_file_enter/format",
691 "events/f2fs/f2fs_sync_file_exit/format",
692 "events/f2fs/f2fs_readpage/format",
693 "events/f2fs/f2fs_readpages/format",
694 "events/f2fs/f2fs_sync_fs/format",
695 "events/hmdfs/hmdfs_syncfs_enter/format",
696 "events/hmdfs/hmdfs_syncfs_exit/format",
697 "events/erofs/erofs_readpage/format",
698 "events/erofs/erofs_readpages/format",
699 "events/ext4/ext4_da_write_begin/format",
700 "events/ext4/ext4_da_write_end/format",
701 "events/ext4/ext4_sync_file_enter/format",
702 "events/ext4/ext4_sync_file_exit/format",
703 "events/block/block_bio_remap/format",
704 "events/block/block_rq_issue/format",
705 "events/block/block_rq_complete/format",
706 "events/block/block_rq_insert/format",
707 "events/dma_fence/dma_fence_emit/format",
708 "events/dma_fence/dma_fence_destroy/format",
709 "events/dma_fence/dma_fence_enable_signal/format",
710 "events/dma_fence/dma_fence_signaled/format",
711 "events/dma_fence/dma_fence_wait_end/format",
712 "events/dma_fence/dma_fence_wait_start/format",
713 "events/dma_fence/dma_fence_init/format",
714 "events/binder/binder_transaction/format",
715 "events/binder/binder_transaction_received/format",
716 "events/mmc/mmc_request_start/format",
717 "events/mmc/mmc_request_done/format",
718 "events/memory_bus/format",
719 "events/cpufreq_interactive/format",
720 "events/filemap/file_check_and_advance_wb_err/format",
721 "events/filemap/filemap_set_wb_err/format",
722 "events/filemap/mm_filemap_add_to_page_cache/format",
723 "events/filemap/mm_filemap_delete_from_page_cache/format",
724 "events/workqueue/workqueue_execute_end/format",
725 "events/workqueue/workqueue_execute_start/format",
726 "events/thermal_power_allocator/thermal_power_allocator/format",
727 "events/thermal_power_allocator/thermal_power_allocator_pid/format",
728 "events/ftrace/print/format",
729 "events/tracing_mark_write/tracing_mark_write/format",
730 "events/power/cpu_idle/format",
731 "events/power_kernel/cpu_idle/format",
732 "events/xacct/tracing_mark_write/format",
733 "events/ufs/ufshcd_command/format",
734 "events/irq/irq_handler_entry/format"
735 };
736 for (size_t i = 0; i < priorityTracingCategory.size(); i++) {
737 std::string srcPath = g_traceRootPath + priorityTracingCategory[i];
738 if (access(srcPath.c_str(), R_OK) != -1) {
739 WriteEventFile(srcPath, fd);
740 }
741 }
742 close(fd);
743 HILOG_INFO(LOG_CORE, "WriteEventsFormat end. path: %{public}s.", filePath.c_str());
744 return WriteFile(CONTENT_TYPE_EVENTS_FORMAT, filePath, outFd, outputFile);
745 }
746
WriteHeaderPage(int outFd,const std::string & outputFile)747 bool WriteHeaderPage(int outFd, const std::string &outputFile)
748 {
749 if (IsHmKernel()) {
750 return true;
751 }
752 std::string headerPagePath = GetFilePath("events/header_page");
753 return WriteFile(CONTENT_TYPE_HEADER_PAGE, headerPagePath, outFd, outputFile);
754 }
755
WritePrintkFormats(int outFd,const std::string & outputFile)756 bool WritePrintkFormats(int outFd, const std::string &outputFile)
757 {
758 if (IsHmKernel()) {
759 return true;
760 }
761 std::string printkFormatPath = GetFilePath("printk_formats");
762 return WriteFile(CONTENT_TYPE_PRINTK_FORMATS, printkFormatPath, outFd, outputFile);
763 }
764
WriteKallsyms(int outFd)765 bool WriteKallsyms(int outFd)
766 {
767 /* not implement in hmkernel */
768 if (IsHmKernel()) {
769 return true;
770 }
771 /* not implement in linux */
772 return true;
773 }
774
HmWriteCpuRawInner(int outFd,const std::string & outputFile)775 bool HmWriteCpuRawInner(int outFd, const std::string &outputFile)
776 {
777 uint8_t type = CONTENT_TYPE_CPU_RAW;
778 std::string src = g_traceRootPath + "/trace_pipe_raw";
779
780 return WriteFile(type, src, outFd, outputFile);
781 }
782
WriteCpuRawInner(int outFd,const std::string & outputFile)783 bool WriteCpuRawInner(int outFd, const std::string &outputFile)
784 {
785 int cpuNums = GetCpuProcessors();
786 int ret = true;
787 uint8_t type = CONTENT_TYPE_CPU_RAW;
788 for (int i = 0; i < cpuNums; i++) {
789 std::string src = g_traceRootPath + "per_cpu/cpu" + std::to_string(i) + "/trace_pipe_raw";
790 if (!WriteFile(static_cast<uint8_t>(type + i), src, outFd, outputFile)) {
791 ret = false;
792 break;
793 }
794 }
795 return ret;
796 }
797
WriteCpuRaw(int outFd,const std::string & outputFile)798 bool WriteCpuRaw(int outFd, const std::string &outputFile)
799 {
800 if (!IsHmKernel()) {
801 return WriteCpuRawInner(outFd, outputFile);
802 } else {
803 return HmWriteCpuRawInner(outFd, outputFile);
804 }
805 }
806
WriteCmdlines(int outFd,const std::string & outputFile)807 bool WriteCmdlines(int outFd, const std::string &outputFile)
808 {
809 std::string cmdlinesPath = GetFilePath("saved_cmdlines");
810 return WriteFile(CONTENT_TYPE_CMDLINES, cmdlinesPath, outFd, outputFile);
811 }
812
WriteTgids(int outFd,const std::string & outputFile)813 bool WriteTgids(int outFd, const std::string &outputFile)
814 {
815 std::string tgidsPath = GetFilePath("saved_tgids");
816 return WriteFile(CONTENT_TYPE_TGIDS, tgidsPath, outFd, outputFile);
817 }
818
GenerateNewFile(int & outFd,std::string & outPath)819 bool GenerateNewFile(int &outFd, std::string &outPath)
820 {
821 if (access(outPath.c_str(), F_OK) == 0) {
822 return true;
823 }
824 std::string outputFileName = GenerateName(false);
825 outPath = CanonicalizeSpecPath(outputFileName.c_str());
826 outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
827 if (outFd < 0) {
828 g_newTraceFileLimit++;
829 HILOG_ERROR(LOG_CORE, "open %{public}s failed, errno: %{public}d.", outPath.c_str(), errno);
830 }
831 if (g_newTraceFileLimit > MAX_NEW_TRACE_FILE_LIMIT) {
832 HILOG_ERROR(LOG_CORE, "create new trace file %{public}s limited.", outPath.c_str());
833 return false;
834 }
835 g_needGenerateNewTraceFile = true;
836 return true;
837 }
838
DumpTraceLoop(const std::string & outputFileName,bool isLimited)839 bool DumpTraceLoop(const std::string &outputFileName, bool isLimited)
840 {
841 const int sleepTime = 1;
842 int fileSizeThreshold = DEFAULT_FILE_SIZE * KB_PER_MB;
843 if (!g_currentTraceParams.fileSize.empty()) {
844 fileSizeThreshold = std::stoi(g_currentTraceParams.fileSize) * KB_PER_MB;
845 }
846 g_outputFileSize = 0;
847 std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
848 int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
849 if (outFd < 0) {
850 HILOG_ERROR(LOG_CORE, "open %{public}s failed, errno: %{public}d.", outPath.c_str(), errno);
851 return false;
852 }
853 MarkClockSync(g_traceRootPath);
854 struct TraceFileHeader header;
855 GetArchWordSize(header);
856 GetCpuNums(header);
857 if (IsHmKernel()) {
858 header.fileType = HM_FILE_RAW_TRACE;
859 }
860 do {
861 g_needGenerateNewTraceFile = false;
862 write(outFd, reinterpret_cast<char *>(&header), sizeof(header));
863 WriteEventsFormat(outFd, outPath);
864 while (g_dumpFlag) {
865 if (isLimited && g_outputFileSize > fileSizeThreshold) {
866 break;
867 }
868 sleep(sleepTime);
869 if (!WriteCpuRaw(outFd, outPath)) {
870 break;
871 }
872 }
873 WriteCmdlines(outFd, outPath);
874 WriteTgids(outFd, outPath);
875 WriteHeaderPage(outFd, outPath);
876 WritePrintkFormats(outFd, outPath);
877 WriteKallsyms(outFd);
878 if (!GenerateNewFile(outFd, outPath)) {
879 HILOG_INFO(LOG_CORE, "DumpTraceLoop access file:%{public}s failed, errno: %{public}d.",
880 outPath.c_str(), errno);
881 return false;
882 }
883 } while (g_needGenerateNewTraceFile);
884 close(outFd);
885 return true;
886 }
887
888 /**
889 * When the raw trace is started, clear the saved_events_format files in the folder.
890 */
ClearSavedEventsFormat()891 void ClearSavedEventsFormat()
892 {
893 const std::string savedEventsFormatPath = DEFAULT_OUTPUT_DIR + SAVED_EVENTS_FORMAT;
894 if (access(savedEventsFormatPath.c_str(), F_OK) != 0) {
895 // saved_events_format not exit
896 return;
897 }
898 // saved_events_format exit
899 if (remove(savedEventsFormatPath.c_str()) == 0) {
900 HILOG_INFO(LOG_CORE, "Delete saved_events_format success.");
901 } else {
902 HILOG_ERROR(LOG_CORE, "Delete saved_events_format failed.");
903 }
904 }
905
GetFilesInDirectory(std::vector<std::string> & fileNames)906 void GetFilesInDirectory(std::vector<std::string> &fileNames)
907 {
908 for (const auto &entry : std::filesystem::directory_iterator(DEFAULT_OUTPUT_DIR)) {
909 if (entry.is_regular_file() &&
910 entry.path().filename().string().substr(0, RECORDING_PREFIX.size()) == RECORDING_PREFIX) {
911 fileNames.push_back(entry.path().filename().string());
912 }
913 }
914 }
915
916 /**
917 * open trace file aging mechanism
918 */
ClearOldTraceFileInDirectory()919 void ClearOldTraceFileInDirectory()
920 {
921 if (g_currentTraceParams.fileLimit.empty()) {
922 HILOG_INFO(LOG_CORE, "ClearOldTraceFileInDirectory: no activate aging mechanism.");
923 return;
924 }
925 std::vector<std::string> fileNames;
926 GetFilesInDirectory(fileNames);
927 if (fileNames.size() <= 0) {
928 HILOG_INFO(LOG_CORE, "no file need clear");
929 }
930 while (static_cast<int>(fileNames.size()) > std::stoi(g_currentTraceParams.fileLimit)) {
931 if (remove((DEFAULT_OUTPUT_DIR + fileNames[0]).c_str()) == 0) {
932 HILOG_INFO(LOG_CORE, "ClearOldTraceFileInDirectory: delete first: %{public}s success.",
933 fileNames[0].c_str());
934 } else {
935 HILOG_ERROR(LOG_CORE, "ClearOldTraceFileInDirectory: delete first: %{public}s failed, errno: %{public}d.",
936 fileNames[0].c_str(), errno);
937 }
938 fileNames.erase(fileNames.begin());
939 }
940 }
941
ClearOldTraceFile()942 void ClearOldTraceFile()
943 {
944 if (g_currentTraceParams.fileLimit.empty()) {
945 HILOG_INFO(LOG_CORE, "ClearOldTraceFile: no activate aging mechanism.");
946 return;
947 }
948 if (static_cast<int>(g_outputFilesForCmd.size()) > std::stoi(g_currentTraceParams.fileLimit) &&
949 access(g_outputFilesForCmd[0].c_str(), F_OK) == 0) {
950 if (remove(g_outputFilesForCmd[0].c_str()) == 0) {
951 g_outputFilesForCmd.erase(g_outputFilesForCmd.begin());
952 HILOG_INFO(LOG_CORE, "ClearOldTraceFile: delete first success.");
953 } else {
954 HILOG_ERROR(LOG_CORE, "ClearOldTraceFile: delete first failed, errno: %{public}d.", errno);
955 }
956 }
957 }
958
959 /**
960 * read trace data loop
961 * g_dumpFlag: true = open,false = close
962 * g_dumpEnd: true = end,false = not end
963 * if user has own output file, Output all data to the file specified by the user;
964 * if not, Then place all the result files in /data/log/hitrace/ and package them once in 96M.
965 */
ProcessDumpTask()966 void ProcessDumpTask()
967 {
968 g_dumpFlag = true;
969 g_dumpEnd = false;
970 g_outputFilesForCmd = {};
971 const std::string threadName = "TraceDumpTask";
972 prctl(PR_SET_NAME, threadName.c_str());
973 HILOG_INFO(LOG_CORE, "ProcessDumpTask: trace dump thread start.");
974 ClearSavedEventsFormat();
975 ClearOldTraceFileInDirectory();
976 if (g_currentTraceParams.fileSize.empty()) {
977 std::string outputFileName = g_currentTraceParams.outputFile.empty() ?
978 GenerateName(false) : g_currentTraceParams.outputFile;
979 if (DumpTraceLoop(outputFileName, false)) {
980 g_outputFilesForCmd.push_back(outputFileName);
981 }
982 g_dumpEnd = true;
983 return;
984 }
985
986 while (g_dumpFlag) {
987 ClearOldTraceFile();
988 // Generate file name
989 std::string outputFileName = GenerateName(false);
990 if (DumpTraceLoop(outputFileName, true)) {
991 g_outputFilesForCmd.push_back(outputFileName);
992 } else {
993 break;
994 }
995 }
996 HILOG_INFO(LOG_CORE, "ProcessDumpTask: trace dump thread exit.");
997 g_dumpEnd = true;
998 }
999
SearchFromTable(std::vector<std::string> & outputFiles,int nowSec)1000 void SearchFromTable(std::vector<std::string> &outputFiles, int nowSec)
1001 {
1002 const int maxInterval = 30;
1003 const int agingTime = 30 * 60;
1004
1005 for (auto iter = g_traceFilesTable.begin(); iter != g_traceFilesTable.end();) {
1006 if (nowSec - iter->second >= agingTime) {
1007 // delete outdated trace file
1008 if (access(iter->first.c_str(), F_OK) == 0) {
1009 remove(iter->first.c_str());
1010 HILOG_INFO(LOG_CORE, "delete old %{public}s file success.", iter->first.c_str());
1011 }
1012 iter = g_traceFilesTable.erase(iter);
1013 continue;
1014 }
1015
1016 if (nowSec - iter->second <= maxInterval) {
1017 outputFiles.push_back(iter->first);
1018 }
1019 iter++;
1020 }
1021 }
1022
ReadRawTrace(std::string & outputFileName)1023 bool ReadRawTrace(std::string &outputFileName)
1024 {
1025 // read trace data from /per_cpu/cpux/trace_pipe_raw
1026 std::string outPath = CanonicalizeSpecPath(outputFileName.c_str());
1027 int outFd = open(outPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); // 0644:-rw-r--r--
1028 if (outFd < 0) {
1029 return false;
1030 }
1031 struct TraceFileHeader header;
1032 GetArchWordSize(header);
1033 GetCpuNums(header);
1034 if (IsHmKernel()) {
1035 header.fileType = HM_FILE_RAW_TRACE;
1036 }
1037 write(outFd, reinterpret_cast<char*>(&header), sizeof(header));
1038
1039 if (WriteEventsFormat(outFd, outPath) && WriteCpuRaw(outFd, outPath) &&
1040 WriteCmdlines(outFd, outPath) && WriteTgids(outFd, outPath) &&
1041 WriteHeaderPage(outFd, outPath) && WritePrintkFormats(outFd, outPath) &&
1042 WriteKallsyms(outFd)) {
1043 close(outFd);
1044 return true;
1045 }
1046 HILOG_ERROR(LOG_CORE, "ReadRawTrace failed.");
1047 close(outFd);
1048 return false;
1049 }
1050
WaitPidTimeout(pid_t pid,const int timeoutUsec)1051 bool WaitPidTimeout(pid_t pid, const int timeoutUsec)
1052 {
1053 int delayTime = timeoutUsec;
1054 while (delayTime > 0) {
1055 usleep(UNIT_TIME);
1056 delayTime -= UNIT_TIME;
1057 int status = 0;
1058 int ret = waitpid(pid, &status, WNOHANG);
1059 if (ret == pid) {
1060 HILOG_INFO(LOG_CORE, "wait pid(%{public}d) exit success.", pid);
1061 return true;
1062 } else if (ret < 0) {
1063 HILOG_ERROR(LOG_CORE, "wait pid(%{public}d) exit failed, status: %{public}d.", pid, status);
1064 return false;
1065 }
1066 HILOG_DEBUG(LOG_CORE, "grasping trace, pid(%{public}d), ret(%{public}d).", pid, ret);
1067 }
1068 HILOG_ERROR(LOG_CORE, "wait pid(%{public}d) %{public}d us timeout.", pid, timeoutUsec);
1069 return false;
1070 }
1071
SetProcessName(std::string & processName)1072 void SetProcessName(std::string& processName)
1073 {
1074 if (processName.size() <= 0) {
1075 return;
1076 }
1077
1078 const int maxNameLen = 16;
1079 std::string setName;
1080 if (processName.size() > maxNameLen) {
1081 setName = processName.substr(0, maxNameLen);
1082 } else {
1083 setName = processName;
1084 }
1085
1086 prctl(PR_SET_NAME, setName.c_str(), nullptr, nullptr, nullptr);
1087 HILOG_INFO(LOG_CORE, "New process: %{public}s.", setName.c_str());
1088 }
1089
DumpTraceInner(std::vector<std::string> & outputFiles)1090 TraceErrorCode DumpTraceInner(std::vector<std::string> &outputFiles)
1091 {
1092 g_dumpEnd = false;
1093 std::string outputFileName = GenerateName();
1094 std::string reOutPath = CanonicalizeSpecPath(outputFileName.c_str());
1095
1096 /*Child process handles task, Father process wait.*/
1097 pid_t pid = fork();
1098 if (pid < 0) {
1099 HILOG_ERROR(LOG_CORE, "fork error.");
1100 g_dumpEnd = true;
1101 return TraceErrorCode::WRITE_TRACE_INFO_ERROR;
1102 }
1103 bool ret = false;
1104 if (pid == 0) {
1105 std::string processName = "HitraceDump";
1106 SetProcessName(processName);
1107 MarkClockSync(g_traceRootPath);
1108 const int waitTime = 10000; // 10ms
1109 usleep(waitTime);
1110 ReadRawTrace(reOutPath);
1111 HILOG_DEBUG(LOG_CORE, "%{public}s exit.", processName.c_str());
1112 _exit(EXIT_SUCCESS);
1113 } else {
1114 const int timeoutUsec = 10000000; // 10s
1115 bool isTrue = WaitPidTimeout(pid, timeoutUsec);
1116 if (isTrue && access(reOutPath.c_str(), F_OK) == 0) {
1117 HILOG_INFO(LOG_CORE, "Output: %{public}s.", reOutPath.c_str());
1118 ret = true;
1119 } else {
1120 HILOG_ERROR(LOG_CORE, "Output error: %{public}s.", reOutPath.c_str());
1121 }
1122 }
1123
1124 struct timeval now = {0, 0};
1125 gettimeofday(&now, nullptr);
1126 int nowSec = now.tv_sec;
1127 SearchFromTable(outputFiles, nowSec);
1128 if (ret) {
1129 outputFiles.push_back(outputFileName);
1130 g_traceFilesTable.push_back({outputFileName, nowSec});
1131 } else {
1132 HILOG_ERROR(LOG_CORE, "DumpTraceInner: write %{public}s failed.", outputFileName.c_str());
1133 g_dumpEnd = true;
1134 return TraceErrorCode::WRITE_TRACE_INFO_ERROR;
1135 }
1136 g_dumpEnd = true;
1137 return TraceErrorCode::SUCCESS;
1138 }
1139
GetSysParamTags()1140 uint64_t GetSysParamTags()
1141 {
1142 return OHOS::system::GetUintParameter<uint64_t>("debug.hitrace.tags.enableflags", 0);
1143 }
1144
RestartService()1145 void RestartService()
1146 {
1147 CloseTrace();
1148 const std::vector<std::string> tagGroups = {"scene_performance"};
1149 OpenTrace(tagGroups);
1150 }
1151
CheckParam()1152 bool CheckParam()
1153 {
1154 uint64_t currentTags = GetSysParamTags();
1155 if (currentTags == g_sysInitParamTags) {
1156 return true;
1157 }
1158
1159 if (currentTags == 0) {
1160 HILOG_ERROR(LOG_CORE, "tag is 0, restart it.");
1161 RestartService();
1162 return false;
1163 }
1164 HILOG_ERROR(LOG_CORE, "trace is being used, restart later.");
1165 return false;
1166 }
1167
CheckTraceFile()1168 bool CheckTraceFile()
1169 {
1170 const std::string enable = "1";
1171 if (ReadFile("tracing_on").substr(0, enable.size()) == enable) {
1172 return true;
1173 }
1174 HILOG_ERROR(LOG_CORE, "tracing_on is 0, restart it.");
1175 RestartService();
1176 return false;
1177 }
1178
1179 /**
1180 * SERVICE_MODE is running, check param and tracing_on.
1181 */
CheckServiceRunning()1182 bool CheckServiceRunning()
1183 {
1184 if (CheckParam() && CheckTraceFile()) {
1185 return true;
1186 }
1187 return false;
1188 }
1189
MonitorServiceTask()1190 void MonitorServiceTask()
1191 {
1192 g_serviceThreadIsStart = true;
1193 const std::string threadName = "TraceMonitor";
1194 prctl(PR_SET_NAME, threadName.c_str());
1195 HILOG_INFO(LOG_CORE, "MonitorServiceTask: monitor thread start.");
1196 const int intervalTime = 15;
1197 while (true) {
1198 sleep(intervalTime);
1199 if (g_traceMode != TraceMode::SERVICE_MODE) {
1200 break;
1201 }
1202
1203 if (!CheckServiceRunning()) {
1204 continue;
1205 }
1206
1207 const int cpuNums = GetCpuProcessors();
1208 std::vector<int> result;
1209 std::unique_ptr<DynamicBuffer> dynamicBuffer = std::make_unique<DynamicBuffer>(g_traceRootPath, cpuNums);
1210 dynamicBuffer->CalculateBufferSize(result);
1211
1212 if (static_cast<int>(result.size()) != cpuNums) {
1213 HILOG_ERROR(LOG_CORE, "CalculateAllNewBufferSize failed.");
1214 break;
1215 }
1216
1217 for (size_t i = 0; i < result.size(); i++) {
1218 HILOG_DEBUG(LOG_CORE, "cpu%{public}zu set size %{public}d.", i, result[i]);
1219 std::string path = "per_cpu/cpu" + std::to_string(i) + "/buffer_size_kb";
1220 WriteStrToFile(path, std::to_string(result[i]));
1221 }
1222 }
1223 HILOG_INFO(LOG_CORE, "MonitorServiceTask: monitor thread exit.");
1224 g_serviceThreadIsStart = false;
1225 }
1226
HandleTraceOpen(const TraceParams & traceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)1227 TraceErrorCode HandleTraceOpen(const TraceParams &traceParams,
1228 const std::map<std::string, TagCategory> &allTags,
1229 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
1230 {
1231 if (!SetTraceSetting(traceParams, allTags, tagGroupTable)) {
1232 return TraceErrorCode::FILE_ERROR;
1233 }
1234 SetTraceNodeStatus("tracing_on", true);
1235 g_currentTraceParams = traceParams;
1236 return TraceErrorCode::SUCCESS;
1237 }
1238
HandleServiceTraceOpen(const std::vector<std::string> & tagGroups,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)1239 TraceErrorCode HandleServiceTraceOpen(const std::vector<std::string> &tagGroups,
1240 const std::map<std::string, TagCategory> &allTags,
1241 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
1242 {
1243 TraceParams serviceTraceParams;
1244 serviceTraceParams.tagGroups = tagGroups;
1245 serviceTraceParams.bufferSize = std::to_string(DEFAULT_BUFFER_SIZE);
1246 if (IsHmKernel()) {
1247 serviceTraceParams.bufferSize = std::to_string(HM_DEFAULT_BUFFER_SIZE);
1248 }
1249 serviceTraceParams.clockType = "boot";
1250 serviceTraceParams.isOverWrite = "1";
1251 serviceTraceParams.fileSize = std::to_string(DEFAULT_FILE_SIZE);
1252 return HandleTraceOpen(serviceTraceParams, allTags, tagGroupTable);
1253 }
1254
RemoveUnSpace(std::string str,std::string & args)1255 void RemoveUnSpace(std::string str, std::string& args)
1256 {
1257 int maxCircleTimes = 30;
1258 int curTimes = 0;
1259 const size_t symbolAndSpaceLen = 2;
1260 std::string strSpace = str + " ";
1261 while (curTimes < maxCircleTimes) {
1262 curTimes++;
1263 std::string::size_type index = args.find(strSpace);
1264 if (index != std::string::npos) {
1265 args.replace(index, symbolAndSpaceLen, str);
1266 } else {
1267 break;
1268 }
1269 }
1270 }
1271
1272 /**
1273 * args: tags:tag1,tags2... tagGroups:group1,group2... clockType:boot bufferSize:1024 overwrite:1 output:filename
1274 * cmdTraceParams: Save the above parameters
1275 */
ParseArgs(const std::string & args,TraceParams & cmdTraceParams,const std::map<std::string,TagCategory> & allTags,const std::map<std::string,std::vector<std::string>> & tagGroupTable)1276 bool ParseArgs(const std::string &args, TraceParams &cmdTraceParams, const std::map<std::string, TagCategory> &allTags,
1277 const std::map<std::string, std::vector<std::string>> &tagGroupTable)
1278 {
1279 std::string userArgs = args;
1280 std::string str = ":";
1281 RemoveUnSpace(str, userArgs);
1282 str = ",";
1283 RemoveUnSpace(str, userArgs);
1284 std::vector<std::string> argList = Split(userArgs, ' ');
1285 for (std::string item : argList) {
1286 size_t pos = item.find(":");
1287 if (pos == std::string::npos) {
1288 HILOG_ERROR(LOG_CORE, "trace command line without colon appears: %{public}s, continue.", item.c_str());
1289 continue;
1290 }
1291 std::string itemName = item.substr(0, pos);
1292 if (itemName == "tags") {
1293 cmdTraceParams.tags = Split(item.substr(pos + 1), ',');
1294 } else if (itemName == "tagGroups") {
1295 cmdTraceParams.tagGroups = Split(item.substr(pos + 1), ',');
1296 } else if (itemName == "clockType") {
1297 cmdTraceParams.clockType = item.substr(pos + 1);
1298 } else if (itemName == "bufferSize") {
1299 cmdTraceParams.bufferSize = item.substr(pos + 1);
1300 } else if (itemName == "overwrite") {
1301 cmdTraceParams.isOverWrite = item.substr(pos + 1);
1302 } else if (itemName == "output") {
1303 cmdTraceParams.outputFile = item.substr(pos + 1);
1304 } else if (itemName == "fileSize") {
1305 cmdTraceParams.fileSize = item.substr(pos + 1);
1306 } else if (itemName == "fileLimit") {
1307 cmdTraceParams.fileLimit = item.substr(pos + 1);
1308 } else if (itemName == "appPid") {
1309 std::string pidStr = item.substr(pos + 1);
1310 if (!IsNumber(pidStr)) {
1311 HILOG_ERROR(LOG_CORE, "Illegal input, appPid(%{public}s) must be number.", pidStr.c_str());
1312 return false;
1313 }
1314 int appPid = std::stoi(pidStr);
1315 if (appPid <= 0) {
1316 HILOG_ERROR(LOG_CORE, "Illegal input, appPid(%{public}d) must be greater than 0.", appPid);
1317 return false;
1318 }
1319 OHOS::system::SetParameter("debug.hitrace.app_pid", pidStr);
1320 } else {
1321 HILOG_ERROR(LOG_CORE, "Extra trace command line options appear when ParseArgs: %{public}s, return false.",
1322 itemName.c_str());
1323 return false;
1324 }
1325 }
1326 if (CheckTags(cmdTraceParams.tags, allTags) && CheckTagGroup(cmdTraceParams.tagGroups, tagGroupTable)) {
1327 return true;
1328 }
1329 return false;
1330 }
1331
1332 /**
1333 * When the SERVICE_MODE is started, clear the remaining trace files in the folder.
1334 */
ClearRemainingTrace()1335 void ClearRemainingTrace()
1336 {
1337 if (access(DEFAULT_OUTPUT_DIR.c_str(), F_OK) != 0) {
1338 return;
1339 }
1340 DIR* dirPtr = opendir(DEFAULT_OUTPUT_DIR.c_str());
1341 if (dirPtr == nullptr) {
1342 HILOG_ERROR(LOG_CORE, "opendir failed.");
1343 return;
1344 }
1345 struct dirent* ptr = nullptr;
1346 while ((ptr = readdir(dirPtr)) != nullptr) {
1347 if (ptr->d_type == DT_REG) {
1348 std::string name = std::string(ptr->d_name);
1349 if (name.compare(0, SNAPSHOT_PREFIX.size(), SNAPSHOT_PREFIX) != 0 &&
1350 name.compare(0, SAVED_EVENTS_FORMAT.size(), SAVED_EVENTS_FORMAT) != 0) {
1351 continue;
1352 }
1353 std::string subFileName = DEFAULT_OUTPUT_DIR + name;
1354 int dataFile = open(subFileName.c_str(), O_RDONLY | O_NONBLOCK);
1355 if (dataFile == -1) {
1356 HILOG_INFO(LOG_CORE, "open old trace file failed: %{public}s", subFileName.c_str());
1357 continue;
1358 }
1359 if (flock(dataFile, LOCK_EX | LOCK_NB) < 0) {
1360 HILOG_INFO(LOG_CORE, "get old trace file lock failed, skip remove: %{public}s", subFileName.c_str());
1361 continue;
1362 }
1363 if (remove(subFileName.c_str()) == 0) {
1364 HILOG_INFO(LOG_CORE, "Delete old trace file: %{public}s success.", subFileName.c_str());
1365 } else {
1366 HILOG_ERROR(LOG_CORE, "Delete old trace file: %{public}s failed.", subFileName.c_str());
1367 }
1368 flock(dataFile, LOCK_UN);
1369 close(dataFile);
1370 }
1371 }
1372 closedir(dirPtr);
1373 }
1374 } // namespace
1375
1376 #ifdef HITRACE_UNITTEST
SetSysInitParamTags(uint64_t sysInitParamTags)1377 void SetSysInitParamTags(uint64_t sysInitParamTags)
1378 {
1379 g_sysInitParamTags = sysInitParamTags;
1380 }
1381
SetCheckParam()1382 bool SetCheckParam()
1383 {
1384 int ret = CheckParam();
1385 return ret;
1386 }
1387 #endif
1388
GetTraceMode()1389 TraceMode GetTraceMode()
1390 {
1391 return g_traceMode;
1392 }
1393
OpenTrace(const std::vector<std::string> & tagGroups)1394 TraceErrorCode OpenTrace(const std::vector<std::string> &tagGroups)
1395 {
1396 if (g_traceMode != CLOSE) {
1397 HILOG_ERROR(LOG_CORE, "OpenTrace: CALL_ERROR, g_traceMode:%{public}d.", static_cast<int>(g_traceMode));
1398 return CALL_ERROR;
1399 }
1400 std::lock_guard<std::mutex> lock(g_traceMutex);
1401 if (!IsTraceMounted()) {
1402 HILOG_ERROR(LOG_CORE, "OpenTrace: TRACE_NOT_SUPPORTED.");
1403 return TRACE_NOT_SUPPORTED;
1404 }
1405
1406 std::map<std::string, TagCategory> allTags;
1407 std::map<std::string, std::vector<std::string>> tagGroupTable;
1408 if (!ParseTagInfo(allTags, tagGroupTable)) {
1409 HILOG_ERROR(LOG_CORE, "OpenTrace: ParseTagInfo TAG_ERROR.");
1410 return TAG_ERROR;
1411 }
1412
1413 if (tagGroups.size() == 0 || !CheckTagGroup(tagGroups, tagGroupTable)) {
1414 HILOG_ERROR(LOG_CORE, "OpenTrace: TAG_ERROR.");
1415 return TAG_ERROR;
1416 }
1417
1418 TraceErrorCode ret = HandleServiceTraceOpen(tagGroups, allTags, tagGroupTable);
1419 if (ret != SUCCESS) {
1420 HILOG_ERROR(LOG_CORE, "OpenTrace: open fail.");
1421 return ret;
1422 }
1423 g_traceMode = SERVICE_MODE;
1424
1425 ClearRemainingTrace();
1426 if (!IsHmKernel() && !g_serviceThreadIsStart) {
1427 // open SERVICE_MODE monitor thread
1428 auto it = []() {
1429 MonitorServiceTask();
1430 };
1431 std::thread auxiliaryTask(it);
1432 auxiliaryTask.detach();
1433 }
1434 g_sysInitParamTags = GetSysParamTags();
1435 HILOG_INFO(LOG_CORE, "OpenTrace: SERVICE_MODE open success.");
1436 return ret;
1437 }
1438
OpenTrace(const std::string & args)1439 TraceErrorCode OpenTrace(const std::string &args)
1440 {
1441 std::lock_guard<std::mutex> lock(g_traceMutex);
1442 if (g_traceMode != CLOSE) {
1443 HILOG_ERROR(LOG_CORE, "OpenTrace: CALL_ERROR, g_traceMode:%{public}d.", static_cast<int>(g_traceMode));
1444 return CALL_ERROR;
1445 }
1446
1447 if (!IsTraceMounted()) {
1448 HILOG_ERROR(LOG_CORE, "Hitrace OpenTrace: TRACE_NOT_SUPPORTED.");
1449 return TRACE_NOT_SUPPORTED;
1450 }
1451
1452 std::map<std::string, TagCategory> allTags;
1453 std::map<std::string, std::vector<std::string>> tagGroupTable;
1454 if (!ParseTagInfo(allTags, tagGroupTable) || allTags.size() == 0 || tagGroupTable.size() == 0) {
1455 HILOG_ERROR(LOG_CORE, "Hitrace OpenTrace: ParseTagInfo TAG_ERROR.");
1456 return TAG_ERROR;
1457 }
1458 // parse args
1459 TraceParams cmdTraceParams;
1460 if (!ParseArgs(args, cmdTraceParams, allTags, tagGroupTable)) {
1461 HILOG_ERROR(LOG_CORE, "Hitrace OpenTrace: TAG_ERROR.");
1462 return TAG_ERROR;
1463 }
1464
1465 TraceErrorCode ret = HandleTraceOpen(cmdTraceParams, allTags, tagGroupTable);
1466 if (ret != SUCCESS) {
1467 HILOG_ERROR(LOG_CORE, "Hitrace OpenTrace: CMD_MODE open failed.");
1468 return FILE_ERROR;
1469 }
1470 g_traceMode = CMD_MODE;
1471 HILOG_INFO(LOG_CORE, "Hitrace OpenTrace: CMD_MODE open success, args:%{public}s.", args.c_str());
1472 return ret;
1473 }
1474
DumpTrace()1475 TraceRetInfo DumpTrace()
1476 {
1477 TraceRetInfo ret;
1478 HILOG_INFO(LOG_CORE, "DumpTrace start.");
1479 if (g_traceMode != SERVICE_MODE) {
1480 HILOG_ERROR(LOG_CORE, "DumpTrace: CALL_ERROR, g_traceMode:%{public}d.", static_cast<int>(g_traceMode));
1481 ret.errorCode = CALL_ERROR;
1482 return ret;
1483 }
1484
1485 if (!CheckServiceRunning()) {
1486 HILOG_ERROR(LOG_CORE, "DumpTrace: TRACE_IS_OCCUPIED.");
1487 ret.errorCode = TRACE_IS_OCCUPIED;
1488 return ret;
1489 }
1490 std::lock_guard<std::mutex> lock(g_traceMutex);
1491 ret.errorCode = DumpTraceInner(ret.outputFiles);
1492 HILOG_INFO(LOG_CORE, "DumpTrace done.");
1493 return ret;
1494 }
1495
DumpTrace(int timeLimit)1496 TraceRetInfo DumpTrace(int timeLimit)
1497 {
1498 HILOG_INFO(LOG_CORE, "DumpTrace with time limit start, time limit is %{public}d.", timeLimit);
1499 TraceRetInfo ret;
1500 if (timeLimit <= 0) {
1501 HILOG_ERROR(LOG_CORE, "DumpTrace: Illegal input.");
1502 ret.errorCode = CALL_ERROR;
1503 return ret;
1504 }
1505 {
1506 std::lock_guard<std::mutex> lock(g_traceMutex);
1507 g_timeLimit = timeLimit;
1508 }
1509 ret = DumpTrace();
1510 {
1511 std::lock_guard<std::mutex> lock(g_traceMutex);
1512 g_timeLimit = 0;
1513 }
1514 HILOG_INFO(LOG_CORE, "DumpTrace with time limit done.");
1515 return ret;
1516 }
1517
DumpTraceOn()1518 TraceErrorCode DumpTraceOn()
1519 {
1520 std::lock_guard<std::mutex> lock(g_traceMutex);
1521 // check current trace status
1522 if (g_traceMode != CMD_MODE) {
1523 HILOG_ERROR(LOG_CORE, "DumpTraceOn: CALL_ERROR, g_traceMode:%{public}d.", static_cast<int>(g_traceMode));
1524 return CALL_ERROR;
1525 }
1526
1527 if (!g_dumpEnd) {
1528 HILOG_ERROR(LOG_CORE, "DumpTraceOn: CALL_ERROR, record trace is dumping now.");
1529 return CALL_ERROR;
1530 }
1531
1532 // start task thread
1533 auto it = []() {
1534 ProcessDumpTask();
1535 };
1536 std::thread task(it);
1537 task.detach();
1538 HILOG_INFO(LOG_CORE, "Recording trace on.");
1539 return SUCCESS;
1540 }
1541
DumpTraceOff()1542 TraceRetInfo DumpTraceOff()
1543 {
1544 std::lock_guard<std::mutex> lock(g_traceMutex);
1545 TraceRetInfo ret;
1546 // check current trace status
1547 if (g_traceMode != CMD_MODE) {
1548 HILOG_ERROR(LOG_CORE, "DumpTraceOff: The current state is %{public}d, data exception.",
1549 static_cast<int>(g_traceMode));
1550 ret.errorCode = CALL_ERROR;
1551 ret.outputFiles = g_outputFilesForCmd;
1552 return ret;
1553 }
1554
1555 g_dumpFlag = false;
1556 while (!g_dumpEnd) {
1557 usleep(UNIT_TIME);
1558 g_dumpFlag = false;
1559 }
1560 ret.errorCode = SUCCESS;
1561 ret.outputFiles = g_outputFilesForCmd;
1562 HILOG_INFO(LOG_CORE, "Recording trace off.");
1563 return ret;
1564 }
1565
CloseTrace()1566 TraceErrorCode CloseTrace()
1567 {
1568 std::lock_guard<std::mutex> lock(g_traceMutex);
1569 HILOG_INFO(LOG_CORE, "CloseTrace start.");
1570 if (g_traceMode == CLOSE) {
1571 HILOG_INFO(LOG_CORE, "Trace already close.");
1572 return SUCCESS;
1573 }
1574
1575 g_traceMode = CLOSE;
1576 // Waiting for the data drop task to end
1577 g_dumpFlag = false;
1578 while (!g_dumpEnd) {
1579 usleep(UNIT_TIME);
1580 g_dumpFlag = false;
1581 }
1582 OHOS::system::SetParameter("debug.hitrace.app_pid", "-1");
1583 std::map<std::string, TagCategory> allTags;
1584 std::map<std::string, std::vector<std::string>> tagGroupTable;
1585 if (!ParseTagInfo(allTags, tagGroupTable) || allTags.size() == 0 || tagGroupTable.size() == 0) {
1586 HILOG_ERROR(LOG_CORE, "CloseTrace: ParseTagInfo TAG_ERROR.");
1587 return TAG_ERROR;
1588 }
1589 TraceInit(allTags);
1590 TruncateFile();
1591 HILOG_INFO(LOG_CORE, "CloseTrace done.");
1592 return SUCCESS;
1593 }
1594
GetTraceFilesTable()1595 std::vector<std::pair<std::string, int>> GetTraceFilesTable()
1596 {
1597 return g_traceFilesTable;
1598 }
1599
SetTraceFilesTable(const std::vector<std::pair<std::string,int>> & traceFilesTable)1600 void SetTraceFilesTable(const std::vector<std::pair<std::string, int>>& traceFilesTable)
1601 {
1602 g_traceFilesTable = traceFilesTable;
1603 }
1604
1605 } // Hitrace
1606 } // HiviewDFX
1607 } // OHOS
1608