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