• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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