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