diff --git a/common/dfxutil/proc_util.cpp b/common/dfxutil/proc_util.cpp index 996e20b3cff892dffad422953f26c27dc3478c95..69b67a013233c8f5be580c6a083cd682021a3c2e 100644 --- a/common/dfxutil/proc_util.cpp +++ b/common/dfxutil/proc_util.cpp @@ -15,6 +15,7 @@ #include "proc_util.h" +#include #include #include #include @@ -245,5 +246,59 @@ bool ParseProcInfo(pid_t pid, ProcessInfo& info) std::string path = "/proc/" + std::to_string(pid) + "/stat"; return ParseStat(path, info); } + +std::string GetFirstNumberSeq(const std::string& cont) +{ + auto start = std::find_if(cont.begin(), cont.end(), isdigit); + if (start == cont.end()) { + return ""; + } + auto end = std::find_if_not(start, cont.end(), isdigit); + return std::string(start, end); +} + +bool GetUidAndSigBlk(pid_t pid, long& uid, uint64_t& sigBlk) +{ + std::string procPath = "/proc/" + std::to_string(pid) + "/task/" + std::to_string(pid) + "/status"; + FILE *fp = fopen(procPath.c_str(), "r"); + if (fp == nullptr) { + return false; + } + char line[256] = {0}; // 256 : read status line is enough + std::string uidStr; + std::string sigBlkStr; + while (fgets(line, sizeof(line) - 1, fp) != nullptr) { + std::string strLine(line); + if (uidStr.empty() && strLine.find("Uid:") != std::string::npos) { + uidStr = GetFirstNumberSeq(strLine); + } else if (strLine.find("SigBlk:") != std::string::npos) { + sigBlkStr = GetFirstNumberSeq(strLine); + break; + } + } + (void)fclose(fp); + + if (uidStr.empty() || sigBlkStr.empty()) { + return false; + } + + char* end; + uid = strtol(uidStr .c_str(), &end, 10); // 10 : Uid is in decimal format + if (errno == ERANGE || *end != '\0') { + return false; + } + + sigBlk = strtoull(sigBlkStr.c_str(), &end, 16); // 16 : SigBlk is in hex format + if (errno == ERANGE || *end != '\0') { + return false; + } + return true; +} + +bool IsSigDumpMask(uint64_t sigBlk) +{ + constexpr uint64_t sigDumpMask = UINT64_C(1) << 34; // 34 : SIGDUMP signal is the 35th bit (0-indexed) + return (sigBlk & sigDumpMask) != 0; +} } // namespace HiviewDFX } // namespace OHOS diff --git a/common/dfxutil/proc_util.h b/common/dfxutil/proc_util.h index 1952134ad7ed0b38ddd260ff5c4f55a050bcbc73..b56a82148f4f380eaae233df75357d1cb4a27f9e 100644 --- a/common/dfxutil/proc_util.h +++ b/common/dfxutil/proc_util.h @@ -85,6 +85,9 @@ struct ProcessInfo { std::string ThreadStateToString(ThreadState state); bool ParseStat(const std::string& statPath, ProcessInfo& info); bool ParseProcInfo(pid_t pid, ProcessInfo& info); +std::string GetFirstNumberSeq(const std::string& cont); +bool GetUidAndSigBlk(pid_t pid, long& uid, uint64_t& sigBlk); +bool IsSigDumpMask(uint64_t sigBlk); } // namespace Dfx } // namespace OHOS #endif // PROC_UTIL_H diff --git a/interfaces/innerkits/procinfo/include/procinfo.h b/interfaces/innerkits/procinfo/include/procinfo.h index 1773bf7d848ba010be8abb8ae7fa87fa2999d31c..8d905b6a8b0804f4b9827a1734653a94b4724c10 100644 --- a/interfaces/innerkits/procinfo/include/procinfo.h +++ b/interfaces/innerkits/procinfo/include/procinfo.h @@ -142,6 +142,14 @@ std::string GetStacktraceHeader(); * @return rss value(KB) */ uint64_t GetProcRssMemInfo(pid_t pid); + +/** + * @brief Get process thread id by thread name + * + * @param pid process id + * @return thread id if found, otherwise return -1 +*/ +pid_t GetTidByThreadName(pid_t pid, const std::string& threadName); } // nameapace HiviewDFX } // nameapace OHOS #endif diff --git a/interfaces/innerkits/procinfo/procinfo.cpp b/interfaces/innerkits/procinfo/procinfo.cpp index 9d222a38acfcbdeb602bbcdcfbcb8322a2a6a1c4..36a54121796b16c957b6fcc596290625cf117023 100644 --- a/interfaces/innerkits/procinfo/procinfo.cpp +++ b/interfaces/innerkits/procinfo/procinfo.cpp @@ -354,5 +354,25 @@ uint64_t GetProcRssMemInfo(pid_t pid) rss = (rss * pageSizeKB * sizekiB) / sizekB; return rss; } + +pid_t GetTidByThreadName(pid_t pid, const std::string& threadName) +{ + if (pid <= 0) { + return -1; + } + std::vector tids; + std::vector nstids; + if (!GetTidsByPid(pid, tids, nstids)) { + return -1; + } + for (const auto tid : tids) { + std::string tmpThreadName; + ReadThreadNameByPidAndTid(pid, tid, tmpThreadName); + if (tmpThreadName == threadName) { + return tid; + } + } + return -1; +} } // namespace HiviewDFX } // namespace OHOS diff --git a/services/BUILD.gn b/services/BUILD.gn index 2b747fa61d2fe8632add76e0eec435841d037683..132ffbacbd23762c4688babc4c05fdf11023f8cd 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -45,6 +45,7 @@ if (defined(ohos_lite)) { "$hilog_lite_include_path", "$faultloggerd_path/interfaces/innerkits/faultloggerd_client/include", "$faultloggerd_path/interfaces/innerkits/faultloggerd_client", + "$faultloggerd_interfaces_path/innerkits/procinfo/include", ] sources = faultloggerd_sources @@ -61,6 +62,7 @@ if (defined(ohos_lite)) { "$faultloggerd_path/common/dfxlog:dfx_hilog", "$faultloggerd_path/common/dfxutil:dfx_util", "$faultloggerd_path/interfaces/innerkits/faultloggerd_client:libfaultloggerd", + "$faultloggerd_interfaces_path/innerkits/procinfo:libdfx_procinfo", ] external_deps = [ "hilog_lite:hilog_shared" ] @@ -95,6 +97,7 @@ if (defined(ohos_lite)) { "$faultloggerd_path/common/dfxutil", "$faultloggerd_path/interfaces/innerkits/faultloggerd_client", "$faultloggerd_path/interfaces/innerkits/signal_handler", + "$faultloggerd_interfaces_path/innerkits/procinfo/include", ] } @@ -161,6 +164,7 @@ if (defined(ohos_lite)) { "$faultloggerd_path/common/dfxutil:dfx_util", "$faultloggerd_path/common/trace:dfx_trace", "$faultloggerd_path/interfaces/innerkits/faultloggerd_client:libfaultloggerd", + "$faultloggerd_interfaces_path/innerkits/procinfo:libdfx_procinfo", ] if (!is_asan) { @@ -198,6 +202,7 @@ if (defined(ohos_lite)) { "$faultloggerd_path/common/dfxutil:dfx_util", "$faultloggerd_path/common/trace:dfx_trace", "$faultloggerd_path/interfaces/innerkits/faultloggerd_client:libfaultloggerd", + "$faultloggerd_interfaces_path/innerkits/procinfo:libdfx_procinfo", ] external_deps = [ diff --git a/services/fault_logger_service.cpp b/services/fault_logger_service.cpp index cc6e565f468ca10a5ebf07278d311cef2b84a37a..d3e7410fab1056906e8e22c9aba09b23c55be2d4 100644 --- a/services/fault_logger_service.cpp +++ b/services/fault_logger_service.cpp @@ -27,6 +27,8 @@ #include "dfx_util.h" #include "fault_logger_daemon.h" #include "faultloggerd_socket.h" +#include "procinfo.h" +#include "proc_util.h" #ifndef is_ohos_lite #include "fault_logger_pipe.h" @@ -283,6 +285,47 @@ int32_t SdkDumpService::Filter(const std::string& socketName, const SdkDumpReque return ResponseCode::REQUEST_SUCCESS; } +int32_t SdkDumpService::SendSigDumpToHapWatchdog(pid_t pid, siginfo_t& si) +{ + long uid = 0; + uint64_t sigBlk = 0; + if (!GetUidAndSigBlk(pid, uid, sigBlk)) { + return ResponseCode::DEFAULT_ERROR_CODE; + }; + constexpr long minUid = 10000; // 10000 : minimum uid for hap + if (uid < minUid || IsSigDumpMask(sigBlk)) { + return ResponseCode::DEFAULT_ERROR_CODE; + } + + pid_t tid = GetTidByThreadName(pid, "OS_DfxWatchdog"); + if (tid <= 0) { + return ResponseCode::DEFAULT_ERROR_CODE; + } +#ifndef FAULTLOGGERD_TEST + if (syscall(SYS_rt_tgsigqueueinfo, pid, tid, si.si_signo, &si) != 0) { + DFXLOGE("%{public}s :: Failed to SYS_rt_tgsigqueueinfo signal(%{public}d), errno(%{public}d).", + FAULTLOGGERD_SERVICE_TAG, si.si_signo, errno); + return ResponseCode::SDK_DUMP_NOPROC; + } +#endif + return ResponseCode::REQUEST_SUCCESS; +} + +int32_t SdkDumpService::SendSigDumpToProcess(pid_t pid, siginfo_t& si) +{ + auto ret = SendSigDumpToHapWatchdog(pid, si); + if (ret == ResponseCode::SDK_DUMP_NOPROC || ResponseCode::REQUEST_SUCCESS) { + return ret; + } + + if (syscall(SYS_rt_sigqueueinfo, pid, si.si_signo, &si) != 0) { + DFXLOGE("%{public}s :: Failed to SYS_rt_sigqueueinfo signal(%{public}d), errno(%{public}d).", + FAULTLOGGERD_SERVICE_TAG, si.si_signo, errno); + return ResponseCode::SDK_DUMP_NOPROC; + } + return ResponseCode::REQUEST_SUCCESS; +} + int32_t SdkDumpService::OnRequest(const std::string& socketName, int32_t connectionFd, const SdkDumpRequestData& requestData) { @@ -345,11 +388,9 @@ int32_t SdkDumpService::OnRequest(const std::string& socketName, int32_t connect */ auto& faultLoggerPipe = FaultLoggerPipePair::CreateSdkDumpPipePair(requestData.pid, requestData.time); #ifndef FAULTLOGGERD_TEST - if (syscall(SYS_rt_sigqueueinfo, requestData.pid, si.si_signo, &si) != 0) { - DFXLOGE("%{public}s :: Failed to SYS_rt_sigqueueinfo signal(%{public}d), errno(%{public}d).", - FAULTLOGGERD_SERVICE_TAG, si.si_signo, errno); + if (auto ret = SendSigDumpToProcess(requestData.pid, si); ret != ResponseCode::REQUEST_SUCCESS) { FaultLoggerPipePair::DelSdkDumpPipePair(requestData.pid); - return ResponseCode::SDK_DUMP_NOPROC; + return ret; } #endif diff --git a/services/fault_logger_service.h b/services/fault_logger_service.h index 9533109cfd85325d1a1125bda3498185bf584f03..342405614e62b7a9bcf339aabcdacf8c45747924 100644 --- a/services/fault_logger_service.h +++ b/services/fault_logger_service.h @@ -18,6 +18,7 @@ #include "string" #include "vector" +#include "csignal" #include "cstdint" #include "dfx_socket_request.h" #include "temp_file_manager.h" @@ -101,6 +102,8 @@ public: const SdkDumpRequestData& requestData) override; private: static int32_t Filter(const std::string& socketName, const SdkDumpRequestData& requestData, uint32_t uid); + static int32_t SendSigDumpToProcess(pid_t pid, siginfo_t& si); + static int32_t SendSigDumpToHapWatchdog(pid_t pid, siginfo_t& si); }; class PipeService : public FaultLoggerService { diff --git a/test/fuzztest/faultloggerdserver_fuzzer/BUILD.gn b/test/fuzztest/faultloggerdserver_fuzzer/BUILD.gn index 54f9526c83c4a9cc0672e414a6a28c93ea7e3dd5..f1ec0f304d79a135b91b130f58f3d64ae25dbf27 100644 --- a/test/fuzztest/faultloggerdserver_fuzzer/BUILD.gn +++ b/test/fuzztest/faultloggerdserver_fuzzer/BUILD.gn @@ -32,6 +32,7 @@ if (defined(ohos_lite)) { "$faultloggerd_interfaces_path/common", "$faultloggerd_interfaces_path/innerkits/faultloggerd_client", "$faultloggerd_interfaces_path/innerkits/faultloggerd_client/include", + "$faultloggerd_interfaces_path/innerkits/procinfo/include", "$faultloggerd_path/common/dfxlog", "$faultloggerd_path/services", "$faultloggerd_path/test/utils", @@ -48,6 +49,7 @@ if (defined(ohos_lite)) { deps = [ "$faultloggerd_frameworks_path/localhandler:dfx_local_handler_src", + "$faultloggerd_interfaces_path/innerkits/procinfo:libdfx_procinfo", "$faultloggerd_path/common/dfxlog:dfx_hilog_base", "$faultloggerd_path/common/dfxutil:dfx_util", "$faultloggerd_path/common/trace:dfx_trace", diff --git a/test/unittest/common/proc_util_test.cpp b/test/unittest/common/proc_util_test.cpp index 84e4baf8f1be1d3231ecf15b1af6d2bb2b5ba2f7..e7e5b12c78e2b0f107eaa520098e0bc5134c7796 100644 --- a/test/unittest/common/proc_util_test.cpp +++ b/test/unittest/common/proc_util_test.cpp @@ -14,6 +14,7 @@ */ #include +#include "csignal" #include "proc_util.h" using namespace testing::ext; @@ -230,5 +231,82 @@ HWTEST(ProcUtilTest, ParseStatTest009, TestSize.Level2) ASSERT_EQ(info.pid, getpid()); ASSERT_EQ(info.comm, std::string("test_common")); } + +/** + * @tc.name: GetFirstNumberSeqTest010 + * @tc.desc: get first number sequence. + * @tc.type: FUNC + */ +HWTEST(ProcUtilTest, GetFirstNumberSeqTest010, TestSize.Level2) +{ + std::string str = "abc"; + std::string result = GetFirstNumberSeq(str); + ASSERT_EQ(result, ""); + + std::string data = "123456"; + result = GetFirstNumberSeq(data); + ASSERT_EQ(result, data); + + result = GetFirstNumberSeq(str + data); + ASSERT_EQ(result, data); + + result = GetFirstNumberSeq(str + data + " "); + ASSERT_EQ(result, data); + + result = GetFirstNumberSeq(str + data + " adc"); + ASSERT_EQ(result, data); + + result = GetFirstNumberSeq(str + data + " 123"); + ASSERT_EQ(result, data); +} + +/** + * @tc.name: IsSigDumpMaskTest011 + * @tc.desc: is sig dump mask. + * @tc.type: FUNC + */ +HWTEST(ProcUtilTest, IsSigDumpMaskTest011, TestSize.Level2) +{ + uint64_t sigBlk = 0x00000000; + ASSERT_FALSE(IsSigDumpMask(sigBlk)); + + sigBlk = 0x00000004; + ASSERT_FALSE(IsSigDumpMask(sigBlk)); + // SigBlk: 0000000400000000 + sigBlk = 0x0000000400000000; + ASSERT_TRUE(IsSigDumpMask(sigBlk)); + + sigBlk = 0x4000000000; + ASSERT_FALSE(IsSigDumpMask(sigBlk)); +} + +/** + * @tc.name: ParsePidStatus013 + * @tc.desc: is hap. + * @tc.type: FUNC + */ +HWTEST(ProcUtilTest, ParsePidStatus013, TestSize.Level2) +{ + pid_t pid = 99999; // 99999 : Invalid PID + long uid = 0; + uint64_t sigBlk = 0; + auto result = GetUidAndSigBlk(pid, uid, sigBlk); + EXPECT_TRUE(uid == 0); + EXPECT_TRUE(sigBlk == 0); + + pid = getpid(); + result = GetUidAndSigBlk(pid, uid, sigBlk); + EXPECT_TRUE(sigBlk == 0); + + sigset_t sigSet; + sigemptyset(&sigSet); + sigaddset(&sigSet, SIGQUIT); + sigprocmask(SIG_BLOCK, &sigSet, nullptr); + + result = GetUidAndSigBlk(pid, uid, sigBlk); + EXPECT_TRUE(sigBlk == (1 << (SIGQUIT -1))); + + sigprocmask(SIG_UNBLOCK, &sigSet, nullptr); +} } // namespace HiviewDFX } // namespace OHOS diff --git a/test/unittest/faultloggerd/BUILD.gn b/test/unittest/faultloggerd/BUILD.gn index 8b2aeb0755c20852303be2691d8b0b8fed5fcdc6..bb3edd1d9496e7ff5b679bd2e5e7c9145b67b101 100644 --- a/test/unittest/faultloggerd/BUILD.gn +++ b/test/unittest/faultloggerd/BUILD.gn @@ -49,6 +49,7 @@ if (defined(ohos_lite)) { "$faultloggerd_path/common/cutil", "$faultloggerd_path/common/dfxlog", "$faultloggerd_path/common/dfxutil", + "$faultloggerd_path/test/utils", ] sources = [ @@ -108,6 +109,7 @@ if (defined(ohos_lite)) { "$faultloggerd_path/common/dfxlog", "$faultloggerd_path/interfaces/innerkits/faultloggerd_client", "$faultloggerd_path/interfaces/innerkits/faultloggerd_client/include", + "$faultloggerd_interfaces_path/innerkits/procinfo/include", "$faultloggerd_path/services", "$faultloggerd_path/test/utils", ] @@ -119,13 +121,16 @@ if (defined(ohos_lite)) { "faultloggerd_test.cpp", "temp_file_manager_test.cpp", ] + cflags_cc = [ "-Dprivate=public" ] defines = [ "FAULTLOGGERD_TEST" ] deps = [ "$faultloggerd_frameworks_path/localhandler:dfx_local_handler_src", + "$faultloggerd_interfaces_path/innerkits/procinfo:libdfx_procinfo", "$faultloggerd_path/common/dfxlog:dfx_hilog_base", "$faultloggerd_path/common/dfxutil:dfx_util", "$faultloggerd_path/common/trace:dfx_trace", "$faultloggerd_path/services:faultloggerd_test_src", + "$faultloggerd_path/test/utils:dfx_test_util", ] external_deps = [ @@ -141,7 +146,7 @@ if (defined(ohos_lite)) { if (build_selinux) { external_deps += [ "selinux:libselinux" ] - cflags_cc = [ "-DHAS_LIB_SELINUX" ] + cflags_cc += [ "-DHAS_LIB_SELINUX" ] } } diff --git a/test/unittest/faultloggerd/faultlogger_server_test.cpp b/test/unittest/faultloggerd/faultlogger_server_test.cpp index 907065254070f522447c68c65e0a47d70f7a20d9..0f8f453e33e9e16ee39f6eda44d13de5573fcc31 100644 --- a/test/unittest/faultloggerd/faultlogger_server_test.cpp +++ b/test/unittest/faultloggerd/faultlogger_server_test.cpp @@ -26,6 +26,7 @@ #include "dfx_log.h" #include "dfx_socket_request.h" #include "dfx_util.h" +#include "dfx_test_util.h" #include "fault_logger_daemon.h" #include "fault_logger_pipe.h" #include "faultloggerd_client.h" @@ -215,6 +216,29 @@ HWTEST_F(FaultLoggerdServiceTest, SdkDumpClientTest03, TestSize.Level2) int32_t retCode = SendRequestToServer(SERVER_SDKDUMP_SOCKET_NAME, &requestData, sizeof(requestData)); ASSERT_EQ(retCode, ResponseCode::SDK_PROCESS_CRASHED); } +/** + * @tc.name: SdkDumpServiceTest001 + * @tc.desc: request sdk dumpJson after request a fd for cppcrash. + * @tc.type: FUNC + */ +HWTEST_F(FaultLoggerdServiceTest, SdkDumpServiceTest001, TestSize.Level2) +{ + pid_t pid; + pid = getpid(); // 99999 : Invalid pid + siginfo_t si; + auto ret = SdkDumpService::SendSigDumpToHapWatchdog(pid, si); + EXPECT_EQ(ret, ResponseCode::DEFAULT_ERROR_CODE); +#if defined(__aarch64__) + std::string appName = "com.ohos.sceneboard"; + pid = GetProcessPid(appName); + if (pid > 0) { + ret = SdkDumpService::SendSigDumpToHapWatchdog(pid, si); // sceneboard is mask + EXPECT_EQ(ret, ResponseCode::DEFAULT_ERROR_CODE); + } else { + FAIL() << "GetWatchdogTidByPid006: " << appName << " not running."; + } +#endif +} /** * @tc.name: PipeFdClientTest01 * @tc.desc: request a pip fd. @@ -537,4 +561,3 @@ HWTEST_F(FaultLoggerdServiceTest, AbnormalTest007, TestSize.Level2) } } // namespace HiviewDFX } // namespace OHOS - diff --git a/test/unittest/procinfo/BUILD.gn b/test/unittest/procinfo/BUILD.gn index c120a669dfd6bfc1530f63bdf6f2450469eebf32..86baa22bb20f3a3611eeee841ce07ec99282a693 100644 --- a/test/unittest/procinfo/BUILD.gn +++ b/test/unittest/procinfo/BUILD.gn @@ -28,6 +28,7 @@ if (defined(ohos_lite)) { "$faultloggerd_path/common/dfxlog", "$faultloggerd_path/common/dfxutil", "$faultloggerd_path/interfaces/innerkits/procinfo/include", + "$faultloggerd_path/test/utils", "$hilog_lite_include_path", ] @@ -37,6 +38,7 @@ if (defined(ohos_lite)) { "$faultloggerd_path/common/dfxlog:dfx_hilog", "$faultloggerd_path/common/dfxutil:dfx_util", "$faultloggerd_path/interfaces/innerkits/procinfo:libdfx_procinfo", + "$faultloggerd_path/test/utils:dfx_test_util", "$hilog_lite_deps_path", ] } @@ -54,7 +56,10 @@ if (defined(ohos_lite)) { config("module_private_config") { visibility = [ ":*" ] - include_dirs = [ "$faultloggerd_interfaces_path/common" ] + include_dirs = [ + "$faultloggerd_interfaces_path/common", + "$faultloggerd_path/test/utils", + ] } module_output_path = "faultloggerd/faultloggerd/procinfo" @@ -68,6 +73,7 @@ if (defined(ohos_lite)) { deps = [ "$faultloggerd_path/common/dfxutil:dfx_util", "$faultloggerd_path/interfaces/innerkits/procinfo:libdfx_procinfo", + "$faultloggerd_path/test/utils:dfx_test_util", ] external_deps = [ diff --git a/test/unittest/procinfo/procinfo_test.cpp b/test/unittest/procinfo/procinfo_test.cpp index 7ba6688d5f7256560baab796a57b2d0aa7f303e0..fe0aa2e94ca71dfc62544f97490812aba786c743 100644 --- a/test/unittest/procinfo/procinfo_test.cpp +++ b/test/unittest/procinfo/procinfo_test.cpp @@ -19,6 +19,7 @@ #include #include #include "dfx_util.h" +#include "dfx_test_util.h" #include "procinfo.h" using namespace OHOS::HiviewDFX; @@ -134,3 +135,26 @@ HWTEST_F(ProcinfoTest, ProcinfoTest005, TestSize.Level2) ASSERT_TRUE(result.find("test_procinfo") != std::string::npos); GTEST_LOG_(INFO) << "ProcinfoTest005: end."; } + +/** + * @tc.name: GetWatchdogTidByPid006 + * @tc.desc: test GetWatchdogTidByPid + * @tc.type: FUNC + */ +HWTEST_F(ProcinfoTest, GetWatchdogTidByPid006, TestSize.Level2) +{ + pid_t watchdogTid = GetTidByThreadName(-1, "OS_DfxWatchdog"); + ASSERT_TRUE(watchdogTid == -1); + + watchdogTid = GetTidByThreadName(getpid(), "OS_DfxWatchdog"); + ASSERT_TRUE(watchdogTid == -1); + + std::thread watchdogThread([] { + pthread_setname_np(pthread_self(), "OS_DfxWatchdog"); + std::this_thread::sleep_for(std::chrono::seconds(2)); // 2 : sleep for 2 seconds + }); + watchdogTid = GetTidByThreadName(getpid(), "OS_DfxWatchdog"); + ASSERT_TRUE(watchdogTid != -1); + + watchdogThread.join(); +}