1 /*
2 * Copyright (c) 2021-2024 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 "dfx_process.h"
17
18 #include <climits>
19 #include <cstdio>
20 #include <cstdlib>
21 #include <cstring>
22 #include <dirent.h>
23 #include <securec.h>
24 #include <sys/types.h>
25 #include <sys/sysinfo.h>
26 #include <unistd.h>
27 #include <vector>
28
29 #include "dfx_config.h"
30 #include "dfx_define.h"
31 #include "dfx_logger.h"
32 #include "dfx_ring_buffer_wrapper.h"
33 #include "dfx_signal.h"
34 #include "dfx_util.h"
35 #include "procinfo.h"
36 #include "unique_fd.h"
37
38 namespace OHOS {
39 namespace HiviewDFX {
Create(pid_t pid,pid_t nsPid)40 std::shared_ptr<DfxProcess> DfxProcess::Create(pid_t pid, pid_t nsPid)
41 {
42 auto process = std::make_shared<DfxProcess>(pid, nsPid);
43 return process;
44 }
45
DfxProcess(pid_t pid,pid_t nsPid)46 DfxProcess::DfxProcess(pid_t pid, pid_t nsPid)
47 {
48 InitProcessInfo(pid, nsPid);
49 }
50
InitProcessInfo(pid_t pid,pid_t nsPid)51 void DfxProcess::InitProcessInfo(pid_t pid, pid_t nsPid)
52 {
53 processInfo_.pid = pid;
54 processInfo_.nsPid = nsPid;
55 ReadProcessName(processInfo_.pid, processInfo_.processName);
56 }
57
InitOtherThreads(bool attach)58 bool DfxProcess::InitOtherThreads(bool attach)
59 {
60 std::vector<int> tids;
61 std::vector<int> nstids;
62 if (!GetTidsByPid(processInfo_.pid, tids, nstids)) {
63 return false;
64 }
65
66 for (size_t i = 0; i < nstids.size(); ++i) {
67 if ((recycleTid_ > 0) && (nstids[i] == static_cast<int>(recycleTid_))) {
68 DFXLOG_DEBUG("skip recycle thread:%d.", nstids[i]);
69 continue;
70 }
71
72 if ((keyThread_ != nullptr) && nstids[i] == keyThread_->threadInfo_.nsTid) {
73 DFXLOG_DEBUG("skip key thread:%d.", nstids[i]);
74 continue;
75 }
76
77 auto thread = DfxThread::Create(processInfo_.pid, tids[i], nstids[i]);
78 if (attach) {
79 thread->Attach(PTRACE_ATTATCH_OTHER_THREAD_TIMEOUT);
80 }
81 otherThreads_.push_back(thread);
82 }
83 return true;
84 }
85
ChangeTid(pid_t tid,bool ns)86 pid_t DfxProcess::ChangeTid(pid_t tid, bool ns)
87 {
88 if (processInfo_.pid == processInfo_.nsPid) {
89 return tid;
90 }
91
92 if (kvThreads_.empty()) {
93 std::vector<int> tids;
94 std::vector<int> nstids;
95 if (!GetTidsByPid(processInfo_.pid, tids, nstids)) {
96 return tid;
97 }
98 for (size_t i = 0; i < nstids.size(); ++i) {
99 kvThreads_[nstids[i]] = tids[i];
100 }
101 }
102
103 for (auto iter = kvThreads_.begin(); iter != kvThreads_.end(); iter++) {
104 if (ns && (iter->first == tid)) {
105 return iter->second;
106 }
107 if (!ns && (iter->second == tid)) {
108 return iter->first;
109 }
110 }
111 return tid;
112 }
113
GetOtherThreads()114 std::vector<std::shared_ptr<DfxThread>>& DfxProcess::GetOtherThreads()
115 {
116 return otherThreads_;
117 }
118
ClearOtherThreads()119 void DfxProcess::ClearOtherThreads()
120 {
121 otherThreads_.clear();
122 }
123
Attach(bool hasKey)124 void DfxProcess::Attach(bool hasKey)
125 {
126 if (hasKey && keyThread_) {
127 keyThread_->Attach(PTRACE_ATTATCH_KEY_THREAD_TIMEOUT);
128 }
129
130 if (otherThreads_.empty()) {
131 return;
132 }
133 for (auto thread : otherThreads_) {
134 if (thread->threadInfo_.nsTid == processInfo_.nsPid) {
135 thread->Attach(PTRACE_ATTATCH_KEY_THREAD_TIMEOUT);
136 continue;
137 }
138 thread->Attach(PTRACE_ATTATCH_OTHER_THREAD_TIMEOUT);
139 }
140 }
141
Detach()142 void DfxProcess::Detach()
143 {
144 if (otherThreads_.empty()) {
145 return;
146 }
147
148 for (auto thread : otherThreads_) {
149 thread->Detach();
150 }
151 }
152
SetFatalMessage(const std::string & msg)153 void DfxProcess::SetFatalMessage(const std::string &msg)
154 {
155 fatalMsg_ = msg;
156 }
157
GetFatalMessage() const158 std::string DfxProcess::GetFatalMessage() const
159 {
160 return fatalMsg_;
161 }
162
163 namespace {
GetProcessInfo(pid_t tid,unsigned long long & startTime)164 bool GetProcessInfo(pid_t tid, unsigned long long &startTime)
165 {
166 std::string path = "/proc/" +std::to_string(tid);
167 UniqueFd dirFd(open(path.c_str(), O_DIRECTORY | O_RDONLY));
168 if (dirFd == -1) {
169 return false;
170 }
171
172 UniqueFd statFd(openat(dirFd.Get(), "stat", O_RDONLY | O_CLOEXEC));
173 if (statFd == -1) {
174 return false;
175 }
176
177 std::string statStr;
178 if (!ReadFdToString(statFd.Get(), statStr)) {
179 return false;
180 }
181
182 std::string eoc = statStr.substr(statStr.find_last_of(")"));
183 std::istringstream is(eoc);
184 constexpr int startTimePos = 21;
185 constexpr int base = 10;
186 int pos = 0;
187 std::string tmp;
188 while (is >> tmp && pos <= startTimePos) {
189 pos++;
190 if (pos == startTimePos) {
191 startTime = strtoull(tmp.c_str(), nullptr, base);
192 return true;
193 }
194 }
195 return false;
196 }
197 }
198
GetProcessLifeCycle(pid_t pid)199 std::string DfxProcess::GetProcessLifeCycle(pid_t pid)
200 {
201 struct sysinfo si;
202 sysinfo(&si);
203 unsigned long long startTime = 0;
204 if (GetProcessInfo(pid, startTime)) {
205 if (sysconf(_SC_CLK_TCK) == -1) {
206 return "";
207 }
208 uint64_t upTime = si.uptime - startTime / static_cast<uint32_t>(sysconf(_SC_CLK_TCK));
209 return std::to_string(upTime) + "s";
210 }
211 return "";
212 }
213 } // namespace HiviewDFX
214 } // namespace OHOS
215