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