• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 
16 #include "system_info.h"
17 
18 #include <dirent.h>
19 #include <unistd.h>
20 
21 #include <fstream>
22 #include <sstream>
23 #include <string>
24 #include <thread>
25 
26 #include "securec.h"
27 #include "sensors_errors.h"
28 
29 namespace OHOS {
30 namespace Sensors {
31 namespace SYSTEM_INFO {
32 using namespace OHOS::HiviewDFX;
33 namespace {
34 constexpr HiLogLabel LABEL = { LOG_CORE, OHOS::Sensors::SENSOR_LOG_DOMAIN, "SYSTEM_INFO" };
35 constexpr int32_t LOCATION = 14;
36 constexpr int32_t TIME_WAIT_FOR_OP = 1000;
37 constexpr int32_t DEFAULT_PID = -1;
38 } // namespace
39 
CHK_RATE(double rate)40 inline double CHK_RATE(double rate)
41 {
42     return (rate > CPU_USAGE_MAX ? CPU_USAGE_MAX : rate);
43 }
44 
GetTaskPidFile(const std::string & process_name)45 int32_t CpuInfo::GetTaskPidFile(const std::string& process_name)
46 {
47     int32_t pid = DEFAULT_PID;
48     static const std::string procPath = "/proc";
49     DIR* dir = ::opendir(procPath.c_str());
50     if (dir == nullptr) {
51         SEN_HILOGE("Failed to open path:%{public}s", procPath.c_str());
52         return DEFAULT_PID;
53     }
54     struct dirent* pidFile;
55     while ((pidFile = ::readdir(dir)) != nullptr) {
56         if ((::strcmp(pidFile->d_name, ".") == 0) || (::strcmp(pidFile->d_name, "..") == 0)) {
57             continue;
58         }
59         if (pidFile->d_type != DT_DIR) {
60             continue;
61         }
62         const std::string path = procPath + "/" + pidFile->d_name + "/status";
63         std::ifstream filePath(path);
64         if (!filePath.is_open()) {
65             continue;
66         }
67         std::string strLine;
68         std::getline(filePath, strLine);
69         if (strLine.empty()) {
70             filePath.close();
71             continue;
72         }
73         if ((strLine.find(process_name)) == std::string::npos) {
74             filePath.close();
75             continue;
76         }
77         while (std::getline(filePath, strLine)) {
78             if ((strLine.find("Pid")) != std::string::npos) {
79                 if (sscanf_s(strLine.c_str(), "%*s%d", &pid) == -1) {
80                     SEN_HILOGE("sscanf_s failed");
81                 }
82                 break;
83             }
84         }
85         filePath.close();
86         break;
87     }
88     ::closedir(dir);
89 
90     return pid;
91 }
92 
GetTaskPidCmd(const std::string & process_name,int32_t flag,std::string user)93 int32_t CpuInfo::GetTaskPidCmd(const std::string& process_name, int32_t flag, std::string user)
94 {
95     std::string command;
96     if (flag) {
97         if (user.empty()) {
98             user = ::getlogin();
99         }
100         command = "pgrep " + process_name + " -u " + user;
101     } else {
102         command = "pidof -s " + process_name;
103     }
104     ::FILE *fp = nullptr;
105     if ((fp = ::popen(command.c_str(), "r")) == nullptr) {
106         SEN_HILOGE("Failed to open, cmd:%{public}s", command.c_str());
107         fp = nullptr;
108         return DEFAULT_PID;
109     }
110     char buf[100] = { 0 };
111     if (::fgets(buf, sizeof(buf), fp) == nullptr) {
112         SEN_HILOGE("Failed to read content");
113         ::pclose(fp);
114         fp = nullptr;
115         return DEFAULT_PID;
116     }
117     ::pclose(fp);
118     return ::atoi(buf);
119 }
120 
GetProcOccupy(int32_t pid)121 int32_t CpuInfo::GetProcOccupy(int32_t pid)
122 {
123     Proc_Cpu_Occupy info;
124     static const std::string procPath = "/proc/" + std::to_string(pid) + "/stat";
125     std::ifstream file(procPath);
126     if (!file.is_open()) {
127         SEN_HILOGE("Failed to open path:%{public}s", procPath.c_str());
128         return OHOS::Sensors::ERROR;
129     }
130 
131     std::string strLine;
132     std::getline(file, strLine);
133     if (strLine.empty()) {
134         SEN_HILOGE("Failed to read content");
135         file.close();
136         return OHOS::Sensors::ERROR;
137     }
138     file.close();
139 
140     int pos = 1;
141     std::istringstream ss(strLine);
142     while (ss >> strLine) {
143         pos++;
144         if (pos >= LOCATION) {
145             break;
146         }
147     }
148     ss >> info.utime >> info.stime >> info.cutime >> info.cstime;
149     return (info.utime + info.stime + info.cutime + info.cstime);
150 }
151 
GetCpuUsage(const Total_Cpu_Occupy & first,const Total_Cpu_Occupy & second)152 double CpuInfo::GetCpuUsage(const Total_Cpu_Occupy& first, const Total_Cpu_Occupy& second)
153 {
154     unsigned long cpuTime2 = static_cast<unsigned long>(second.user + second.nice + second.system +
155                                                         second.idle + second.lowait + second.irq + second.softirq);
156     unsigned long cpuTime1 = static_cast<unsigned long>(first.user + first.nice + first.system +
157                                                         first.idle + first.lowait + first.irq + first.softirq);
158 
159     double cpu_use = (second.user - first.user) * CPU_USAGE_MAX / (cpuTime2 - cpuTime1);
160     double cpu_sys = (second.system - first.system) * CPU_USAGE_MAX / (cpuTime2 - cpuTime1);
161 
162     return CHK_RATE(cpu_use + cpu_sys);
163 }
164 
GetSystemCpuStatInfo(Total_Cpu_Occupy & info)165 int32_t CpuInfo::GetSystemCpuStatInfo(Total_Cpu_Occupy& info)
166 {
167     std::ifstream statFile("/proc/stat");
168     if (!statFile.is_open()) {
169         SEN_HILOGE("Failed to open config file");
170         return FILE_OPEN_FAIL;
171     }
172     std::string strLine;
173     std::getline(statFile, strLine);
174     if (strLine.empty()) {
175         SEN_HILOGE("No valid content was read");
176         statFile.close();
177         return STREAM_BUF_READ_FAIL;
178     }
179     if ((strLine.find("cpu")) == std::string::npos) {
180         SEN_HILOGE("The keyword was not matched. Procedure");
181         statFile.close();
182         return OHOS::Sensors::ERROR;
183     }
184     std::istringstream ss(strLine);
185     ss >> info.name >> info.user >> info.nice >> info.system >> info.idle >> info.lowait \
186         >> info.irq >> info.softirq >> info.steal >> info.guest >> info.guest_nice;
187 
188     statFile.close();
189     return OHOS::Sensors::SUCCESS;
190 }
191 
GetSystemCpuUsage()192 double CpuInfo::GetSystemCpuUsage()
193 {
194     Total_Cpu_Occupy first {};
195     int32_t ret = GetSystemCpuStatInfo(first);
196     if (ret != OHOS::Sensors::SUCCESS) {
197         SEN_HILOGE("Failed to obtain CPU information, errcode:%{public}d", ret);
198         return CPU_USAGE_UNKONW;
199     }
200     std::this_thread::sleep_for(std::chrono::milliseconds(TIME_WAIT_FOR_OP));
201     Total_Cpu_Occupy second {};
202     ret = GetSystemCpuStatInfo(second);
203     if (ret != OHOS::Sensors::SUCCESS) {
204         SEN_HILOGE("Failed to obtain CPU information, errcode:%{public}d", ret);
205         return CPU_USAGE_UNKONW;
206     }
207 
208     return GetCpuUsage(first, second);
209 }
210 
GetSystemTotalOccupy()211 int64_t CpuInfo::GetSystemTotalOccupy()
212 {
213     int ret = -1;
214     Total_Cpu_Occupy occupy {};
215     if ((ret = GetSystemCpuStatInfo(occupy)) != OHOS::Sensors::SUCCESS) {
216         SEN_HILOGE("Failed to obtain CPU information, errcode:%{public}d", ret);
217         return OHOS::Sensors::ERROR;
218     }
219     return (occupy.user + occupy.nice + occupy.system + occupy.idle);
220 }
221 
GetProcCpuUsage(const std::string & process_name)222 double CpuInfo::GetProcCpuUsage(const std::string& process_name)
223 {
224     int64_t totalTime1 = 0;
225     int64_t totalTime2 = 0;
226     int64_t procTime1 = 0;
227     int64_t procTime2 = 0;
228     int32_t pid = GetTaskPidFile(process_name);
229 
230     if ((totalTime1 = GetSystemTotalOccupy()) == OHOS::Sensors::ERROR) {
231         SEN_HILOGE("Failed to obtain CPU occupy");
232         return CPU_USAGE_UNKONW;
233     }
234     if ((procTime1 = GetProcOccupy(pid)) == OHOS::Sensors::ERROR) {
235         SEN_HILOGE("Failed to obtain process CPU information");
236         return CPU_USAGE_UNKONW;
237     }
238 
239     std::this_thread::sleep_for(std::chrono::milliseconds(TIME_WAIT_FOR_OP));
240 
241     if ((totalTime2 = GetSystemTotalOccupy()) == OHOS::Sensors::ERROR) {
242         SEN_HILOGE("Failed to obtain CPU occupy");
243         return CPU_USAGE_UNKONW;
244     }
245     if ((procTime2 = GetProcOccupy(pid)) == OHOS::Sensors::ERROR) {
246         SEN_HILOGE("Failed to obtain process CPU information");
247         return CPU_USAGE_UNKONW;
248     }
249 
250     return CHK_RATE(CPU_USAGE_MAX * (procTime2 - procTime1) / (totalTime2 - totalTime1));
251 }
252 } // namespace SYSTEM_INFO
253 } // namespace Sensors
254 } // namespace OHOS