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