/* * Copyright (c) 2021-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "hiview_service.h" #include #include #include #include #include #include "bundle_mgr_client.h" #include "collect_event.h" #include "file_util.h" #include "hiview_logger.h" #include "hiview_platform.h" #include "hiview_service_adapter.h" #include "sys_event.h" #include "string_util.h" #include "time_util.h" #ifdef UNIFIED_COLLECTOR_TRACE_ENABLE #include "trace_state_machine.h" #include "trace_strategy.h" #endif namespace OHOS { namespace HiviewDFX { using namespace UCollect; DEFINE_LOG_TAG("HiView-Service"); namespace { constexpr int MIN_SUPPORT_CMD_SIZE = 1; constexpr int32_t ERR_DEFAULT = -1; } HiviewService::HiviewService() { cpuCollector_ = UCollectUtil::CpuCollector::Create(); graphicMemoryCollector_ = UCollectUtil::GraphicMemoryCollector::Create(); } void HiviewService::StartService() { std::unique_ptr adapter = std::make_unique(); adapter->StartService(this); } void HiviewService::DumpRequestDispatcher(int fd, const std::vector &cmds) { if (fd < 0) { HIVIEW_LOGW("invalid fd."); return; } if (cmds.size() == 0) { DumpLoadedPluginInfo(fd); return; } // hidumper hiviewdfx -d if ((cmds.size() == MIN_SUPPORT_CMD_SIZE) && (cmds[0] == "-d")) { DumpDetailedInfo(fd); return; } // hidumper hiviewdfx -p if ((cmds.size() >= MIN_SUPPORT_CMD_SIZE) && (cmds[0] == "-p")) { DumpPluginInfo(fd, cmds); return; } PrintUsage(fd); return; } void HiviewService::DumpPluginInfo(int fd, const std::vector &cmds) const { std::string pluginName = ""; const int pluginNameSize = 2; const int pluginNamePos = 1; std::vector newCmd; if (cmds.size() >= pluginNameSize) { pluginName = cmds[pluginNamePos]; newCmd.insert(newCmd.begin(), cmds.begin() + pluginNamePos, cmds.end()); } auto &platform = HiviewPlatform::GetInstance(); auto const &curPluginMap = platform.GetPluginMap(); for (auto const &entry : curPluginMap) { auto const &pluginPtr = entry.second; if (pluginPtr == nullptr) { continue; } if (pluginName.empty()) { pluginPtr->Dump(fd, newCmd); continue; } if (pluginPtr->GetName() == pluginName) { pluginPtr->Dump(fd, newCmd); break; } } } void HiviewService::DumpDetailedInfo(int fd) { if (parser_ != nullptr) { parser_.reset(); } DumpLoadedPluginInfo(fd); parser_ = std::make_unique(); parser_->StartParse(); std::string timeScope = parser_->GetAuditLogTimeScope(); dprintf(fd, "%s\n", timeScope.c_str()); DumpPluginUsageInfo(fd); DumpThreadUsageInfo(fd); DumpPipelineUsageInfo(fd); parser_.reset(); } void HiviewService::DumpLoadedPluginInfo(int fd) const { auto &platform = HiviewPlatform::GetInstance(); auto const &curPluginMap = platform.GetPluginMap(); dprintf(fd, "Current Loaded Plugins:\n"); for (auto const &entry : curPluginMap) { auto const &pluginName = entry.first; if (entry.second != nullptr) { dprintf(fd, "PluginName:%s ", pluginName.c_str()); dprintf(fd, "IsDynamic:%s ", (entry.second->GetType() == Plugin::PluginType::DYNAMIC) ? "True" : "False"); dprintf(fd, "Version:%s ", (entry.second->GetVersion().c_str())); dprintf(fd, "ThreadName:%s\n", ((entry.second->GetWorkLoop() == nullptr) ? "Null" : entry.second->GetWorkLoop()->GetName().c_str())); } } dprintf(fd, "Dump Plugin Loaded Info Done.\n\n"); } void HiviewService::DumpPluginUsageInfo(int fd) { auto &platform = HiviewPlatform::GetInstance(); auto const &curPluginMap = platform.GetPluginMap(); for (auto const &entry : curPluginMap) { auto pluginName = entry.first; if (entry.second != nullptr) { DumpPluginUsageInfo(fd, pluginName); } } } void HiviewService::DumpPluginUsageInfo(int fd, const std::string &pluginName) const { if (parser_ == nullptr) { return; } auto logList = parser_->GetPluginSummary(pluginName); dprintf(fd, "Following events processed By Plugin %s:\n", pluginName.c_str()); for (auto &log : logList) { dprintf(fd, " %s.\n", log.c_str()); } dprintf(fd, "Dump Plugin Usage Done.\n\n"); } void HiviewService::DumpThreadUsageInfo(int fd) const { auto &platform = HiviewPlatform::GetInstance(); auto const &curThreadMap = platform.GetWorkLoopMap(); dprintf(fd, "Start Dump ThreadInfo:\n"); for (auto const &entry : curThreadMap) { if (entry.second != nullptr) { std::string name = entry.second->GetName(); DumpThreadUsageInfo(fd, name); } } dprintf(fd, "Dump ThreadInfo Done.\n\n"); } void HiviewService::DumpThreadUsageInfo(int fd, const std::string &threadName) const { if (parser_ == nullptr) { return; } auto logList = parser_->GetThreadSummary(threadName); dprintf(fd, "Following events processed on Thread %s:\n", threadName.c_str()); for (auto &log : logList) { dprintf(fd, " %s.\n", log.c_str()); } } void HiviewService::DumpPipelineUsageInfo(int fd) const { auto &platform = HiviewPlatform::GetInstance(); auto const &curPipelineMap = platform.GetPipelineMap(); dprintf(fd, "Start Dump Pipeline Info:\n"); for (auto const &entry : curPipelineMap) { auto pipeline = entry.first; DumpPipelineUsageInfo(fd, pipeline); } } void HiviewService::DumpPipelineUsageInfo(int fd, const std::string &pipelineName) const { if (parser_ == nullptr) { return; } auto logList = parser_->GetPipelineSummary(pipelineName); dprintf(fd, "Following events processed on Pipeline %s:\n", pipelineName.c_str()); for (auto &log : logList) { dprintf(fd, " %s.\n", log.c_str()); } dprintf(fd, "Dump Pipeline Usage Info Done.\n\n"); } void HiviewService::PrintUsage(int fd) const { dprintf(fd, "Hiview Plugin Platform dump options:\n"); dprintf(fd, "hidumper hiviewdfx [-d(etail)]\n"); dprintf(fd, " [-p(lugin) pluginName]\n"); } int32_t HiviewService::CopyFile(const std::string& srcFilePath, const std::string& destFilePath) { int srcFd = open(srcFilePath.c_str(), O_RDONLY); if (srcFd == -1) { HIVIEW_LOGE("failed to open source file, src=%{public}s", StringUtil::HideSnInfo(srcFilePath).c_str()); return ERR_DEFAULT; } struct stat st{}; if (fstat(srcFd, &st) == -1) { HIVIEW_LOGE("failed to stat file."); close(srcFd); return ERR_DEFAULT; } int destFd = open(destFilePath.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH); if (destFd == -1) { HIVIEW_LOGE("failed to open destination file, des=%{public}s", StringUtil::HideSnInfo(destFilePath).c_str()); close(srcFd); return ERR_DEFAULT; } off_t offset = 0; int cycleNum = 0; while (offset < st.st_size) { size_t count = static_cast((st.st_size - offset) > SSIZE_MAX ? SSIZE_MAX : st.st_size - offset); ssize_t ret = sendfile(destFd, srcFd, &offset, count); if (cycleNum > 0) { HIVIEW_LOGI("sendfile cycle num:%{public}d, ret:%{public}zd, offset:%{public}lld, size:%{public}lld", cycleNum, ret, static_cast(offset), static_cast(st.st_size)); } cycleNum++; if (ret < 0 || offset > st.st_size) { HIVIEW_LOGE("sendfile fail, ret:%{public}zd, offset:%{public}lld, size:%{public}lld", ret, static_cast(offset), static_cast(st.st_size)); close(srcFd); close(destFd); return ERR_DEFAULT; } } close(srcFd); close(destFd); return 0; } int32_t HiviewService::Copy(const std::string& srcFilePath, const std::string& destFilePath) { return CopyFile(srcFilePath, destFilePath); } int32_t HiviewService::Move(const std::string& srcFilePath, const std::string& destFilePath) { int copyResult = CopyFile(srcFilePath, destFilePath); if (copyResult != 0) { HIVIEW_LOGW("copy file failed, result: %{public}d", copyResult); return copyResult; } bool result = FileUtil::RemoveFile(srcFilePath); HIVIEW_LOGI("move file, delete src result: %{public}d", result); if (!result) { bool destResult = FileUtil::RemoveFile(destFilePath); HIVIEW_LOGI("move file, delete dest result: %{public}d", destResult); return ERR_DEFAULT; } return 0; } int32_t HiviewService::Remove(const std::string& filePath) { bool result = FileUtil::RemoveFile(filePath); HIVIEW_LOGI("remove file, result:%{public}d", result); return 0; } CollectResult HiviewService::OpenSnapshotTrace(const std::vector& tagGroups) { #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE return {UcError::FEATURE_CLOSED}; #else TraceRet openRet = TraceStateMachine::GetInstance().OpenTrace(TraceScenario::TRACE_COMMAND, tagGroups); return {GetUcError(openRet)}; #endif } CollectResult> HiviewService::DumpSnapshotTrace(UCollect::TraceClient client) { #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE return {UcError::FEATURE_CLOSED}; #else HIVIEW_LOGI("client:[%{public}d] dump trace in snapshot mode.", static_cast(client)); CollectResult> result; auto traceStrategy = TraceFactory::CreateTraceStrategy(client, 0, static_cast(0)); if (traceStrategy == nullptr) { HIVIEW_LOGE("Create traceStrategy error client:%{public}d", static_cast(client)); return {UcError::UNSUPPORT}; } TraceRet dumpRet = traceStrategy->DoDump(result.data); result.retCode = GetUcError(dumpRet); return result; #endif } CollectResult HiviewService::OpenRecordingTrace(const std::string& tags) { #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE return {UcError::FEATURE_CLOSED}; #else TraceRet openRet = TraceStateMachine::GetInstance().OpenTrace(TraceScenario::TRACE_COMMAND, tags); return {GetUcError(openRet)}; #endif } CollectResult HiviewService::RecordingTraceOn() { #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE return {UcError::FEATURE_CLOSED}; #else TraceRet ret = TraceStateMachine::GetInstance().TraceDropOn(TraceScenario::TRACE_COMMAND); return {GetUcError(ret)}; #endif } CollectResult> HiviewService::RecordingTraceOff() { #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE return {UcError::FEATURE_CLOSED}; #else TraceRetInfo traceRetInfo; TraceRet ret = TraceStateMachine::GetInstance().TraceDropOff(TraceScenario::TRACE_COMMAND, traceRetInfo); CollectResult> result(GetUcError(ret)); result.data = traceRetInfo.outputFiles; return result; #endif } CollectResult HiviewService::CloseTrace() { #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE return {UcError::FEATURE_CLOSED}; #else TraceRet ret = TraceStateMachine::GetInstance().CloseTrace(TraceScenario::TRACE_COMMAND); return {GetUcError(ret)}; #endif } #ifdef UNIFIED_COLLECTOR_TRACE_ENABLE static std::shared_ptr InnerCreateAppCallerEvent(UCollectClient::AppCaller &appCaller, const std::string &eventName) { std::shared_ptr appCallerEvent = std::make_shared("HiViewService"); appCallerEvent->messageType_ = Event::MessageType::PLUGIN_MAINTENANCE; appCallerEvent->eventName_ = eventName; appCallerEvent->isBusinessJank_ = appCaller.isBusinessJank; appCallerEvent->bundleName_ = appCaller.bundleName; appCallerEvent->bundleVersion_ = appCaller.bundleVersion; appCallerEvent->uid_ = appCaller.uid; appCallerEvent->pid_ = appCaller.pid; appCallerEvent->happenTime_ = static_cast(appCaller.happenTime); appCallerEvent->beginTime_ = appCaller.beginTime; appCallerEvent->endTime_ = appCaller.endTime; appCallerEvent->taskBeginTime_ = static_cast(TimeUtil::GetMilliseconds()); appCallerEvent->taskEndTime_ = appCallerEvent->taskBeginTime_; appCallerEvent->resultCode_ = UCollect::UcError::SUCCESS; appCallerEvent->foreground_ = appCaller.foreground; appCallerEvent->threadName_ = appCaller.threadName; return appCallerEvent; } bool HiviewService::InnerHasCallAppTrace(std::shared_ptr appCallerEvent) { return TraceFlowController(ClientName::APP).HasCallOnceToday(appCallerEvent->uid_, appCallerEvent->happenTime_); } CollectResult HiviewService::InnerResponseStartAppTrace(UCollectClient::AppCaller &appCaller) { auto appCallerEvent = InnerCreateAppCallerEvent(appCaller, UCollectUtil::START_APP_TRACE); if (InnerHasCallAppTrace(appCallerEvent)) { HIVIEW_LOGW("deny: already capture trace uid=%{public}d pid=%{public}d", appCallerEvent->uid_, appCallerEvent->pid_); return {UCollect::UcError::HAD_CAPTURED_TRACE}; } TraceRet ret = TraceStateMachine::GetInstance().OpenDynamicTrace(appCallerEvent->pid_); if (!ret.IsSuccess()) { return {GetUcError(ret)}; } if (!HiviewPlatform::GetInstance().PostSyncEventToTarget(nullptr, UCollectUtil::UCOLLECTOR_PLUGIN, appCallerEvent)) { HIVIEW_LOGE("post event failed"); return {UCollect::UcError::SYSTEM_ERROR}; } return {UCollect::UcError::SUCCESS}; } CollectResult HiviewService::InnerResponseDumpAppTrace(UCollectClient::AppCaller &appCaller) { CollectResult> result; auto strategy = TraceFactory::CreateAppStrategy(InnerCreateAppCallerEvent(appCaller, UCollectUtil::DUMP_APP_TRACE)); return {GetUcError(strategy->DoDump(result.data))}; } #endif CollectResult HiviewService::CaptureDurationTrace(UCollectClient::AppCaller &appCaller) { #ifndef UNIFIED_COLLECTOR_TRACE_ENABLE return {UcError::FEATURE_CLOSED}; #else if (appCaller.actionId == UCollectClient::ACTION_ID_START_TRACE) { return InnerResponseStartAppTrace(appCaller); } else if (appCaller.actionId == UCollectClient::ACTION_ID_DUMP_TRACE) { return InnerResponseDumpAppTrace(appCaller); } else { HIVIEW_LOGE("invalid param %{public}d, can not capture trace for uid=%{public}d, pid=%{public}d", appCaller.actionId, appCaller.uid, appCaller.pid); return {UCollect::UcError::INVALID_ACTION_ID}; } #endif } CollectResult HiviewService::GetSysCpuUsage() { CollectResult cpuUsageRet = cpuCollector_->GetSysCpuUsage(); if (cpuUsageRet.retCode != UCollect::UcError::SUCCESS) { HIVIEW_LOGE("failed to collect system cpu usage"); } return cpuUsageRet; } CollectResult HiviewService::SetAppResourceLimit(UCollectClient::MemoryCaller& memoryCaller) { std::string eventName = "APP_RESOURCE_LIMIT"; SysEventCreator sysEventCreator("HIVIEWDFX", eventName, SysEventCreator::FAULT); sysEventCreator.SetKeyValue("PID", memoryCaller.pid); sysEventCreator.SetKeyValue("RESOURCE_TYPE", memoryCaller.resourceType); sysEventCreator.SetKeyValue("RESOURCE_LIMIT", memoryCaller.limitValue); sysEventCreator.SetKeyValue("RESOURCE_DEBUG_ENABLE", memoryCaller.enabledDebugLog ? "true" : "false"); auto sysEvent = std::make_shared(eventName, nullptr, sysEventCreator); std::shared_ptr event = std::dynamic_pointer_cast(sysEvent); if (!HiviewPlatform::GetInstance().PostSyncEventToTarget(nullptr, "XPower", event)) { HIVIEW_LOGE("%{public}s failed for pid=%{public}d error", eventName.c_str(), memoryCaller.pid); return {UCollect::UcError::SYSTEM_ERROR}; } return {UCollect::UcError::SUCCESS}; } CollectResult HiviewService::SetSplitMemoryValue(std::vector& memList) { std::vector pidList; std::vector resourceList; for (auto it : memList) { pidList.push_back(it.pid); resourceList.push_back(it.limitValue); } std::string eventName = "AVCODEC_SPLITMEMORY"; SysEventCreator sysEventCreator("HIVIEWDFX", eventName, SysEventCreator::FAULT); sysEventCreator.SetKeyValue("PID_LIST", pidList); sysEventCreator.SetKeyValue("RESOURCE_LIST", resourceList); auto sysEvent = std::make_shared(eventName, nullptr, sysEventCreator); auto event = std::dynamic_pointer_cast(sysEvent); if (!HiviewPlatform::GetInstance().PostSyncEventToTarget(nullptr, "XPower", event)) { HIVIEW_LOGE("%{public}s failed", eventName.c_str()); return {UCollect::UcError::SYSTEM_ERROR}; } return {UCollect::UcError::SUCCESS}; } CollectResult HiviewService::GetGraphicUsage(int32_t pid) { return graphicMemoryCollector_->GetGraphicUsage(pid, GraphicType::TOTAL, true); } } // namespace HiviewDFX } // namespace OHOS