• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "utilities.h"
16 #include <zlib.h>
17 #include <thread>
18 #if defined(CONFIG_HAS_SYSPARA) && defined(is_ohos) && is_ohos
19 #include <parameters.h>
20 #endif
21 #if defined(is_mingw) && is_mingw
22 #include <io.h>
23 #endif
24 #if defined(is_ohos) && is_ohos && defined(BUNDLE_FRAMEWORK_ENABLE)
25 #include "application_info.h"
26 #include "bundle_mgr_proxy.h"
27 #endif
28 #if defined(is_ohos) && is_ohos
29 #include "iservice_registry.h"
30 #include "system_ability_definition.h"
31 using namespace OHOS;
32 using namespace OHOS::AppExecFwk;
33 #endif
34 
35 using namespace std::chrono;
36 namespace OHOS {
37 namespace Developtools {
38 namespace HiPerf {
39 
CanonicalizeSpecPath(const char * src)40 std::string CanonicalizeSpecPath(const char* src)
41 {
42     if (src == nullptr) {
43         fprintf(stderr, "Error: CanonicalizeSpecPath failed");
44         return "";
45     } else if (strlen(src) >= PATH_MAX) {
46         fprintf(stderr, "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         fprintf(stderr, "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             (void)strncpy_s(resolvedPath, sizeof(resolvedPath), src, strlen(src));
59         } else if (realpath(src, resolvedPath) == nullptr) {
60             fprintf(stderr, "Error: realpath %s failed", src);
61             return "";
62         }
63     } else {
64         std::string fileName(src);
65         if (fileName.find("..") == std::string::npos) {
66             if (sprintf_s(resolvedPath, PATH_MAX, "%s", src) == -1) {
67                 fprintf(stderr, "Error: sprintf_s %s failed", src);
68                 return "";
69             }
70         } else {
71             fprintf(stderr, "Error: find .. %s failed", src);
72             return "";
73         }
74     }
75 #endif
76     std::string res(resolvedPath);
77     return res;
78 }
79 
RoundUp(uint32_t x,const int align)80 uint32_t RoundUp(uint32_t x, const int align)
81 {
82     return (((x) + (align) - 1) / (align)) * (align);
83 }
84 
StringReplace(std::string source,const std::string & from,const std::string & to)85 std::string StringReplace(std::string source, const std::string &from, const std::string &to)
86 {
87     size_t pos = 0;
88     std::string result;
89     // find
90     while ((pos = source.find(from)) != std::string::npos) {
91         // replace
92         result.append(source.substr(0, pos) + to);
93         source.erase(0, pos + from.length());
94     }
95     // add last token
96     result.append(source);
97     return result;
98 }
99 
SubStringCount(const std::string & source,const std::string & sub)100 size_t SubStringCount(const std::string &source, const std::string &sub)
101 {
102     size_t count(0);
103     size_t pos(0);
104     if (sub.empty()) {
105         return source.size();
106     }
107     while ((pos = source.find(sub, pos)) != std::string::npos) {
108         pos += sub.size();
109         count++;
110     }
111     return count;
112 }
113 
StringSplit(std::string source,const std::string split)114 std::vector<std::string> StringSplit(std::string source, const std::string split)
115 {
116     std::vector<std::string> result;
117 
118     // find
119     if (!split.empty()) {
120         size_t pos = 0;
121         while ((pos = source.find(split)) != std::string::npos) {
122             // split
123             std::string token = source.substr(0, pos);
124             if (!token.empty()) {
125                 result.push_back(token);
126             }
127             source.erase(0, pos + split.length());
128         }
129     }
130     // add last token
131     if (!source.empty()) {
132         result.push_back(source);
133     }
134     return result;
135 }
StdoutRecord(const std::string & tempFile,const std::string & mode)136 StdoutRecord::StdoutRecord(const std::string &tempFile, const std::string &mode)
137 {
138     if (!tempFile.empty()) {
139         std::string resolvedPath = CanonicalizeSpecPath(tempFile.c_str());
140         recordFile_ = fopen(resolvedPath.c_str(), mode.c_str());
141         if (recordFile_ == nullptr) {
142             HLOGE("tmpfile create failed '%s' with mode '%s'", tempFile.c_str(), mode.c_str());
143         } else {
144             // auto start it
145             Start();
146         }
147     }
148 }
Start()149 bool StdoutRecord::Start()
150 {
151     content_ = EMPTY_STRING;
152     fflush(stdout);
153 
154     // we will save output here
155     if (recordFile_ == nullptr) {
156         recordFile_ = std::tmpfile();
157     }
158     if (recordFile_ == nullptr) {
159         // try second way
160         std::string fileName = "/data/local/tmp/temp.stdout";
161         std::string resolvedPath = CanonicalizeSpecPath(fileName.c_str());
162         recordFile_ = fopen(resolvedPath.c_str(), "w+");
163         if (recordFile_ == nullptr) {
164             HLOGF("tmpfile create failed '%s'", fileName.c_str());
165             return false;
166         }
167     }
168 
169     // we save the stdout
170     stdoutFile_ = OHOS::UniqueFd(dup(STDOUT_FILENO));
171     if (stdoutFile_ == -1) {
172         HLOGF("std dup failed");
173         return false;
174     }
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     fflush(stdout);
191     // restore fd
192     dup2(stdoutFile_, STDOUT_FILENO);
193 
194     // return file content
195     if (recordFile_ != nullptr) {
196         const long fileLength = lseek(fileno(recordFile_), 0, SEEK_END);
197         content_.resize(fileLength);
198         lseek(fileno(recordFile_), 0, SEEK_SET);
199         const long len = read(fileno(recordFile_), content_.data(), fileLength);
200         std::fclose(recordFile_);
201         recordFile_ = nullptr;
202         if (len < 0) {
203             HLOGE("tmp file read failed (try read %ld)", fileLength);
204         } else if (len < fileLength) {
205             HLOGE("not all the data is read, lost %ld/%ld bytes", fileLength - len, fileLength);
206         }
207     } else {
208         HLOGE("recordFile_ is nullptr");
209     }
210     stop_ = true;
211     return content_;
212 }
213 
IsDigits(const std::string & str)214 bool IsDigits(const std::string &str)
215 {
216     if (str.empty()) {
217         return false;
218     } else {
219         return std::all_of(str.begin(), str.end(), ::isdigit);
220     }
221 }
222 
IsHexDigits(const std::string & str)223 bool IsHexDigits(const std::string &str)
224 {
225     if (str.empty()) {
226         return false;
227     }
228     const std::string prefix {"0x"};
229     std::string effectStr {str};
230     if (prefix.compare(0, prefix.size(), effectStr.substr(0, prefix.size())) == 0) {
231         effectStr = effectStr.substr(prefix.size(), effectStr.size() - prefix.size());
232     }
233     if (effectStr.empty()) {
234         return false;
235     }
236     std::size_t start {0};
237     for (; start < effectStr.size(); ++start) {
238         if (effectStr[start] == '0') {
239             continue;
240         }
241         break;
242     }
243     if (start == effectStr.size()) {
244         effectStr = "0";
245     }
246     return std::all_of(effectStr.begin(), effectStr.end(), ::isxdigit);
247 }
248 
IsDir(const std::string & path)249 bool IsDir(const std::string &path)
250 {
251     struct stat st;
252     if (stat(path.c_str(), &st) == 0) {
253         return S_ISDIR(st.st_mode);
254     }
255     return false;
256 }
257 
IsPath(const std::string & fileName)258 bool IsPath(const std::string &fileName)
259 {
260     HLOG_ASSERT(!fileName.empty());
261     if (fileName[0] == PATH_SEPARATOR) {
262         return true;
263     }
264     const int prefixPathLen = 2;
265     if (fileName.substr(0, prefixPathLen) == "./") {
266         return true;
267     }
268     return false;
269 }
270 
PlatformPathConvert(const std::string & path)271 std::string PlatformPathConvert(const std::string &path)
272 {
273 #if defined(is_mingw) && is_mingw
274     return StringReplace(path, "/", "\\");
275 #else
276     return path;
277 #endif
278 }
279 
ReadFileToString(const std::string & fileName)280 std::string ReadFileToString(const std::string &fileName)
281 {
282     std::ifstream inputString(fileName, std::ios::in);
283     if (!inputString or !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::ofstream output(fileName, std::ios::out);
318     if (!output) {
319         return false;
320     }
321     output << value;
322 
323     return output.good();
324 }
325 
IsRoot()326 bool IsRoot()
327 {
328 #if is_linux || is_ohos
329     static bool isRoot = (getuid() == 0);
330     return isRoot;
331 #else
332     return true;
333 #endif
334 }
335 
PowerOfTwo(uint64_t n)336 bool PowerOfTwo(uint64_t n)
337 {
338     return n && (!(n & (n - 1)));
339 }
340 
ReadIntFromProcFile(const std::string & path,int & value)341 bool ReadIntFromProcFile(const std::string &path, int &value)
342 {
343     std::string s = ReadFileToString(path);
344     if (s.empty()) {
345         return false;
346     }
347     value = std::stoi(s);
348     return true;
349 }
350 
WriteIntToProcFile(const std::string & path,int value)351 bool WriteIntToProcFile(const std::string &path, int value)
352 {
353     std::string s = std::to_string(value);
354 
355     return WriteStringToFile(path, s);
356 }
357 
358 // compress specified dataFile into gzip file
CompressFile(const std::string & dataFile,const std::string & destFile)359 bool CompressFile(const std::string &dataFile, const std::string &destFile)
360 {
361     std::string resolvedPath = CanonicalizeSpecPath(dataFile.c_str());
362     FILE *fp = fopen(resolvedPath.c_str(), "rb");
363     if (fp == nullptr) {
364         HLOGE("Fail to open data file %s", dataFile.c_str());
365         perror("Fail to fopen(rb)");
366         return false;
367     }
368 
369     std::unique_ptr<gzFile_s, decltype(&gzclose)> fgz(gzopen(destFile.c_str(), "wb"), gzclose);
370     if (fgz == nullptr) {
371         HLOGE("Fail to call gzopen(%s)", destFile.c_str());
372         fclose(fp);
373         return false;
374     }
375 
376     std::vector<char> buf(COMPRESS_READ_BUF_SIZE);
377     size_t len = 0;
378     while ((len = fread(buf.data(), sizeof(uint8_t), buf.size(), fp))) {
379         if (gzwrite(fgz.get(), buf.data(), len) == 0) {
380             HLOGE("Fail to call gzwrite for %zu bytes", len);
381             fclose(fp);
382             return false;
383         }
384     }
385     if (!feof(fp)) {
386         if (ferror(fp) != 0) {
387             HLOGE("ferror return err");
388             fclose(fp);
389             return false;
390         }
391     }
392     if (fclose(fp) < 0) {
393         return false;
394     }
395     return true;
396 }
397 
398 // uncompress specified gzip file into dataFile
UncompressFile(const std::string & gzipFile,const std::string & dataFile)399 bool UncompressFile(const std::string &gzipFile, const std::string &dataFile)
400 {
401     std::string resolvedPath = CanonicalizeSpecPath(dataFile.c_str());
402     FILE *fp = fopen(resolvedPath.c_str(), "wb");
403     if (fp == nullptr) {
404         HLOGE("Fail to open data file %s", dataFile.c_str());
405         perror("Fail to fopen(rb)");
406         return false;
407     }
408     std::unique_ptr<gzFile_s, decltype(&gzclose)> fgz(gzopen(gzipFile.c_str(), "rb"), gzclose);
409     if (fgz == nullptr) {
410         HLOGE("Fail to call gzopen(%s)", gzipFile.c_str());
411         fclose(fp);
412         return false;
413     }
414 
415     std::vector<char> buf(COMPRESS_READ_BUF_SIZE);
416     z_size_t len = 0;
417     while ((len = gzfread(buf.data(), sizeof(uint8_t), buf.size(), fgz.get()))) {
418         if (len != fwrite(buf.data(), sizeof(uint8_t), len, fp)) {
419             HLOGE("Fail to call fwrite for %zu bytes", len);
420             fclose(fp);
421             return false;
422         }
423     }
424     if (!gzeof(fgz.get())) {
425         int rc = 0;
426         const char *err = gzerror(fgz.get(), &rc);
427         if (rc != Z_OK) {
428             HLOGE("gzfread return %d:%s", rc, err);
429             fclose(fp);
430             return false;
431         }
432     }
433     if (fclose(fp) < 0) {
434         return false;
435     }
436     return true;
437 }
438 
StringTrim(std::string & string)439 std::string &StringTrim(std::string &string)
440 {
441     if (!string.empty()) {
442         string.erase(0, string.find_first_not_of(" "));
443         string.erase(string.find_last_not_of(" ") + 1);
444     }
445     return string;
446 }
447 
GetEntriesInDir(const std::string & basePath)448 std::vector<std::string> GetEntriesInDir(const std::string &basePath)
449 {
450     std::vector<std::string> result;
451     std::string resolvedPath = CanonicalizeSpecPath(basePath.c_str());
452     if (resolvedPath.empty()) {
453         return result;
454     }
455     DIR *dir = opendir(resolvedPath.c_str());
456     if (dir == nullptr) {
457         return result;
458     }
459     dirent *entry;
460     while ((entry = readdir(dir)) != nullptr) {
461         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
462             continue;
463         }
464         result.push_back(entry->d_name);
465     }
466     closedir(dir);
467     return result;
468 }
469 
GetSubDirs(const std::string & basePath)470 std::vector<std::string> GetSubDirs(const std::string &basePath)
471 {
472     std::vector<std::string> entries = GetEntriesInDir(basePath);
473     std::vector<std::string> result = {};
474     for (std::size_t index = 0; index < entries.size(); ++index) {
475         if (IsDir(basePath + "/" + entries[index])) {
476             result.push_back(std::move(entries[index]));
477         }
478     }
479     return result;
480 }
481 
IsSameCommand(const std::string & cmdLine,const std::string & cmdName)482 bool IsSameCommand(const std::string &cmdLine, const std::string &cmdName)
483 {
484     std::vector<std::string> cmdpaths = StringSplit(cmdLine, "/");
485     if (!cmdpaths.empty()) {
486         if (strcmp(cmdpaths.back().c_str(), cmdName.c_str()) == 0) {
487             return true;
488         }
489     }
490     return false;
491 }
492 
GetSubthreadIDs(const pid_t pid)493 std::vector<pid_t> GetSubthreadIDs(const pid_t pid)
494 {
495     std::string path {"/proc/"};
496     path += std::to_string(pid);
497     path += "/task/";
498     auto tids = GetSubDirs(path);
499     std::vector<pid_t> res {};
500     for (auto tidStr : tids) {
501         pid_t tid = static_cast<pid_t>(std::stoul(tidStr, nullptr));
502         if (tid == pid) {
503             continue;
504         }
505         res.push_back(tid);
506     }
507     return res;
508 }
509 
GetSubthreadIDs(const pid_t pid,std::map<pid_t,ThreadInfos> & thread_map)510 std::vector<pid_t> GetSubthreadIDs(const pid_t pid, std::map<pid_t, ThreadInfos> &thread_map)
511 {
512     std::string path {"/proc/"};
513     path += std::to_string(pid);
514     path += "/task/";
515     auto tids = GetSubDirs(path);
516     std::vector<pid_t> res{};
517     for (auto tidStr : tids) {
518         ThreadInfos info;
519         pid_t tid = static_cast<pid_t>(std::stoul(tidStr, nullptr));
520         info.tid = tid;
521         info.pid = pid;
522         thread_map[tid] = info;
523         res.push_back(tid);
524     }
525     return res;
526 }
527 
StringStartsWith(const std::string & string,const std::string & with)528 bool StringStartsWith(const std::string &string, const std::string &with)
529 {
530     return string.find(with) == 0;
531 }
532 
StringEndsWith(const std::string & string,const std::string & with)533 bool StringEndsWith(const std::string &string, const std::string &with)
534 {
535     if (string.empty()) {
536         // empty string only end with empty string
537         if (with.empty()) {
538             return true;
539         } else {
540             return false;
541         }
542     }
543     return string.rfind(with) == (string.length() - with.length());
544 }
545 
HexDump(const void * buf,size_t size,size_t maxSize)546 void HexDump(const void *buf, size_t size, size_t maxSize)
547 {
548     const unsigned char *byteBuf = static_cast<const unsigned char *>(buf);
549     const size_t dumpByteEachLine = 8;
550     size_t outputBytes = 0;
551     if (!maxSize) {
552         outputBytes = size;
553     } else {
554         outputBytes = std::min(size, maxSize);
555     }
556 
557     for (size_t i = 0; i <= outputBytes; i += dumpByteEachLine) {
558         HLOGM(" %02zu: %s ", i, BufferToHexString(byteBuf, dumpByteEachLine).c_str());
559         byteBuf += dumpByteEachLine;
560     }
561 }
562 
BufferToHexString(const std::vector<unsigned char> & vec)563 std::string BufferToHexString(const std::vector<unsigned char> &vec)
564 {
565     return BufferToHexString(vec.data(), vec.size());
566 }
567 
BufferToHexString(const unsigned char buf[],size_t size)568 std::string BufferToHexString(const unsigned char buf[], size_t size)
569 {
570     std::stringstream ss;
571     ss << size << ":";
572     for (size_t i = 0; i < size; i++) {
573         ss << " 0x" << std::setfill('0') << std::setw(BYTE_PRINT_WIDTH) << std::hex
574            << (unsigned short)buf[i];
575     }
576     return ss.str();
577 }
578 
CollectPidsByAppname(std::set<pid_t> & pids,const std::string & appPackage)579 void CollectPidsByAppname(std::set<pid_t> &pids, const std::string &appPackage)
580 {
581     const std::string basePath {"/proc/"};
582     const std::string cmdline {"/cmdline"};
583     std::vector<std::string> subDirs = GetSubDirs(basePath);
584     for (const auto &subDir : subDirs) {
585         if (!IsDigits(subDir)) {
586             continue;
587         }
588         std::string fileName {basePath + subDir + cmdline};
589         if (IsSameCommand(ReadFileToString(fileName), appPackage)) {
590             pids.emplace(std::stoul(subDir, nullptr));
591         }
592     }
593 }
594 
IsRestarted(const std::string & appPackage)595 bool IsRestarted(const std::string &appPackage)
596 {
597     printf("please restart %s for profiling within 30 seconds\n", appPackage.c_str());
598     std::set<pid_t> oldPids {};
599     std::set<pid_t> newPids {};
600     std::vector<pid_t> intersection;
601     const auto startTime = steady_clock::now();
602     const auto endTime = startTime + std::chrono::seconds(CHECK_TIMEOUT);
603     CollectPidsByAppname(oldPids, appPackage);
604     do {
605         CollectPidsByAppname(newPids, appPackage);
606         std::set_intersection(oldPids.begin(), oldPids.end(),
607             newPids.begin(), newPids.end(), std::back_insert_iterator(intersection));
608         if (intersection.empty()) {
609             // app names are same, no intersection, means app restarted
610             return true;
611         }
612         intersection.clear();
613         newPids.clear();
614         std::this_thread::sleep_for(milliseconds(CHECK_FREQUENCY));
615     } while (steady_clock::now() < endTime);
616     printf("app %s was not stopped within 30 seconds\n", appPackage.c_str());
617     return false;
618 }
619 
GetAppPackagePid(const std::string & appPackage,const pid_t oldPid,const int checkAppMs,const uint64_t waitAppTimeOut)620 pid_t GetAppPackagePid(const std::string &appPackage, const pid_t oldPid, const int checkAppMs,
621                        const uint64_t waitAppTimeOut)
622 {
623     pid_t res {-1};
624     const std::string basePath {"/proc/"};
625     const std::string cmdline {"/cmdline"};
626     const auto startTime = steady_clock::now();
627     const auto endTime = startTime + std::chrono::seconds(waitAppTimeOut);
628     do {
629         std::vector<std::string> subDirs = GetSubDirs(basePath);
630         for (const auto &subDir : subDirs) {
631             if (!IsDigits(subDir)) {
632                 continue;
633             }
634             std::string fileName {basePath + subDir + cmdline};
635             if (IsSameCommand(ReadFileToString(fileName), appPackage)) {
636                 res = std::stoul(subDir, nullptr);
637                 HLOGD("[GetAppPackagePid]: get appid for %s is %d", appPackage.c_str(), res);
638                 return res;
639             }
640         }
641         std::this_thread::sleep_for(milliseconds(checkAppMs));
642     } while (steady_clock::now() < endTime);
643 
644     return res;
645 }
646 
CheckAppIsRunning(std::vector<pid_t> & selectPids,const std::string & appPackage,int checkAppMs)647 bool CheckAppIsRunning (std::vector<pid_t> &selectPids, const std::string &appPackage, int checkAppMs)
648 {
649     if (!appPackage.empty()) {
650         pid_t appPid = GetAppPackagePid(appPackage, -1, checkAppMs, waitAppRunCheckTimeOut);
651         if (appPid <= 0) {
652             printf("app %s not running\n", appPackage.c_str());
653             return false;
654         }
655         HLOGD("[CheckAppIsRunning] get appPid %d for app %s\n", appPid, appPackage.c_str());
656         selectPids.push_back(appPid);
657     }
658     return true;
659 }
660 
IsSupportNonDebuggableApp()661 bool IsSupportNonDebuggableApp()
662 {
663     // root first
664     if (IsRoot()) {
665         return true;
666     }
667     // user mode
668     if (!IsBeta()) {
669         return false;
670     }
671     // restricted aplication for beta
672     if (!IsAllowProfilingUid()) {
673         return false;
674     }
675     return true;
676 }
677 
GetUserType()678 const std::string GetUserType()
679 {
680 #if defined(is_ohos) && is_ohos
681     std::string userType = OHOS::system::GetParameter(USER_TYPE_PARAM, USER_TYPE_PARAM_GET);
682     HLOGD("GetUserType: userType is %s", userType.c_str());
683     return userType;
684 #else
685     return "";
686 #endif
687 }
688 
LittleMemory()689 bool LittleMemory()
690 {
691     std::ifstream file("/proc/meminfo");
692     std::string line;
693     while (getline(file, line)) {
694         if (line.find("MemTotal:") != std::string::npos) {
695             int memSize = stoi(line.substr(line.find(":") + 1));
696             if (memSize < (LITTLE_MEMORY_SIZE * MULTIPLE_SIZE * MULTIPLE_SIZE)) {
697                 return true;
698             }
699         }
700     }
701     return false;
702 }
703 
704 // only for domestic beta
IsBeta()705 bool IsBeta()
706 {
707     std::string userTypeRsp = GetUserType();
708     if (userTypeRsp == USER_DOMESTIC_BETA) {
709         return true;
710     }
711     // default release when usertype param is invalid
712     if (userTypeRsp.empty()) {
713         HLOGE("GetUserType is empty [%s]", userTypeRsp.c_str());
714         return true;
715     }
716     return false;
717 }
718 
IsAllowProfilingUid()719 bool IsAllowProfilingUid()
720 {
721 #if (defined(is_linux) && is_linux) || (defined(is_ohos) && is_ohos)
722     static unsigned int curUid = getuid();
723     HLOGD("curUid is %d\n", curUid);
724     if (ALLOW_UIDS.find(curUid) != ALLOW_UIDS.end()) {
725         return true;
726     }
727     return false;
728 #else
729     return false;
730 #endif
731 }
732 
GetProcessName(int pid)733 std::string GetProcessName(int pid)
734 {
735 #if defined(is_ohos) && is_ohos
736     std::string filePath = "/proc/" + std::to_string(pid) + "/cmdline";
737     std::string bundleName = ReadFileToString(filePath);
738     return bundleName.substr(0, strlen(bundleName.c_str()));
739 #else
740     return "";
741 #endif
742 }
743 
NeedAdaptSandboxPath(char * filename,int pid,u16 & headerSize)744 bool NeedAdaptSandboxPath(char *filename, int pid, u16 &headerSize)
745 {
746     std::string oldFilename = filename;
747     if (oldFilename.find("/data/storage") == 0 && access(oldFilename.c_str(), F_OK) != 0) {
748         std::string newFilename = "/proc/" + std::to_string(pid) + "/root" + oldFilename;
749         (void)memset_s(filename, KILO, '\0', KILO);
750         if (strncpy_s(filename, KILO, newFilename.c_str(), newFilename.size()) != 0) {
751             HLOGD("strncpy_s recordMmap2 failed!");
752         }
753         headerSize += newFilename.size() - oldFilename.size();
754         return true;
755     }
756     return false;
757 }
758 
NeedAdaptHMBundlePath(std::string & filename,const std::string & threadname)759 bool NeedAdaptHMBundlePath(std::string& filename, const std::string& threadname)
760 {
761     std::string path = "/data/storage/el1/bundle";
762     std::string newpath = "/data/app/el1/bundle/public/";
763     size_t pos = filename.find(path);
764     if (pos != std::string::npos && access(filename.c_str(), F_OK) != 0) {
765         // /data/storage/el1/bundle/libs/arm64/libentry.so
766         filename.replace(pos, path.length(), newpath + threadname);
767         // /data/app/el1/bundle/public/<procname>/libs/arm64/libentry.so
768         HLOGD("Fix hm bundle path to %s", filename.c_str());
769         return true;
770     }
771     return false;
772 }
773 
774 } // namespace HiPerf
775 } // namespace Developtools
776 } // namespace OHOS
777 
778 // this will also used for libunwind head (out of namespace)
779 #if defined(is_mingw) && is_mingw
780 using namespace OHOS::Developtools::HiPerf;
GetLastErrorString()781 std::string GetLastErrorString()
782 {
783     LPVOID lpMsgBuf;
784     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
785                       FORMAT_MESSAGE_IGNORE_INSERTS,
786                   NULL, GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, NULL);
787     std::string error((LPTSTR)lpMsgBuf);
788     LocalFree(lpMsgBuf);
789     return error;
790 }
791 
mmap(void * addr,size_t length,int prot,int flags,int fd,size_t offset)792 void *mmap(void *addr, size_t length, int prot, int flags, int fd, size_t offset)
793 {
794     HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
795     if (FileHandle == INVALID_HANDLE_VALUE) {
796         return MMAP_FAILED;
797     }
798 
799     HLOGV("fd is %d", fd);
800 
801     HANDLE FileMappingHandle = ::CreateFileMappingW(FileHandle, 0, PAGE_READONLY, 0, 0, 0);
802     if (FileMappingHandle == nullptr) {
803         HLOGE("CreateFileMappingW %zu Failed with %ld:%s", length, GetLastError(),
804               GetLastErrorString().c_str());
805         return MMAP_FAILED;
806     }
807 
808     void *mapAddr = ::MapViewOfFile(FileMappingHandle, FILE_MAP_READ, 0, 0, 0);
809     if (mapAddr == nullptr) {
810         HLOGE("MapViewOfFile %zu Failed with %ld:%s", length, GetLastError(),
811               GetLastErrorString().c_str());
812         return MMAP_FAILED;
813     }
814 
815     // Close all the handles except for the view. It will keep the other handles
816     // alive.
817     ::CloseHandle(FileMappingHandle);
818     return mapAddr;
819 }
820 
munmap(void * addr,size_t)821 int munmap(void *addr, size_t)
822 {
823     /*
824         On success, munmap() returns 0.  On failure, it returns -1, and
825         errno is set to indicate the error (probably to EINVAL).
826 
827         UnmapViewOfFile function (memoryapi.h)
828 
829         If the function succeeds, the return value is nonzero.
830         If the function fails, the return value is zero. To get extended error information, call
831     GetLastError.
832     */
833     return !UnmapViewOfFile(addr);
834 }
835 #endif
836