• 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 #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