• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2025 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 "memory_collector_impl.h"
17 
18 #include <csignal>
19 #include <dlfcn.h>
20 #include <fcntl.h>
21 #include <map>
22 #include <mutex>
23 #include <regex>
24 #include <securec.h>
25 #include <sstream>
26 #include <string_ex.h>
27 #include <sys/resource.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 
31 #include "common_util.h"
32 #include "common_utils.h"
33 #include "file_util.h"
34 #include "hiview_logger.h"
35 #include "memory_decorator.h"
36 #include "memory_utils.h"
37 #include "process_status.h"
38 #include "string_util.h"
39 #include "time_util.h"
40 
41 
42 const std::size_t MAX_FILE_SAVE_SIZE = 10;
43 const std::size_t WIDTH = 12;
44 const std::size_t DELAY_MILLISEC = 3;
45 const std::size_t BYTE_2_KB_SHIFT_BITS = 10;
46 using namespace OHOS::HiviewDFX::UCollect;
47 
48 namespace OHOS {
49 namespace HiviewDFX {
50 namespace UCollectUtil {
51 DEFINE_LOG_TAG("UCollectUtil");
52 
53 std::mutex g_memMutex;
54 const int NON_PC_APP_STATE = -1;
55 constexpr char DDR_CUR_FREQ[] = "/sys/class/devfreq/ddrfreq/cur_freq";
56 using IHiaiInfraGetFunc = struct IHiaiInfra*(*)(bool);
57 using IHiaiInfraReleaseFunc = void(*)(struct IHiaiInfra*, bool);
58 
GetCurrTimestamp()59 static std::string GetCurrTimestamp()
60 {
61     auto logTime = TimeUtil::GetMilliseconds() / TimeUtil::SEC_TO_MILLISEC;
62     return TimeUtil::TimestampFormatToDate(logTime, "%Y%m%d%H%M%S");
63 }
64 
GetSavePath(const std::string & preFix,const std::string & ext)65 static std::string GetSavePath(const std::string& preFix, const std::string& ext)
66 {
67     std::lock_guard<std::mutex> lock(g_memMutex);   // lock when get save path
68     if ((!FileUtil::FileExists(MEMINFO_SAVE_DIR)) &&
69         (!FileUtil::ForceCreateDirectory(MEMINFO_SAVE_DIR, FileUtil::FILE_PERM_755))) {
70         HIVIEW_LOGE("create %{public}s dir failed.", MEMINFO_SAVE_DIR);
71         return "";
72     }
73     std::string timeStamp = GetCurrTimestamp();
74     std::string savePath = std::string(MEMINFO_SAVE_DIR) + "/" + preFix + timeStamp + ext;
75     int suffix = 0;
76     while (FileUtil::FileExists(savePath)) {
77         std::stringstream ss;
78         ss << std::string(MEMINFO_SAVE_DIR) << "/" << preFix << timeStamp << "_" << suffix << ext;
79         suffix++;
80         savePath = ss.str();
81     }
82     int fd = 0;
83     if (fd = creat(savePath.c_str(), FileUtil::DEFAULT_FILE_MODE); fd == -1) {
84         HIVIEW_LOGE("create %{public}s failed, errno=%{public}d.", savePath.c_str(), errno);
85         return "";
86     }
87     close(fd);
88     return savePath;
89 }
90 
WriteProcessMemoryToFile(std::string & filePath,const std::vector<ProcessMemory> & processMems)91 static bool WriteProcessMemoryToFile(std::string& filePath, const std::vector<ProcessMemory>& processMems)
92 {
93     FILE* fp = fopen(filePath.c_str(), "w");
94     if (fp == nullptr) {
95         HIVIEW_LOGE("open %{public}s failed.", FileUtil::ExtractFileName(filePath).c_str());
96         return false;
97     }
98     (void)fprintf(fp, "pid\tpname\trss(KB)\tpss(KB)\tswapPss(KB)\tadj\tprocState\n");
99 
100     for (auto& processMem : processMems) {
101         (void)fprintf(fp, "%d\t%s\t%d\t%d\t%d\t%d\t%d\n", processMem.pid, processMem.name.c_str(), processMem.rss,
102             processMem.pss, processMem.swapPss, processMem.adj, processMem.procState);
103     }
104     (void)fclose(fp);
105     return true;
106 }
107 
WriteAIProcessMemToFile(std::string & filePath,const std::vector<AIProcessMem> & aiProcMems)108 static bool WriteAIProcessMemToFile(std::string& filePath, const std::vector<AIProcessMem>& aiProcMems)
109 {
110     std::ofstream file;
111     file.open(filePath.c_str(), std::ios::out | std::ios::trunc);
112     if (!file.is_open()) {
113         HIVIEW_LOGE("open %{public}s failed.", filePath.c_str());
114         return false;
115     }
116 
117     file << "pid" << '\t' << "mem(byte)" << std::endl;
118     for (auto& aiProcMem : aiProcMems) {
119         file << std::setw(WIDTH) << std::left << aiProcMem.pid << '\t' << aiProcMem.size << std::endl;
120     }
121     file.close();
122     return true;
123 }
124 
ReadMemFromAILib(AIProcessMem memInfos[],uint32_t len,int & realSize)125 static bool ReadMemFromAILib(AIProcessMem memInfos[], uint32_t len, int& realSize)
126 {
127     void* handle = dlopen("libhiai_infra_proxy_1.0.z.so", RTLD_LAZY);
128     if (!handle) {
129         HIVIEW_LOGE("dlopen fail, error : %{public}s", dlerror());
130         return false;
131     }
132     IHiaiInfraGetFunc aiInfraGet = reinterpret_cast<IHiaiInfraGetFunc>(dlsym(handle, "IHiaiInfraGet"));
133     if (!aiInfraGet) {
134         HIVIEW_LOGE("dlsym fail, error : %{public}s", dlerror());
135         dlclose(handle);
136         return false;
137     }
138     struct IHiaiInfra* aiInfra = aiInfraGet(true);
139     if (!aiInfra) {
140         HIVIEW_LOGE("aiInfraGet fail");
141         dlclose(handle);
142         return false;
143     }
144     int ret = aiInfra->QueryAllUserAllocatedMemInfo(aiInfra, memInfos, &len, &realSize);
145     IHiaiInfraReleaseFunc aiInfraRelease = reinterpret_cast<IHiaiInfraReleaseFunc>(dlsym(handle, "IHiaiInfraRelease"));
146     if (aiInfraRelease) {
147         aiInfraRelease(aiInfra, true);
148     }
149     dlclose(handle);
150     return (ret == 0) && (realSize >= 0);
151 }
152 
DoClearFiles(const std::string & filePrefix)153 static void DoClearFiles(const std::string& filePrefix)
154 {
155     // Filter files with same prefix
156     std::vector<std::string> files;
157     FileUtil::GetDirFiles(MEMINFO_SAVE_DIR, files, false);
158     std::map<uint64_t, std::string> fileLists;
159     for (auto& file : files) {
160         std::string fileName = FileUtil::ExtractFileName(file);
161         if (!StringUtil::StartWith(fileName, filePrefix)) {
162             continue;
163         }
164         struct stat fileInfo;
165         if (stat(file.c_str(), &fileInfo) != 0) {
166             HIVIEW_LOGE("stat %{public}s failed.", file.c_str());
167             continue;
168         }
169         fileLists.insert(std::pair<uint64_t, std::string>(fileInfo.st_mtime, file));
170     }
171 
172     size_t len = fileLists.size();
173     if (len <= MAX_FILE_SAVE_SIZE) {
174         HIVIEW_LOGI("%{public}zu files with same prefix %{public}s.", len, filePrefix.c_str());
175         return;
176     }
177     // clear more than 10 old files
178     size_t count = len - MAX_FILE_SAVE_SIZE;
179     for (auto it = fileLists.begin(); it != fileLists.end() && count > 0; ++it, --count) {
180         if (!FileUtil::RemoveFile(it->second)) {
181             HIVIEW_LOGE("remove %{public}s failed.", it->second.c_str());
182         }
183         HIVIEW_LOGI("succ remove %{public}s.", it->second.c_str());
184     }
185 }
186 
CollectRawInfo(const std::string & filePath,const std::string & preFix,bool doClearFlag=true)187 static CollectResult<std::string> CollectRawInfo(const std::string& filePath, const std::string& preFix,
188                                                  bool doClearFlag = true)
189 {
190     CollectResult<std::string> result;
191     std::string content;
192     if (!FileUtil::LoadStringFromFile(filePath, content)) {
193         result.retCode = UcError::READ_FAILED;
194         return result;
195     }
196 
197     result.data = GetSavePath(preFix, ".txt");
198     if (result.data.empty()) {
199         result.retCode = UcError::WRITE_FAILED;
200         return result;
201     }
202     HIVIEW_LOGI("save path is %{public}s.", result.data.c_str());
203     if (!FileUtil::SaveStringToFile(result.data, content)) {
204         HIVIEW_LOGE("save to %{public}s failed, content is %{public}s.", result.data.c_str(), content.c_str());
205         result.retCode = UcError::WRITE_FAILED;
206         return result;
207     }
208     if (doClearFlag) {
209         DoClearFiles(preFix);
210     }
211     result.retCode = UcError::SUCCESS;
212     return result;
213 }
214 
SetValueOfProcessMemory(ProcessMemory & processMemory,const std::string & attrName,int32_t value)215 static void SetValueOfProcessMemory(ProcessMemory& processMemory, const std::string& attrName, int32_t value)
216 {
217     static std::map<std::string, std::function<void(ProcessMemory&, int32_t)>> assignFuncMap = {
218         {"Rss", [] (ProcessMemory& memory, int32_t value) {
219             memory.rss = value;
220         }},
221         {"Pss", [] (ProcessMemory& memory, int32_t value) {
222             memory.pss = value;
223         }},
224         {"Shared_Dirty", [] (ProcessMemory& memory, int32_t value) {
225             memory.sharedDirty = value;
226         }},
227         {"Private_Dirty", [] (ProcessMemory& memory, int32_t value) {
228             memory.privateDirty = value;
229         }},
230         {"SwapPss", [] (ProcessMemory& memory, int32_t value) {
231             memory.swapPss = value;
232         }},
233         {"Shared_Clean", [] (ProcessMemory& memory, int32_t value) {
234             memory.sharedClean = value;
235         }},
236         {"Private_Clean", [] (ProcessMemory& memory, int32_t value) {
237             memory.privateClean = value;
238         }},
239     };
240     auto iter = assignFuncMap.find(attrName);
241     if (iter == assignFuncMap.end() || iter->second == nullptr) {
242         HIVIEW_LOGD("%{public}s isn't defined in ProcessMemory.", attrName.c_str());
243         return;
244     }
245     iter->second(processMemory, value);
246 }
247 
InitSmapsOfProcessMemory(const std::string & procDir,ProcessMemory & memory)248 static void InitSmapsOfProcessMemory(const std::string& procDir, ProcessMemory& memory)
249 {
250     std::string smapsFilePath = procDir + SMAPS_ROLLUP;
251     std::string content;
252     if (!FileUtil::LoadStringFromFile(smapsFilePath, content)) {
253         HIVIEW_LOGW("failed to read smaps file:%{public}s.", smapsFilePath.c_str());
254         return;
255     }
256     std::vector<std::string> vec;
257     OHOS::SplitStr(content, "\n", vec);
258     for (const std::string& str : vec) {
259         std::string attrName;
260         int64_t value = 0;
261         if (CommonUtil::ParseTypeAndValue(str, attrName, value)) {
262             SetValueOfProcessMemory(memory, attrName, value);
263         }
264     }
265 }
266 
InitAdjOfProcessMemory(const std::string & procDir,ProcessMemory & memory)267 static void InitAdjOfProcessMemory(const std::string& procDir, ProcessMemory& memory)
268 {
269     std::string adjFilePath = procDir + "/oom_score_adj";
270     std::string content;
271     if (!FileUtil::LoadStringFromFile(adjFilePath, content)) {
272         HIVIEW_LOGW("failed to read adj file:%{public}s.", adjFilePath.c_str());
273         return;
274     }
275     if (!CommonUtil::StrToNum(content, memory.adj)) {
276         HIVIEW_LOGW("failed to translate \"%{public}s\" into number.", content.c_str());
277     }
278 }
279 
InitProcessMemory(int32_t pid,ProcessMemory & memory)280 static bool InitProcessMemory(int32_t pid, ProcessMemory& memory)
281 {
282     std::string procDir = PROC + std::to_string(pid);
283     if (!FileUtil::FileExists(procDir)) {
284         HIVIEW_LOGW("%{public}s isn't exist.", procDir.c_str());
285         return false;
286     }
287     memory.pid = pid;
288     memory.name = CommonUtils::GetProcFullNameByPid(pid);
289     if (memory.name.empty()) {
290         HIVIEW_LOGD("process name is empty, pid=%{public}d.", pid);
291         return false;
292     }
293 #if PC_APP_STATE_COLLECT_ENABLE
294     memory.procState = ProcessStatus::GetInstance().GetProcessState(pid);
295 #else
296     memory.procState = NON_PC_APP_STATE;
297 #endif
298     InitSmapsOfProcessMemory(procDir, memory);
299     InitAdjOfProcessMemory(procDir, memory);
300     return true;
301 }
302 
SetValueOfSysMemory(SysMemory & sysMemory,const std::string & attrName,int32_t value)303 static void SetValueOfSysMemory(SysMemory& sysMemory, const std::string& attrName, int32_t value)
304 {
305     static std::map<std::string, std::function<void(SysMemory&, int32_t)>> assignFuncMap = {
306         {"MemTotal", [] (SysMemory& memory, int32_t value) {
307             memory.memTotal = value;
308         }},
309         {"MemFree", [] (SysMemory& memory, int32_t value) {
310             memory.memFree = value;
311         }},
312         {"MemAvailable", [] (SysMemory& memory, int32_t value) {
313             memory.memAvailable = value;
314         }},
315         {"ZramUsed", [] (SysMemory& memory, int32_t value) {
316             memory.zramUsed = value;
317         }},
318         {"SwapCached", [] (SysMemory& memory, int32_t value) {
319             memory.swapCached = value;
320         }},
321         {"Cached", [] (SysMemory& memory, int32_t value) {
322             memory.cached = value;
323         }},
324     };
325     auto iter = assignFuncMap.find(attrName);
326     if (iter == assignFuncMap.end() || iter->second == nullptr) {
327         HIVIEW_LOGD("%{public}s isn't defined in SysMemory.", attrName.c_str());
328         return;
329     }
330     iter->second(sysMemory, value);
331 }
332 
Create()333 std::shared_ptr<MemoryCollector> MemoryCollector::Create()
334 {
335     return std::make_shared<MemoryDecorator>(std::make_shared<MemoryCollectorImpl>());
336 }
337 
CollectProcessMemory(int32_t pid)338 CollectResult<ProcessMemory> MemoryCollectorImpl::CollectProcessMemory(int32_t pid)
339 {
340     CollectResult<ProcessMemory> result;
341     result.retCode = InitProcessMemory(pid, result.data) ? UcError::SUCCESS : UcError::READ_FAILED;
342     return result;
343 }
344 
CollectSysMemory()345 CollectResult<SysMemory> MemoryCollectorImpl::CollectSysMemory()
346 {
347     CollectResult<SysMemory> result;
348     std::string content;
349     FileUtil::LoadStringFromFile(MEM_INFO, content);
350     std::vector<std::string> vec;
351     OHOS::SplitStr(content, "\n", vec);
352     SysMemory& sysmemory = result.data;
353     for (const std::string& str : vec) {
354         std::string attrName;
355         int64_t value = 0;
356         if (CommonUtil::ParseTypeAndValue(str, attrName, value)) {
357             SetValueOfSysMemory(sysmemory, attrName, value);
358         }
359     }
360     result.retCode = UcError::SUCCESS;
361     return result;
362 }
363 
CollectRawMemInfo()364 CollectResult<std::string> MemoryCollectorImpl::CollectRawMemInfo()
365 {
366     return CollectRawInfo(MEM_INFO, "proc_meminfo_");
367 }
368 
ExportMemView()369 CollectResult<std::string> MemoryCollectorImpl::ExportMemView()
370 {
371     if (FileUtil::FileExists("/proc/memview")) {
372         return CollectRawInfo("/proc/memview", "proc_memview_");
373     }
374     HIVIEW_LOGW("path not exist");
375     CollectResult<std::string> result;
376     return result;
377 }
378 
CollectAllProcessMemory()379 CollectResult<std::vector<ProcessMemory>> MemoryCollectorImpl::CollectAllProcessMemory()
380 {
381     CollectResult<std::vector<ProcessMemory>> result;
382     std::vector<ProcessMemory> procMemoryVec;
383     std::vector<std::string> procFiles;
384     FileUtil::GetDirFiles(PROC, procFiles, false);
385     for (auto& procFile : procFiles) {
386         std::string fileName = FileUtil::ExtractFileName(procFile);
387         int value = 0;
388         if (!StringUtil::StrToInt(fileName, value)) {
389             HIVIEW_LOGD("%{public}s is not num string, value=%{public}d.", fileName.c_str(), value);
390             continue;
391         }
392         ProcessMemory procMemory;
393         if (!InitProcessMemory(value, procMemory)) {
394             continue;
395         }
396         procMemoryVec.emplace_back(procMemory);
397     }
398     result.data = procMemoryVec;
399     result.retCode = UcError::SUCCESS;
400     return result;
401 }
402 
ExportAllProcessMemory()403 CollectResult<std::string> MemoryCollectorImpl::ExportAllProcessMemory()
404 {
405     CollectResult<std::string> result;
406     CollectResult<std::vector<ProcessMemory>> processMemory = this->CollectAllProcessMemory();
407     if (processMemory.retCode != UcError::SUCCESS) {
408         result.retCode = processMemory.retCode;
409         return result;
410     }
411 
412     std::string savePath = GetSavePath("all_processes_mem_", ".txt");
413     if (savePath.empty()) {
414         result.retCode = UcError::WRITE_FAILED;
415         return result;
416     }
417     if (!WriteProcessMemoryToFile(savePath, processMemory.data)) {
418         result.retCode = UcError::WRITE_FAILED;
419         return result;
420     }
421     DoClearFiles("all_processes_mem_");
422     result.data = savePath;
423     result.retCode = UcError::SUCCESS;
424     return result;
425 }
426 
CollectRawSlabInfo()427 CollectResult<std::string> MemoryCollectorImpl::CollectRawSlabInfo()
428 {
429     return CollectRawInfo("/proc/slabinfo", "proc_slabinfo_");
430 }
431 
CollectRawPageTypeInfo()432 CollectResult<std::string> MemoryCollectorImpl::CollectRawPageTypeInfo()
433 {
434     return CollectRawInfo("/proc/pagetypeinfo", "proc_pagetypeinfo_");
435 }
436 
CollectRawDMA()437 CollectResult<std::string> MemoryCollectorImpl::CollectRawDMA()
438 {
439     return CollectRawInfo("/proc/process_dmabuf_info", "proc_process_dmabuf_info_");
440 }
441 
CollectAllAIProcess()442 CollectResult<std::vector<AIProcessMem>> MemoryCollectorImpl::CollectAllAIProcess()
443 {
444     CollectResult<std::vector<AIProcessMem>> result;
445     AIProcessMem memInfos[HIAI_MAX_QUERIED_USER_MEMINFO_LIMIT];
446     int realSize = 0;
447     if (!ReadMemFromAILib(memInfos, HIAI_MAX_QUERIED_USER_MEMINFO_LIMIT, realSize)) {
448         result.retCode = UcError::READ_FAILED;
449         return result;
450     }
451 
452     for (int i = 0; i < realSize; ++i) {
453         result.data.emplace_back(memInfos[i]);
454         HIVIEW_LOGD("memInfo: pid=%{public}d, size=%{public}d.", memInfos[i].pid, memInfos[i].size);
455     }
456     result.retCode = UcError::SUCCESS;
457     return result;
458 }
459 
ExportAllAIProcess()460 CollectResult<std::string> MemoryCollectorImpl::ExportAllAIProcess()
461 {
462     CollectResult<std::string> result;
463     CollectResult<std::vector<AIProcessMem>> aiProcessMem = this->CollectAllAIProcess();
464     if (aiProcessMem.retCode != UcError::SUCCESS) {
465         result.retCode = aiProcessMem.retCode;
466         return result;
467     }
468 
469     std::string savePath = GetSavePath("all_ai_processes_mem_", ".txt");
470     if (savePath.empty()) {
471         result.retCode = UcError::WRITE_FAILED;
472         return result;
473     }
474     if (!WriteAIProcessMemToFile(savePath, aiProcessMem.data)) {
475         result.retCode = UcError::WRITE_FAILED;
476         return result;
477     }
478     DoClearFiles("all_ai_processes_mem_");
479     result.data = savePath;
480     result.retCode = UcError::SUCCESS;
481     return result;
482 }
483 
CollectRawSmaps(int32_t pid)484 CollectResult<std::string> MemoryCollectorImpl::CollectRawSmaps(int32_t pid)
485 {
486     std::string pidStr = std::to_string(pid);
487     std::string fileName = PROC + pidStr + "/smaps";
488     std::string preFix = "proc_smaps_" + pidStr + "_";
489     CollectResult<std::string> result = CollectRawInfo(fileName, preFix, false);
490     DoClearFiles("proc_smaps_");
491     return result;
492 }
493 
GetNewestSnapshotPath(const std::string & path)494 static std::string GetNewestSnapshotPath(const std::string& path)
495 {
496     std::string latestFilePath;
497     time_t newestFileTime = 0;
498     DIR *dir = opendir(path.c_str());
499     if (dir == nullptr) {
500         return "";
501     }
502     while (true) {
503         struct dirent *ptr = readdir(dir);
504         if (ptr == nullptr) {
505             break;
506         }
507         if ((!StringUtil::StartWith(ptr->d_name, "jsheap") && !StringUtil::EndWith(ptr->d_name, "heapsnapshot"))) {
508             continue;
509         }
510 
511         std::string snapshotPath = FileUtil::IncludeTrailingPathDelimiter(path) + std::string(ptr->d_name);
512         struct stat st;
513         if ((stat(snapshotPath.c_str(), &st) == 0) && (st.st_mtime > newestFileTime)) {
514             newestFileTime = st.st_mtime;
515             latestFilePath = snapshotPath;
516         }
517     }
518     closedir(dir);
519     return latestFilePath;
520 }
521 
GetSnapshotPath(const std::string & dirPath,const std::string & pidStr)522 static std::string GetSnapshotPath(const std::string& dirPath, const std::string& pidStr)
523 {
524     std::string fileName = GetNewestSnapshotPath(dirPath);
525     if (fileName.empty()) {
526         HIVIEW_LOGI("not newest snapshot file gerenated.");
527         return "";
528     }
529 
530     std::string parsePidStr;
531     std::regex pattern(".*-(\\d+)-.*");
532     std::smatch match;
533     if (std::regex_search(fileName, match, pattern)) {
534         parsePidStr = match[1].str();
535     }
536     if (pidStr.compare(parsePidStr) != 0) {
537         HIVIEW_LOGI("%{public}s is not suitable pid.", fileName.c_str());
538         return "";
539     }
540     return fileName;
541 }
542 
CollectHprof(int32_t pid)543 CollectResult<std::string> MemoryCollectorImpl::CollectHprof(int32_t pid)
544 {
545     CollectResult<std::string> result;
546     std::string pidStr = std::to_string(pid);
547     if (kill(pid, 40) != 0) {   // kill -40
548         HIVIEW_LOGE("send kill-signal failed, pid=%{public}d, errno=%{public}d.", pid, errno);
549         result.retCode = UcError::UNSUPPORT;
550         return result;
551     }
552     TimeUtil::Sleep(DELAY_MILLISEC);
553 
554     std::string preFix = "jsheap_" + pidStr + "_";
555     std::string savePath = GetSavePath(preFix, ".snapshot");
556     if (savePath.empty()) {
557         result.retCode = UcError::WRITE_FAILED;
558         return result;
559     }
560 
561     std::string srcFilePath = GetSnapshotPath("/data/log/faultlog/temp", pidStr);
562     if (srcFilePath.empty()) {
563         srcFilePath = GetSnapshotPath("/data/log/reliability/resource_leak/memory_leak", pidStr);
564         if (srcFilePath.empty()) {
565             std::string procName = CommonUtils::GetProcFullNameByPid(pid);
566             std::string content = "unsupport dump js heap snapshot: " + procName;
567             if (!FileUtil::SaveStringToFile(savePath, content)) {
568                 HIVIEW_LOGE("save to %{public}s failed, content is %{public}s.", savePath.c_str(), content.c_str());
569                 result.retCode = UcError::WRITE_FAILED;
570                 return result;
571             }
572             DoClearFiles("jsheap_");
573             result.data = savePath;
574             result.retCode = UcError::SUCCESS;
575             return result;
576         }
577     }
578 
579     if (FileUtil::CopyFile(srcFilePath, savePath) != 0) {
580         HIVIEW_LOGE("copy from %{public}s to %{public}s failed.", srcFilePath.c_str(), savePath.c_str());
581         result.retCode = UcError::WRITE_FAILED;
582         return result;
583     }
584     DoClearFiles("jsheap_");
585     result.data = savePath;
586     result.retCode = UcError::SUCCESS;
587     return result;
588 }
589 
CollectProcessVss(int32_t pid)590 CollectResult<uint64_t> MemoryCollectorImpl::CollectProcessVss(int32_t pid)
591 {
592     CollectResult<uint64_t> result;
593     std::string filename = PROC + std::to_string(pid) + STATM;
594     std::string content;
595     FileUtil::LoadStringFromFile(filename, content);
596     uint64_t& vssValue = result.data;
597     if (!content.empty()) {
598         uint64_t tempValue = 0;
599         int retScanf = sscanf_s(content.c_str(), "%llu^*", &tempValue);
600         if (retScanf != -1) {
601             vssValue = tempValue * VSS_BIT;
602         } else {
603             HIVIEW_LOGD("GetVss error! pid = %d", pid);
604         }
605     }
606     result.retCode = UcError::SUCCESS;
607     return result;
608 }
609 
CollectMemoryLimit()610 CollectResult<MemoryLimit> MemoryCollectorImpl::CollectMemoryLimit()
611 {
612     CollectResult<MemoryLimit> result;
613     result.retCode = UcError::READ_FAILED;
614     MemoryLimit& memoryLimit = result.data;
615 
616     struct rlimit rlim;
617     int err = getrlimit(RLIMIT_RSS, &rlim);
618     if (err != 0) {
619         HIVIEW_LOGE("get rss limit error! err = %{public}d", err);
620         return result;
621     }
622     memoryLimit.rssLimit = rlim.rlim_cur >> BYTE_2_KB_SHIFT_BITS;
623 
624     err = getrlimit(RLIMIT_AS, &rlim);
625     if (err != 0) {
626         HIVIEW_LOGE("get vss limit error! err = %{public}d", err);
627         return result;
628     }
629     memoryLimit.vssLimit = rlim.rlim_cur >> BYTE_2_KB_SHIFT_BITS;
630     result.retCode = UcError::SUCCESS;
631     return result;
632 }
633 
CollectDdrFreq()634 CollectResult<uint32_t> MemoryCollectorImpl::CollectDdrFreq()
635 {
636     CollectResult<uint32_t> result;
637     if (!FileUtil::FileExists(DDR_CUR_FREQ)) {
638         return result;
639     }
640     std::string content;
641     FileUtil::LoadStringFromFile(DDR_CUR_FREQ, content);
642     std::stringstream ss(content);
643     ss >> result.data;
644     result.retCode = UcError::SUCCESS;
645     return result;
646 }
647 
CollectProcessMemoryDetail(int32_t pid,GraphicMemOption option)648 CollectResult<ProcessMemoryDetail> MemoryCollectorImpl::CollectProcessMemoryDetail(int32_t pid,
649     GraphicMemOption option)
650 {
651     CollectResult<ProcessMemoryDetail> result;
652     std::string smapsPath = "/proc/" + std::to_string(pid) + "/smaps";
653     if (ParseSmaps(pid, smapsPath, result.data, option)) {
654         result.retCode = UcError::SUCCESS;
655     } else {
656         result.retCode = UcError::READ_FAILED;
657     }
658     return result;
659 }
660 } // UCollectUtil
661 } // HiViewDFX
662 } // OHOS
663