diff --git a/interfaces/common/dfx_socket_request.h b/interfaces/common/dfx_socket_request.h index 3d552af26aafb36ce0cbb1e5f9334479955ab8c8..830113c642b92abc85f648d0e9c16d48a1a649f4 100644 --- a/interfaces/common/dfx_socket_request.h +++ b/interfaces/common/dfx_socket_request.h @@ -106,6 +106,10 @@ enum FaultLoggerSdkDumpResp : int32_t { SDK_DUMP_NOPROC, /** process has crashed */ SDK_PROCESS_CRASHED, + /** connect faultloggerd fail */ + SDK_CONNECT_FAIL, + /** write data to faultloggerd fail */ + SDK_WRITE_FAIL, }; /** * @brief request information diff --git a/interfaces/innerkits/backtrace/dfx_kernel_stack.cpp b/interfaces/innerkits/backtrace/dfx_kernel_stack.cpp index c1bbd38861fa5685b29dd102bf9fbf2c088361a4..1bd7e20bb1aeee5e489ed72d7b93361cb766280b 100644 --- a/interfaces/innerkits/backtrace/dfx_kernel_stack.cpp +++ b/interfaces/innerkits/backtrace/dfx_kernel_stack.cpp @@ -38,29 +38,31 @@ typedef struct HstackVal { char hstackLogBuff[BUFF_STACK_SIZE] {0}; } HstackVal; } -int DfxGetKernelStack(int32_t pid, std::string& kernelStack) +int32_t DfxGetKernelStack(int32_t pid, std::string& kernelStack) { auto kstackBuf = std::make_shared(); if (kstackBuf == nullptr) { - DFXLOGW("Failed create HstackVal, errno:%{public}d", errno); - return -1; + DFXLOGW("Failed create HstackVal, pid:%{public}d, errno:%{public}d", pid, errno); + return KERNELSTACK_ECREATE; } kstackBuf->pid = pid; kstackBuf->magic = MAGIC_NUM; int fd = open(BBOX_PATH, O_WRONLY | O_CLOEXEC); if (fd < 0) { - DFXLOGW("Failed to open bbox, errno:%{public}d", errno); - return -1; + DFXLOGW("Failed to open bbox, pid:%{public}d, errno:%{public}d", pid, errno); + return KERNELSTACK_EOPEN; } int ret = ioctl(fd, LOGGER_GET_STACK, kstackBuf.get()); + int32_t res = KERNELSTACK_ESUCCESS; if (ret != 0) { DFXLOGW("Failed to get pid(%{public}d) kernel stack, errno:%{public}d", pid, errno); + res = KERNELSTACK_EIOCTL; } else { kernelStack = std::string(kstackBuf->hstackLogBuff); } close(fd); - return ret; + return res; } bool FormatThreadKernelStack(const std::string& kernelStack, DfxThreadStack& threadStack) diff --git a/interfaces/innerkits/backtrace/include/dfx_kernel_stack.h b/interfaces/innerkits/backtrace/include/dfx_kernel_stack.h index 6d3a1a33423c09baeb6fcfd8e12b72367ae00ab7..5f480ccddeab5f1e8bc91f245a0840ad5116b03a 100644 --- a/interfaces/innerkits/backtrace/include/dfx_kernel_stack.h +++ b/interfaces/innerkits/backtrace/include/dfx_kernel_stack.h @@ -26,6 +26,12 @@ struct DfxThreadStack { long int tid = 0; std::vector frames; }; +enum KernelStackErrorCode : int32_t { + KERNELSTACK_ESUCCESS = 0, + KERNELSTACK_ECREATE, + KERNELSTACK_EOPEN, + KERNELSTACK_EIOCTL, +}; int32_t DfxGetKernelStack(int32_t pid, std::string& kernelStack); bool FormatThreadKernelStack(const std::string& kernelStack, DfxThreadStack& threadStack); bool FormatProcessKernelStack(const std::string& kernelStack, std::vector& processStack); diff --git a/interfaces/innerkits/dump_catcher/BUILD.gn b/interfaces/innerkits/dump_catcher/BUILD.gn index 730473dbe30625c99cf3a545ff4c483d00214110..4d44ed7a3e10086e9151dd5eff124dc5e2605e9c 100644 --- a/interfaces/innerkits/dump_catcher/BUILD.gn +++ b/interfaces/innerkits/dump_catcher/BUILD.gn @@ -13,7 +13,10 @@ import("//base/hiviewdfx/faultloggerd/faultloggerd.gni") -dumpcatcher_sources = [ "dfx_dump_catcher.cpp" ] +dumpcatcher_sources = [ + "dfx_dump_catcher.cpp", + "dfx_dump_catcher_errno.cpp", +] if (defined(ohos_lite)) { shared_library("libdfx_dumpcatcher") { diff --git a/interfaces/innerkits/dump_catcher/dfx_dump_catcher.cpp b/interfaces/innerkits/dump_catcher/dfx_dump_catcher.cpp index e87c6e22ac68b3f3ef5ffea9de511a7fb81cc7d0..ced18f01a33f6278b6db6af69dd81ac4edc5ceed 100644 --- a/interfaces/innerkits/dump_catcher/dfx_dump_catcher.cpp +++ b/interfaces/innerkits/dump_catcher/dfx_dump_catcher.cpp @@ -56,10 +56,13 @@ static const int DUMP_CATCHE_WORK_TIME_S = 60; static const std::string DFXDUMPCATCHER_TAG = "DfxDumpCatcher"; static std::string g_kernelStackInfo; static std::atomic_bool g_asyncThreadRunning; +static int32_t g_kernelStackRet = -1; // -1 : incomplete kernel stack dump static pid_t g_kernelStackPid = 0; static std::condition_variable g_cv; static std::mutex g_kernelStackMutex; static constexpr int WAIT_GET_KERNEL_STACK_TIMEOUT = 1000; // 1000 : time out 1000 ms +static constexpr int32_t HIVIEW_UID = 1201; +static constexpr int32_t FOUNDATION_UID = 5523; enum DfxDumpPollRes : int32_t { DUMP_POLL_INIT = -1, @@ -93,6 +96,13 @@ static bool IsLinuxKernel() return isLinux; } +static void InitKernelStackInfo() +{ + g_kernelStackInfo.clear(); + g_kernelStackRet = -1; + g_kernelStackPid = 0; +} + bool DfxDumpCatcher::DoDumpCurrTid(const size_t skipFrameNum, std::string& msg, size_t maxFrameNums) { bool ret = false; @@ -150,7 +160,7 @@ bool DfxDumpCatcher::DoDumpLocalPid(int pid, std::string& msg, size_t maxFrameNu return ret; } -bool DfxDumpCatcher::DoDumpRemoteLocked(int pid, int tid, std::string& msg, bool isJson, int timeout) +int32_t DfxDumpCatcher::DoDumpRemoteLocked(int pid, int tid, std::string& msg, bool isJson, int timeout) { return DoDumpCatchRemote(pid, tid, msg, isJson, timeout); } @@ -176,7 +186,7 @@ bool DfxDumpCatcher::DoDumpLocalLocked(int pid, int tid, std::string& msg, size_ } static void ReportDumpCatcherStats(int32_t pid, - uint64_t requestTime, bool ret, std::string& msg, void* retAddr) + uint64_t requestTime, int32_t ret, void* retAddr) { std::vector buf(sizeof(struct FaultLoggerdStatsRequest), 0); auto stat = reinterpret_cast(buf.data()); @@ -184,8 +194,8 @@ static void ReportDumpCatcherStats(int32_t pid, stat->pid = pid; stat->requestTime = requestTime; stat->dumpCatcherFinishTime = GetTimeMilliSeconds(); - stat->result = ret ? DUMP_RES_WITH_USERSTACK : DUMP_RES_WITH_KERNELSTACK; // we need more detailed failure info - if (!ret && g_kernelStackInfo.empty()) { + stat->result = (ret == DUMPCATCH_ESUCCESS) ? DUMP_RES_WITH_USERSTACK : DUMP_RES_WITH_KERNELSTACK; + if ((ret != DUMPCATCH_ESUCCESS) && g_kernelStackInfo.empty()) { stat->result = DUMP_RES_NO_KERNELSTACK; } size_t copyLen; @@ -197,9 +207,10 @@ static void ReportDumpCatcherStats(int32_t pid, return; } - if (!ret) { - copyLen = std::min(sizeof(stat->summary) - 1, msg.size()); - if (memcpy_s(stat->summary, sizeof(stat->summary) - 1, msg.c_str(), copyLen) != 0) { + if (ret != DUMPCATCH_ESUCCESS) { + std::string summary = DfxDumpCatchError::ToString(ret); + copyLen = std::min(sizeof(stat->summary) - 1, summary.size()); + if (memcpy_s(stat->summary, sizeof(stat->summary) - 1, summary.c_str(), copyLen) != 0) { DFXLOGE("%{public}s::Failed to copy dumpcatcher summary", DFXDUMPCATCHER_TAG.c_str()); return; } @@ -228,6 +239,243 @@ static void ReportDumpCatcherStats(int32_t pid, ReportDumpStats(stat); } +static bool IsBitOn(const std::string& content, const std::string& filed, int signal) +{ + if (content.find(filed) == std::string::npos) { + return false; + } + //SigBlk: 0000000000000000 + std::string num = content.substr(content.find(filed) + filed.size() + 2, 16); + uint64_t hexValue = strtol(num.c_str(), nullptr, 16); + uint64_t mask = 1ULL << (signal - 1); + + return (hexValue & mask) != 0; +} + +static bool IsSignalBlocked(int pid, int32_t& ret) +{ + std::vector tids; + std::vector nstids; + GetTidsByPid(pid, tids, nstids); + std::string threadName; + std::string content; + int targetTid = -1; + for (size_t i = 0; i < tids.size(); ++i) { + ReadThreadNameByPidAndTid(pid, tids[i], threadName); + if (threadName == "OS_DfxWatchdog") { + targetTid = tids[i]; + break; + } + } + if (targetTid != -1) { + std::string threadStatusPath = StringPrintf("/proc/%d/task/%d/status", pid, targetTid); + if (!LoadStringFromFile(threadStatusPath, content) || content.empty()) { + DFXLOGE("the pid(%{public}d)thread(%{public}d) read status fail, errno(%{public}d)", pid, targetTid, errno); + ret = DUMPCATCH_UNKNOWN; + return true; + } + + if (IsBitOn(content, "SigBlk", SIGDUMP) || IsBitOn(content, "SigIgn", SIGDUMP)) { + DFXLOGI("the pid(%{public}d)thread(%{public}d) signal has been blocked by target process", pid, targetTid); + ret = DUMPCATCH_TIMEOUT_SIGNAL_BLOCK; + return true; + } + } + return false; +} + +static bool IsFrozen(int pid, int32_t& ret) +{ + std::string content; + std::string cgroupPath = StringPrintf("/proc/%d/cgroup", pid); + if (!LoadStringFromFile(cgroupPath, content)) { + DFXLOGE("the pid (%{public}d) read cgroup fail, errno (%{public}d)", pid, errno); + ret = DUMPCATCH_UNKNOWN; + return true; + } + + if (content.find("Frozen") != std::string::npos) { + DFXLOGI("the pid (%{public}d) has been frozen", pid); + ret = DUMPCATCH_TIMEOUT_KERNEL_FROZEN; + return true; + } + return false; +} + +static void AnalyzeTimeoutReason(int pid, int32_t& ret) +{ + std::string statusPath = StringPrintf("/proc/%d/status", pid); + if (access(statusPath.c_str(), F_OK) != 0) { + DFXLOGI("the pid (%{public}d) process exit during the dump, errno (%{public}d)", pid, errno); + ret = DUMPCATCH_TIMEOUT_PROCESS_KILLED; + return; + } + + if (IsSignalBlocked(pid, ret)) { + return; + } + + if (IsFrozen(pid, ret)) { + return; + } + + DFXLOGI("the pid (%{public}d) dump slow", pid); + ret = DUMPCATCH_TIMEOUT_DUMP_SLOW; +} + +void DfxDumpCatcher::DealWithPollRet(int pollRet, int pid, int32_t& ret, std::string& msg) +{ + if (pollRet == DUMP_POLL_OK) { + ret = DUMPCATCH_ESUCCESS; + return; + } + if (g_kernelStackPid != pid) { + AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); + } + msg.append(halfProcStatus_); + msg.append(halfProcWchan_); + switch (pollRet) { + case DUMP_POLL_FD: + ret = DUMPCATCH_EFD; + break; + case DUMP_POLL_FAILED: + ret = DUMPCATCH_EPOLL; + break; + case DUMP_POLL_TIMEOUT: + AnalyzeTimeoutReason(pid, ret); + break; + case DUMP_POLL_RETURN: + if (msg.find("ptrace attach thread failed") != std::string::npos) { + ret = DUMPCATCH_DUMP_EPTRACE; + } else if (msg.find("stop unwinding") != std::string::npos) { + ret = DUMPCATCH_DUMP_EUNWIND; + } else if (msg.find("mapinfo is not exist") != std::string::npos) { + ret = DUMPCATCH_DUMP_EMAP; + } else { + ret = DUMPCATCH_UNKNOWN; + } + break; + default: + ret = DUMPCATCH_UNKNOWN; + break; + } +} + +void DfxDumpCatcher::DealWithSdkDumpRet(int sdkdumpRet, int pid, int32_t& ret, std::string& msg) +{ + int32_t uid = getuid(); + if (sdkdumpRet == static_cast(FaultLoggerSdkDumpResp::SDK_DUMP_REPEAT)) { + AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); + msg.append("Result: pid(" + std::to_string(pid) + ") process is dumping.\n"); + ret = DUMPCATCH_IS_DUMPING; + } else if (sdkdumpRet == static_cast(FaultLoggerSdkDumpResp::SDK_DUMP_REJECT)) { + msg.append("Result: pid(" + std::to_string(pid) + ") process check permission error.\n"); + ret = DUMPCATCH_EPERMISSION; + } else if (sdkdumpRet == static_cast(FaultLoggerSdkDumpResp::SDK_DUMP_NOPROC)) { + msg.append("Result: pid(" + std::to_string(pid) + ") process has exited.\n"); + RequestDelPipeFd(pid); + ret = DUMPCATCH_NO_PROCESS; + } else if (sdkdumpRet == static_cast(FaultLoggerSdkDumpResp::SDK_PROCESS_CRASHED)) { + msg.append("Result: pid(" + std::to_string(pid) + ") process has been crashed.\n"); + ret = DUMPCATCH_HAS_CRASHED; + } else if (sdkdumpRet == static_cast(FaultLoggerSdkDumpResp::SDK_CONNECT_FAIL)) { + if (uid == HIVIEW_UID || uid == FOUNDATION_UID) { + AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); + } + msg.append("Result: pid(" + std::to_string(pid) + ") process fail to conntect faultloggerd.\n"); + ret = DUMPCATCH_ECONNECT; + } else if (sdkdumpRet == static_cast(FaultLoggerSdkDumpResp::SDK_WRITE_FAIL)) { + if (uid == HIVIEW_UID || uid == FOUNDATION_UID) { + AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); + } + msg.append("Result: pid(" + std::to_string(pid) + ") process fail to write to faultloggerd.\n"); + ret = DUMPCATCH_EWRITE; + } + DFXLOGW("%{public}s :: %{public}s :: %{public}s", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str()); +} + +static std::pair DealWithDumpCatchRet(int pid, int32_t& ret, std::string& msg) +{ + int result = ret == 0 ? 0 : -1; + std::string reason; + if (result == 0) { + reason = "Reason:" + DfxDumpCatchError::ToString(ret) + "\n"; + } else { + reason = "Reason:\nnormal stack:" + DfxDumpCatchError::ToString(ret) + "\n"; + } + if (result != 0) { + if (pid == g_kernelStackPid && !g_asyncThreadRunning) { + msg.append(g_kernelStackInfo); + result = 1; + InitKernelStackInfo(); + } else if (g_kernelStackRet != -1) { + ret = g_kernelStackRet; + reason += "kernel stack:" + DfxDumpCatchError::ToString(ret) + "\n"; + g_kernelStackRet = -1; + } else if (g_kernelStackRet == -1) { + reason += "kernel stack:" + DfxDumpCatchError::ToString(DUMPCATCH_KERNELSTACK_NONEED) + "\n"; + } + } + std::string toFind = "Result:"; + size_t startPos = msg.find(toFind); + if (startPos != std::string::npos) { + size_t endPos = msg.find("\n", startPos); + if (endPos != std::string::npos) { + msg.erase(startPos, endPos - startPos + 1); + } + } + return std::make_pair(result, reason); +} + +std::pair DfxDumpCatcher::DumpCatchWithTimeout(int pid, std::string& msg, int timeout, + int tid, bool isJson) +{ + DfxEnableTraceDlsym(true); + ElapsedTime counter; + uint64_t requestTime = GetTimeMilliSeconds(); + int32_t dumpcatchErrno = DUMPCATCH_UNKNOWN; + bool reportStat = false; + do { + if (pid <= 0 || tid <0 || timeout <= WAIT_GET_KERNEL_STACK_TIMEOUT) { + DFXLOGE("DumpCatchWithTimeout:: param error."); + dumpcatchErrno = DUMPCATCH_EPARAM; + break; + } + if (!IsLinuxKernel()) { + std::string statusPath = StringPrintf("/proc/%d/status", pid); + if (access(statusPath.c_str(), F_OK) != 0 && errno != EACCES) { + DFXLOGE("DumpCatchWithTimeout:: the pid(%{public}d) process has exited, errno(%{public}d)", pid, errno); + msg.append("Result: pid(" + std::to_string(pid) + ") process has exited.\n"); + dumpcatchErrno = DUMPCATCH_NO_PROCESS; + break; + } + } + std::unique_lock lck(mutex_); + int currentPid = getpid(); + if (pid == currentPid) { + DFXLOGE("DumpCatchWithTimeout:: param error (don't support dumpcatch self)"); + dumpcatchErrno = DUMPCATCH_EPARAM; + break; + } else { + DFXLOGI("Receive DumpCatch request for cPid:(%{public}d), pid(%{public}d)", currentPid, pid); + dumpcatchErrno = DoDumpRemoteLocked(pid, tid, msg, isJson, timeout); + reportStat = true; + } + } while (false); + + auto result = DealWithDumpCatchRet(pid, dumpcatchErrno, msg); + if (reportStat) { + void* retAddr = __builtin_return_address(0); + ReportDumpCatcherStats(pid, requestTime, dumpcatchErrno, retAddr); + } + + DFXLOGI("dump_catch : pid = %{public}d, elapsed time = %{public}" PRId64 " ms, " \ + "msgLength = %{public}zu, ret = %{public}d\n%{public}s", + pid, counter.Elapsed(), msg.size(), result.first, result.second.c_str()); + DfxEnableTraceDlsym(false); + return result; +} + int DfxDumpCatcher::DumpCatchProcess(int pid, std::string& msg, size_t maxFrameNums, bool isJson) { if (DumpCatch(pid, 0, msg, maxFrameNums, isJson)) { @@ -235,10 +483,10 @@ int DfxDumpCatcher::DumpCatchProcess(int pid, std::string& msg, size_t maxFrameN } if (pid == g_kernelStackPid && !g_asyncThreadRunning) { msg.append(g_kernelStackInfo); - g_kernelStackInfo.clear(); - g_kernelStackPid = 0; + InitKernelStackInfo(); return 1; } + g_kernelStackRet = -1; return -1; } @@ -261,7 +509,6 @@ bool DfxDumpCatcher::DumpCatch(int pid, int tid, std::string& msg, size_t maxFra ElapsedTime counter; std::unique_lock lck(mutex_); int currentPid = getpid(); - bool reportStat = false; uint64_t requestTime = GetTimeMilliSeconds(); DFXLOGI("Receive DumpCatch request for cPid:(%{public}d), pid(%{public}d), " \ "tid:(%{public}d).", currentPid, pid, tid); @@ -272,14 +519,14 @@ bool DfxDumpCatcher::DumpCatch(int pid, int tid, std::string& msg, size_t maxFra DFXLOGI("%{public}s :: dump_catch :: maxFrameNums does not support setting " \ "when pid is not equal to caller pid", DFXDUMPCATCHER_TAG.c_str()); } - reportStat = true; int timeout = (tid == 0 ? 3 : 10) * 1000; // when tid not zero, timeout is 10s - ret = DoDumpRemoteLocked(pid, tid, msg, isJson, timeout); - } - - if (reportStat) { + int32_t res = DoDumpRemoteLocked(pid, tid, msg, isJson, timeout); void* retAddr = __builtin_return_address(0); - ReportDumpCatcherStats(pid, requestTime, ret, msg, retAddr); + if (res != DUMPCATCH_ESUCCESS && g_kernelStackRet != DUMPCATCH_ESUCCESS && g_kernelStackRet != -1) { + res = g_kernelStackRet; + } + ReportDumpCatcherStats(pid, requestTime, res, retAddr); + ret = res == DUMPCATCH_ESUCCESS; } DFXLOGI("dump_catch : pid = %{public}d, elapsed time = %{public}" PRId64 " ms, ret = %{public}d, " \ @@ -299,54 +546,27 @@ bool DfxDumpCatcher::DumpCatchFd(int pid, int tid, std::string& msg, int fd, siz return ret; } -bool DfxDumpCatcher::DoDumpCatchRemote(int pid, int tid, std::string& msg, bool isJson, int timeout) +int32_t DfxDumpCatcher::DoDumpCatchRemote(int pid, int tid, std::string& msg, bool isJson, int timeout) { DFX_TRACE_SCOPED_DLSYM("DoDumpCatchRemote"); - bool ret = false; - if (pid <= 0 || tid < 0) { + int32_t ret = DUMPCATCH_UNKNOWN; + if (pid <= 0 || tid < 0 || timeout <= WAIT_GET_KERNEL_STACK_TIMEOUT) { msg.append("Result: pid(" + std::to_string(pid) + ") param error.\n"); DFXLOGW("%{public}s :: %{public}s :: %{public}s", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str()); - return ret; + return DUMPCATCH_EPARAM; } pid_ = pid; int pipeReadFd[] = { -1, -1 }; uint64_t sdkDumpStartTime = GetAbsTimeMilliSeconds(); int sdkdumpRet = RequestSdkDump(pid, tid, pipeReadFd, isJson, timeout); if (sdkdumpRet != static_cast(FaultLoggerSdkDumpResp::SDK_DUMP_PASS)) { - if (sdkdumpRet == static_cast(FaultLoggerSdkDumpResp::SDK_DUMP_REPEAT)) { - AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); - msg.append("Result: pid(" + std::to_string(pid) + ") process is dumping.\n"); - } else if (sdkdumpRet == static_cast(FaultLoggerSdkDumpResp::SDK_DUMP_REJECT)) { - msg.append("Result: pid(" + std::to_string(pid) + ") process check permission error.\n"); - } else if (sdkdumpRet == static_cast(FaultLoggerSdkDumpResp::SDK_DUMP_NOPROC)) { - msg.append("Result: pid(" + std::to_string(pid) + ") process has exited.\n"); - RequestDelPipeFd(pid); - } else if (sdkdumpRet == static_cast(FaultLoggerSdkDumpResp::SDK_PROCESS_CRASHED)) { - msg.append("Result: pid(" + std::to_string(pid) + ") process has been crashed.\n"); - } - DFXLOGW("%{public}s :: %{public}s :: %{public}s", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str()); + DealWithSdkDumpRet(sdkdumpRet, pid, ret, msg); return ret; } // timeout sub the cost time of sdkdump timeout -= static_cast(GetAbsTimeMilliSeconds() - sdkDumpStartTime); int pollRet = DoDumpRemotePid(pid, msg, pipeReadFd, isJson, timeout); - switch (pollRet) { - case DUMP_POLL_OK: - ret = true; - break; - case DUMP_POLL_TIMEOUT: { - msg.append(halfProcStatus_); - msg.append(halfProcWchan_); - break; - } - default: - if (g_kernelStackPid != pid) { // maybe not get kernel stack, try again - AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); - } - msg.append(halfProcStatus_); - msg.append(halfProcWchan_); - break; - } + DealWithPollRet(pollRet, pid, ret, msg); DFXLOGI("%{public}s :: %{public}s :: pid(%{public}d) ret: %{public}d", DFXDUMPCATCHER_TAG.c_str(), __func__, pid, ret); return ret; @@ -376,10 +596,25 @@ int DfxDumpCatcher::DoDumpRemotePid(int pid, std::string& msg, int (&pipeReadFd) return ret; } +static int32_t KernelRet2DumpcatchRet(int32_t ret) +{ + switch (ret) { + case KERNELSTACK_ECREATE: + return DUMPCATCH_KERNELSTACK_ECREATE; + case KERNELSTACK_EOPEN: + return DUMPCATCH_KERNELSTACK_EOPEN; + case KERNELSTACK_EIOCTL: + return DUMPCATCH_KERNELSTACK_EIOCTL; + default: + return DUMPCATCH_UNKNOWN; + } +} + void DfxDumpCatcher::CollectKernelStack(pid_t pid, int waitMilliSeconds) { ElapsedTime timer; std::string kernelStackInfo; + int32_t kernelRet = 0; auto finishCollect = [waitMilliSeconds]() { if (waitMilliSeconds > 0) { std::unique_lock lock(g_kernelStackMutex); @@ -402,8 +637,11 @@ void DfxDumpCatcher::CollectKernelStack(pid_t pid, int waitMilliSeconds) return false; } std::string tidKernelStackInfo; - if (DfxGetKernelStack(tid, tidKernelStackInfo) == 0) { + int32_t ret = DfxGetKernelStack(tid, tidKernelStackInfo); + if (ret == 0) { kernelStackInfo.append(tidKernelStackInfo); + } else if (kernelRet == 0) { + kernelRet = ret; } return true; }; @@ -411,11 +649,13 @@ void DfxDumpCatcher::CollectKernelStack(pid_t pid, int waitMilliSeconds) MAYBE_UNUSED bool ret = GetTidsByPidWithFunc(pid, tids, func); if (kernelStackInfo.empty()) { DFXLOGE("Process(%{public}d) collect kernel stack fail!", pid); + g_kernelStackRet = KernelRet2DumpcatchRet(kernelRet); finishCollect(); return; } g_kernelStackPid = pid; g_kernelStackInfo = kernelStackInfo; + g_kernelStackRet = 0; finishCollect(); DFXLOGI("finish collect all tid info for pid(%{public}d) time(%{public}" PRId64 ")ms", pid, timer.Elapsed()); @@ -430,8 +670,7 @@ void DfxDumpCatcher::AsyncGetAllTidKernelStack(pid_t pid, int waitMilliSeconds) return; } g_asyncThreadRunning = true; - g_kernelStackPid = 0; - g_kernelStackInfo.clear(); + InitKernelStackInfo(); auto func = [pid, waitMilliSeconds] { CollectKernelStack(pid, waitMilliSeconds); }; @@ -611,7 +850,8 @@ bool DfxDumpCatcher::DumpCatchMultiPid(const std::vector pidV, std::string& for (int i = 0; i < pidSize; i++) { int pid = pidV[i]; std::string pidStr; - if (DoDumpRemoteLocked(pid, 0, pidStr)) { + bool ret = DoDumpRemoteLocked(pid, 0, pidStr) == DUMPCATCH_ESUCCESS; + if (ret) { msg.append(pidStr + "\n"); } else { msg.append("Failed to dump process:" + std::to_string(pid)); diff --git a/interfaces/innerkits/dump_catcher/dfx_dump_catcher_errno.cpp b/interfaces/innerkits/dump_catcher/dfx_dump_catcher_errno.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4c5cb65bd30e0b1795d27164cec1a60ac0ad726d --- /dev/null +++ b/interfaces/innerkits/dump_catcher/dfx_dump_catcher_errno.cpp @@ -0,0 +1,55 @@ +/* + * 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_dump_catcher_errno.h" + +namespace OHOS { +namespace HiviewDFX { + +const std::map ERROR_CODE_MAP = { + { DUMPCATCH_ESUCCESS, std::string("success") }, + { DUMPCATCH_EPARAM, std::string("param error") }, + { DUMPCATCH_NO_PROCESS, std::string("process has exited") }, + { DUMPCATCH_IS_DUMPING, std::string("process is dumping") }, + { DUMPCATCH_EPERMISSION, std::string("check permission error") }, + { DUMPCATCH_HAS_CRASHED, std::string("process has been crashed") }, + { DUMPCATCH_ECONNECT, std::string("failed to connect to faultloggerd") }, + { DUMPCATCH_EWRITE, std::string("failed to write data to faultloggerd") }, + { DUMPCATCH_EFD, std::string("buf or res fd error") }, + { DUMPCATCH_EPOLL, std::string("poll error") }, + { DUMPCATCH_DUMP_EPTRACE, std::string("failed to ptrace thread") }, + { DUMPCATCH_DUMP_EUNWIND, std::string("failed to unwind") }, + { DUMPCATCH_DUMP_EMAP, std::string("failed to find map") }, + { DUMPCATCH_TIMEOUT_SIGNAL_BLOCK, std::string("signal has been block by target process") }, + { DUMPCATCH_TIMEOUT_KERNEL_FROZEN, std::string("target process has been frozen in kernel") }, + { DUMPCATCH_TIMEOUT_PROCESS_KILLED, std::string("target process has been killed during dumping") }, + { DUMPCATCH_TIMEOUT_DUMP_SLOW, std::string("failed to fully dump due to timeout") }, + { DUMPCATCH_KERNELSTACK_ECREATE, std::string("kernelstack fail due to create hstackval fail") }, + { DUMPCATCH_KERNELSTACK_EOPEN, std::string("kernelstack fail due to open bbox fail") }, + { DUMPCATCH_KERNELSTACK_EIOCTL, std::string("kernelstack fail due to ioctl fail") }, + { DUMPCATCH_KERNELSTACK_NONEED, std::string("no need to dump kernelstack") }, + { DUMPCATCH_UNKNOWN, std::string("unknown reason") } +}; + +std::string DfxDumpCatchError::ToString(const int32_t res) +{ + auto it = ERROR_CODE_MAP.find(res); + if (it != ERROR_CODE_MAP.end()) { + return it->second; + } + return std::string("invalid error code"); +} +} // namespace HiviewDFX +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/dump_catcher/include/dfx_dump_catcher.h b/interfaces/innerkits/dump_catcher/include/dfx_dump_catcher.h index 498d2a2529ea24b7ba78c80111f16b8a5e208217..2fbf641268c492513ad31f6e6207fec03d94bf54 100644 --- a/interfaces/innerkits/dump_catcher/include/dfx_dump_catcher.h +++ b/interfaces/innerkits/dump_catcher/include/dfx_dump_catcher.h @@ -25,6 +25,8 @@ #include #include +#include "dfx_dump_catcher_errno.h" + namespace OHOS { namespace HiviewDFX { static const size_t DEFAULT_MAX_FRAME_NUM = 256; @@ -79,14 +81,28 @@ public: */ int DumpCatchProcess(int pid, std::string& msg, size_t maxFrameNums = DEFAULT_MAX_FRAME_NUM, bool isJson = false); + /** + * @brief Dump stack of process with timeout + * + * @param pid process id + * @param msg message of stack + * @param timeout Set the dump timeout time to be at least 1000ms + * @param isJson whether message of stack is json formatted + * @return ret and reason. + * ret: -1: dump catch failed 0:msg is normal stack 1:msg is kernel stack(not json format) + * reason: if ret is 1, it contains normal stack fail reason. + * if ret is -1, it contains normal stack fail reason and kernel stack fail reason. + */ + std::pair DumpCatchWithTimeout(int pid, std::string& msg, int timeout = 3000, + int tid = 0, bool isJson = false); private: bool DoDumpCurrTid(const size_t skipFrameNum, std::string& msg, size_t maxFrameNums); bool DoDumpLocalTid(const int tid, std::string& msg, size_t maxFrameNums); bool DoDumpLocalPid(int pid, std::string& msg, size_t maxFrameNums); bool DoDumpLocalLocked(int pid, int tid, std::string& msg, size_t maxFrameNums); - bool DoDumpRemoteLocked(int pid, int tid, std::string& msg, bool isJson = false, + int32_t DoDumpRemoteLocked(int pid, int tid, std::string& msg, bool isJson = false, int timeout = DUMPCATCHER_REMOTE_TIMEOUT); - bool DoDumpCatchRemote(int pid, int tid, std::string& msg, bool isJson = false, + int32_t DoDumpCatchRemote(int pid, int tid, std::string& msg, bool isJson = false, int timeout = DUMPCATCHER_REMOTE_TIMEOUT); int DoDumpRemotePid(int pid, std::string& msg, int (&pipeReadFd)[2], bool isJson = false, int32_t timeout = DUMPCATCHER_REMOTE_TIMEOUT); @@ -95,6 +111,8 @@ private: bool DoReadRes(int fd, bool &ret, std::string& msg); static void CollectKernelStack(pid_t pid, int waitMilliSeconds = 0); void AsyncGetAllTidKernelStack(pid_t pid, int waitMilliSeconds = 0); + void DealWithPollRet(int pollRet, int pid, int32_t& ret, std::string& msg); + void DealWithSdkDumpRet(int sdkdumpRet, int pid, int32_t& ret, std::string& msg); private: static const int DUMPCATCHER_REMOTE_P90_TIMEOUT = 1000; diff --git a/interfaces/innerkits/dump_catcher/include/dfx_dump_catcher_errno.h b/interfaces/innerkits/dump_catcher/include/dfx_dump_catcher_errno.h new file mode 100644 index 0000000000000000000000000000000000000000..3260a8459b11936a701af3a47eab03b7ad8e97d4 --- /dev/null +++ b/interfaces/innerkits/dump_catcher/include/dfx_dump_catcher_errno.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef DFX_DUMPCATCH_ERRNO_H +#define DFX_DUMPCATCH_ERRNO_H + +#include +#include +#include + +namespace OHOS { +namespace HiviewDFX { + +/** + * @brief Dumpcatch error code + * It describes the error status of dumpcatch. + */ +enum DumpCatchErrorCode : int32_t { + DUMPCATCH_ESUCCESS = 0, /* success */ + + DUMPCATCH_EPARAM = 101, /* param error */ + DUMPCATCH_NO_PROCESS, /* process has exited */ + DUMPCATCH_IS_DUMPING, /* process is dumping */ + DUMPCATCH_EPERMISSION, /* check permission error */ + DUMPCATCH_HAS_CRASHED, /* process has been crashed */ + DUMPCATCH_ECONNECT, /* failed to connect to faultloggerd */ + DUMPCATCH_EWRITE, /* failed to write data to faultloggerd */ + DUMPCATCH_EFD, /* buf or res fd error */ + DUMPCATCH_EPOLL, /* poll error */ + + DUMPCATCH_DUMP_EPTRACE = 201, /* failed to ptrace thread */ + DUMPCATCH_DUMP_EUNWIND, /* failed to unwind */ + DUMPCATCH_DUMP_EMAP, /* failed to find map */ + + DUMPCATCH_TIMEOUT_SIGNAL_BLOCK = 301, /* signal has been block by target process */ + DUMPCATCH_TIMEOUT_KERNEL_FROZEN, /* target process has been frozen in kernel */ + DUMPCATCH_TIMEOUT_PROCESS_KILLED, /* target process has been killed during dumping */ + DUMPCATCH_TIMEOUT_DUMP_SLOW, /* failed to fully dump due to timeout */ + + DUMPCATCH_UNKNOWN = 400, /* unknown reason */ + + DUMPCATCH_KERNELSTACK_ECREATE = 401, /* kernelstack fail due to create hstackval fail */ + DUMPCATCH_KERNELSTACK_EOPEN, /* kernelstack fail due to open bbox fail */ + DUMPCATCH_KERNELSTACK_EIOCTL, /* kernelstack fail due to ioctl fail */ + DUMPCATCH_KERNELSTACK_NONEED, /* no need to dump kernelstack */ +}; + +class DfxDumpCatchError { +public: + static std::string ToString(const int32_t res); +}; +} // namespace HiviewDFX +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/innerkits/dump_catcher/libdfx_dumpcatcher.map b/interfaces/innerkits/dump_catcher/libdfx_dumpcatcher.map index 968cf1c0d74a39baa289391a2c25150339ba958f..9c49c9ad0838978fa20811b0c8052fe493576421 100644 --- a/interfaces/innerkits/dump_catcher/libdfx_dumpcatcher.map +++ b/interfaces/innerkits/dump_catcher/libdfx_dumpcatcher.map @@ -3,6 +3,7 @@ extern "C++" { OHOS::HiviewDFX::DfxDumpCatcher::Dump*; OHOS::HiviewDFX::DfxDumpCatcher::Do*; + OHOS::HiviewDFX::DfxDumpCatchError::ToString*; }; local: *; diff --git a/interfaces/innerkits/faultloggerd_client/faultloggerd_client.cpp b/interfaces/innerkits/faultloggerd_client/faultloggerd_client.cpp index e79468abed0ad79c3e18da9167f8db4283641d65..2499e49cb825bbad381501f4d8040bd30b197c5a 100644 --- a/interfaces/innerkits/faultloggerd_client/faultloggerd_client.cpp +++ b/interfaces/innerkits/faultloggerd_client/faultloggerd_client.cpp @@ -179,11 +179,13 @@ static int SendSdkDumpRequestToServer(const FaultLoggerdRequest &request, int (& if (!StartConnect(sockfd, name.c_str(), SOCKET_TIMEOUT)) { DFXLOGE("[%{public}d]: StartConnect(%{public}d) failed", __LINE__, sockfd); + resRsp = static_cast(SDK_CONNECT_FAIL); break; } if (OHOS_TEMP_FAILURE_RETRY(write(sockfd, &request, sizeof(struct FaultLoggerdRequest))) != static_cast(sizeof(request))) { DFXLOGE("write failed."); + resRsp = static_cast(SDK_WRITE_FAIL); break; } diff --git a/test/systemtest/dumpcatcher_system_test.cpp b/test/systemtest/dumpcatcher_system_test.cpp index 7f87996e82429ff59390b02ad0f5d510ba4d17c6..7f3b2c29127fd14f27bd02d8b5b18281d9782604 100644 --- a/test/systemtest/dumpcatcher_system_test.cpp +++ b/test/systemtest/dumpcatcher_system_test.cpp @@ -675,7 +675,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest020, TestSize.Level2) string procCMD = "dumpcatcher -p " + to_string(g_loopAppPid); string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; EXPECT_EQ(count, 1) << "DumpCatcherSystemTest020 Failed"; @@ -695,7 +695,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest021, TestSize.Level2) string procCMD = "dumpcatcher -p " + to_string(g_loopAppPid) + " -t " + to_string(g_loopAppPid); string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; EXPECT_EQ(count, 1) << "DumpCatcherSystemTest021 Failed"; @@ -719,7 +719,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest022, TestSize.Level2) string procCMD = "dumpcatcher -p " + to_string(g_loopAppPid) + " -t " + to_string(tid); string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; EXPECT_EQ(count, 1) << "DumpCatcherSystemTest022 Failed"; @@ -740,7 +740,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest023, TestSize.Level2) string procCMD = "dumpcatcher -p " + to_string(g_loopSysPid) + " -t " + to_string(g_loopSysPid); string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; EXPECT_EQ(count, 1) << "DumpCatcherSystemTest023 Failed"; @@ -762,7 +762,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest024, TestSize.Level2) string procCMD = "dumpcatcher -p " + to_string(g_loopRootPid) + " -t " + to_string(g_loopRootPid); string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; EXPECT_EQ(count, 1) << "DumpCatcherSystemTest024 Failed"; @@ -783,7 +783,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest025, TestSize.Level2) string procCMD = "dumpcatcher -p 9999 -t "+ to_string(g_loopAppPid); string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; EXPECT_EQ(count, 1) << "DumpCatcherSystemTest025 Failed"; @@ -803,7 +803,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest026, TestSize.Level2) string procCMD = "dumpcatcher -p " + to_string(g_loopAppPid) + " -t 9999"; string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; EXPECT_EQ(count, 1) << "DumpCatcherSystemTest026 Failed"; @@ -824,7 +824,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest027, TestSize.Level2) string procCMD = "dumpcatcher -p " + to_string(g_loopAppPid) + " -t " + to_string(g_loopSysPid); string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; EXPECT_EQ(count, 1) << "DumpCatcherSystemTest027 Failed"; @@ -846,7 +846,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest028, TestSize.Level2) string procCMD = "dumpcatcher -p " + to_string(g_loopSysPid) + " -t " + to_string(g_loopAppPid); string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; EXPECT_EQ(count, 1) << "DumpCatcherSystemTest028 Failed"; @@ -887,10 +887,10 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest030, TestSize.Level2) string procCMD = "dumpcatcher -p " + to_string(g_loopAppPid) + " -t "; string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Usage:", "dump the stacktrace"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; - EXPECT_EQ(count, 2) << "DumpCatcherSystemTest030 Failed"; + EXPECT_EQ(count, 1) << "DumpCatcherSystemTest030 Failed"; StopCrasherLoop(APP_CRASHER_C); GTEST_LOG_(INFO) << "DumpCatcherSystemTest030: end."; } @@ -1096,7 +1096,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest039, TestSize.Level2) string procCMD = "dumpcatcher -p " + to_string(g_loopAppPid) + " -t " + to_string(g_loopRootPid); string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; EXPECT_EQ(count, 1) << "DumpCatcherSystemTest039 Failed"; @@ -1118,7 +1118,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest040, TestSize.Level2) string procCMD = "dumpcatcher -p " + to_string(g_loopRootPid) + " -t " + to_string(g_loopAppPid); string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); EXPECT_EQ(count, 1) << "DumpCatcherSystemTest040 Failed"; StopCrasherLoop(ROOT); @@ -1138,7 +1138,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest041, TestSize.Level2) string procCMD = "dumpcatcher -p " + GetPidMax() + " -t " + GetTidMax(); string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; EXPECT_EQ(count, 1) << "DumpCatcherSystemTest041 Failed"; @@ -1158,7 +1158,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest042, TestSize.Level2) string procCMD = "dumpcatcher -p 65535 -t 65535"; string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; EXPECT_EQ(count, 1) << "DumpCatcherSystemTest042 Failed"; @@ -1178,7 +1178,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest043, TestSize.Level2) string procCMD = "dumpcatcher -p 65536 -t 65536"; string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); GTEST_LOG_(INFO) << count; EXPECT_EQ(count, 1) << "DumpCatcherSystemTest043 Failed"; @@ -1193,12 +1193,12 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest043, TestSize.Level2) */ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest044, TestSize.Level2) { - GTEST_LOG_(INFO) << "DumpCatcherSystemTest117: start."; + GTEST_LOG_(INFO) << "DumpCatcherSystemTest044: start."; StartCrasherLoop(APP_CRASHER_C); string procCMD = "dumpcatcher -p 65534 -t 65534"; string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); EXPECT_EQ(count, 1) << "DumpCatcherSystemTest044 Failed"; StopCrasherLoop(APP_CRASHER_C); @@ -1236,7 +1236,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest046, TestSize.Level2) string procCMD = "dumpcatcher -p " + to_string(g_loopAppPid); string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = {"Failed"}; + string log[] = {"failed"}; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); EXPECT_EQ(count, 1) << "DumpCatcherSystemTest046 Failed"; StopCrasherLoop(APP_CRASHER_C); @@ -1379,7 +1379,7 @@ HWTEST_F(DumpCatcherSystemTest, DumpCatcherSystemTest101, TestSize.Level2) string procCMD = "dumpcatcher -p " + to_string(pid); string procDumpLog = ExecuteCommands(procCMD); GTEST_LOG_(INFO) << "procDumpLog: " << procDumpLog; - string log[] = { "Failed", "status:", "Name:", "nonvoluntary_ctxt_switches:", "wchan:", "Tid:" }; + string log[] = { "status:", "Name:", "nonvoluntary_ctxt_switches:", "wchan:", "Tid:" }; int count = GetKeywordsNum(procDumpLog, log, sizeof(log) / sizeof(log[0])); kill(pid, SIGKILL); EXPECT_EQ(count, sizeof(log) / sizeof(log[0])) << "DumpCatcherSystemTest101 Failed"; diff --git a/test/unittest/dump_catcher/dumpcatcher_command_test.cpp b/test/unittest/dump_catcher/dumpcatcher_command_test.cpp index 55a114201068346fcdfdd1a920df45cfd73fd6cf..989d1c008b178bfd2e2b8232705acdd88c1e26a5 100644 --- a/test/unittest/dump_catcher/dumpcatcher_command_test.cpp +++ b/test/unittest/dump_catcher/dumpcatcher_command_test.cpp @@ -268,5 +268,28 @@ HWTEST_F(DumpCatcherCommandTest, DumpCatcherCommandTest015, TestSize.Level2) ASSERT_EQ(ret, false); GTEST_LOG_(INFO) << "DumpCatcherCommandTest015: end."; } + +/** + * @tc.name: DumpCatcherCommandTest016 + * @tc.desc: test dumpcatcher command: -p [accountmgr] -t [main thread] -T [1500] + * @tc.type: FUNC + */ +HWTEST_F(DumpCatcherCommandTest, DumpCatcherCommandTest016, TestSize.Level2) +{ + GTEST_LOG_(INFO) << "DumpCatcherCommandTest016: start."; + int testPid = GetProcessPid("accountmgr"); + int timeout = 1500; + string testCommand = "dumpcatcher -p " + to_string(testPid) + " -t " + to_string(testPid); + testCommand += " -T " + to_string(timeout); + string dumpRes = ExecuteCommands(testCommand); + GTEST_LOG_(INFO) << dumpRes; + string log[] = {"Pid:", "Name:", "#00", "#01", "#02"}; + log[0] = log[0] + to_string(testPid); + log[1] = log[1] + "accountmgr"; + int len = sizeof(log) / sizeof(log[0]); + int count = GetKeywordsNum(dumpRes, log, len); + EXPECT_EQ(count, len) << "DumpCatcherCommandTest016 Failed"; + GTEST_LOG_(INFO) << "DumpCatcherCommandTest016: end."; +} } // namespace HiviewDFX } // namepsace OHOS \ No newline at end of file diff --git a/test/unittest/dump_catcher/dumpcatcher_interfaces_test.cpp b/test/unittest/dump_catcher/dumpcatcher_interfaces_test.cpp index a00b3c320fb5d9329c46a324d88305523e1c4b15..1db08832cdb167969158eb98c8b1ae3edff28244 100644 --- a/test/unittest/dump_catcher/dumpcatcher_interfaces_test.cpp +++ b/test/unittest/dump_catcher/dumpcatcher_interfaces_test.cpp @@ -770,6 +770,8 @@ HWTEST_F(DumpCatcherInterfacesTest, DumpCatcherInterfacesTest031, TestSize.Level std::string msg = ""; ASSERT_EQ(dumplog.DumpCatchProcess(g_testPid, msg), 1); //kernel stack GTEST_LOG_(INFO) << msg; + std::string startProcessCmd = "kill -s SIGCONT $(pidof com.example.myapplication)"; + ExecuteCommands(startProcessCmd); std::string formattedStack = ""; ASSERT_TRUE(DfxJsonFormatter::FormatKernelStack(msg, formattedStack, false)); ASSERT_GT(formattedStack.size(), 0); @@ -846,5 +848,215 @@ HWTEST_F(DumpCatcherInterfacesTest, DumpCatcherInterfacesTest033, TestSize.Level } GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest033: end."; } + +/** + * @tc.name: DumpCatcherInterfacesTest034 + * @tc.desc: test DumpCatchWithTimeout API: PID(test hap) + * @tc.type: FUNC + * @tc.require: IB1XY4 + */ +HWTEST_F(DumpCatcherInterfacesTest, DumpCatcherInterfacesTest034, TestSize.Level2) +{ + GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest034: start."; + bool isSuccess = g_testPid != 0; + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + GTEST_LOG_(ERROR) << "Failed to launch target hap."; + return; + } + isSuccess = CheckProcessComm(g_testPid, TRUNCATE_TEST_BUNDLE_NAME); + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + GTEST_LOG_(ERROR) << "Error process comm"; + return; + } + DfxDumpCatcher dumplog; + std::string msg = ""; + auto result = dumplog.DumpCatchWithTimeout(g_testPid, msg); + GTEST_LOG_(INFO) << result.second; + EXPECT_TRUE(result.first == 0) << "DumpCatcherInterfacesTest034 Failed"; + string log[] = { "Tid:", "Name:", "#00", "/system/bin/appspawn", "Name:OS_DfxWatchdog" }; + log[0] += std::to_string(g_testPid); + log[1] += TRUNCATE_TEST_BUNDLE_NAME; + int len = sizeof(log) / sizeof(log[0]); + int count = GetKeywordsNum(msg, log, len); + EXPECT_EQ(count, len) << "DumpCatcherInterfacesTest034 Failed"; + GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest034: end."; +} + +/** + * @tc.name: DumpCatcherInterfacesTest035 + * @tc.desc: test DumpCatchWithTimeout API: PID(test hap), TIMEOUT(1000) + * @tc.type: FUNC + * @tc.require: IB1XY4 + */ +HWTEST_F(DumpCatcherInterfacesTest, DumpCatcherInterfacesTest035, TestSize.Level2) +{ + GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest035: start."; + bool isSuccess = g_testPid != 0; + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + GTEST_LOG_(ERROR) << "Failed to launch target hap."; + return; + } + isSuccess = CheckProcessComm(g_testPid, TRUNCATE_TEST_BUNDLE_NAME); + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + GTEST_LOG_(ERROR) << "Error process comm"; + return; + } + DfxDumpCatcher dumplog; + std::string msg = ""; + int timeout = 1000; + auto result = dumplog.DumpCatchWithTimeout(g_testPid, msg, timeout); + GTEST_LOG_(INFO) << result.second; + EXPECT_TRUE(result.first == -1) << "DumpCatcherInterfacesTest035 Failed"; + GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest035: end."; +} + +/** + * @tc.name: DumpCatcherInterfacesTest036 + * @tc.desc: test DumpCatchWithTimeout API: PID(nonexistent) + * @tc.type: FUNC + * @tc.require: IB1XY4 + */ +HWTEST_F(DumpCatcherInterfacesTest, DumpCatcherInterfacesTest036, TestSize.Level2) +{ + GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest036: start."; + bool isSuccess = g_testPid != 0; + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + GTEST_LOG_(ERROR) << "Failed to launch target hap."; + return; + } + isSuccess = CheckProcessComm(g_testPid, TRUNCATE_TEST_BUNDLE_NAME); + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + GTEST_LOG_(ERROR) << "Error process comm"; + return; + } + DfxDumpCatcher dumplog; + std::string msg = ""; + int nonexistPid = 123456; + auto result = dumplog.DumpCatchWithTimeout(nonexistPid, msg); + GTEST_LOG_(INFO) << result.second; + EXPECT_TRUE(result.first == -1) << "DumpCatcherInterfacesTest036 Failed"; + GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest036: end."; +} + +/** + * @tc.name: DumpCatcherInterfacesTest037 + * @tc.desc: test DumpCatchWithTimeout API: PID(test hap), TIMEOUT(2000) + * @tc.type: FUNC + * @tc.require: IB1XY4 + */ +HWTEST_F(DumpCatcherInterfacesTest, DumpCatcherInterfacesTest037, TestSize.Level2) +{ + GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest037: start."; + bool isSuccess = g_testPid != 0; + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + GTEST_LOG_(ERROR) << "Failed to launch target hap."; + return; + } + isSuccess = CheckProcessComm(g_testPid, TRUNCATE_TEST_BUNDLE_NAME); + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + GTEST_LOG_(ERROR) << "Error process comm"; + return; + } + DfxDumpCatcher dumplog; + std::string msg = ""; + int timeout = 2000; + auto result = dumplog.DumpCatchWithTimeout(g_testPid, msg, timeout); + GTEST_LOG_(INFO) << result.second; + EXPECT_TRUE(result.first == 0) << "DumpCatcherInterfacesTest037 Failed"; + string log[] = { "Tid:", "Name:", "#00", "/system/bin/appspawn", "Name:OS_DfxWatchdog" }; + log[0] += std::to_string(g_testPid); + log[1] += TRUNCATE_TEST_BUNDLE_NAME; + int len = sizeof(log) / sizeof(log[0]); + int count = GetKeywordsNum(msg, log, len); + EXPECT_EQ(count, len) << "DumpCatcherInterfacesTest037 Failed"; + GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest037: end."; +} + +/** + * @tc.name: DumpCatcherInterfacesTest038 + * @tc.desc: test DumpCatchWithTimeout API: PID(test hap) and SIGSTOP the process + * @tc.type: FUNC + * @tc.require: IB1XY4 + */ +HWTEST_F(DumpCatcherInterfacesTest, DumpCatcherInterfacesTest038, TestSize.Level2) +{ + GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest038: start."; + std::string res = ExecuteCommands("uname"); + bool isSuccess = res.find("Linux") == std::string::npos; + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + return; + } + isSuccess = g_testPid != 0; + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + GTEST_LOG_(ERROR) << "Failed to launch target hap."; + return; + } + isSuccess = CheckProcessComm(g_testPid, TRUNCATE_TEST_BUNDLE_NAME); + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + GTEST_LOG_(ERROR) << "Error process comm"; + return; + } + std::string stopProcessCmd = "kill -s SIGSTOP $(pidof com.example.myapplication)"; + ExecuteCommands(stopProcessCmd); + DfxDumpCatcher dumplog; + std::string msg = ""; + auto result = dumplog.DumpCatchWithTimeout(g_testPid, msg); + std::string startProcessCmd = "kill -s SIGCONT $(pidof com.example.myapplication)"; + ExecuteCommands(startProcessCmd); + GTEST_LOG_(INFO) << result.second; + ASSERT_TRUE(result.first == 1); + + GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest038: end."; +} + +/** + * @tc.name: DumpCatcherInterfacesTest039 + * @tc.desc: test DumpCatchWithTimeout API: PID(test hap) and stop the faultloggerd + * @tc.type: FUNC + * @tc.require: IB1XY4 + */ +HWTEST_F(DumpCatcherInterfacesTest, DumpCatcherInterfacesTest039, TestSize.Level2) +{ + GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest039: start."; + std::string res = ExecuteCommands("uname"); + bool isSuccess = res.find("Linux") == std::string::npos; + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + return; + } + isSuccess = g_testPid != 0; + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + GTEST_LOG_(ERROR) << "Failed to launch target hap."; + return; + } + isSuccess = CheckProcessComm(g_testPid, TRUNCATE_TEST_BUNDLE_NAME); + if (!isSuccess) { + ASSERT_FALSE(isSuccess); + GTEST_LOG_(ERROR) << "Error process comm"; + return; + } + DfxDumpCatcher dumplog; + std::string msg = ""; + std::string stopFaultloggerdCmd = "service_control stop faultloggerd"; + ExecuteCommands(stopFaultloggerdCmd); + auto result = dumplog.DumpCatchWithTimeout(g_testPid, msg); + std::string startFaultloggerdCmd = "service_control start faultloggerd"; + ExecuteCommands(startFaultloggerdCmd); + GTEST_LOG_(INFO) << result.second; + EXPECT_TRUE(result.first == -1); + GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest039: end."; +} } // namespace HiviewDFX } // namepsace OHOS \ No newline at end of file diff --git a/test/unittest/faultloggerd_client/faultloggerd_client_test.cpp b/test/unittest/faultloggerd_client/faultloggerd_client_test.cpp index 61ed9ae8f360f69e3831b4429c0eb0c54cc4cc7c..c4a34ce220bdcffef8b5cf4af5c05b8e39111ba9 100644 --- a/test/unittest/faultloggerd_client/faultloggerd_client_test.cpp +++ b/test/unittest/faultloggerd_client/faultloggerd_client_test.cpp @@ -301,7 +301,7 @@ HWTEST_F(FaultloggerdClientTest, FaultloggerdClientTest006, TestSize.Level2) setuid(appUid); int pipeReadFd[] = { -1, -1 }; int resp = RequestSdkDump(1, 1, pipeReadFd); - if (resp == FaultLoggerCheckPermissionResp::CHECK_PERMISSION_REJECT) { + if (resp != FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS) { ret = 0; } exit(ret); diff --git a/tools/dump_catcher/dump_catcher.cpp b/tools/dump_catcher/dump_catcher.cpp index 4bc77755597eb7147e6b4b52617c580d367054b3..891e3ab91cfe362567fca9a2e64dfba005084eee 100644 --- a/tools/dump_catcher/dump_catcher.cpp +++ b/tools/dump_catcher/dump_catcher.cpp @@ -27,19 +27,20 @@ DumpCatcher &DumpCatcher::GetInstance() return ins; } -void DumpCatcher::Dump(int32_t pid, int32_t tid) const +void DumpCatcher::Dump(int32_t pid, int32_t tid, int timeout) const { DfxDumpCatcher dfxDump; std::string msg = ""; - bool dumpRet = dfxDump.DumpCatch(pid, tid, msg); - if (!dumpRet) { - printf("Dump Failed.\n"); - } - if (!msg.empty()) { - printf("%s\n", msg.c_str()); - } else { - printf("Dump msg empty.\n"); + auto dumpResult = dfxDump.DumpCatchWithTimeout(pid, msg, timeout, tid); + if (dumpResult.first == -1) { + printf("Result:dump failed.\n"); + } else if (dumpResult.first == 0) { + printf("Result:dump normal stack success.\n"); + } else if (dumpResult.first == 1) { + printf("Result:dump kernel stack success.\n"); } + printf("%s", dumpResult.second.c_str()); + printf("%s\n", msg.c_str()); } } // namespace HiviewDFX } // namespace OHOS diff --git a/tools/dump_catcher/dump_catcher.h b/tools/dump_catcher/dump_catcher.h index aaea85ccce6a6e91325d1fd292c6c4af72fc4916..4dc90185630a53c9461656fa20a827e9cad95071 100644 --- a/tools/dump_catcher/dump_catcher.h +++ b/tools/dump_catcher/dump_catcher.h @@ -26,7 +26,7 @@ public: static DumpCatcher &GetInstance(); ~DumpCatcher() = default; - void Dump(int32_t pid, int32_t tid) const; + void Dump(int32_t pid, int32_t tid, int timeout) const; private: DumpCatcher() = default; diff --git a/tools/dump_catcher/main.cpp b/tools/dump_catcher/main.cpp index dd176e3b29b9e0f4c2197300cd40c84ae5e9a361..115a01eb8cdda4615238f32b5332e45d273112cd 100644 --- a/tools/dump_catcher/main.cpp +++ b/tools/dump_catcher/main.cpp @@ -29,20 +29,22 @@ static const std::string DUMP_STACK_TAG_USAGE = "Usage:"; static const std::string DUMP_STACK_TAG_FAILED = "Failed:"; +static constexpr int WAIT_GET_KERNEL_STACK_TIMEOUT = 1000; // 1000 : time out 1000 ms static void PrintCommandHelp() { printf("%s\n", DUMP_STACK_TAG_USAGE.c_str()); printf("-p pid -t tid dump the stacktrace of the thread with given tid.\n"); printf("-p pid dump the stacktrace of all the threads with given pid.\n"); + printf("-T timeout(ms) dump in the timeout.\n"); } static void PrintCommandFailed() { - printf("%s\npid and tid must > 0.\n", DUMP_STACK_TAG_FAILED.c_str()); + printf("%s\npid and tid must > 0 and timeout must > 1000.\n", DUMP_STACK_TAG_FAILED.c_str()); } -static int ParseParamters(int argc, char *argv[], int32_t &pid, int32_t &tid) +static int ParseParamters(int argc, char *argv[], int32_t &pid, int32_t &tid, int &timeout) { int ret = 0; if (argc <= 1) { @@ -51,13 +53,13 @@ static int ParseParamters(int argc, char *argv[], int32_t &pid, int32_t &tid) DFXLOGD("[%{public}d]: argc: %{public}d, argv1: %{public}s", __LINE__, argc, argv[1]); int optRet; - const char *optString = "cmkp:t:"; + const char *optString = "p:t:T:"; while ((optRet = getopt(argc, argv, optString)) != -1) { + if (optarg == nullptr) { + continue; + } switch (optRet) { case 'p': - if (optarg == nullptr) { - break; - } if (atoi(optarg) > 0) { ret = 1; pid = atoi(optarg); @@ -67,9 +69,6 @@ static int ParseParamters(int argc, char *argv[], int32_t &pid, int32_t &tid) } break; case 't': - if (optarg == nullptr) { - break; - } if (atoi(optarg) > 0) { tid = atoi(optarg); } else { @@ -77,6 +76,14 @@ static int ParseParamters(int argc, char *argv[], int32_t &pid, int32_t &tid) PrintCommandFailed(); } break; + case 'T': + if (atoi(optarg) > WAIT_GET_KERNEL_STACK_TIMEOUT) { + timeout = atoi(optarg); + } else { + ret = -1; + PrintCommandFailed(); + } + break; default: ret = 0; break; @@ -97,15 +104,16 @@ int main(int argc, char *argv[]) int32_t pid = 0; int32_t tid = 0; + int timeout = 3000; alarm(DUMPCATCHER_TIMEOUT); setsid(); - if (ParseParamters(argc, argv, pid, tid) <= 0) { + if (ParseParamters(argc, argv, pid, tid, timeout) <= 0) { return 0; } - DFXLOGD("pid: %{public}d, tid: %{public}d", pid, tid); - OHOS::HiviewDFX::DumpCatcher::GetInstance().Dump(pid, tid); + DFXLOGD("pid: %{public}d, tid: %{public}d, timeout: %{public}d", pid, tid, timeout); + OHOS::HiviewDFX::DumpCatcher::GetInstance().Dump(pid, tid, timeout); return 0; }