diff --git a/frameworks/native/appkit/app/mix_stack_dumper.cpp b/frameworks/native/appkit/app/mix_stack_dumper.cpp index baf2849a81..21ed486269 100644 --- a/frameworks/native/appkit/app/mix_stack_dumper.cpp +++ b/frameworks/native/appkit/app/mix_stack_dumper.cpp @@ -15,6 +15,7 @@ #include "mix_stack_dumper.h" +#include #include #include #include @@ -35,8 +36,10 @@ static const char PID_STR_NAME[] = "Pid:"; static const char PPID_STR_NAME[] = "PPid:"; static const char NSPID_STR_NAME[] = "NSpid:"; static const char PROC_SELF_STATUS_PATH[] = "/proc/self/status"; +static const std::string PROC_SELF_CMDLINE_PATH = "/proc/self/cmdline"; static constexpr int STATUS_LINE_SIZE = 1024; static constexpr int FRAME_BUF_LEN = 1024; +static constexpr int HEADER_BUF_LEN = 512; static constexpr int NATIVE_DUMP = -1; static constexpr int MIX_DUMP = -2; static constexpr int NAMESPACE_MATCH_NUM = 2; @@ -190,6 +193,31 @@ static void TidToNstid(const int tid, int& nstid) (void)fclose(fp); } +static std::string GetCurrentTimeStr(uint64_t current = 0) +{ + time_t now = time(nullptr); + uint64_t millisecond = 0; + const uint64_t ratio = 1000; + if (current > static_cast(now)) { + millisecond = current % ratio; + now = static_cast(current / ratio); + } + + auto tm = std::localtime(&now); + char seconds[128] = { 0 }; // 128 : time buffer size + if (tm == nullptr || strftime(seconds, sizeof(seconds) - 1, "%Y-%m-%d %H:%M:%S", tm) == 0) { + return "invalid timestamp\n"; + } + + char formatTimeBuf[256] = { 0 }; // 256 : buffer size + int ret = snprintf_s(formatTimeBuf, sizeof(formatTimeBuf), sizeof(formatTimeBuf) - 1, + "%s.%03u\n", seconds, millisecond); + if (ret <= 0) { + return "invalid timestamp\n"; + } + return std::string(formatTimeBuf, strlen(formatTimeBuf)); +} + void MixStackDumper::Dump_SignalHandler(int sig, siginfo_t *si, void *context) { switch (si->si_code) { @@ -200,6 +228,7 @@ void MixStackDumper::Dump_SignalHandler(int sig, siginfo_t *si, void *context) break; } case MIX_DUMP: { + HILOG_INFO("Received mix stack dump request."); auto handler = signalHandler_.lock(); if (handler == nullptr) { return; @@ -296,6 +325,27 @@ void MixStackDumper::PrintNativeFrames(int fd, std::vector 0) { pid_t targetNsTid = g_targetDumpTid; if (HasNameSpace()) { @@ -436,6 +487,7 @@ void MixStackDumper::HandleMixDumpRequest() if (fd != -1) { close(fd); } + HILOG_INFO("Finish dumping stack trace."); } } // AppExecFwk } // OHOS diff --git a/interfaces/kits/native/appkit/app/mix_stack_dumper.h b/interfaces/kits/native/appkit/app/mix_stack_dumper.h index 8f00d330d5..7d98d76e66 100644 --- a/interfaces/kits/native/appkit/app/mix_stack_dumper.h +++ b/interfaces/kits/native/appkit/app/mix_stack_dumper.h @@ -44,6 +44,7 @@ private: std::vector>& nativeFrames); std::string GetThreadStackTraceLabel(pid_t tid); void PrintNativeFrames(int fd, std::vector>& nativeFrames); + void PrintProcessHeader(int fd, pid_t pid, uid_t uid); static void Dump_SignalHandler(int sig, siginfo_t *si, void *context); static void HandleMixDumpRequest(); diff --git a/test/unittest/frameworks_kits_appkit_native_test/mix_stack_dumper_test.cpp b/test/unittest/frameworks_kits_appkit_native_test/mix_stack_dumper_test.cpp index f83e820002..81dbe2c181 100644 --- a/test/unittest/frameworks_kits_appkit_native_test/mix_stack_dumper_test.cpp +++ b/test/unittest/frameworks_kits_appkit_native_test/mix_stack_dumper_test.cpp @@ -15,6 +15,11 @@ #include +#include +#include +#include +#include +#include #include #include @@ -80,6 +85,33 @@ static int GetServicePid(const std::string& serviceName) return pid; } +static bool CheckMixStackKeyWords(const char *filePath, std::string *keywords, int length) +{ + std::ifstream file; + file.open(filePath, std::ios::in); + std::vector buf(128); // 128 : buf size + int cnt = 0; + int i = 0; + int j = 0; + std::string::size_type idx; + while (!file.eof()) { + file >> buf.at(i); + idx = buf.at(i).find(keywords[j]); + if (idx != std::string::npos) { + GTEST_LOG_(INFO) << buf.at(i); + cnt++; + j++; + if (j == length) { + break; + } + continue; + } + i++; + } + file.close(); + return cnt == length; +} + /** * @tc.number: MixStackDumperTest001 * @tc.name: dump com.ohos.systemui process @@ -87,12 +119,24 @@ static int GetServicePid(const std::string& serviceName) */ HWTEST_F(MixStackDumperTest, MixStackDumperTest001, Function | MediumTest | Level3) { + char testFile[] = "/data/mix_stack_header_test01"; + int fd = open(testFile, O_RDWR | O_CREAT, 0755); // 0755 : -rwxr-xr-x + if (fd == -1) { + GTEST_LOG_(ERROR) << "Failed to create test file."; + return; + } MixStackDumper mixDumper; pid_t pid = GetServicePid("com.ohos.systemui"); mixDumper.Init(pid); - bool ret = mixDumper.DumpMixFrame(1, pid, pid); + bool ret = mixDumper.DumpMixFrame(fd, pid, pid); mixDumper.Destroy(); EXPECT_FALSE(ret); + close(fd); + std::string keywords[] = { + "Tid:" + std::to_string(pid), "Failed", "suspend", + }; + int length = sizeof(keywords) / sizeof(keywords[0]); + EXPECT_TRUE(CheckMixStackKeyWords(testFile, keywords, length)); } /** @@ -102,15 +146,28 @@ HWTEST_F(MixStackDumperTest, MixStackDumperTest001, Function | MediumTest | Leve */ HWTEST_F(MixStackDumperTest, MixStackDumperTest002, Function | MediumTest | Level3) { + char testFile[] = "/data/mix_stack_header_test02"; + int fd = open(testFile, O_RDWR | O_CREAT, 0755); // 0755 : -rwxr-xr-x + if (fd == -1) { + GTEST_LOG_(ERROR) << "Failed to create test file."; + return; + } MixStackDumper mixDumper; - bool ret = mixDumper.DumpMixFrame(1, getpid(), getpid()); + bool ret = mixDumper.DumpMixFrame(fd, getpid(), getpid()); EXPECT_FALSE(ret); mixDumper.Init(getpid()); - ret = mixDumper.DumpMixFrame(1, -1, -1); + ret = mixDumper.DumpMixFrame(fd, -1, -1); EXPECT_FALSE(ret); - ret = mixDumper.DumpMixFrame(1, getpid(), getpid()); + ret = mixDumper.DumpMixFrame(fd, getpid(), getpid()); mixDumper.Destroy(); EXPECT_TRUE(ret); + close(fd); + std::string keywords[] = { + "Tid:-1", "Failed", "suspend", "Tid:" + std::to_string(getpid()), "#00", "pc", + "libappkit_native.z.so", "mix_stack_dumper_test", + }; + int length = sizeof(keywords) / sizeof(keywords[0]); + EXPECT_TRUE(CheckMixStackKeyWords(testFile, keywords, length)); } /** @@ -141,8 +198,21 @@ HWTEST_F(MixStackDumperTest, MixStackDumperTest004, Function | MediumTest | Leve nativeFrames.emplace_back(nativeFrame2); nativeFrames.emplace_back(nullptr); MixStackDumper mixDumper; - mixDumper.PrintNativeFrames(1, nativeFrames); - EXPECT_TRUE(true); + char testFile[] = "/data/mix_stack_header_test04"; + int fd = open(testFile, O_RDWR | O_CREAT, 0755); // 0755 : -rwxr-xr-x + if (fd == -1) { + GTEST_LOG_(ERROR) << "Failed to create test file."; + mixDumper.PrintNativeFrames(1, nativeFrames); + EXPECT_TRUE(true); + } else { + mixDumper.PrintNativeFrames(fd, nativeFrames); + close(fd); + std::string keywords[] = { + "#00", "pc", "testmapname", "Unknown", + }; + int length = sizeof(keywords) / sizeof(keywords[0]); + EXPECT_TRUE(CheckMixStackKeyWords(testFile, keywords, length)); + } } /** @@ -155,7 +225,8 @@ HWTEST_F(MixStackDumperTest, MixStackDumperTest005, Function | MediumTest | Leve MixStackDumper mixDumper; std::string label = mixDumper.GetThreadStackTraceLabel(gettid()); GTEST_LOG_(INFO) << label; - EXPECT_TRUE(true); + std::string keyword = "mix_stack_dump"; + EXPECT_TRUE(label.find(keyword) != std::string::npos); } /** @@ -169,5 +240,30 @@ HWTEST_F(MixStackDumperTest, MixStackDumperTest006, Function | MediumTest | Leve mixDumper.HandleMixDumpRequest(); EXPECT_TRUE(true); } + +/** + * @tc.number: MixStackDumperTest007 + * @tc.name: Call PrintProcessHeader Func + * @tc.desc: test PrintProcessHeader Func + */ +HWTEST_F(MixStackDumperTest, MixStackDumperTest007, Function | MediumTest | Level3) +{ + MixStackDumper mixDumper; + char testFile[] = "/data/mix_stack_header_test07"; + int fd = open(testFile, O_RDWR | O_CREAT, 0755); // 0755 : -rwxr-xr-x + if (fd == -1) { + GTEST_LOG_(ERROR) << "Failed to create test file."; + mixDumper.PrintProcessHeader(1, getpid(), getuid()); + EXPECT_TRUE(true); + } else { + mixDumper.PrintProcessHeader(fd, getpid(), getuid()); + close(fd); + std::string headerKeywords[] = { + "Timestamp:", "Pid:" + std::to_string(getpid()), "Uid:" + std::to_string(getuid()), "mix_stack_dumper_test", + }; + int length = sizeof(headerKeywords) / sizeof(headerKeywords[0]); + EXPECT_TRUE(CheckMixStackKeyWords(testFile, headerKeywords, length)); + } +} } // namespace AppExecFwk } // namespace OHOS