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