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() const114 std::vector<std::shared_ptr<DfxThread>> DfxProcess::GetOtherThreads() const
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 thread->Attach(PTRACE_ATTATCH_OTHER_THREAD_TIMEOUT);
135 }
136 }
137
Detach()138 void DfxProcess::Detach()
139 {
140 if (otherThreads_.empty()) {
141 return;
142 }
143
144 for (auto thread : otherThreads_) {
145 thread->Detach();
146 }
147 }
148
SetFatalMessage(const std::string & msg)149 void DfxProcess::SetFatalMessage(const std::string &msg)
150 {
151 fatalMsg_ = msg;
152 }
153
GetFatalMessage() const154 std::string DfxProcess::GetFatalMessage() const
155 {
156 return fatalMsg_;
157 }
158
159 namespace {
GetProcessInfo(pid_t tid,unsigned long long & startTime)160 bool GetProcessInfo(pid_t tid, unsigned long long &startTime)
161 {
162 std::string path = "/proc/" +std::to_string(tid);
163 UniqueFd dirFd(open(path.c_str(), O_DIRECTORY | O_RDONLY));
164 if (dirFd == -1) {
165 return false;
166 }
167
168 UniqueFd statFd(openat(dirFd.Get(), "stat", O_RDONLY | O_CLOEXEC));
169 if (statFd == -1) {
170 return false;
171 }
172
173 std::string statStr;
174 if (!ReadFdToString(statFd.Get(), statStr)) {
175 return false;
176 }
177
178 std::string eoc = statStr.substr(statStr.find_last_of(")"));
179 std::istringstream is(eoc);
180 constexpr int startTimePos = 21;
181 constexpr int base = 10;
182 int pos = 0;
183 std::string tmp;
184 while (is >> tmp && pos <= startTimePos) {
185 pos++;
186 if (pos == startTimePos) {
187 startTime = strtoull(tmp.c_str(), nullptr, base);
188 return true;
189 }
190 }
191 return false;
192 }
193 }
194
GetProcessLifeCycle(pid_t pid)195 std::string DfxProcess::GetProcessLifeCycle(pid_t pid)
196 {
197 struct sysinfo si;
198 sysinfo(&si);
199 unsigned long long startTime = 0;
200 if (GetProcessInfo(pid, startTime)) {
201 if (sysconf(_SC_CLK_TCK) == -1) {
202 return "";
203 }
204 uint64_t upTime = si.uptime - startTime / static_cast<uint32_t>(sysconf(_SC_CLK_TCK));
205 return std::to_string(upTime) + "s";
206 }
207 return "";
208 }
209 } // namespace HiviewDFX
210 } // namespace OHOS
211