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