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