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 "trace_collector_impl.h"
17
18 #include <memory>
19 #include <mutex>
20 #include <string>
21 #include <fcntl.h>
22 #include <sys/file.h>
23 #include <unistd.h>
24
25 #include "hiview_logger.h"
26 #include "trace_decorator.h"
27 #include "trace_strategy.h"
28 #include "trace_state_machine.h"
29 #include "trace_utils.h"
30 #include "trace_strategy_factory.h"
31 #include "hiview_zip_util.h"
32 #include "hiview_event_report.h"
33
34 using namespace OHOS::HiviewDFX;
35 using namespace OHOS::HiviewDFX::UCollectUtil;
36 using namespace OHOS::HiviewDFX::UCollect;
37
38 namespace OHOS {
39 namespace HiviewDFX {
40 namespace UCollectUtil {
41 namespace {
42 DEFINE_LOG_TAG("UCollectUtil-TraceCollector");
43 constexpr uid_t HIVIEW_UID = 1201;
44 const int64_t MS_TO_US = 1000;
45
ZipShareTempTraceFile(const std::string & srcFile)46 void ZipShareTempTraceFile(const std::string &srcFile)
47 {
48 std::string tempZipFile = UNIFIED_SHARE_PATH + StringUtil::ReplaceStr(FileUtil::ExtractFileName(srcFile),
49 ".sys", ".zip");
50 std::string zipTraceFile = AddVersionInfoToZipName(tempZipFile);
51 if (FileUtil::FileExists(zipTraceFile)) {
52 HIVIEW_LOGI("dst: %{public}s already exist", zipTraceFile.c_str());
53 return;
54 }
55 CheckCurrentCpuLoad();
56 HiviewEventReport::ReportCpuScene("5");
57 HiviewZipUnit zipUnit(zipTraceFile);
58 if (int32_t ret = zipUnit.AddFileInZip(srcFile, ZipFileLevel::KEEP_NONE_PARENT_PATH); ret != 0) {
59 HIVIEW_LOGE("zip trace failed, ret: %{public}d.", ret);
60 return;
61 }
62 HIVIEW_LOGI("ZipTraceFile success: %{public}s", FileUtil::ExtractFileName(zipTraceFile).c_str());
63 }
64 }
Create()65 std::shared_ptr<TraceCollector> TraceCollector::Create()
66 {
67 static std::shared_ptr<TraceCollector> instance_ =
68 std::make_shared<TraceDecorator>(std::make_shared<TraceCollectorImpl>());
69 return instance_;
70 }
71
DumpTraceWithDuration(TraceCaller caller,uint32_t maxDuration,uint64_t happenTime)72 CollectResult<std::vector<std::string>> TraceCollectorImpl::DumpTraceWithDuration(
73 TraceCaller caller, uint32_t maxDuration, uint64_t happenTime)
74 {
75 if (maxDuration > INT32_MAX) {
76 return StartDumpTrace(caller, INT32_MAX, happenTime);
77 }
78 return StartDumpTrace(caller, maxDuration, happenTime);
79 }
80
DumpTraceWithFilter(TeleModule module,uint32_t maxDuration,uint64_t happenTime)81 CollectResult<std::vector<std::string>> TraceCollectorImpl::DumpTraceWithFilter(TeleModule module,
82 uint32_t maxDuration, uint64_t happenTime)
83 {
84 if (auto uid = getuid(); uid != HIVIEW_UID) {
85 HIVIEW_LOGE("Do not allow uid:%{public}d to dump trace except in hiview process", uid);
86 return {UcError::PERMISSION_CHECK_FAILED};
87 }
88 CollectResult<std::vector<std::string>> result;
89 auto strategy = TraceStrategyFactory::CreateStrategy(module, maxDuration, happenTime);
90 TraceRetInfo traceRetInfo;
91 TraceRet ret = strategy->DoDump(result.data, traceRetInfo);
92 result.retCode = GetUcError(ret);
93 HIVIEW_LOGI("caller:%{public}s retCode = %{public}d, file number = %{public}zu.", ModuleToString(module).c_str(),
94 result.retCode, result.data.size());
95 return result;
96 }
97
FilterTraceOn(TeleModule module,uint64_t postTime)98 CollectResult<int32_t> TraceCollectorImpl::FilterTraceOn(TeleModule module, uint64_t postTime)
99 {
100 if (auto uid = getuid(); uid != HIVIEW_UID) {
101 HIVIEW_LOGE("Do not allow uid:%{public}d to invoke in hiview process", uid);
102 return {UcError::PERMISSION_CHECK_FAILED};
103 }
104 if (postTime == 0) {
105 HIVIEW_LOGI("trace on module:%{public}d", static_cast<int32_t>(module));
106 return GetUcError(TraceStateMachine::GetInstance().TraceTelemetryOn());
107 }
108 auto ret = TraceStateMachine::GetInstance().PostTelemetryOn(postTime);
109 if (ret.GetStateError() != TraceStateCode::UPDATE_TIME) {
110 HIVIEW_LOGI("module:%{public}d post on not update timer", static_cast<int32_t>(module));
111 return GetUcError(ret);
112 }
113 std::lock_guard<std::mutex> lock(postMutex_);
114 if (ffrtQueue_ == nullptr) {
115 ffrtQueue_ = std::make_unique<ffrt::queue>("telemetry_post_on");
116 }
117 if (ffrtQueue_->cancel(handle_) < 0) {
118 HIVIEW_LOGW("no task to cancel");
119 }
120 HIVIEW_LOGI("post a timeout task to ffrt delay:%{public} " PRId64 ", module:%{public}d", postTime,
121 static_cast<int32_t>(module));
122 handle_ = ffrtQueue_->submit_h([]() {
123 TraceStateMachine::GetInstance().PostTelemetryTimeOut();
124 }, ffrt::task_attr().name("post_trace_on").delay(postTime * MS_TO_US));
125 return GetUcError(ret);
126 }
127
FilterTraceOff(TeleModule module)128 CollectResult<int32_t> TraceCollectorImpl::FilterTraceOff(TeleModule module)
129 {
130 if (auto uid = getuid(); uid != HIVIEW_UID) {
131 HIVIEW_LOGE("Do not allow uid:%{public}d to dump trace except in hiview process", uid);
132 return {UcError::PERMISSION_CHECK_FAILED};
133 }
134 HIVIEW_LOGI("module:%{public}d", static_cast<int32_t>(module));
135 return GetUcError(TraceStateMachine::GetInstance().TraceTelemetryOff());
136 }
137
DumpTrace(TraceCaller caller)138 CollectResult<std::vector<std::string>> TraceCollectorImpl::DumpTrace(TraceCaller caller)
139 {
140 return StartDumpTrace(caller, 0, static_cast<uint64_t>(0));
141 }
142
StartDumpTrace(TraceCaller & caller,uint32_t timeLimit,uint64_t happenTime)143 CollectResult<std::vector<std::string>> TraceCollectorImpl::StartDumpTrace(TraceCaller &caller, uint32_t timeLimit,
144 uint64_t happenTime)
145 {
146 if (auto uid = getuid(); uid != HIVIEW_UID) {
147 HIVIEW_LOGE("Do not allow uid:%{public}d to dump trace except in hiview process", uid);
148 return {UcError::PERMISSION_CHECK_FAILED};
149 }
150 CollectResult<std::vector<std::string>> result;
151 auto strategy = TraceStrategyFactory::CreateTraceStrategy(caller, timeLimit, happenTime);
152 if (strategy == nullptr) {
153 HIVIEW_LOGE("Create traceStrategy error caller:%{public}d", caller);
154 result.retCode = UcError::UNSUPPORT;
155 return result;
156 }
157 TraceRetInfo traceRetInfo;
158 TraceRet ret = strategy->DoDump(result.data, traceRetInfo);
159 result.retCode = GetUcError(ret);
160 HIVIEW_LOGI("caller:%{public}s, retCode = %{public}d, data.size = %{public}zu.", EnumToString(caller).c_str(),
161 result.retCode, result.data.size());
162 return result;
163 }
164
RecoverTmpTrace()165 bool TraceCollectorImpl::RecoverTmpTrace()
166 {
167 if (auto uid = getuid(); uid != HIVIEW_UID) {
168 HIVIEW_LOGE("Do not allow uid:%{public}d to RecoverTmpTrace trace except in hiview process", uid);
169 return false;
170 }
171 std::vector<std::string> traceFiles;
172 FileUtil::GetDirFiles(UNIFIED_SHARE_TEMP_PATH, traceFiles, false);
173 HIVIEW_LOGI("traceFiles need recover: %{public}zu", traceFiles.size());
174 for (auto &filePath : traceFiles) {
175 std::string fileName = FileUtil::ExtractFileName(filePath);
176 HIVIEW_LOGI("unfinished trace file: %{public}s", fileName.c_str());
177 std::string originTraceFile = StringUtil::ReplaceStr("/data/log/hitrace/" + fileName, ".zip", ".sys");
178 if (!FileUtil::FileExists(originTraceFile)) {
179 HIVIEW_LOGI("source file not exist: %{public}s", originTraceFile.c_str());
180 FileUtil::RemoveFile(UNIFIED_SHARE_TEMP_PATH + fileName);
181 continue;
182 }
183 int fd = open(originTraceFile.c_str(), O_RDONLY | O_NONBLOCK);
184 if (fd == -1) {
185 HIVIEW_LOGI("open source file failed: %{public}s", originTraceFile.c_str());
186 continue;
187 }
188 fdsan_exchange_owner_tag(fd, 0, logLabelDomain);
189 // add lock before zip trace file, in case hitrace delete origin trace file.
190 if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
191 HIVIEW_LOGI("get source file lock failed: %{public}s", originTraceFile.c_str());
192 fdsan_close_with_tag(fd, logLabelDomain);
193 continue;
194 }
195 HIVIEW_LOGI("originTraceFile path: %{public}s", originTraceFile.c_str());
196 UcollectionTask traceTask = [=]() {
197 ZipShareTempTraceFile(originTraceFile);
198 flock(fd, LOCK_UN);
199 fdsan_close_with_tag(fd, logLabelDomain);
200 };
201 TraceWorker::GetInstance().HandleUcollectionTask(traceTask);
202 }
203 return true;
204 }
205 } // UCollectUtil
206 } // HiViewDFX
207 } // OHOS
208