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