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