• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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