• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "procinfo.h"
17 
18 #include <cctype>
19 #include <cerrno>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <cstring>
23 #include <iostream>
24 #include <sstream>
25 #include <securec.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include "dfx_define.h"
29 #include "dfx_util.h"
30 #include "file_util.h"
31 #include "string_printf.h"
32 #include "string_util.h"
33 #include <iostream>
34 
35 namespace OHOS {
36 namespace HiviewDFX {
37 namespace {
38 const char PID_STR_NAME[] = "Pid:";
39 const char PPID_STR_NAME[] = "PPid:";
40 const char NSPID_STR_NAME[] = "NSpid:";
41 const int ARGS_COUNT_ONE = 1;
42 const int ARGS_COUNT_TWO = 2;
43 const int STATUS_LINE_SIZE = 1024;
44 }
45 
GetProcStatusByPath(struct ProcInfo & procInfo,const std::string & path)46 static bool GetProcStatusByPath(struct ProcInfo& procInfo, const std::string& path)
47 {
48     char buf[STATUS_LINE_SIZE];
49     FILE *fp = fopen(path.c_str(), "r");
50     if (fp == nullptr) {
51         return false;
52     }
53 
54     int pid = 0;
55     int ppid = 0;
56     int nsPid = 0;
57     while (!feof(fp)) {
58         if (fgets(buf, STATUS_LINE_SIZE, fp) == nullptr) {
59             fclose(fp);
60             return false;
61         }
62 
63         if (strncmp(buf, PID_STR_NAME, strlen(PID_STR_NAME)) == 0) {
64             // Pid:   1892
65             if (sscanf_s(buf, "%*[^0-9]%d", &pid) != ARGS_COUNT_ONE) {
66                 procInfo.pid = getpid();
67             } else {
68                 procInfo.pid = pid;
69             }
70             procInfo.nsPid = pid;
71             continue;
72         }
73 
74         if (strncmp(buf, PPID_STR_NAME, strlen(PPID_STR_NAME)) == 0) {
75             // PPid:   240
76             if (sscanf_s(buf, "%*[^0-9]%d", &ppid) != ARGS_COUNT_ONE) {
77                 procInfo.ppid = getppid();
78             } else {
79                 procInfo.ppid = ppid;
80             }
81             continue;
82         }
83 
84         if (strncmp(buf, NSPID_STR_NAME, strlen(NSPID_STR_NAME)) == 0) {
85             // NSpid:  1892    1
86             if (sscanf_s(buf, "%*[^0-9]%d%*[^0-9]%d", &pid, &nsPid) != ARGS_COUNT_TWO) {
87                 procInfo.ns = false;
88                 procInfo.nsPid = pid;
89             } else {
90                 procInfo.ns = true;
91                 procInfo.nsPid = nsPid;
92             }
93             procInfo.pid = pid;
94             break;
95         }
96     }
97     (void)fclose(fp);
98     return true;
99 }
100 
TidToNstid(const int pid,const int tid,int & nstid)101 bool TidToNstid(const int pid, const int tid, int& nstid)
102 {
103     std::string path = StringPrintf("/proc/%d/task/%d/status", pid, tid);
104     if (path.empty()) {
105         return false;
106     }
107 
108     struct ProcInfo procInfo;
109     if (!GetProcStatusByPath(procInfo, path)) {
110         return false;
111     }
112     nstid = procInfo.nsPid;
113     return true;
114 }
115 
GetProcStatusByPid(int realPid,struct ProcInfo & procInfo)116 bool GetProcStatusByPid(int realPid, struct ProcInfo& procInfo)
117 {
118     if (realPid == getpid()) {
119         return GetProcStatus(procInfo);
120     }
121     std::string path = StringPrintf("/proc/%d/status", realPid);
122     return GetProcStatusByPath(procInfo, path);
123 }
124 
GetProcStatus(struct ProcInfo & procInfo)125 bool GetProcStatus(struct ProcInfo& procInfo)
126 {
127     return GetProcStatusByPath(procInfo, PROC_SELF_STATUS_PATH);
128 }
129 
IsThreadInPid(int32_t pid,int32_t tid)130 bool IsThreadInPid(int32_t pid, int32_t tid)
131 {
132     std::string path;
133     if (pid == getpid()) {
134         path = StringPrintf("%s/%d", PROC_SELF_TASK_PATH, tid);
135     } else {
136         path = StringPrintf("/proc/%d/task/%d", pid, tid);
137     }
138     return access(path.c_str(), F_OK) == 0;
139 }
140 
GetTidsByPidWithFunc(const int pid,std::vector<int> & tids,std::function<bool (int)> const & func)141 bool GetTidsByPidWithFunc(const int pid, std::vector<int>& tids, std::function<bool(int)> const& func)
142 {
143     std::vector<std::string> files;
144     if (ReadDirFilesByPid(pid, files)) {
145         for (size_t i = 0; i < files.size(); ++i) {
146             pid_t tid = atoi(files[i].c_str());
147             if (tid == 0) {
148                 continue;
149             }
150             tids.push_back(tid);
151 
152             if (func != nullptr) {
153                 func(tid);
154             }
155         }
156     }
157     return (tids.size() > 0);
158 }
159 
GetTidsByPid(const int pid,std::vector<int> & tids,std::vector<int> & nstids)160 bool GetTidsByPid(const int pid, std::vector<int>& tids, std::vector<int>& nstids)
161 {
162     struct ProcInfo procInfo;
163     (void)GetProcStatusByPid(pid, procInfo);
164 
165     std::function<bool(int)> func = nullptr;
166     if (procInfo.ns) {
167         func = [&](int tid) {
168             pid_t nstid = tid;
169             TidToNstid(pid, tid, nstid);
170             nstids.push_back(nstid);
171             return true;
172         };
173     }
174     bool ret = GetTidsByPidWithFunc(pid, tids, func);
175     if (ret && !procInfo.ns) {
176         nstids = tids;
177     }
178     return (nstids.size() > 0);
179 }
180 
ReadThreadName(const int tid,std::string & str)181 void ReadThreadName(const int tid, std::string& str)
182 {
183     std::string path = StringPrintf("/proc/%d/comm", tid);
184     std::string name;
185     OHOS::HiviewDFX::LoadStringFromFile(path, name);
186     TrimAndDupStr(name, str);
187 }
188 
ReadProcessName(const int pid,std::string & str)189 void ReadProcessName(const int pid, std::string& str)
190 {
191     std::string path;
192     if (pid == getpid()) {
193         path = std::string(PROC_SELF_CMDLINE_PATH);
194     } else {
195         path = StringPrintf("/proc/%d/cmdline", pid);
196     }
197     std::string name;
198     OHOS::HiviewDFX::LoadStringFromFile(path, name);
199     std::cout << name << std::endl;
200     TrimAndDupStr(name, str);
201 }
202 
ReadProcessStatus(std::string & result,const int pid)203 void ReadProcessStatus(std::string& result, const int pid)
204 {
205     std::string path = StringPrintf("/proc/%d/status", pid);
206     if (access(path.c_str(), F_OK) != 0) {
207         result.append(StringPrintf("Failed to access path(%s), errno(%d).\n", path.c_str(), errno));
208         return;
209     }
210     std::string content;
211     OHOS::HiviewDFX::LoadStringFromFile(path, content);
212     if (!content.empty()) {
213         std::string str = StringPrintf("Process status:\n%s\n", content.c_str());
214         result.append(str);
215     }
216 }
217 
ReadProcessWchan(std::string & result,const int pid,bool onlyPid,bool withThreadName)218 void ReadProcessWchan(std::string& result, const int pid, bool onlyPid, bool withThreadName)
219 {
220     std::string path = StringPrintf("/proc/%d/wchan", pid);
221     if (access(path.c_str(), F_OK) != 0) {
222         result.append(StringPrintf("Failed to access path(%s), errno(%d).\n", path.c_str(), errno));
223         return;
224     }
225     std::ostringstream ss;
226     std::string content;
227     OHOS::HiviewDFX::LoadStringFromFile(path, content);
228     if (!content.empty()) {
229         ss << "Process wchan:\n";
230         ss << StringPrintf("%s\n", content.c_str());
231     }
232     if (onlyPid) {
233         result.append(ss.str());
234         return;
235     }
236     ss << "\nProcess threads wchan:\n";
237     ss << "=======================================\n";
238     bool flag = false;
239     std::string comm = "";
240     std::string wchan = "";
241     std::string taskPath = StringPrintf("/proc/%d/task", pid);
242     std::vector<std::string> files;
243     flag = ReadDirFiles(taskPath, files);
244     for (size_t i = 0; i < files.size(); ++i) {
245         std::string tidStr = files[i];
246         std::string commPath = StringPrintf("%s/%s/comm", taskPath.c_str(), tidStr.c_str());
247         std::string wchanPath = StringPrintf("%s/%s/wchan", taskPath.c_str(), tidStr.c_str());
248         OHOS::HiviewDFX::LoadStringFromFile(commPath, comm);
249         OHOS::HiviewDFX::LoadStringFromFile(wchanPath, wchan);
250         if (!comm.empty() && !wchan.empty()) {
251             flag = true;
252             if (withThreadName) {
253                 ss << "Tid:" << tidStr << ", Name:" << comm;
254             }
255             ss << "wchan:" << wchan << std::endl;
256         }
257     }
258 
259     if (!flag) {
260         ss << "Failed to access path: " << taskPath << std::endl;
261     }
262     ss << "=======================================\n";
263     result.append(ss.str());
264 }
265 
ReadThreadWchan(std::string & result,const int tid,bool withThreadName)266 void ReadThreadWchan(std::string& result, const int tid, bool withThreadName)
267 {
268     std::ostringstream ss;
269     if (withThreadName) {
270         std::string threadName;
271         ReadThreadName(tid, threadName);
272         ss << "Tid:" << tid << ", Name:" << threadName << std::endl;
273     }
274     std::string wchanPath = StringPrintf("%s/%d/wchan", PROC_SELF_TASK_PATH, tid);
275     std::string wchan;
276     if (OHOS::HiviewDFX::LoadStringFromFile(wchanPath, wchan)) {
277         ss << "wchan:" << wchan << std::endl;
278     } else {
279         ss << "Load thread wchan failed." << std::endl;
280     }
281     result = ss.str();
282 }
283 }   // namespace HiviewDFX
284 }   // namespace OHOS
285