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