1 /*
2  * Copyright (c) 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_sigdump_handler.h"
17 
18 #include <cinttypes>
19 #include <csignal>
20 #include <ctime>
21 #include <mutex>
22 #include <sigchain.h>
23 #include <sys/syscall.h>
24 #include <thread>
25 #include <unistd.h>
26 
27 #include "backtrace_local.h"
28 #include "dfx_define.h"
29 #include "dfx_dump_res.h"
30 #include "dfx_log.h"
31 #include "faultloggerd_client.h"
32 
33 namespace OHOS {
34 namespace HiviewDFX {
35 namespace {
36 #ifdef LOG_DOMAIN
37 #undef LOG_DOMAIN
38 #define LOG_DOMAIN 0xD002D11
39 #endif
40 
41 #ifdef LOG_TAG
42 #undef LOG_TAG
43 #define LOG_TAG "DfxSigDumpHandler"
44 #endif
45 }
46 
47 static const struct timespec SIG_WAIT_TIMEOUT = {
48     .tv_sec = 1,
49     .tv_nsec = 0,
50 };
51 
52 class DfxSigDumpHandler {
53 public:
54     static DfxSigDumpHandler& GetInstance(void);
55     bool Init(void);
56     void Deinit(void);
57     bool IsThreadRunning(void) const;
58     int GetRunThreadId(void) const;
59     void SetRunThreadId(int tid);
60 private:
61     DfxSigDumpHandler() = default;
62     DfxSigDumpHandler(DfxSigDumpHandler&) = delete;
63     DfxSigDumpHandler& operator=(const DfxSigDumpHandler&)=delete;
64     static void RunThread(void);
65     static void SignalDumpRetranHandler(int signo, siginfo_t* si, void* context);
66     bool isThreadRunning_{false};
67     int runThreadId_{0};
68 };
69 
GetInstance()70 DfxSigDumpHandler& DfxSigDumpHandler::GetInstance()
71 {
72     static DfxSigDumpHandler sigDumperHandler;
73     return sigDumperHandler;
74 }
75 
IsThreadRunning() const76 bool DfxSigDumpHandler::IsThreadRunning() const
77 {
78     return isThreadRunning_;
79 }
80 
GetRunThreadId() const81 int DfxSigDumpHandler::GetRunThreadId() const
82 {
83     return runThreadId_;
84 }
85 
SetRunThreadId(int tid)86 void DfxSigDumpHandler::SetRunThreadId(int tid)
87 {
88     runThreadId_ = tid;
89 }
90 
SignalDumpRetranHandler(int signo,siginfo_t * si,void * context)91 void DfxSigDumpHandler::SignalDumpRetranHandler(int signo, siginfo_t* si, void* context)
92 {
93     int tid = DfxSigDumpHandler::GetInstance().GetRunThreadId();
94     if (tid == 0) {
95         return;
96     }
97     if (syscall(SYS_tkill, tid, SIGDUMP) != 0) {
98         return;
99     }
100 }
101 
RunThread()102 void DfxSigDumpHandler::RunThread()
103 {
104     sigset_t set;
105     sigemptyset(&set);
106     sigaddset(&set, SIGDUMP);
107     if (pthread_sigmask(SIG_BLOCK, &set, nullptr) != 0) {
108         DFXLOG_ERROR("pthread sigmask failed, err(%d)", errno);
109     }
110     DfxSigDumpHandler::GetInstance().SetRunThreadId(gettid());
111     while (DfxSigDumpHandler::GetInstance().IsThreadRunning()) {
112         siginfo_t si;
113         if (OHOS_TEMP_FAILURE_RETRY(sigtimedwait(&set, &si, &SIG_WAIT_TIMEOUT)) == -1) {
114             continue;
115         }
116         int32_t resFd = -1;
117         int res = DUMP_ESUCCESS;
118         int32_t pid = getpid();
119         FaultLoggerPipeType jsonType = FaultLoggerPipeType::PIPE_FD_JSON_WRITE_RES;
120         int32_t fd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_JSON_WRITE_BUF);
121         if (fd < 0) {
122             fd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_WRITE_BUF);
123             jsonType = FaultLoggerPipeType::PIPE_FD_WRITE_RES;
124         }
125         if (fd < 0) {
126             DFXLOG_ERROR("Pid %d GetPipeFd Failed", pid);
127             continue;
128         }
129         resFd = RequestPipeFd(pid, jsonType);
130         if (resFd < 0) {
131             DFXLOG_ERROR("Pid %d GetPipeResFd Failed", pid);
132             close(fd);
133             continue;
134         }
135         std::string dumpInfo = OHOS::HiviewDFX::GetProcessStacktrace();
136         const ssize_t nwrite = static_cast<ssize_t>(dumpInfo.length());
137         if (!dumpInfo.empty() &&
138                 OHOS_TEMP_FAILURE_RETRY(write(fd, dumpInfo.data(), dumpInfo.length())) != nwrite) {
139             DFXLOG_ERROR("Pid %d Write Buf Pipe Failed(%d), nwrite(%zd)", pid, errno, nwrite);
140             res = DUMP_EBADFRAME;
141         } else if (dumpInfo.empty()) {
142             res = DUMP_ENOINFO;
143         }
144         ssize_t nres = OHOS_TEMP_FAILURE_RETRY(write(resFd, &res, sizeof(res)));
145         if (nres != sizeof(res)) {
146             DFXLOG_ERROR("Pid %d Write Res Pipe Failed(%d), nres(%zd)", pid, errno, nres);
147         }
148         close(fd);
149         close(resFd);
150     }
151 }
152 
Init()153 bool DfxSigDumpHandler::Init()
154 {
155     if (IsThreadRunning()) {
156         DFXLOG_INFO("%s", "SigDumpHandler Thread has been inited");
157         return true;
158     }
159     remove_all_special_handler(SIGDUMP);
160     struct sigaction action;
161     (void)memset_s(&action, sizeof(action), 0, sizeof(action));
162     sigemptyset(&action.sa_mask);
163     sigaddset(&action.sa_mask, SIGDUMP);
164     action.sa_flags = SA_RESTART | SA_SIGINFO;
165     action.sa_sigaction = DfxSigDumpHandler::SignalDumpRetranHandler;
166     DFXLOG_INFO("%s", "Init Install signal handler");
167     sigaction(SIGDUMP, &action, nullptr);
168     isThreadRunning_ = true;
169     std::thread catchThread = std::thread(&DfxSigDumpHandler::RunThread);
170     catchThread.detach();
171     return true;
172 }
173 
Deinit()174 void DfxSigDumpHandler::Deinit()
175 {
176     isThreadRunning_ = false;
177 }
178 } // namespace HiviewDFX
179 } // namespace OHOS
180 
InitSigDumpHandler()181 bool InitSigDumpHandler()
182 {
183     return OHOS::HiviewDFX::DfxSigDumpHandler::GetInstance().Init();
184 }
185 
DeinitSigDumpHandler()186 void DeinitSigDumpHandler()
187 {
188     OHOS::HiviewDFX::DfxSigDumpHandler::GetInstance().Deinit();
189 }
190