• 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             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