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