• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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             DFXLOGD("skip recycle thread:%{public}d.", nstids[i]);
69             continue;
70         }
71 
72         if ((keyThread_ != nullptr) && nstids[i] == keyThread_->threadInfo_.nsTid) {
73             DFXLOGD("skip key thread:%{public}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         DFXLOGE("GetProcessInfo open %{public}s fail. errno %{public}d", path.c_str(), errno);
170         return false;
171     }
172 
173     UniqueFd statFd(openat(dirFd.Get(), "stat", O_RDONLY | O_CLOEXEC));
174     if (statFd == -1) {
175         DFXLOGE("GetProcessInfo open %{public}s/stat fail. errno %{public}d", path.c_str(), errno);
176         return false;
177     }
178 
179     std::string statStr;
180     if (!ReadFdToString(statFd.Get(), statStr)) {
181         DFXLOGE("GetProcessInfo read string fail.");
182         return false;
183     }
184 
185     std::string eoc = statStr.substr(statStr.find_last_of(")"));
186     std::istringstream is(eoc);
187     constexpr int startTimePos = 21;
188     constexpr int base = 10;
189     int pos = 0;
190     std::string tmp;
191     while (is >> tmp && pos <= startTimePos) {
192         pos++;
193         if (pos == startTimePos) {
194             startTime = strtoull(tmp.c_str(), nullptr, base);
195             return true;
196         }
197     }
198     DFXLOGE("GetProcessInfo Get process info fail.");
199     return false;
200 }
201 }
202 
GetProcessLifeCycle(pid_t pid)203 std::string DfxProcess::GetProcessLifeCycle(pid_t pid)
204 {
205     struct sysinfo si;
206     sysinfo(&si);
207     unsigned long long startTime = 0;
208     if (GetProcessInfo(pid, startTime)) {
209         auto clkTck = sysconf(_SC_CLK_TCK);
210         if (clkTck == -1) {
211             DFXLOGE("Get _SC_CLK_TCK fail. errno %{public}d", errno);
212             return "";
213         }
214         uint64_t upTime = si.uptime - startTime / static_cast<uint32_t>(clkTck);
215         return std::to_string(upTime) + "s";
216     }
217     return "";
218 }
219 } // namespace HiviewDFX
220 } // namespace OHOS
221