• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #include "dump_common_utils.h"
16 #include <file_ex.h>
17 #include <securec.h>
18 #include <string_ex.h>
19 #include <dirent.h>
20 #include <fstream>
21 #include <iostream>
22 #include "hilog_wrapper.h"
23 #include "sys/stat.h"
24 #include "util/file_utils.h"
25 
26 using namespace std;
27 namespace OHOS {
28 namespace HiviewDFX {
29 namespace {
30 constexpr int LINE_ITEM_MIN = 2;
31 constexpr int LINE_KEY = 0;
32 constexpr int LINE_VALUE = 1;
33 constexpr int LINE_VALUE_0 = 0;
34 constexpr int UNSET = -1;
35 static const std::string CPU_STR = "cpu";
36 }
37 
GetSubNodes(const std::string & path,bool digit)38 std::vector<std::string> DumpCommonUtils::GetSubNodes(const std::string &path, bool digit)
39 {
40     std::vector<std::string> subNodes;
41     auto dir = opendir(path.c_str());
42     if (dir == nullptr) {
43         return subNodes;
44     }
45     for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
46         std::string childNode = ent->d_name;
47         if (childNode == "." || childNode == "..") {
48             continue;
49         }
50         if (digit && !isdigit(childNode[0])) {
51             continue;
52         }
53         subNodes.push_back(childNode);
54     }
55     closedir(dir);
56     return subNodes;
57 }
58 
59 // the parameter of path should be full.
IsDirectory(const std::string & path)60 bool DumpCommonUtils::IsDirectory(const std::string &path)
61 {
62     struct stat statBuffer;
63     if (stat(path.c_str(), &statBuffer) == 0 && S_ISDIR(statBuffer.st_mode)) {
64         return true;
65     }
66     return false;
67 }
68 
GetSubDir(const std::string & path,bool digit)69 std::vector<std::string> DumpCommonUtils::GetSubDir(const std::string &path, bool digit)
70 {
71     std::vector<std::string> subDirs;
72     auto dir = opendir(path.c_str());
73     if (dir == nullptr) {
74         DUMPER_HILOGE(MODULE_SERVICE, "failed to open dir: %{public}s, errno: %{public}d", path.c_str(), errno);
75         return subDirs;
76     }
77     for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
78         std::string childNode = ent->d_name;
79         if (childNode == "." || childNode == "..") {
80             continue;
81         }
82         if (digit && !isdigit(childNode[0])) {
83             continue;
84         }
85         if (!IsDirectory(path + "/" + childNode)) {
86             continue; // skip directory
87         }
88         subDirs.push_back(childNode);
89     }
90     closedir(dir);
91     return subDirs;
92 }
93 
GetAllPids()94 std::vector<int32_t> DumpCommonUtils::GetAllPids()
95 {
96     std::string path = "/proc";
97     std::vector<int32_t> pids;
98     std::vector<std::string> allPids = GetSubDir(path, true);
99     for (const auto &pid : allPids) {
100         if (!isdigit(pid[0])) {
101             continue;
102         }
103         pids.push_back(std::stoi(pid));
104     }
105     return pids;
106 }
107 
CpuInfo()108 DumpCommonUtils::CpuInfo::CpuInfo()
109 {
110     id_ = UNSET;
111 }
112 
GetCpuInfos(std::vector<CpuInfo> & infos)113 bool DumpCommonUtils::GetCpuInfos(std::vector<CpuInfo> &infos)
114 {
115     std::vector<std::string> names;
116     if (!GetNamesInFolder("/sys/devices/system/cpu/", names)) {
117         return false;
118     }
119     for (size_t i = 0; i < names.size(); i++) {
120         std::string name = names[i];
121         if (!StartWith(name, CPU_STR)) {
122             continue;
123         }
124         std::string cpuId = name.substr(CPU_STR.size());
125         if (cpuId.empty() || (!IsNumericStr(cpuId))) {
126             continue;
127         }
128         CpuInfo cpuInfo;
129         StrToInt(cpuId, cpuInfo.id_);
130         infos.push_back(cpuInfo);
131     }
132     return true;
133 }
134 
PidInfo()135 DumpCommonUtils::PidInfo::PidInfo()
136 {
137     Reset();
138 }
139 
Reset()140 void DumpCommonUtils::PidInfo::Reset()
141 {
142     pid_ = UNSET;
143     uid_ = UNSET;
144     gid_ = UNSET;
145     ppid_ = UNSET;
146     name_.clear();
147     cmdline_.clear();
148 }
149 
GetPidInfos(std::vector<PidInfo> & infos,bool all)150 bool DumpCommonUtils::GetPidInfos(std::vector<PidInfo> &infos, bool all)
151 {
152     std::vector<std::string> names;
153     if (!GetNamesInFolder("/proc/", names)) {
154         return false;
155     }
156     for (size_t i = 0; i < names.size(); i++) {
157         std::string name = names[i];
158         if (name.empty()) {
159             continue;
160         }
161         if (!IsNumericStr(name)) {
162             continue;
163         }
164         PidInfo pidInfo;
165         StrToInt(name, pidInfo.pid_);
166         GetProcessInfo(pidInfo.pid_, pidInfo);
167         if (all) {
168             GetProcessNameByPid(pidInfo.pid_, pidInfo.cmdline_);
169         }
170         infos.push_back(pidInfo);
171     }
172     return true;
173 }
174 
IsUserPid(const std::string & pid)175 bool DumpCommonUtils::IsUserPid(const std::string &pid)
176 {
177     string path = "/proc/" + pid + "/smaps";
178     string lineContent;
179     bool ret = FileUtils::GetInstance().LoadStringFromProcCb(path, true, false, [&](const string& line) -> void {
180         lineContent += line;
181     });
182     if (!ret) {
183         return false;
184     }
185     if (!lineContent.empty()) {
186         return true;
187     }
188     return false;
189 }
190 
GetUserPids(std::vector<int> & pids)191 bool DumpCommonUtils::GetUserPids(std::vector<int> &pids)
192 {
193     std::vector<std::string> files;
194     if (!GetNamesInFolder("/proc/", files)) {
195         return false;
196     }
197 
198     for (auto file : files) {
199         if (file.empty()) {
200             continue;
201         }
202         if (!IsNumericStr(file)) {
203             continue;
204         }
205 
206         if (!IsUserPid(file)) {
207             continue;
208         }
209 
210         int pid;
211         StrToInt(file, pid);
212 
213         pids.push_back(pid);
214     }
215     return true;
216 }
217 
GetLinesInFile(const std::string & file,std::vector<std::string> & lines)218 bool DumpCommonUtils::GetLinesInFile(const std::string& file, std::vector<std::string>& lines)
219 {
220     std::string content;
221     bool ret = FileUtils::GetInstance().LoadStringFromProcCb(file, false, false, [&](const std::string& line) -> void {
222         content += line;
223     });
224     if (!ret) {
225         return false;
226     }
227     SplitStr(content, "\n", lines);
228     return true;
229 }
230 
GetNamesInFolder(const std::string & folder,std::vector<std::string> & names)231 bool DumpCommonUtils::GetNamesInFolder(const std::string& folder, std::vector<std::string>& names)
232 {
233     bool ret = false;
234     DIR* dir = nullptr;
235     if ((dir = opendir(folder.c_str())) != nullptr) {
236         dirent* ptr = nullptr;
237         while ((ptr = readdir(dir)) != nullptr) {
238             std::string name = ptr->d_name;
239             if ((name == ".") || (name == "..")) {
240                 continue;
241             }
242             names.push_back(name);
243         }
244         closedir(dir);
245         ret = true;
246     }
247     return ret;
248 }
249 
StartWith(const std::string & str,const std::string & head)250 bool DumpCommonUtils::StartWith(const std::string& str, const std::string& head)
251 {
252     if (str.length() < head.length()) {
253         return false;
254     }
255     return (str.compare(0, head.size(), head) == 0);
256 }
257 
GetProcessNameByPid(int pid,std::string & name)258 bool DumpCommonUtils::GetProcessNameByPid(int pid, std::string& name)
259 {
260     char filesysdir[128] = { 0 };
261     if (sprintf_s(filesysdir, sizeof(filesysdir), "/proc/%d/cmdline", pid) < 0) {
262         return false;
263     }
264     std::string filePath = filesysdir;
265     std::string content;
266     bool ret = FileUtils::GetInstance().LoadStringFromProcCb(filePath, false, false, [&](const string& line) -> void {
267         content += line;
268     });
269     if (!ret) {
270         return false;
271     }
272     name = content;
273     return true;
274 }
275 
GetProcessInfo(int pid,PidInfo & info)276 bool DumpCommonUtils::GetProcessInfo(int pid, PidInfo &info)
277 {
278     info.Reset();
279     char filesysdir[128] = { 0 };
280     if (sprintf_s(filesysdir, sizeof(filesysdir), "/proc/%d/status", pid) < 0) {
281         return false;
282     }
283     std::string file = filesysdir;
284     std::vector<std::string> lines;
285     if (!GetLinesInFile(file, lines)) {
286         return false;
287     }
288     const std::string splitKeyValueToken = ":";
289     const std::string splitValuesToken = "\t";
290     for (size_t i = 0; i < lines.size(); i++) {
291         std::vector<std::string> keyValue;
292         SplitStr(lines[i], splitKeyValueToken, keyValue);
293         if (keyValue.size() < LINE_ITEM_MIN) {
294             continue;
295         }
296         std::string key = keyValue[LINE_KEY];
297         std::string val = TrimStr(keyValue[LINE_VALUE], '\t');
298         std::vector<std::string> values;
299         SplitStr(val, splitValuesToken, values, true);
300         if (values.empty()) {
301             continue;
302         }
303         std::string val0 = values[LINE_VALUE_0];
304         if (key == "Pid") {
305             StrToInt(val0, info.pid_);
306         } else if (key == "PPid") {
307             StrToInt(val0, info.ppid_);
308         } else if (key == "Uid") {
309             StrToInt(val0, info.uid_);
310         } else if (key == "Gid") {
311             StrToInt(val0, info.gid_);
312         } else if (key == "Name") {
313             info.name_ = val;
314         } else {
315             continue;
316         }
317         if ((info.pid_ > UNSET) && (info.ppid_ > UNSET) && (info.uid_ > UNSET) && (info.gid_ > UNSET)) {
318             return true;
319         }
320     }
321     return false;
322 }
323 } // namespace HiviewDFX
324 } // namespace OHOS
325