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