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