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