1b0e7dd80Sopenharmony_ci/* 2b0e7dd80Sopenharmony_ci * Copyright (C) 2024 Huawei Device Co., Ltd. 3b0e7dd80Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4b0e7dd80Sopenharmony_ci * you may not use this file except in compliance with the License. 5b0e7dd80Sopenharmony_ci * You may obtain a copy of the License at 6b0e7dd80Sopenharmony_ci * 7b0e7dd80Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8b0e7dd80Sopenharmony_ci * 9b0e7dd80Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10b0e7dd80Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11b0e7dd80Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12b0e7dd80Sopenharmony_ci * See the License for the specific language governing permissions and 13b0e7dd80Sopenharmony_ci * limitations under the License. 14b0e7dd80Sopenharmony_ci */ 15b0e7dd80Sopenharmony_ci 16b0e7dd80Sopenharmony_ci#include "trace_utils.h" 17b0e7dd80Sopenharmony_ci 18b0e7dd80Sopenharmony_ci#include <cinttypes> 19b0e7dd80Sopenharmony_ci#include <ctime> 20b0e7dd80Sopenharmony_ci#include <dirent.h> 21b0e7dd80Sopenharmony_ci#include <fcntl.h> 22b0e7dd80Sopenharmony_ci#include <filesystem> 23b0e7dd80Sopenharmony_ci#include <sys/file.h> 24b0e7dd80Sopenharmony_ci#include <sys/stat.h> 25b0e7dd80Sopenharmony_ci#include <unistd.h> 26b0e7dd80Sopenharmony_ci 27b0e7dd80Sopenharmony_ci#include "hilog/log.h" 28b0e7dd80Sopenharmony_ci 29b0e7dd80Sopenharmony_cinamespace OHOS { 30b0e7dd80Sopenharmony_cinamespace HiviewDFX { 31b0e7dd80Sopenharmony_cinamespace Hitrace { 32b0e7dd80Sopenharmony_cinamespace { 33b0e7dd80Sopenharmony_ciconst std::string TRACE_DEFAULT_DIR = "/data/log/hitrace/"; 34b0e7dd80Sopenharmony_ciconst std::string TRACE_EVENT_FORMT = "saved_events_format"; 35b0e7dd80Sopenharmony_ciconst std::string TRACE_SNAPSHOT_PREFIX = "trace_"; 36b0e7dd80Sopenharmony_ciconst std::string TRACE_RECORDING_PREFIX = "record_trace_"; 37b0e7dd80Sopenharmony_ciconst size_t DEFAULT_TRACE_FILE_LIMIT = 15; 38b0e7dd80Sopenharmony_ci 39b0e7dd80Sopenharmony_cistruct FileWithTime { 40b0e7dd80Sopenharmony_ci std::string filename; 41b0e7dd80Sopenharmony_ci time_t ctime; 42b0e7dd80Sopenharmony_ci}; 43b0e7dd80Sopenharmony_ci 44b0e7dd80Sopenharmony_civoid RemoveFile(const std::string& fileName) 45b0e7dd80Sopenharmony_ci{ 46b0e7dd80Sopenharmony_ci int fd = open(fileName.c_str(), O_RDONLY | O_NONBLOCK); 47b0e7dd80Sopenharmony_ci if (fd == -1) { 48b0e7dd80Sopenharmony_ci HILOG_WARN(LOG_CORE, "RemoveFile :: open file failed: %{public}s", fileName.c_str()); 49b0e7dd80Sopenharmony_ci return; 50b0e7dd80Sopenharmony_ci } 51b0e7dd80Sopenharmony_ci if (flock(fd, LOCK_EX | LOCK_NB) < 0) { 52b0e7dd80Sopenharmony_ci HILOG_WARN(LOG_CORE, "RemoveFile :: get file lock failed, skip remove: %{public}s", fileName.c_str()); 53b0e7dd80Sopenharmony_ci close(fd); 54b0e7dd80Sopenharmony_ci return; 55b0e7dd80Sopenharmony_ci } 56b0e7dd80Sopenharmony_ci if (remove(fileName.c_str()) == 0) { 57b0e7dd80Sopenharmony_ci HILOG_INFO(LOG_CORE, "RemoveFile :: Delete %{public}s success.", fileName.c_str()); 58b0e7dd80Sopenharmony_ci } else { 59b0e7dd80Sopenharmony_ci HILOG_WARN(LOG_CORE, "RemoveFile :: Delete %{public}s failed.", fileName.c_str()); 60b0e7dd80Sopenharmony_ci } 61b0e7dd80Sopenharmony_ci flock(fd, LOCK_UN); 62b0e7dd80Sopenharmony_ci close(fd); 63b0e7dd80Sopenharmony_ci} 64b0e7dd80Sopenharmony_ci 65b0e7dd80Sopenharmony_civoid GetRecordTraceFilesInDir(std::vector<FileWithTime>& fileList) 66b0e7dd80Sopenharmony_ci{ 67b0e7dd80Sopenharmony_ci struct stat fileStat; 68b0e7dd80Sopenharmony_ci for (const auto &entry : std::filesystem::directory_iterator(TRACE_DEFAULT_DIR)) { 69b0e7dd80Sopenharmony_ci if (!entry.is_regular_file()) { 70b0e7dd80Sopenharmony_ci continue; 71b0e7dd80Sopenharmony_ci } 72b0e7dd80Sopenharmony_ci std::string fileName = entry.path().filename().string(); 73b0e7dd80Sopenharmony_ci if (fileName.substr(0, TRACE_RECORDING_PREFIX.size()) == TRACE_RECORDING_PREFIX) { 74b0e7dd80Sopenharmony_ci if (stat((TRACE_DEFAULT_DIR + fileName).c_str(), &fileStat) == 0) { 75b0e7dd80Sopenharmony_ci fileList.push_back({fileName, fileStat.st_ctime}); 76b0e7dd80Sopenharmony_ci } 77b0e7dd80Sopenharmony_ci } 78b0e7dd80Sopenharmony_ci } 79b0e7dd80Sopenharmony_ci std::sort(fileList.begin(), fileList.end(), [](const FileWithTime& a, const FileWithTime& b) { 80b0e7dd80Sopenharmony_ci return a.ctime < b.ctime; 81b0e7dd80Sopenharmony_ci }); 82b0e7dd80Sopenharmony_ci} 83b0e7dd80Sopenharmony_ci} 84b0e7dd80Sopenharmony_ci 85b0e7dd80Sopenharmony_cistd::string GenerateTraceFileName(bool isSnapshot) 86b0e7dd80Sopenharmony_ci{ 87b0e7dd80Sopenharmony_ci // eg: /data/log/hitrace/trace_localtime@boottime.sys 88b0e7dd80Sopenharmony_ci std::string name = TRACE_DEFAULT_DIR; 89b0e7dd80Sopenharmony_ci 90b0e7dd80Sopenharmony_ci if (isSnapshot) { 91b0e7dd80Sopenharmony_ci name += TRACE_SNAPSHOT_PREFIX; 92b0e7dd80Sopenharmony_ci } else { 93b0e7dd80Sopenharmony_ci name += TRACE_RECORDING_PREFIX; 94b0e7dd80Sopenharmony_ci } 95b0e7dd80Sopenharmony_ci 96b0e7dd80Sopenharmony_ci // get localtime 97b0e7dd80Sopenharmony_ci time_t currentTime = time(nullptr); 98b0e7dd80Sopenharmony_ci struct tm timeInfo = {}; 99b0e7dd80Sopenharmony_ci const int bufferSize = 16; 100b0e7dd80Sopenharmony_ci char timeStr[bufferSize] = {0}; 101b0e7dd80Sopenharmony_ci if (localtime_r(¤tTime, &timeInfo) == nullptr) { 102b0e7dd80Sopenharmony_ci HILOG_ERROR(LOG_CORE, "Failed to get localtime."); 103b0e7dd80Sopenharmony_ci return ""; 104b0e7dd80Sopenharmony_ci } 105b0e7dd80Sopenharmony_ci (void)strftime(timeStr, bufferSize, "%Y%m%d%H%M%S", &timeInfo); 106b0e7dd80Sopenharmony_ci name += std::string(timeStr); 107b0e7dd80Sopenharmony_ci // get boottime 108b0e7dd80Sopenharmony_ci struct timespec bts = {0, 0}; 109b0e7dd80Sopenharmony_ci clock_gettime(CLOCK_BOOTTIME, &bts); 110b0e7dd80Sopenharmony_ci name += "@" + std::to_string(bts.tv_sec) + "-" + std::to_string(bts.tv_nsec) + ".sys"; 111b0e7dd80Sopenharmony_ci 112b0e7dd80Sopenharmony_ci struct timespec mts = {0, 0}; 113b0e7dd80Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &mts); 114b0e7dd80Sopenharmony_ci HILOG_INFO(LOG_CORE, "output trace: %{public}s, boot_time(%{public}" PRId64 "), mono_time(%{public}" PRId64 ").", 115b0e7dd80Sopenharmony_ci name.c_str(), static_cast<int64_t>(bts.tv_sec), static_cast<int64_t>(mts.tv_sec)); 116b0e7dd80Sopenharmony_ci return name; 117b0e7dd80Sopenharmony_ci} 118b0e7dd80Sopenharmony_ci 119b0e7dd80Sopenharmony_ci/** 120b0e7dd80Sopenharmony_ci * When the SERVICE_MODE is started, clear the remaining trace files in the folder. 121b0e7dd80Sopenharmony_ci*/ 122b0e7dd80Sopenharmony_civoid DelSnapshotTraceFile(const bool deleteSavedFmt, const int keepFileCount) 123b0e7dd80Sopenharmony_ci{ 124b0e7dd80Sopenharmony_ci if (access(TRACE_DEFAULT_DIR.c_str(), F_OK) != 0) { 125b0e7dd80Sopenharmony_ci return; 126b0e7dd80Sopenharmony_ci } 127b0e7dd80Sopenharmony_ci DIR* dirPtr = opendir(TRACE_DEFAULT_DIR.c_str()); 128b0e7dd80Sopenharmony_ci if (dirPtr == nullptr) { 129b0e7dd80Sopenharmony_ci HILOG_ERROR(LOG_CORE, "Failed to opendir %{public}s.", TRACE_DEFAULT_DIR.c_str()); 130b0e7dd80Sopenharmony_ci return; 131b0e7dd80Sopenharmony_ci } 132b0e7dd80Sopenharmony_ci std::vector<FileWithTime> snapshotTraceFiles; 133b0e7dd80Sopenharmony_ci struct dirent* ptr = nullptr; 134b0e7dd80Sopenharmony_ci struct stat fileStat; 135b0e7dd80Sopenharmony_ci while ((ptr = readdir(dirPtr)) != nullptr) { 136b0e7dd80Sopenharmony_ci if (ptr->d_type == DT_REG) { 137b0e7dd80Sopenharmony_ci std::string name = std::string(ptr->d_name); 138b0e7dd80Sopenharmony_ci if (deleteSavedFmt && name.compare(0, TRACE_EVENT_FORMT.size(), TRACE_EVENT_FORMT) == 0) { 139b0e7dd80Sopenharmony_ci RemoveFile(TRACE_DEFAULT_DIR + name); 140b0e7dd80Sopenharmony_ci continue; 141b0e7dd80Sopenharmony_ci } 142b0e7dd80Sopenharmony_ci if (name.compare(0, TRACE_SNAPSHOT_PREFIX.size(), TRACE_SNAPSHOT_PREFIX) != 0) { 143b0e7dd80Sopenharmony_ci continue; 144b0e7dd80Sopenharmony_ci } 145b0e7dd80Sopenharmony_ci if (stat((TRACE_DEFAULT_DIR + name).c_str(), &fileStat) == 0) { 146b0e7dd80Sopenharmony_ci snapshotTraceFiles.push_back({name, fileStat.st_ctime}); 147b0e7dd80Sopenharmony_ci } 148b0e7dd80Sopenharmony_ci } 149b0e7dd80Sopenharmony_ci } 150b0e7dd80Sopenharmony_ci closedir(dirPtr); 151b0e7dd80Sopenharmony_ci 152b0e7dd80Sopenharmony_ci std::sort(snapshotTraceFiles.begin(), snapshotTraceFiles.end(), [](const FileWithTime& a, const FileWithTime& b) { 153b0e7dd80Sopenharmony_ci return a.ctime < b.ctime; 154b0e7dd80Sopenharmony_ci }); 155b0e7dd80Sopenharmony_ci 156b0e7dd80Sopenharmony_ci int snapshotTraceFilesSize = static_cast<int>(snapshotTraceFiles.size()); 157b0e7dd80Sopenharmony_ci int deleteFileCnt = snapshotTraceFilesSize - keepFileCount; 158b0e7dd80Sopenharmony_ci for (int i = 0; i < deleteFileCnt && i < snapshotTraceFilesSize; i++) { 159b0e7dd80Sopenharmony_ci RemoveFile(TRACE_DEFAULT_DIR + snapshotTraceFiles[i].filename); 160b0e7dd80Sopenharmony_ci } 161b0e7dd80Sopenharmony_ci} 162b0e7dd80Sopenharmony_ci 163b0e7dd80Sopenharmony_ci/** 164b0e7dd80Sopenharmony_ci * open trace file aging mechanism 165b0e7dd80Sopenharmony_ci */ 166b0e7dd80Sopenharmony_civoid DelOldRecordTraceFile(const int& fileLimit) 167b0e7dd80Sopenharmony_ci{ 168b0e7dd80Sopenharmony_ci size_t traceFileLimit = DEFAULT_TRACE_FILE_LIMIT; 169b0e7dd80Sopenharmony_ci if (fileLimit != 0) { 170b0e7dd80Sopenharmony_ci traceFileLimit = static_cast<size_t>(fileLimit); 171b0e7dd80Sopenharmony_ci } 172b0e7dd80Sopenharmony_ci HILOG_INFO(LOG_CORE, "DelOldRecordTraceFile: activate aging mechanism with file limit %{public}zu", traceFileLimit); 173b0e7dd80Sopenharmony_ci 174b0e7dd80Sopenharmony_ci std::vector<FileWithTime> fileList; 175b0e7dd80Sopenharmony_ci GetRecordTraceFilesInDir(fileList); 176b0e7dd80Sopenharmony_ci 177b0e7dd80Sopenharmony_ci if (fileList.size() <= traceFileLimit) { 178b0e7dd80Sopenharmony_ci HILOG_INFO(LOG_CORE, "DelOldRecordTraceFile: no record trace file need be deleted."); 179b0e7dd80Sopenharmony_ci return; 180b0e7dd80Sopenharmony_ci } 181b0e7dd80Sopenharmony_ci 182b0e7dd80Sopenharmony_ci size_t deleteNum = fileList.size() - traceFileLimit; 183b0e7dd80Sopenharmony_ci for (size_t i = 0; i < deleteNum; ++i) { 184b0e7dd80Sopenharmony_ci if (remove((TRACE_DEFAULT_DIR + fileList[i].filename).c_str()) == 0) { 185b0e7dd80Sopenharmony_ci HILOG_INFO(LOG_CORE, "DelOldRecordTraceFile: delete first: %{public}s success.", 186b0e7dd80Sopenharmony_ci fileList[i].filename.c_str()); 187b0e7dd80Sopenharmony_ci } else { 188b0e7dd80Sopenharmony_ci HILOG_ERROR(LOG_CORE, "DelOldRecordTraceFile: delete first: %{public}s failed, errno: %{public}d.", 189b0e7dd80Sopenharmony_ci fileList[i].filename.c_str(), errno); 190b0e7dd80Sopenharmony_ci } 191b0e7dd80Sopenharmony_ci } 192b0e7dd80Sopenharmony_ci} 193b0e7dd80Sopenharmony_ci 194b0e7dd80Sopenharmony_civoid ClearOldTraceFile(std::vector<std::string>& fileLists, const int& fileLimit) 195b0e7dd80Sopenharmony_ci{ 196b0e7dd80Sopenharmony_ci if (fileLists.size() == 0) { 197b0e7dd80Sopenharmony_ci return; 198b0e7dd80Sopenharmony_ci } 199b0e7dd80Sopenharmony_ci 200b0e7dd80Sopenharmony_ci size_t traceFileLimit = DEFAULT_TRACE_FILE_LIMIT; 201b0e7dd80Sopenharmony_ci if (fileLimit != 0) { 202b0e7dd80Sopenharmony_ci traceFileLimit = static_cast<size_t>(fileLimit); 203b0e7dd80Sopenharmony_ci } 204b0e7dd80Sopenharmony_ci HILOG_INFO(LOG_CORE, "ClearOldTraceFile: activate aging mechanism with file limit %{public}zu", traceFileLimit); 205b0e7dd80Sopenharmony_ci 206b0e7dd80Sopenharmony_ci if (fileLists.size() > traceFileLimit && access(fileLists[0].c_str(), F_OK) == 0) { 207b0e7dd80Sopenharmony_ci if (remove(fileLists[0].c_str()) == 0) { 208b0e7dd80Sopenharmony_ci fileLists.erase(fileLists.begin()); 209b0e7dd80Sopenharmony_ci HILOG_INFO(LOG_CORE, "ClearOldTraceFile: delete first success."); 210b0e7dd80Sopenharmony_ci } else { 211b0e7dd80Sopenharmony_ci HILOG_ERROR(LOG_CORE, "ClearOldTraceFile: delete first failed, errno: %{public}d.", errno); 212b0e7dd80Sopenharmony_ci } 213b0e7dd80Sopenharmony_ci } 214b0e7dd80Sopenharmony_ci} 215b0e7dd80Sopenharmony_ci 216b0e7dd80Sopenharmony_ci/** 217b0e7dd80Sopenharmony_ci * When the raw trace is started, clear the saved_events_format files in the folder. 218b0e7dd80Sopenharmony_ci */ 219b0e7dd80Sopenharmony_civoid DelSavedEventsFormat() 220b0e7dd80Sopenharmony_ci{ 221b0e7dd80Sopenharmony_ci const std::string savedEventsFormatPath = TRACE_DEFAULT_DIR + TRACE_EVENT_FORMT; 222b0e7dd80Sopenharmony_ci if (access(savedEventsFormatPath.c_str(), F_OK) != 0) { 223b0e7dd80Sopenharmony_ci // saved_events_format not exit 224b0e7dd80Sopenharmony_ci return; 225b0e7dd80Sopenharmony_ci } 226b0e7dd80Sopenharmony_ci // saved_events_format exit 227b0e7dd80Sopenharmony_ci if (remove(savedEventsFormatPath.c_str()) == 0) { 228b0e7dd80Sopenharmony_ci HILOG_INFO(LOG_CORE, "Delete saved_events_format success."); 229b0e7dd80Sopenharmony_ci } else { 230b0e7dd80Sopenharmony_ci HILOG_ERROR(LOG_CORE, "Delete saved_events_format failed."); 231b0e7dd80Sopenharmony_ci } 232b0e7dd80Sopenharmony_ci} 233b0e7dd80Sopenharmony_ci} // namespace Hitrace 234b0e7dd80Sopenharmony_ci} // namespace HiviewDFX 235b0e7dd80Sopenharmony_ci} // namespace OHOS 236