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