• 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     readStream.open(filename.c_str(), ios::in);
86     if (readStream.fail()) {
87         return 0;
88     } else {
89         int n = 0;
90         string tempData;
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(const string & applyName)184 static int GetProcessPid(const 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 string & serviceName)204 static int GetServicePid(const string& serviceName)
205 {
206     string cmd = "pidof " + serviceName;
207     string pidStr = GetCmdResultFromPopen(cmd);
208     int32_t pid = 0;
209     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 string & cmds)215 static string ProcessDumpCommands(const string& cmds)
216 {
217     GTEST_LOG_(INFO) << "threadCMD = " << cmds;
218     FILE *procFileInfo = nullptr;
219     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     GTEST_LOG_(INFO) << "DfxProcessDumpTest004: end.";
359 }
360 
361 /**
362  * @tc.name: DfxProcessDumpTest005
363  * @tc.desc: test SIGILL crash
364  * @tc.type: FUNC
365  */
366 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest005, TestSize.Level2)
367 {
368     GTEST_LOG_(INFO) << "DfxProcessDumpTest005: start.";
369     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
370     sleep(1);
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     sleep(1);
388     kill(testProcess, SIGTRAP);
389     sleep(3); // 3 : wait 3s to generate cpp crash file
390     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGTRAP);
391     ASSERT_TRUE(ret);
392     GTEST_LOG_(INFO) << "DfxProcessDumpTest006: end.";
393 }
394 
395 /**
396  * @tc.name: DfxProcessDumpTest007
397  * @tc.desc: test SIGABRT crash
398  * @tc.type: FUNC
399  */
400 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest007, TestSize.Level2)
401 {
402     GTEST_LOG_(INFO) << "DfxProcessDumpTest007: start.";
403     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
404     sleep(1);
405     kill(testProcess, SIGABRT);
406     sleep(3); // 3 : wait 3s to generate cpp crash file
407     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGABRT);
408     ASSERT_TRUE(ret);
409     GTEST_LOG_(INFO) << "DfxProcessDumpTest007: end.";
410 }
411 
412 /**
413  * @tc.name: DfxProcessDumpTest008
414  * @tc.desc: test SIGBUS crash
415  * @tc.type: FUNC
416  */
417 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest008, TestSize.Level2)
418 {
419     GTEST_LOG_(INFO) << "DfxProcessDumpTest008: start.";
420     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
421     sleep(1);
422     kill(testProcess, SIGBUS);
423     sleep(3); // 3 : wait 3s to generate cpp crash file
424     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGBUS);
425     ASSERT_TRUE(ret);
426     GTEST_LOG_(INFO) << "DfxProcessDumpTest008: end.";
427 }
428 
429 /**
430  * @tc.name: DfxProcessDumpTest009
431  * @tc.desc: test SIGFPE crash
432  * @tc.type: FUNC
433  */
434 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest009, TestSize.Level2)
435 {
436     GTEST_LOG_(INFO) << "DfxProcessDumpTest009: start.";
437     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
438     sleep(1);
439     kill(testProcess, SIGFPE);
440     sleep(3); // 3 : wait 3s to generate cpp crash file
441     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGFPE);
442     ASSERT_TRUE(ret);
443     GTEST_LOG_(INFO) << "DfxProcessDumpTest009: end.";
444 }
445 
446 /**
447  * @tc.name: DfxProcessDumpTest010
448  * @tc.desc: test SIGSEGV crash
449  * @tc.type: FUNC
450  */
451 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest010, TestSize.Level2)
452 {
453     GTEST_LOG_(INFO) << "DfxProcessDumpTest010: start.";
454     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
455     sleep(1);
456     kill(testProcess, SIGSEGV);
457     sleep(3); // 3 : wait 3s to generate cpp crash file
458     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGSEGV);
459     ASSERT_TRUE(ret);
460     GTEST_LOG_(INFO) << "DfxProcessDumpTest010: end.";
461 }
462 
463 /**
464  * @tc.name: DfxProcessDumpTest011
465  * @tc.desc: test SIGSTKFLT crash
466  * @tc.type: FUNC
467  */
468 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest011, TestSize.Level2)
469 {
470     GTEST_LOG_(INFO) << "DfxProcessDumpTest011: start.";
471     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
472     sleep(1);
473     kill(testProcess, SIGSTKFLT);
474     sleep(3); // 3 : wait 3s to generate cpp crash file
475     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGSTKFLT);
476     ASSERT_TRUE(ret);
477     GTEST_LOG_(INFO) << "DfxProcessDumpTest011: end.";
478 }
479 
480 /**
481  * @tc.name: DfxProcessDumpTest012
482  * @tc.desc: test SIGSYS crash
483  * @tc.type: FUNC
484  */
485 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest012, TestSize.Level2)
486 {
487     GTEST_LOG_(INFO) << "DfxProcessDumpTest012: start.";
488     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
489     sleep(1);
490     kill(testProcess, SIGSYS);
491     sleep(3); // 3 : wait 3s to generate cpp crash file
492     bool ret = CheckCppCrashKeyWords(GetCppCrashFileName(testProcess), testProcess, SIGSYS);
493     ASSERT_TRUE(ret);
494     GTEST_LOG_(INFO) << "DfxProcessDumpTest012: end.";
495 }
496 
497 /**
498  * @tc.name: DfxProcessDumpTest013
499  * @tc.desc: test dumpcatcher -p [namespace application process]
500  * @tc.type: FUNC
501  */
502 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest013, TestSize.Level2)
503 {
504     GTEST_LOG_(INFO) << "DfxProcessDumpTest013: start.";
505     string testBundleName = "ohos.samples.clock";
506     string testAbiltyName = testBundleName + ".MainAbility";
507     int testPid = LaunchTestHap(testAbiltyName, testBundleName);
508     if (testPid == 0) {
509         GTEST_LOG_(ERROR) << "Failed to launch target hap.";
510         return;
511     }
512     ProcInfo procinfo;
513     GTEST_LOG_(INFO) << "ppid = " << GetProcStatusByPid(testPid, procinfo);
514     string testCommand = "dumpcatcher -p " + to_string(testPid);
515     string dumpRes = ProcessDumpCommands(testCommand);
516     GTEST_LOG_(INFO) << dumpRes;
517     int count = 0;
518     string log[] = {"Pid:", "Name:", "#00", "#01", "#02"};
519     log[0] = log[0] + to_string(testPid);
520     log[1] = log[1] + "ohos.samples.cl";
521     string::size_type idx;
522     int len = sizeof(log) / sizeof(log[0]);
523     for (int i = 0; i < len; i++) {
524         idx = dumpRes.find(log[i]);
525         if (idx != string::npos) {
526             GTEST_LOG_(INFO) << log[i];
527             count++;
528         }
529     }
530     ASSERT_EQ(count, len);
531     GTEST_LOG_(INFO) << "DfxProcessDumpTest013: end.";
532 }
533 
534 /**
535  * @tc.name: DfxProcessDumpTest014
536  * @tc.desc: test dumpcatcher -p -t [namespace application process]
537  * @tc.type: FUNC
538  */
539 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest014, TestSize.Level2)
540 {
541     GTEST_LOG_(INFO) << "DfxProcessDumpTest014: start.";
542     string testBundleName = "ohos.samples.clock";
543     string testAbiltyName = testBundleName + ".MainAbility";
544     int testPid = LaunchTestHap(testAbiltyName, testBundleName);
545     if (testPid == 0) {
546         GTEST_LOG_(ERROR) << "Failed to launch target hap.";
547         return;
548     }
549     string testCommand = "dumpcatcher -p " + to_string(testPid) + " -t " + to_string(testPid);
550     string dumpRes = ProcessDumpCommands(testCommand);
551     GTEST_LOG_(INFO) << dumpRes;
552     int count = 0;
553     string log[] = {"Pid:", "Name:", "#00", "#01", "#02"};
554     log[0] = log[0] + to_string(testPid);
555     log[1] = log[1] + "ohos.samples.cl";
556     string::size_type idx;
557     int len = sizeof(log) / sizeof(log[0]);
558     for (int i = 0; i < len; i++) {
559         idx = dumpRes.find(log[i]);
560         if (idx != string::npos) {
561             GTEST_LOG_(INFO) << log[i];
562             count++;
563         }
564     }
565     ASSERT_EQ(count, len);
566     kill(testPid, SIGKILL);
567     GTEST_LOG_(INFO) << "DfxProcessDumpTest014: end.";
568 }
569