• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 #include "memory_data_plugin.h"
16 
17 #include <cmath>
18 #include <sstream>
19 
20 #include "dump_usage.h"
21 #include "memory_plugin_result.pbencoder.h"
22 #include "securec.h"
23 #include "smaps_stats.h"
24 #include "transaction/rs_interfaces.h"
25 
26 namespace {
27 using namespace OHOS::Rosen;
28 using namespace OHOS::HDI::Memorytracker::V1_0;
29 using namespace OHOS::Developtools::Profiler;
30 
31 const char* CMD_FORMAT = "memory service meminfo --local ";
32 constexpr size_t READ_BUFFER_SIZE = 1024 * 16;
33 constexpr int BUF_MAX_LEN = 2048;
34 constexpr int MAX_ZRAM_DEVICES = 256;
35 constexpr int ZRAM_KB = 1024;
36 constexpr size_t DEFAULT_READ_SIZE = 4096;
37 const std::string FAKE_DATA_PATH = "/data/local/tmp";
38 constexpr int DATA_START_LINES = 3;
39 constexpr size_t PAGE_SIZE = 4096;
40 constexpr size_t KB_TO_BYTES = 1024;
41 constexpr size_t MB_TO_BYTES = 1024 * 1024;
42 constexpr int INDENT_CATEGORY_NUM = 2;
43 constexpr int INDENT_SUB_TYPE_NUM = 4;
44 const std::string TOTAL_DMA_STR = "Total dma"; // flag for total of DMA memory size
45 const std::string RS_IMAGE_CACHE_START_STR = "RSImageCache:"; // flag for start RSImageCache data
46 const std::string RS_IMAGE_CACHE_END_STR = "  pixelmap:"; // flag for end RSImageCache data
47 const std::string TOTAL_CPU_STR = "Total CPU memory usage"; // flag for total of CPU memory size
48 const std::string SKIA_GPU_STR = "Skia GPU Caches"; // flag for GPU
49 const std::string GPU_LIMIT_STR = "gpu limit"; // flag for gpu limit size
50 const std::string RENDER_SERVICE_NAME = "render_service";
51 const std::string MGR_SVC_START_STR = "----------------------------------WindowManagerService------------";
52 const std::string MGR_SVC_END_STR = "Focus window";
53 const std::string MGR_SVC_INTERVAL_STR = "----------------------------------------------------------";
54 const std::string MEM_PROFILE_STR = "Channel:";
55 } // namespace
56 
MemoryDataPlugin()57 MemoryDataPlugin::MemoryDataPlugin() : meminfoFd_(-1), vmstatFd_(-1), err_(-1)
58 {
59     InitProto2StrVector();
60     SetPath(const_cast<char*>("/proc"));
61     buffer_ = std::make_unique<uint8_t[]>(READ_BUFFER_SIZE);
62 }
63 
~MemoryDataPlugin()64 MemoryDataPlugin::~MemoryDataPlugin()
65 {
66     PROFILER_LOG_INFO(LOG_CORE, "%s:~MemoryDataPlugin!", __func__);
67 
68     buffer_ = nullptr;
69 
70     if (meminfoFd_ > 0) {
71         close(meminfoFd_);
72         meminfoFd_ = -1;
73     }
74     if (vmstatFd_ > 0) {
75         close(vmstatFd_);
76         vmstatFd_ = -1;
77     }
78     for (auto it = pidFds_.begin(); it != pidFds_.end(); it++) {
79         for (int i = FILE_STATUS; i <= FILE_SMAPS; i++) {
80             if (it->second[i] != -1) {
81                 close(it->second[i]);
82             }
83         }
84     }
85     return;
86 }
87 
InitProto2StrVector()88 void MemoryDataPlugin::InitProto2StrVector()
89 {
90     int maxprotobufid = 0;
91     for (unsigned int i = 0; i < sizeof(meminfoMapping) / sizeof(meminfoMapping[0]); i++) {
92         maxprotobufid = std::max(meminfoMapping[i].protobufid, maxprotobufid);
93     }
94     meminfoStrList_.resize(maxprotobufid + 1);
95 
96     for (unsigned int i = 0; i < sizeof(meminfoMapping) / sizeof(meminfoMapping[0]); i++) {
97         meminfoStrList_[meminfoMapping[i].protobufid] = meminfoMapping[i].procstr;
98     }
99 
100     maxprotobufid = 0;
101     for (unsigned int i = 0; i < sizeof(vmeminfoMapping) / sizeof(vmeminfoMapping[0]); i++) {
102         maxprotobufid = std::max(vmeminfoMapping[i].protobufid, maxprotobufid);
103     }
104     vmstatStrList_.resize(maxprotobufid + 1);
105 
106     for (unsigned int i = 0; i < sizeof(vmeminfoMapping) / sizeof(vmeminfoMapping[0]); i++) {
107         vmstatStrList_[vmeminfoMapping[i].protobufid] = vmeminfoMapping[i].procstr;
108     }
109 
110     return;
111 }
112 
InitMemVmemFd()113 int MemoryDataPlugin::InitMemVmemFd()
114 {
115     if (protoConfig_.report_sysmem_mem_info()) {
116         char fileName[PATH_MAX + 1] = {0};
117         char realPath[PATH_MAX + 1] = {0};
118         CHECK_TRUE(snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1, "%s/meminfo", testpath_) >= 0, RET_FAIL,
119                    "%s:snprintf_s error", __func__);
120         if (realpath(fileName, realPath) == nullptr) {
121             const int bufSize = 256;
122             char buf[bufSize] = { 0 };
123             strerror_r(errno, buf, bufSize);
124             PROFILER_LOG_ERROR(LOG_CORE, "%s:realpath failed, errno(%d:%s)", __func__, errno, buf);
125             return RET_FAIL;
126         }
127         meminfoFd_ = open(realPath, O_RDONLY | O_CLOEXEC);
128         if (meminfoFd_ == -1) {
129             const int bufSize = 256;
130             char buf[bufSize] = { 0 };
131             strerror_r(errno, buf, bufSize);
132             PROFILER_LOG_ERROR(LOG_CORE, "%s:open failed, fileName, errno(%d:%s)", __func__, errno, buf);
133             return RET_FAIL;
134         }
135     }
136 
137     if (protoConfig_.report_sysmem_vmem_info()) {
138         char fileName[PATH_MAX + 1] = {0};
139         char realPath[PATH_MAX + 1] = {0};
140         CHECK_TRUE(snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1, "%s/vmstat", testpath_) >= 0, RET_FAIL,
141                    "%s:snprintf_s error", __func__);
142         if (realpath(fileName, realPath) == nullptr) {
143             const int bufSize = 256;
144             char buf[bufSize] = { 0 };
145             strerror_r(errno, buf, bufSize);
146             PROFILER_LOG_ERROR(LOG_CORE, "%s:realpath failed, errno(%d:%s)", __func__, errno, buf);
147             return RET_FAIL;
148         }
149         vmstatFd_ = open(realPath, O_RDONLY | O_CLOEXEC);
150         if (vmstatFd_ == -1) {
151             const int bufSize = 256;
152             char buf[bufSize] = { 0 };
153             strerror_r(errno, buf, bufSize);
154             PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to open(/proc/vmstat), errno(%d:%s)", __func__, errno, buf);
155             return RET_FAIL;
156         }
157     }
158 
159     return RET_SUCC;
160 }
161 
Start(const uint8_t * configData,uint32_t configSize)162 int MemoryDataPlugin::Start(const uint8_t* configData, uint32_t configSize)
163 {
164     CHECK_NOTNULL(buffer_, RET_FAIL, "%s:buffer_ == null", __func__);
165 
166     CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, RET_FAIL,
167                "%s:parseFromArray failed!", __func__);
168 
169     CHECK_TRUE(InitMemVmemFd() == RET_SUCC, RET_FAIL, "InitMemVmemFd fail");
170 
171     if (protoConfig_.sys_meminfo_counters().size() > 0) {
172         for (int i = 0; i < protoConfig_.sys_meminfo_counters().size(); i++) {
173             CHECK_TRUE((size_t)protoConfig_.sys_meminfo_counters(i) < meminfoStrList_.size(), RET_FAIL,
174                        "%s:sys meminfo counter index invalid!", __func__);
175             if (meminfoStrList_[protoConfig_.sys_meminfo_counters(i)]) {
176                 meminfoCounters_.emplace(meminfoStrList_[protoConfig_.sys_meminfo_counters(i)],
177                                          protoConfig_.sys_meminfo_counters(i));
178             }
179         }
180     }
181 
182     if (protoConfig_.sys_vmeminfo_counters().size() > 0) {
183         for (int i = 0; i < protoConfig_.sys_vmeminfo_counters().size(); i++) {
184             CHECK_TRUE((size_t)protoConfig_.sys_vmeminfo_counters(i) < vmstatStrList_.size(), RET_FAIL,
185                        "%s:vmstat counter index invalid!", __func__);
186             if (vmstatStrList_[protoConfig_.sys_vmeminfo_counters(i)]) {
187                 vmstatCounters_.emplace(vmstatStrList_[protoConfig_.sys_vmeminfo_counters(i)],
188                                         protoConfig_.sys_vmeminfo_counters(i));
189             }
190         }
191     }
192 
193     if (protoConfig_.pid().size() > 0) {
194         for (int i = 0; i < protoConfig_.pid().size(); i++) {
195             int32_t pid = protoConfig_.pid(i);
196             pidFds_.emplace(pid, OpenProcPidFiles(pid));
197         }
198     }
199 
200     PROFILER_LOG_INFO(LOG_CORE, "%s:start success!", __func__);
201     return RET_SUCC;
202 }
203 
WriteMeminfo(T & memoryData)204 template <typename T> void MemoryDataPlugin::WriteMeminfo(T& memoryData)
205 {
206     int readsize = ReadFile(meminfoFd_);
207     if (readsize == RET_FAIL) {
208         return;
209     }
210     BufferSplitter totalbuffer((const char*)buffer_.get(), readsize);
211 
212     do {
213         if (!totalbuffer.NextWord(':')) {
214             continue;
215         }
216         const_cast<char *>(totalbuffer.CurWord())[totalbuffer.CurWordSize()] = '\0';
217         auto it = meminfoCounters_.find(totalbuffer.CurWord());
218         if (it == meminfoCounters_.end()) {
219             continue;
220         }
221 
222         int counter_id = it->second;
223         if (!totalbuffer.NextWord(' ')) {
224             continue;
225         }
226         auto value = static_cast<uint64_t>(strtoll(totalbuffer.CurWord(), nullptr, DEC_BASE));
227         auto* meminfo = memoryData.add_meminfo();
228 
229         meminfo->set_key(static_cast<SysMeminfoType>(counter_id));
230         meminfo->set_value(value);
231     } while (totalbuffer.NextLine());
232 
233     return;
234 }
235 
WriteZramData(T & memoryData)236 template <typename T> void MemoryDataPlugin::WriteZramData(T& memoryData)
237 {
238     uint64_t zramSum = 0;
239     for (int i = 0; i < MAX_ZRAM_DEVICES; i++) {
240         std::string path = "/sys/block/zram" + std::to_string(i);
241         if (access(path.c_str(), F_OK) == 0) {
242             uint64_t zramValue = 0;
243             std::string file = path + "/mm_stat";
244             auto fptr = std::unique_ptr<FILE, decltype(&fclose)>{fopen(file.c_str(), "rb"), fclose};
245             if (fptr != nullptr) {
246                 int ret = fscanf_s(fptr.get(), "%*" PRIu64 " %*" PRIu64 " %" PRIu64, &zramValue);
247                 if (ret != 1) {
248                     file = path + "/mem_used_total";
249                     std::string content = ReadFile(file);
250                     char* end = nullptr;
251                     uint64_t value = strtoull(content.c_str(), &end, DEC_BASE);
252                     zramValue = (value > 0) ? value : 0;
253                 }
254             }
255 
256             zramSum += zramValue;
257         }
258     }
259 
260     memoryData.set_zram(zramSum / ZRAM_KB);
261 }
262 
WriteVmstat(T & memoryData)263 template <typename T> void MemoryDataPlugin::WriteVmstat(T& memoryData)
264 {
265     int readsize = ReadFile(vmstatFd_);
266     if (readsize == RET_FAIL) {
267         return;
268     }
269     BufferSplitter totalbuffer((const char*)buffer_.get(), readsize);
270 
271     do {
272         if (!totalbuffer.NextWord(' ')) {
273             continue;
274         }
275         const_cast<char *>(totalbuffer.CurWord())[totalbuffer.CurWordSize()] = '\0';
276         auto it = vmstatCounters_.find(totalbuffer.CurWord());
277         if (it == vmstatCounters_.end()) {
278             continue;
279         }
280 
281         int counter_id = it->second;
282         char* valuestr = const_cast<char *>(totalbuffer.CurWord() + totalbuffer.CurWordSize() + 1);
283         valuestr[totalbuffer.CurLineSize() - (valuestr - totalbuffer.CurLine())] = '\0';
284 
285         auto value = static_cast<uint64_t>(strtoll(valuestr, nullptr, DEC_BASE));
286         auto* vmeminfo = memoryData.add_vmeminfo();
287 
288         vmeminfo->set_key(static_cast<SysVMeminfoType>(counter_id));
289         vmeminfo->set_value(value);
290     } while (totalbuffer.NextLine());
291 
292     return;
293 }
294 
WriteAppsummary(T & processMemoryInfo,SmapsStats & smapInfo)295 template <typename T> void MemoryDataPlugin::WriteAppsummary(T& processMemoryInfo, SmapsStats& smapInfo)
296 {
297     auto* memsummary = processMemoryInfo.mutable_memsummary();
298     memsummary->set_java_heap(smapInfo.GetProcessJavaHeap());
299     memsummary->set_native_heap(smapInfo.GetProcessNativeHeap());
300     memsummary->set_code(smapInfo.GetProcessCode());
301     memsummary->set_stack(smapInfo.GetProcessStack());
302     memsummary->set_graphics(smapInfo.GetProcessGraphics());
303     memsummary->set_private_other(smapInfo.GetProcessPrivateOther());
304     memsummary->set_system(smapInfo.GetProcessSystem());
305 }
306 
ParseNumber(std::string line)307 int MemoryDataPlugin::ParseNumber(std::string line)
308 {
309     return atoi(line.substr(line.find_first_of("01234567890")).c_str());
310 }
311 
GetMemInfoByMemoryService(uint32_t pid,T & processMemoryInfo)312 template <typename T> bool MemoryDataPlugin::GetMemInfoByMemoryService(uint32_t pid, T& processMemoryInfo)
313 {
314     std::string fullCmd = CMD_FORMAT + std::to_string(pid);
315 
316     std::unique_ptr<uint8_t[]> buffer {new (std::nothrow) uint8_t[BUF_MAX_LEN]};
317     std::unique_ptr<FILE, int (*)(FILE*)> fp(popen(fullCmd.c_str(), "r"), pclose);
318     CHECK_TRUE(fp, false, "%s:popen error", __func__);
319 
320     size_t ret = fread(buffer.get(), 1, BUF_MAX_LEN, fp.get());
321     if (ret == 0) {
322         PROFILER_LOG_ERROR(LOG_CORE, "%s:fread failed", __func__);
323     }
324     buffer.get()[BUF_MAX_LEN - 1] = '\0';
325 
326     return ParseMemInfo(reinterpret_cast<char*>(buffer.get()), processMemoryInfo);
327 }
328 
WriteMemoryData(T & memoryDataProto,S smapsInfo)329 template <typename T, typename S> void MemoryDataPlugin::WriteMemoryData(T& memoryDataProto, S smapsInfo)
330 {
331     if (protoConfig_.report_process_tree()) {
332         WriteProcesseList(memoryDataProto);
333     }
334 
335     if (protoConfig_.report_sysmem_mem_info()) {
336         WriteMeminfo(memoryDataProto);
337         WriteZramData(memoryDataProto);
338     }
339 
340     if (protoConfig_.report_sysmem_vmem_info()) {
341         WriteVmstat(memoryDataProto);
342     }
343 
344     for (int i = 0; i < protoConfig_.pid().size(); i++) {
345         int32_t pid = protoConfig_.pid(i);
346         auto* processinfo = memoryDataProto.add_processesinfo();
347         if (protoConfig_.report_process_mem_info()) {
348             WriteProcinfoByPidfds(*processinfo, pid);
349         }
350 
351         bool isReportApp = protoConfig_.report_app_mem_info() && !protoConfig_.report_app_mem_by_memory_service();
352         bool isReportSmaps = protoConfig_.report_smaps_mem_info();
353         if (i == 0 && (isReportApp || isReportSmaps)) {
354             SmapsStats smapInfo;
355             smapInfo.ParseMaps(pid, *processinfo, smapsInfo, isReportApp, isReportSmaps);
356             if (isReportApp) {
357                 WriteAppsummary(*processinfo, smapInfo);
358             }
359         }
360     }
361 
362     if (protoConfig_.report_purgeable_ashmem_info()) {
363         WriteAshmemInfo(memoryDataProto);
364     }
365 
366     if (protoConfig_.report_dma_mem_info()) {
367         WriteDmaInfo(memoryDataProto);
368     }
369 
370     if (protoConfig_.report_gpu_mem_info()) {
371         WriteGpuMemInfo(memoryDataProto);
372     }
373 
374     WriteDumpProcessInfo(memoryDataProto);
375 
376     if (protoConfig_.report_gpu_dump_info()) {
377         WriteGpuDumpInfo(memoryDataProto);
378         WriteManagerServiceInfo(memoryDataProto);
379         WriteProfileMemInfo(memoryDataProto);
380     }
381 }
382 
ReportOptimize(RandomWriteCtx * randomWrite)383 int MemoryDataPlugin::ReportOptimize(RandomWriteCtx* randomWrite)
384 {
385     ProtoEncoder::MemoryData dataProto(randomWrite);
386     ProtoEncoder::SmapsInfo* smapsInfo = nullptr;
387     WriteMemoryData(dataProto, smapsInfo);
388 
389     int msgSize = dataProto.Finish();
390     return msgSize;
391 }
392 
Report(uint8_t * data,uint32_t dataSize)393 int MemoryDataPlugin::Report(uint8_t* data, uint32_t dataSize)
394 {
395     MemoryData dataProto;
396     SmapsInfo* smapsInfo = nullptr;
397     WriteMemoryData(dataProto, smapsInfo);
398 
399     uint32_t length = dataProto.ByteSizeLong();
400     if (length > dataSize) {
401         return -length;
402     }
403     if (dataProto.SerializeToArray(data, length) > 0) {
404         return length;
405     }
406     return 0;
407 }
408 
Stop()409 int MemoryDataPlugin::Stop()
410 {
411     if (meminfoFd_ > 0) {
412         close(meminfoFd_);
413         meminfoFd_ = -1;
414     }
415     if (vmstatFd_ > 0) {
416         close(vmstatFd_);
417         vmstatFd_ = -1;
418     }
419     for (auto it = pidFds_.begin(); it != pidFds_.end(); it++) {
420         for (int i = FILE_STATUS; i <= FILE_SMAPS; i++) {
421             if (it->second[i] != -1) {
422                 close(it->second[i]);
423                 it->second[i] = -1;
424             }
425         }
426     }
427     PROFILER_LOG_INFO(LOG_CORE, "%s:stop success!", __func__);
428     return 0;
429 }
430 
WriteProcinfoByPidfds(T & processMemoryInfo,int32_t pid)431 template <typename T> void MemoryDataPlugin::WriteProcinfoByPidfds(T& processMemoryInfo, int32_t pid)
432 {
433     char* end = nullptr;
434     int32_t readSize;
435 
436     readSize = ReadFile(pidFds_[pid][FILE_STATUS]);
437     if (readSize != RET_FAIL) {
438         WriteProcess(processMemoryInfo, reinterpret_cast<char*>(buffer_.get()), readSize, pid);
439     }
440 
441     if (ReadFile(pidFds_[pid][FILE_OOM]) != RET_FAIL) {
442         processMemoryInfo.set_oom_score_adj(static_cast<int64_t>(strtol(reinterpret_cast<char*>(buffer_.get()),
443                                                                         &end, DEC_BASE)));
444     }
445     return;
446 }
447 
ReadFile(int fd)448 int32_t MemoryDataPlugin::ReadFile(int fd)
449 {
450     if ((buffer_.get() == nullptr) || (fd == -1)) {
451         return RET_FAIL;
452     }
453     int readsize = pread(fd, buffer_.get(), READ_BUFFER_SIZE - 1, 0);
454     if (readsize <= 0) {
455         const int bufSize = 256;
456         char buf[bufSize] = { 0 };
457         strerror_r(errno, buf, bufSize);
458         PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to read(%d), errno(%d:%s)", __func__, fd, errno, buf);
459         err_ = errno;
460         return RET_FAIL;
461     }
462     return readsize;
463 }
464 
ReadFile(const std::string & path)465 std::string MemoryDataPlugin::ReadFile(const std::string& path)
466 {
467     char realPath[PATH_MAX] = {0};
468     CHECK_TRUE((path.length() < PATH_MAX) && (realpath(path.c_str(), realPath) != nullptr), "",
469                "%s:path is invalid: %s, errno=%d", __func__, path.c_str(), errno);
470     int fd = open(realPath, O_RDONLY);
471     if (fd == -1) {
472         const int maxSize = 256;
473         char buf[maxSize] = { 0 };
474         strerror_r(errno, buf, maxSize);
475         PROFILER_LOG_WARN(LOG_CORE, "open file %s FAILED: %s!", path.c_str(), buf);
476         return "";
477     }
478 
479     std::string content;
480     size_t count = 0;
481     while (true) {
482         if (content.size() - count < DEFAULT_READ_SIZE) {
483             content.resize(content.size() + DEFAULT_READ_SIZE);
484         }
485         ssize_t nBytes = read(fd, &content[count], content.size() - count);
486         if (nBytes <= 0) {
487             break;
488         }
489         count += static_cast<size_t>(nBytes);
490     }
491     content.resize(count);
492     CHECK_TRUE(close(fd) != -1, content, "close %s failed, %d", path.c_str(), errno);
493     return content;
494 }
495 
OpenProcPidFiles(int32_t pid)496 std::vector<int> MemoryDataPlugin::OpenProcPidFiles(int32_t pid)
497 {
498     char fileName[PATH_MAX + 1] = {0};
499     char realPath[PATH_MAX + 1] = {0};
500     int count = sizeof(procfdMapping) / sizeof(procfdMapping[0]);
501     std::vector<int> profds;
502 
503     for (int i = 0; i < count; i++) {
504         if (snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1,
505             "%s/%d/%s", testpath_, pid, procfdMapping[i].file) < 0) {
506             PROFILER_LOG_ERROR(LOG_CORE, "%s:snprintf_s error", __func__);
507         }
508         if (realpath(fileName, realPath) == nullptr) {
509             const int bufSize = 256;
510             char buf[bufSize] = { 0 };
511             strerror_r(errno, buf, bufSize);
512             PROFILER_LOG_ERROR(LOG_CORE, "%s:realpath failed, errno(%d:%s)", __func__, errno, buf);
513         }
514         int fd = open(realPath, O_RDONLY | O_CLOEXEC);
515         if (fd == -1) {
516             const int bufSize = 256;
517             char buf[bufSize] = { 0 };
518             strerror_r(errno, buf, bufSize);
519             PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to open(%s), errno(%d:%s)", __func__, fileName, errno, buf);
520         }
521         profds.emplace(profds.begin() + i, fd);
522     }
523     return profds;
524 }
525 
OpenDestDir(const char * dirPath)526 DIR* MemoryDataPlugin::OpenDestDir(const char* dirPath)
527 {
528     DIR* destDir = nullptr;
529 
530     destDir = opendir(dirPath);
531     if (destDir == nullptr) {
532         const int bufSize = 256;
533         char buf[bufSize] = { 0 };
534         strerror_r(errno, buf, bufSize);
535         PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to opendir(%s), errno(%d:%s)", __func__, dirPath, errno, buf);
536     }
537 
538     return destDir;
539 }
540 
GetValidPid(DIR * dirp)541 int32_t MemoryDataPlugin::GetValidPid(DIR* dirp)
542 {
543     if (!dirp) return 0;
544     while (struct dirent* dirEnt = readdir(dirp)) {
545         if (dirEnt->d_type != DT_DIR) {
546             continue;
547         }
548 
549         int32_t pid = atoi(dirEnt->d_name);
550         if (pid) {
551             return pid;
552         }
553     }
554     return 0;
555 }
556 
ReadProcPidFile(int32_t pid,const char * pFileName)557 int32_t MemoryDataPlugin::ReadProcPidFile(int32_t pid, const char* pFileName)
558 {
559     char fileName[PATH_MAX + 1] = {0};
560     char realPath[PATH_MAX + 1] = {0};
561     int fd = -1;
562     ssize_t bytesRead = 0;
563     CHECK_TRUE(snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1, "%s/%d/%s", testpath_, pid, pFileName) >= 0,
564                RET_FAIL, "%s:snprintf_s error", __func__);
565     if (realpath(fileName, realPath) == nullptr) {
566         const int bufSize = 256;
567         char buf[bufSize] = { 0 };
568         strerror_r(errno, buf, bufSize);
569         PROFILER_LOG_ERROR(LOG_CORE, "%s:realpath failed, errno(%d:%s)", __func__, errno, buf);
570         return RET_FAIL;
571     }
572     fd = open(realPath, O_RDONLY | O_CLOEXEC);
573     if (fd == -1) {
574         const int bufSize = 256;
575         char buf[bufSize] = { 0 };
576         strerror_r(errno, buf, bufSize);
577         PROFILER_LOG_INFO(LOG_CORE, "%s:failed to open(%s), errno(%d:%s)", __func__, fileName, errno, buf);
578         err_ = errno;
579         return RET_FAIL;
580     }
581     if (buffer_.get() == nullptr) {
582         PROFILER_LOG_INFO(LOG_CORE, "%s:empty address, buffer_ is NULL", __func__);
583         err_ = RET_NULL_ADDR;
584         close(fd);
585         return RET_FAIL;
586     }
587     bytesRead = read(fd, buffer_.get(), READ_BUFFER_SIZE - 1);
588     if (bytesRead < 0) {
589         close(fd);
590         const int bufSize = 256;
591         char buf[bufSize] = { 0 };
592         strerror_r(errno, buf, bufSize);
593         PROFILER_LOG_INFO(LOG_CORE, "%s:failed to read(%s), errno(%d:%s)", __func__, fileName, errno, buf);
594         err_ = errno;
595         return RET_FAIL;
596     }
597     buffer_.get()[bytesRead] = '\0';
598     close(fd);
599 
600     return bytesRead;
601 }
602 
BufnCmp(const char * src,int srcLen,const char * key,int keyLen)603 bool MemoryDataPlugin::BufnCmp(const char* src, int srcLen, const char* key, int keyLen)
604 {
605     if (!src || !key || (srcLen < keyLen)) {
606         return false;
607     }
608     for (int i = 0; i < keyLen; i++) {
609         if (*src++ != *key++) {
610             return false;
611         }
612     }
613     return true;
614 }
615 
addPidBySort(int32_t pid)616 bool MemoryDataPlugin::addPidBySort(int32_t pid)
617 {
618     auto pidsEnd = seenPids_.end();
619     auto it = std::lower_bound(seenPids_.begin(), pidsEnd, pid);
620     if (it != pidsEnd && *it == pid) {
621         return false;
622     }
623     it = seenPids_.insert(it, std::move(pid));
624     return true;
625 }
626 
GetProcStatusId(const char * src,int srcLen)627 int MemoryDataPlugin::GetProcStatusId(const char* src, int srcLen)
628 {
629     int count = sizeof(procStatusMapping) / sizeof(procStatusMapping[0]);
630     for (int i = 0; i < count; i++) {
631         if (BufnCmp(src, srcLen, procStatusMapping[i].procstr, strlen(procStatusMapping[i].procstr))) {
632             return procStatusMapping[i].procid;
633         }
634     }
635     return RET_FAIL;
636 }
637 
StringToUll(const char * word,uint64_t & value)638 bool MemoryDataPlugin::StringToUll(const char* word, uint64_t& value)
639 {
640     char* end = nullptr;
641     errno = 0;
642     value = strtoull(word, &end, DEC_BASE);
643     if ((errno == ERANGE && (value == ULLONG_MAX)) || (errno != 0 && value == 0)) {
644         return false;
645     } else if (end == word && (*word >= '0' && *word <= '9')) {
646         return false;
647     }
648 
649     return true;
650 }
651 
SetProcessInfo(T & processMemoryInfo,int key,const char * word)652 template <typename T> void MemoryDataPlugin::SetProcessInfo(T& processMemoryInfo, int key, const char* word)
653 {
654     uint64_t value;
655 
656     if ((key >= PRO_TGID && key <= PRO_PURGPIN && key != PRO_NAME) && !StringToUll(word, value)) {
657         PROFILER_LOG_ERROR(LOG_CORE, "MemoryDataPlugin:%s, strtoull failed, key(%d), word(%s)", __func__, key, word);
658         return;
659     }
660 
661     switch (key) {
662         case PRO_TGID:
663             processMemoryInfo.set_pid(static_cast<int32_t>(value));
664             break;
665         case PRO_VMSIZE:
666             processMemoryInfo.set_vm_size_kb(value);
667             break;
668         case PRO_VMRSS:
669             processMemoryInfo.set_vm_rss_kb(value);
670             break;
671         case PRO_RSSANON:
672             processMemoryInfo.set_rss_anon_kb(value);
673             break;
674         case PRO_RSSFILE:
675             processMemoryInfo.set_rss_file_kb(value);
676             break;
677         case PRO_RSSSHMEM:
678             processMemoryInfo.set_rss_shmem_kb(value);
679             break;
680         case PRO_VMSWAP:
681             processMemoryInfo.set_vm_swap_kb(value);
682             break;
683         case PRO_VMLCK:
684             processMemoryInfo.set_vm_locked_kb(value);
685             break;
686         case PRO_VMHWM:
687             processMemoryInfo.set_vm_hwm_kb(value);
688             break;
689         case PRO_PURGSUM:
690             processMemoryInfo.set_purg_sum_kb(value);
691             break;
692         case PRO_PURGPIN:
693             processMemoryInfo.set_purg_pin_kb(value);
694             break;
695         default:
696             break;
697     }
698     return;
699 }
700 
701 template <typename T>
WriteProcess(T & processMemoryInfo,const char * pFile,uint32_t fileLen,int32_t pid)702 void MemoryDataPlugin::WriteProcess(T& processMemoryInfo, const char* pFile, uint32_t fileLen, int32_t pid)
703 {
704     BufferSplitter totalbuffer(const_cast<const char*>(pFile), fileLen + 1);
705 
706     do {
707         totalbuffer.NextWord(':');
708         if (!totalbuffer.CurWord()) {
709             return;
710         }
711 
712         int key = GetProcStatusId(totalbuffer.CurWord(), totalbuffer.CurWordSize());
713         totalbuffer.NextWord('\n');
714         if (!totalbuffer.CurWord()) {
715             continue;
716         }
717         if (key == PRO_NAME) {
718             processMemoryInfo.set_name(totalbuffer.CurWord(), totalbuffer.CurWordSize());
719         }
720         SetProcessInfo(processMemoryInfo, key, totalbuffer.CurWord());
721     } while (totalbuffer.NextLine());
722     // update process name
723     int32_t ret = ReadProcPidFile(pid, "cmdline");
724     if (ret > 0) {
725         processMemoryInfo.set_name(reinterpret_cast<char*>(buffer_.get()),
726                                    strlen(reinterpret_cast<char*>(buffer_.get())));
727     }
728 }
729 
WriteOomInfo(T & processMemoryInfo,int32_t pid)730 template <typename T> void MemoryDataPlugin::WriteOomInfo(T& processMemoryInfo, int32_t pid)
731 {
732     char* end = nullptr;
733 
734     if (ReadProcPidFile(pid, "oom_score_adj") == RET_FAIL) {
735         return;
736     }
737     if (buffer_.get() == nullptr) {
738         PROFILER_LOG_ERROR(LOG_CORE, "%s:invalid params, read buffer_ is NULL", __func__);
739         return;
740     }
741     processMemoryInfo.set_oom_score_adj(static_cast<int64_t>(strtol(reinterpret_cast<char*>(buffer_.get()),
742                                                                     &end, DEC_BASE)));
743 }
744 
WriteProcessInfo(T & memoryData,int32_t pid)745 template <typename T> void MemoryDataPlugin::WriteProcessInfo(T& memoryData, int32_t pid)
746 {
747     int32_t ret = ReadProcPidFile(pid, "status");
748     if (ret == RET_FAIL) {
749         return;
750     }
751     if ((buffer_.get() == nullptr) || (ret == 0)) {
752         return;
753     }
754     auto* processinfo = memoryData.add_processesinfo();
755     WriteProcess(*processinfo, reinterpret_cast<char*>(buffer_.get()), ret, pid);
756     WriteOomInfo(*processinfo, pid);
757 }
758 
WriteProcesseList(T & memoryData)759 template <typename T> void MemoryDataPlugin::WriteProcesseList(T& memoryData)
760 {
761     DIR* procDir = nullptr;
762 
763     procDir = OpenDestDir(testpath_);
764     if (procDir == nullptr) {
765         return;
766     }
767 
768     seenPids_.clear();
769     while (int32_t pid = GetValidPid(procDir)) {
770         addPidBySort(pid);
771     }
772 
773     for (unsigned int i = 0; i < seenPids_.size(); i++) {
774         WriteProcessInfo(memoryData, seenPids_[i]);
775     }
776     closedir(procDir);
777 }
778 
SetAshmemInfo(T & ashmemInfo,int key,const char * word)779 template <typename T> void MemoryDataPlugin::SetAshmemInfo(T& ashmemInfo, int key, const char* word)
780 {
781     int64_t value = 0;
782     int64_t size = 0;
783     switch (key) {
784         case ASHMEM_PROCESS_NAME:
785             ashmemInfo.set_name(word);
786             break;
787         case ASHMEM_PID:
788             value = strtol(word, nullptr, DEC_BASE);
789             CHECK_TRUE(value > 0, NO_RETVAL, "%s:strtoull pid failed", __func__);
790             ashmemInfo.set_pid(value);
791             break;
792         case ASHMEM_FD:
793             value = strtol(word, nullptr, DEC_BASE);
794             CHECK_TRUE(value >= 0, NO_RETVAL, "%s:strtoull fd failed", __func__);
795             ashmemInfo.set_fd(value);
796             break;
797         case ASHMEM_ADJ:
798             value = strtoull(word, nullptr, DEC_BASE);
799             CHECK_TRUE(value >= 0, NO_RETVAL, "%s:strtoull adj failed", __func__);
800             ashmemInfo.set_adj(value);
801             break;
802         case ASHMEM_NAME:
803             ashmemInfo.set_ashmem_name(word);
804             break;
805         case ASHMEM_SIZE:
806             size = strtol(word, nullptr, DEC_BASE);
807             CHECK_TRUE(size >= 0, NO_RETVAL, "%s:strtoull size failed", __func__);
808             ashmemInfo.set_size(size);
809             break;
810         case ASHMEM_ID:
811             value = strtol(word, nullptr, DEC_BASE);
812             CHECK_TRUE(value >= 0, NO_RETVAL, "%s:strtoull id failed", __func__);
813             ashmemInfo.set_id(value);
814             break;
815         case ASHMEM_TIME:
816             size = strtol(word, nullptr, DEC_BASE);
817             CHECK_TRUE(size >= 0, NO_RETVAL, "%s:strtoull time failed", __func__);
818             ashmemInfo.set_time(size);
819             break;
820         case ASHMEM_REF_COUNT:
821             size = strtol(word, nullptr, DEC_BASE);
822             CHECK_TRUE(size >= 0, NO_RETVAL, "%s:strtoull ref_count failed", __func__);
823             ashmemInfo.set_ref_count(size);
824             break;
825         case ASHMEM_PURGED:
826             size = strtol(word, nullptr, DEC_BASE);
827             CHECK_TRUE(size >= 0, NO_RETVAL, "%s:strtoull purged failed", __func__);
828             ashmemInfo.set_purged(size);
829             break;
830         default:
831             break;
832     }
833 }
834 
WriteAshmemInfo(T & dataProto)835 template <typename T> void MemoryDataPlugin::WriteAshmemInfo(T& dataProto)
836 {
837     std::string path = protoConfig_.report_fake_data() ? FAKE_DATA_PATH : std::string(testpath_);
838     std::string file = path + "/purgeable_ashmem_trigger";
839     std::ifstream input(file, std::ios::in);
840     if (input.fail()) {
841         PROFILER_LOG_ERROR(LOG_CORE, "%s:open %s failed, errno = %d", __func__, file.c_str(), errno);
842         return;
843     }
844 
845     int lines = 0;
846     do {
847         if (!input.good()) {
848             return;
849         }
850 
851         std::string line;
852         getline(input, line);
853         line += '\n';
854         if (++lines <= DATA_START_LINES) {
855             // The first three lines are not data.
856             continue;
857         }
858 
859         BufferSplitter totalBuffer(static_cast<const char*>(line.c_str()), line.size() + 1);
860         if (!totalBuffer.NextWord(',')) {
861             break;
862         }
863         auto* ashmemInfo = dataProto.add_ashmeminfo();
864         for (int i = ASHMEM_PROCESS_NAME; i <= ASHMEM_PURGED; i++) {
865             std::string curWord = std::string(totalBuffer.CurWord(), totalBuffer.CurWordSize());
866             SetAshmemInfo(*ashmemInfo, i, curWord.c_str());
867             char delimiter = (i == ASHMEM_REF_COUNT) ? '\n' : ',';
868             if (!totalBuffer.NextWord(delimiter)) {
869                 break;
870             }
871         }
872     } while (!input.eof());
873     input.close();
874 }
875 
SetDmaInfo(T & dmaInfo,int key,const char * word)876 template <typename T> void MemoryDataPlugin::SetDmaInfo(T& dmaInfo, int key, const char* word)
877 {
878     int64_t value = 0;
879     int64_t size = 0;
880     switch (key) {
881         case DMA_NAME:
882             dmaInfo.set_name(word);
883             break;
884         case DMA_PID:
885             value = strtol(word, nullptr, DEC_BASE);
886             CHECK_TRUE(value > 0, NO_RETVAL, "%s:strtoull pid failed", __func__);
887             dmaInfo.set_pid(value);
888             break;
889         case DMA_FD:
890             value = strtol(word, nullptr, DEC_BASE);
891             CHECK_TRUE(value >= 0, NO_RETVAL, "%s:strtoull fd failed", __func__);
892             dmaInfo.set_fd(value);
893             break;
894         case DMA_SIZE:
895             size = strtol(word, nullptr, DEC_BASE);
896             CHECK_TRUE(size >= 0, NO_RETVAL, "%s:strtoull size failed", __func__);
897             dmaInfo.set_size(size);
898             break;
899         case DMA_INO:
900             value = strtol(word, nullptr, DEC_BASE);
901             CHECK_TRUE(value >= 0, NO_RETVAL, "%s:strtoull magic failed", __func__);
902             dmaInfo.set_ino(value);
903             break;
904         case DMA_EXP_PID:
905             value = strtol(word, nullptr, DEC_BASE);
906             CHECK_TRUE(value > 0, NO_RETVAL, "%s:strtoull exp_pid failed", __func__);
907             dmaInfo.set_exp_pid(value);
908             break;
909         case DMA_EXP_TASK_COMM:
910             dmaInfo.set_exp_task_comm(word);
911             break;
912         case DMA_BUF_NAME:
913             dmaInfo.set_buf_name(word);
914             break;
915         case DMA_EXP_NAME:
916             if (*(word + strlen(word) - 1) == '\r') {
917                 dmaInfo.set_exp_name(std::string(word, strlen(word) - 1));
918             } else {
919                 dmaInfo.set_exp_name(word);
920             }
921             break;
922         default:
923             break;
924     }
925 }
926 
WriteDmaInfo(T & dataProto)927 template <typename T> void MemoryDataPlugin::WriteDmaInfo(T& dataProto)
928 {
929     std::string file = std::string(testpath_) + "/process_dmabuf_info";
930     std::ifstream input(file, std::ios::in);
931     if (input.fail()) {
932         PROFILER_LOG_ERROR(LOG_CORE, "%s:open %s failed, errno = %d", __func__, file.c_str(), errno);
933         return;
934     }
935 
936     int lines = 0;
937     do {
938         if (!input.good()) {
939             return;
940         }
941 
942         std::string line;
943         getline(input, line);
944         line += '\n';
945         if (++lines < DATA_START_LINES
946             || strncmp(line.c_str(), TOTAL_DMA_STR.c_str(), TOTAL_DMA_STR.size()) == 0) {
947             continue; // not data.
948         }
949 
950         BufferSplitter totalBuffer(static_cast<const char*>(line.c_str()), line.size() + 1);
951         if (!totalBuffer.NextWord(' ')) {
952             break;
953         }
954         auto* dmaInfo = dataProto.add_dmainfo();
955         for (int i = DMA_NAME; i <= DMA_EXP_NAME; i++) {
956             std::string curWord = std::string(totalBuffer.CurWord(), totalBuffer.CurWordSize());
957             SetDmaInfo(*dmaInfo, i, curWord.c_str());
958             char delimiter = (i == DMA_BUF_NAME) ? '\n' : ' ';
959             if (!totalBuffer.NextWord(delimiter)) {
960                 break;
961             }
962         }
963     } while (!input.eof());
964     input.close();
965 }
966 
SetGpuProcessInfo(T & gpuProcessInfo,int key,const char * word)967 template <typename T> void MemoryDataPlugin::SetGpuProcessInfo(T& gpuProcessInfo, int key, const char* word)
968 {
969     int64_t value = 0;
970     int64_t size = 0;
971     switch (key) {
972         case GPU_ADDR:
973             gpuProcessInfo.set_addr(word);
974             break;
975         case GPU_TID:
976             value = strtol(word, nullptr, DEC_BASE);
977             CHECK_TRUE(value > 0, NO_RETVAL, "%s:strtoull tid failed", __func__);
978             gpuProcessInfo.set_tid(value);
979             break;
980         case GPU_PID:
981             value = strtol(word, nullptr, DEC_BASE);
982             CHECK_TRUE(value > 0, NO_RETVAL, "%s:strtoull pid failed", __func__);
983             gpuProcessInfo.set_pid(value);
984             break;
985         case GPU_USED_SIZE:
986             size = strtol(word, nullptr, DEC_BASE);
987             CHECK_TRUE(size >= 0, NO_RETVAL, "%s:strtoull used_gpu_size failed", __func__);
988             gpuProcessInfo.set_used_gpu_size(size * PAGE_SIZE);
989             break;
990         default:
991             break;
992     }
993 }
994 
WriteGpuMemInfo(T & dataProto)995 template <typename T> void MemoryDataPlugin::WriteGpuMemInfo(T& dataProto)
996 {
997     std::string path = protoConfig_.report_fake_data() ? FAKE_DATA_PATH : std::string(testpath_);
998     std::string file = path + "/gpu_memory";
999     std::ifstream input(file, std::ios::in);
1000     if (input.fail()) {
1001         PROFILER_LOG_ERROR(LOG_CORE, "%s:open %s failed, errno = %d", __func__, file.c_str(), errno);
1002         return;
1003     }
1004 
1005     std::string line;
1006     getline(input, line);
1007     line += '\n';
1008 
1009     BufferSplitter totalBuffer(static_cast<const char*>(line.c_str()), line.size() + 1);
1010     auto* gpuMemoryInfo = dataProto.add_gpumemoryinfo();
1011     if (totalBuffer.NextWord(' ')) {
1012         gpuMemoryInfo->set_gpu_name(std::string(totalBuffer.CurWord(), totalBuffer.CurWordSize()));
1013     }
1014     if (totalBuffer.NextWord('\n')) {
1015         gpuMemoryInfo->set_all_gpu_size((strtoull(totalBuffer.CurWord(), nullptr, DEC_BASE) * PAGE_SIZE));
1016     }
1017 
1018     do {
1019         if (!input.good()) {
1020             return;
1021         }
1022 
1023         getline(input, line);
1024         line += '\n';
1025 
1026         BufferSplitter buffer(static_cast<const char*>(line.c_str()), line.size() + 1);
1027         if (!buffer.NextWord(' ')) {
1028             break;
1029         }
1030         auto* gpuProcessInfo = gpuMemoryInfo->add_gpu_process_info();
1031         for (int i = GPU_ADDR; i <= GPU_USED_SIZE; i++) {
1032             std::string curWord = std::string(buffer.CurWord(), buffer.CurWordSize());
1033             SetGpuProcessInfo(*gpuProcessInfo, i, curWord.c_str());
1034             if (!buffer.NextWord(' ')) {
1035                 break;
1036             }
1037         }
1038     } while (!input.eof());
1039     input.close();
1040 }
1041 
RunCommand(const std::string & cmd)1042 std::string MemoryDataPlugin::RunCommand(const std::string& cmd)
1043 {
1044     std::string ret = "";
1045     std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
1046     if (!pipe) {
1047         PROFILER_LOG_ERROR(LOG_CORE, "%s:popen(%s) error", __func__, cmd.c_str());
1048         return ret;
1049     }
1050 
1051     std::array<char, READ_BUFFER_SIZE> buffer;
1052     while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
1053         ret += buffer.data();
1054     }
1055     return ret;
1056 }
1057 
GetIndentNum(const std::string & line)1058 int MemoryDataPlugin::GetIndentNum(const std::string& line)
1059 {
1060     int indentNum = 0;
1061     while (isspace(line[indentNum])) {
1062         indentNum++;
1063     }
1064     return indentNum;
1065 }
1066 
SizeToBytes(const std::string & sizeStr,const std::string & type)1067 uint64_t MemoryDataPlugin::SizeToBytes(const std::string& sizeStr, const std::string& type)
1068 {
1069     auto size = std::atof(sizeStr.c_str());
1070     uint64_t byteSize = round(size);
1071     if (type == "KB") {
1072         byteSize = round(size * KB_TO_BYTES);
1073     } else if (type == "MB") {
1074         byteSize = round(size * MB_TO_BYTES);
1075     }
1076     return byteSize;
1077 }
1078 
SetGpuDumpInfo(T & gpuDumpInfo,BufferSplitter & totalBuffer)1079 template <typename T> bool MemoryDataPlugin::SetGpuDumpInfo(T& gpuDumpInfo, BufferSplitter& totalBuffer)
1080 {
1081     int ret = totalBuffer.NextLine();
1082     CHECK_TRUE(ret, false, "totalBuffer is end!");
1083     std::string line = std::string(totalBuffer.CurLine());
1084     int indentNum = GetIndentNum(line);
1085     while (indentNum > 0) {
1086         if (indentNum == INDENT_CATEGORY_NUM && totalBuffer.NextWord(':')) {
1087             auto* gpuDetailInfo = gpuDumpInfo.add_gpu_detail_info();
1088             gpuDetailInfo->set_module_name(std::string(totalBuffer.CurWord(), totalBuffer.CurWordSize()));
1089             ret = totalBuffer.NextLine();
1090             CHECK_TRUE(ret, false, "totalBuffer is end!");
1091             line = std::string(totalBuffer.CurLine());
1092             indentNum = GetIndentNum(line);
1093             while (indentNum == INDENT_SUB_TYPE_NUM && totalBuffer.NextWord(':')) {
1094                 auto* gpuSubInfo = gpuDetailInfo->add_gpu_sub_info();
1095                 gpuSubInfo->set_category_name(std::string(totalBuffer.CurWord(), totalBuffer.CurWordSize()));
1096                 std::string size = "";
1097                 if (totalBuffer.NextWord(' ')) {
1098                     size = std::string(totalBuffer.CurWord(), totalBuffer.CurWordSize());
1099                 }
1100                 if (totalBuffer.NextWord(' ')) {
1101                     std::string type = std::string(totalBuffer.CurWord(), totalBuffer.CurWordSize());
1102                     gpuSubInfo->set_size(SizeToBytes(size, type));
1103                 }
1104                 if (totalBuffer.NextWord(' ')) {
1105                     gpuSubInfo->set_entry_num(strtoull(totalBuffer.CurWord() + 1, nullptr, DEC_BASE));
1106                 }
1107                 ret = totalBuffer.NextLine();
1108                 CHECK_TRUE(ret, false, "totalBuffer is end!");
1109                 line = std::string(totalBuffer.CurLine());
1110                 indentNum = GetIndentNum(line);
1111             }
1112         }
1113     }
1114 
1115     ret = totalBuffer.NextLine();
1116     CHECK_TRUE(ret, false, "totalBuffer is end!");
1117     std::string size = "";
1118     if (totalBuffer.NextWord('(') && totalBuffer.NextWord(' ')) {
1119         size = std::string(totalBuffer.CurWord(), totalBuffer.CurWordSize());
1120     }
1121     if (totalBuffer.NextWord(' ')) {
1122         std::string type = std::string(totalBuffer.CurWord(), totalBuffer.CurWordSize());
1123         gpuDumpInfo.set_gpu_purgeable_size(SizeToBytes(size, type));
1124     }
1125     return true;
1126 }
1127 
SetRSImageDumpInfo(T & rsDumpInfo,int key,const char * word)1128 template <typename T> void MemoryDataPlugin::SetRSImageDumpInfo(T& rsDumpInfo, int key, const char* word)
1129 {
1130     int64_t pid = 0;
1131     int64_t size = 0;
1132     size_t dataLen = strlen(word) > 1 ? strlen(word) - 1 : 0;
1133     switch (key) {
1134         case RS_SIZE:
1135             size = strtol(word, nullptr, DEC_BASE);
1136             CHECK_TRUE(size >= 0, NO_RETVAL, "%s:strtoull size failed", __func__);
1137             rsDumpInfo.set_size(size);
1138             break;
1139         case RS_TYPE:
1140             if (*(word + dataLen) == '\t') {
1141                 rsDumpInfo.set_type(std::string(word, dataLen));
1142             } else {
1143                 rsDumpInfo.set_type(word);
1144             }
1145             break;
1146         case RS_PID:
1147             pid = strtol(word, nullptr, DEC_BASE);
1148             CHECK_TRUE(pid >= 0, NO_RETVAL, "%s:strtoull pid failed", __func__);
1149             rsDumpInfo.set_pid(pid);
1150             break;
1151         case RS_SURFACENAME:
1152             if (*(word + dataLen) == '\t') {
1153                 rsDumpInfo.set_surface_name(std::string(word, dataLen));
1154             } else {
1155                 rsDumpInfo.set_surface_name(word);
1156             }
1157             break;
1158         default:
1159             break;
1160     }
1161 }
1162 
WriteGpuDumpInfo(T & dataProto)1163 template <typename T> void MemoryDataPlugin::WriteGpuDumpInfo(T& dataProto)
1164 {
1165     std::string content = "";
1166     if (!protoConfig_.report_fake_data()) {
1167         if (strcmp(testpath_, "/proc") == 0) {
1168             content = RunCommand("hidumper -s 10 '-a dumpMem'");
1169         } else {
1170             // for UT
1171             content = ReadFile(std::string(testpath_) + "/dumpMem.txt");
1172         }
1173     } else {
1174         content = ReadFile(FAKE_DATA_PATH + "/dumpMem.txt");
1175     }
1176     CHECK_TRUE(content != "", NO_RETVAL, "hidumper no data!");
1177 
1178     BufferSplitter totalBuffer((const char*)content.c_str(), content.size() + 1);
1179     do {
1180         std::string line = totalBuffer.CurLine();
1181         if (strncmp(line.c_str(), RS_IMAGE_CACHE_START_STR.c_str(), RS_IMAGE_CACHE_START_STR.size()) == 0) {
1182             totalBuffer.NextLine(); // data starts from the next line
1183             while (totalBuffer.NextLine()) {
1184                 line = totalBuffer.CurLine();
1185                 if (strncmp(line.c_str(), RS_IMAGE_CACHE_END_STR.c_str(), RS_IMAGE_CACHE_END_STR.size()) == 0) {
1186                     break;
1187                 }
1188                 auto* rsDumpInfo = dataProto.add_rsdumpinfo();
1189                 for (int i = RS_SIZE; i <= RS_SURFACENAME; i++) {
1190                     if (!totalBuffer.NextWord(' ')) {
1191                         break;
1192                     }
1193                     std::string curWord = std::string(totalBuffer.CurWord(), totalBuffer.CurWordSize());
1194                     SetRSImageDumpInfo(*rsDumpInfo, i, curWord.c_str());
1195                 }
1196             }
1197         } else if (strncmp(line.c_str(), TOTAL_CPU_STR.c_str(), TOTAL_CPU_STR.size()) == 0) {
1198             totalBuffer.NextLine(); // data starts from the next line
1199             if (!totalBuffer.NextWord(' ')) {
1200                 break;
1201             }
1202             auto* cpuDumpInfo = dataProto.add_cpudumpinfo();
1203             cpuDumpInfo->set_total_cpu_memory_size(strtoull(totalBuffer.CurWord(), nullptr, DEC_BASE));
1204         } else if (strncmp(line.c_str(), SKIA_GPU_STR.c_str(), SKIA_GPU_STR.size()) == 0) {
1205             auto* gpuDumpInfo = dataProto.add_gpudumpinfo();
1206             if (totalBuffer.NextWord(':') && (totalBuffer.NextWord(' ') || totalBuffer.NextWord('\n'))) {
1207                 std::string name = std::string(totalBuffer.CurWord(), totalBuffer.CurWordSize());
1208                 gpuDumpInfo->set_window_name(name.substr(0, name.find("\r")));
1209             }
1210             if (totalBuffer.NextWord('\n')) {
1211                 gpuDumpInfo->set_id(strtoull(totalBuffer.CurWord(), nullptr, DEC_BASE));
1212             }
1213             SetGpuDumpInfo(*gpuDumpInfo, totalBuffer);
1214         } else if (strncmp(line.c_str(), GPU_LIMIT_STR.c_str(), GPU_LIMIT_STR.size()) == 0) {
1215             if (totalBuffer.NextWord('=') && totalBuffer.NextWord(' ')) {
1216                 dataProto.set_gpu_limit_size(strtoull(totalBuffer.CurWord(), nullptr, DEC_BASE));
1217             }
1218             if (totalBuffer.NextWord('=') && totalBuffer.NextWord(' ')) {
1219                 dataProto.set_gpu_used_size(strtoull(totalBuffer.CurWord(), nullptr, DEC_BASE));
1220             }
1221             break;
1222         }
1223     } while (totalBuffer.NextLine());
1224 }
1225 
isRenderService(int pid)1226 bool MemoryDataPlugin::isRenderService(int pid)
1227 {
1228     if (ReadProcPidFile(pid, "cmdline") > 0) {
1229         std::string processName(reinterpret_cast<char*>(buffer_.get()), strlen(reinterpret_cast<char*>(buffer_.get())));
1230         int index = static_cast<int>(processName.size()) - static_cast<int>(RENDER_SERVICE_NAME.size());
1231         if (index >= 0 && processName.substr(index) == RENDER_SERVICE_NAME) {
1232             return true;
1233         }
1234     }
1235     return false;
1236 }
1237 
GetRenderServiceGlSize(int32_t pid,GraphicsMemory & graphicsMemory)1238 bool MemoryDataPlugin::GetRenderServiceGlSize(int32_t pid, GraphicsMemory& graphicsMemory)
1239 {
1240     // refers hidumper
1241     // https://gitee.com/openharmony/hiviewdfx_hidumper/blob/master/frameworks/native/src/executor/memory/memory_info.cpp#L203
1242     bool ret = false;
1243     sptr<IMemoryTrackerInterface> memtrack = IMemoryTrackerInterface::Get(true);
1244     if (memtrack == nullptr) {
1245         PROFILER_LOG_ERROR(LOG_CORE, "%s: get IMemoryTrackerInterface failed", __func__);
1246         return ret;
1247     }
1248 
1249     std::vector<MemoryRecord> records;
1250     if (memtrack->GetDevMem(pid, MEMORY_TRACKER_TYPE_GL, records) == HDF_SUCCESS) {
1251         uint64_t value = 0;
1252         for (const auto& record : records) {
1253             if ((static_cast<uint32_t>(record.flags) & FLAG_UNMAPPED) == FLAG_UNMAPPED) {
1254                 value = static_cast<uint64_t>(record.size / KB_TO_BYTES);
1255                 break;
1256             }
1257         }
1258         graphicsMemory.gl = value;
1259         ret = true;
1260     }
1261     return ret;
1262 }
1263 
WriteDumpProcessInfo(T & dataProto)1264 template <typename T> void MemoryDataPlugin::WriteDumpProcessInfo(T& dataProto)
1265 {
1266     for (int i = 0; i < protoConfig_.pid().size(); i++) {
1267         int32_t pid = protoConfig_.pid(i);
1268         auto* processesInfo = dataProto.add_processesinfo();
1269         processesInfo->set_pid(pid);
1270 
1271         // refers hidumper
1272         // https://gitee.com/openharmony/hiviewdfx_hidumper/blob/master/frameworks/native/src/executor/memory/memory_info.cpp#L260
1273         GraphicsMemory graphicsMemory;
1274         std::unique_ptr<OHOS::HiviewDFX::DumpUsage> dumpUsage = std::make_unique<OHOS::HiviewDFX::DumpUsage>();
1275         graphicsMemory.graph = dumpUsage->GetDma(pid);
1276         if (isRenderService(pid)) {
1277             std::vector<MemoryGraphic> memGraphicVec = RSInterfaces::GetInstance().GetMemoryGraphics();
1278             uint64_t sumPidsMemGL = 0;
1279             for (auto it = memGraphicVec.begin(); it != memGraphicVec.end(); it++) {
1280                 sumPidsMemGL += it->GetGpuMemorySize();
1281             }
1282             sumPidsMemGL = static_cast<uint64_t>(sumPidsMemGL / KB_TO_BYTES);
1283 
1284             if (GetRenderServiceGlSize(pid, graphicsMemory)) {
1285                 graphicsMemory.gl -= sumPidsMemGL;
1286                 processesInfo->set_gl_pss_kb(graphicsMemory.gl);
1287                 processesInfo->set_graph_pss_kb(graphicsMemory.graph);
1288             }
1289         } else {
1290             GetRenderServiceGlSize(pid, graphicsMemory);
1291             auto& rsClient = RSInterfaces::GetInstance();
1292             std::unique_ptr<MemoryGraphic> memGraphic = std::make_unique<MemoryGraphic>(rsClient.GetMemoryGraphic(pid));
1293             graphicsMemory.gl += memGraphic->GetGpuMemorySize() / KB_TO_BYTES;
1294             processesInfo->set_gl_pss_kb(graphicsMemory.gl);
1295             processesInfo->set_graph_pss_kb(graphicsMemory.graph);
1296         }
1297     }
1298 }
1299 
SetManagerServiceInfo(T & windowinfo,int key,const char * word)1300 template <typename T> void MemoryDataPlugin::SetManagerServiceInfo(T& windowinfo, int key, const char* word)
1301 {
1302     int64_t pid = 0;
1303     switch (key) {
1304         case WINDOW_NAME:
1305             windowinfo.set_window_name(word);
1306             break;
1307         case WINDOW_PID:
1308             pid = strtol(word, nullptr, DEC_BASE);
1309             CHECK_TRUE(pid >= 0, NO_RETVAL, "%s:strtoull pid failed", __func__);
1310             windowinfo.set_pid(pid);
1311             break;
1312         default:
1313             break;
1314     }
1315 }
1316 
WriteManagerServiceInfo(T & dataProto)1317 template <typename T> void MemoryDataPlugin::WriteManagerServiceInfo(T& dataProto)
1318 {
1319     std::string content = "";
1320     if (strcmp(testpath_, "/proc") == 0) {
1321         content = RunCommand("hidumper -s WindowManagerService -a '-a'");
1322     } else {
1323         // for UT
1324         content = ReadFile(std::string(testpath_) + "/window_manager_service.txt");
1325     }
1326     CHECK_TRUE(content != "", NO_RETVAL, "hidumper WindowManagerService no data!");
1327 
1328     BufferSplitter totalBuffer((const char*)content.c_str(), content.size() + 1);
1329     do {
1330         std::string line = totalBuffer.CurLine();
1331         if (strncmp(line.c_str(), MGR_SVC_START_STR.c_str(), MGR_SVC_START_STR.size()) == 0) {
1332             totalBuffer.NextLine();
1333             totalBuffer.NextLine(); // data starts from the next line
1334             while (totalBuffer.NextLine()) {
1335                 line = totalBuffer.CurLine();
1336                 if (strncmp(line.c_str(), MGR_SVC_INTERVAL_STR.c_str(), MGR_SVC_INTERVAL_STR.size()) == 0) {
1337                     continue;
1338                 }
1339 
1340                 if (strncmp(line.c_str(), MGR_SVC_END_STR.c_str(), MGR_SVC_END_STR.size()) == 0) {
1341                     return;
1342                 }
1343 
1344                 auto* windowinfo = dataProto.add_windowinfo();
1345                 for (int i = WINDOW_NAME; i <= WINDOW_PID; i++) {
1346                     if (!totalBuffer.NextWord(' ')) {
1347                         break;
1348                     }
1349                     std::string curWord = std::string(totalBuffer.CurWord(), totalBuffer.CurWordSize());
1350                     SetManagerServiceInfo(*windowinfo, i, curWord.c_str());
1351                 }
1352             }
1353         }
1354     } while (totalBuffer.NextLine());
1355 }
1356 
WriteProfileMemInfo(T & dataProto)1357 template <typename T> void MemoryDataPlugin::WriteProfileMemInfo(T& dataProto)
1358 {
1359     for (int i = 0; i < protoConfig_.pid().size(); i++) {
1360         std::string file = "";
1361         if (!protoConfig_.report_fake_data()) {
1362             if (strcmp(testpath_, "/proc") == 0) {
1363                 file = "/sys/kernel/debug/mali0/ctx/" + std::to_string(protoConfig_.pid(i)) + "_0/mem_profile";
1364             } else {
1365                 // for UT
1366                 file = std::string(testpath_) + "/mem_profile.txt";
1367             }
1368         } else {
1369             file = FAKE_DATA_PATH + "/mem_profile.txt";
1370         }
1371 
1372         std::ifstream input(file, std::ios::in);
1373         if (input.fail()) {
1374             PROFILER_LOG_ERROR(LOG_CORE, "%s:open %s failed, errno = %d", __func__, file.c_str(), errno);
1375             return;
1376         }
1377 
1378         do {
1379             if (!input.good()) {
1380                 return;
1381             }
1382 
1383             std::string line;
1384             getline(input, line);
1385             line += '\n';
1386 
1387             if (strncmp(line.c_str(), MEM_PROFILE_STR.c_str(), MEM_PROFILE_STR.size()) == 0) {
1388                 auto* profileMemInfo = dataProto.add_profilememinfo();
1389                 BufferSplitter totalBuffer(static_cast<const char*>(line.c_str()), line.size() + 1);
1390                 if (totalBuffer.NextWord(':') && totalBuffer.NextWord('(')) {
1391                     size_t dataLen =
1392                         totalBuffer.CurWordSize() > 1 ? static_cast<size_t>(totalBuffer.CurWordSize() - 1) : 0;
1393                     profileMemInfo->set_channel(std::string(totalBuffer.CurWord(), dataLen));
1394                 }
1395                 if (totalBuffer.NextWord(':') && totalBuffer.NextWord(')')) {
1396                     profileMemInfo->set_total_memory_size(strtoull(totalBuffer.CurWord(), nullptr, DEC_BASE));
1397                 }
1398             }
1399         } while (!input.eof());
1400         input.close();
1401     }
1402 }
1403