• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "dfx_processdump_test.h"
17 
18 #include <fstream>
19 #include <map>
20 #include <csignal>
21 #include <string>
22 #include <unistd.h>
23 #include <vector>
24 
25 #include "dfx_config.h"
26 #include "dfx_cutil.h"
27 #include "dfx_define.h"
28 #include "dfx_util.h"
29 #include "directory_ex.h"
30 #include "multithread_constructor.h"
31 #include "process_dumper.h"
32 
33 using namespace OHOS::HiviewDFX;
34 using namespace testing::ext;
35 using namespace std;
36 
37 static const int BUF_LEN = 100;
38 
SetUpTestCase(void)39 void DfxProcessDumpTest::SetUpTestCase(void)
40 {
41 }
42 
TearDownTestCase(void)43 void DfxProcessDumpTest::TearDownTestCase(void)
44 {
45 }
46 
SetUp(void)47 void DfxProcessDumpTest::SetUp(void)
48 {
49 }
50 
TearDown(void)51 void DfxProcessDumpTest::TearDown(void)
52 {
53 }
54 
CreateMultiThreadProcess(int threadNum)55 static pid_t CreateMultiThreadProcess(int threadNum)
56 {
57     pid_t pid = fork();
58     if (pid < 0) {
59         GTEST_LOG_(ERROR) << "Failed to fork new test process.";
60     } else if (pid == 0) {
61         (void)MultiThreadConstructor(threadNum);
62     }
63     return pid;
64 }
65 
GetCppCrashFileName(pid_t pid)66 static string GetCppCrashFileName(pid_t pid)
67 {
68     if (pid <= 0) {
69         return "";
70     }
71     vector<string> files;
72     OHOS::GetDirFiles("/data/log/faultlog/temp", files);
73     string fileNamePrefix = "cppcrash-" + to_string(pid);
74     for (const auto& file : files) {
75         if (file.find(fileNamePrefix) != string::npos) {
76             return file;
77         }
78     }
79     return "";
80 }
81 
CountLines(const string & filename)82 static int CountLines(const string& filename)
83 {
84     ifstream readStream;
85     string tempData;
86     readStream.open(filename.c_str(), ios::in);
87     if (readStream.fail()) {
88         return 0;
89     } else {
90         int n = 0;
91         while (getline(readStream, tempData, '\n')) {
92             n++;
93         }
94         readStream.close();
95         return n;
96     }
97 }
98 
CheckKeyWords(const string & filePath,string * keywords,int length)99 static int CheckKeyWords(const string& filePath, string *keywords, int length)
100 {
101     ifstream file;
102     file.open(filePath.c_str(), ios::in);
103     long lines = CountLines(filePath);
104     vector<string> t(lines * 4); // 4 : max string blocks of one line
105     int i = 0;
106     int j = 0;
107     string::size_type idx;
108     int count = 0;
109     int minRegIdx = 6; // 6 : index of REGISTERS
110     int maxRegIdx = minRegIdx + REGISTERS_NUM + 1;
111     while (!file.eof()) {
112         file >> t.at(i);
113         idx = t.at(i).find(keywords[j]);
114         if (idx != string::npos) {
115             GTEST_LOG_(INFO) << t.at(i);
116             if (j > minRegIdx && j < maxRegIdx) {
117                 if (t.at(i).size() < REGISTERS_LENGTH) {
118                     count--;
119                 }
120             }
121             count++;
122             j++;
123             if (j == length) {
124                 break;
125             }
126             continue;
127         }
128         i++;
129     }
130     file.close();
131     GTEST_LOG_(INFO) << count << " keys matched.";
132     return count;
133 }
134 
CheckCppCrashKeyWords(const string & filePath,pid_t pid,int sig)135 static bool CheckCppCrashKeyWords(const string& filePath, pid_t pid, int sig)
136 {
137     if (filePath.empty() || pid <= 0) {
138         return false;
139     }
140     map<int, string> sigKey = {
141         { SIGILL, string("SIGILL") },
142         { SIGTRAP, string("SIGTRAP") },
143         { SIGABRT, string("SIGABRT") },
144         { SIGBUS, string("SIGBUS") },
145         { SIGFPE, string("SIGFPE") },
146         { SIGSEGV, string("SIGSEGV") },
147         { SIGSTKFLT, string("SIGSTKFLT") },
148         { SIGSYS, string("SIGSYS") },
149     };
150     string sigKeyword = "";
151     map<int, string>::iterator iter = sigKey.find(sig);
152     if (iter != sigKey.end()) {
153         sigKeyword = iter->second;
154     }
155     string keywords[] = {
156         "Pid:" + to_string(pid), "Uid:", "test_processdump", sigKeyword, "Tid:", "#00", "Registers:", REGISTERS,
157         "FaultStack:", "Maps:", "test_processdump"
158     };
159     int length = sizeof(keywords) / sizeof(keywords[0]);
160     return CheckKeyWords(filePath, keywords, length) == length;
161 }
162 
GetCmdResultFromPopen(const string & cmd)163 static string GetCmdResultFromPopen(const string& cmd)
164 {
165     if (cmd.empty()) {
166         return "";
167     }
168     FILE* fp = popen(cmd.c_str(), "r");
169     if (fp == nullptr) {
170         return "";
171     }
172     const int bufSize = 128;
173     char buffer[bufSize];
174     string result = "";
175     while (!feof(fp)) {
176         if (fgets(buffer, bufSize - 1, fp) != nullptr) {
177             result += buffer;
178         }
179     }
180     pclose(fp);
181     return result;
182 }
183 
GetProcessPid(string applyName)184 static int GetProcessPid(string applyName)
185 {
186     string procCMD = "pgrep '" + applyName + "'";
187     GTEST_LOG_(INFO) << "threadCMD = " << procCMD;
188     FILE *procFileInfo = nullptr;
189     procFileInfo = popen(procCMD.c_str(), "r");
190     if (procFileInfo == nullptr) {
191         perror("popen execute failed");
192         return -1;
193     }
194     string applyPid;
195     char resultBuf[BUF_LEN] = { 0, };
196     while (fgets(resultBuf, sizeof(resultBuf), procFileInfo) != nullptr) {
197         applyPid = resultBuf;
198         GTEST_LOG_(INFO) << "applyPid: " << applyPid;
199     }
200     pclose(procFileInfo);
201     return atoi(applyPid.c_str());
202 }
203 
GetServicePid(const std::string & serviceName)204 static int GetServicePid(const std::string& serviceName)
205 {
206     string cmd = "pidof " + serviceName;
207     string pidStr = GetCmdResultFromPopen(cmd);
208     int32_t pid = 0;
209     std::stringstream pidStream(pidStr);
210     pidStream >> pid;
211     printf("the pid of service(%s) is %s \n", serviceName.c_str(), pidStr.c_str());
212     return pid;
213 }
214 
ProcessDumpCommands(const std::string cmds)215 static string ProcessDumpCommands(const std::string cmds)
216 {
217     GTEST_LOG_(INFO) << "threadCMD = " << cmds;
218     FILE *procFileInfo = nullptr;
219     std::string cmdLog = "";
220     procFileInfo = popen(cmds.c_str(), "r");
221     if (procFileInfo == nullptr) {
222         perror("popen execute failed");
223         return cmdLog;
224     }
225     char resultBuf[BUF_LEN] = { 0, };
226     while (fgets(resultBuf, sizeof(resultBuf), procFileInfo) != nullptr) {
227         cmdLog += resultBuf;
228     }
229     pclose(procFileInfo);
230     return cmdLog;
231 }
232 
LaunchTestHap(const string & abilityName,const string & bundleName)233 static int LaunchTestHap(const string& abilityName, const string& bundleName)
234 {
235     string launchCmd = "/system/bin/aa start -a " + abilityName + " -b " + bundleName;
236     (void)GetCmdResultFromPopen(launchCmd);
237     sleep(2); // 2 : sleep 2s
238     return GetServicePid(bundleName);
239 }
240 
241 /**
242  * @tc.name: DfxProcessDumpTest001
243  * @tc.desc: test dumpcatcher -p [native process]
244  * @tc.type: FUNC
245  */
246 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest001, TestSize.Level2)
247 {
248     GTEST_LOG_(INFO) << "DfxProcessDumpTest001: start.";
249     int testPid = GetProcessPid("accountmgr");
250     string testCommand = "dumpcatcher -p " + to_string(testPid);
251     string dumpRes = ProcessDumpCommands(testCommand);
252     GTEST_LOG_(INFO) << dumpRes;
253     int count = 0;
254     string log[] = {"Pid:", "Name:", "#00", "#01", "#02"};
255     log[0] = log[0] + to_string(testPid);
256     log[1] = log[1] + "accountmgr";
257     string::size_type idx;
258     int len = sizeof(log) / sizeof(log[0]);
259     for (int i = 0; i < len; i++) {
260         idx = dumpRes.find(log[i]);
261         if (idx != string::npos) {
262             GTEST_LOG_(INFO) << log[i];
263             count++;
264         }
265     }
266     ASSERT_EQ(count, len);
267     GTEST_LOG_(INFO) << "DfxProcessDumpTest001: end.";
268 }
269 
270 /**
271  * @tc.name: DfxProcessDumpTest002
272  * @tc.desc: test dumpcatcher -p -t [native process]
273  * @tc.type: FUNC
274  */
275 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest002, TestSize.Level2)
276 {
277     GTEST_LOG_(INFO) << "DfxProcessDumpTest002: start.";
278     int testPid = GetProcessPid("accountmgr");
279     string testCommand = "dumpcatcher -p " + to_string(testPid) + " -t " + to_string(testPid);
280     string dumpRes = ProcessDumpCommands(testCommand);
281     GTEST_LOG_(INFO) << dumpRes;
282     int count = 0;
283     string log[] = {"Pid:", "Name:", "#00", "#01", "#02"};
284     log[0] = log[0] + to_string(testPid);
285     log[1] = log[1] + "accountmgr";
286     string::size_type idx;
287     int len = sizeof(log) / sizeof(log[0]);
288     for (int i = 0; i < len; i++) {
289         idx = dumpRes.find(log[i]);
290         if (idx != string::npos) {
291             GTEST_LOG_(INFO) << log[i];
292             count++;
293         }
294     }
295     ASSERT_EQ(count, len);
296     GTEST_LOG_(INFO) << "DfxProcessDumpTest002: end.";
297 }
298 
299 /**
300  * @tc.name: DfxProcessDumpTest003
301  * @tc.desc: test dumpcatcher -p [application process]
302  * @tc.type: FUNC
303  */
304 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest003, TestSize.Level2)
305 {
306     GTEST_LOG_(INFO) << "DfxProcessDumpTest003: start.";
307     string testBundleName = "ohos.samples.distributedcalc";
308     string testAbiltyName = testBundleName + ".MainAbility";
309     int testPid = LaunchTestHap(testAbiltyName, testBundleName);
310     string testCommand = "dumpcatcher -p " + to_string(testPid);
311     string dumpRes = ProcessDumpCommands(testCommand);
312     GTEST_LOG_(INFO) << dumpRes;
313     int count = 0;
314     string log[] = {"Pid:", "Name:", "#00", "#01", "#02"};
315     log[0] = log[0] + to_string(testPid);
316     log[1] = log[1] + "ohos.samples.di";
317     string::size_type idx;
318     int len = sizeof(log) / sizeof(log[0]);
319     for (int i = 0; i < len; i++) {
320         idx = dumpRes.find(log[i]);
321         if (idx != string::npos) {
322             GTEST_LOG_(INFO) << log[i];
323             count++;
324         }
325     }
326     ASSERT_EQ(count, len);
327     GTEST_LOG_(INFO) << "DfxProcessDumpTest003: end.";
328 }
329 
330 /**
331  * @tc.name: DfxProcessDumpTest004
332  * @tc.desc: test dumpcatcher -p -t [application process]
333  * @tc.type: FUNC
334  */
335 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest004, TestSize.Level2)
336 {
337     GTEST_LOG_(INFO) << "DfxProcessDumpTest004: start.";
338     string testBundleName = "ohos.samples.distributedcalc";
339     string testAbiltyName = testBundleName + ".MainAbility";
340     int testPid = LaunchTestHap(testAbiltyName, testBundleName);
341     string testCommand = "dumpcatcher -p " + to_string(testPid) + " -t " + to_string(testPid);
342     string dumpRes = ProcessDumpCommands(testCommand);
343     GTEST_LOG_(INFO) << dumpRes;
344     int count = 0;
345     string log[] = {"Pid:", "Name:", "#00", "#01", "#02"};
346     log[0] = log[0] + to_string(testPid);
347     log[1] = log[1] + "ohos.samples.di";
348     string::size_type idx;
349     int len = sizeof(log) / sizeof(log[0]);
350     for (int i = 0; i < len; i++) {
351         idx = dumpRes.find(log[i]);
352         if (idx != string::npos) {
353             GTEST_LOG_(INFO) << log[i];
354             count++;
355         }
356     }
357     ASSERT_EQ(count, len);
358     // kill(testPid, SIGKILL);
359     GTEST_LOG_(INFO) << "DfxProcessDumpTest004: end.";
360 }
361 
362 /**
363  * @tc.name: DfxProcessDumpTest005
364  * @tc.desc: test SIGILL crash
365  * @tc.type: FUNC
366  */
367 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest005, TestSize.Level2)
368 {
369     GTEST_LOG_(INFO) << "DfxProcessDumpTest005: start.";
370     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
371     kill(testProcess, SIGILL);
372     sleep(3); // 3 : wait 3s to generate cpp crash file
373     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGILL);
374     ASSERT_TRUE(ret);
375     GTEST_LOG_(INFO) << "DfxProcessDumpTest005: end.";
376 }
377 
378 /**
379  * @tc.name: DfxProcessDumpTest006
380  * @tc.desc: test SIGTRAP crash
381  * @tc.type: FUNC
382  */
383 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest006, TestSize.Level2)
384 {
385     GTEST_LOG_(INFO) << "DfxProcessDumpTest006: start.";
386     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
387     kill(testProcess, SIGTRAP);
388     sleep(3); // 3 : wait 3s to generate cpp crash file
389     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGTRAP);
390     ASSERT_TRUE(ret);
391     GTEST_LOG_(INFO) << "DfxProcessDumpTest006: end.";
392 }
393 
394 /**
395  * @tc.name: DfxProcessDumpTest007
396  * @tc.desc: test SIGABRT crash
397  * @tc.type: FUNC
398  */
399 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest007, TestSize.Level2)
400 {
401     GTEST_LOG_(INFO) << "DfxProcessDumpTest007: start.";
402     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
403     kill(testProcess, SIGABRT);
404     sleep(3); // 3 : wait 3s to generate cpp crash file
405     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGABRT);
406     ASSERT_TRUE(ret);
407     GTEST_LOG_(INFO) << "DfxProcessDumpTest007: end.";
408 }
409 
410 /**
411  * @tc.name: DfxProcessDumpTest008
412  * @tc.desc: test SIGBUS crash
413  * @tc.type: FUNC
414  */
415 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest008, TestSize.Level2)
416 {
417     GTEST_LOG_(INFO) << "DfxProcessDumpTest008: start.";
418     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
419     kill(testProcess, SIGBUS);
420     sleep(3); // 3 : wait 3s to generate cpp crash file
421     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGBUS);
422     ASSERT_TRUE(ret);
423     GTEST_LOG_(INFO) << "DfxProcessDumpTest008: end.";
424 }
425 
426 /**
427  * @tc.name: DfxProcessDumpTest009
428  * @tc.desc: test SIGFPE crash
429  * @tc.type: FUNC
430  */
431 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest009, TestSize.Level2)
432 {
433     GTEST_LOG_(INFO) << "DfxProcessDumpTest009: start.";
434     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
435     kill(testProcess, SIGFPE);
436     sleep(3); // 3 : wait 3s to generate cpp crash file
437     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGFPE);
438     ASSERT_TRUE(ret);
439     GTEST_LOG_(INFO) << "DfxProcessDumpTest009: end.";
440 }
441 
442 /**
443  * @tc.name: DfxProcessDumpTest010
444  * @tc.desc: test SIGSEGV crash
445  * @tc.type: FUNC
446  */
447 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest010, TestSize.Level2)
448 {
449     GTEST_LOG_(INFO) << "DfxProcessDumpTest010: start.";
450     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
451     kill(testProcess, SIGSEGV);
452     sleep(3); // 3 : wait 3s to generate cpp crash file
453     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGSEGV);
454     ASSERT_TRUE(ret);
455     GTEST_LOG_(INFO) << "DfxProcessDumpTest010: end.";
456 }
457 
458 /**
459  * @tc.name: DfxProcessDumpTest011
460  * @tc.desc: test SIGSTKFLT crash
461  * @tc.type: FUNC
462  */
463 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest011, TestSize.Level2)
464 {
465     GTEST_LOG_(INFO) << "DfxProcessDumpTest011: start.";
466     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
467     kill(testProcess, SIGSTKFLT);
468     sleep(3); // 3 : wait 3s to generate cpp crash file
469     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGSTKFLT);
470     ASSERT_TRUE(ret);
471     GTEST_LOG_(INFO) << "DfxProcessDumpTest011: end.";
472 }
473 
474 /**
475  * @tc.name: DfxProcessDumpTest012
476  * @tc.desc: test SIGSYS crash
477  * @tc.type: FUNC
478  */
479 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest012, TestSize.Level2)
480 {
481     GTEST_LOG_(INFO) << "DfxProcessDumpTest012: start.";
482     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
483     kill(testProcess, SIGSYS);
484     sleep(3); // 3 : wait 3s to generate cpp crash file
485     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGSYS);
486     ASSERT_TRUE(ret);
487     GTEST_LOG_(INFO) << "DfxProcessDumpTest012: end.";
488 }
489 
490 /**
491  * @tc.name: DfxProcessDumpTest013
492  * @tc.desc: test dumpcatcher -p [namespace application process]
493  * @tc.type: FUNC
494  */
495 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest013, TestSize.Level2)
496 {
497     GTEST_LOG_(INFO) << "DfxProcessDumpTest013: start.";
498     string testBundleName = "ohos.samples.clock";
499     string testAbiltyName = testBundleName + ".MainAbility";
500     int testPid = LaunchTestHap(testAbiltyName, testBundleName);
501     if (testPid == 0) {
502         GTEST_LOG_(ERROR) << "Failed to launch target hap.";
503         return;
504     }
505     ProcInfo procinfo;
506     GTEST_LOG_(INFO) << "ppid = " << GetProcStatusByPid(testPid, procinfo);
507     string testCommand = "dumpcatcher -p " + to_string(testPid);
508     string dumpRes = ProcessDumpCommands(testCommand);
509     GTEST_LOG_(INFO) << dumpRes;
510     int count = 0;
511     string log[] = {"Pid:", "Name:", "#00", "#01", "#02"};
512     log[0] = log[0] + to_string(testPid);
513     log[1] = log[1] + "ohos.samples.cl";
514     string::size_type idx;
515     int len = sizeof(log) / sizeof(log[0]);
516     for (int i = 0; i < len; i++) {
517         idx = dumpRes.find(log[i]);
518         if (idx != string::npos) {
519             GTEST_LOG_(INFO) << log[i];
520             count++;
521         }
522     }
523     ASSERT_EQ(count, len);
524     GTEST_LOG_(INFO) << "DfxProcessDumpTest013: end.";
525 }
526 
527 /**
528  * @tc.name: DfxProcessDumpTest014
529  * @tc.desc: test dumpcatcher -p -t [namespace application process]
530  * @tc.type: FUNC
531  */
532 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest014, TestSize.Level2)
533 {
534     GTEST_LOG_(INFO) << "DfxProcessDumpTest014: start.";
535     string testBundleName = "ohos.samples.clock";
536     string testAbiltyName = testBundleName + ".MainAbility";
537     int testPid = LaunchTestHap(testAbiltyName, testBundleName);
538     if (testPid == 0) {
539         GTEST_LOG_(ERROR) << "Failed to launch target hap.";
540         return;
541     }
542     string testCommand = "dumpcatcher -p " + to_string(testPid) + " -t " + to_string(testPid);
543     string dumpRes = ProcessDumpCommands(testCommand);
544     GTEST_LOG_(INFO) << dumpRes;
545     int count = 0;
546     string log[] = {"Pid:", "Name:", "#00", "#01", "#02"};
547     log[0] = log[0] + to_string(testPid);
548     log[1] = log[1] + "ohos.samples.cl";
549     string::size_type idx;
550     int len = sizeof(log) / sizeof(log[0]);
551     for (int i = 0; i < len; i++) {
552         idx = dumpRes.find(log[i]);
553         if (idx != string::npos) {
554             GTEST_LOG_(INFO) << log[i];
555             count++;
556         }
557     }
558     ASSERT_EQ(count, len);
559     kill(testPid, SIGKILL);
560     GTEST_LOG_(INFO) << "DfxProcessDumpTest014: end.";
561 }
562