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