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