!4253 优化混合栈字段打印,补充进程Pid、Uid、进程名、时间戳等信息

Merge pull request !4253 from hw_mzyan/master
This commit is contained in:
openharmony_ci
2022-12-15 13:29:01 +00:00
committed by Gitee
3 changed files with 157 additions and 8 deletions
@@ -15,6 +15,7 @@
#include "mix_stack_dumper.h"
#include <ctime>
#include <dirent.h>
#include <securec.h>
#include <unistd.h>
@@ -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<uint64_t>(now)) {
millisecond = current % ratio;
now = static_cast<time_t>(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<std::shared_ptr<OHOS:
}
}
void MixStackDumper::PrintProcessHeader(int fd, pid_t pid, uid_t uid)
{
char headerBuf[HEADER_BUF_LEN] = { 0 };
std::string processName = "";
int ret = 1;
if (LoadStringFromFile(PROC_SELF_CMDLINE_PATH, processName)) {
ret = snprintf_s(headerBuf, HEADER_BUF_LEN, HEADER_BUF_LEN - 1,
"Timestamp:%sPid:%d\nUid:%d\nProcess name:%s\n",
GetCurrentTimeStr().c_str(), pid, uid, processName.c_str());
} else {
ret = snprintf_s(headerBuf, HEADER_BUF_LEN, HEADER_BUF_LEN - 1,
"Timestamp:%sPid:%d\nUid:%d\nProcess name:unknown\n",
GetCurrentTimeStr().c_str(), pid, uid);
}
if (ret <= 0) {
HILOG_ERROR("snprintf_s process mix stack header failed.");
return;
}
write(fd, headerBuf, strlen(headerBuf));
}
bool MixStackDumper::DumpMixFrame(int fd, pid_t nstid, pid_t tid)
{
if (catcher_ == nullptr) {
@@ -333,7 +383,6 @@ bool MixStackDumper::DumpMixFrame(int fd, pid_t nstid, pid_t tid)
}
BuildJsNativeMixStack(fd, jsFrames, nativeFrames);
write(fd, "\n", 1);
return true;
}
@@ -388,6 +437,7 @@ void MixStackDumper::HandleMixDumpRequest()
int dumpRes = OHOS::HiviewDFX::ProcessDumpRes::DUMP_ESUCCESS;
(void)memset_s(&g_procInfo, sizeof(g_procInfo), 0, sizeof(g_procInfo));
(void)GetProcStatus(&g_procInfo);
HILOG_INFO("Current process is ready to dump stack trace.");
do {
fd = RequestPipeFd(GetPid(), FaultLoggerPipeType::PIPE_FD_WRITE_BUF);
resFd = RequestPipeFd(GetPid(), FaultLoggerPipeType::PIPE_FD_WRITE_RES);
@@ -398,6 +448,7 @@ void MixStackDumper::HandleMixDumpRequest()
}
MixStackDumper mixDumper;
mixDumper.Init(GetPid());
mixDumper.PrintProcessHeader(fd, GetPid(), getuid());
if (g_targetDumpTid > 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
@@ -44,6 +44,7 @@ private:
std::vector<std::shared_ptr<OHOS::HiviewDFX::DfxFrame>>& nativeFrames);
std::string GetThreadStackTraceLabel(pid_t tid);
void PrintNativeFrames(int fd, std::vector<std::shared_ptr<OHOS::HiviewDFX::DfxFrame>>& 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();
@@ -15,6 +15,11 @@
#include <gtest/gtest.h>
#include <cstring>
#include <fcntl.h>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <vector>
@@ -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<std::string> 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