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