1c29fa5a6Sopenharmony_ci/*
2c29fa5a6Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3c29fa5a6Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4c29fa5a6Sopenharmony_ci * you may not use this file except in compliance with the License.
5c29fa5a6Sopenharmony_ci * You may obtain a copy of the License at
6c29fa5a6Sopenharmony_ci *
7c29fa5a6Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8c29fa5a6Sopenharmony_ci *
9c29fa5a6Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10c29fa5a6Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11c29fa5a6Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12c29fa5a6Sopenharmony_ci * See the License for the specific language governing permissions and
13c29fa5a6Sopenharmony_ci * limitations under the License.
14c29fa5a6Sopenharmony_ci */
15c29fa5a6Sopenharmony_ci
16c29fa5a6Sopenharmony_ci#include "system_info.h"
17c29fa5a6Sopenharmony_ci
18c29fa5a6Sopenharmony_ci#include <dirent.h>
19c29fa5a6Sopenharmony_ci#include <unistd.h>
20c29fa5a6Sopenharmony_ci
21c29fa5a6Sopenharmony_ci#include <chrono>
22c29fa5a6Sopenharmony_ci#include <fstream>
23c29fa5a6Sopenharmony_ci#include <string>
24c29fa5a6Sopenharmony_ci
25c29fa5a6Sopenharmony_ci#include "securec.h"
26c29fa5a6Sopenharmony_ci
27c29fa5a6Sopenharmony_ci#include "error_multimodal.h"
28c29fa5a6Sopenharmony_ci#include "mmi_log.h"
29c29fa5a6Sopenharmony_ci
30c29fa5a6Sopenharmony_ci#undef MMI_LOG_TAG
31c29fa5a6Sopenharmony_ci#define MMI_LOG_TAG "SYSTEM_INFO"
32c29fa5a6Sopenharmony_ci
33c29fa5a6Sopenharmony_cinamespace OHOS {
34c29fa5a6Sopenharmony_cinamespace MMI {
35c29fa5a6Sopenharmony_cinamespace SYSTEM_INFO {
36c29fa5a6Sopenharmony_cinamespace {
37c29fa5a6Sopenharmony_ciconstexpr int32_t LOCATION { 14 };
38c29fa5a6Sopenharmony_ciconstexpr int32_t TIME_WAIT_FOR_OP { 1000 };
39c29fa5a6Sopenharmony_ciconstexpr int32_t DEFAULT_PID { -1 };
40c29fa5a6Sopenharmony_ci} // namespace
41c29fa5a6Sopenharmony_ci
42c29fa5a6Sopenharmony_ciinline double CHK_RATE(double rate)
43c29fa5a6Sopenharmony_ci{
44c29fa5a6Sopenharmony_ci    return (rate > CPU_USAGE_MAX ? CPU_USAGE_MAX : rate);
45c29fa5a6Sopenharmony_ci}
46c29fa5a6Sopenharmony_ci
47c29fa5a6Sopenharmony_ciint32_t CpuInfo::GetTaskPidFile(const std::string &process_name)
48c29fa5a6Sopenharmony_ci{
49c29fa5a6Sopenharmony_ci    int32_t pid = DEFAULT_PID;
50c29fa5a6Sopenharmony_ci    static const std::string procPath = "/proc";
51c29fa5a6Sopenharmony_ci    DIR* dir = ::opendir(procPath.c_str());
52c29fa5a6Sopenharmony_ci    CHKPR(dir, DEFAULT_PID);
53c29fa5a6Sopenharmony_ci    struct dirent* pidFile;
54c29fa5a6Sopenharmony_ci    while ((pidFile = ::readdir(dir)) != nullptr) {
55c29fa5a6Sopenharmony_ci        if ((::strcmp(pidFile->d_name, ".") == 0) || (::strcmp(pidFile->d_name, "..") == 0)) {
56c29fa5a6Sopenharmony_ci            continue;
57c29fa5a6Sopenharmony_ci        }
58c29fa5a6Sopenharmony_ci        if (pidFile->d_type != DT_DIR) {
59c29fa5a6Sopenharmony_ci            continue;
60c29fa5a6Sopenharmony_ci        }
61c29fa5a6Sopenharmony_ci        const std::string path = procPath + "/" + pidFile->d_name + "/status";
62c29fa5a6Sopenharmony_ci        std::ifstream file(path);
63c29fa5a6Sopenharmony_ci        if (!file.is_open()) {
64c29fa5a6Sopenharmony_ci            continue;
65c29fa5a6Sopenharmony_ci        }
66c29fa5a6Sopenharmony_ci        std::string strLine;
67c29fa5a6Sopenharmony_ci        if (!std::getline(file, strLine)) {
68c29fa5a6Sopenharmony_ci            MMI_HILOGE("getline failed");
69c29fa5a6Sopenharmony_ci            file.close();
70c29fa5a6Sopenharmony_ci            return DEFAULT_PID;
71c29fa5a6Sopenharmony_ci        }
72c29fa5a6Sopenharmony_ci        if (strLine.empty()) {
73c29fa5a6Sopenharmony_ci            file.close();
74c29fa5a6Sopenharmony_ci            continue;
75c29fa5a6Sopenharmony_ci        }
76c29fa5a6Sopenharmony_ci        if ((strLine.find(process_name)) == std::string::npos) {
77c29fa5a6Sopenharmony_ci            file.close();
78c29fa5a6Sopenharmony_ci            continue;
79c29fa5a6Sopenharmony_ci        }
80c29fa5a6Sopenharmony_ci        while (std::getline(file, strLine)) {
81c29fa5a6Sopenharmony_ci            if ((strLine.find("Pid")) != std::string::npos) {
82c29fa5a6Sopenharmony_ci                if (::sscanf_s(strLine.c_str(), "%*s%d", &pid, sizeof(pid)) != 1) {
83c29fa5a6Sopenharmony_ci                    MMI_HILOGE("Failed to delete the pid");
84c29fa5a6Sopenharmony_ci                }
85c29fa5a6Sopenharmony_ci                break;
86c29fa5a6Sopenharmony_ci            }
87c29fa5a6Sopenharmony_ci        }
88c29fa5a6Sopenharmony_ci        file.close();
89c29fa5a6Sopenharmony_ci        break;
90c29fa5a6Sopenharmony_ci    }
91c29fa5a6Sopenharmony_ci    if (::closedir(dir) != 0) {
92c29fa5a6Sopenharmony_ci        MMI_HILOGE("Failed to close dir");
93c29fa5a6Sopenharmony_ci    }
94c29fa5a6Sopenharmony_ci    return pid;
95c29fa5a6Sopenharmony_ci}
96c29fa5a6Sopenharmony_ci
97c29fa5a6Sopenharmony_ciint32_t CpuInfo::GetTaskPidCmd(const std::string &process_name, int32_t flag, std::string user)
98c29fa5a6Sopenharmony_ci{
99c29fa5a6Sopenharmony_ci    std::string command;
100c29fa5a6Sopenharmony_ci    if (flag) {
101c29fa5a6Sopenharmony_ci        if (user.empty()) {
102c29fa5a6Sopenharmony_ci            user = ::getlogin();
103c29fa5a6Sopenharmony_ci        }
104c29fa5a6Sopenharmony_ci        command = "pgrep " + process_name + " -u " + user;
105c29fa5a6Sopenharmony_ci    } else {
106c29fa5a6Sopenharmony_ci        command = "pidof -s " + process_name;
107c29fa5a6Sopenharmony_ci    }
108c29fa5a6Sopenharmony_ci    ::FILE *fp = nullptr;
109c29fa5a6Sopenharmony_ci    if ((fp = ::popen(command.c_str(), "r")) == nullptr) {
110c29fa5a6Sopenharmony_ci        MMI_HILOGE("Failed to open, cmd:%{public}s", command.c_str());
111c29fa5a6Sopenharmony_ci        fp = nullptr;
112c29fa5a6Sopenharmony_ci        return DEFAULT_PID;
113c29fa5a6Sopenharmony_ci    }
114c29fa5a6Sopenharmony_ci    char buf[100] = { 0 };
115c29fa5a6Sopenharmony_ci    if (::fgets(buf, sizeof(buf), fp) == nullptr) {
116c29fa5a6Sopenharmony_ci        MMI_HILOGE("Failed to read content");
117c29fa5a6Sopenharmony_ci        ::pclose(fp);
118c29fa5a6Sopenharmony_ci        fp = nullptr;
119c29fa5a6Sopenharmony_ci        return DEFAULT_PID;
120c29fa5a6Sopenharmony_ci    }
121c29fa5a6Sopenharmony_ci    ::pclose(fp);
122c29fa5a6Sopenharmony_ci    return std::stoi(buf);
123c29fa5a6Sopenharmony_ci}
124c29fa5a6Sopenharmony_ci
125c29fa5a6Sopenharmony_ciint32_t CpuInfo::GetProcOccupy(int32_t pid)
126c29fa5a6Sopenharmony_ci{
127c29fa5a6Sopenharmony_ci    Proc_Cpu_Occupy info;
128c29fa5a6Sopenharmony_ci    static const std::string procPath = "/proc/" + std::to_string(pid) + "/stat";
129c29fa5a6Sopenharmony_ci    std::ifstream file(procPath);
130c29fa5a6Sopenharmony_ci    if (!file.is_open()) {
131c29fa5a6Sopenharmony_ci        MMI_HILOGE("Failed to open path:%{private}s", procPath.c_str());
132c29fa5a6Sopenharmony_ci        return RET_ERR;
133c29fa5a6Sopenharmony_ci    }
134c29fa5a6Sopenharmony_ci
135c29fa5a6Sopenharmony_ci    std::string strLine;
136c29fa5a6Sopenharmony_ci    std::getline(file, strLine);
137c29fa5a6Sopenharmony_ci    if (strLine.empty()) {
138c29fa5a6Sopenharmony_ci        MMI_HILOGE("Failed to read content");
139c29fa5a6Sopenharmony_ci        file.close();
140c29fa5a6Sopenharmony_ci        return RET_ERR;
141c29fa5a6Sopenharmony_ci    }
142c29fa5a6Sopenharmony_ci    file.close();
143c29fa5a6Sopenharmony_ci
144c29fa5a6Sopenharmony_ci    int position = 1;
145c29fa5a6Sopenharmony_ci    std::istringstream ss(strLine);
146c29fa5a6Sopenharmony_ci    while (ss >> strLine) {
147c29fa5a6Sopenharmony_ci        position++;
148c29fa5a6Sopenharmony_ci        if (position >= LOCATION) {
149c29fa5a6Sopenharmony_ci            break;
150c29fa5a6Sopenharmony_ci        }
151c29fa5a6Sopenharmony_ci    }
152c29fa5a6Sopenharmony_ci    ss >> info.utime >> info.stime >> info.cutime >> info.cstime;
153c29fa5a6Sopenharmony_ci    return (info.utime + info.stime + info.cutime + info.cstime);
154c29fa5a6Sopenharmony_ci}
155c29fa5a6Sopenharmony_ci
156c29fa5a6Sopenharmony_cidouble CpuInfo::GetCpuUsage(const Total_Cpu_Occupy &first, const Total_Cpu_Occupy &second)
157c29fa5a6Sopenharmony_ci{
158c29fa5a6Sopenharmony_ci    unsigned long cpuTime2 = static_cast<unsigned long>(second.user + second.nice + second.system +
159c29fa5a6Sopenharmony_ci                                                        second.idle + second.lowait + second.irq + second.softirq);
160c29fa5a6Sopenharmony_ci    unsigned long cpuTime1 = static_cast<unsigned long>(first.user + first.nice + first.system +
161c29fa5a6Sopenharmony_ci                                                        first.idle + first.lowait + first.irq + first.softirq);
162c29fa5a6Sopenharmony_ci
163c29fa5a6Sopenharmony_ci    double cpu_use = (second.user - first.user) * CPU_USAGE_MAX / (cpuTime2 - cpuTime1);
164c29fa5a6Sopenharmony_ci    double cpu_sys = (second.system - first.system) * CPU_USAGE_MAX / (cpuTime2 - cpuTime1);
165c29fa5a6Sopenharmony_ci
166c29fa5a6Sopenharmony_ci    return CHK_RATE(cpu_use + cpu_sys);
167c29fa5a6Sopenharmony_ci}
168c29fa5a6Sopenharmony_ci
169c29fa5a6Sopenharmony_ciint32_t CpuInfo::GetSystemCpuStatInfo(Total_Cpu_Occupy &info)
170c29fa5a6Sopenharmony_ci{
171c29fa5a6Sopenharmony_ci    std::ifstream statFile("/proc/stat");
172c29fa5a6Sopenharmony_ci    if (!statFile.is_open()) {
173c29fa5a6Sopenharmony_ci        MMI_HILOGE("Failed to open config file");
174c29fa5a6Sopenharmony_ci        return FILE_OPEN_FAIL;
175c29fa5a6Sopenharmony_ci    }
176c29fa5a6Sopenharmony_ci    std::string strLine;
177c29fa5a6Sopenharmony_ci    std::getline(statFile, strLine);
178c29fa5a6Sopenharmony_ci    if (strLine.empty()) {
179c29fa5a6Sopenharmony_ci        MMI_HILOGE("No valid content was read");
180c29fa5a6Sopenharmony_ci        statFile.close();
181c29fa5a6Sopenharmony_ci        return STREAM_BUF_READ_FAIL;
182c29fa5a6Sopenharmony_ci    }
183c29fa5a6Sopenharmony_ci    if ((strLine.find("cpu")) == std::string::npos) {
184c29fa5a6Sopenharmony_ci        MMI_HILOGE("The keyword was not matched. Procedure");
185c29fa5a6Sopenharmony_ci        statFile.close();
186c29fa5a6Sopenharmony_ci        return RET_ERR;
187c29fa5a6Sopenharmony_ci    }
188c29fa5a6Sopenharmony_ci    std::istringstream ss(strLine);
189c29fa5a6Sopenharmony_ci    ss >> info.name >> info.user >> info.nice >> info.system >> info.idle >> info.lowait \
190c29fa5a6Sopenharmony_ci        >> info.irq >> info.softirq >> info.steal >> info.guest >> info.guest_nice;
191c29fa5a6Sopenharmony_ci
192c29fa5a6Sopenharmony_ci    statFile.close();
193c29fa5a6Sopenharmony_ci    return RET_OK;
194c29fa5a6Sopenharmony_ci}
195c29fa5a6Sopenharmony_ci
196c29fa5a6Sopenharmony_cidouble CpuInfo::GetSystemCpuUsage()
197c29fa5a6Sopenharmony_ci{
198c29fa5a6Sopenharmony_ci    Total_Cpu_Occupy first {};
199c29fa5a6Sopenharmony_ci    int32_t ret = GetSystemCpuStatInfo(first);
200c29fa5a6Sopenharmony_ci    if (ret != RET_OK) {
201c29fa5a6Sopenharmony_ci        MMI_HILOGE("Failed to obtain CPU information, errcode:%{public}d", ret);
202c29fa5a6Sopenharmony_ci        return CPU_USAGE_UNKNOWN;
203c29fa5a6Sopenharmony_ci    }
204c29fa5a6Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(TIME_WAIT_FOR_OP));
205c29fa5a6Sopenharmony_ci    Total_Cpu_Occupy second {};
206c29fa5a6Sopenharmony_ci    ret = GetSystemCpuStatInfo(second);
207c29fa5a6Sopenharmony_ci    if (ret != RET_OK) {
208c29fa5a6Sopenharmony_ci        MMI_HILOGE("Failed to obtain CPU information, errcode:%{public}d", ret);
209c29fa5a6Sopenharmony_ci        return CPU_USAGE_UNKNOWN;
210c29fa5a6Sopenharmony_ci    }
211c29fa5a6Sopenharmony_ci
212c29fa5a6Sopenharmony_ci    return GetCpuUsage(first, second);
213c29fa5a6Sopenharmony_ci}
214c29fa5a6Sopenharmony_ci
215c29fa5a6Sopenharmony_ciint64_t CpuInfo::GetSystemTotalOccupy()
216c29fa5a6Sopenharmony_ci{
217c29fa5a6Sopenharmony_ci    int ret = -1;
218c29fa5a6Sopenharmony_ci    Total_Cpu_Occupy occupy {};
219c29fa5a6Sopenharmony_ci    if ((ret = GetSystemCpuStatInfo(occupy)) != RET_OK) {
220c29fa5a6Sopenharmony_ci        MMI_HILOGE("Failed to obtain CPU information, errcode:%{public}d", ret);
221c29fa5a6Sopenharmony_ci        return RET_ERR;
222c29fa5a6Sopenharmony_ci    }
223c29fa5a6Sopenharmony_ci    return (occupy.user + occupy.nice + occupy.system + occupy.idle);
224c29fa5a6Sopenharmony_ci}
225c29fa5a6Sopenharmony_ci
226c29fa5a6Sopenharmony_cidouble CpuInfo::GetProcCpuUsage(const std::string &process_name)
227c29fa5a6Sopenharmony_ci{
228c29fa5a6Sopenharmony_ci    int64_t totalTime1 = 0;
229c29fa5a6Sopenharmony_ci    int64_t totalTime2 = 0;
230c29fa5a6Sopenharmony_ci    int64_t procTime1 = 0;
231c29fa5a6Sopenharmony_ci    int64_t procTime2 = 0;
232c29fa5a6Sopenharmony_ci    int32_t pid = GetTaskPidFile(process_name);
233c29fa5a6Sopenharmony_ci
234c29fa5a6Sopenharmony_ci    if ((totalTime1 = GetSystemTotalOccupy()) == RET_ERR) {
235c29fa5a6Sopenharmony_ci        MMI_HILOGE("Failed to obtain CPU occupy");
236c29fa5a6Sopenharmony_ci        return CPU_USAGE_UNKNOWN;
237c29fa5a6Sopenharmony_ci    }
238c29fa5a6Sopenharmony_ci    if ((procTime1 = GetProcOccupy(pid)) == RET_ERR) {
239c29fa5a6Sopenharmony_ci        MMI_HILOGE("Failed to obtain process CPU information");
240c29fa5a6Sopenharmony_ci        return CPU_USAGE_UNKNOWN;
241c29fa5a6Sopenharmony_ci    }
242c29fa5a6Sopenharmony_ci
243c29fa5a6Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(TIME_WAIT_FOR_OP));
244c29fa5a6Sopenharmony_ci
245c29fa5a6Sopenharmony_ci    if ((totalTime2 = GetSystemTotalOccupy()) == RET_ERR) {
246c29fa5a6Sopenharmony_ci        MMI_HILOGE("Failed to obtain CPU occupy");
247c29fa5a6Sopenharmony_ci        return CPU_USAGE_UNKNOWN;
248c29fa5a6Sopenharmony_ci    }
249c29fa5a6Sopenharmony_ci    if ((procTime2 = GetProcOccupy(pid)) == RET_ERR) {
250c29fa5a6Sopenharmony_ci        MMI_HILOGE("Failed to obtain process CPU information");
251c29fa5a6Sopenharmony_ci        return CPU_USAGE_UNKNOWN;
252c29fa5a6Sopenharmony_ci    }
253c29fa5a6Sopenharmony_ci
254c29fa5a6Sopenharmony_ci    return CHK_RATE(CPU_USAGE_MAX * (procTime2 - procTime1) / (totalTime2 - totalTime1));
255c29fa5a6Sopenharmony_ci}
256c29fa5a6Sopenharmony_ci} // namespace SYSTEM_INFO
257c29fa5a6Sopenharmony_ci} // namespace MMI
258c29fa5a6Sopenharmony_ci} // namespace OHOS