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