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