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 #include "smart_fd.h"
34
35 namespace OHOS {
36 namespace HiviewDFX {
37 namespace {
38 #ifdef LOG_DOMAIN
39 #undef LOG_DOMAIN
40 #define LOG_DOMAIN 0xD002D11
41 #endif
42
43 #ifdef LOG_TAG
44 #undef LOG_TAG
45 #define LOG_TAG "DfxSigDumpHandler"
46 #endif
47 }
48
49 static const struct timespec SIG_WAIT_TIMEOUT = {
50 .tv_sec = 1,
51 .tv_nsec = 0,
52 };
53
54 class DfxSigDumpHandler {
55 public:
56 static DfxSigDumpHandler& GetInstance(void);
57 bool Init(void);
58 void Deinit(void);
59 bool IsThreadRunning(void) const;
60 int GetRunThreadId(void) const;
61 void SetRunThreadId(int tid);
62 private:
63 DfxSigDumpHandler() = default;
64 DfxSigDumpHandler(DfxSigDumpHandler&) = delete;
65 DfxSigDumpHandler& operator=(const DfxSigDumpHandler&)=delete;
66 static void RunThread(void);
67 static void SignalDumpRetranHandler(int signo, siginfo_t* si, void* context);
68 bool isThreadRunning_{false};
69 int runThreadId_{0};
70 };
71
GetInstance()72 DfxSigDumpHandler& DfxSigDumpHandler::GetInstance()
73 {
74 static DfxSigDumpHandler sigDumperHandler;
75 return sigDumperHandler;
76 }
77
IsThreadRunning() const78 bool DfxSigDumpHandler::IsThreadRunning() const
79 {
80 return isThreadRunning_;
81 }
82
GetRunThreadId() const83 int DfxSigDumpHandler::GetRunThreadId() const
84 {
85 return runThreadId_;
86 }
87
SetRunThreadId(int tid)88 void DfxSigDumpHandler::SetRunThreadId(int tid)
89 {
90 runThreadId_ = tid;
91 }
92
SignalDumpRetranHandler(int signo,siginfo_t * si,void * context)93 void DfxSigDumpHandler::SignalDumpRetranHandler(int signo, siginfo_t* si, void* context)
94 {
95 int tid = DfxSigDumpHandler::GetInstance().GetRunThreadId();
96 if (tid == 0) {
97 return;
98 }
99 if (syscall(SYS_tkill, tid, SIGDUMP) != 0) {
100 return;
101 }
102 }
103
RunThread()104 void DfxSigDumpHandler::RunThread()
105 {
106 sigset_t set;
107 sigemptyset(&set);
108 sigaddset(&set, SIGDUMP);
109 if (pthread_sigmask(SIG_BLOCK, &set, nullptr) != 0) {
110 DFXLOGE("pthread sigmask failed, err(%{public}d)", errno);
111 }
112 DfxSigDumpHandler::GetInstance().SetRunThreadId(gettid());
113 while (DfxSigDumpHandler::GetInstance().IsThreadRunning()) {
114 siginfo_t si;
115 if (OHOS_TEMP_FAILURE_RETRY(sigtimedwait(&set, &si, &SIG_WAIT_TIMEOUT)) == -1) {
116 continue;
117 }
118
119 int res = DUMP_ESUCCESS;
120 int32_t pid = getpid();
121 int pipeWriteFd[] = { -1, -1 };
122 if (RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_WRITE, pipeWriteFd) == -1) {
123 DFXLOGE("Pid %{public}d RequestPipeFd Failed", pid);
124 continue;
125 }
126 SmartFd bufFd(pipeWriteFd[0]);
127 SmartFd resFd(pipeWriteFd[1]);
128
129 std::string dumpInfo = OHOS::HiviewDFX::GetProcessStacktrace();
130 const ssize_t nwrite = static_cast<ssize_t>(dumpInfo.length());
131 if (!dumpInfo.empty() &&
132 OHOS_TEMP_FAILURE_RETRY(write(bufFd.GetFd(), dumpInfo.data(), dumpInfo.length())) != nwrite) {
133 DFXLOGE("Pid %{public}d Write Buf Pipe Failed(%{public}d), nwrite(%{public}zd)", pid, errno, nwrite);
134 res = DUMP_EBADFRAME;
135 } else if (dumpInfo.empty()) {
136 res = DUMP_ENOINFO;
137 }
138 ssize_t nres = OHOS_TEMP_FAILURE_RETRY(write(resFd.GetFd(), &res, sizeof(res)));
139 if (nres != sizeof(res)) {
140 DFXLOGE("Pid %{public}d Write Res Pipe Failed(%{public}d), nres(%{public}zd)", pid, errno, nres);
141 }
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