1/* 2 * Copyright (c) 2023 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#include "dump_manager_cpu_service.h" 16#include <file_ex.h> 17#include <if_system_ability_manager.h> 18#include <ipc_skeleton.h> 19#include <iservice_registry.h> 20#include <string_ex.h> 21#include <system_ability_definition.h> 22#include <thread> 23#include <unistd.h> 24#include "securec.h" 25 26#include "accesstoken_kit.h" 27#include "common/dumper_constant.h" 28#include "cpu_collector.h" 29#include "datetime_ex.h" 30#include "dump_log_manager.h" 31#include "dump_utils.h" 32#include "hilog_wrapper.h" 33#include "inner/dump_service_id.h" 34#include "manager/dump_implement.h" 35#include "token_setproc.h" 36#include "util/string_utils.h" 37#include "util/file_utils.h" 38 39using namespace std; 40namespace OHOS { 41namespace HiviewDFX { 42namespace { 43const std::string DUMPMGR_CPU_SERVICE_NAME = "HiDumperCpuService"; 44static constexpr size_t LOAD_AVG_INFO_COUNT = 3; 45static constexpr int PROC_CPU_LENGTH = 256; 46static constexpr double HUNDRED_PERCENT_VALUE = 100.00; 47static constexpr long unsigned THOUSAND_PERCENT_VALUE = 1000; 48static constexpr int INVALID_PID = -1; 49static const int TM_START_YEAR = 1900; 50static const int DEC_SYSTEM_VALUE = 10; 51static const int AVG_INFO_SUBSTR_LENGTH = 4; 52static std::shared_ptr<OHOS::HiviewDFX::UCollectUtil::CpuCollector> g_collector; 53} 54DumpManagerCpuService::DumpManagerCpuService() : SystemAbility(DFX_SYS_HIDUMPER_CPU_ABILITY_ID, true) 55{ 56} 57 58DumpManagerCpuService::~DumpManagerCpuService() 59{ 60} 61 62void DumpManagerCpuService::OnStart() 63{ 64 DUMPER_HILOGI(MODULE_CPU_SERVICE, "on start"); 65 if (started_) { 66 DUMPER_HILOGE(MODULE_CPU_SERVICE, "it's ready, nothing to do."); 67 return; 68 } 69 g_collector = OHOS::HiviewDFX::UCollectUtil::CpuCollector::Create(); 70 started_ = true; 71} 72 73int32_t DumpManagerCpuService::Request(DumpCpuData &dumpCpuData) 74{ 75 DUMPER_HILOGI(MODULE_CPU_SERVICE, "enter"); 76 static std::mutex mutex_; 77 unique_lock<mutex> lock(mutex_); 78 InitParam(dumpCpuData); 79 if (!HasDumpPermission()) { 80 DUMPER_HILOGE(MODULE_SERVICE, 81 "No ohos.permission.DUMP permission to acccess hidumper cpuservice, please check!"); 82 return DumpStatus::DUMP_NOPERMISSION; 83 } 84 int32_t ret = DumpCpuUsageData(); 85 dumpCpuData.dumpCPUDatas_ = *dumpCPUDatas_; 86 ResetParam(); 87 return ret; 88} 89 90void DumpManagerCpuService::InitParam(DumpCpuData &dumpCpuData) 91{ 92 cpuUsagePid_ = dumpCpuData.cpuUsagePid_; 93 if (cpuUsagePid_ != INVALID_PID) { 94 curSpecProc_ = std::make_shared<ProcInfo>(); 95 } 96 curCPUInfo_ = std::make_shared<CPUInfo>(); 97 dumpCPUDatas_ = std::make_shared<std::vector<std::vector<std::string>>>(dumpCpuData.dumpCPUDatas_); 98} 99 100void DumpManagerCpuService::ResetParam() 101{ 102 curCPUInfo_.reset(); 103 curProcs_.clear(); 104 if (cpuUsagePid_ != INVALID_PID) { 105 curSpecProc_.reset(); 106 } 107} 108 109int DumpManagerCpuService::DumpCpuUsageData() 110{ 111 if (!GetSysCPUInfo(curCPUInfo_)) { 112 return DumpStatus::DUMP_FAIL; 113 } 114 115 if (cpuUsagePid_ != INVALID_PID) { 116 if (!GetSingleProcInfo(cpuUsagePid_, curSpecProc_)) { 117 return DumpStatus::DUMP_FAIL; 118 } 119 } else { 120 if (!GetAllProcInfo(curProcs_)) { 121 return DumpStatus::DUMP_FAIL; 122 } 123 } 124 std::string avgInfo; 125 if (ReadLoadAvgInfo(avgInfo) != DumpStatus::DUMP_OK) { 126 return DumpStatus::DUMP_FAIL; 127 } 128 AddStrLineToDumpInfo(avgInfo); 129 130 std::string startTime; 131 std::string endTime; 132 GetDateAndTime(startTime_ / THOUSAND_PERCENT_VALUE, startTime); 133 GetDateAndTime(endTime_ / THOUSAND_PERCENT_VALUE, endTime); 134 std::string dumpTimeStr; 135 CreateDumpTimeString(startTime, endTime, dumpTimeStr); 136 AddStrLineToDumpInfo(dumpTimeStr); 137 138 std::string cpuStatStr; 139 CreateCPUStatString(cpuStatStr); 140 AddStrLineToDumpInfo(cpuStatStr); 141 142 DumpProcInfo(); 143 return DumpStatus::DUMP_OK; 144} 145 146int DumpManagerCpuService::GetCpuUsageByPid(int32_t pid, double &cpuUsage) 147{ 148 static std::mutex mutex_; 149 unique_lock<mutex> lock(mutex_); 150 if (g_collector == nullptr) { 151 g_collector = OHOS::HiviewDFX::UCollectUtil::CpuCollector::Create(); 152 } 153 if (pid != INVALID_PID) { 154 std::shared_ptr<ProcInfo> singleProcInfo = std::make_shared<ProcInfo>(); 155 if (!GetSingleProcInfo(pid, singleProcInfo)) { 156 return DumpStatus::DUMP_FAIL; 157 } 158 cpuUsage = singleProcInfo->totalUsage / HUNDRED_PERCENT_VALUE; 159 } 160 DUMPER_HILOGD(MODULE_CPU_SERVICE, "GetCpuUsageByPid end, pid = %{public}d, cpuUsage = %{public}f", pid, cpuUsage); 161 return DumpStatus::DUMP_OK; 162} 163 164DumpStatus DumpManagerCpuService::ReadLoadAvgInfo(std::string &info) 165{ 166 CollectResult<OHOS::HiviewDFX::SysCpuLoad> collectResult = g_collector->CollectSysCpuLoad(); 167 if (collectResult.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) { 168 DUMPER_HILOGE(MODULE_CPU_SERVICE, "collect system cpu load error, ret:%{public}d", collectResult.retCode); 169 return DumpStatus::DUMP_FAIL; 170 } 171 std::vector<std::string> avgLoadInfo; 172 avgLoadInfo.push_back(std::string(std::to_string(collectResult.data.avgLoad1)).substr(0, AVG_INFO_SUBSTR_LENGTH)); 173 avgLoadInfo.push_back(std::string(std::to_string(collectResult.data.avgLoad5)).substr(0, AVG_INFO_SUBSTR_LENGTH)); 174 avgLoadInfo.push_back(std::string(std::to_string(collectResult.data.avgLoad15)).substr(0, AVG_INFO_SUBSTR_LENGTH)); 175 176 info = "Load average:"; 177 for (size_t i = 0; i < LOAD_AVG_INFO_COUNT; i++) { 178 info.append(" "); 179 info.append(avgLoadInfo[i]); 180 if (i == LOAD_AVG_INFO_COUNT - 1) { 181 info.append(";"); 182 } else { 183 info.append(" /"); 184 } 185 } 186 info.append(" the cpu load average in 1 min, 5 min and 15 min"); 187 DUMPER_HILOGD(MODULE_CPU_SERVICE, "info is %{public}s", info.c_str()); 188 return DumpStatus::DUMP_OK; 189} 190 191bool DumpManagerCpuService::GetSysCPUInfo(std::shared_ptr<CPUInfo> &cpuInfo) 192{ 193 if (cpuInfo == nullptr) { 194 return false; 195 } 196 auto collectResult = g_collector->CollectProcessCpuStatInfos(false); 197 if (collectResult.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS || collectResult.data.empty()) { 198 DUMPER_HILOGE(MODULE_CPU_SERVICE, "collect process cpu stat info error"); 199 return false; 200 } 201 202 CollectResult<OHOS::HiviewDFX::SysCpuUsage> result = g_collector->CollectSysCpuUsage(false); 203 if (result.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) { 204 DUMPER_HILOGE(MODULE_CPU_SERVICE, "collect system cpu usage error,retCode is %{public}d", result.retCode); 205 return false; 206 } 207 const OHOS::HiviewDFX::SysCpuUsage& sysCpuUsage = result.data; 208 startTime_ = sysCpuUsage.startTime; 209 endTime_ = sysCpuUsage.endTime; 210 211 for (const auto& oneCpuInfo : sysCpuUsage.cpuInfos) { 212 cpuInfo->userUsage = oneCpuInfo.userUsage; 213 cpuInfo->niceUsage = oneCpuInfo.niceUsage; 214 cpuInfo->systemUsage = oneCpuInfo.systemUsage; 215 cpuInfo->idleUsage = oneCpuInfo.idleUsage; 216 cpuInfo->ioWaitUsage = oneCpuInfo.ioWaitUsage; 217 cpuInfo->irqUsage = oneCpuInfo.irqUsage; 218 cpuInfo->softIrqUsage = oneCpuInfo.softIrqUsage; 219 break; 220 } 221 222 return true; 223} 224 225bool DumpManagerCpuService::GetAllProcInfo(std::vector<std::shared_ptr<ProcInfo>> &procInfos) 226{ 227 auto collectResult = g_collector->CollectProcessCpuStatInfos(false); 228 if (collectResult.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS || collectResult.data.empty()) { 229 DUMPER_HILOGE(MODULE_CPU_SERVICE, "collect process cpu stat info error"); 230 return false; 231 } 232 for (const auto& cpuInfo : collectResult.data) { 233 std::shared_ptr<ProcInfo> ptrProcInfo = std::make_shared<ProcInfo>();; 234 ptrProcInfo->pid = std::to_string(cpuInfo.pid); 235 ptrProcInfo->comm = cpuInfo.procName; 236 ptrProcInfo->minflt = std::to_string(cpuInfo.minFlt); 237 ptrProcInfo->majflt = std::to_string(cpuInfo.majFlt); 238 ptrProcInfo->userSpaceUsage = cpuInfo.uCpuUsage * HUNDRED_PERCENT_VALUE; 239 ptrProcInfo->sysSpaceUsage = cpuInfo.sCpuUsage * HUNDRED_PERCENT_VALUE; 240 ptrProcInfo->totalUsage = cpuInfo.cpuUsage * HUNDRED_PERCENT_VALUE; 241 procInfos.push_back(ptrProcInfo); 242 } 243 return true; 244} 245 246bool DumpManagerCpuService::GetSingleProcInfo(int pid, std::shared_ptr<ProcInfo> &specProc) 247{ 248 if (specProc == nullptr) { 249 return false; 250 } 251 252 CollectResult<OHOS::HiviewDFX::ProcessCpuStatInfo> collectResult = g_collector->CollectProcessCpuStatInfo(pid); 253 if (collectResult.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) { 254 DUMPER_HILOGE(MODULE_CPU_SERVICE, "collect system cpu usage error,ret:%{public}d", collectResult.retCode); 255 return false; 256 } 257 specProc->comm = collectResult.data.procName; 258 specProc->pid = std::to_string(collectResult.data.pid); 259 specProc->minflt = std::to_string(collectResult.data.minFlt); 260 specProc->majflt = std::to_string(collectResult.data.majFlt); 261 specProc->userSpaceUsage = collectResult.data.uCpuUsage * HUNDRED_PERCENT_VALUE; 262 specProc->sysSpaceUsage = collectResult.data.sCpuUsage * HUNDRED_PERCENT_VALUE; 263 specProc->totalUsage = collectResult.data.cpuUsage * HUNDRED_PERCENT_VALUE; 264 return true; 265} 266 267bool DumpManagerCpuService::GetDateAndTime(uint64_t timeStamp, std::string &dateTime) 268{ 269 time_t time = static_cast<time_t>(timeStamp); 270 struct tm timeData = {0}; 271 localtime_r(&time, &timeData); 272 273 dateTime = " "; 274 dateTime.append(std::to_string(TM_START_YEAR + timeData.tm_year)); 275 dateTime.append("-"); 276 if (1 + timeData.tm_mon < DEC_SYSTEM_VALUE) { 277 dateTime.append(std::to_string(0)); 278 } 279 dateTime.append(std::to_string(1 + timeData.tm_mon)); 280 dateTime.append("-"); 281 if (timeData.tm_mday < DEC_SYSTEM_VALUE) { 282 dateTime.append(std::to_string(0)); 283 } 284 dateTime.append(std::to_string(timeData.tm_mday)); 285 dateTime.append(" "); 286 if (timeData.tm_hour < DEC_SYSTEM_VALUE) { 287 dateTime.append(std::to_string(0)); 288 } 289 dateTime.append(std::to_string(timeData.tm_hour)); 290 dateTime.append(":"); 291 if (timeData.tm_min < DEC_SYSTEM_VALUE) { 292 dateTime.append(std::to_string(0)); 293 } 294 dateTime.append(std::to_string(timeData.tm_min)); 295 dateTime.append(":"); 296 if (timeData.tm_sec < DEC_SYSTEM_VALUE) { 297 dateTime.append(std::to_string(0)); 298 } 299 dateTime.append(std::to_string(timeData.tm_sec)); 300 return true; 301} 302 303 304void DumpManagerCpuService::CreateDumpTimeString(const std::string &startTime, 305 const std::string &endTime, std::string &timeStr) 306{ 307 DUMPER_HILOGD(MODULE_CPU_SERVICE, "start:%{public}s, end:%{public}s", startTime.c_str(), endTime.c_str()); 308 timeStr = "CPU usage from"; 309 timeStr.append(startTime); 310 timeStr.append(" to"); 311 timeStr.append(endTime); 312} 313 314void DumpManagerCpuService::AddStrLineToDumpInfo(const std::string &strLine) 315{ 316 std::vector<std::string> vec; 317 vec.push_back(strLine); 318 dumpCPUDatas_->push_back(vec); 319} 320 321void DumpManagerCpuService::CreateCPUStatString(std::string &str) 322{ 323 double userSpaceUsage = (curCPUInfo_->userUsage + curCPUInfo_->niceUsage) * HUNDRED_PERCENT_VALUE; 324 double sysSpaceUsage = curCPUInfo_->systemUsage * HUNDRED_PERCENT_VALUE; 325 double iowUsage = curCPUInfo_->ioWaitUsage * HUNDRED_PERCENT_VALUE; 326 double irqUsage = (curCPUInfo_->irqUsage + curCPUInfo_->softIrqUsage) * HUNDRED_PERCENT_VALUE; 327 double idleUsage = curCPUInfo_->idleUsage * HUNDRED_PERCENT_VALUE; 328 double totalUsage = userSpaceUsage + sysSpaceUsage; 329 330 char format[PROC_CPU_LENGTH] = {0}; 331 int ret = sprintf_s(format, PROC_CPU_LENGTH, 332 "Total: %.2f%%; User Space: %.2f%%; Kernel Space: %.2f%%; " 333 "iowait: %.2f%%; irq: %.2f%%; idle: %.2f%%", 334 totalUsage, userSpaceUsage, sysSpaceUsage, iowUsage, irqUsage, idleUsage); 335 if (ret < 0) { 336 DUMPER_HILOGE(MODULE_CPU_SERVICE, "create process cpu info failed!."); 337 return; 338 } 339 str = std::string(format); 340} 341 342void DumpManagerCpuService::DumpProcInfo() 343{ 344 std::vector<std::shared_ptr<ProcInfo>> sortedInfos; 345 sortedInfos.assign(curProcs_.begin(), curProcs_.end()); 346 std::sort(sortedInfos.begin(), sortedInfos.end(), SortProcInfo); 347 348 AddStrLineToDumpInfo("Details of Processes:"); 349 AddStrLineToDumpInfo(" PID Total Usage User Space Kernel Space Page Fault Minor" 350 " Page Fault Major Name"); 351 if (cpuUsagePid_ != INVALID_PID) { 352 char format[PROC_CPU_LENGTH] = {0}; 353 int ret = sprintf_s(format, PROC_CPU_LENGTH, 354 " %-5s %6.2f%% %6.2f%%" 355 " %6.2f%% %8s %8s %-15s", 356 (curSpecProc_->pid).c_str(), curSpecProc_->totalUsage, 357 curSpecProc_->userSpaceUsage, curSpecProc_->sysSpaceUsage, 358 (curSpecProc_->minflt).c_str(), (curSpecProc_->majflt).c_str(), 359 (curSpecProc_->comm).c_str()); 360 AddStrLineToDumpInfo(std::string(format)); 361 if (ret < 0) { 362 DUMPER_HILOGE(MODULE_CPU_SERVICE, "Dump process %{public}d cpu info failed!.", cpuUsagePid_); 363 } 364 return; 365 } 366 for (size_t i = 0; i < sortedInfos.size(); i++) { 367 char format[PROC_CPU_LENGTH] = {0}; 368 int ret = sprintf_s(format, PROC_CPU_LENGTH, 369 " %-5s %6.2f%% %6.2f%%" 370 " %6.2f%% %8s %8s %-15s", 371 (sortedInfos[i]->pid).c_str(), sortedInfos[i]->totalUsage, 372 sortedInfos[i]->userSpaceUsage, sortedInfos[i]->sysSpaceUsage, 373 (sortedInfos[i]->minflt).c_str(), (sortedInfos[i]->majflt).c_str(), 374 (sortedInfos[i]->comm).c_str()); 375 if (ret < 0) { 376 continue; 377 } 378 AddStrLineToDumpInfo(std::string(format)); 379 } 380} 381 382bool DumpManagerCpuService::SortProcInfo(std::shared_ptr<ProcInfo> &left, std::shared_ptr<ProcInfo> &right) 383{ 384 if (right->totalUsage != left->totalUsage) { 385 return right->totalUsage < left->totalUsage; 386 } 387 if (right->userSpaceUsage != left->userSpaceUsage) { 388 return right->userSpaceUsage < left->userSpaceUsage; 389 } 390 if (right->sysSpaceUsage != left->sysSpaceUsage) { 391 return right->sysSpaceUsage < left->sysSpaceUsage; 392 } 393 if (right->pid.length() != left->pid.length()) { 394 return right->pid.length() < left->pid.length(); 395 } 396 return (right->pid.compare(left->pid) < 0); 397} 398 399void DumpManagerCpuService::StartService() 400{ 401 sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); 402 if (samgr == nullptr) { 403 DUMPER_HILOGE(MODULE_CPU_SERVICE, "failed to find SystemAbilityManager."); 404 return; 405 } 406 auto dumpManagerCpuService = DumpDelayedSpSingleton<DumpManagerCpuService>::GetInstance(); 407 int ret = samgr->AddSystemAbility(DFX_SYS_HIDUMPER_CPU_ABILITY_ID, dumpManagerCpuService); 408 if (ret != 0) { 409 DUMPER_HILOGE(MODULE_CPU_SERVICE, "failed to add sys dump cpu service ability."); 410 return; 411 } 412 OnStart(); 413} 414 415// Authenticate dump permissions 416bool DumpManagerCpuService::HasDumpPermission() const 417{ 418 uint32_t callingTokenID = IPCSkeleton::GetCallingTokenID(); 419 int res = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callingTokenID, "ohos.permission.DUMP"); 420 if (res != Security::AccessToken::PermissionState::PERMISSION_GRANTED) { 421 DUMPER_HILOGI(MODULE_SERVICE, "No dump permission, please check!"); 422 return false; 423 } 424 return true; 425} 426} // namespace HiviewDFX 427} // namespace OHOS 428