• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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