• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "xcollie_utils.h"
17 #include <ctime>
18 #include <cinttypes>
19 #include <algorithm>
20 #include <cmath>
21 #include <cstdlib>
22 #include <cstdio>
23 #include <csignal>
24 #include <sstream>
25 #include <securec.h>
26 #include <iostream>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <filesystem>
30 #include <sys/prctl.h>
31 #include <sys/stat.h>
32 #include <set>
33 #include "directory_ex.h"
34 #include "file_ex.h"
35 #include "storage_acl.h"
36 #include "parameter.h"
37 #include "parameters.h"
38 #include <dlfcn.h>
39 #include <dirent.h>
40 
41 namespace OHOS {
42 namespace HiviewDFX {
43 namespace {
44 constexpr int64_t SEC_TO_MANOSEC = 1000000000;
45 constexpr uint64_t MAX_FILE_SIZE = 10 * 1024 * 1024; // 10M
46 const int MAX_NAME_SIZE = 128;
47 const int MIN_WAIT_NUM = 3;
48 const int TIME_INDEX_MAX = 32;
49 const int INIT_PID = 1;
50 const int TIMES_ARR_SIZE = 6;
51 const uint64_t TIMES_AVE_PARAM = 2;
52 const int32_t APP_MIN_UID = 20000;
53 const uint64_t START_TIME_INDEX = 21;
54 const int START_PATH_LEN = 128;
55 constexpr int64_t MAX_TIME_BUFF = 64;
56 constexpr int64_t SEC_TO_MILLISEC = 1000;
57 constexpr int64_t MINUTE_TO_S = 60; // 60s
58 constexpr size_t TOTAL_HALF = 2; // 2 : remove half of the total
59 constexpr size_t DEFAULT_LOGSTORE_MIN_KEEP_FILE_COUNT = 100;
60 constexpr mode_t DEFAULT_LOG_DIR_MODE = 0770;
61 constexpr const char* const LOGGER_TEANSPROC_PATH = "/proc/transaction_proc";
62 constexpr const char* const KEY_DEVELOPER_MODE_STATE = "const.security.developermode.state";
63 constexpr const char* const KEY_BETA_TYPE = "const.logsystem.versiontype";
64 constexpr const char* const ENABLE_VAULE = "true";
65 constexpr const char* const ENABLE_BETA_VAULE = "beta";
66 constexpr const char* const KEY_REPORT_TIMES_TYPE = "persist.hiview.jank.reporttimes";
67 
68 static std::string g_curProcName;
69 static int32_t g_lastPid;
70 static std::mutex g_lock;
71 }
72 #ifdef SUSPEND_CHECK_ENABLE
GetSuspendTime(const char * path,uint64_t & now)73 std::pair<double, double> GetSuspendTime(const char *path, uint64_t &now)
74 {
75     std::ifstream file(path);
76     if (!file.is_open()) {
77         XCOLLIE_LOGE("Failed to open file: %{public}s", path);
78         return {-1.0, -1.0};
79     }
80 
81     std::string line;
82     if (!std::getline(file, line)) {
83         XCOLLIE_LOGE("Failed to read file: %{public}s", path);
84         file.close();
85         return {-1.0, -1.0};
86     }
87     file.close();
88     double suspendStartTime = -1.0;
89     double suspendEndTime = -1.0;
90     std::istringstream iss(line);
91     if (!(iss >> suspendStartTime >> suspendEndTime)) {
92         XCOLLIE_LOGE("Parse failed: %{public}s", line.c_str());
93         return {-1.0, -1.0};
94     }
95     suspendStartTime *= SEC_TO_MILLISEC;
96     suspendEndTime *= SEC_TO_MILLISEC;
97     uint64_t currentTime = GetCurrentTickMillseconds();
98     uint64_t diff = (currentTime > now) ? (currentTime - now) : (now - currentTime);
99     XCOLLIE_LOGW("open file %{public}s, suspendStartTime: %{public}f, suspendEndTime: %{public}f, currentTime: "
100                  "%{public}" PRIu64 " now: %{public}" PRIu64 " diff: %{public}" PRIu64,
101         path,
102         suspendStartTime,
103         suspendEndTime,
104         currentTime,
105         now,
106         diff);
107     return {suspendStartTime, suspendEndTime};
108 }
109 #endif
GetCurrentTickMillseconds()110 uint64_t GetCurrentTickMillseconds()
111 {
112     struct timespec t;
113     t.tv_sec = 0;
114     t.tv_nsec = 0;
115     clock_gettime(CLOCK_MONOTONIC, &t);
116     return static_cast<uint64_t>((t.tv_sec) * SEC_TO_MANOSEC + t.tv_nsec) / SEC_TO_MICROSEC;
117 }
118 
GetCurrentBootMillseconds()119 uint64_t GetCurrentBootMillseconds()
120 {
121     struct timespec t;
122     t.tv_sec = 0;
123     t.tv_nsec = 0;
124     clock_gettime(CLOCK_BOOTTIME, &t);
125     return static_cast<uint64_t>((t.tv_sec) * SEC_TO_MANOSEC + t.tv_nsec) / SEC_TO_MICROSEC;
126 }
127 
CalculateTimes(uint64_t & bootTimeStart,uint64_t & monoTimeStart)128 void CalculateTimes(uint64_t &bootTimeStart, uint64_t &monoTimeStart)
129 {
130     uint64_t timesArr[TIMES_ARR_SIZE] = {0};
131     uint64_t minTimeDiff = UINT64_MAX;
132     size_t index = 1;
133 
134     for (size_t i = 0; i < TIMES_ARR_SIZE; i++) {
135         timesArr[i] = (i & 1) ? GetCurrentTickMillseconds() : GetCurrentBootMillseconds();
136         if (i <= 1) {
137             continue;
138         }
139         uint64_t tmpDiff = GetNumsDiffAbs(timesArr[i], timesArr[i - 2]);
140         if (tmpDiff < minTimeDiff) {
141             minTimeDiff = tmpDiff;
142             index = i - 1;
143         }
144     }
145     bootTimeStart = (index & 1) ? (timesArr[index - 1] + timesArr[index + 1]) / TIMES_AVE_PARAM : timesArr[index];
146     monoTimeStart = (index & 1) ? timesArr[index] : (timesArr[index - 1] + timesArr[index + 1]) / TIMES_AVE_PARAM;
147 }
148 
GetNumsDiffAbs(const uint64_t & numOne,const uint64_t & numTwo)149 uint64_t GetNumsDiffAbs(const uint64_t& numOne, const uint64_t& numTwo)
150 {
151     return (numOne > numTwo) ? (numOne - numTwo) : (numTwo - numOne);
152 }
153 
IsFileNameFormat(char c)154 bool IsFileNameFormat(char c)
155 {
156     if (c >= '0' && c <= '9') {
157         return false;
158     }
159 
160     if (c >= 'a' && c <= 'z') {
161         return false;
162     }
163 
164     if (c >= 'A' && c <= 'Z') {
165         return false;
166     }
167 
168     if (c == '.' || c == '-' || c == '_') {
169         return false;
170     }
171 
172     return true;
173 }
174 
GetSelfProcName()175 std::string GetSelfProcName()
176 {
177     std::string ret = GetProcessNameFromProcCmdline();
178     ret.erase(std::remove_if(ret.begin(), ret.end(), IsFileNameFormat), ret.end());
179     return ret;
180 }
181 
GetFirstLine(const std::string & path)182 std::string GetFirstLine(const std::string& path)
183 {
184     char checkPath[PATH_MAX] = {0};
185     if (realpath(path.c_str(), checkPath) == nullptr) {
186         XCOLLIE_LOGE("canonicalize failed. path is %{public}s", path.c_str());
187         return "";
188     }
189 
190     std::ifstream inFile(checkPath);
191     if (!inFile) {
192         return "";
193     }
194     std::string firstLine;
195     getline(inFile, firstLine);
196     inFile.close();
197     return firstLine;
198 }
199 
IsDeveloperOpen()200 bool IsDeveloperOpen()
201 {
202     static std::string isDeveloperOpen;
203     if (!isDeveloperOpen.empty()) {
204         return (isDeveloperOpen.find(ENABLE_VAULE) != std::string::npos);
205     }
206     isDeveloperOpen = system::GetParameter(KEY_DEVELOPER_MODE_STATE, "");
207     return (isDeveloperOpen.find(ENABLE_VAULE) != std::string::npos);
208 }
209 
IsBetaVersion()210 bool IsBetaVersion()
211 {
212     static std::string isBetaVersion;
213     if (!isBetaVersion.empty()) {
214         return (isBetaVersion.find(ENABLE_BETA_VAULE) != std::string::npos);
215     }
216     isBetaVersion = system::GetParameter(KEY_BETA_TYPE, "");
217     return (isBetaVersion.find(ENABLE_BETA_VAULE) != std::string::npos);
218 }
219 
GetProcessNameFromProcCmdline(int32_t pid)220 std::string GetProcessNameFromProcCmdline(int32_t pid)
221 {
222     if (pid > 0) {
223         g_lock.lock();
224         if (!g_curProcName.empty() && g_lastPid == pid) {
225             g_lock.unlock();
226             return g_curProcName;
227         }
228     }
229 
230     std::string pidStr = pid > 0 ? std::to_string(pid) : "self";
231     std::string procCmdlinePath = "/proc/" + pidStr + "/cmdline";
232     std::string procCmdlineContent = GetFirstLine(procCmdlinePath);
233     if (procCmdlineContent.empty()) {
234         if (pid > 0) {
235             g_lock.unlock();
236         }
237         return "";
238     }
239 
240     size_t procNameStartPos = 0;
241     size_t procNameEndPos = procCmdlineContent.size();
242     for (size_t i = 0; i < procCmdlineContent.size(); i++) {
243         if (procCmdlineContent[i] == '/') {
244             procNameStartPos = i + 1;
245         } else if (procCmdlineContent[i] == '\0') {
246             procNameEndPos = i;
247             break;
248         }
249     }
250     size_t endPos = procNameEndPos - procNameStartPos;
251     if (pid <= 0) {
252         return procCmdlineContent.substr(procNameStartPos, endPos);
253     }
254     g_curProcName = procCmdlineContent.substr(procNameStartPos, endPos);
255     g_lastPid = pid;
256     g_lock.unlock();
257     XCOLLIE_LOGD("g_curProcName is empty, name %{public}s pid %{public}d", g_curProcName.c_str(), pid);
258     return g_curProcName;
259 }
260 
GetLimitedSizeName(std::string name)261 std::string GetLimitedSizeName(std::string name)
262 {
263     if (name.size() > MAX_NAME_SIZE) {
264         return name.substr(0, MAX_NAME_SIZE);
265     }
266     return name;
267 }
268 
IsProcessDebug(int32_t pid)269 bool IsProcessDebug(int32_t pid)
270 {
271     const int buffSize = 128;
272     char paramBundle[buffSize] = {0};
273     GetParameter("hiviewdfx.appfreeze.filter_bundle_name", "", paramBundle, buffSize - 1);
274     std::string debugBundle(paramBundle);
275     std::string procCmdlineContent = GetProcessNameFromProcCmdline(pid);
276     if (procCmdlineContent.compare(debugBundle) == 0) {
277         XCOLLIE_LOGI("appfreeze filtration %{public}s_%{public}s don't exit.",
278             debugBundle.c_str(), procCmdlineContent.c_str());
279         return true;
280     }
281     return false;
282 }
283 
DelayBeforeExit(unsigned int leftTime)284 void DelayBeforeExit(unsigned int leftTime)
285 {
286     while (leftTime > 0) {
287         leftTime = sleep(leftTime);
288     }
289 }
290 
TrimStr(const std::string & str,const char cTrim)291 std::string TrimStr(const std::string& str, const char cTrim)
292 {
293     std::string strTmp = str;
294     strTmp.erase(0, strTmp.find_first_not_of(cTrim));
295     strTmp.erase(strTmp.find_last_not_of(cTrim) + sizeof(char));
296     return strTmp;
297 }
298 
SplitStr(const std::string & str,const std::string & sep,std::vector<std::string> & strs,bool canEmpty,bool needTrim)299 void SplitStr(const std::string& str, const std::string& sep,
300     std::vector<std::string>& strs, bool canEmpty, bool needTrim)
301 {
302     strs.clear();
303     std::string strTmp = needTrim ? TrimStr(str) : str;
304     std::string strPart;
305     while (true) {
306         std::string::size_type pos = strTmp.find(sep);
307         if (pos == std::string::npos || sep.empty()) {
308             strPart = needTrim ? TrimStr(strTmp) : strTmp;
309             if (!strPart.empty() || canEmpty) {
310                 strs.push_back(strPart);
311             }
312             break;
313         } else {
314             strPart = needTrim ? TrimStr(strTmp.substr(0, pos)) : strTmp.substr(0, pos);
315             if (!strPart.empty() || canEmpty) {
316                 strs.push_back(strPart);
317             }
318             strTmp = strTmp.substr(sep.size() + pos, strTmp.size() - sep.size() - pos);
319         }
320     }
321 }
322 
ParsePeerBinderPid(std::ifstream & fin,int32_t pid)323 int ParsePeerBinderPid(std::ifstream& fin, int32_t pid)
324 {
325     const int decimal = 10;
326     std::string line;
327     bool isBinderMatchup = false;
328     while (getline(fin, line)) {
329         if (isBinderMatchup) {
330             break;
331         }
332 
333         if (line.find("async\t") != std::string::npos) {
334             continue;
335         }
336 
337         std::istringstream lineStream(line);
338         std::vector<std::string> strList;
339         std::string tmpstr;
340         while (lineStream >> tmpstr) {
341             strList.push_back(tmpstr);
342         }
343 
344         auto splitPhase = [](const std::string& str, uint16_t index) -> std::string {
345             std::vector<std::string> strings;
346             SplitStr(str, ":", strings);
347             if (index < strings.size()) {
348                 return strings[index];
349             }
350             return "";
351         };
352 
353         if (strList.size() >= 7) { // 7: valid array size
354             // 2: peer id,
355             std::string server = splitPhase(strList[2], 0);
356             // 0: local id,
357             std::string client = splitPhase(strList[0], 0);
358             // 5: wait time, s
359             std::string wait = splitPhase(strList[5], 1);
360             if (server == "" || client == "" || wait == "") {
361                 continue;
362             }
363             int serverNum = std::strtol(server.c_str(), nullptr, decimal);
364             int clientNum = std::strtol(client.c_str(), nullptr, decimal);
365             int waitNum = std::strtol(wait.c_str(), nullptr, decimal);
366             XCOLLIE_LOGI("server:%{public}d, client:%{public}d, wait:%{public}d",
367                 serverNum, clientNum, waitNum);
368             if (clientNum != pid || waitNum < MIN_WAIT_NUM) {
369                 continue;
370             }
371             return serverNum;
372         }
373         if (line.find("context") != line.npos) {
374             isBinderMatchup = true;
375         }
376     }
377     return -1;
378 }
379 
KillProcessByPid(int32_t pid)380 bool KillProcessByPid(int32_t pid)
381 {
382     std::ifstream fin;
383     std::string path = std::string(LOGGER_TEANSPROC_PATH);
384     char resolvePath[PATH_MAX] = {0};
385     if (realpath(path.c_str(), resolvePath) == nullptr) {
386         XCOLLIE_LOGI("GetBinderPeerPids realpath error");
387         return false;
388     }
389     fin.open(resolvePath);
390     if (!fin.is_open()) {
391         XCOLLIE_LOGI("open file failed, %{public}s.", resolvePath);
392         return false;
393     }
394 
395     int peerBinderPid = ParsePeerBinderPid(fin, pid);
396     fin.close();
397     if (peerBinderPid <= INIT_PID || peerBinderPid == pid) {
398         XCOLLIE_LOGI("No PeerBinder process freeze occurs in the current process. "
399             "peerBinderPid=%{public}d, pid=%{public}d", peerBinderPid, pid);
400         return false;
401     }
402     int32_t uid = GetUidByPid(peerBinderPid);
403     if (uid < APP_MIN_UID) {
404         XCOLLIE_LOGI("Current peer process can not kill, "
405             "peerBinderPid=%{public}d, uid=%{public}d", peerBinderPid, uid);
406         return false;
407     }
408 
409     int32_t ret = kill(peerBinderPid, SIGKILL);
410     if (ret == -1) {
411         XCOLLIE_LOGI("Kill PeerBinder process failed");
412     } else {
413         XCOLLIE_LOGI("Kill PeerBinder process success, name=%{public}s, pid=%{public}d",
414             GetProcessNameFromProcCmdline(peerBinderPid).c_str(), peerBinderPid);
415     }
416     return (ret >= 0);
417 }
418 
CreateDir(const std::string & dirPath)419 bool CreateDir(const std::string& dirPath)
420 {
421     if (!OHOS::FileExists(dirPath)) {
422         OHOS::ForceCreateDirectory(dirPath);
423         OHOS::ChangeModeDirectory(dirPath, DEFAULT_LOG_DIR_MODE);
424     }
425     if (OHOS::StorageDaemon::AclSetAccess(dirPath, "g:1201:rwx") != 0) {
426         XCOLLIE_LOGI("Failed to AclSetAccess");
427         return false;
428     }
429     return true;
430 }
431 
GetFilesByDir(std::vector<FileInfo> & fileList,const std::string & dir)432 void GetFilesByDir(std::vector<FileInfo> &fileList, const std::string& dir)
433 {
434     if (!OHOS::FileExists(dir)) {
435         XCOLLIE_LOGW("dir: %{public}s not exists.", dir.c_str());
436         return;
437     }
438     struct stat fileStat {};
439     for (const auto &entry : std::filesystem::directory_iterator(dir)) {
440         if (!entry.is_regular_file()) {
441             continue;
442         }
443         std::string filePath = entry.path().string();
444         int err = stat(filePath.c_str(), &fileStat);
445         if (err != 0) {
446             XCOLLIE_LOGW("%{public}s: get fileStat failed, err(%{public}d).", filePath.c_str(), err);
447         } else {
448             FileInfo fileInfo = {
449                 .filePath = filePath,
450                 .mtime = fileStat.st_mtime
451             };
452             fileList.push_back(fileInfo);
453         }
454     }
455     XCOLLIE_LOGI("GetFilesByDir fileList size: %{public}zu.", fileList.size());
456 }
457 
ClearOldFiles(const std::vector<FileInfo> & fileList)458 int ClearOldFiles(const std::vector<FileInfo> &fileList)
459 {
460     size_t fileSize = fileList.size();
461     if (fileSize > 0) {
462         int removeFileNumber = static_cast<int>(fileSize - DEFAULT_LOGSTORE_MIN_KEEP_FILE_COUNT);
463         if (removeFileNumber < 0) {
464             removeFileNumber = static_cast<int>(std::ceil(fileSize / static_cast<double>(TOTAL_HALF)));
465         }
466         int deleteCount = 0;
467         for (auto it = fileList.begin(); it != fileList.end(); it++) {
468             if (deleteCount >= removeFileNumber) {
469                 break;
470             }
471             XCOLLIE_LOGW("Remove file %{public}s.", it->filePath.c_str());
472             OHOS::RemoveFile(it->filePath);
473             deleteCount++;
474         }
475         return deleteCount;
476     }
477     return 0;
478 }
479 
WriteStackToFd(int32_t pid,std::string & path,const std::string & stack,const std::string & eventName,bool & isOverLimit)480 bool WriteStackToFd(int32_t pid, std::string& path, const std::string& stack, const std::string& eventName,
481     bool& isOverLimit)
482 {
483     if (!CreateDir(WATCHDOG_DIR)) {
484         return false;
485     }
486     isOverLimit = ClearFreezeFileIfNeed(stack.size());
487 
488     std::string time = GetFormatDate();
489     std::string realPath;
490     if (!OHOS::PathToRealPath(WATCHDOG_DIR, realPath)) {
491         XCOLLIE_LOGE("Path to realPath failed.errno:%{public}d", errno);
492         return false;
493     }
494     path = realPath + "/" + eventName + "_" + time.c_str() + "_" +
495         std::to_string(pid).c_str() + ".txt";
496     return SaveStringToFile(path, stack);
497 }
498 
ClearFreezeFileIfNeed(uint64_t stackSize)499 bool ClearFreezeFileIfNeed(uint64_t stackSize)
500 {
501     uint64_t fileSize = OHOS::GetFolderSize(WATCHDOG_DIR) + stackSize;
502     if (fileSize < MAX_FILE_SIZE) {
503         return false;
504     }
505     XCOLLIE_LOGW("CurrentDir: %{public}s is over limit. Will to clear old file, fileSize: "
506         "%{public}" PRIu64 " max fileSize: %{public}" PRIu64 ".", WATCHDOG_DIR, fileSize, MAX_FILE_SIZE);
507     std::vector<FileInfo> fileList;
508     GetFilesByDir(fileList, FREEZE_DIR);
509     GetFilesByDir(fileList, WATCHDOG_DIR);
510     std::sort(fileList.begin(), fileList.end(), [](FileInfo lfile, FileInfo rfile) {
511         return lfile.mtime < rfile.mtime;
512     });
513     int deleteCount = ClearOldFiles(fileList);
514     XCOLLIE_LOGI("Clear old file count:%{public}d", deleteCount);
515     return true;
516 }
517 
SaveStringToFile(const std::string & path,const std::string & content)518 bool SaveStringToFile(const std::string& path, const std::string& content)
519 {
520     constexpr mode_t defaultLogFileMode = 0644;
521     FILE* fp = fopen(path.c_str(), "w+");
522     chmod(path.c_str(), defaultLogFileMode);
523     if (fp == nullptr) {
524         XCOLLIE_LOGE("Failed to create path=%{public}s", path.c_str());
525         return false;
526     } else {
527         XCOLLIE_LOGI("success to create path=%{public}s", path.c_str());
528     }
529     OHOS::SaveStringToFile(path, content, true);
530     (void)fclose(fp);
531     return true;
532 }
533 
GetFormatDate()534 std::string GetFormatDate()
535 {
536     time_t t = time(nullptr);
537     char tmp[TIME_INDEX_MAX] = {0};
538     strftime(tmp, sizeof(tmp), "%Y%m%d%H%M%S", localtime(&t));
539     std::string date(tmp);
540     return date;
541 }
542 
FormatTime(const std::string & format)543 std::string FormatTime(const std::string &format)
544 {
545     auto now = std::chrono::system_clock::now();
546     auto millisecs = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
547     auto timestamp = millisecs.count();
548     std::time_t tt = static_cast<std::time_t>(timestamp / SEC_TO_MILLISEC);
549     std::tm* t = std::localtime(&tt);
550     if (t == nullptr) {
551         XCOLLIE_LOGE("localtime failed.");
552         return "";
553     }
554     char buffer[MAX_TIME_BUFF] = {0};
555     if (std::strftime(buffer, sizeof(buffer), format.c_str(), t) == 0) {
556         XCOLLIE_LOGE("strftime failed.");
557         return "";
558     }
559     return std::string(buffer);
560 }
561 
GetTimeStamp()562 int64_t GetTimeStamp()
563 {
564     std::chrono::nanoseconds ms = std::chrono::duration_cast< std::chrono::nanoseconds >(
565         std::chrono::system_clock::now().time_since_epoch());
566     return ms.count();
567 }
568 
FunctionOpen(void * funcHandler,const char * funcName)569 void* FunctionOpen(void* funcHandler, const char* funcName)
570 {
571     dlerror();
572     char* err = nullptr;
573     void* func = dlsym(funcHandler, funcName);
574     err = dlerror();
575     if (err != nullptr) {
576         XCOLLIE_LOGE("dlopen %{public}s failed. %{public}s\n", funcName, err);
577         return nullptr;
578     }
579     return func;
580 }
581 
GetUidByPid(const int32_t pid)582 int32_t GetUidByPid(const int32_t pid)
583 {
584     std::string uidFlag = "Uid:";
585     std::string cmdLinePath = "/proc/" + std::to_string(pid) + "/status";
586     std::string realPath = "";
587     if (!OHOS::PathToRealPath(cmdLinePath, realPath)) {
588         XCOLLIE_LOGE("Path to realPath failed.");
589         return -1;
590     }
591     std::ifstream file(realPath);
592     if (!file.is_open()) {
593         XCOLLIE_LOGE("open realPath failed.");
594         return -1;
595     }
596     int32_t uid = -1;
597     std::string line;
598     while (std::getline(file, line)) {
599         if (line.compare(0, uidFlag.size(), uidFlag) == 0) {
600             std::istringstream iss(line);
601             std::string temp;
602             if (std::getline(iss, temp, ':') && std::getline(iss, line)) {
603                 std::istringstream(line) >> uid;
604                 XCOLLIE_LOGI("get uid is %{public}d.", uid);
605                 break;
606             }
607         }
608     }
609     file.close();
610     return uid;
611 }
612 
GetAppStartTime(int32_t pid,int64_t tid)613 int64_t GetAppStartTime(int32_t pid, int64_t tid)
614 {
615     static int32_t startTime = -1;
616     static int32_t lastTid = -1;
617     if (startTime > 0 && lastTid == tid) {
618         return startTime;
619     }
620     char filePath[START_PATH_LEN] = {0};
621     if (snprintf_s(filePath, START_PATH_LEN, START_PATH_LEN - 1, "/proc/%d/task/%d/stat", pid, tid) < 0) {
622         XCOLLIE_LOGE("failed to build path, tid=%{public}" PRId64, tid);
623     }
624     std::string realPath = "";
625     if (!OHOS::PathToRealPath(filePath, realPath)) {
626         XCOLLIE_LOGE("Path to realPath failed.");
627         return startTime;
628     }
629     std::string content = "";
630     OHOS::LoadStringFromFile(realPath, content);
631     if (!content.empty()) {
632         std::vector<std::string> strings;
633         SplitStr(content, " ", strings);
634         if (strings.size() <= START_TIME_INDEX) {
635             XCOLLIE_LOGE("get startTime failed.");
636             return startTime;
637         }
638         content = strings[START_TIME_INDEX];
639         if (!IsNum(content)) {
640             return startTime;
641         }
642         startTime = std::stoi(content);
643         lastTid = tid;
644     }
645     return startTime;
646 }
647 
GetReportTimesMap()648 std::map<std::string, int> GetReportTimesMap()
649 {
650     std::map<std::string, int> keyValueMap;
651     std::string reportTimes = system::GetParameter(KEY_REPORT_TIMES_TYPE, "");
652     XCOLLIE_LOGD("get reporttimes value is %{public}s.", reportTimes.c_str());
653     std::stringstream reportParams(reportTimes);
654     std::string line;
655     while (getline(reportParams, line, ';') && !line.empty()) {
656         std::string key;
657         std::string value;
658         if (value.size() > std::to_string(INT32_MAX).length() ||
659             !GetKeyValueByStr(line, key, value, ':')) {
660             XCOLLIE_LOGE("Parse param failed, key:%{public}s value:%{public}s",
661                 key.c_str(), value.c_str());
662             continue;
663         }
664         keyValueMap[key] = std::stoi(value);
665     }
666     return keyValueMap;
667 }
668 
UpdateReportTimes(const std::string & bundleName,int32_t & times,int32_t & checkInterval)669 void UpdateReportTimes(const std::string& bundleName, int32_t& times, int32_t& checkInterval)
670 {
671     std::map<std::string, int> keyValueMap = GetReportTimesMap();
672     auto it = keyValueMap.find(bundleName);
673     if (it != keyValueMap.end()) {
674         times = it->second / MINUTE_TO_S;
675         checkInterval = MINUTE_TO_S * SEC_TO_MILLISEC;
676         XCOLLIE_LOGI("get reportTimes value is %{public}d, checkInterval is %{public}d.",
677             times, checkInterval);
678     }
679 }
680 
IsNum(const std::string & str)681 bool IsNum(const std::string& str)
682 {
683     return std::all_of(str.begin(), str.end(), ::isdigit);
684 }
685 
GetKeyValueByStr(const std::string & tokens,std::string & key,std::string & value,char flag)686 bool GetKeyValueByStr(const std::string& tokens, std::string& key, std::string& value,
687     char flag)
688 {
689     size_t colonPos = tokens.find(flag);
690     if (colonPos == std::string::npos) {
691         return false;
692     }
693     key = tokens.substr(0, colonPos);
694     value = tokens.substr(colonPos + 1);
695     if (key.empty() || value.empty()) {
696         return false;
697     }
698     value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
699     if (!IsNum(value)) {
700         return false;
701     }
702     return true;
703 }
704 } // end of HiviewDFX
705 } // end of OHOS