• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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 "process_dump_config.h"
30 #include "crash_exception.h"
31 #include "dfx_define.h"
32 
33 #include "dfx_buffer_writer.h"
34 #include "dfx_log.h"
35 #include "dfx_signal.h"
36 #include "dfx_util.h"
37 #include "procinfo.h"
38 #include "unique_fd.h"
39 
40 namespace OHOS {
41 namespace HiviewDFX {
InitProcessInfo(pid_t pid,pid_t nsPid,uid_t uid,const std::string & processName)42 void DfxProcess::InitProcessInfo(pid_t pid, pid_t nsPid, uid_t uid, const std::string& processName)
43 {
44     processInfo_.pid = pid;
45     processInfo_.nsPid = nsPid;
46     processInfo_.uid = uid;
47     processInfo_.processName = processName;
48 }
49 
InitKeyThread(const ProcessDumpRequest & request)50 bool DfxProcess::InitKeyThread(const ProcessDumpRequest& request)
51 {
52     pid_t nsTid = request.tid;
53     pid_t tid = ChangeTid(nsTid, true);
54     keyThread_ = DfxThread::Create(processInfo_.pid, tid, nsTid);
55     if (!keyThread_->Attach(PTRACE_ATTATCH_KEY_THREAD_TIMEOUT)) {
56         DFXLOGE("Failed to attach key thread(%{public}d).", nsTid);
57         ReportCrashException(CrashExceptionCode::CRASH_DUMP_EATTACH);
58         if (request.type == ProcessDumpType::DUMP_TYPE_DUMP_CATCH) {
59             return false;
60         }
61     }
62     if (keyThread_->GetThreadInfo().threadName.empty()) {
63         keyThread_->SetThreadName(std::string(request.threadName));
64     }
65     keyThread_->SetThreadRegs(DfxRegs::CreateFromUcontext(request.context));
66     if (request.type == ProcessDumpType::DUMP_TYPE_DUMP_CATCH) { // dumpcatch set target thread to key thread
67         pid_t dumpCatchTargetTid = request.siginfo.si_value.sival_int == 0 ?
68             request.nsPid : request.siginfo.si_value.sival_int;
69         DFXLOGE("dumpCatchTargetTid(%{public}d).", dumpCatchTargetTid);
70         if (dumpCatchTargetTid != tid) {
71             otherThreads_.emplace_back(keyThread_);
72             keyThread_ = DfxThread::Create(processInfo_.pid, dumpCatchTargetTid, dumpCatchTargetTid);
73             if (keyThread_ != nullptr && keyThread_->Attach(PTRACE_ATTATCH_OTHER_THREAD_TIMEOUT)) {
74                 keyThread_->SetThreadRegs(DfxRegs::CreateRemoteRegs(dumpCatchTargetTid));
75             }
76         }
77     }
78     return true;
79 }
80 
InitOtherThreads(pid_t requestTid)81 bool DfxProcess::InitOtherThreads(pid_t requestTid)
82 {
83     std::vector<int> tids;
84     std::vector<int> nstids;
85     if (!GetTidsByPid(processInfo_.pid, tids, nstids)) {
86         return false;
87     }
88     pid_t keyThreadNsTid = 0;
89     if (keyThread_ != nullptr) {
90         keyThreadNsTid = keyThread_->GetThreadInfo().nsTid;
91     }
92     for (size_t i = 0; i < nstids.size(); ++i) {
93         // KeyThread and requestThread have been initialized, skip directly
94         if ((nstids[i] == keyThreadNsTid) || nstids[i] == requestTid) {
95             continue;
96         }
97         auto thread = DfxThread::Create(processInfo_.pid, tids[i], nstids[i]);
98         if (thread->Attach(PTRACE_ATTATCH_OTHER_THREAD_TIMEOUT)) {
99             thread->SetThreadRegs(DfxRegs::CreateRemoteRegs(thread->GetThreadInfo().nsTid));
100         }
101         otherThreads_.push_back(thread);
102     }
103     return true;
104 }
105 
ChangeTid(pid_t tid,bool ns)106 pid_t DfxProcess::ChangeTid(pid_t tid, bool ns)
107 {
108     if (processInfo_.pid == processInfo_.nsPid) {
109         return tid;
110     }
111 
112     if (kvThreads_.empty()) {
113         std::vector<int> tids;
114         std::vector<int> nstids;
115         if (!GetTidsByPid(processInfo_.pid, tids, nstids)) {
116             return tid;
117         }
118         for (size_t i = 0; i < nstids.size(); ++i) {
119             kvThreads_[nstids[i]] = tids[i];
120         }
121     }
122 
123     for (auto iter = kvThreads_.begin(); iter != kvThreads_.end(); iter++) {
124         if (ns && (iter->first == tid)) {
125             return iter->second;
126         }
127         if (!ns && (iter->second == tid)) {
128             return iter->first;
129         }
130     }
131     return tid;
132 }
133 
GetOtherThreads()134 std::vector<std::shared_ptr<DfxThread>>& DfxProcess::GetOtherThreads()
135 {
136     return otherThreads_;
137 }
138 
ClearOtherThreads()139 void DfxProcess::ClearOtherThreads()
140 {
141     otherThreads_.clear();
142 }
143 
Attach(bool hasKey)144 void DfxProcess::Attach(bool hasKey)
145 {
146     if (hasKey && keyThread_) {
147         keyThread_->Attach(PTRACE_ATTATCH_KEY_THREAD_TIMEOUT);
148     }
149 
150     if (otherThreads_.empty()) {
151         return;
152     }
153     for (auto& thread : otherThreads_) {
154         if (thread->GetThreadInfo().nsTid == processInfo_.nsPid) {
155             thread->Attach(PTRACE_ATTATCH_KEY_THREAD_TIMEOUT);
156             continue;
157         }
158         thread->Attach(PTRACE_ATTATCH_OTHER_THREAD_TIMEOUT);
159     }
160 }
161 
Detach()162 void DfxProcess::Detach()
163 {
164     if (keyThread_ != nullptr) {
165         keyThread_->Detach();
166     }
167 
168     for (const auto& thread : otherThreads_) {
169         if (thread != nullptr) {
170             thread->Detach();
171         }
172     }
173 }
174 
AppendFatalMessage(const std::string & msg)175 void DfxProcess::AppendFatalMessage(const std::string &msg)
176 {
177     fatalMsg_ += msg;
178 }
179 
GetFatalMessage() const180 const std::string& DfxProcess::GetFatalMessage() const
181 {
182     return fatalMsg_;
183 }
184 
185 namespace {
GetProcessStartTime(pid_t tid,unsigned long long & startTime)186 bool GetProcessStartTime(pid_t tid, unsigned long long &startTime)
187 {
188     std::string path = "/proc/" +std::to_string(tid);
189     UniqueFd dirFd(open(path.c_str(), O_DIRECTORY | O_RDONLY));
190     if (dirFd == -1) {
191         DFXLOGE("GetProcessInfo open %{public}s fail. errno %{public}d", path.c_str(), errno);
192         return false;
193     }
194 
195     UniqueFd statFd(openat(dirFd.Get(), "stat", O_RDONLY | O_CLOEXEC));
196     if (statFd == -1) {
197         DFXLOGE("GetProcessInfo open %{public}s/stat fail. errno %{public}d", path.c_str(), errno);
198         return false;
199     }
200 
201     std::string statStr;
202     if (!ReadFdToString(statFd.Get(), statStr)) {
203         DFXLOGE("GetProcessInfo read string fail.");
204         return false;
205     }
206 
207     std::string eoc = statStr.substr(statStr.find_last_of(")"));
208     std::istringstream is(eoc);
209     constexpr int startTimePos = 21;
210     constexpr int base = 10;
211     int pos = 0;
212     std::string tmp;
213     while (is >> tmp && pos <= startTimePos) {
214         pos++;
215         if (pos == startTimePos) {
216             startTime = strtoull(tmp.c_str(), nullptr, base);
217             return true;
218         }
219     }
220     DFXLOGE("GetProcessInfo Get process info fail.");
221     return false;
222 }
223 }
224 
GetProcessLifeCycle()225 std::string DfxProcess::GetProcessLifeCycle()
226 {
227     struct timespec ts;
228     (void)clock_gettime(CLOCK_BOOTTIME, &ts);
229     uint64_t sysUpTime = static_cast<uint64_t>(ts.tv_sec + static_cast<time_t>(ts.tv_nsec != 0 ? 1L : 0L));
230 
231     unsigned long long startTime = 0;
232     if (GetProcessStartTime(processInfo_.pid, startTime)) {
233         auto clkTck = sysconf(_SC_CLK_TCK);
234         if (clkTck == -1) {
235             DFXLOGE("Get _SC_CLK_TCK fail. errno %{public}d", errno);
236             return "";
237         }
238         uint64_t procUpTime = sysUpTime - startTime / static_cast<uint32_t>(clkTck);
239         constexpr uint64_t invalidTimeLimit = 10 * 365 * 24 * 3600; // 10 year
240         if (procUpTime > invalidTimeLimit) {
241             DFXLOGE("invalid system upTime %{public}" PRIu64"  proc upTime: %{public}" PRIu64 ",  "
242                 "startTime: %{public}llu.", sysUpTime, procUpTime, startTime);
243             return "";
244         }
245         return std::to_string(procUpTime) + "s";
246     }
247     return "";
248 }
249 } // namespace HiviewDFX
250 } // namespace OHOS
251