1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "trace_handler.h"
16
17 #include <deque>
18
19 #include "hiview_logger.h"
20 #include "file_util.h"
21 #include "trace_decorator.h"
22 #include "hiview_event_report.h"
23 #include "hiview_zip_util.h"
24
25 namespace OHOS::HiviewDFX {
26 namespace {
27 DEFINE_LOG_TAG("UCollectUtil-TraceCollector");
WriteTrafficLog(std::chrono::time_point<std::chrono::steady_clock> startTime,const std::string & caller,const std::string & srcFile,const std::string & traceFile)28 void WriteTrafficLog(std::chrono::time_point<std::chrono::steady_clock> startTime, const std::string& caller,
29 const std::string& srcFile, const std::string& traceFile)
30 {
31 auto endTime = std::chrono::steady_clock::now();
32 auto execDuration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
33 UCollectUtil::TraceTrafficInfo traceInfo {
34 caller,
35 traceFile,
36 FileUtil::GetFileSize(srcFile),
37 0,
38 execDuration
39 };
40 UCollectUtil::TraceDecorator::WriteTrafficAfterHandle(traceInfo);
41 }
42
WriteZipTrafficLog(std::chrono::time_point<std::chrono::steady_clock> startTime,const std::string & caller,const std::string & srcFile,const std::string & zipFile)43 void WriteZipTrafficLog(std::chrono::time_point<std::chrono::steady_clock> startTime, const std::string& caller,
44 const std::string& srcFile, const std::string& zipFile)
45 {
46 auto endTime = std::chrono::steady_clock::now();
47 auto execDuration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
48 UCollectUtil::TraceTrafficInfo traceInfo {
49 caller,
50 zipFile,
51 FileUtil::GetFileSize(srcFile),
52 FileUtil::GetFileSize(zipFile),
53 execDuration
54 };
55 UCollectUtil::TraceDecorator::WriteTrafficAfterHandle(traceInfo);
56 }
57 }
58
HandleUcollectionTask(UcollectionTask ucollectionTask)59 void TraceWorker::HandleUcollectionTask(UcollectionTask ucollectionTask)
60 {
61 ffrtQueue_->submit(ucollectionTask, ffrt::task_attr().name("dft_uc_trace"));
62 }
63
DoClean(const std::string & prefix)64 void TraceHandler::DoClean(const std::string &prefix)
65 {
66 // Load all files under the path
67 std::vector<std::string> files;
68 FileUtil::GetDirFiles(tracePath_, files);
69
70 // Filter files that belong to me
71 std::deque<std::string> filteredFiles;
72 for (const auto &file : files) {
73 if (prefix.empty() || file.find(prefix) != std::string::npos) {
74 filteredFiles.emplace_back(file);
75 }
76 }
77 std::sort(filteredFiles.begin(), filteredFiles.end(), [](const auto& a, const auto& b) {
78 return a < b;
79 });
80 HIVIEW_LOGI("myFiles size : %{public}zu, MyThreshold : %{public}u.", filteredFiles.size(), cleanThreshold_);
81
82 while (filteredFiles.size() > cleanThreshold_) {
83 FileUtil::RemoveFile(filteredFiles.front());
84 HIVIEW_LOGI("remove file : %{public}s is deleted.", filteredFiles.front().c_str());
85 filteredFiles.pop_front();
86 }
87 }
88
HandleTrace(const std::vector<std::string> & outputFiles,HandleCallback callback,std::shared_ptr<AppCallerEvent> appCallerEvent)89 auto TraceZipHandler::HandleTrace(const std::vector<std::string>& outputFiles, HandleCallback callback,
90 std::shared_ptr<AppCallerEvent> appCallerEvent) -> std::vector<std::string>
91 {
92 if (!FileUtil::FileExists(tracePath_) && !FileUtil::CreateMultiDirectory(tracePath_)) {
93 HIVIEW_LOGE("failed to create multidirectory.");
94 return {};
95 }
96 std::vector<std::string> files;
97 for (const auto &filename : outputFiles) {
98 auto startTime = std::chrono::steady_clock::now();
99 const std::string traceZipFile = GetTraceFinalPath(filename, "");
100 if (FileUtil::FileExists(traceZipFile)) {
101 HIVIEW_LOGI("trace:%{public}s already zipped, zip pass", traceZipFile.c_str());
102 continue;
103 }
104 const std::string tmpZipFile = GetTraceZipTmpPath(filename);
105 if (!tmpZipFile.empty()) {
106 if (FileUtil::FileExists(tmpZipFile)) {
107 HIVIEW_LOGI("trace:%{public}s already in zip queue, zip pass", traceZipFile.c_str());
108 continue;
109 }
110 // a trace producted, just make a marking
111 FileUtil::SaveStringToFile(tmpZipFile, " ", true);
112 }
113 UcollectionTask traceTask = [filename, traceZipFile, tmpZipFile, startTime, callback,
114 handler = shared_from_this()] {
115 handler->ZipTraceFile(filename, traceZipFile, tmpZipFile);
116 handler->DoClean("");
117 if (callback != nullptr) {
118 callback(static_cast<int64_t>(FileUtil::GetFileSize(traceZipFile)));
119 }
120 WriteZipTrafficLog(startTime, handler->caller_, filename, traceZipFile);
121 };
122 TraceWorker::GetInstance().HandleUcollectionTask(traceTask);
123 files.push_back(traceZipFile);
124 HIVIEW_LOGI("insert zip file : %{public}s.", traceZipFile.c_str());
125 }
126 return files;
127 }
128
GetTraceZipTmpPath(const std::string & fileName)129 std::string TraceZipHandler::GetTraceZipTmpPath(const std::string &fileName)
130 {
131 std::string tempPath = tracePath_ + "temp/";
132 if (!FileUtil::FileExists(tempPath)) {
133 return "";
134 }
135 return tempPath + StringUtil::ReplaceStr(FileUtil::ExtractFileName(fileName), ".sys", ".zip");
136 }
137
AddZipFile(const std::string & srcPath,const std::string & traceZipFile)138 void TraceZipHandler::AddZipFile(const std::string &srcPath, const std::string &traceZipFile)
139 {
140 HiviewZipUnit zipUnit(traceZipFile);
141 if (int32_t ret = zipUnit.AddFileInZip(srcPath, ZipFileLevel::KEEP_NONE_PARENT_PATH); ret != 0) {
142 HIVIEW_LOGW("zip trace failed, ret: %{public}d.", ret);
143 }
144 }
145
ZipTraceFile(const std::string & srcPath,const std::string & traceZipFile,const std::string & tmpZipFile)146 void TraceZipHandler::ZipTraceFile(const std::string &srcPath, const std::string &traceZipFile,
147 const std::string &tmpZipFile)
148 {
149 if (FileUtil::FileExists(traceZipFile)) {
150 HIVIEW_LOGI("trace zip file : %{public}s already exist", traceZipFile.c_str());
151 return;
152 }
153 CheckCurrentCpuLoad();
154 HiviewEventReport::ReportCpuScene("5");
155 if (tmpZipFile.empty()) {
156 AddZipFile(srcPath, traceZipFile);
157 } else {
158 AddZipFile(srcPath, tmpZipFile);
159 FileUtil::RenameFile(tmpZipFile, traceZipFile);
160 }
161 HIVIEW_LOGI("finish rename file %{public}s", traceZipFile.c_str());
162 }
163
CopyTraceFile(const std::string & src,const std::string & dst)164 void TraceCopyHandler::CopyTraceFile(const std::string &src, const std::string &dst)
165 {
166 std::string dstFileName = FileUtil::ExtractFileName(dst);
167 if (FileUtil::FileExists(dst)) {
168 HIVIEW_LOGI("copy already, file : %{public}s.", dstFileName.c_str());
169 return;
170 }
171 HIVIEW_LOGI("copy start, file : %{public}s.", dstFileName.c_str());
172 int ret = FileUtil::CopyFileFast(src, dst);
173 if (ret != 0) {
174 HIVIEW_LOGE("copy failed, file : %{public}s, errno : %{public}d", src.c_str(), errno);
175 } else {
176 HIVIEW_LOGI("copy end, file : %{public}s.", dstFileName.c_str());
177 }
178 }
179
HandleTrace(const std::vector<std::string> & outputFiles,HandleCallback callback,std::shared_ptr<AppCallerEvent> appCallerEvent)180 auto TraceCopyHandler::HandleTrace(const std::vector<std::string>& outputFiles, HandleCallback callback,
181 std::shared_ptr<AppCallerEvent> appCallerEvent) -> std::vector<std::string>
182 {
183 if (!FileUtil::FileExists(tracePath_) && !FileUtil::CreateMultiDirectory(tracePath_)) {
184 HIVIEW_LOGE("create dir %{public}s fail", tracePath_.c_str());
185 return {};
186 }
187 std::vector<std::string> files;
188 for (const auto &trace : outputFiles) {
189 auto startTime = std::chrono::steady_clock::now();
190 std::string dst = GetTraceFinalPath(trace, caller_);
191 files.push_back(dst);
192 if (FileUtil::FileExists(dst)) {
193 continue;
194 }
195
196 // copy trace in ffrt asynchronously
197 UcollectionTask traceTask = [trace, dst, startTime, handler = shared_from_this()]() {
198 handler->CopyTraceFile(trace, dst);
199 handler->DoClean(handler->caller_);
200 WriteTrafficLog(startTime, handler->caller_, trace, dst);
201 };
202 TraceWorker::GetInstance().HandleUcollectionTask(traceTask);
203 }
204 return files;
205 }
206
HandleTrace(const std::vector<std::string> & outputFiles,HandleCallback callback,std::shared_ptr<AppCallerEvent> appCallerEvent)207 auto TraceSyncCopyHandler::HandleTrace(const std::vector<std::string>& outputFiles, HandleCallback callback,
208 std::shared_ptr<AppCallerEvent> appCallerEvent) -> std::vector<std::string>
209 {
210 if (!FileUtil::FileExists(tracePath_) && !FileUtil::CreateMultiDirectory(tracePath_)) {
211 HIVIEW_LOGE("create dir %{public}s fail", tracePath_.c_str());
212 return {};
213 }
214 std::vector<std::string> files;
215
216 // copy trace immediately for betaclub and screen recording
217 for (const auto &trace : outputFiles) {
218 auto startTime = std::chrono::steady_clock::now();
219 std::string dst = GetTraceFinalPath(trace, caller_);
220 files.push_back(dst);
221 CopyTraceFile(trace, dst);
222 DoClean(caller_);
223 WriteTrafficLog(startTime, caller_, trace, dst);
224 }
225 return files;
226 }
227
HandleTrace(const std::vector<std::string> & outputFiles,HandleCallback callback,std::shared_ptr<AppCallerEvent> appCallerEvent)228 auto TraceAppHandler::HandleTrace(const std::vector<std::string> &outputFiles, HandleCallback callback,
229 std::shared_ptr<AppCallerEvent> appCallerEvent) -> std::vector<std::string>
230 {
231 if (appCallerEvent == nullptr || outputFiles.empty()) {
232 return {};
233 }
234 std::string traceFileName = MakeTraceFileName(appCallerEvent);
235 HIVIEW_LOGI("src:%{public}s, dir:%{public}s", outputFiles[0].c_str(), traceFileName.c_str());
236 FileUtil::RenameFile(outputFiles[0], traceFileName);
237 appCallerEvent->externalLog_ = traceFileName;
238 DoClean(caller_);
239 return {traceFileName};
240 }
241
MakeTraceFileName(std::shared_ptr<AppCallerEvent> appCallerEvent)242 std::string TraceAppHandler::MakeTraceFileName(std::shared_ptr<AppCallerEvent> appCallerEvent)
243 {
244 std::string &bundleName = appCallerEvent->bundleName_;
245 int32_t pid = appCallerEvent->pid_;
246 int64_t beginTime = appCallerEvent->taskBeginTime_;
247 int64_t endTime = appCallerEvent->taskEndTime_;
248 int32_t costTime = (appCallerEvent->taskEndTime_ - appCallerEvent->taskBeginTime_);
249
250 std::string d1 = TimeUtil::TimestampFormatToDate(beginTime/ TimeUtil::SEC_TO_MILLISEC, "%Y%m%d%H%M%S");
251 std::string d2 = TimeUtil::TimestampFormatToDate(endTime/ TimeUtil::SEC_TO_MILLISEC, "%Y%m%d%H%M%S");
252
253 std::string name;
254 name.append(tracePath_).append("APP_").append(bundleName).append("_").append(std::to_string(pid));
255 name.append("_").append(d1).append("_").append(d2).append("_").append(std::to_string(costTime)).append(".sys");
256 return name;
257 }
258 }
259