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