• 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         if (!std::getline(filePath, strLine)) {
69             SEN_HILOGE("getline fail");
70             filePath.close();
71             continue;
72         }
73         if (strLine.empty()) {
74             filePath.close();
75             continue;
76         }
77         if ((strLine.find(process_name)) == std::string::npos) {
78             filePath.close();
79             continue;
80         }
81         while (std::getline(filePath, strLine)) {
82             if ((strLine.find("Pid")) != std::string::npos) {
83                 if (::sscanf_s(strLine.c_str(), "%*s%d", &pid, sizeof(pid)) != 1) {
84                     SEN_HILOGE("sscanf_s failed");
85                 }
86                 break;
87             }
88         }
89         filePath.close();
90         break;
91     }
92     ::closedir(dir);
93 
94     return pid;
95 }
96 
GetProcOccupy(int32_t pid)97 int32_t CpuInfo::GetProcOccupy(int32_t pid)
98 {
99     Proc_Cpu_Occupy info;
100     static const std::string procPath = "/proc/" + std::to_string(pid) + "/stat";
101     std::ifstream file(procPath);
102     if (!file.is_open()) {
103         SEN_HILOGE("Failed to open path:%{public}s", procPath.c_str());
104         return OHOS::Sensors::ERROR;
105     }
106 
107     std::string strLine;
108     if (!std::getline(file, strLine)) {
109         SEN_HILOGE("getline fail");
110         file.close();
111         return OHOS::Sensors::ERROR;
112     }
113     if (strLine.empty()) {
114         SEN_HILOGE("Failed to read content");
115         file.close();
116         return OHOS::Sensors::ERROR;
117     }
118     file.close();
119 
120     int pos = 1;
121     std::istringstream ss(strLine);
122     while (ss >> strLine) {
123         pos++;
124         if (pos >= LOCATION) {
125             break;
126         }
127     }
128     ss >> info.utime >> info.stime >> info.cutime >> info.cstime;
129     return (info.utime + info.stime + info.cutime + info.cstime);
130 }
131 
GetCpuUsage(const Total_Cpu_Occupy & first,const Total_Cpu_Occupy & second)132 double CpuInfo::GetCpuUsage(const Total_Cpu_Occupy& first, const Total_Cpu_Occupy& second)
133 {
134     unsigned long cpuTime2 = static_cast<unsigned long>(second.user + second.nice + second.system +
135                                                         second.idle + second.lowait + second.irq + second.softirq);
136     unsigned long cpuTime1 = static_cast<unsigned long>(first.user + first.nice + first.system +
137                                                         first.idle + first.lowait + first.irq + first.softirq);
138 
139     double cpu_use = (second.user - first.user) * CPU_USAGE_MAX / (cpuTime2 - cpuTime1);
140     double cpu_sys = (second.system - first.system) * CPU_USAGE_MAX / (cpuTime2 - cpuTime1);
141 
142     return CHK_RATE(cpu_use + cpu_sys);
143 }
144 
GetSystemCpuStatInfo(Total_Cpu_Occupy & info)145 int32_t CpuInfo::GetSystemCpuStatInfo(Total_Cpu_Occupy& info)
146 {
147     std::ifstream statFile("/proc/stat");
148     if (!statFile.is_open()) {
149         SEN_HILOGE("Failed to open config file");
150         return FILE_OPEN_FAIL;
151     }
152     std::string strLine;
153     if (!std::getline(statFile, strLine)) {
154         SEN_HILOGE("getline fail");
155         statFile.close();
156         return STREAM_BUF_READ_FAIL;
157     }
158     if (strLine.empty()) {
159         SEN_HILOGE("No valid content was read");
160         statFile.close();
161         return STREAM_BUF_READ_FAIL;
162     }
163     if ((strLine.find("cpu")) == std::string::npos) {
164         SEN_HILOGE("The keyword was not matched. Procedure");
165         statFile.close();
166         return OHOS::Sensors::ERROR;
167     }
168     std::istringstream ss(strLine);
169     ss >> info.name >> info.user >> info.nice >> info.system >> info.idle >> info.lowait \
170         >> info.irq >> info.softirq >> info.steal >> info.guest >> info.guest_nice;
171 
172     statFile.close();
173     return OHOS::Sensors::SUCCESS;
174 }
175 
GetSystemCpuUsage()176 double CpuInfo::GetSystemCpuUsage()
177 {
178     Total_Cpu_Occupy first {};
179     int32_t ret = GetSystemCpuStatInfo(first);
180     if (ret != OHOS::Sensors::SUCCESS) {
181         SEN_HILOGE("Failed to obtain CPU information, errcode:%{public}d", ret);
182         return CPU_USAGE_UNKNOWN;
183     }
184     std::this_thread::sleep_for(std::chrono::milliseconds(TIME_WAIT_FOR_OP));
185     Total_Cpu_Occupy second {};
186     ret = GetSystemCpuStatInfo(second);
187     if (ret != OHOS::Sensors::SUCCESS) {
188         SEN_HILOGE("Failed to obtain CPU information, errcode:%{public}d", ret);
189         return CPU_USAGE_UNKNOWN;
190     }
191 
192     return GetCpuUsage(first, second);
193 }
194 
GetSystemTotalOccupy()195 int64_t CpuInfo::GetSystemTotalOccupy()
196 {
197     int ret = -1;
198     Total_Cpu_Occupy occupy {};
199     if ((ret = GetSystemCpuStatInfo(occupy)) != OHOS::Sensors::SUCCESS) {
200         SEN_HILOGE("Failed to obtain CPU information, errcode:%{public}d", ret);
201         return OHOS::Sensors::ERROR;
202     }
203     return (occupy.user + occupy.nice + occupy.system + occupy.idle);
204 }
205 
GetProcCpuUsage(const std::string & process_name)206 double CpuInfo::GetProcCpuUsage(const std::string& process_name)
207 {
208     int64_t totalTime1 = 0;
209     int64_t totalTime2 = 0;
210     int64_t procTime1 = 0;
211     int64_t procTime2 = 0;
212     int32_t pid = GetTaskPidFile(process_name);
213 
214     if ((totalTime1 = GetSystemTotalOccupy()) == OHOS::Sensors::ERROR) {
215         SEN_HILOGE("Failed to obtain CPU occupy");
216         return CPU_USAGE_UNKNOWN;
217     }
218     if ((procTime1 = GetProcOccupy(pid)) == OHOS::Sensors::ERROR) {
219         SEN_HILOGE("Failed to obtain process CPU information");
220         return CPU_USAGE_UNKNOWN;
221     }
222 
223     std::this_thread::sleep_for(std::chrono::milliseconds(TIME_WAIT_FOR_OP));
224 
225     if ((totalTime2 = GetSystemTotalOccupy()) == OHOS::Sensors::ERROR) {
226         SEN_HILOGE("Failed to obtain CPU occupy");
227         return CPU_USAGE_UNKNOWN;
228     }
229     if ((procTime2 = GetProcOccupy(pid)) == OHOS::Sensors::ERROR) {
230         SEN_HILOGE("Failed to obtain process CPU information");
231         return CPU_USAGE_UNKNOWN;
232     }
233 
234     return CHK_RATE(CPU_USAGE_MAX * (procTime2 - procTime1) / (totalTime2 - totalTime1));
235 }
236 } // namespace SYSTEM_INFO
237 } // namespace Sensors
238 } // namespace OHOS