• 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 
16 #include <dlfcn.h>
17 #include <hwext/gtest-ext.h>
18 #include <hwext/gtest-tag.h>
19 #include <sys/types.h>
20 
21 #include "memory_data_plugin.h"
22 #include "plugin_module_api.h"
23 
24 using namespace testing::ext;
25 
26 namespace {
27 const std::string DEFAULT_TEST_PATH("/data/local/tmp/");
28 #if defined(__LP64__)
29 const std::string DEFAULT_SO_PATH("/system/lib64/");
30 #else
31 const std::string DEFAULT_SO_PATH("/system/lib/");
32 #endif
33 const std::string DEFAULT_BIN_PATH("/data/local/tmp/memorytest");
34 constexpr uint32_t BUF_SIZE = 4 * 1024 * 1024;
35 const int US_PER_S = 1000000;
36 
37 std::string g_path;
38 
39 struct TestElement {
40     int32_t pid;
41     std::string name;
42     // data from /proc/$pid/stat
43     uint64_t vm_size_kb;
44     uint64_t vm_rss_kb;
45     uint64_t rss_anon_kb;
46     uint64_t rss_file_kb;
47     uint64_t rss_shmem_kb;
48     uint64_t vm_swap_kb;
49     uint64_t vm_locked_kb;
50     uint64_t vm_hwm_kb;
51     int64_t oom_score_adj;
52 
53     uint64_t java_heap;
54     uint64_t native_heap;
55     uint64_t code;
56     uint64_t stack;
57     uint64_t graphics;
58     uint64_t private_other;
59 };
60 
61 TestElement g_pidtarget[] = {
62     {1, "systemd", 226208, 9388, 2984, 6404, 0, 0, 0, 9616, -1, 3036, 4256, 288, 748, 0, 1388},
63     {2, "kthreadd", 0, 0, 0, 0, 0, 0, 0, 0, -100, 3036, 4260, 336, 760, 0, 4204},
64     {11, "rcu_sched", 0, 0, 0, 0, 0, 0, 0, 0, 0, 3036, 4272, 400, 772, 0, 7160},
65 };
66 
67 unsigned long g_meminfo[] = {
68     16168696, 1168452, 12363564, 2726188, 7370484, 29260,    8450388,  4807668,
69     2535372,  658832,  4148836,  132,     0,       63999996, 62211580, 0
70 };
71 
72 unsigned long g_vmeminfo[] = {
73     112823, 0,      587,    1848,   101,   9074,  8426,   18314,
74     0,     2416,  2348,  9073,   1876,  26863, 1,      0
75 };
76 
77 std::string GetFullPath(std::string path);
78 
79 class MemoryDataPluginTest : public ::testing::Test {
80 public:
81     static void SetUpTestCase();
82 
TearDownTestCase()83     static void TearDownTestCase()
84     {
85         if (access(g_path.c_str(), F_OK) == 0) {
86             std::string str = "rm -rf " + GetFullPath(DEFAULT_TEST_PATH) + "utresources";
87             system(str.c_str());
88         }
89     }
SetUp()90     void SetUp() {}
TearDown()91     void TearDown() {}
92 };
93 
Getexepath()94 string Getexepath()
95 {
96     char buf[PATH_MAX] = "";
97     std::string path = "/proc/self/exe";
98     size_t rslt = readlink(path.c_str(), buf, sizeof(buf));
99     if (rslt < 0 || (rslt >= sizeof(buf))) {
100         return "";
101     }
102     buf[rslt] = '\0';
103     for (int i = rslt; i >= 0; i--) {
104         if (buf[i] == '/') {
105             buf[i + 1] = '\0';
106             break;
107         }
108     }
109     return buf;
110 }
111 
SetPluginProcessConfig(std::vector<int> processList,MemoryConfig & protoConfig)112 void SetPluginProcessConfig(std::vector<int> processList, MemoryConfig& protoConfig)
113 {
114     if (processList.size() != 0) {
115         // 具体进程
116         protoConfig.set_report_process_mem_info(true);
117         protoConfig.set_report_app_mem_info(true);
118         for (size_t i = 0; i < processList.size(); i++) {
119             protoConfig.add_pid(processList.at(i));
120         }
121     } else {
122         // 进程树
123         protoConfig.set_report_process_tree(true);
124     }
125 }
126 
SetPluginSysMemConfig(MemoryConfig & protoConfig)127 void SetPluginSysMemConfig(MemoryConfig &protoConfig)
128 {
129     protoConfig.set_report_sysmem_mem_info(true);
130 
131     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_MEM_TOTAL);
132     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_MEM_FREE);
133     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_MEM_AVAILABLE);
134     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_BUFFERS);
135     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_CACHED);
136     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_SWAP_CACHED);
137     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_ACTIVE);
138     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_INACTIVE);
139 
140     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_ACTIVE_ANON);
141     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_INACTIVE_ANON);
142     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_INACTIVE_FILE);
143     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_UNEVICTABLE);
144     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_MLOCKED);
145     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_SWAP_TOTAL);
146     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_SWAP_FREE);
147     protoConfig.add_sys_meminfo_counters(SysMeminfoType::PMEM_DIRTY);
148 
149     protoConfig.set_report_sysmem_vmem_info(true);
150 
151     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_FREE_PAGES);
152     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_INACTIVE_ANON);
153     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_ACTIVE_ANON);
154     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_INACTIVE_FILE);
155 
156     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_ACTIVE_FILE);
157     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_UNEVICTABLE);
158     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_MLOCK);
159     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_ANON_PAGES);
160 
161     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_MAPPED);
162     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_FILE_PAGES);
163     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_DIRTY);
164     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_SLAB_RECLAIMABLE);
165 
166     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_SLAB_UNRECLAIMABLE);
167     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_PAGE_TABLE_PAGES);
168     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_KERNEL_STACK);
169     protoConfig.add_sys_vmeminfo_counters(SysVMeminfoType::VMEMINFO_NR_UNSTABLE);
170 }
171 
SetPluginMemoryServiceConfig(MemoryConfig & protoConfig)172 void SetPluginMemoryServiceConfig(MemoryConfig& protoConfig)
173 {
174     protoConfig.set_report_process_mem_info(true);
175     protoConfig.set_report_app_mem_info(true);
176     protoConfig.add_pid(1);
177     protoConfig.set_report_app_mem_by_memory_service(true);
178 }
179 
PluginStub(MemoryDataPlugin & memoryPlugin,MemoryConfig & protoConfig,MemoryData & memoryData)180 bool PluginStub(MemoryDataPlugin& memoryPlugin, MemoryConfig& protoConfig, MemoryData& memoryData)
181 {
182     // serialize
183     int configSize = protoConfig.ByteSizeLong();
184     std::vector<uint8_t> configData(configSize);
185     int ret = protoConfig.SerializeToArray(configData.data(), configData.size());
186     CHECK_TRUE(ret > 0, false, "PluginStub::SerializeToArray fail!!!");
187 
188     // start
189     ret = memoryPlugin.Start(configData.data(), configData.size());
190     CHECK_TRUE(ret == 0, false, "PluginStub::start plugin fail!!!");
191 
192     // report
193     std::vector<uint8_t> bufferData(BUF_SIZE);
194     ret = memoryPlugin.Report(bufferData.data(), bufferData.size());
195     if (ret >= 0) {
196         memoryData.ParseFromArray(bufferData.data(), ret);
197         return true;
198     }
199 
200     return false;
201 }
202 
GetFullPath(std::string path)203 std::string GetFullPath(std::string path)
204 {
205     if (path.size() > 0 && path[0] != '/') {
206         return Getexepath() + path;
207     }
208     return path;
209 }
210 
SetUpTestCase()211 void MemoryDataPluginTest::SetUpTestCase()
212 {
213     g_path = GetFullPath(DEFAULT_TEST_PATH);
214     EXPECT_NE("", g_path);
215     g_path += "utresources/proc";
216 }
217 
218 /**
219  * @tc.name: memory plugin
220  * @tc.desc: Test whether the path exists.
221  * @tc.type: FUNC
222  */
223 HWTEST_F(MemoryDataPluginTest, TestUtpath, TestSize.Level1)
224 {
225     EXPECT_NE(g_path, "");
226 }
227 
228 /**
229  * @tc.name: memory plugin
230  * @tc.desc: Pid list test in a specific directory.
231  * @tc.type: FUNC
232  */
233 HWTEST_F(MemoryDataPluginTest, Testpidlist, TestSize.Level1)
234 {
235     MemoryDataPlugin* memoryPlugin = new MemoryDataPlugin();
236     const std::vector<int> expectPidList = {1, 2, 11};
237 
238     DIR* dir = memoryPlugin->OpenDestDir(g_path.c_str());
239     EXPECT_NE(nullptr, dir);
240 
241     std::vector<int> cmpPidList;
242     while (int32_t pid = memoryPlugin->GetValidPid(dir)) {
243         cmpPidList.push_back(pid);
244     }
245     sort(cmpPidList.begin(), cmpPidList.end());
246     closedir(dir);
247     EXPECT_EQ(cmpPidList, expectPidList);
248     delete memoryPlugin;
249 }
250 
251 /**
252  * @tc.name: memory plugin
253  * @tc.desc: Mem information test for specific pid.
254  * @tc.type: FUNC
255  */
256 HWTEST_F(MemoryDataPluginTest, Testpluginformeminfo, TestSize.Level1)
257 {
258     MemoryDataPlugin memoryPlugin;
259     MemoryData memoryData;
260     MemoryConfig protoConfig;
261 
262     memoryPlugin.SetPath(const_cast<char*>(g_path.c_str()));
263     SetPluginSysMemConfig(protoConfig);
264     EXPECT_TRUE(PluginStub(memoryPlugin, protoConfig, memoryData));
265 
266     EXPECT_EQ(16, memoryData.meminfo().size());
267     int index = memoryData.meminfo_size();
268     for (int i = 0; i < index; ++i) {
269         EXPECT_EQ(g_meminfo[i], memoryData.meminfo(i).value());
270     }
271 
272     EXPECT_EQ(16, memoryData.vmeminfo().size());
273     index = memoryData.vmeminfo_size();
274     for (int i = 0; i < index; ++i) {
275         EXPECT_EQ(g_vmeminfo[i], memoryData.vmeminfo(i).value());
276     }
277     memoryPlugin.Stop();
278 }
279 
280 /**
281  * @tc.name: memory plugin
282  * @tc.desc: pid list information test for process tree.
283  * @tc.type: FUNC
284  */
285 HWTEST_F(MemoryDataPluginTest, Testpluginforlist, TestSize.Level1)
286 {
287     MemoryDataPlugin memoryPlugin;
288     MemoryData memoryData;
289     MemoryConfig protoConfig;
290 
291     std::vector<int> cmpPidList;
292     EXPECT_EQ((size_t)0, cmpPidList.size());
293 
294     memoryPlugin.SetPath(const_cast<char*>(g_path.c_str()));
295 
296     SetPluginProcessConfig(cmpPidList, protoConfig);
297     EXPECT_TRUE(PluginStub(memoryPlugin, protoConfig, memoryData));
298 
299     int index = memoryData.processesinfo_size();
300     EXPECT_EQ(3, index);
301     for (int i = 0; i < index; ++i) {
302         ProcessMemoryInfo it = memoryData.processesinfo(i);
303         EXPECT_EQ(g_pidtarget[i].pid, it.pid());
304         EXPECT_EQ(g_pidtarget[i].name, it.name());
305         EXPECT_EQ(g_pidtarget[i].vm_size_kb, it.vm_size_kb());
306         EXPECT_EQ(g_pidtarget[i].vm_rss_kb, it.vm_rss_kb());
307         EXPECT_EQ(g_pidtarget[i].rss_anon_kb, it.rss_anon_kb());
308         EXPECT_EQ(g_pidtarget[i].rss_file_kb, it.rss_file_kb());
309         EXPECT_EQ(g_pidtarget[i].rss_shmem_kb, it.rss_shmem_kb());
310         EXPECT_EQ(g_pidtarget[i].vm_locked_kb, it.vm_locked_kb());
311         EXPECT_EQ(g_pidtarget[i].vm_hwm_kb, it.vm_hwm_kb());
312 
313         EXPECT_EQ(g_pidtarget[i].oom_score_adj, it.oom_score_adj());
314 
315         EXPECT_FALSE(it.has_memsummary());
316     }
317 
318     memoryPlugin.Stop();
319 }
320 
321 /**
322  * @tc.name: memory plugin
323  * @tc.desc: pid list information test for specific pid.
324  * @tc.type: FUNC
325  */
326 HWTEST_F(MemoryDataPluginTest, Testpluginforsinglepid, TestSize.Level1)
327 {
328     MemoryDataPlugin memoryPlugin;
329     MemoryData memoryData;
330     MemoryConfig protoConfig;
331 
332     std::vector<int> pid = {5};
333     TestElement singlepid = {};
334 
335     memoryPlugin.SetPath(const_cast<char*>(g_path.c_str()));
336 
337     SetPluginProcessConfig(pid, protoConfig);
338     EXPECT_TRUE(PluginStub(memoryPlugin, protoConfig, memoryData));
339 
340     int index = memoryData.processesinfo_size();
341     EXPECT_EQ(1, index);
342 
343     ProcessMemoryInfo it = memoryData.processesinfo(0);
344     EXPECT_EQ(singlepid.pid, it.pid());
345     EXPECT_EQ(singlepid.name, it.name());
346     EXPECT_EQ(singlepid.vm_size_kb, it.vm_size_kb());
347     EXPECT_EQ(singlepid.vm_rss_kb, it.vm_rss_kb());
348     EXPECT_EQ(singlepid.rss_anon_kb, it.rss_anon_kb());
349     EXPECT_EQ(singlepid.rss_file_kb, it.rss_file_kb());
350     EXPECT_EQ(singlepid.rss_shmem_kb, it.rss_shmem_kb());
351     EXPECT_EQ(singlepid.vm_locked_kb, it.vm_locked_kb());
352     EXPECT_EQ(singlepid.vm_hwm_kb, it.vm_hwm_kb());
353 
354     EXPECT_EQ(singlepid.oom_score_adj, it.oom_score_adj());
355 
356     EXPECT_TRUE(it.has_memsummary());
357     AppSummary app = it.memsummary();
358     EXPECT_EQ(singlepid.java_heap, app.java_heap());
359     EXPECT_EQ(singlepid.native_heap, app.native_heap());
360     EXPECT_EQ(singlepid.code, app.code());
361     EXPECT_EQ(singlepid.stack, app.stack());
362     EXPECT_EQ(singlepid.graphics, app.graphics());
363     EXPECT_EQ(singlepid.private_other, app.private_other());
364 
365     memoryPlugin.Stop();
366 }
367 
368 /**
369  * @tc.name: memory plugin
370  * @tc.desc: pid list information test for specific pids.
371  * @tc.type: FUNC
372  */
373 HWTEST_F(MemoryDataPluginTest, Testpluginforpids, TestSize.Level1)
374 {
375     MemoryDataPlugin memoryPlugin;
376     MemoryData memoryData;
377     MemoryConfig protoConfig;
378 
379     std::vector<int> cmpPidList = {1, 2, 11};
380     EXPECT_NE((size_t)0, cmpPidList.size());
381 
382     memoryPlugin.SetPath(const_cast<char*>(g_path.c_str()));
383 
384     SetPluginProcessConfig(cmpPidList, protoConfig);
385     EXPECT_TRUE(PluginStub(memoryPlugin, protoConfig, memoryData));
386 
387     int index = memoryData.processesinfo_size();
388     EXPECT_EQ(3, index);
389     for (int i = 0; i < index; ++i) {
390         ProcessMemoryInfo it = memoryData.processesinfo(i);
391         EXPECT_EQ(g_pidtarget[i].pid, it.pid());
392         EXPECT_EQ(g_pidtarget[i].name, it.name());
393         EXPECT_EQ(g_pidtarget[i].vm_size_kb, it.vm_size_kb());
394         EXPECT_EQ(g_pidtarget[i].vm_rss_kb, it.vm_rss_kb());
395         EXPECT_EQ(g_pidtarget[i].rss_anon_kb, it.rss_anon_kb());
396         EXPECT_EQ(g_pidtarget[i].rss_file_kb, it.rss_file_kb());
397         EXPECT_EQ(g_pidtarget[i].rss_shmem_kb, it.rss_shmem_kb());
398         EXPECT_EQ(g_pidtarget[i].vm_locked_kb, it.vm_locked_kb());
399         EXPECT_EQ(g_pidtarget[i].vm_hwm_kb, it.vm_hwm_kb());
400 
401         EXPECT_EQ(g_pidtarget[i].oom_score_adj, it.oom_score_adj());
402 
403         EXPECT_TRUE(it.has_memsummary());
404     }
405 
406     memoryPlugin.Stop();
407 }
408 
409 /**
410  * @tc.name: memory plugin
411  * @tc.desc: Smaps stats info test for specific pids.
412  * @tc.type: FUNC
413  */
414 HWTEST_F(MemoryDataPluginTest, TestSmapsStatsInfo, TestSize.Level1)
415 {
416     const std::vector<int> expectPidList = {1, 2, 11};
417 
418     SmapsStats smap(std::string(g_path + "/"));
419     for (size_t i = 0; i < expectPidList.size(); i++) {
420         EXPECT_TRUE(smap.ParseMaps(expectPidList[i]));
421         EXPECT_EQ(g_pidtarget[i].java_heap, (uint64_t)(smap.GetProcessJavaHeap()));
422         EXPECT_EQ(g_pidtarget[i].native_heap, (uint64_t)(smap.GetProcessNativeHeap()));
423         EXPECT_EQ(g_pidtarget[i].code, (uint64_t)(smap.GetProcessCode()));
424         EXPECT_EQ(g_pidtarget[i].stack, (uint64_t)(smap.GetProcessStack()));
425         EXPECT_EQ(g_pidtarget[i].graphics, (uint64_t)(smap.GetProcessGraphics()));
426         EXPECT_EQ(g_pidtarget[i].private_other, (uint64_t)(smap.GetProcessPrivateOther()));
427     }
428 }
429 
430 /**
431  * @tc.name: memory plugin
432  * @tc.desc: Vmstat info test for specific pids.
433  * @tc.type: FUNC
434  */
435 HWTEST_F(MemoryDataPluginTest, TestpluginWriteVmstat, TestSize.Level1)
436 {
437     MemoryDataPlugin memoryPlugin;
438     MemoryData memoryData;
439     MemoryConfig protoConfig;
440 
441     protoConfig.set_report_sysmem_vmem_info(true);
442     EXPECT_TRUE(PluginStub(memoryPlugin, protoConfig, memoryData));
443 
444     memoryPlugin.Stop();
445 }
446 
447 /**
448  * @tc.name: memory plugin
449  * @tc.desc: Get information through MemoryService.
450  * @tc.type: FUNC
451  */
452 HWTEST_F(MemoryDataPluginTest, TestpluginMemoryService, TestSize.Level1)
453 {
454     MemoryDataPlugin memoryPlugin;
455     MemoryData memoryData;
456     MemoryConfig protoConfig;
457 
458     SetPluginMemoryServiceConfig(protoConfig);
459     EXPECT_TRUE(PluginStub(memoryPlugin, protoConfig, memoryData));
460     std::string line = "01234567890";
461     memoryPlugin.ParseNumber(line);
462 
463     ProcessMemoryInfo it = memoryData.processesinfo(0);
464     EXPECT_FALSE(it.has_memsummary());
465     AppSummary app = it.memsummary();
466     EXPECT_EQ((uint64_t)0, app.java_heap());
467     EXPECT_EQ((uint64_t)0, app.native_heap());
468     EXPECT_EQ((uint64_t)0, app.code());
469     EXPECT_EQ((uint64_t)0, app.stack());
470     EXPECT_EQ((uint64_t)0, app.graphics());
471     EXPECT_EQ((uint64_t)0, app.private_other());
472 
473     memoryPlugin.Stop();
474 }
475 
WriteFunc(WriterStruct * writer,const void * data,size_t size)476 long WriteFunc(WriterStruct* writer, const void* data, size_t size)
477 {
478     if (writer == nullptr || data == nullptr || size <= 0) {
479         return -1;
480     }
481     return 0;
482 }
483 
FlushFunc(WriterStruct * writer)484 bool FlushFunc(WriterStruct* writer)
485 {
486     if (writer == nullptr) {
487         return false;
488     }
489     return true;
490 }
491 
492 /**
493  * @tc.name: mem plugin
494  * @tc.desc: test register
495  * @tc.type: FUNC
496  */
497 HWTEST_F(MemoryDataPluginTest, TestRegister, TestSize.Level1)
498 {
499     std::string path = DEFAULT_SO_PATH + std::string("libmemdataplugin.z.so");
500     void* handle = dlopen(path.c_str(), RTLD_LAZY);
501     EXPECT_NE(handle, nullptr);
502     PluginModuleStruct* plugin = reinterpret_cast<PluginModuleStruct*>(dlsym(handle, "g_pluginModule"));
503     EXPECT_NE(plugin, nullptr);
504     EXPECT_STREQ(plugin->name, "memory-plugin");
505 
506     // set config
507     MemoryConfig config;
508     config.set_report_process_mem_info(true);
509     int size = config.ByteSizeLong();
510     ASSERT_GT(size, 0);
511     std::vector<uint8_t> configData(size);
512     ASSERT_GT(config.SerializeToArray(configData.data(), configData.size()), 0);
513 
514     // test framework process
515     WriterStruct writer = {WriteFunc, FlushFunc};
516     std::vector<uint8_t> dataBuffer(plugin->resultBufferSizeHint);
517     EXPECT_EQ(plugin->callbacks->onRegisterWriterStruct(&writer), 0);
518 }
519 
520 /**
521  * @tc.name: mem plugin
522  * @tc.desc: start fail test
523  * @tc.type: FUNC
524  */
525 HWTEST_F(MemoryDataPluginTest, TestStartFail, TestSize.Level1)
526 {
527     MemoryConfig config;
528     MemoryDataPlugin plugin;
529 
530     // set config
531     config.set_report_process_mem_info(true);
532 
533     // serialize
534     int size = config.ByteSizeLong();
535     ASSERT_GT(size, 0);
536     std::vector<uint8_t> configData(size);
537     ASSERT_GT(config.SerializeToArray(configData.data(), configData.size()), 0);
538 
539     // start
540     EXPECT_NE(plugin.Start(configData.data(), size - 1), 0);
541 }
542 
543 /**
544  * @tc.name: mem plugin
545  * @tc.desc: Framework test
546  * @tc.type: FUNC
547  */
548 HWTEST_F(MemoryDataPluginTest, TestFramework, TestSize.Level1)
549 {
550     std::string path = DEFAULT_SO_PATH + std::string("libmemdataplugin.z.so");
551     void* handle = dlopen(path.c_str(), RTLD_LAZY);
552     EXPECT_NE(handle, nullptr);
553     PluginModuleStruct* plugin = reinterpret_cast<PluginModuleStruct*>(dlsym(handle, "g_pluginModule"));
554     EXPECT_NE(plugin, nullptr);
555     EXPECT_STREQ(plugin->name, "memory-plugin");
556 
557     // set config
558     MemoryConfig config;
559     config.set_report_process_mem_info(true);
560     int size = config.ByteSizeLong();
561     ASSERT_GT(size, 0);
562     std::vector<uint8_t> configData(size);
563     ASSERT_GT(config.SerializeToArray(configData.data(), configData.size()), 0);
564 
565     // test framework process
566     std::vector<uint8_t> dataBuffer(plugin->resultBufferSizeHint);
567     EXPECT_EQ(plugin->callbacks->onPluginSessionStart(configData.data(), configData.size()), 0);
568     EXPECT_EQ(plugin->callbacks->onPluginReportResult(dataBuffer.data(), dataBuffer.size()), 0);
569     EXPECT_EQ(plugin->callbacks->onPluginSessionStop(), 0);
570 }
571 
OutputData(uint8_t * data,uint32_t size)572 void OutputData(uint8_t* data, uint32_t size)
573 {
574     MemoryData memoryData;
575     int ret = memoryData.ParseFromArray(data, size);
576     if (ret <= 0) {
577         HILOG_ERROR(LOG_CORE, "MemoryDataPluginTest, %s:parseFromArray failed!", __func__);
578         return;
579     }
580 
581     return;
582 }
583 
584 /**
585  * @tc.name: mem plugin
586  * @tc.desc: ProcessTree test
587  * @tc.type: FUNC
588  */
589 HWTEST_F(MemoryDataPluginTest, TestProcessTreeRunTime, TestSize.Level1)
590 {
591     std::string path = DEFAULT_SO_PATH + std::string("libmemdataplugin.z.so");
592     void* handle = dlopen(path.c_str(), RTLD_LAZY);
593     EXPECT_NE(handle, nullptr);
594     PluginModuleStruct* plugin = reinterpret_cast<PluginModuleStruct*>(dlsym(handle, "g_pluginModule"));
595     EXPECT_NE(plugin, nullptr);
596     EXPECT_STREQ(plugin->name, "memory-plugin");
597 
598     // set config
599     MemoryConfig config;
600     config.set_report_process_tree(true);
601     int size = config.ByteSizeLong();
602     ASSERT_GT(size, 0);
603     std::vector<uint8_t> configData(size);
604     ASSERT_GT(config.SerializeToArray(configData.data(), configData.size()), 0);
605 
606     // test framework process
607     int testCount = 10;
608     struct timeval start, end;
609     std::vector<uint8_t> dataBuffer(plugin->resultBufferSizeHint);
610     EXPECT_EQ(plugin->callbacks->onPluginSessionStart(configData.data(), configData.size()), 0);
611     clock_t clockstart = clock();
612     gettimeofday(&start, NULL);
613     while (testCount--) {
614         int ret = plugin->callbacks->onPluginReportResult(dataBuffer.data(), dataBuffer.size());
615         ASSERT_GT(ret, 0);
616         OutputData(dataBuffer.data(), (uint32_t)ret);
617     }
618     gettimeofday(&end, NULL);
619     clock_t clockend = clock();
620     int timeuse = US_PER_S * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
621     HILOG_INFO(LOG_CORE, "clock time=%.3fs, timeofday=%.3fs", (double)(clockend - clockstart) / CLOCKS_PER_SEC,
622         (double)timeuse / US_PER_S);
623     EXPECT_EQ(plugin->callbacks->onPluginSessionStop(), 0);
624 }
625 
626 namespace {
627 const char* DUMP_FORMAT = R"(Applications Memory Usage (in Kilobytes):
628 Uptime: 559174 Realtime: 559174
629 App Summary
630 Pss(KB)
631 ------
632 Java Heap:  0
633 Native Heap:    2932
634 Code:   640
635 Stack:  60
636 Graphics:   0
637 Private Other:  1056
638 System: 1092
639 TOTAL:  5780      TOTAL SWAP (KB):        0)";
640 }
641 
642 /**
643  * @tc.name: mem plugin
644  * @tc.desc: test ParseMemInfo
645  * @tc.type: FUNC
646  */
647 HWTEST_F(MemoryDataPluginTest, TestParseMemInfo, TestSize.Level1)
648 {
649     MemoryDataPlugin plugin;
650     ProcessMemoryInfo memoryInfo;
651     uint64_t javaHeap = 0;
652     uint64_t nativeHeap = 2932;
653     uint64_t code = 640;
654     uint64_t stack = 60;
655     uint64_t graphics = 0;
656     uint64_t other = 1056;
657     uint64_t system = 1092;
658 
659     ASSERT_TRUE(plugin.ParseMemInfo(DUMP_FORMAT, &memoryInfo));
660     // test result
661     EXPECT_EQ(memoryInfo.mutable_memsummary()->java_heap(), javaHeap);
662     EXPECT_EQ(memoryInfo.mutable_memsummary()->native_heap(), nativeHeap);
663     EXPECT_EQ(memoryInfo.mutable_memsummary()->code(), code);
664     EXPECT_EQ(memoryInfo.mutable_memsummary()->stack(), stack);
665     EXPECT_EQ(memoryInfo.mutable_memsummary()->graphics(), graphics);
666     EXPECT_EQ(memoryInfo.mutable_memsummary()->private_other(), other);
667     EXPECT_EQ(memoryInfo.mutable_memsummary()->system(), system);
668 }
669 
ExecuteBin(const std::string & bin,const std::vector<std::string> & args)670 bool ExecuteBin(const std::string& bin, const std::vector<std::string>& args)
671 {
672     std::vector<char*> argv;
673     for (size_t i = 0; i < args.size(); i++) {
674         argv.push_back(const_cast<char*>(args[i].c_str()));
675     }
676     argv.push_back(nullptr); // last item in argv must be NULL
677 
678     int retval = execvp(bin.c_str(), argv.data());
679     CHECK_TRUE(retval != -1, false, "execv %s failed, %d!", bin.c_str(), errno);
680     _exit(EXIT_FAILURE);
681     abort(); // never should be here.
682     return true;
683 }
684 
685 /**
686  * @tc.name: mem plugin
687  * @tc.desc: test ParseMemInfo
688  * @tc.type: FUNC
689  */
690 HWTEST_F(MemoryDataPluginTest, TestPid, TestSize.Level1)
691 {
692     MemoryDataPlugin plugin;
693     MemoryData memoryData;
694     MemoryConfig config;
695 
696     std::string cmd = "chmod 777 " + DEFAULT_BIN_PATH;
697     system(cmd.c_str());
698     pid_t pid1 = fork();
699     if (pid1 == 0) {
700         std::vector<std::string> argv = {"childpidtest1", "10"};
701         ASSERT_TRUE(ExecuteBin(DEFAULT_BIN_PATH, argv));
702     }
703     pid_t pid2 = fork();
704     if (pid2 == 0) {
705         std::vector<std::string> argv = {"childpidtest2", "1"};
706         ASSERT_TRUE(ExecuteBin(DEFAULT_BIN_PATH, argv));
707     }
708     sleep(1);
709 
710     // set config
711     config.set_report_process_mem_info(true);
712     config.set_report_app_mem_info(true);
713     config.add_pid(pid1);
714     config.add_pid(pid2);
715     // check result
716     EXPECT_TRUE(PluginStub(plugin, config, memoryData));
717     EXPECT_GT(memoryData.processesinfo(0).vm_size_kb(), memoryData.processesinfo(1).vm_size_kb());
718 
719     while (waitpid(-1, NULL, WNOHANG) == 0) {
720         kill(pid1, SIGKILL);
721         kill(pid2, SIGKILL);
722     }
723     plugin.Stop();
724 }
725 } // namespace
726