• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 "utilities.h"
17 
18 #include <sys/utsname.h>
19 #include <zlib.h>
20 #include <thread>
21 #if defined(CONFIG_HAS_SYSPARA) && defined(is_ohos) && is_ohos
22 #include <parameters.h>
23 #endif
24 #if defined(is_mingw) && is_mingw
25 #include <io.h>
26 #endif
27 
28 #ifdef CONFIG_HAS_CCM
29 #include "config_policy_utils.h"
30 #endif
31 #include "directory_ex.h"
32 #include "hiperf_hilog.h"
33 #include "ipc_utilities.h"
34 
35 using namespace std::chrono;
36 namespace OHOS {
37 namespace Developtools {
38 namespace HiPerf {
39 
40 static const std::string USER_DOMESTIC_BETA = "beta";
41 static const std::string USER_TYPE_PARAM = "const.logsystem.versiontype";
42 static const std::string USER_TYPE_PARAM_GET = "";
43 static const std::string HIVIEW_CMDLINE = "/system/bin/hiview";
44 
CanonicalizeSpecPath(const char * src)45 std::string CanonicalizeSpecPath(const char* src)
46 {
47     if (src == nullptr) {
48         HLOGE("Error: CanonicalizeSpecPath failed");
49         return "";
50     } else if (strlen(src) + 1 >= PATH_MAX) {
51         HLOGE("Error: CanonicalizeSpecPath %s failed", src);
52         return "";
53     }
54     char resolvedPath[PATH_MAX] = { 0 };
55 #if defined(_WIN32)
56     if (!_fullpath(resolvedPath, src, PATH_MAX)) {
57         HLOGE("Error: _fullpath %s failed", src);
58         return "";
59     }
60 #else
61     if (access(src, F_OK) == 0) {
62         if (strstr(src, "/proc/") == src && strstr(src, "/data/storage") != nullptr) { // for sandbox
63             if (strncpy_s(resolvedPath, sizeof(resolvedPath), src, strlen(src)) == -1) {
64                 HLOGE("Error: strncpy_s %s failed", src);
65                 return "";
66             }
67         } else if (realpath(src, resolvedPath) == nullptr) {
68             HLOGE("Error: realpath %s failed", src);
69             return "";
70         }
71     } else {
72         std::string fileName(src);
73         if (fileName.find("..") == std::string::npos) {
74             if (sprintf_s(resolvedPath, PATH_MAX, "%s", src) == -1) {
75                 HLOGE("Error: sprintf_s %s failed", src);
76                 return "";
77             }
78         } else {
79             HLOGE("Error: find .. %s failed", src);
80             return "";
81         }
82     }
83 #endif
84     std::string res(resolvedPath);
85     return res;
86 }
87 
RoundUp(const uint32_t x,const int align)88 uint32_t RoundUp(const uint32_t x, const int align)
89 {
90     return (((x) + (align) >= 1 ? (x) + (align) - 1 : 0) / (align)) * (align);
91 }
92 
StringReplace(std::string source,const std::string & from,const std::string & to)93 std::string StringReplace(std::string source, const std::string &from, const std::string &to)
94 {
95     size_t pos = 0;
96     std::string result;
97     // find
98     while ((pos = source.find(from)) != std::string::npos) {
99         // replace
100         result.append(source.substr(0, pos) + to);
101         source.erase(0, pos + from.length());
102     }
103     // add last token
104     result.append(source);
105     return result;
106 }
107 
SubStringCount(const std::string & source,const std::string & sub)108 size_t SubStringCount(const std::string &source, const std::string &sub)
109 {
110     size_t count(0);
111     size_t pos(0);
112     if (sub.empty()) {
113         return source.size();
114     }
115     while ((pos = source.find(sub, pos)) != std::string::npos) {
116         pos += sub.size();
117         count++;
118     }
119     return count;
120 }
121 
StringSplit(std::string source,const std::string & split)122 std::vector<std::string> StringSplit(std::string source, const std::string &split)
123 {
124     std::vector<std::string> result;
125 
126     // find
127     if (!split.empty()) {
128         size_t pos = 0;
129         while ((pos = source.find(split)) != std::string::npos) {
130             // split
131             std::string token = source.substr(0, pos);
132             if (!token.empty()) {
133                 result.push_back(token);
134             }
135             source.erase(0, pos + split.length());
136         }
137     }
138     // add last token
139     if (!source.empty()) {
140         result.push_back(source);
141     }
142     return result;
143 }
StdoutRecord(const std::string & tempFile,const std::string & mode)144 StdoutRecord::StdoutRecord(const std::string &tempFile, const std::string &mode)
145 {
146     if (!tempFile.empty()) {
147         std::string resolvedPath = CanonicalizeSpecPath(tempFile.c_str());
148         recordFile_ = fopen(resolvedPath.c_str(), mode.c_str());
149         if (recordFile_ == nullptr) {
150             HLOGE("tmpfile create failed '%s' with mode '%s'", tempFile.c_str(), mode.c_str());
151         } else {
152             // auto start it
153             Start();
154         }
155     }
156 }
Start()157 bool StdoutRecord::Start()
158 {
159     content_ = EMPTY_STRING;
160     fflush(stdout);
161 
162     // we will save output here
163     if (recordFile_ == nullptr) {
164         recordFile_ = std::tmpfile();
165     }
166     if (recordFile_ == nullptr) {
167         // try second way
168         std::string fileName = "/data/local/tmp/temp.stdout";
169         std::string resolvedPath = CanonicalizeSpecPath(fileName.c_str());
170         recordFile_ = fopen(resolvedPath.c_str(), "w+");
171         if (recordFile_ == nullptr) {
172             HLOGF("tmpfile create failed '%s'", fileName.c_str());
173             return false;
174         }
175     }
176 
177     // we save the stdout
178     stdoutFile_ = OHOS::UniqueFd(dup(STDOUT_FILENO));
179     CHECK_TRUE(stdoutFile_ != -1, false, 1, "std dup failed");
180 
181     // setup temp file as stdout
182     if (dup2(fileno(recordFile_), STDOUT_FILENO) != -1) {
183         stop_ = false;
184         return true;
185     } else {
186         HLOGF("std dup2 failed");
187         return false;
188     }
189 }
190 
Stop()191 std::string StdoutRecord::Stop()
192 {
193     if (stop_) {
194         return content_;
195     }
196     fflush(stdout);
197     // restore fd
198     dup2(stdoutFile_, STDOUT_FILENO);
199 
200     // return file content
201     if (recordFile_ != nullptr) {
202         const long fileLength = lseek(fileno(recordFile_), 0, SEEK_END);
203         content_.resize(fileLength);
204         lseek(fileno(recordFile_), 0, SEEK_SET);
205         const long len = read(fileno(recordFile_), content_.data(), fileLength);
206         std::fclose(recordFile_);
207         recordFile_ = nullptr;
208         if (len < 0) {
209             HLOGE("tmp file read failed (try read %ld)", fileLength);
210         } else if (len < fileLength) {
211             HLOGE("not all the data is read, lost %ld/%ld bytes", fileLength - len, fileLength);
212         }
213     } else {
214         HLOGE("recordFile_ is nullptr");
215     }
216     stop_ = true;
217     return content_;
218 }
219 
IsDigits(const std::string & str)220 bool IsDigits(const std::string &str)
221 {
222     if (str.empty()) {
223         return false;
224     } else {
225         return std::all_of(str.begin(), str.end(), ::isdigit);
226     }
227 }
228 
IsHexDigits(const std::string & str)229 bool IsHexDigits(const std::string &str)
230 {
231     if (str.empty()) {
232         return false;
233     }
234     const std::string prefix {"0x"};
235     std::string effectStr {str};
236     if (prefix.compare(0, prefix.size(), effectStr.substr(0, prefix.size())) == 0) {
237         effectStr = effectStr.substr(prefix.size(), effectStr.size() - prefix.size());
238     }
239     CHECK_TRUE(!effectStr.empty(), false, 0, "");
240     std::size_t start {0};
241     for (; start < effectStr.size(); ++start) {
242         if (effectStr[start] == '0') {
243             continue;
244         }
245         break;
246     }
247     if (start == effectStr.size()) {
248         effectStr = "0";
249     }
250     return std::all_of(effectStr.begin(), effectStr.end(), ::isxdigit);
251 }
252 
IsDir(const std::string & path)253 bool IsDir(const std::string &path)
254 {
255     struct stat st;
256     if (stat(path.c_str(), &st) == 0) {
257         return S_ISDIR(st.st_mode);
258     }
259     return false;
260 }
261 
IsPath(const std::string & fileName)262 bool IsPath(const std::string &fileName)
263 {
264     HLOG_ASSERT(!fileName.empty());
265     if (fileName[0] == PATH_SEPARATOR) {
266         return true;
267     }
268     const int prefixPathLen = 2;
269     if (fileName.substr(0, prefixPathLen) == "./") {
270         return true;
271     }
272     return false;
273 }
274 
PlatformPathConvert(const std::string & path)275 std::string PlatformPathConvert(const std::string &path)
276 {
277 #if defined(is_mingw) && is_mingw
278     return StringReplace(path, "/", "\\");
279 #else
280     return path;
281 #endif
282 }
283 
ReadFileToString(const std::string & fileName)284 std::string ReadFileToString(const std::string &fileName)
285 {
286     std::string resolvedPath = CanonicalizeSpecPath(fileName.c_str());
287     std::ifstream inputString(resolvedPath, std::ios::in);
288     if (!inputString || !inputString.is_open()) {
289         return EMPTY_STRING;
290     }
291     std::istreambuf_iterator<char> firstIt = {inputString};
292     std::istreambuf_iterator<char> lastIt = {};
293 
294     std::string content(firstIt, lastIt);
295     return content;
296 }
297 
ReadFileToString(const std::string & fileName,std::string & fileData,const size_t fileSize)298 bool ReadFileToString(const std::string &fileName, std::string &fileData, const size_t fileSize)
299 {
300     fileData.clear();
301     std::string resolvedPath = CanonicalizeSpecPath(fileName.c_str());
302     OHOS::UniqueFd fd(open(resolvedPath.c_str(), O_RDONLY | O_BINARY));
303     if (fileSize == 0) {
304         struct stat fileStat;
305         if (fstat(fd.Get(), &fileStat) != -1 && fileStat.st_size > 0) {
306             fileData.reserve(fileStat.st_size);
307         }
308     } else {
309         fileData.reserve(fileSize);
310     }
311 
312     char buf[BUFSIZ] __attribute__((__uninitialized__));
313     ssize_t readSize;
314     while ((readSize = read(fd.Get(), &buf[0], sizeof(buf))) > 0) {
315         fileData.append(buf, readSize);
316     }
317     return (readSize == 0) ? true : false;
318 }
319 
WriteStringToFile(const std::string & fileName,const std::string & value)320 bool WriteStringToFile(const std::string &fileName, const std::string &value)
321 {
322     std::string resolvedPath = CanonicalizeSpecPath(fileName.c_str());
323     std::ofstream output(resolvedPath, std::ios::out);
324     if (!output) {
325         return false;
326     }
327     output << value;
328 
329     return output.good();
330 }
331 
IsRoot()332 bool IsRoot()
333 {
334 #if defined(is_ohos) && is_ohos
335     std::string debugMode = "0";
336     debugMode = OHOS::system::GetParameter("const.debuggable", debugMode);
337     return debugMode == "1";
338 #else
339     return true;
340 #endif
341 }
342 
PowerOfTwo(const uint64_t n)343 bool PowerOfTwo(const uint64_t n)
344 {
345     return n && (!(n & (n - 1)));
346 }
347 
IscontainDigits(const std::string & str)348 bool IscontainDigits(const std::string& str)
349 {
350     for (char c : str) {
351         if (std::isdigit(static_cast<unsigned char>(c))) {
352             return true;
353         }
354     }
355     HLOGE("not contain [0-9], str: %s", str.c_str());
356     return false;
357 }
358 
IsStringToIntSuccess(const std::string & str,int & val)359 bool IsStringToIntSuccess(const std::string &str, int &val)
360 {
361     char *endPtr = nullptr;
362     errno = 0;
363     long num = 0;
364     num = std::strtol(str.c_str(), &endPtr, 10); // 10 : decimal scale
365     if (endPtr == str.c_str() || *endPtr != '\0' || errno != 0 || num > INT_MAX || num < INT_MIN) {
366         HLOGE("get int failed, str: %s", str.c_str());
367         return false;
368     }
369     val = static_cast<int>(num);
370     return true;
371 }
372 
StringToUint64(const std::string & str,uint64_t & val)373 bool StringToUint64(const std::string &str, uint64_t &val)
374 {
375     char *endPtr = nullptr;
376     errno = 0;
377     uint64_t num = std::strtoull(str.c_str(), &endPtr, 10); // 10 : decimal scale
378     if (endPtr == str.c_str() || *endPtr != '\0' || errno != 0 || num > ULLONG_MAX || str.c_str()[0] == '-') {
379         HIPERF_HILOGE(MODULE_DEFAULT, "get uint64 failed");
380         return false;
381     }
382     val = num;
383     return true;
384 }
385 
ReadIntFromProcFile(const std::string & path,int & value)386 bool ReadIntFromProcFile(const std::string &path, int &value)
387 {
388     std::string s = ReadFileToString(path);
389     CHECK_TRUE(!s.empty(), false, 0, "");
390     if (!IscontainDigits(s)) {
391         return false;
392     }
393     if (s.size() >= 2 && StringEndsWith(s, "\n")) { // 2: string size
394         s.resize(s.size() - 1);
395     }
396     if (!IsStringToIntSuccess(s, value)) {
397         return false;
398     }
399     return true;
400 }
401 
WriteIntToProcFile(const std::string & path,const int value)402 bool WriteIntToProcFile(const std::string &path, const int value)
403 {
404     std::string s = std::to_string(value);
405 
406     return WriteStringToFile(path, s);
407 }
408 
409 // compress specified dataFile into gzip file
CompressFile(const std::string & dataFile,const std::string & destFile)410 bool CompressFile(const std::string &dataFile, const std::string &destFile)
411 {
412     std::string resolvedPath = CanonicalizeSpecPath(dataFile.c_str());
413     FILE *fp = fopen(resolvedPath.c_str(), "rb");
414     if (fp == nullptr) {
415         HLOGE("Fail to open data file %s", dataFile.c_str());
416         perror("Fail to fopen(rb)");
417         return false;
418     }
419 
420     std::unique_ptr<gzFile_s, decltype(&gzclose)> fgz(gzopen(destFile.c_str(), "wb"), gzclose);
421     if (fgz == nullptr) {
422         HLOGE("Fail to call gzopen(%s)", destFile.c_str());
423         fclose(fp);
424         return false;
425     }
426 
427     std::vector<char> buf(COMPRESS_READ_BUF_SIZE);
428     size_t len = 0;
429     while ((len = fread(buf.data(), sizeof(uint8_t), buf.size(), fp))) {
430         if (gzwrite(fgz.get(), buf.data(), len) == 0) {
431             HLOGE("Fail to call gzwrite for %zu bytes", len);
432             fclose(fp);
433             return false;
434         }
435     }
436     if (!feof(fp)) {
437         if (ferror(fp) != 0) {
438             HLOGE("ferror return err");
439             fclose(fp);
440             return false;
441         }
442     }
443     if (fclose(fp) < 0) {
444         return false;
445     }
446     return true;
447 }
448 
449 // uncompress specified gzip file into dataFile
UncompressFile(const std::string & gzipFile,const std::string & dataFile)450 bool UncompressFile(const std::string &gzipFile, const std::string &dataFile)
451 {
452     std::string resolvedPath = CanonicalizeSpecPath(dataFile.c_str());
453     FILE *fp = fopen(resolvedPath.c_str(), "wb");
454     if (fp == nullptr) {
455         HLOGE("Fail to open data file %s", dataFile.c_str());
456         perror("Fail to fopen(rb)");
457         return false;
458     }
459     std::unique_ptr<gzFile_s, decltype(&gzclose)> fgz(gzopen(gzipFile.c_str(), "rb"), gzclose);
460     if (fgz == nullptr) {
461         HLOGE("Fail to call gzopen(%s)", gzipFile.c_str());
462         fclose(fp);
463         return false;
464     }
465 
466     std::vector<char> buf(COMPRESS_READ_BUF_SIZE);
467     z_size_t len = 0;
468     while ((len = gzfread(buf.data(), sizeof(uint8_t), buf.size(), fgz.get()))) {
469         if (len != fwrite(buf.data(), sizeof(uint8_t), len, fp)) {
470             HLOGE("Fail to call fwrite for %zu bytes", len);
471             fclose(fp);
472             return false;
473         }
474     }
475     if (!gzeof(fgz.get())) {
476         int rc = 0;
477         const char *err = gzerror(fgz.get(), &rc);
478         if (rc != Z_OK) {
479             HLOGE("gzfread return %d:%s", rc, err);
480             fclose(fp);
481             return false;
482         }
483     }
484     if (fclose(fp) < 0) {
485         return false;
486     }
487     return true;
488 }
489 
StringTrim(std::string & string)490 std::string &StringTrim(std::string &string)
491 {
492     if (!string.empty()) {
493         string.erase(0, string.find_first_not_of(" "));
494         string.erase(string.find_last_not_of(" ") + 1);
495     }
496     return string;
497 }
498 
GetEntriesInDir(const std::string & basePath)499 std::vector<std::string> GetEntriesInDir(const std::string &basePath)
500 {
501     std::vector<std::string> result;
502     std::string resolvedPath = CanonicalizeSpecPath(basePath.c_str());
503     CHECK_TRUE(!resolvedPath.empty(), result, 0, "");
504     DIR *dir = opendir(resolvedPath.c_str());
505     CHECK_TRUE(dir != nullptr, result, 0, "");
506     dirent *entry;
507     while ((entry = readdir(dir)) != nullptr) {
508         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
509             continue;
510         }
511         result.push_back(entry->d_name);
512     }
513     closedir(dir);
514     return result;
515 }
516 
GetSubDirs(const std::string & basePath)517 std::vector<std::string> GetSubDirs(const std::string &basePath)
518 {
519     std::vector<std::string> entries = GetEntriesInDir(basePath);
520     std::vector<std::string> result = {};
521     for (std::size_t index = 0; index < entries.size(); ++index) {
522         if (IsDir(basePath + "/" + entries[index])) {
523             result.push_back(std::move(entries[index]));
524         }
525     }
526     return result;
527 }
528 
IsSameCommand(const std::string & cmdLine,const std::string & cmdName)529 bool IsSameCommand(const std::string &cmdLine, const std::string &cmdName)
530 {
531     std::vector<std::string> cmdpaths = StringSplit(cmdLine, "/");
532     if (!cmdpaths.empty()) {
533         if (strcmp(cmdpaths.back().c_str(), cmdName.c_str()) == 0) {
534             return true;
535         }
536     }
537     return false;
538 }
539 
IsSameCommand(const std::string & cmdLine,const std::vector<std::string> & cmdNames)540 bool IsSameCommand(const std::string &cmdLine, const std::vector<std::string>& cmdNames)
541 {
542     std::vector<std::string> cmdpaths = StringSplit(cmdLine, "/");
543     if (cmdpaths.empty()) {
544         return false;
545     }
546 
547     for (const auto& cmdName : cmdNames) {
548         if (strcmp(cmdpaths.back().c_str(), cmdName.c_str()) == 0) {
549             return true;
550         }
551     }
552     return false;
553 }
554 
GetSubthreadIDs(const pid_t pid)555 std::vector<pid_t> GetSubthreadIDs(const pid_t pid)
556 {
557     std::string path {"/proc/"};
558     path += std::to_string(pid);
559     path += "/task/";
560     auto tids = GetSubDirs(path);
561     std::vector<pid_t> res {};
562     for (auto tidStr : tids) {
563         if (!tidStr.empty()) {
564             uint64_t dest = 0;
565             if (!StringToUint64(tidStr, dest)) {
566                 continue;
567             }
568             pid_t tid = static_cast<pid_t>(dest);
569             if (tid == pid) {
570                 continue;
571             }
572             res.push_back(tid);
573         }
574     }
575     return res;
576 }
577 
GetSubthreadIDs(const pid_t pid,std::map<pid_t,ThreadInfos> & thread_map)578 std::vector<pid_t> GetSubthreadIDs(const pid_t pid, std::map<pid_t, ThreadInfos> &thread_map)
579 {
580     std::string path {"/proc/"};
581     path += std::to_string(pid);
582     path += "/task/";
583     auto tids = GetSubDirs(path);
584     std::vector<pid_t> res{};
585     for (auto tidStr : tids) {
586         ThreadInfos info;
587         uint64_t dest = 0;
588         if (!StringToUint64(tidStr, dest)) {
589             continue;
590         }
591         pid_t tid = static_cast<pid_t>(dest);
592         info.tid = tid;
593         info.pid = pid;
594         thread_map[tid] = info;
595         res.push_back(tid);
596     }
597     return res;
598 }
599 
StringStartsWith(const std::string & string,const std::string & with)600 bool StringStartsWith(const std::string &string, const std::string &with)
601 {
602     return string.find(with) == 0;
603 }
604 
StringEndsWith(const std::string & string,const std::string & with)605 bool StringEndsWith(const std::string &string, const std::string &with)
606 {
607     if (string.empty()) {
608         // empty string only end with empty string
609         if (with.empty()) {
610             return true;
611         } else {
612             return false;
613         }
614     }
615     return string.rfind(with) == (string.length() - with.length());
616 }
617 
HexDump(const void * buf,const size_t size,const size_t maxSize)618 bool HexDump(const void *buf, const size_t size, const size_t maxSize)
619 {
620     CHECK_TRUE(buf != nullptr, false, 0, "");
621     const unsigned char *byteBuf = static_cast<const unsigned char *>(buf);
622     const size_t dumpByteEachLine = 8;
623     size_t outputBytes = 0;
624     if (!maxSize) {
625         outputBytes = size;
626     } else {
627         outputBytes = std::min(size, maxSize);
628     }
629 
630     for (size_t i = 0; i <= outputBytes; i += dumpByteEachLine) {
631         HLOGM(" %02zu: %s ", i, BufferToHexString(byteBuf, dumpByteEachLine).c_str());
632         byteBuf += dumpByteEachLine;
633     }
634     return true;
635 }
636 
BufferToHexString(const std::vector<unsigned char> & vec)637 std::string BufferToHexString(const std::vector<unsigned char> &vec)
638 {
639     return BufferToHexString(vec.data(), vec.size());
640 }
641 
BufferToHexString(const unsigned char buf[],const size_t size)642 std::string BufferToHexString(const unsigned char buf[], const size_t size)
643 {
644     std::stringstream ss;
645     ss << size << ":";
646     for (size_t i = 0; i < size; i++) {
647         ss << " 0x" << std::setfill('0') << std::setw(BYTE_PRINT_WIDTH) << std::hex
648            << (unsigned short)buf[i];
649     }
650     return ss.str();
651 }
652 
IsRestarted(const std::string & appPackage)653 bool IsRestarted(const std::string &appPackage)
654 {
655     printf("please restart %s for profiling within 30 seconds\n", appPackage.c_str());
656     std::set<pid_t> oldPids {};
657     std::set<pid_t> newPids {};
658     std::vector<pid_t> intersection;
659     const auto startTime = steady_clock::now();
660     const auto endTime = startTime + std::chrono::seconds(CHECK_TIMEOUT);
661     CollectPidsByAppname(oldPids, appPackage);
662     do {
663         CollectPidsByAppname(newPids, appPackage);
664         std::set_intersection(oldPids.begin(), oldPids.end(),
665             newPids.begin(), newPids.end(), std::back_insert_iterator(intersection));
666         // app names are same, no intersection, means app restarted
667         CHECK_TRUE(!intersection.empty(), true, 0, "");
668         intersection.clear();
669         newPids.clear();
670         std::this_thread::sleep_for(milliseconds(CHECK_FREQUENCY));
671     } while (steady_clock::now() < endTime);
672     printf("app %s was not stopped within 30 seconds\n", appPackage.c_str());
673     return false;
674 }
675 
GetAppPackagePid(const std::string & appPackage,const pid_t oldPid,const int checkAppMs,const uint64_t waitAppTimeOut)676 pid_t GetAppPackagePid(const std::string &appPackage, const pid_t oldPid, const int checkAppMs,
677                        const uint64_t waitAppTimeOut)
678 {
679     pid_t res {-1};
680     const std::string basePath {"/proc/"};
681     const std::string cmdline {"/cmdline"};
682     const auto startTime = steady_clock::now();
683     const auto endTime = startTime + std::chrono::seconds(waitAppTimeOut);
684     do {
685         std::vector<std::string> subDirs = GetSubDirs(basePath);
686         for (const auto &subDir : subDirs) {
687             if (!IsDigits(subDir)) {
688                 continue;
689             }
690             std::string fileName {basePath + subDir + cmdline};
691             if (IsSameCommand(ReadFileToString(fileName), appPackage)) {
692                 res = std::stoul(subDir, nullptr);
693                 HLOGD("[GetAppPackagePid]: get appid for %s is %d", appPackage.c_str(), res);
694                 return res;
695             }
696         }
697         std::this_thread::sleep_for(milliseconds(checkAppMs));
698     } while (steady_clock::now() < endTime);
699 
700     return res;
701 }
702 
CheckAppIsRunning(std::vector<pid_t> & selectPids,const std::string & appPackage,const int checkAppMs)703 bool CheckAppIsRunning(std::vector<pid_t> &selectPids, const std::string &appPackage, const int checkAppMs)
704 {
705     if (!appPackage.empty()) {
706         pid_t appPid = GetAppPackagePid(appPackage, -1, checkAppMs, waitAppRunCheckTimeOut);
707         if (appPid <= 0) {
708             printf("app %s not running\n", appPackage.c_str());
709             return false;
710         }
711         HLOGD("[CheckAppIsRunning] get appPid %d for app %s\n", appPid, appPackage.c_str());
712         selectPids.push_back(appPid);
713     }
714     return true;
715 }
716 
IsExistDebugByApp(const std::string & bundleName,std::string & err)717 bool IsExistDebugByApp(const std::string& bundleName, std::string& err)
718 {
719     std::string bundleNameTmp = bundleName;
720     auto pos = bundleNameTmp.find(":");
721     if (pos != std::string::npos) {
722         bundleNameTmp = bundleNameTmp.substr(0, pos);
723     }
724     if (!IsSupportNonDebuggableApp() && !bundleNameTmp.empty() && !IsDebugableApp(bundleNameTmp)) {
725         HLOGE("--app option only support debug application.");
726         err = "--app option only support debug application\n";
727         printf("%s", err.c_str());
728         return false;
729     }
730     return true;
731 }
732 
IsExistDebugByPid(const std::vector<pid_t> & pids,std::string & err)733 bool IsExistDebugByPid(const std::vector<pid_t> &pids, std::string& err)
734 {
735     CHECK_TRUE(!pids.empty(), true, 1, "IsExistDebugByPid: pids is empty.");
736     for (auto pid : pids) {
737         if (pid <= 0) {
738             err = "Invalid -p value '" + std::to_string(pid) + "', the pid should be larger than 0\n";
739             printf("%s", err.c_str());
740             return false;
741         }
742         std::string bundleName = GetProcessName(pid);
743         auto pos = bundleName.find(":");
744         if (pos != std::string::npos) {
745             bundleName = bundleName.substr(0, pos);
746         }
747         if (!IsSupportNonDebuggableApp() && !IsDebugableApp(bundleName)) {
748             HLOGE("-p option only support debug application for %s", bundleName.c_str());
749             err = "-p option only support debug application\n";
750             printf("%s", err.c_str());
751             return false;
752         }
753     }
754     return true;
755 }
756 
HandleAppInfo(const std::string & appPackage,const std::vector<pid_t> & inputPidTidArgs)757 std::string HandleAppInfo(const std::string& appPackage, const std::vector<pid_t> &inputPidTidArgs)
758 {
759     std::string err = "";
760     if (!appPackage.empty()) {
761         if (!IsExistDebugByApp(appPackage, err)) {
762             return err;
763         }
764     } else {
765         if (!IsExistDebugByPid(inputPidTidArgs, err)) {
766             return err;
767         }
768     }
769     return err;
770 }
771 
IsSupportNonDebuggableApp()772 bool IsSupportNonDebuggableApp()
773 {
774     // root first
775     if (IsRoot()) {
776         return true;
777     }
778     // user mode
779     if (!IsBeta()) {
780         HIPERF_HILOGE(MODULE_DEFAULT, "IsSupportNonDebuggableApp error, not beta");
781         return false;
782     }
783     if (!IsAllowProfilingUid()) {
784         HIPERF_HILOGE(MODULE_DEFAULT, "IsSupportNonDebuggableApp error, not allow profiling uid");
785         return false;
786     }
787     return true;
788 }
789 
GetUserType()790 const std::string GetUserType()
791 {
792 #if defined(is_ohos) && is_ohos
793     std::string userType = OHOS::system::GetParameter(USER_TYPE_PARAM, USER_TYPE_PARAM_GET);
794     HLOGD("GetUserType: userType is %s", userType.c_str());
795     return userType;
796 #else
797     return "";
798 #endif
799 }
800 
GetDeveloperMode()801 bool GetDeveloperMode()
802 {
803 #if defined(is_ohos) && is_ohos
804     bool developerMode = OHOS::system::GetBoolParameter("const.security.developermode.state", false);
805     HLOGD("GetDeveloperMode: developerMode is %d", developerMode);
806     return developerMode;
807 #else
808     return true;
809 #endif
810 }
811 
LittleMemory()812 bool LittleMemory()
813 {
814     std::ifstream file("/proc/meminfo");
815     std::string line;
816     while (getline(file, line)) {
817         if (line.find("MemTotal:") != std::string::npos) {
818             int memSize = stoi(line.substr(line.find(":") + 1));
819             CHECK_TRUE(memSize >= (LITTLE_MEMORY_SIZE * MULTIPLE_SIZE * MULTIPLE_SIZE), true, 0, "");
820         }
821     }
822     return false;
823 }
824 
825 // only for domestic beta
IsBeta()826 bool IsBeta()
827 {
828     std::string userTypeRsp = GetUserType();
829     if (userTypeRsp == USER_DOMESTIC_BETA) {
830         return true;
831     }
832     // default release when usertype param is invalid
833     CHECK_TRUE(!userTypeRsp.empty(), true, 1, "GetUserType is empty [%s]", userTypeRsp.c_str());
834     return false;
835 }
836 
IsHM()837 bool IsHM()
838 {
839     utsname unameBuf;
840     bool isHM = false;
841     if ((uname(&unameBuf)) == 0) {
842         std::string osrelease = unameBuf.release;
843         isHM = osrelease.find(HMKERNEL) != std::string::npos;
844     }
845     return isHM;
846 }
847 
IsAllowProfilingUid()848 bool IsAllowProfilingUid()
849 {
850 #if (defined(is_linux) && is_linux) || (defined(is_ohos) && is_ohos)
851     static unsigned int curUid = getuid();
852     HLOGD("curUid is %d\n", curUid);
853     CHECK_TRUE(ALLOW_UIDS.find(curUid) == ALLOW_UIDS.end(), true, 0, "");
854     return false;
855 #else
856     return false;
857 #endif
858 }
859 
GetProcessName(const int pid)860 std::string GetProcessName(const int pid)
861 {
862 #if defined(is_ohos) && is_ohos
863     std::string filePath = "/proc/" + std::to_string(pid) + "/cmdline";
864     std::string bundleName = ReadFileToString(filePath);
865     return bundleName.substr(0, strlen(bundleName.c_str()));
866 #else
867     return "";
868 #endif
869 }
870 
NeedAdaptSandboxPath(char * filename,const int pid,u16 & headerSize)871 bool NeedAdaptSandboxPath(char *filename, const int pid, u16 &headerSize)
872 {
873     std::string oldFilename = filename;
874     if (oldFilename.find("/data/storage") == 0 && access(oldFilename.c_str(), F_OK) != 0) {
875         std::string newFilename = "/proc/" + std::to_string(pid) + "/root" + oldFilename;
876         if (memset_s(filename, KILO, '\0', KILO) != EOK) {
877             HLOGD("memset_s filename failed!");
878             return false;
879         }
880         if (strncpy_s(filename, KILO, newFilename.c_str(), newFilename.size()) != 0) {
881             HLOGD("strncpy_s recordMmap2 failed!");
882             return false;
883         }
884         headerSize += newFilename.size() - oldFilename.size();
885         return true;
886     }
887     return false;
888 }
889 
NeedAdaptHMBundlePath(std::string & filename,const std::string & threadname)890 bool NeedAdaptHMBundlePath(std::string& filename, const std::string& threadname)
891 {
892     static bool needCheck = true;
893     if (!needCheck) {
894         return false;
895     }
896     const std::string path = "/data/storage/el1/bundle";
897     std::string newFileName = filename;
898     size_t pos = newFileName.find(path);
899     if (pos != std::string::npos) {
900         if (access(filename.c_str(), F_OK) != 0) {
901             const std::string newpath = "/data/app/el1/bundle/public/";
902             // /data/storage/el1/bundle/libs/arm64/libentry.so
903             newFileName.replace(pos, path.length(), newpath + threadname);
904             if (access(newFileName.c_str(), F_OK) != 0) {
905                 return false;
906             }
907             // /data/app/el1/bundle/public/<procname>/libs/arm64/libentry.so
908             filename = newFileName;
909             HLOGD("Fix hm bundle path to %s", filename.c_str());
910             return true;
911         } else {
912             needCheck = false;
913         }
914     }
915     return false;
916 }
917 
IsArkJsFile(const std::string & filepath)918 bool IsArkJsFile(const std::string& filepath)
919 {
920     return (StringEndsWith(filepath, ".hap") ||
921             StringStartsWith(filepath, "[anon:ArkTS Code") ||
922             StringEndsWith(filepath, ".hsp") ||
923             StringEndsWith(filepath, ".abc") ||
924             StringEndsWith(filepath, ".hqf"));
925 }
926 
IsV8File(const std::string & filepath)927 bool IsV8File(const std::string& filepath)
928 {
929     return (StringStartsWith(filepath, "[anon:JSVM_JIT") ||
930             StringStartsWith(filepath, "[anon:ARKWEB_JIT") ||
931             StringStartsWith(filepath, "[anon:v8"));
932 }
933 
IsHiviewCall()934 bool IsHiviewCall()
935 {
936 #if defined(is_ohos) && is_ohos
937     pid_t ppid = syscall(SYS_getppid);
938     std::string cmdline = GetProcessName(ppid);
939     HLOGD("getppid is %d, cmdline is %s", ppid, cmdline.c_str());
940     if (cmdline == HIVIEW_CMDLINE) {
941         HLOGD("hiview call");
942         return true;
943     }
944     return false;
945 #else
946     return false;
947 #endif
948 }
949 
IsNumeric(const std::string & str)950 bool IsNumeric(const std::string& str)
951 {
952     std::istringstream iss(str);
953     int number;
954     char trailingCharacter;
955     if (!(iss >> number)) {
956         return false;
957     }
958     if (iss >> trailingCharacter) {
959         return false;
960     }
961     return true;
962 }
963 
964 #ifdef CONFIG_HAS_CCM
GetProductCfgRoot(const char * cfgPath)965 cJSON* GetProductCfgRoot(const char* cfgPath)
966 {
967     char buf[PATH_MAX] = {0};
968     char* configFilePath = GetOneCfgFile(cfgPath, buf, PATH_MAX);
969     if (configFilePath == nullptr || (configFilePath[0] == '\0') || (strlen(configFilePath) > PATH_MAX)) {
970         HLOGD("get configFilePath from cfgPath %s failed", cfgPath);
971         return nullptr;
972     }
973     HLOGD("get configFilePath %s from cfgPath %s", configFilePath, cfgPath);
974     return ParseJson(configFilePath);
975 }
976 
ParseJson(const std::string & filePath)977 cJSON* ParseJson(const std::string &filePath)
978 {
979     std::string resolvedPath = CanonicalizeSpecPath(filePath.c_str());
980     std::ifstream inFile(resolvedPath, std::ios::in);
981     if (!inFile.is_open()) {
982         HLOGE("open file %s failed", filePath.c_str());
983         return nullptr;
984     }
985     std::string fileContent((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
986     cJSON* root = cJSON_Parse(fileContent.c_str());
987     inFile.close();
988     return root;
989 }
990 
GetJsonNum(cJSON * tag,const char * key,size_t & value)991 bool GetJsonNum(cJSON* tag, const char* key, size_t &value)
992 {
993     cJSON* subNode = cJSON_GetObjectItem(tag, key);
994     if (subNode != nullptr && cJSON_IsNumber(subNode)) {
995         value = static_cast<size_t>(subNode->valuedouble);
996         return true;
997     }
998     HLOGE("GetJsonNum key %s failed", key);
999     return false;
1000 }
1001 
GetCfgValue(const char * cfgPath,const char * cfgKey,size_t & value)1002 bool GetCfgValue(const char* cfgPath, const char* cfgKey, size_t &value)
1003 {
1004     bool ret = false;
1005     cJSON* root = GetProductCfgRoot(cfgPath);
1006     if (root == nullptr) {
1007         HLOGD("GetProductCfgRoot file %s failed", cfgPath);
1008         return ret;
1009     }
1010     if (GetJsonNum(root, cfgKey, value)) {
1011         ret = true;
1012         HLOGD("GetCfgValue %s: %zu", cfgKey, value);
1013     }
1014     cJSON_Delete(root);
1015     return ret;
1016 }
1017 #endif
1018 
IsDirectoryExists(const std::string & fileName)1019 bool IsDirectoryExists(const std::string& fileName)
1020 {
1021     struct stat fileInfo;
1022     if (stat(fileName.c_str(), &fileInfo) == 0) {
1023         return S_ISDIR(fileInfo.st_mode);
1024     }
1025     return false;
1026 }
1027 
CreateDirectory(const std::string & path,const mode_t mode)1028 bool CreateDirectory(const std::string& path, const mode_t mode)
1029 {
1030 #if defined(is_ohos) && is_ohos
1031     std::string::size_type pos = 0;
1032     do {
1033         pos = path.find('/', pos + 1);
1034         std::string subPath = (pos == std::string::npos) ? path : path.substr(0, pos);
1035         if (access(subPath.c_str(), F_OK) != 0) {
1036             if (mkdir(subPath.c_str(), mode) != 0) {
1037                 return false;
1038             }
1039         }
1040     } while (pos != std::string::npos);
1041     return access(path.c_str(), F_OK) == 0;
1042 #else
1043     return false;
1044 #endif
1045 }
1046 
IsValidOutPath(const std::string & path)1047 bool IsValidOutPath(const std::string& path)
1048 {
1049     std::vector<std::string> fileName = {"/data/log/hiperflog/", "data/log/hiperflog/"};
1050     for (auto name : fileName) {
1051         if (StringStartsWith(path, name)) {
1052             return false;
1053         }
1054     }
1055     return true;
1056 }
1057 
AgeHiperflogFiles()1058 void AgeHiperflogFiles()
1059 {
1060 #if defined(is_ohos) && is_ohos
1061     std::vector<std::string> allFiles;
1062     OHOS::GetDirFiles("/data/log/hiperflog/", allFiles);
1063     std::set<std::string> fileNames = {"/data/log/hiperflog/[shmm]", "/data/log/hiperflog/[vdso]",
1064                                        "/data/log/hiperflog/.hiperf_record_control_c2s",
1065                                        "/data/log/hiperflog/.hiperf_record_control_s2c",
1066                                        "/data/log/hiperflog/.hiperf_stat_control_c2s",
1067                                        "/data/log/hiperflog/.hiperf_stat_control_s2c"};
1068     for (std::string file : allFiles) {
1069         if (fileNames.count(file)) {
1070             HLOGD("the file is %s,not need to delete", file.c_str());
1071             continue;
1072         }
1073         if (!OHOS::RemoveFile(file)) {
1074             HIPERF_HILOGI(MODULE_DEFAULT, "remove hiperflog file : %{public}s failed", file.c_str());
1075             continue;
1076         }
1077         HIPERF_HILOGI(MODULE_DEFAULT, "remove hiperflog file : %{public}s", file.c_str());
1078     }
1079 #endif
1080 }
1081 } // namespace HiPerf
1082 } // namespace Developtools
1083 } // namespace OHOS
1084