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