1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 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_sigdump_handler.h"
17800b99b8Sopenharmony_ci
18800b99b8Sopenharmony_ci#include <cinttypes>
19800b99b8Sopenharmony_ci#include <csignal>
20800b99b8Sopenharmony_ci#include <ctime>
21800b99b8Sopenharmony_ci#include <mutex>
22800b99b8Sopenharmony_ci#include <sigchain.h>
23800b99b8Sopenharmony_ci#include <sys/syscall.h>
24800b99b8Sopenharmony_ci#include <thread>
25800b99b8Sopenharmony_ci#include <unistd.h>
26800b99b8Sopenharmony_ci
27800b99b8Sopenharmony_ci#include "backtrace_local.h"
28800b99b8Sopenharmony_ci#include "dfx_define.h"
29800b99b8Sopenharmony_ci#include "dfx_dump_res.h"
30800b99b8Sopenharmony_ci#include "dfx_log.h"
31800b99b8Sopenharmony_ci#include "faultloggerd_client.h"
32800b99b8Sopenharmony_ci
33800b99b8Sopenharmony_cinamespace OHOS {
34800b99b8Sopenharmony_cinamespace HiviewDFX {
35800b99b8Sopenharmony_cinamespace {
36800b99b8Sopenharmony_ci#ifdef LOG_DOMAIN
37800b99b8Sopenharmony_ci#undef LOG_DOMAIN
38800b99b8Sopenharmony_ci#define LOG_DOMAIN 0xD002D11
39800b99b8Sopenharmony_ci#endif
40800b99b8Sopenharmony_ci
41800b99b8Sopenharmony_ci#ifdef LOG_TAG
42800b99b8Sopenharmony_ci#undef LOG_TAG
43800b99b8Sopenharmony_ci#define LOG_TAG "DfxSigDumpHandler"
44800b99b8Sopenharmony_ci#endif
45800b99b8Sopenharmony_ci}
46800b99b8Sopenharmony_ci
47800b99b8Sopenharmony_cistatic const struct timespec SIG_WAIT_TIMEOUT = {
48800b99b8Sopenharmony_ci    .tv_sec = 1,
49800b99b8Sopenharmony_ci    .tv_nsec = 0,
50800b99b8Sopenharmony_ci};
51800b99b8Sopenharmony_ci
52800b99b8Sopenharmony_ciclass DfxSigDumpHandler {
53800b99b8Sopenharmony_cipublic:
54800b99b8Sopenharmony_ci    static DfxSigDumpHandler& GetInstance(void);
55800b99b8Sopenharmony_ci    bool Init(void);
56800b99b8Sopenharmony_ci    void Deinit(void);
57800b99b8Sopenharmony_ci    bool IsThreadRunning(void) const;
58800b99b8Sopenharmony_ci    int GetRunThreadId(void) const;
59800b99b8Sopenharmony_ci    void SetRunThreadId(int tid);
60800b99b8Sopenharmony_ciprivate:
61800b99b8Sopenharmony_ci    DfxSigDumpHandler() = default;
62800b99b8Sopenharmony_ci    DfxSigDumpHandler(DfxSigDumpHandler&) = delete;
63800b99b8Sopenharmony_ci    DfxSigDumpHandler& operator=(const DfxSigDumpHandler&)=delete;
64800b99b8Sopenharmony_ci    static void RunThread(void);
65800b99b8Sopenharmony_ci    static void SignalDumpRetranHandler(int signo, siginfo_t* si, void* context);
66800b99b8Sopenharmony_ci    bool isThreadRunning_{false};
67800b99b8Sopenharmony_ci    int runThreadId_{0};
68800b99b8Sopenharmony_ci};
69800b99b8Sopenharmony_ci
70800b99b8Sopenharmony_ciDfxSigDumpHandler& DfxSigDumpHandler::GetInstance()
71800b99b8Sopenharmony_ci{
72800b99b8Sopenharmony_ci    static DfxSigDumpHandler sigDumperHandler;
73800b99b8Sopenharmony_ci    return sigDumperHandler;
74800b99b8Sopenharmony_ci}
75800b99b8Sopenharmony_ci
76800b99b8Sopenharmony_cibool DfxSigDumpHandler::IsThreadRunning() const
77800b99b8Sopenharmony_ci{
78800b99b8Sopenharmony_ci    return isThreadRunning_;
79800b99b8Sopenharmony_ci}
80800b99b8Sopenharmony_ci
81800b99b8Sopenharmony_ciint DfxSigDumpHandler::GetRunThreadId() const
82800b99b8Sopenharmony_ci{
83800b99b8Sopenharmony_ci    return runThreadId_;
84800b99b8Sopenharmony_ci}
85800b99b8Sopenharmony_ci
86800b99b8Sopenharmony_civoid DfxSigDumpHandler::SetRunThreadId(int tid)
87800b99b8Sopenharmony_ci{
88800b99b8Sopenharmony_ci    runThreadId_ = tid;
89800b99b8Sopenharmony_ci}
90800b99b8Sopenharmony_ci
91800b99b8Sopenharmony_civoid DfxSigDumpHandler::SignalDumpRetranHandler(int signo, siginfo_t* si, void* context)
92800b99b8Sopenharmony_ci{
93800b99b8Sopenharmony_ci    int tid = DfxSigDumpHandler::GetInstance().GetRunThreadId();
94800b99b8Sopenharmony_ci    if (tid == 0) {
95800b99b8Sopenharmony_ci        return;
96800b99b8Sopenharmony_ci    }
97800b99b8Sopenharmony_ci    if (syscall(SYS_tkill, tid, SIGDUMP) != 0) {
98800b99b8Sopenharmony_ci        return;
99800b99b8Sopenharmony_ci    }
100800b99b8Sopenharmony_ci}
101800b99b8Sopenharmony_ci
102800b99b8Sopenharmony_civoid DfxSigDumpHandler::RunThread()
103800b99b8Sopenharmony_ci{
104800b99b8Sopenharmony_ci    sigset_t set;
105800b99b8Sopenharmony_ci    sigemptyset(&set);
106800b99b8Sopenharmony_ci    sigaddset(&set, SIGDUMP);
107800b99b8Sopenharmony_ci    if (pthread_sigmask(SIG_BLOCK, &set, nullptr) != 0) {
108800b99b8Sopenharmony_ci        DFXLOGE("pthread sigmask failed, err(%{public}d)", errno);
109800b99b8Sopenharmony_ci    }
110800b99b8Sopenharmony_ci    DfxSigDumpHandler::GetInstance().SetRunThreadId(gettid());
111800b99b8Sopenharmony_ci    while (DfxSigDumpHandler::GetInstance().IsThreadRunning()) {
112800b99b8Sopenharmony_ci        siginfo_t si;
113800b99b8Sopenharmony_ci        if (OHOS_TEMP_FAILURE_RETRY(sigtimedwait(&set, &si, &SIG_WAIT_TIMEOUT)) == -1) {
114800b99b8Sopenharmony_ci            continue;
115800b99b8Sopenharmony_ci        }
116800b99b8Sopenharmony_ci        int32_t resFd = -1;
117800b99b8Sopenharmony_ci        int res = DUMP_ESUCCESS;
118800b99b8Sopenharmony_ci        int32_t pid = getpid();
119800b99b8Sopenharmony_ci        FaultLoggerPipeType jsonType = FaultLoggerPipeType::PIPE_FD_JSON_WRITE_RES;
120800b99b8Sopenharmony_ci        int32_t fd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_JSON_WRITE_BUF);
121800b99b8Sopenharmony_ci        if (fd < 0) {
122800b99b8Sopenharmony_ci            fd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_WRITE_BUF);
123800b99b8Sopenharmony_ci            jsonType = FaultLoggerPipeType::PIPE_FD_WRITE_RES;
124800b99b8Sopenharmony_ci        }
125800b99b8Sopenharmony_ci        if (fd < 0) {
126800b99b8Sopenharmony_ci            DFXLOGE("Pid %{public}d GetPipeFd Failed", pid);
127800b99b8Sopenharmony_ci            continue;
128800b99b8Sopenharmony_ci        }
129800b99b8Sopenharmony_ci        resFd = RequestPipeFd(pid, jsonType);
130800b99b8Sopenharmony_ci        if (resFd < 0) {
131800b99b8Sopenharmony_ci            DFXLOGE("Pid %{public}d GetPipeResFd Failed", pid);
132800b99b8Sopenharmony_ci            close(fd);
133800b99b8Sopenharmony_ci            continue;
134800b99b8Sopenharmony_ci        }
135800b99b8Sopenharmony_ci        std::string dumpInfo = OHOS::HiviewDFX::GetProcessStacktrace();
136800b99b8Sopenharmony_ci        const ssize_t nwrite = static_cast<ssize_t>(dumpInfo.length());
137800b99b8Sopenharmony_ci        if (!dumpInfo.empty() &&
138800b99b8Sopenharmony_ci                OHOS_TEMP_FAILURE_RETRY(write(fd, dumpInfo.data(), dumpInfo.length())) != nwrite) {
139800b99b8Sopenharmony_ci            DFXLOGE("Pid %{public}d Write Buf Pipe Failed(%{public}d), nwrite(%{public}zd)", pid, errno, nwrite);
140800b99b8Sopenharmony_ci            res = DUMP_EBADFRAME;
141800b99b8Sopenharmony_ci        } else if (dumpInfo.empty()) {
142800b99b8Sopenharmony_ci            res = DUMP_ENOINFO;
143800b99b8Sopenharmony_ci        }
144800b99b8Sopenharmony_ci        ssize_t nres = OHOS_TEMP_FAILURE_RETRY(write(resFd, &res, sizeof(res)));
145800b99b8Sopenharmony_ci        if (nres != sizeof(res)) {
146800b99b8Sopenharmony_ci            DFXLOGE("Pid %{public}d Write Res Pipe Failed(%{public}d), nres(%{public}zd)", pid, errno, nres);
147800b99b8Sopenharmony_ci        }
148800b99b8Sopenharmony_ci        close(fd);
149800b99b8Sopenharmony_ci        close(resFd);
150800b99b8Sopenharmony_ci    }
151800b99b8Sopenharmony_ci}
152800b99b8Sopenharmony_ci
153800b99b8Sopenharmony_cibool DfxSigDumpHandler::Init()
154800b99b8Sopenharmony_ci{
155800b99b8Sopenharmony_ci    if (IsThreadRunning()) {
156800b99b8Sopenharmony_ci        DFXLOGI("SigDumpHandler Thread has been inited");
157800b99b8Sopenharmony_ci        return true;
158800b99b8Sopenharmony_ci    }
159800b99b8Sopenharmony_ci    remove_all_special_handler(SIGDUMP);
160800b99b8Sopenharmony_ci    struct sigaction action;
161800b99b8Sopenharmony_ci    (void)memset_s(&action, sizeof(action), 0, sizeof(action));
162800b99b8Sopenharmony_ci    sigemptyset(&action.sa_mask);
163800b99b8Sopenharmony_ci    sigaddset(&action.sa_mask, SIGDUMP);
164800b99b8Sopenharmony_ci    action.sa_flags = SA_RESTART | SA_SIGINFO;
165800b99b8Sopenharmony_ci    action.sa_sigaction = DfxSigDumpHandler::SignalDumpRetranHandler;
166800b99b8Sopenharmony_ci    DFXLOGI("Init Install signal handler");
167800b99b8Sopenharmony_ci    sigaction(SIGDUMP, &action, nullptr);
168800b99b8Sopenharmony_ci    isThreadRunning_ = true;
169800b99b8Sopenharmony_ci    std::thread catchThread = std::thread(&DfxSigDumpHandler::RunThread);
170800b99b8Sopenharmony_ci    catchThread.detach();
171800b99b8Sopenharmony_ci    return true;
172800b99b8Sopenharmony_ci}
173800b99b8Sopenharmony_ci
174800b99b8Sopenharmony_civoid DfxSigDumpHandler::Deinit()
175800b99b8Sopenharmony_ci{
176800b99b8Sopenharmony_ci    isThreadRunning_ = false;
177800b99b8Sopenharmony_ci}
178800b99b8Sopenharmony_ci} // namespace HiviewDFX
179800b99b8Sopenharmony_ci} // namespace OHOS
180800b99b8Sopenharmony_ci
181800b99b8Sopenharmony_cibool InitSigDumpHandler()
182800b99b8Sopenharmony_ci{
183800b99b8Sopenharmony_ci    return OHOS::HiviewDFX::DfxSigDumpHandler::GetInstance().Init();
184800b99b8Sopenharmony_ci}
185800b99b8Sopenharmony_ci
186800b99b8Sopenharmony_civoid DeinitSigDumpHandler()
187800b99b8Sopenharmony_ci{
188800b99b8Sopenharmony_ci    OHOS::HiviewDFX::DfxSigDumpHandler::GetInstance().Deinit();
189800b99b8Sopenharmony_ci}
190