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