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