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