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