1 /*
2 * Copyright (c) 2021-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 "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 #endif
37 namespace OHOS {
38 namespace HiviewDFX {
39 using namespace UCollect;
40 DEFINE_LOG_TAG("HiView-Service");
41 namespace {
42 constexpr int MIN_SUPPORT_CMD_SIZE = 1;
43 constexpr int32_t ERR_DEFAULT = -1;
44 }
45
HiviewService()46 HiviewService::HiviewService()
47 {
48 cpuCollector_ = UCollectUtil::CpuCollector::Create();
49 graphicMemoryCollector_ = UCollectUtil::GraphicMemoryCollector::Create();
50 }
51
StartService()52 void HiviewService::StartService()
53 {
54 std::unique_ptr<HiviewServiceAdapter> adapter = std::make_unique<HiviewServiceAdapter>();
55 adapter->StartService(this);
56 }
57
DumpRequestDispatcher(int fd,const std::vector<std::string> & cmds)58 void HiviewService::DumpRequestDispatcher(int fd, const std::vector<std::string> &cmds)
59 {
60 if (fd < 0) {
61 HIVIEW_LOGW("invalid fd.");
62 return;
63 }
64
65 if (cmds.size() == 0) {
66 DumpLoadedPluginInfo(fd);
67 return;
68 }
69
70 // hidumper hiviewdfx -d
71 if ((cmds.size() == MIN_SUPPORT_CMD_SIZE) && (cmds[0] == "-d")) {
72 DumpDetailedInfo(fd);
73 return;
74 }
75
76 // hidumper hiviewdfx -p
77 if ((cmds.size() >= MIN_SUPPORT_CMD_SIZE) && (cmds[0] == "-p")) {
78 DumpPluginInfo(fd, cmds);
79 return;
80 }
81
82 PrintUsage(fd);
83 return;
84 }
85
DumpPluginInfo(int fd,const std::vector<std::string> & cmds) const86 void HiviewService::DumpPluginInfo(int fd, const std::vector<std::string> &cmds) const
87 {
88 std::string pluginName = "";
89 const int pluginNameSize = 2;
90 const int pluginNamePos = 1;
91 std::vector<std::string> newCmd;
92 if (cmds.size() >= pluginNameSize) {
93 pluginName = cmds[pluginNamePos];
94 newCmd.insert(newCmd.begin(), cmds.begin() + pluginNamePos, cmds.end());
95 }
96
97 auto &platform = HiviewPlatform::GetInstance();
98 auto const &curPluginMap = platform.GetPluginMap();
99 for (auto const &entry : curPluginMap) {
100 auto const &pluginPtr = entry.second;
101 if (pluginPtr == nullptr) {
102 continue;
103 }
104
105 if (pluginName.empty()) {
106 pluginPtr->Dump(fd, newCmd);
107 continue;
108 }
109
110 if (pluginPtr->GetName() == pluginName) {
111 pluginPtr->Dump(fd, newCmd);
112 break;
113 }
114 }
115 }
116
DumpDetailedInfo(int fd)117 void HiviewService::DumpDetailedInfo(int fd)
118 {
119 if (parser_ != nullptr) {
120 parser_.reset();
121 }
122 DumpLoadedPluginInfo(fd);
123 parser_ = std::make_unique<AuditLogParser>();
124 parser_->StartParse();
125 std::string timeScope = parser_->GetAuditLogTimeScope();
126 dprintf(fd, "%s\n", timeScope.c_str());
127 DumpPluginUsageInfo(fd);
128 DumpThreadUsageInfo(fd);
129 DumpPipelineUsageInfo(fd);
130 parser_.reset();
131 }
132
DumpLoadedPluginInfo(int fd) const133 void HiviewService::DumpLoadedPluginInfo(int fd) const
134 {
135 auto &platform = HiviewPlatform::GetInstance();
136 auto const &curPluginMap = platform.GetPluginMap();
137 dprintf(fd, "Current Loaded Plugins:\n");
138 for (auto const &entry : curPluginMap) {
139 auto const &pluginName = entry.first;
140 if (entry.second != nullptr) {
141 dprintf(fd, "PluginName:%s ", pluginName.c_str());
142 dprintf(fd, "IsDynamic:%s ",
143 (entry.second->GetType() == Plugin::PluginType::DYNAMIC) ? "True" : "False");
144 dprintf(fd, "Version:%s ", (entry.second->GetVersion().c_str()));
145 dprintf(fd,
146 "ThreadName:%s\n",
147 ((entry.second->GetWorkLoop() == nullptr) ? "Null" : entry.second->GetWorkLoop()->GetName().c_str()));
148 }
149 }
150 dprintf(fd, "Dump Plugin Loaded Info Done.\n\n");
151 }
152
DumpPluginUsageInfo(int fd)153 void HiviewService::DumpPluginUsageInfo(int fd)
154 {
155 auto &platform = HiviewPlatform::GetInstance();
156 auto const &curPluginMap = platform.GetPluginMap();
157 for (auto const &entry : curPluginMap) {
158 auto pluginName = entry.first;
159 if (entry.second != nullptr) {
160 DumpPluginUsageInfo(fd, pluginName);
161 }
162 }
163 }
164
DumpPluginUsageInfo(int fd,const std::string & pluginName) const165 void HiviewService::DumpPluginUsageInfo(int fd, const std::string &pluginName) const
166 {
167 if (parser_ == nullptr) {
168 return;
169 }
170 auto logList = parser_->GetPluginSummary(pluginName);
171 dprintf(fd, "Following events processed By Plugin %s:\n", pluginName.c_str());
172 for (auto &log : logList) {
173 dprintf(fd, " %s.\n", log.c_str());
174 }
175 dprintf(fd, "Dump Plugin Usage Done.\n\n");
176 }
177
DumpThreadUsageInfo(int fd) const178 void HiviewService::DumpThreadUsageInfo(int fd) const
179 {
180 auto &platform = HiviewPlatform::GetInstance();
181 auto const &curThreadMap = platform.GetWorkLoopMap();
182 dprintf(fd, "Start Dump ThreadInfo:\n");
183 for (auto const &entry : curThreadMap) {
184 if (entry.second != nullptr) {
185 std::string name = entry.second->GetName();
186 DumpThreadUsageInfo(fd, name);
187 }
188 }
189 dprintf(fd, "Dump ThreadInfo Done.\n\n");
190 }
191
DumpThreadUsageInfo(int fd,const std::string & threadName) const192 void HiviewService::DumpThreadUsageInfo(int fd, const std::string &threadName) const
193 {
194 if (parser_ == nullptr) {
195 return;
196 }
197 auto logList = parser_->GetThreadSummary(threadName);
198 dprintf(fd, "Following events processed on Thread %s:\n", threadName.c_str());
199 for (auto &log : logList) {
200 dprintf(fd, " %s.\n", log.c_str());
201 }
202 }
203
DumpPipelineUsageInfo(int fd) const204 void HiviewService::DumpPipelineUsageInfo(int fd) const
205 {
206 auto &platform = HiviewPlatform::GetInstance();
207 auto const &curPipelineMap = platform.GetPipelineMap();
208 dprintf(fd, "Start Dump Pipeline Info:\n");
209 for (auto const &entry : curPipelineMap) {
210 auto pipeline = entry.first;
211 DumpPipelineUsageInfo(fd, pipeline);
212 }
213 }
214
DumpPipelineUsageInfo(int fd,const std::string & pipelineName) const215 void HiviewService::DumpPipelineUsageInfo(int fd, const std::string &pipelineName) const
216 {
217 if (parser_ == nullptr) {
218 return;
219 }
220 auto logList = parser_->GetPipelineSummary(pipelineName);
221 dprintf(fd, "Following events processed on Pipeline %s:\n", pipelineName.c_str());
222 for (auto &log : logList) {
223 dprintf(fd, " %s.\n", log.c_str());
224 }
225 dprintf(fd, "Dump Pipeline Usage Info Done.\n\n");
226 }
227
PrintUsage(int fd) const228 void HiviewService::PrintUsage(int fd) const
229 {
230 dprintf(fd, "Hiview Plugin Platform dump options:\n");
231 dprintf(fd, "hidumper hiviewdfx [-d(etail)]\n");
232 dprintf(fd, " [-p(lugin) pluginName]\n");
233 }
234
CopyFile(const std::string & srcFilePath,const std::string & destFilePath)235 int32_t HiviewService::CopyFile(const std::string& srcFilePath, const std::string& destFilePath)
236 {
237 int srcFd = open(srcFilePath.c_str(), O_RDONLY);
238 if (srcFd == -1) {
239 HIVIEW_LOGE("failed to open source file, src=%{public}s", StringUtil::HideSnInfo(srcFilePath).c_str());
240 return ERR_DEFAULT;
241 }
242 struct stat st{};
243 if (fstat(srcFd, &st) == -1) {
244 HIVIEW_LOGE("failed to stat file.");
245 close(srcFd);
246 return ERR_DEFAULT;
247 }
248 int destFd = open(destFilePath.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
249 if (destFd == -1) {
250 HIVIEW_LOGE("failed to open destination file, des=%{public}s", StringUtil::HideSnInfo(destFilePath).c_str());
251 close(srcFd);
252 return ERR_DEFAULT;
253 }
254 off_t offset = 0;
255 int cycleNum = 0;
256 while (offset < st.st_size) {
257 size_t count = static_cast<size_t>((st.st_size - offset) > SSIZE_MAX ? SSIZE_MAX : st.st_size - offset);
258 ssize_t ret = sendfile(destFd, srcFd, &offset, count);
259 if (cycleNum > 0) {
260 HIVIEW_LOGI("sendfile cycle num:%{public}d, ret:%{public}zd, offset:%{public}lld, size:%{public}lld",
261 cycleNum, ret, static_cast<long long>(offset), static_cast<long long>(st.st_size));
262 }
263 cycleNum++;
264 if (ret < 0 || offset > st.st_size) {
265 HIVIEW_LOGE("sendfile fail, ret:%{public}zd, offset:%{public}lld, size:%{public}lld",
266 ret, static_cast<long long>(offset), static_cast<long long>(st.st_size));
267 close(srcFd);
268 close(destFd);
269 return ERR_DEFAULT;
270 }
271 }
272 close(srcFd);
273 close(destFd);
274 return 0;
275 }
276
Copy(const std::string & srcFilePath,const std::string & destFilePath)277 int32_t HiviewService::Copy(const std::string& srcFilePath, const std::string& destFilePath)
278 {
279 return CopyFile(srcFilePath, destFilePath);
280 }
281
Move(const std::string & srcFilePath,const std::string & destFilePath)282 int32_t HiviewService::Move(const std::string& srcFilePath, const std::string& destFilePath)
283 {
284 int copyResult = CopyFile(srcFilePath, destFilePath);
285 if (copyResult != 0) {
286 HIVIEW_LOGW("copy file failed, result: %{public}d", copyResult);
287 return copyResult;
288 }
289 bool result = FileUtil::RemoveFile(srcFilePath);
290 HIVIEW_LOGI("move file, delete src result: %{public}d", result);
291 if (!result) {
292 bool destResult = FileUtil::RemoveFile(destFilePath);
293 HIVIEW_LOGI("move file, delete dest result: %{public}d", destResult);
294 return ERR_DEFAULT;
295 }
296 return 0;
297 }
298
Remove(const std::string & filePath)299 int32_t HiviewService::Remove(const std::string& filePath)
300 {
301 bool result = FileUtil::RemoveFile(filePath);
302 HIVIEW_LOGI("remove file, result:%{public}d", result);
303 return 0;
304 }
305
OpenSnapshotTrace(const std::vector<std::string> & tagGroups)306 CollectResult<int32_t> HiviewService::OpenSnapshotTrace(const std::vector<std::string>& tagGroups)
307 {
308 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
309 return {UcError::FEATURE_CLOSED};
310 #else
311 TraceRet openRet = TraceStateMachine::GetInstance().OpenTrace(TraceScenario::TRACE_COMMAND, tagGroups);
312 return {GetUcError(openRet)};
313 #endif
314 }
315
DumpSnapshotTrace(UCollect::TraceClient client)316 CollectResult<std::vector<std::string>> HiviewService::DumpSnapshotTrace(UCollect::TraceClient client)
317 {
318 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
319 return {UcError::FEATURE_CLOSED};
320 #else
321 HIVIEW_LOGI("client:[%{public}d] dump trace in snapshot mode.", static_cast<int32_t>(client));
322 CollectResult<std::vector<std::string>> result;
323 auto traceStrategy = TraceFactory::CreateTraceStrategy(client, 0, static_cast<uint64_t>(0));
324 if (traceStrategy == nullptr) {
325 HIVIEW_LOGE("Create traceStrategy error client:%{public}d", static_cast<int32_t>(client));
326 return {UcError::UNSUPPORT};
327 }
328 TraceRet dumpRet = traceStrategy->DoDump(result.data);
329 result.retCode = GetUcError(dumpRet);
330 return result;
331 #endif
332 }
333
OpenRecordingTrace(const std::string & tags)334 CollectResult<int32_t> HiviewService::OpenRecordingTrace(const std::string& tags)
335 {
336 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
337 return {UcError::FEATURE_CLOSED};
338 #else
339 TraceRet openRet = TraceStateMachine::GetInstance().OpenTrace(TraceScenario::TRACE_COMMAND, tags);
340 return {GetUcError(openRet)};
341 #endif
342 }
343
RecordingTraceOn()344 CollectResult<int32_t> HiviewService::RecordingTraceOn()
345 {
346 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
347 return {UcError::FEATURE_CLOSED};
348 #else
349 TraceRet ret = TraceStateMachine::GetInstance().TraceDropOn(TraceScenario::TRACE_COMMAND);
350 return {GetUcError(ret)};
351 #endif
352 }
353
RecordingTraceOff()354 CollectResult<std::vector<std::string>> HiviewService::RecordingTraceOff()
355 {
356 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
357 return {UcError::FEATURE_CLOSED};
358 #else
359 TraceRetInfo traceRetInfo;
360 TraceRet ret = TraceStateMachine::GetInstance().TraceDropOff(TraceScenario::TRACE_COMMAND, traceRetInfo);
361 CollectResult<std::vector<std::string>> result(GetUcError(ret));
362 result.data = traceRetInfo.outputFiles;
363 return result;
364 #endif
365 }
366
CloseTrace()367 CollectResult<int32_t> HiviewService::CloseTrace()
368 {
369 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
370 return {UcError::FEATURE_CLOSED};
371 #else
372 TraceRet ret = TraceStateMachine::GetInstance().CloseTrace(TraceScenario::TRACE_COMMAND);
373 return {GetUcError(ret)};
374 #endif
375 }
376
377 #ifdef UNIFIED_COLLECTOR_TRACE_ENABLE
InnerCreateAppCallerEvent(UCollectClient::AppCaller & appCaller,const std::string & eventName)378 static std::shared_ptr<AppCallerEvent> InnerCreateAppCallerEvent(UCollectClient::AppCaller &appCaller,
379 const std::string &eventName)
380 {
381 std::shared_ptr<AppCallerEvent> appCallerEvent = std::make_shared<AppCallerEvent>("HiViewService");
382 appCallerEvent->messageType_ = Event::MessageType::PLUGIN_MAINTENANCE;
383 appCallerEvent->eventName_ = eventName;
384 appCallerEvent->isBusinessJank_ = appCaller.isBusinessJank;
385 appCallerEvent->bundleName_ = appCaller.bundleName;
386 appCallerEvent->bundleVersion_ = appCaller.bundleVersion;
387 appCallerEvent->uid_ = appCaller.uid;
388 appCallerEvent->pid_ = appCaller.pid;
389 appCallerEvent->happenTime_ = static_cast<uint64_t>(appCaller.happenTime);
390 appCallerEvent->beginTime_ = appCaller.beginTime;
391 appCallerEvent->endTime_ = appCaller.endTime;
392 appCallerEvent->taskBeginTime_ = static_cast<int64_t>(TimeUtil::GetMilliseconds());
393 appCallerEvent->taskEndTime_ = appCallerEvent->taskBeginTime_;
394 appCallerEvent->resultCode_ = UCollect::UcError::SUCCESS;
395 appCallerEvent->foreground_ = appCaller.foreground;
396 appCallerEvent->threadName_ = appCaller.threadName;
397 return appCallerEvent;
398 }
399
InnerHasCallAppTrace(std::shared_ptr<AppCallerEvent> appCallerEvent)400 bool HiviewService::InnerHasCallAppTrace(std::shared_ptr<AppCallerEvent> appCallerEvent)
401 {
402 return TraceFlowController(ClientName::APP).HasCallOnceToday(appCallerEvent->uid_, appCallerEvent->happenTime_);
403 }
404
InnerResponseStartAppTrace(UCollectClient::AppCaller & appCaller)405 CollectResult<int32_t> HiviewService::InnerResponseStartAppTrace(UCollectClient::AppCaller &appCaller)
406 {
407 auto appCallerEvent = InnerCreateAppCallerEvent(appCaller, UCollectUtil::START_APP_TRACE);
408 if (InnerHasCallAppTrace(appCallerEvent)) {
409 HIVIEW_LOGW("deny: already capture trace uid=%{public}d pid=%{public}d",
410 appCallerEvent->uid_, appCallerEvent->pid_);
411 return {UCollect::UcError::HAD_CAPTURED_TRACE};
412 }
413 TraceRet ret = TraceStateMachine::GetInstance().OpenDynamicTrace(appCallerEvent->pid_);
414 if (!ret.IsSuccess()) {
415 return {GetUcError(ret)};
416 }
417 if (!HiviewPlatform::GetInstance().PostSyncEventToTarget(nullptr, UCollectUtil::UCOLLECTOR_PLUGIN,
418 appCallerEvent)) {
419 HIVIEW_LOGE("post event failed");
420 return {UCollect::UcError::SYSTEM_ERROR};
421 }
422 return {UCollect::UcError::SUCCESS};
423 }
424
InnerResponseDumpAppTrace(UCollectClient::AppCaller & appCaller)425 CollectResult<int32_t> HiviewService::InnerResponseDumpAppTrace(UCollectClient::AppCaller &appCaller)
426 {
427 CollectResult<std::vector<std::string>> result;
428 auto strategy = TraceFactory::CreateAppStrategy(InnerCreateAppCallerEvent(appCaller, UCollectUtil::DUMP_APP_TRACE));
429 return {GetUcError(strategy->DoDump(result.data))};
430 }
431 #endif
432
CaptureDurationTrace(UCollectClient::AppCaller & appCaller)433 CollectResult<int32_t> HiviewService::CaptureDurationTrace(UCollectClient::AppCaller &appCaller)
434 {
435 #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE
436 return {UcError::FEATURE_CLOSED};
437 #else
438 if (appCaller.actionId == UCollectClient::ACTION_ID_START_TRACE) {
439 return InnerResponseStartAppTrace(appCaller);
440 } else if (appCaller.actionId == UCollectClient::ACTION_ID_DUMP_TRACE) {
441 return InnerResponseDumpAppTrace(appCaller);
442 } else {
443 HIVIEW_LOGE("invalid param %{public}d, can not capture trace for uid=%{public}d, pid=%{public}d",
444 appCaller.actionId, appCaller.uid, appCaller.pid);
445 return {UCollect::UcError::INVALID_ACTION_ID};
446 }
447 #endif
448 }
449
450
GetSysCpuUsage()451 CollectResult<double> HiviewService::GetSysCpuUsage()
452 {
453 CollectResult<double> cpuUsageRet = cpuCollector_->GetSysCpuUsage();
454 if (cpuUsageRet.retCode != UCollect::UcError::SUCCESS) {
455 HIVIEW_LOGE("failed to collect system cpu usage");
456 }
457 return cpuUsageRet;
458 }
459
SetAppResourceLimit(UCollectClient::MemoryCaller & memoryCaller)460 CollectResult<int32_t> HiviewService::SetAppResourceLimit(UCollectClient::MemoryCaller& memoryCaller)
461 {
462 std::string eventName = "APP_RESOURCE_LIMIT";
463 SysEventCreator sysEventCreator("HIVIEWDFX", eventName, SysEventCreator::FAULT);
464 sysEventCreator.SetKeyValue("PID", memoryCaller.pid);
465 sysEventCreator.SetKeyValue("RESOURCE_TYPE", memoryCaller.resourceType);
466 sysEventCreator.SetKeyValue("RESOURCE_LIMIT", memoryCaller.limitValue);
467 sysEventCreator.SetKeyValue("RESOURCE_DEBUG_ENABLE", memoryCaller.enabledDebugLog ? "true" : "false");
468 auto sysEvent = std::make_shared<SysEvent>(eventName, nullptr, sysEventCreator);
469 std::shared_ptr<Event> event = std::dynamic_pointer_cast<Event>(sysEvent);
470 if (!HiviewPlatform::GetInstance().PostSyncEventToTarget(nullptr, "XPower", event)) {
471 HIVIEW_LOGE("%{public}s failed for pid=%{public}d error", eventName.c_str(), memoryCaller.pid);
472 return {UCollect::UcError::SYSTEM_ERROR};
473 }
474 return {UCollect::UcError::SUCCESS};
475 }
476
SetSplitMemoryValue(std::vector<UCollectClient::MemoryCaller> & memList)477 CollectResult<int32_t> HiviewService::SetSplitMemoryValue(std::vector<UCollectClient::MemoryCaller>& memList)
478 {
479 std::vector<int32_t> pidList;
480 std::vector<int32_t> resourceList;
481 for (auto it : memList) {
482 pidList.push_back(it.pid);
483 resourceList.push_back(it.limitValue);
484 }
485 std::string eventName = "AVCODEC_SPLITMEMORY";
486 SysEventCreator sysEventCreator("HIVIEWDFX", eventName, SysEventCreator::FAULT);
487 sysEventCreator.SetKeyValue("PID_LIST", pidList);
488 sysEventCreator.SetKeyValue("RESOURCE_LIST", resourceList);
489
490 auto sysEvent = std::make_shared<SysEvent>(eventName, nullptr, sysEventCreator);
491 auto event = std::dynamic_pointer_cast<Event>(sysEvent);
492 if (!HiviewPlatform::GetInstance().PostSyncEventToTarget(nullptr, "XPower", event)) {
493 HIVIEW_LOGE("%{public}s failed", eventName.c_str());
494 return {UCollect::UcError::SYSTEM_ERROR};
495 }
496 return {UCollect::UcError::SUCCESS};
497 }
498
GetGraphicUsage(int32_t pid)499 CollectResult<int32_t> HiviewService::GetGraphicUsage(int32_t pid)
500 {
501 return graphicMemoryCollector_->GetGraphicUsage(pid, GraphicType::TOTAL, true);
502 }
503 } // namespace HiviewDFX
504 } // namespace OHOS
505