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