1 /*
2 * Copyright (c) 2023 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_test_util.h"
17
18 #include <fstream>
19 #include <iostream>
20 #include <sstream>
21 #include <unistd.h>
22
23 #include "dfx_define.h"
24 #include <directory_ex.h>
25 #include "file_util.h"
26 #include <string_ex.h>
27 #include <sys/inotify.h>
28
29 namespace OHOS {
30 namespace HiviewDFX {
31 namespace {
32 #define EVENT_SIZE (sizeof(struct inotify_event))
33 #define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
34 const int BUF_LEN = 128;
35 }
36
ExecuteCommands(const std::string & cmds)37 std::string ExecuteCommands(const std::string& cmds)
38 {
39 if (cmds.empty()) {
40 return "";
41 }
42 FILE *procFileInfo = nullptr;
43 std::string cmdLog = "";
44 procFileInfo = popen(cmds.c_str(), "r");
45 if (procFileInfo == nullptr) {
46 perror("popen execute failed\n");
47 return cmdLog;
48 }
49 char res[BUF_LEN] = { '\0' };
50 while (fgets(res, sizeof(res), procFileInfo) != nullptr) {
51 cmdLog += res;
52 }
53 pclose(procFileInfo);
54 return cmdLog;
55 }
56
ExecuteCommands(const std::string & cmds,std::vector<std::string> & ress)57 bool ExecuteCommands(const std::string& cmds, std::vector<std::string>& ress)
58 {
59 if (cmds.empty()) {
60 return false;
61 }
62
63 ress.clear();
64 FILE *fp = nullptr;
65 fp = popen(cmds.c_str(), "r");
66 if (fp == nullptr) {
67 perror("popen execute failed\n");
68 return false;
69 }
70
71 char res[BUF_LEN] = { '\0' };
72 while (fgets(res, sizeof(res), fp) != nullptr) {
73 ress.push_back(std::string(res));
74 }
75 pclose(fp);
76 return true;
77 }
78
GetProcessPid(const std::string & processName)79 int GetProcessPid(const std::string& processName)
80 {
81 std::string cmd = "pidof " + processName;
82 std::string pidStr = ExecuteCommands(cmd);
83 int32_t pid = 0;
84 std::stringstream pidStream(pidStr);
85 pidStream >> pid;
86 printf("the pid of process(%s) is %s \n", processName.c_str(), pidStr.c_str());
87 return pid;
88 }
89
LaunchTestHap(const std::string & abilityName,const std::string & bundleName)90 int LaunchTestHap(const std::string& abilityName, const std::string& bundleName)
91 {
92 std::string launchCmd = "/system/bin/aa start -a " + abilityName + " -b " + bundleName;
93 (void)ExecuteCommands(launchCmd);
94 sleep(2); // 2 : sleep 2s
95 return GetProcessPid(bundleName);
96 }
97
StopTestHap(const std::string & bundleName)98 void StopTestHap(const std::string& bundleName)
99 {
100 std::string stopCmd = "/system/bin/aa force-stop " + bundleName;
101 (void)ExecuteCommands(stopCmd);
102 }
103
InstallTestHap(const std::string & hapName)104 void InstallTestHap(const std::string& hapName)
105 {
106 std::string installCmd = "bm install -p " + hapName;
107 (void)ExecuteCommands(installCmd);
108 }
109
UninstallTestHap(const std::string & bundleName)110 void UninstallTestHap(const std::string& bundleName)
111 {
112 std::string uninstallCmd = "bm uninstall -n " + bundleName;
113 (void)ExecuteCommands(uninstallCmd);
114 }
115
CountLines(const std::string & fileName)116 int CountLines(const std::string& fileName)
117 {
118 std::ifstream readFile;
119 readFile.open(fileName.c_str(), std::ios::in);
120 if (readFile.fail()) {
121 return 0;
122 } else {
123 int n = 0;
124 std::string tmpuseValue;
125 while (getline(readFile, tmpuseValue, '\n')) {
126 n++;
127 }
128 readFile.close();
129 return n;
130 }
131 }
132
CheckProcessComm(int pid,const std::string & name)133 bool CheckProcessComm(int pid, const std::string& name)
134 {
135 std::string cmd = "cat /proc/" + std::to_string(pid) + "/comm";
136 std::string comm = ExecuteCommands(cmd);
137 size_t pos = comm.find('\n');
138 if (pos != std::string::npos) {
139 comm.erase(pos, 1);
140 }
141 if (!strcmp(comm.c_str(), name.c_str())) {
142 return true;
143 }
144 return false;
145 }
146
CheckKeyWords(const std::string & filePath,std::string * keywords,int length,int minRegIdx)147 int CheckKeyWords(const std::string& filePath, std::string *keywords, int length, int minRegIdx)
148 {
149 std::ifstream file;
150 file.open(filePath.c_str(), std::ios::in);
151 long lines = CountLines(filePath);
152 std::vector<std::string> t(lines * 4); // 4 : max string blocks of one line
153 int i = 0;
154 int j = 0;
155 std::string::size_type idx;
156 int count = 0;
157 int maxRegIdx = minRegIdx + REGISTERS_NUM + 1;
158 while (!file.eof()) {
159 file >> t.at(i);
160 idx = t.at(i).find(keywords[j]);
161 if (idx != std::string::npos) {
162 if (minRegIdx != -1 && j > minRegIdx && // -1 : do not check register value
163 j < maxRegIdx && t.at(i).size() < (REGISTER_FORMAT_LENGTH + 3)) { // 3 : register label length
164 count--;
165 }
166 count++;
167 j++;
168 if (j == length) {
169 break;
170 }
171 continue;
172 }
173 i++;
174 }
175 file.close();
176 std::cout << "Matched keywords count: " << count << std::endl;
177 if (j < length) {
178 std::cout << "Not found keyword: " << keywords[j] << std::endl;
179 }
180 return count;
181 }
182
CheckLineMatch(const std::string & filePath,std::list<LineRule> & rules)183 bool CheckLineMatch(const std::string& filePath, std::list<LineRule>& rules)
184 {
185 std::ifstream logFile(filePath);
186 if (!logFile.is_open()) {
187 return false;
188 }
189
190 std::string line;
191 while (std::getline(logFile, line)) {
192 if (!logFile.good()) {
193 break;
194 }
195
196 for (auto it = rules.begin(); it != rules.end(); /* no increment here */) {
197 if (!std::regex_match(line, it->lineReg)) {
198 ++it;
199 continue;
200 }
201
202 it->needMatchCnt -= 1;
203 if (it->needMatchCnt == 0) {
204 it = rules.erase(it);
205 }
206 break;
207 }
208
209 if (rules.empty()) {
210 break;
211 }
212 }
213 if (!rules.empty()) {
214 for (const auto& it : rules) {
215 std::cout << "not match rule: " << it.regString << std::endl;
216 }
217 return false;
218 }
219 return true;
220 }
221
CheckContent(const std::string & content,const std::string & keyContent,bool checkExist)222 bool CheckContent(const std::string& content, const std::string& keyContent, bool checkExist)
223 {
224 bool findKeyContent = false;
225 if (content.find(keyContent) != std::string::npos) {
226 findKeyContent = true;
227 }
228
229 if (checkExist && !findKeyContent) {
230 printf("Failed to find: %s in %s\n", keyContent.c_str(), content.c_str());
231 return false;
232 }
233
234 if (!checkExist && findKeyContent) {
235 printf("Find: %s in %s\n", keyContent.c_str(), content.c_str());
236 return false;
237 }
238 return true;
239 }
240
GetKeywordsNum(const std::string & msg,std::string * keywords,int length)241 int GetKeywordsNum(const std::string& msg, std::string *keywords, int length)
242 {
243 int count = 0;
244 std::string::size_type idx;
245 for (int i = 0; i < length; i++) {
246 idx = msg.find(keywords[i]);
247 if (idx != std::string::npos) {
248 count++;
249 }
250 }
251 return count;
252 }
253
GetKeywordCount(const std::string & msg,const std::string & keyword)254 int GetKeywordCount(const std::string& msg, const std::string& keyword)
255 {
256 int count = 0;
257 auto position = msg.find(keyword);
258 while (position != std::string::npos) {
259 ++count;
260 position = msg.find(keyword, position + 1);
261 }
262 return count;
263 }
264
GetDumpLogFileName(const std::string & prefix,const pid_t pid,const std::string & tempPath)265 std::string GetDumpLogFileName(const std::string& prefix, const pid_t pid, const std::string& tempPath)
266 {
267 std::string filePath = "";
268 if (pid <= 0) {
269 return filePath;
270 }
271 std::string fileNamePrefix = prefix + "-" + std::to_string(pid);
272 std::vector<std::string> files;
273 OHOS::GetDirFiles(tempPath, files);
274 for (const auto& file : files) {
275 if (file.find(fileNamePrefix) != std::string::npos) {
276 filePath = file;
277 break;
278 }
279 }
280 return filePath;
281 }
282
GetCppCrashFileName(const pid_t pid,const std::string & tempPath)283 std::string GetCppCrashFileName(const pid_t pid, const std::string& tempPath)
284 {
285 return GetDumpLogFileName("cppcrash", pid, tempPath);
286 }
287
GetSelfMemoryCount()288 uint64_t GetSelfMemoryCount()
289 {
290 std::string path = "/proc/self/smaps_rollup";
291 std::string content;
292 if (!OHOS::HiviewDFX::LoadStringFromFile(path, content)) {
293 printf("Failed to load path content: %s\n", path.c_str());
294 return 0;
295 }
296
297 std::vector<std::string> result;
298 OHOS::SplitStr(content, "\n", result);
299 auto iter = std::find_if(result.begin(), result.end(),
300 [] (const std::string& str) {
301 return str.find("Pss:") != std::string::npos;
302 });
303 if (iter == result.end()) {
304 perror("Failed to find Pss.\n");
305 return 0;
306 }
307
308 std::string pss = *iter;
309 uint64_t retVal = 0;
310 for (size_t i = 0; i < pss.size(); i++) {
311 if (isdigit(pss[i])) {
312 retVal = atoi(&pss[i]);
313 break;
314 }
315 }
316 return retVal;
317 }
318
GetSelfMapsCount()319 uint32_t GetSelfMapsCount()
320 {
321 std::string path = std::string(PROC_SELF_MAPS_PATH);
322 std::string content;
323 if (!OHOS::HiviewDFX::LoadStringFromFile(path, content)) {
324 printf("Failed to load path content: %s\n", path.c_str());
325 return 0;
326 }
327
328 std::vector<std::string> result;
329 OHOS::SplitStr(content, "\n", result);
330 return result.size();
331 }
332
GetSelfFdCount()333 uint32_t GetSelfFdCount()
334 {
335 std::string path = "/proc/self/fd";
336 std::vector<std::string> content;
337 OHOS::GetDirFiles(path, content);
338 return content.size();
339 }
340
CheckResourceUsage(uint32_t fdCount,uint32_t mapsCount,uint64_t memCount)341 void CheckResourceUsage(uint32_t fdCount, uint32_t mapsCount, uint64_t memCount)
342 {
343 // check memory/fd/maps
344 auto curFdCount = GetSelfFdCount();
345 printf("AfterTest Fd New: %u\n", curFdCount);
346 printf("Fd Old: %u\n", fdCount);
347
348 auto curMapsCount = GetSelfMapsCount();
349 printf("AfterTest Maps New: %u\n", curMapsCount);
350 printf("Maps Old: %u\n", mapsCount);
351
352 auto curMemSize = GetSelfMemoryCount();
353 printf("AfterTest Memory New: %lu\n", static_cast<unsigned long>(curMemSize));
354 printf("Memory Old: %lu\n", static_cast<unsigned long>(memCount));
355 }
356
WaitCreateCrashFile(const std::string & prefix,pid_t pid,int retryCnt)357 std::string WaitCreateCrashFile(const std::string& prefix, pid_t pid, int retryCnt)
358 {
359 std::string fileName;
360 int fd = inotify_init();
361 if (fd < 0) {
362 return fileName;
363 }
364 int wd = inotify_add_watch(fd, TEMP_DIR, IN_CLOSE_WRITE);
365 if (wd < 0) {
366 close(fd);
367 return fileName;
368 }
369 struct timeval timeoutVal;
370 timeoutVal.tv_sec = 1;
371 timeoutVal.tv_usec = 0;
372 fd_set rfds;
373 FD_ZERO(&rfds);
374 FD_SET(fd, &rfds);
375 std::string fileNamePrefix = prefix + "-" + std::to_string(pid);
376 while (retryCnt > 0) {
377 int ret = select(fd + 1, &rfds, nullptr, nullptr, &timeoutVal);
378 retryCnt--;
379 if (ret <= 0 || !FD_ISSET(fd, &rfds)) {
380 FD_SET(fd, &rfds);
381 continue;
382 }
383 char buffer[EVENT_BUF_LEN] = {0};
384 int length = read(fd, buffer, EVENT_BUF_LEN);
385 int eventCnt = 0;
386 while (length > 0 && eventCnt < length) {
387 struct inotify_event *event = reinterpret_cast<struct inotify_event*>(&buffer[eventCnt]);
388 if ((event->len) && (event->mask & IN_CLOSE_WRITE) &&
389 strncmp(event->name, fileNamePrefix.c_str(), strlen(fileNamePrefix.c_str())) == 0) {
390 fileName = TEMP_DIR;
391 fileName.append(event->name);
392 retryCnt = 0;
393 break;
394 }
395 eventCnt += EVENT_SIZE + event->len;
396 }
397 FD_SET(fd, &rfds);
398 }
399 inotify_rm_watch(fd, wd);
400 close(fd);
401 if (fileName.empty()) {
402 fileName = GetDumpLogFileName(prefix, pid, TEMP_DIR);
403 }
404 return fileName;
405 }
406
WaitCreateFile(const std::string & folder,std::regex & reg,time_t timeOut)407 std::string WaitCreateFile(const std::string& folder, std::regex& reg, time_t timeOut)
408 {
409 std::string fileName;
410 int fd = inotify_init();
411 if (fd < 0) {
412 return fileName;
413 }
414 int wd = inotify_add_watch(fd, folder.c_str(), IN_CLOSE_WRITE);
415 if (wd < 0) {
416 close(fd);
417 return fileName;
418 }
419 time_t end = time(nullptr) + timeOut;
420 struct timeval timeoutVal;
421 timeoutVal.tv_usec = 0;
422 fd_set rfds;
423 bool isRun = true;
424 while (isRun) {
425 FD_ZERO(&rfds);
426 FD_SET(fd, &rfds);
427 timeoutVal.tv_sec = end - time(nullptr);
428 int ret = select(fd + 1, &rfds, nullptr, nullptr, &timeoutVal);
429 if (ret <= 0 || !FD_ISSET(fd, &rfds)) {
430 continue;
431 }
432 char buffer[EVENT_BUF_LEN] = {0};
433 int length = read(fd, buffer, EVENT_BUF_LEN);
434 int eventCnt = 0;
435 while (length > 0 && eventCnt < length) {
436 struct inotify_event *event = reinterpret_cast<struct inotify_event*>(&buffer[eventCnt]);
437 if ((event->len) && (event->mask & IN_CLOSE_WRITE) && std::regex_match(event->name, reg)) {
438 fileName = folder;
439 fileName.append(event->name);
440 isRun = false;
441 break;
442 }
443 eventCnt += EVENT_SIZE + event->len;
444 }
445 }
446 inotify_rm_watch(fd, wd);
447 close(fd);
448 return fileName;
449 }
450
CreatePipeFd(int (& fd)[2])451 bool CreatePipeFd(int (&fd)[2])
452 {
453 if (pipe(fd) == -1) {
454 return false;
455 }
456 return true;
457 }
458
NotifyProcStart(int (& fd)[2])459 void NotifyProcStart(int (&fd)[2])
460 {
461 close(fd[0]);
462 write(fd[1], "a", 1);
463 close(fd[1]);
464 }
465
WaitProcStart(int (& fd)[2])466 void WaitProcStart(int (&fd)[2])
467 {
468 close(fd[1]);
469 const size_t size = 10;
470 char msg[size];
471 read(fd[0], msg, sizeof(msg));
472 close(fd[0]);
473 }
474
CheckAndExit(bool hasFailure)475 void CheckAndExit(bool hasFailure)
476 {
477 if (hasFailure) {
478 _exit(1);
479 }
480 _exit(0);
481 }
482
IsLinuxKernel()483 bool IsLinuxKernel()
484 {
485 static bool isLinux = [] {
486 std::string content;
487 LoadStringFromFile("/proc/version", content);
488 if (content.empty()) {
489 return true;
490 }
491 if (content.find("Linux") != std::string::npos) {
492 return true;
493 }
494 return false;
495 }();
496 return isLinux;
497 }
498 } // namespace HiviewDFX
499 } // namespace OHOS
500