1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
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 <sstream>
18
19 #include "buffer_splitter.h"
20 #include "securec.h"
21 #include "smaps_stats.h"
22
23 namespace {
24 const char* CMD_FORMAT = "memory service meminfo --local ";
25 constexpr size_t READ_BUFFER_SIZE = 1024 * 16;
26 constexpr int BUF_MAX_LEN = 2048;
27 constexpr int MAX_ZRAM_DEVICES = 256;
28 constexpr int ZRAM_KB = 1024;
29 constexpr size_t DEFAULT_READ_SIZE = 4096;
30 } // namespace
31
MemoryDataPlugin()32 MemoryDataPlugin::MemoryDataPlugin()
33 : buffer_(new (std::nothrow) uint8_t[READ_BUFFER_SIZE]), meminfoFd_(-1), vmstatFd_(-1), err_(-1)
34 {
35 InitProto2StrVector();
36 SetPath(const_cast<char*>("/proc"));
37 }
38
~MemoryDataPlugin()39 MemoryDataPlugin::~MemoryDataPlugin()
40 {
41 HILOG_INFO(LOG_CORE, "%s:~MemoryDataPlugin!", __func__);
42
43 buffer_ = nullptr;
44
45 if (meminfoFd_ > 0) {
46 close(meminfoFd_);
47 meminfoFd_ = -1;
48 }
49 if (vmstatFd_ > 0) {
50 close(vmstatFd_);
51 vmstatFd_ = -1;
52 }
53 for (auto it = pidFds_.begin(); it != pidFds_.end(); it++) {
54 for (int i = FILE_STATUS; i <= FILE_SMAPS; i++) {
55 if (it->second[i] != -1) {
56 close(it->second[i]);
57 }
58 }
59 }
60 return;
61 }
62
InitProto2StrVector()63 void MemoryDataPlugin::InitProto2StrVector()
64 {
65 int maxprotobufid = 0;
66 for (unsigned int i = 0; i < sizeof(meminfoMapping) / sizeof(meminfoMapping[0]); i++) {
67 maxprotobufid = std::max(meminfoMapping[i].protobufid, maxprotobufid);
68 }
69 meminfoStrList_.resize(maxprotobufid + 1);
70
71 for (unsigned int i = 0; i < sizeof(meminfoMapping) / sizeof(meminfoMapping[0]); i++) {
72 meminfoStrList_[meminfoMapping[i].protobufid] = meminfoMapping[i].procstr;
73 }
74
75 maxprotobufid = 0;
76 for (unsigned int i = 0; i < sizeof(vmeminfoMapping) / sizeof(vmeminfoMapping[0]); i++) {
77 maxprotobufid = std::max(vmeminfoMapping[i].protobufid, maxprotobufid);
78 }
79 vmstatStrList_.resize(maxprotobufid + 1);
80
81 for (unsigned int i = 0; i < sizeof(vmeminfoMapping) / sizeof(vmeminfoMapping[0]); i++) {
82 vmstatStrList_[vmeminfoMapping[i].protobufid] = vmeminfoMapping[i].procstr;
83 }
84
85 return;
86 }
87
InitMemVmemFd()88 int MemoryDataPlugin::InitMemVmemFd()
89 {
90 if (protoConfig_.report_sysmem_mem_info()) {
91 char fileName[PATH_MAX + 1] = {0};
92 char realPath[PATH_MAX + 1] = {0};
93 CHECK_TRUE(snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1, "%s/meminfo", testpath_) >= 0, RET_FAIL,
94 "%s:snprintf_s error", __func__);
95 if (realpath(fileName, realPath) == nullptr) {
96 const int bufSize = 256;
97 char buf[bufSize] = { 0 };
98 strerror_r(errno, buf, bufSize);
99 HILOG_ERROR(LOG_CORE, "%s:realpath failed, errno(%d:%s)", __func__, errno, buf);
100 return RET_FAIL;
101 }
102 meminfoFd_ = open(realPath, O_RDONLY | O_CLOEXEC);
103 if (meminfoFd_ == -1) {
104 const int bufSize = 256;
105 char buf[bufSize] = { 0 };
106 strerror_r(errno, buf, bufSize);
107 HILOG_ERROR(LOG_CORE, "%s:open failed, fileName, errno(%d:%s)", __func__, errno, buf);
108 return RET_FAIL;
109 }
110 }
111
112 if (protoConfig_.report_sysmem_vmem_info()) {
113 char fileName[PATH_MAX + 1] = {0};
114 char realPath[PATH_MAX + 1] = {0};
115 CHECK_TRUE(snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1, "%s/vmstat", testpath_) >= 0, RET_FAIL,
116 "%s:snprintf_s error", __func__);
117 if (realpath(fileName, realPath) == nullptr) {
118 const int bufSize = 256;
119 char buf[bufSize] = { 0 };
120 strerror_r(errno, buf, bufSize);
121 HILOG_ERROR(LOG_CORE, "%s:realpath failed, errno(%d:%s)", __func__, errno, buf);
122 return RET_FAIL;
123 }
124 vmstatFd_ = open(realPath, O_RDONLY | O_CLOEXEC);
125 if (vmstatFd_ == -1) {
126 const int bufSize = 256;
127 char buf[bufSize] = { 0 };
128 strerror_r(errno, buf, bufSize);
129 HILOG_ERROR(LOG_CORE, "%s:failed to open(/proc/vmstat), errno(%d:%s)", __func__, errno, buf);
130 return RET_FAIL;
131 }
132 }
133
134 return RET_SUCC;
135 }
136
Start(const uint8_t * configData,uint32_t configSize)137 int MemoryDataPlugin::Start(const uint8_t* configData, uint32_t configSize)
138 {
139 CHECK_NOTNULL(buffer_, RET_FAIL, "%s:buffer_ == null", __func__);
140
141 CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, RET_FAIL,
142 "%s:parseFromArray failed!", __func__);
143
144 CHECK_TRUE(InitMemVmemFd() == RET_SUCC, RET_FAIL, "InitMemVmemFd fail");
145
146 if (protoConfig_.sys_meminfo_counters().size() > 0) {
147 for (int i = 0; i < protoConfig_.sys_meminfo_counters().size(); i++) {
148 CHECK_TRUE((size_t)protoConfig_.sys_meminfo_counters(i) < meminfoStrList_.size(), RET_FAIL,
149 "%s:sys meminfo counter index invalid!", __func__);
150 if (meminfoStrList_[protoConfig_.sys_meminfo_counters(i)]) {
151 meminfoCounters_.emplace(meminfoStrList_[protoConfig_.sys_meminfo_counters(i)],
152 protoConfig_.sys_meminfo_counters(i));
153 }
154 }
155 }
156
157 if (protoConfig_.sys_vmeminfo_counters().size() > 0) {
158 for (int i = 0; i < protoConfig_.sys_vmeminfo_counters().size(); i++) {
159 CHECK_TRUE((size_t)protoConfig_.sys_vmeminfo_counters(i) < vmstatStrList_.size(), RET_FAIL,
160 "%s:vmstat counter index invalid!", __func__);
161 if (vmstatStrList_[protoConfig_.sys_vmeminfo_counters(i)]) {
162 vmstatCounters_.emplace(vmstatStrList_[protoConfig_.sys_vmeminfo_counters(i)],
163 protoConfig_.sys_vmeminfo_counters(i));
164 }
165 }
166 }
167
168 if (protoConfig_.pid().size() > 0) {
169 for (int i = 0; i < protoConfig_.pid().size(); i++) {
170 int32_t pid = protoConfig_.pid(i);
171 pidFds_.emplace(pid, OpenProcPidFiles(pid));
172 }
173 }
174
175 HILOG_INFO(LOG_CORE, "%s:start success!", __func__);
176 return RET_SUCC;
177 }
178
WriteMeminfo(MemoryData & data)179 void MemoryDataPlugin::WriteMeminfo(MemoryData& data)
180 {
181 int readsize = ReadFile(meminfoFd_);
182 if (readsize == RET_FAIL) {
183 return;
184 }
185 BufferSplitter totalbuffer((const char*)buffer_.get(), readsize);
186
187 do {
188 if (!totalbuffer.NextWord(':')) {
189 continue;
190 }
191 const_cast<char *>(totalbuffer.CurWord())[totalbuffer.CurWordSize()] = '\0';
192 auto it = meminfoCounters_.find(totalbuffer.CurWord());
193 if (it == meminfoCounters_.end()) {
194 continue;
195 }
196
197 int counter_id = it->second;
198 if (!totalbuffer.NextWord(' ')) {
199 continue;
200 }
201 auto value = static_cast<uint64_t>(strtoll(totalbuffer.CurWord(), nullptr, DEC_BASE));
202 auto* meminfo = data.add_meminfo();
203
204 meminfo->set_key(static_cast<SysMeminfoType>(counter_id));
205 meminfo->set_value(value);
206 } while (totalbuffer.NextLine());
207
208 return;
209 }
210
WriteZramData(MemoryData & data)211 void MemoryDataPlugin::WriteZramData(MemoryData& data)
212 {
213 uint64_t zramSum = 0;
214 for (int i = 0; i < MAX_ZRAM_DEVICES; i++) {
215 std::string path = "/sys/block/zram" + std::to_string(i);
216 if (access(path.c_str(), F_OK) == 0) {
217 uint64_t zramValue = 0;
218 std::string file = path + "/mm_stat";
219 auto fptr = std::unique_ptr<FILE, decltype(&fclose)>{fopen(file.c_str(), "rb"), fclose};
220 if (fptr != nullptr) {
221 int ret = fscanf_s(fptr.get(), "%*" PRIu64 " %*" PRIu64 " %" PRIu64, &zramValue);
222 if (ret != 1) {
223 file = path + "/mem_used_total";
224 std::string content = ReadFile(file);
225 char* end = nullptr;
226 uint64_t value = strtoull(content.c_str(), &end, DEC_BASE);
227 zramValue = (value > 0) ? value : 0;
228 }
229 }
230
231 zramSum += zramValue;
232 }
233 }
234
235 data.set_zram(zramSum / ZRAM_KB);
236 }
237
WriteVmstat(MemoryData & data)238 void MemoryDataPlugin::WriteVmstat(MemoryData& data)
239 {
240 int readsize = ReadFile(vmstatFd_);
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 = vmstatCounters_.find(totalbuffer.CurWord());
252 if (it == vmstatCounters_.end()) {
253 continue;
254 }
255
256 int counter_id = it->second;
257 char* valuestr = const_cast<char *>(totalbuffer.CurWord() + totalbuffer.CurWordSize() + 1);
258 valuestr[totalbuffer.CurLineSize() - (valuestr - totalbuffer.CurLine())] = '\0';
259
260 auto value = static_cast<uint64_t>(strtoll(valuestr, nullptr, DEC_BASE));
261 auto* vmeminfo = data.add_vmeminfo();
262
263 vmeminfo->set_key(static_cast<SysVMeminfoType>(counter_id));
264 vmeminfo->set_value(value);
265 } while (totalbuffer.NextLine());
266
267 return;
268 }
269
WriteAppsummary(ProcessMemoryInfo * processinfo,SmapsStats & smapInfo)270 void MemoryDataPlugin::WriteAppsummary(ProcessMemoryInfo* processinfo, SmapsStats& smapInfo)
271 {
272 processinfo->mutable_memsummary()->set_java_heap(smapInfo.GetProcessJavaHeap());
273 processinfo->mutable_memsummary()->set_native_heap(smapInfo.GetProcessNativeHeap());
274 processinfo->mutable_memsummary()->set_code(smapInfo.GetProcessCode());
275 processinfo->mutable_memsummary()->set_stack(smapInfo.GetProcessStack());
276 processinfo->mutable_memsummary()->set_graphics(smapInfo.GetProcessGraphics());
277 processinfo->mutable_memsummary()->set_private_other(smapInfo.GetProcessPrivateOther());
278 processinfo->mutable_memsummary()->set_system(smapInfo.GetProcessSystem());
279 }
280
ParseNumber(std::string line)281 int MemoryDataPlugin::ParseNumber(std::string line)
282 {
283 return atoi(line.substr(line.find_first_of("01234567890")).c_str());
284 }
285
ParseMemInfo(const char * data,ProcessMemoryInfo * memoryInfo)286 bool MemoryDataPlugin::ParseMemInfo(const char* data, ProcessMemoryInfo* memoryInfo)
287 {
288 bool ready = false;
289 bool done = false;
290 std::istringstream ss(data);
291 std::string line;
292
293 while (std::getline(ss, line)) {
294 std::string s(line);
295 if (s.find("App Summary") != s.npos) {
296 ready = true;
297 continue;
298 }
299
300 if (ready) {
301 if (s.find("Java Heap:") != s.npos) {
302 memoryInfo->mutable_memsummary()->set_java_heap(ParseNumber(s));
303 continue;
304 }
305 if (s.find("Native Heap:") != s.npos) {
306 memoryInfo->mutable_memsummary()->set_native_heap(ParseNumber(s));
307 continue;
308 }
309 if (s.find("Code:") != s.npos) {
310 memoryInfo->mutable_memsummary()->set_code(ParseNumber(s));
311 continue;
312 }
313 if (s.find("Stack:") != s.npos) {
314 memoryInfo->mutable_memsummary()->set_stack(ParseNumber(s));
315 continue;
316 }
317 if (s.find("Graphics:") != s.npos) {
318 memoryInfo->mutable_memsummary()->set_graphics(ParseNumber(s));
319 continue;
320 }
321 if (s.find("Private Other:") != s.npos) {
322 memoryInfo->mutable_memsummary()->set_private_other(ParseNumber(s));
323 continue;
324 }
325 if (s.find("System:") != s.npos) {
326 memoryInfo->mutable_memsummary()->set_system(ParseNumber(s));
327 done = true;
328 break;
329 }
330 }
331 }
332 return done;
333 }
334
GetMemInfoByMemoryService(uint32_t pid,ProcessMemoryInfo * memoryInfo)335 bool MemoryDataPlugin::GetMemInfoByMemoryService(uint32_t pid, ProcessMemoryInfo* memoryInfo)
336 {
337 std::string fullCmd = CMD_FORMAT + std::to_string(pid);
338
339 std::unique_ptr<uint8_t[]> buffer {new (std::nothrow) uint8_t[BUF_MAX_LEN]};
340 std::unique_ptr<FILE, int (*)(FILE*)> fp(popen(fullCmd.c_str(), "r"), pclose);
341 CHECK_TRUE(fp, false, "%s:popen error", __func__);
342
343 size_t ret = fread(buffer.get(), 1, BUF_MAX_LEN, fp.get());
344 if (ret == 0) {
345 HILOG_ERROR(LOG_CORE, "%s:fread failed", __func__);
346 }
347 buffer.get()[BUF_MAX_LEN - 1] = '\0';
348
349 return ParseMemInfo(reinterpret_cast<char*>(buffer.get()), memoryInfo);
350 }
351
Report(uint8_t * data,uint32_t dataSize)352 int MemoryDataPlugin::Report(uint8_t* data, uint32_t dataSize)
353 {
354 MemoryData dataProto;
355 uint32_t length;
356
357 if (protoConfig_.report_process_tree()) {
358 WriteProcesseList(dataProto);
359 }
360
361 if (protoConfig_.report_sysmem_mem_info()) {
362 WriteMeminfo(dataProto);
363 WriteZramData(dataProto);
364 }
365
366 if (protoConfig_.report_sysmem_vmem_info()) {
367 WriteVmstat(dataProto);
368 }
369
370 for (int i = 0; i < protoConfig_.pid().size(); i++) {
371 int32_t pid = protoConfig_.pid(i);
372 auto* processinfo = dataProto.add_processesinfo();
373 if (protoConfig_.report_process_mem_info()) {
374 WriteProcinfoByPidfds(processinfo, pid);
375 }
376
377 bool isReportApp = protoConfig_.report_app_mem_info() && !protoConfig_.report_app_mem_by_memory_service();
378 bool isReportSmaps = protoConfig_.report_smaps_mem_info();
379 if (i == 0 && (isReportApp || isReportSmaps)) {
380 SmapsStats smapInfo;
381 smapInfo.ParseMaps(pid, *processinfo, isReportApp, isReportSmaps);
382 if (isReportApp) {
383 WriteAppsummary(processinfo, smapInfo);
384 }
385 }
386 }
387 length = dataProto.ByteSizeLong();
388 if (length > dataSize) {
389 return -length;
390 }
391 if (dataProto.SerializeToArray(data, length) > 0) {
392 return length;
393 }
394 return 0;
395 }
396
Stop()397 int MemoryDataPlugin::Stop()
398 {
399 if (meminfoFd_ > 0) {
400 close(meminfoFd_);
401 meminfoFd_ = -1;
402 }
403 if (vmstatFd_ > 0) {
404 close(vmstatFd_);
405 vmstatFd_ = -1;
406 }
407 for (auto it = pidFds_.begin(); it != pidFds_.end(); it++) {
408 for (int i = FILE_STATUS; i <= FILE_SMAPS; i++) {
409 if (it->second[i] != -1) {
410 close(it->second[i]);
411 it->second[i] = -1;
412 }
413 }
414 }
415 HILOG_INFO(LOG_CORE, "%s:stop success!", __func__);
416 return 0;
417 }
418
WriteProcinfoByPidfds(ProcessMemoryInfo * processinfo,int32_t pid)419 void MemoryDataPlugin::WriteProcinfoByPidfds(ProcessMemoryInfo* processinfo, int32_t pid)
420 {
421 char* end = nullptr;
422 int32_t readSize;
423
424 readSize = ReadFile(pidFds_[pid][FILE_STATUS]);
425 if (readSize != RET_FAIL) {
426 WriteProcess(processinfo, (char*)buffer_.get(), readSize, pid);
427 }
428
429 if (ReadFile(pidFds_[pid][FILE_OOM]) != RET_FAIL) {
430 processinfo->set_oom_score_adj(static_cast<int64_t>(strtol((char*)buffer_.get(), &end, DEC_BASE)));
431 } else {
432 processinfo->set_oom_score_adj(0);
433 }
434 return;
435 }
436
ReadFile(int fd)437 int32_t MemoryDataPlugin::ReadFile(int fd)
438 {
439 if ((buffer_.get() == nullptr) || (fd == -1)) {
440 return RET_FAIL;
441 }
442 int readsize = pread(fd, buffer_.get(), READ_BUFFER_SIZE - 1, 0);
443 if (readsize <= 0) {
444 const int bufSize = 256;
445 char buf[bufSize] = { 0 };
446 strerror_r(errno, buf, bufSize);
447 HILOG_ERROR(LOG_CORE, "%s:failed to read(%d), errno(%d:%s)", __func__, fd, errno, buf);
448 err_ = errno;
449 return RET_FAIL;
450 }
451 return readsize;
452 }
453
ReadFile(const std::string & path)454 std::string MemoryDataPlugin::ReadFile(const std::string& path)
455 {
456 char realPath[PATH_MAX] = {0};
457 CHECK_TRUE((path.length() < PATH_MAX) && (realpath(path.c_str(), realPath) != nullptr), "",
458 "%s:path is invalid: %s, errno=%d", __func__, path.c_str(), errno);
459 int fd = open(realPath, O_RDONLY);
460 if (fd == -1) {
461 const int maxSize = 256;
462 char buf[maxSize] = { 0 };
463 strerror_r(errno, buf, maxSize);
464 HILOG_WARN(LOG_CORE, "open file %s FAILED: %s!", path.c_str(), buf);
465 return "";
466 }
467
468 std::string content;
469 size_t count = 0;
470 while (true) {
471 if (content.size() - count < DEFAULT_READ_SIZE) {
472 content.resize(content.size() + DEFAULT_READ_SIZE);
473 }
474 ssize_t nBytes = read(fd, &content[count], content.size() - count);
475 if (nBytes <= 0) {
476 break;
477 }
478 count += static_cast<size_t>(nBytes);
479 }
480 content.resize(count);
481 CHECK_TRUE(close(fd) != -1, content, "close %s failed, %d", path.c_str(), errno);
482 return content;
483 }
484
OpenProcPidFiles(int32_t pid)485 std::vector<int> MemoryDataPlugin::OpenProcPidFiles(int32_t pid)
486 {
487 char fileName[PATH_MAX + 1] = {0};
488 char realPath[PATH_MAX + 1] = {0};
489 int count = sizeof(procfdMapping) / sizeof(procfdMapping[0]);
490 std::vector<int> profds;
491
492 for (int i = 0; i < count; i++) {
493 if (snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1,
494 "%s/%d/%s", testpath_, pid, procfdMapping[i].file) < 0) {
495 HILOG_ERROR(LOG_CORE, "%s:snprintf_s error", __func__);
496 }
497 if (realpath(fileName, realPath) == nullptr) {
498 const int bufSize = 256;
499 char buf[bufSize] = { 0 };
500 strerror_r(errno, buf, bufSize);
501 HILOG_ERROR(LOG_CORE, "%s:realpath failed, errno(%d:%s)", __func__, errno, buf);
502 }
503 int fd = open(realPath, O_RDONLY | O_CLOEXEC);
504 if (fd == -1) {
505 const int bufSize = 256;
506 char buf[bufSize] = { 0 };
507 strerror_r(errno, buf, bufSize);
508 HILOG_ERROR(LOG_CORE, "%s:failed to open(%s), errno(%d:%s)", __func__, fileName, errno, buf);
509 }
510 profds.emplace(profds.begin() + i, fd);
511 }
512 return profds;
513 }
514
OpenDestDir(const char * dirPath)515 DIR* MemoryDataPlugin::OpenDestDir(const char* dirPath)
516 {
517 DIR* destDir = nullptr;
518
519 destDir = opendir(dirPath);
520 if (destDir == nullptr) {
521 const int bufSize = 256;
522 char buf[bufSize] = { 0 };
523 strerror_r(errno, buf, bufSize);
524 HILOG_ERROR(LOG_CORE, "%s:failed to opendir(%s), errno(%d:%s)", __func__, dirPath, errno, buf);
525 }
526
527 return destDir;
528 }
529
GetValidPid(DIR * dirp)530 int32_t MemoryDataPlugin::GetValidPid(DIR* dirp)
531 {
532 if (!dirp) return 0;
533 while (struct dirent* dirEnt = readdir(dirp)) {
534 if (dirEnt->d_type != DT_DIR) {
535 continue;
536 }
537
538 int32_t pid = atoi(dirEnt->d_name);
539 if (pid) {
540 return pid;
541 }
542 }
543 return 0;
544 }
545
ReadProcPidFile(int32_t pid,const char * pFileName)546 int32_t MemoryDataPlugin::ReadProcPidFile(int32_t pid, const char* pFileName)
547 {
548 char fileName[PATH_MAX + 1] = {0};
549 char realPath[PATH_MAX + 1] = {0};
550 int fd = -1;
551 ssize_t bytesRead = 0;
552 CHECK_TRUE(snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1, "%s/%d/%s", testpath_, pid, pFileName) >= 0,
553 RET_FAIL, "%s:snprintf_s error", __func__);
554 if (realpath(fileName, realPath) == nullptr) {
555 const int bufSize = 256;
556 char buf[bufSize] = { 0 };
557 strerror_r(errno, buf, bufSize);
558 HILOG_ERROR(LOG_CORE, "%s:realpath failed, errno(%d:%s)", __func__, errno, buf);
559 return RET_FAIL;
560 }
561 fd = open(realPath, O_RDONLY | O_CLOEXEC);
562 if (fd == -1) {
563 const int bufSize = 256;
564 char buf[bufSize] = { 0 };
565 strerror_r(errno, buf, bufSize);
566 HILOG_INFO(LOG_CORE, "%s:failed to open(%s), errno(%d:%s)", __func__, fileName, errno, buf);
567 err_ = errno;
568 return RET_FAIL;
569 }
570 if (buffer_.get() == nullptr) {
571 HILOG_INFO(LOG_CORE, "%s:empty address, buffer_ is NULL", __func__);
572 err_ = RET_NULL_ADDR;
573 close(fd);
574 return RET_FAIL;
575 }
576 bytesRead = read(fd, buffer_.get(), READ_BUFFER_SIZE - 1);
577 if (bytesRead < 0) {
578 close(fd);
579 const int bufSize = 256;
580 char buf[bufSize] = { 0 };
581 strerror_r(errno, buf, bufSize);
582 HILOG_INFO(LOG_CORE, "%s:failed to read(%s), errno(%d:%s)", __func__, fileName, errno, buf);
583 err_ = errno;
584 return RET_FAIL;
585 }
586 buffer_.get()[bytesRead] = '\0';
587 close(fd);
588
589 return bytesRead;
590 }
591
BufnCmp(const char * src,int srcLen,const char * key,int keyLen)592 bool MemoryDataPlugin::BufnCmp(const char* src, int srcLen, const char* key, int keyLen)
593 {
594 if (!src || !key || (srcLen < keyLen)) {
595 return false;
596 }
597 for (int i = 0; i < keyLen; i++) {
598 if (*src++ != *key++) {
599 return false;
600 }
601 }
602 return true;
603 }
604
addPidBySort(int32_t pid)605 bool MemoryDataPlugin::addPidBySort(int32_t pid)
606 {
607 auto pidsEnd = seenPids_.end();
608 auto it = std::lower_bound(seenPids_.begin(), pidsEnd, pid);
609 if (it != pidsEnd && *it == pid) {
610 return false;
611 }
612 it = seenPids_.insert(it, std::move(pid));
613 return true;
614 }
615
GetProcStatusId(const char * src,int srcLen)616 int MemoryDataPlugin::GetProcStatusId(const char* src, int srcLen)
617 {
618 int count = sizeof(procStatusMapping) / sizeof(procStatusMapping[0]);
619 for (int i = 0; i < count; i++) {
620 if (BufnCmp(src, srcLen, procStatusMapping[i].procstr, strlen(procStatusMapping[i].procstr))) {
621 return procStatusMapping[i].procid;
622 }
623 }
624 return RET_FAIL;
625 }
626
StringToUll(const char * word,uint64_t & value)627 bool MemoryDataPlugin::StringToUll(const char* word, uint64_t& value)
628 {
629 char* end = nullptr;
630 errno = 0;
631 value = strtoull(word, &end, DEC_BASE);
632 if ((errno == ERANGE && (value == ULLONG_MAX)) || (errno != 0 && value == 0)) {
633 return false;
634 } else if (end == word && (*word >= '0' && *word <= '9')) {
635 return false;
636 }
637
638 return true;
639 }
640
SetProcessInfo(ProcessMemoryInfo * processinfo,int key,const char * word)641 void MemoryDataPlugin::SetProcessInfo(ProcessMemoryInfo* processinfo, int key, const char* word)
642 {
643 uint64_t value;
644
645 if ((key >= PRO_TGID && key <= PRO_VMHWM && key != PRO_NAME) && !StringToUll(word, value)) {
646 HILOG_ERROR(LOG_CORE, "MemoryDataPlugin:%s, strtoull failed, key(%d), word(%s)", __func__, key, word);
647 return;
648 }
649
650 switch (key) {
651 case PRO_TGID:
652 processinfo->set_pid(static_cast<int32_t>(value));
653 break;
654 case PRO_VMSIZE:
655 processinfo->set_vm_size_kb(value);
656 break;
657 case PRO_VMRSS:
658 processinfo->set_vm_rss_kb(value);
659 break;
660 case PRO_RSSANON:
661 processinfo->set_rss_anon_kb(value);
662 break;
663 case PRO_RSSFILE:
664 processinfo->set_rss_file_kb(value);
665 break;
666 case PRO_RSSSHMEM:
667 processinfo->set_rss_shmem_kb(value);
668 break;
669 case PRO_VMSWAP:
670 processinfo->set_vm_swap_kb(value);
671 break;
672 case PRO_VMLCK:
673 processinfo->set_vm_locked_kb(value);
674 break;
675 case PRO_VMHWM:
676 processinfo->set_vm_hwm_kb(value);
677 break;
678 default:
679 break;
680 }
681 return;
682 }
683
WriteProcess(ProcessMemoryInfo * processinfo,const char * pFile,uint32_t fileLen,int32_t pid)684 void MemoryDataPlugin::WriteProcess(ProcessMemoryInfo* processinfo, const char* pFile, uint32_t fileLen, int32_t pid)
685 {
686 BufferSplitter totalbuffer(const_cast<const char*>(pFile), fileLen + 1);
687
688 do {
689 totalbuffer.NextWord(':');
690 if (!totalbuffer.CurWord()) {
691 return;
692 }
693
694 int key = GetProcStatusId(totalbuffer.CurWord(), totalbuffer.CurWordSize());
695 totalbuffer.NextWord('\n');
696 if (!totalbuffer.CurWord()) {
697 continue;
698 }
699 if (key == PRO_NAME) {
700 processinfo->set_name(totalbuffer.CurWord(), totalbuffer.CurWordSize());
701 }
702 SetProcessInfo(processinfo, key, totalbuffer.CurWord());
703 } while (totalbuffer.NextLine());
704 // update process name
705 int32_t ret = ReadProcPidFile(pid, "cmdline");
706 if (ret > 0) {
707 processinfo->set_name(reinterpret_cast<char*>(buffer_.get()), strlen(reinterpret_cast<char*>(buffer_.get())));
708 }
709 }
710
WriteOomInfo(ProcessMemoryInfo * processinfo,int32_t pid)711 void MemoryDataPlugin::WriteOomInfo(ProcessMemoryInfo* processinfo, int32_t pid)
712 {
713 char* end = nullptr;
714
715 if (ReadProcPidFile(pid, "oom_score_adj") == RET_FAIL) {
716 processinfo->set_oom_score_adj(0);
717 return;
718 }
719 if (buffer_.get() == nullptr) {
720 processinfo->set_oom_score_adj(0);
721 HILOG_ERROR(LOG_CORE, "%s:invalid params, read buffer_ is NULL", __func__);
722 return;
723 }
724 processinfo->set_oom_score_adj(static_cast<int64_t>(strtol((char*)buffer_.get(), &end, DEC_BASE)));
725 }
726
WriteProcessInfo(MemoryData & data,int32_t pid)727 void MemoryDataPlugin::WriteProcessInfo(MemoryData& data, int32_t pid)
728 {
729 int32_t ret = ReadProcPidFile(pid, "status");
730 if (ret == RET_FAIL) {
731 return;
732 }
733 if ((buffer_.get() == nullptr) || (ret == 0)) {
734 return;
735 }
736 auto* processinfo = data.add_processesinfo();
737 WriteProcess(processinfo, (char*)buffer_.get(), ret, pid);
738 WriteOomInfo(processinfo, pid);
739 }
740
WriteProcesseList(MemoryData & data)741 void MemoryDataPlugin::WriteProcesseList(MemoryData& data)
742 {
743 DIR* procDir = nullptr;
744
745 procDir = OpenDestDir(testpath_);
746 if (procDir == nullptr) {
747 return;
748 }
749
750 seenPids_.clear();
751 while (int32_t pid = GetValidPid(procDir)) {
752 addPidBySort(pid);
753 }
754
755 for (unsigned int i = 0; i < seenPids_.size(); i++) {
756 WriteProcessInfo(data, seenPids_[i]);
757 }
758 closedir(procDir);
759 }
760