mirror of
https://github.com/openharmony/ability_ability_runtime.git
synced 2026-08-24 22:21:36 -04:00
!4253 优化混合栈字段打印,补充进程Pid、Uid、进程名、时间戳等信息
Merge pull request !4253 from hw_mzyan/master
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user