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
39 using namespace std;
40 namespace OHOS {
41 namespace HiviewDFX {
42 namespace {
43 const std::string DUMPMGR_CPU_SERVICE_NAME = "HiDumperCpuService";
44 static constexpr size_t LOAD_AVG_INFO_COUNT = 3;
45 static constexpr int PROC_CPU_LENGTH = 256;
46 static constexpr double HUNDRED_PERCENT_VALUE = 100.00;
47 static constexpr long unsigned THOUSAND_PERCENT_VALUE = 1000;
48 static constexpr int INVALID_PID = -1;
49 static const int TM_START_YEAR = 1900;
50 static const int DEC_SYSTEM_VALUE = 10;
51 static const int AVG_INFO_SUBSTR_LENGTH = 4;
52 static std::shared_ptr<OHOS::HiviewDFX::UCollectUtil::CpuCollector> g_collector;
53 }
DumpManagerCpuService()54 DumpManagerCpuService::DumpManagerCpuService() : SystemAbility(DFX_SYS_HIDUMPER_CPU_ABILITY_ID, true)
55 {
56 }
57
~DumpManagerCpuService()58 DumpManagerCpuService::~DumpManagerCpuService()
59 {
60 }
61
OnStart()62 void 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
Request(DumpCpuData & dumpCpuData)73 int32_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
InitParam(DumpCpuData & dumpCpuData)90 void 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
ResetParam()100 void DumpManagerCpuService::ResetParam()
101 {
102 curCPUInfo_.reset();
103 curProcs_.clear();
104 if (cpuUsagePid_ != INVALID_PID) {
105 curSpecProc_.reset();
106 }
107 }
108
DumpCpuUsageData()109 int 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
GetCpuUsageByPid(int32_t pid,double & cpuUsage)146 int 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
ReadLoadAvgInfo(std::string & info)164 DumpStatus 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
GetSysCPUInfo(std::shared_ptr<CPUInfo> & cpuInfo)191 bool 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
GetAllProcInfo(std::vector<std::shared_ptr<ProcInfo>> & procInfos)225 bool 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
GetSingleProcInfo(int pid,std::shared_ptr<ProcInfo> & specProc)246 bool 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
GetDateAndTime(uint64_t timeStamp,std::string & dateTime)267 bool 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
CreateDumpTimeString(const std::string & startTime,const std::string & endTime,std::string & timeStr)304 void 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
AddStrLineToDumpInfo(const std::string & strLine)314 void 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
CreateCPUStatString(std::string & str)321 void 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
DumpProcInfo()342 void 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
SortProcInfo(std::shared_ptr<ProcInfo> & left,std::shared_ptr<ProcInfo> & right)382 bool 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
StartService()399 void 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
HasDumpPermission() const416 bool 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