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