1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License.
5800b99b8Sopenharmony_ci * You may obtain a copy of the License at
6800b99b8Sopenharmony_ci *
7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8800b99b8Sopenharmony_ci *
9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and
13800b99b8Sopenharmony_ci * limitations under the License.
14800b99b8Sopenharmony_ci */
15800b99b8Sopenharmony_ci
16800b99b8Sopenharmony_ci#include "dfx_process.h"
17800b99b8Sopenharmony_ci
18800b99b8Sopenharmony_ci#include <climits>
19800b99b8Sopenharmony_ci#include <cstdio>
20800b99b8Sopenharmony_ci#include <cstdlib>
21800b99b8Sopenharmony_ci#include <cstring>
22800b99b8Sopenharmony_ci#include <dirent.h>
23800b99b8Sopenharmony_ci#include <securec.h>
24800b99b8Sopenharmony_ci#include <sys/types.h>
25800b99b8Sopenharmony_ci#include <sys/sysinfo.h>
26800b99b8Sopenharmony_ci#include <unistd.h>
27800b99b8Sopenharmony_ci#include <vector>
28800b99b8Sopenharmony_ci
29800b99b8Sopenharmony_ci#include "dfx_config.h"
30800b99b8Sopenharmony_ci#include "dfx_define.h"
31800b99b8Sopenharmony_ci#include "dfx_logger.h"
32800b99b8Sopenharmony_ci#include "dfx_ring_buffer_wrapper.h"
33800b99b8Sopenharmony_ci#include "dfx_signal.h"
34800b99b8Sopenharmony_ci#include "dfx_util.h"
35800b99b8Sopenharmony_ci#include "procinfo.h"
36800b99b8Sopenharmony_ci#include "unique_fd.h"
37800b99b8Sopenharmony_ci
38800b99b8Sopenharmony_cinamespace OHOS {
39800b99b8Sopenharmony_cinamespace HiviewDFX {
40800b99b8Sopenharmony_cistd::shared_ptr<DfxProcess> DfxProcess::Create(pid_t pid, pid_t nsPid)
41800b99b8Sopenharmony_ci{
42800b99b8Sopenharmony_ci    auto process = std::make_shared<DfxProcess>(pid, nsPid);
43800b99b8Sopenharmony_ci    return process;
44800b99b8Sopenharmony_ci}
45800b99b8Sopenharmony_ci
46800b99b8Sopenharmony_ciDfxProcess::DfxProcess(pid_t pid, pid_t nsPid)
47800b99b8Sopenharmony_ci{
48800b99b8Sopenharmony_ci    InitProcessInfo(pid, nsPid);
49800b99b8Sopenharmony_ci}
50800b99b8Sopenharmony_ci
51800b99b8Sopenharmony_civoid DfxProcess::InitProcessInfo(pid_t pid, pid_t nsPid)
52800b99b8Sopenharmony_ci{
53800b99b8Sopenharmony_ci    processInfo_.pid = pid;
54800b99b8Sopenharmony_ci    processInfo_.nsPid = nsPid;
55800b99b8Sopenharmony_ci    ReadProcessName(processInfo_.pid, processInfo_.processName);
56800b99b8Sopenharmony_ci}
57800b99b8Sopenharmony_ci
58800b99b8Sopenharmony_cibool DfxProcess::InitOtherThreads(bool attach)
59800b99b8Sopenharmony_ci{
60800b99b8Sopenharmony_ci    std::vector<int> tids;
61800b99b8Sopenharmony_ci    std::vector<int> nstids;
62800b99b8Sopenharmony_ci    if (!GetTidsByPid(processInfo_.pid, tids, nstids)) {
63800b99b8Sopenharmony_ci        return false;
64800b99b8Sopenharmony_ci    }
65800b99b8Sopenharmony_ci
66800b99b8Sopenharmony_ci    for (size_t i = 0; i < nstids.size(); ++i) {
67800b99b8Sopenharmony_ci        if ((recycleTid_ > 0) && (nstids[i] == static_cast<int>(recycleTid_))) {
68800b99b8Sopenharmony_ci            DFXLOGD("skip recycle thread:%{public}d.", nstids[i]);
69800b99b8Sopenharmony_ci            continue;
70800b99b8Sopenharmony_ci        }
71800b99b8Sopenharmony_ci
72800b99b8Sopenharmony_ci        if ((keyThread_ != nullptr) && nstids[i] == keyThread_->threadInfo_.nsTid) {
73800b99b8Sopenharmony_ci            DFXLOGD("skip key thread:%{public}d.", nstids[i]);
74800b99b8Sopenharmony_ci            continue;
75800b99b8Sopenharmony_ci        }
76800b99b8Sopenharmony_ci
77800b99b8Sopenharmony_ci        auto thread = DfxThread::Create(processInfo_.pid, tids[i], nstids[i]);
78800b99b8Sopenharmony_ci        if (attach) {
79800b99b8Sopenharmony_ci            thread->Attach(PTRACE_ATTATCH_OTHER_THREAD_TIMEOUT);
80800b99b8Sopenharmony_ci        }
81800b99b8Sopenharmony_ci        otherThreads_.push_back(thread);
82800b99b8Sopenharmony_ci    }
83800b99b8Sopenharmony_ci    return true;
84800b99b8Sopenharmony_ci}
85800b99b8Sopenharmony_ci
86800b99b8Sopenharmony_cipid_t DfxProcess::ChangeTid(pid_t tid, bool ns)
87800b99b8Sopenharmony_ci{
88800b99b8Sopenharmony_ci    if (processInfo_.pid == processInfo_.nsPid) {
89800b99b8Sopenharmony_ci        return tid;
90800b99b8Sopenharmony_ci    }
91800b99b8Sopenharmony_ci
92800b99b8Sopenharmony_ci    if (kvThreads_.empty()) {
93800b99b8Sopenharmony_ci        std::vector<int> tids;
94800b99b8Sopenharmony_ci        std::vector<int> nstids;
95800b99b8Sopenharmony_ci        if (!GetTidsByPid(processInfo_.pid, tids, nstids)) {
96800b99b8Sopenharmony_ci            return tid;
97800b99b8Sopenharmony_ci        }
98800b99b8Sopenharmony_ci        for (size_t i = 0; i < nstids.size(); ++i) {
99800b99b8Sopenharmony_ci            kvThreads_[nstids[i]] = tids[i];
100800b99b8Sopenharmony_ci        }
101800b99b8Sopenharmony_ci    }
102800b99b8Sopenharmony_ci
103800b99b8Sopenharmony_ci    for (auto iter = kvThreads_.begin(); iter != kvThreads_.end(); iter++) {
104800b99b8Sopenharmony_ci        if (ns && (iter->first == tid)) {
105800b99b8Sopenharmony_ci            return iter->second;
106800b99b8Sopenharmony_ci        }
107800b99b8Sopenharmony_ci        if (!ns && (iter->second == tid)) {
108800b99b8Sopenharmony_ci            return iter->first;
109800b99b8Sopenharmony_ci        }
110800b99b8Sopenharmony_ci    }
111800b99b8Sopenharmony_ci    return tid;
112800b99b8Sopenharmony_ci}
113800b99b8Sopenharmony_ci
114800b99b8Sopenharmony_cistd::vector<std::shared_ptr<DfxThread>>& DfxProcess::GetOtherThreads()
115800b99b8Sopenharmony_ci{
116800b99b8Sopenharmony_ci    return otherThreads_;
117800b99b8Sopenharmony_ci}
118800b99b8Sopenharmony_ci
119800b99b8Sopenharmony_civoid DfxProcess::ClearOtherThreads()
120800b99b8Sopenharmony_ci{
121800b99b8Sopenharmony_ci    otherThreads_.clear();
122800b99b8Sopenharmony_ci}
123800b99b8Sopenharmony_ci
124800b99b8Sopenharmony_civoid DfxProcess::Attach(bool hasKey)
125800b99b8Sopenharmony_ci{
126800b99b8Sopenharmony_ci    if (hasKey && keyThread_) {
127800b99b8Sopenharmony_ci        keyThread_->Attach(PTRACE_ATTATCH_KEY_THREAD_TIMEOUT);
128800b99b8Sopenharmony_ci    }
129800b99b8Sopenharmony_ci
130800b99b8Sopenharmony_ci    if (otherThreads_.empty()) {
131800b99b8Sopenharmony_ci        return;
132800b99b8Sopenharmony_ci    }
133800b99b8Sopenharmony_ci    for (auto thread : otherThreads_) {
134800b99b8Sopenharmony_ci        if (thread->threadInfo_.nsTid == processInfo_.nsPid) {
135800b99b8Sopenharmony_ci            thread->Attach(PTRACE_ATTATCH_KEY_THREAD_TIMEOUT);
136800b99b8Sopenharmony_ci            continue;
137800b99b8Sopenharmony_ci        }
138800b99b8Sopenharmony_ci        thread->Attach(PTRACE_ATTATCH_OTHER_THREAD_TIMEOUT);
139800b99b8Sopenharmony_ci    }
140800b99b8Sopenharmony_ci}
141800b99b8Sopenharmony_ci
142800b99b8Sopenharmony_civoid DfxProcess::Detach()
143800b99b8Sopenharmony_ci{
144800b99b8Sopenharmony_ci    if (otherThreads_.empty()) {
145800b99b8Sopenharmony_ci        return;
146800b99b8Sopenharmony_ci    }
147800b99b8Sopenharmony_ci
148800b99b8Sopenharmony_ci    for (auto thread : otherThreads_) {
149800b99b8Sopenharmony_ci        thread->Detach();
150800b99b8Sopenharmony_ci    }
151800b99b8Sopenharmony_ci}
152800b99b8Sopenharmony_ci
153800b99b8Sopenharmony_civoid DfxProcess::SetFatalMessage(const std::string &msg)
154800b99b8Sopenharmony_ci{
155800b99b8Sopenharmony_ci    fatalMsg_ = msg;
156800b99b8Sopenharmony_ci}
157800b99b8Sopenharmony_ci
158800b99b8Sopenharmony_cistd::string DfxProcess::GetFatalMessage() const
159800b99b8Sopenharmony_ci{
160800b99b8Sopenharmony_ci    return fatalMsg_;
161800b99b8Sopenharmony_ci}
162800b99b8Sopenharmony_ci
163800b99b8Sopenharmony_cinamespace {
164800b99b8Sopenharmony_cibool GetProcessInfo(pid_t tid, unsigned long long &startTime)
165800b99b8Sopenharmony_ci{
166800b99b8Sopenharmony_ci    std::string path = "/proc/" +std::to_string(tid);
167800b99b8Sopenharmony_ci    UniqueFd dirFd(open(path.c_str(), O_DIRECTORY | O_RDONLY));
168800b99b8Sopenharmony_ci    if (dirFd == -1) {
169800b99b8Sopenharmony_ci        return false;
170800b99b8Sopenharmony_ci    }
171800b99b8Sopenharmony_ci
172800b99b8Sopenharmony_ci    UniqueFd statFd(openat(dirFd.Get(), "stat", O_RDONLY | O_CLOEXEC));
173800b99b8Sopenharmony_ci    if (statFd == -1) {
174800b99b8Sopenharmony_ci        return false;
175800b99b8Sopenharmony_ci    }
176800b99b8Sopenharmony_ci
177800b99b8Sopenharmony_ci    std::string statStr;
178800b99b8Sopenharmony_ci    if (!ReadFdToString(statFd.Get(), statStr)) {
179800b99b8Sopenharmony_ci        return false;
180800b99b8Sopenharmony_ci    }
181800b99b8Sopenharmony_ci
182800b99b8Sopenharmony_ci    std::string eoc = statStr.substr(statStr.find_last_of(")"));
183800b99b8Sopenharmony_ci    std::istringstream is(eoc);
184800b99b8Sopenharmony_ci    constexpr int startTimePos = 21;
185800b99b8Sopenharmony_ci    constexpr int base = 10;
186800b99b8Sopenharmony_ci    int pos = 0;
187800b99b8Sopenharmony_ci    std::string tmp;
188800b99b8Sopenharmony_ci    while (is >> tmp && pos <= startTimePos) {
189800b99b8Sopenharmony_ci        pos++;
190800b99b8Sopenharmony_ci        if (pos == startTimePos) {
191800b99b8Sopenharmony_ci            startTime = strtoull(tmp.c_str(), nullptr, base);
192800b99b8Sopenharmony_ci            return true;
193800b99b8Sopenharmony_ci        }
194800b99b8Sopenharmony_ci    }
195800b99b8Sopenharmony_ci    return false;
196800b99b8Sopenharmony_ci}
197800b99b8Sopenharmony_ci}
198800b99b8Sopenharmony_ci
199800b99b8Sopenharmony_cistd::string DfxProcess::GetProcessLifeCycle(pid_t pid)
200800b99b8Sopenharmony_ci{
201800b99b8Sopenharmony_ci    struct sysinfo si;
202800b99b8Sopenharmony_ci    sysinfo(&si);
203800b99b8Sopenharmony_ci    unsigned long long startTime = 0;
204800b99b8Sopenharmony_ci    if (GetProcessInfo(pid, startTime)) {
205800b99b8Sopenharmony_ci        if (sysconf(_SC_CLK_TCK) == -1) {
206800b99b8Sopenharmony_ci            return "";
207800b99b8Sopenharmony_ci        }
208800b99b8Sopenharmony_ci        uint64_t upTime = si.uptime - startTime / static_cast<uint32_t>(sysconf(_SC_CLK_TCK));
209800b99b8Sopenharmony_ci        return std::to_string(upTime) + "s";
210800b99b8Sopenharmony_ci    }
211800b99b8Sopenharmony_ci    return "";
212800b99b8Sopenharmony_ci}
213800b99b8Sopenharmony_ci} // namespace HiviewDFX
214800b99b8Sopenharmony_ci} // namespace OHOS
215