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