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