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