xref: /developtools/hiperf/src/utilities.cpp (revision 48f512ce)
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"
35using namespace OHOS;
36using namespace OHOS::AppExecFwk;
37#endif
38
39using namespace std::chrono;
40namespace OHOS {
41namespace Developtools {
42namespace HiPerf {
43
44static const std::string USER_DOMESTIC_BETA = "beta";
45static const std::string USER_TYPE_PARAM = "const.logsystem.versiontype";
46static const std::string USER_TYPE_PARAM_GET = "";
47static const std::string HIVIEW_CMDLINE = "/system/bin/hiview";
48
49std::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
92uint32_t RoundUp(uint32_t x, const int align)
93{
94    return (((x) + (align) >= 1 ? (x) + (align) - 1 : 0) / (align)) * (align);
95}
96
97std::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
112size_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
126std::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}
148StdoutRecord::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}
161bool 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
195std::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
224bool 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
233bool 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
257bool 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
266bool 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
279std::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
288std::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
302bool 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
324bool 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
336bool 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
347bool PowerOfTwo(uint64_t n)
348{
349    return n && (!(n & (n - 1)));
350}
351
352bool 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
360bool 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
368bool 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
408bool 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
448std::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
457std::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
475std::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
487bool 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
498std::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
515std::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
533bool StringStartsWith(const std::string &string, const std::string &with)
534{
535    return string.find(with) == 0;
536}
537
538bool 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
551void 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
568std::string BufferToHexString(const std::vector<unsigned char> &vec)
569{
570    return BufferToHexString(vec.data(), vec.size());
571}
572
573std::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
584void 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
600bool 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
623pid_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
650bool 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
664bool 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
679bool 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
698bool 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
719bool 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
732const 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
743bool 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
754bool 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
768bool 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
779bool 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
791std::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
802bool 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
817bool 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
845bool 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
854bool 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
870bool 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