/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "dfx_sigdump_handler.h" #include <cinttypes> #include <csignal> #include <ctime> #include <mutex> #include <sigchain.h> #include <sys/syscall.h> #include <thread> #include <unistd.h> #include "backtrace_local.h" #include "dfx_define.h" #include "dfx_dump_res.h" #include "dfx_log.h" #include "faultloggerd_client.h" namespace OHOS { namespace HiviewDFX { namespace { #ifdef LOG_DOMAIN #undef LOG_DOMAIN #define LOG_DOMAIN 0xD002D11 #endif #ifdef LOG_TAG #undef LOG_TAG #define LOG_TAG "DfxSigDumpHandler" #endif } static const struct timespec SIG_WAIT_TIMEOUT = { .tv_sec = 1, .tv_nsec = 0, }; class DfxSigDumpHandler { public: static DfxSigDumpHandler& GetInstance(void); bool Init(void); void Deinit(void); bool IsThreadRunning(void) const; int GetRunThreadId(void) const; void SetRunThreadId(int tid); private: DfxSigDumpHandler() = default; DfxSigDumpHandler(DfxSigDumpHandler&) = delete; DfxSigDumpHandler& operator=(const DfxSigDumpHandler&)=delete; static void RunThread(void); static void SignalDumpRetranHandler(int signo, siginfo_t* si, void* context); bool isThreadRunning_{false}; int runThreadId_{0}; }; DfxSigDumpHandler& DfxSigDumpHandler::GetInstance() { static DfxSigDumpHandler sigDumperHandler; return sigDumperHandler; } bool DfxSigDumpHandler::IsThreadRunning() const { return isThreadRunning_; } int DfxSigDumpHandler::GetRunThreadId() const { return runThreadId_; } void DfxSigDumpHandler::SetRunThreadId(int tid) { runThreadId_ = tid; } void DfxSigDumpHandler::SignalDumpRetranHandler(int signo, siginfo_t* si, void* context) { int tid = DfxSigDumpHandler::GetInstance().GetRunThreadId(); if (tid == 0) { return; } if (syscall(SYS_tkill, tid, SIGDUMP) != 0) { return; } } void DfxSigDumpHandler::RunThread() { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGDUMP); if (pthread_sigmask(SIG_BLOCK, &set, nullptr) != 0) { DFXLOG_ERROR("pthread sigmask failed, err(%d)", errno); } DfxSigDumpHandler::GetInstance().SetRunThreadId(gettid()); while (DfxSigDumpHandler::GetInstance().IsThreadRunning()) { siginfo_t si; if (OHOS_TEMP_FAILURE_RETRY(sigtimedwait(&set, &si, &SIG_WAIT_TIMEOUT)) == -1) { continue; } int32_t resFd = -1; int res = DUMP_ESUCCESS; int32_t pid = getpid(); FaultLoggerPipeType jsonType = FaultLoggerPipeType::PIPE_FD_JSON_WRITE_RES; int32_t fd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_JSON_WRITE_BUF); if (fd < 0) { fd = RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_WRITE_BUF); jsonType = FaultLoggerPipeType::PIPE_FD_WRITE_RES; } if (fd < 0) { DFXLOG_ERROR("Pid %d GetPipeFd Failed", pid); continue; } resFd = RequestPipeFd(pid, jsonType); if (resFd < 0) { DFXLOG_ERROR("Pid %d GetPipeResFd Failed", pid); close(fd); continue; } std::string dumpInfo = OHOS::HiviewDFX::GetProcessStacktrace(); const ssize_t nwrite = static_cast<ssize_t>(dumpInfo.length()); if (!dumpInfo.empty() && OHOS_TEMP_FAILURE_RETRY(write(fd, dumpInfo.data(), dumpInfo.length())) != nwrite) { DFXLOG_ERROR("Pid %d Write Buf Pipe Failed(%d), nwrite(%zd)", pid, errno, nwrite); res = DUMP_EBADFRAME; } else if (dumpInfo.empty()) { res = DUMP_ENOINFO; } ssize_t nres = OHOS_TEMP_FAILURE_RETRY(write(resFd, &res, sizeof(res))); if (nres != sizeof(res)) { DFXLOG_ERROR("Pid %d Write Res Pipe Failed(%d), nres(%zd)", pid, errno, nres); } close(fd); close(resFd); } } bool DfxSigDumpHandler::Init() { if (IsThreadRunning()) { DFXLOG_INFO("%s", "SigDumpHandler Thread has been inited"); return true; } remove_all_special_handler(SIGDUMP); struct sigaction action; (void)memset_s(&action, sizeof(action), 0, sizeof(action)); sigemptyset(&action.sa_mask); sigaddset(&action.sa_mask, SIGDUMP); action.sa_flags = SA_RESTART | SA_SIGINFO; action.sa_sigaction = DfxSigDumpHandler::SignalDumpRetranHandler; DFXLOG_INFO("%s", "Init Install signal handler"); sigaction(SIGDUMP, &action, nullptr); isThreadRunning_ = true; std::thread catchThread = std::thread(&DfxSigDumpHandler::RunThread); catchThread.detach(); return true; } void DfxSigDumpHandler::Deinit() { isThreadRunning_ = false; } } // namespace HiviewDFX } // namespace OHOS bool InitSigDumpHandler() { return OHOS::HiviewDFX::DfxSigDumpHandler::GetInstance().Init(); } void DeinitSigDumpHandler() { OHOS::HiviewDFX::DfxSigDumpHandler::GetInstance().Deinit(); }