• 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         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