1 /*
2 * Copyright (c) 2021-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
16 #include "hiview_service.h"
17
18 #include <cinttypes>
19 #include <cstdio>
20 #include <fcntl.h>
21 #include <sys/sendfile.h>
22 #include <sys/stat.h>
23
24 #include "bundle_mgr_client.h"
25 #include "collect_event.h"
26 #include "file_util.h"
27 #include "hiview_logger.h"
28 #include "hiview_platform.h"
29 #include "hiview_service_adapter.h"
30 #include "sys_event.h"
31 #include "string_util.h"
32 #include "time_util.h"
33 #ifdef UNIFIED_COLLECTOR_TRACE_ENABLE
34 #include "trace_state_machine.h"
35 #include "trace_strategy.h"
36 #include "trace_strategy_factory.h"
37 #endif
38 namespace OHOS {
39 namespace HiviewDFX {
40 using namespace UCollect;
41 DEFINE_LOG_TAG("HiView-Service");
42 namespace {
43 constexpr int MIN_SUPPORT_CMD_SIZE = 1;
44 constexpr int32_t ERR_DEFAULT = -1;
45 }
46
HiviewService()47 HiviewService::HiviewService()
48 {
49 cpuCollector_ = UCollectUtil::CpuCollector::Create();
50 graphicMemoryCollector_ = UCollectUtil::GraphicMemoryCollector::Create();
51 }
52
StartService()53 void HiviewService::StartService()
54 {
55 std::unique_ptr<HiviewServiceAdapter> adapter = std::make_unique<HiviewServiceAdapter>();
56 adapter->StartService(this);
57 }
58
DumpRequestDispatcher(int fd,const std::vector<std::string> & cmds)59 void HiviewService::DumpRequestDispatcher(int fd, const std::vector<std::string> &cmds)
60 {
61 if (fd < 0) {
62 HIVIEW_LOGW("invalid fd.");
63 return;
64 }
65
66 if (cmds.size() == 0) {
67 DumpLoadedPluginInfo(fd);
68 return;
69 }
70
71 // hidumper hiviewdfx -p
72 if ((cmds.size() >= MIN_SUPPORT_CMD_SIZE) && (cmds[0] == "-p")) {
73 DumpPluginInfo(fd, cmds);
74 return;
75 }
76
77 PrintUsage(fd);
78 return;
79 }
80
DumpPluginInfo(int fd,const std::vector<std::string> & cmds) const81 void HiviewService::DumpPluginInfo(int fd, const std::vector<std::string> &cmds) const
82 {
83 std::string pluginName = "";
84 const int pluginNameSize = 2;
85 const int pluginNamePos = 1;
86 std::vector<std::string> newCmd;
87 if (cmds.size() >= pluginNameSize) {
88 pluginName = cmds[pluginNamePos];
89 newCmd.insert(newCmd.begin(), cmds.begin() + pluginNamePos, cmds.end());
90 }
91
92 auto &platform = HiviewPlatform::GetInstance();
93 auto const &curPluginMap = platform.GetPluginMap();
94 for (auto const &entry : curPluginMap) {
95 auto const &pluginPtr = entry.second;
96 if (pluginPtr == nullptr) {
97 continue;
98 }
99
100 if (pluginName.empty()) {
101 pluginPtr->Dump(fd, newCmd);
102 continue;
103 }
104
105 if (pluginPtr->GetName() == pluginName) {
106 pluginPtr->Dump(fd, newCmd);
107 break;
108 }
109 }
110 }
111
DumpLoadedPluginInfo(int fd) const112 void HiviewService::DumpLoadedPluginInfo(int fd) const
113 {
114 auto &platform = HiviewPlatform::GetInstance();
115 auto const &curPluginMap = platform.GetPluginMap();
116 dprintf(fd, "Current Loaded Plugins:\n");
117 for (auto const &entry : curPluginMap) {
118 auto const &pluginName = entry.first;
119 if (entry.second != nullptr) {
120 dprintf(fd, "PluginName:%s ", pluginName.c_str());
121 dprintf(fd, "IsDynamic:%s ",
122 (entry.second->GetType() == Plugin::PluginType::DYNAMIC) ? "True" : "False");
123 dprintf(fd, "Version:%s ", (entry.second->GetVersion().c_str()));
124 dprintf(fd,
125 "ThreadName:%s\n",
126 ((entry.second->GetWorkLoop() == nullptr) ? "Null" : entry.second->GetWorkLoop()->GetName().c_str()));
127 }
128 }
129 dprintf(fd, "Dump Plugin Loaded Info Done.\n\n");
130 }
131
PrintUsage(int fd) const132 void HiviewService::PrintUsage(int fd) const
133 {
134 dprintf(fd, "Hiview Plugin Platform dump options:\n");
135 dprintf(fd, "hidumper hiviewdfx [-p(lugin) pluginName]\n");
136 }
137
CopyFile(const std::string & srcFilePath,const std::string & destFilePath)138 int32_t HiviewService::CopyFile(const std::string& srcFilePath, const std::string& destFilePath)
139 {
140 int srcFd = open(srcFilePath.c_str(), O_RDONLY);
141 if (srcFd == -1) {
142 HIVIEW_LOGE("failed to open source file, src=%{public}s", StringUtil::HideSnInfo(srcFilePath).c_str());
143 return ERR_DEFAULT;
144 }
145 fdsan_exchange_owner_tag(srcFd, 0, logLabelDomain);
146 struct stat st{};
147 if (fstat(srcFd, &st) == -1) {
148 HIVIEW_LOGE("failed to stat file.");
149 fdsan_close_with_tag(srcFd, logLabelDomain);
150 return ERR_DEFAULT;
151 }
152 int destFd = open(destFilePath.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
153 if (destFd == -1) {
154 HIVIEW_LOGE("failed to open destination file, des=%{public}s", StringUtil::HideSnInfo(destFilePath).c_str());
155 fdsan_close_with_tag(srcFd, logLabelDomain);
156 return ERR_DEFAULT;
157 }
158 fdsan_exchange_owner_tag(destFd, 0, logLabelDomain);
159 off_t offset = 0;
160 int cycleNum = 0;
161 while (offset < st.st_size) {
162 size_t count = static_cast<size_t>((st.st_size - offset) > SSIZE_MAX ? SSIZE_MAX : st.st_size - offset);
163 ssize_t ret = sendfile(destFd, srcFd, &offset, count);
164 if (cycleNum > 0) {
165 HIVIEW_LOGI("sendfile cycle num:%{public}d, ret:%{public}zd, offset:%{public}lld, size:%{public}lld",
166 cycleNum, ret, static_cast<long long>(offset), static_cast<long long>(st.st_size));
167 }
168 cycleNum++;
169 if (ret < 0 || offset > st.st_size) {
170 HIVIEW_LOGE("sendfile fail, ret:%{public}zd, offset:%{public}lld, size:%{public}lld",
171 ret, static_cast<long long>(offset), static_cast<long long>(st.st_size));
172 fdsan_close_with_tag(srcFd, logLabelDomain);
173 fdsan_close_with_tag(destFd, logLabelDomain);
174 return ERR_DEFAULT;
175 }
176 }
177 fdsan_close_with_tag(srcFd, logLabelDomain);
178 fdsan_close_with_tag(destFd, logLabelDomain);
179 return 0;
180 }
181
Copy(const std::string & srcFilePath,const std::string & destFilePath)182 int32_t HiviewService::Copy(const std::string& srcFilePath, const std::string& destFilePath)
183 {
184 return CopyFile(srcFilePath, destFilePath);
185 }
186
Move(const std::string & srcFilePath,const std::string & destFilePath)187 int32_t HiviewService::Move(const std::string& srcFilePath, const std::string& destFilePath)
188 {
189 int copyResult = CopyFile(srcFilePath, destFilePath);
190 if (copyResult != 0) {
191 HIVIEW_LOGW("copy file failed, result: %{public}d", copyResult);
192 return copyResult;
193 }
194 bool result = FileUtil::RemoveFile(srcFilePath);
195 if (!result) {
196 bool destResult = FileUtil::RemoveFile(destFilePath);
197 HIVIEW_LOGI("failed to delete src, delete dest result: %{public}d", destResult);
198 return ERR_DEFAULT;
199 }
200 return 0;
201 }
202
Remove(const std::string & filePath)203 int32_t HiviewService::Remove(const std::string& filePath)
204 {
205 bool result = FileUtil::RemoveFile(filePath);
206 HIVIEW_LOGI("remove file, result:%{public}d", result);
207 return 0;
208 }
209
OpenSnapshotTrace(const std::vector<std::string> & tagGroups)210 CollectResult<int32_t> HiviewService::OpenSnapshotTrace(const std::vector<std::string>& tagGroups)
211 {
212 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
213 return {UcError::FEATURE_CLOSED};
214 #else
215 TraceRet openRet = TraceStateMachine::GetInstance().OpenTrace(TraceScenario::TRACE_COMMAND, tagGroups);
216 return {GetUcError(openRet)};
217 #endif
218 }
219
DumpSnapshotTrace(UCollect::TraceClient client)220 CollectResult<std::vector<std::string>> HiviewService::DumpSnapshotTrace(UCollect::TraceClient client)
221 {
222 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
223 return {UcError::FEATURE_CLOSED};
224 #else
225 HIVIEW_LOGI("client:[%{public}d] dump trace in snapshot mode.", static_cast<int32_t>(client));
226 CollectResult<std::vector<std::string>> result;
227 auto traceStrategy = TraceStrategyFactory::CreateTraceStrategy(client, 0, static_cast<uint64_t>(0));
228 if (traceStrategy == nullptr) {
229 HIVIEW_LOGE("Create traceStrategy error client:%{public}d", static_cast<int32_t>(client));
230 return {UcError::UNSUPPORT};
231 }
232 TraceRetInfo traceRetInfo;
233 TraceRet dumpRet = traceStrategy->DoDump(result.data, traceRetInfo);
234 result.retCode = GetUcError(dumpRet);
235 return result;
236 #endif
237 }
238
OpenRecordingTrace(const std::string & tags)239 CollectResult<int32_t> HiviewService::OpenRecordingTrace(const std::string& tags)
240 {
241 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
242 return {UcError::FEATURE_CLOSED};
243 #else
244 TraceRet openRet = TraceStateMachine::GetInstance().OpenTrace(TraceScenario::TRACE_COMMAND, tags);
245 return {GetUcError(openRet)};
246 #endif
247 }
248
RecordingTraceOn()249 CollectResult<int32_t> HiviewService::RecordingTraceOn()
250 {
251 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
252 return {UcError::FEATURE_CLOSED};
253 #else
254 TraceRet ret = TraceStateMachine::GetInstance().TraceDropOn(TraceScenario::TRACE_COMMAND);
255 return {GetUcError(ret)};
256 #endif
257 }
258
RecordingTraceOff()259 CollectResult<std::vector<std::string>> HiviewService::RecordingTraceOff()
260 {
261 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
262 return {UcError::FEATURE_CLOSED};
263 #else
264 TraceRetInfo traceRetInfo;
265 TraceRet ret = TraceStateMachine::GetInstance().TraceDropOff(TraceScenario::TRACE_COMMAND, traceRetInfo);
266 CollectResult<std::vector<std::string>> result(GetUcError(ret));
267 result.data = traceRetInfo.outputFiles;
268 return result;
269 #endif
270 }
271
CloseTrace()272 CollectResult<int32_t> HiviewService::CloseTrace()
273 {
274 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
275 return {UcError::FEATURE_CLOSED};
276 #else
277 TraceRet ret = TraceStateMachine::GetInstance().CloseTrace(TraceScenario::TRACE_COMMAND);
278 return {GetUcError(ret)};
279 #endif
280 }
281
282 #ifdef UNIFIED_COLLECTOR_TRACE_ENABLE
InnerCreateAppCallerEvent(UCollectClient::AppCaller & appCaller,const std::string & eventName)283 static std::shared_ptr<AppCallerEvent> InnerCreateAppCallerEvent(UCollectClient::AppCaller &appCaller,
284 const std::string &eventName)
285 {
286 std::shared_ptr<AppCallerEvent> appCallerEvent = std::make_shared<AppCallerEvent>("HiViewService");
287 appCallerEvent->messageType_ = Event::MessageType::PLUGIN_MAINTENANCE;
288 appCallerEvent->eventName_ = eventName;
289 appCallerEvent->isBusinessJank_ = appCaller.isBusinessJank;
290 appCallerEvent->bundleName_ = appCaller.bundleName;
291 appCallerEvent->bundleVersion_ = appCaller.bundleVersion;
292 appCallerEvent->uid_ = appCaller.uid;
293 appCallerEvent->pid_ = appCaller.pid;
294 appCallerEvent->happenTime_ = static_cast<uint64_t>(appCaller.happenTime);
295 appCallerEvent->beginTime_ = appCaller.beginTime;
296 appCallerEvent->endTime_ = appCaller.endTime;
297 appCallerEvent->taskBeginTime_ = static_cast<int64_t>(TimeUtil::GetMilliseconds());
298 appCallerEvent->taskEndTime_ = appCallerEvent->taskBeginTime_;
299 appCallerEvent->resultCode_ = UCollect::UcError::SUCCESS;
300 appCallerEvent->foreground_ = appCaller.foreground;
301 appCallerEvent->threadName_ = appCaller.threadName;
302 return appCallerEvent;
303 }
304
InnerHasCallAppTrace(std::shared_ptr<AppCallerEvent> appCallerEvent)305 bool HiviewService::InnerHasCallAppTrace(std::shared_ptr<AppCallerEvent> appCallerEvent)
306 {
307 return TraceFlowController(ClientName::APP).HasCallOnceToday(appCallerEvent->uid_, appCallerEvent->happenTime_);
308 }
309
InnerResponseStartAppTrace(UCollectClient::AppCaller & appCaller)310 CollectResult<int32_t> HiviewService::InnerResponseStartAppTrace(UCollectClient::AppCaller &appCaller)
311 {
312 auto appCallerEvent = InnerCreateAppCallerEvent(appCaller, UCollectUtil::START_APP_TRACE);
313 if (InnerHasCallAppTrace(appCallerEvent)) {
314 HIVIEW_LOGW("deny: already capture trace uid=%{public}d pid=%{public}d", appCallerEvent->uid_,
315 appCallerEvent->pid_);
316 return {UCollect::UcError::HAD_CAPTURED_TRACE};
317 }
318 TraceRet ret = TraceStateMachine::GetInstance().OpenDynamicTrace(appCallerEvent->pid_);
319 if (!ret.IsSuccess()) {
320 return {GetUcError(ret)};
321 }
322 HiviewPlatform::GetInstance().PostAsyncEventToTarget(nullptr, UCollectUtil::UCOLLECTOR_PLUGIN, appCallerEvent);
323 return {UCollect::UcError::SUCCESS};
324 }
325
InnerResponseDumpAppTrace(UCollectClient::AppCaller & appCaller)326 CollectResult<int32_t> HiviewService::InnerResponseDumpAppTrace(UCollectClient::AppCaller &appCaller)
327 {
328 CollectResult<std::vector<std::string>> result;
329 auto strategy = TraceStrategyFactory::CreateAppStrategy(InnerCreateAppCallerEvent(appCaller,
330 UCollectUtil::DUMP_APP_TRACE));
331 TraceRetInfo traceRetInfo;
332 return {GetUcError(strategy->DoDump(result.data, traceRetInfo))};
333 }
334 #endif
335
CaptureDurationTrace(UCollectClient::AppCaller & appCaller)336 CollectResult<int32_t> HiviewService::CaptureDurationTrace(UCollectClient::AppCaller &appCaller)
337 {
338 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
339 return {UcError::FEATURE_CLOSED};
340 #else
341 if (appCaller.actionId == UCollectClient::ACTION_ID_START_TRACE) {
342 return InnerResponseStartAppTrace(appCaller);
343 } else if (appCaller.actionId == UCollectClient::ACTION_ID_DUMP_TRACE) {
344 return InnerResponseDumpAppTrace(appCaller);
345 } else {
346 HIVIEW_LOGE("invalid param %{public}d, can not capture trace for uid=%{public}d, pid=%{public}d",
347 appCaller.actionId, appCaller.uid, appCaller.pid);
348 return {UCollect::UcError::INVALID_ACTION_ID};
349 }
350 #endif
351 }
352
353
GetSysCpuUsage()354 CollectResult<double> HiviewService::GetSysCpuUsage()
355 {
356 CollectResult<double> cpuUsageRet = cpuCollector_->GetSysCpuUsage();
357 if (cpuUsageRet.retCode != UCollect::UcError::SUCCESS) {
358 HIVIEW_LOGE("failed to collect system cpu usage");
359 }
360 return cpuUsageRet;
361 }
362
SetAppResourceLimit(UCollectClient::MemoryCaller & memoryCaller)363 CollectResult<int32_t> HiviewService::SetAppResourceLimit(UCollectClient::MemoryCaller& memoryCaller)
364 {
365 std::string eventName = "APP_RESOURCE_LIMIT";
366 SysEventCreator sysEventCreator("HIVIEWDFX", eventName, SysEventCreator::FAULT);
367 sysEventCreator.SetKeyValue("PID", memoryCaller.pid);
368 sysEventCreator.SetKeyValue("RESOURCE_TYPE", memoryCaller.resourceType);
369 sysEventCreator.SetKeyValue("RESOURCE_LIMIT", memoryCaller.limitValue);
370 sysEventCreator.SetKeyValue("RESOURCE_DEBUG_ENABLE", memoryCaller.enabledDebugLog ? "true" : "false");
371 auto sysEvent = std::make_shared<SysEvent>(eventName, nullptr, sysEventCreator);
372 std::shared_ptr<Event> event = std::dynamic_pointer_cast<Event>(sysEvent);
373 if (!HiviewPlatform::GetInstance().PostSyncEventToTarget(nullptr, "XPower", event)) {
374 HIVIEW_LOGE("%{public}s failed for pid=%{public}d error", eventName.c_str(), memoryCaller.pid);
375 return {UCollect::UcError::SYSTEM_ERROR};
376 }
377 return {UCollect::UcError::SUCCESS};
378 }
379
SetSplitMemoryValue(std::vector<UCollectClient::MemoryCaller> & memList)380 CollectResult<int32_t> HiviewService::SetSplitMemoryValue(std::vector<UCollectClient::MemoryCaller>& memList)
381 {
382 std::vector<int32_t> pidList;
383 std::vector<int32_t> resourceList;
384 if (memList.size() < 1) {
385 return {UCollect::UcError::SYSTEM_ERROR};
386 }
387 for (auto it : memList) {
388 pidList.push_back(it.pid);
389 resourceList.push_back(it.limitValue);
390 }
391 std::string eventName = memList[0].resourceType;
392 SysEventCreator sysEventCreator("HIVIEWDFX", eventName, SysEventCreator::FAULT);
393 sysEventCreator.SetKeyValue("PID_LIST", pidList);
394 sysEventCreator.SetKeyValue("RESOURCE_LIST", resourceList);
395
396 auto sysEvent = std::make_shared<SysEvent>(eventName, nullptr, sysEventCreator);
397 auto event = std::dynamic_pointer_cast<Event>(sysEvent);
398 if (!HiviewPlatform::GetInstance().PostSyncEventToTarget(nullptr, "XPower", event)) {
399 HIVIEW_LOGE("%{public}s failed for post event", eventName.c_str());
400 return {UCollect::UcError::SYSTEM_ERROR};
401 }
402 return {UCollect::UcError::SUCCESS};
403 }
404
GetGraphicUsage(int32_t pid)405 CollectResult<int32_t> HiviewService::GetGraphicUsage(int32_t pid)
406 {
407 return graphicMemoryCollector_->GetGraphicUsage(pid, GraphicType::TOTAL, true);
408 }
409 } // namespace HiviewDFX
410 } // namespace OHOS
411