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 33namespace OHOS { 34namespace HiviewDFX { 35namespace { 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 47static const struct timespec SIG_WAIT_TIMEOUT = { 48 .tv_sec = 1, 49 .tv_nsec = 0, 50}; 51 52class DfxSigDumpHandler { 53public: 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); 60private: 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 70DfxSigDumpHandler& DfxSigDumpHandler::GetInstance() 71{ 72 static DfxSigDumpHandler sigDumperHandler; 73 return sigDumperHandler; 74} 75 76bool DfxSigDumpHandler::IsThreadRunning() const 77{ 78 return isThreadRunning_; 79} 80 81int DfxSigDumpHandler::GetRunThreadId() const 82{ 83 return runThreadId_; 84} 85 86void DfxSigDumpHandler::SetRunThreadId(int tid) 87{ 88 runThreadId_ = tid; 89} 90 91void 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 102void DfxSigDumpHandler::RunThread() 103{ 104 sigset_t set; 105 sigemptyset(&set); 106 sigaddset(&set, SIGDUMP); 107 if (pthread_sigmask(SIG_BLOCK, &set, nullptr) != 0) { 108 DFXLOGE("pthread sigmask failed, err(%{public}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 DFXLOGE("Pid %{public}d GetPipeFd Failed", pid); 127 continue; 128 } 129 resFd = RequestPipeFd(pid, jsonType); 130 if (resFd < 0) { 131 DFXLOGE("Pid %{public}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 DFXLOGE("Pid %{public}d Write Buf Pipe Failed(%{public}d), nwrite(%{public}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 DFXLOGE("Pid %{public}d Write Res Pipe Failed(%{public}d), nres(%{public}zd)", pid, errno, nres); 147 } 148 close(fd); 149 close(resFd); 150 } 151} 152 153bool DfxSigDumpHandler::Init() 154{ 155 if (IsThreadRunning()) { 156 DFXLOGI("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 DFXLOGI("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 174void DfxSigDumpHandler::Deinit() 175{ 176 isThreadRunning_ = false; 177} 178} // namespace HiviewDFX 179} // namespace OHOS 180 181bool InitSigDumpHandler() 182{ 183 return OHOS::HiviewDFX::DfxSigDumpHandler::GetInstance().Init(); 184} 185 186void DeinitSigDumpHandler() 187{ 188 OHOS::HiviewDFX::DfxSigDumpHandler::GetInstance().Deinit(); 189} 190