• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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