1 #include <gtest/gtest.h>
2 #include <stdio.h>
3
4 #include <meminspect.h>
5
6 using namespace std;
7
8 /**
9 * This test is meant to be ran by directly pushing the test binary
10 * into the device as using atest will not provide sufficient privileges
11 * to execute drop_caches command.
12 */
TEST(meminspect_test,inspect_matches_resident)13 TEST(meminspect_test, inspect_matches_resident) {
14 // Create test file
15 string test_file = "/data/local/tmp/meminspect_test";
16 // If for any reason a test file already existed from a previous test, remove it.
17 remove(test_file.c_str());
18
19 int test_file_fd = open(test_file.c_str(), O_RDWR | O_CREAT, "w");
20 unsigned int page_size = sysconf(_SC_PAGESIZE);
21 if (test_file_fd == -1) {
22 ADD_FAILURE() << "Failed to open test file for writing. errno: " << std::strerror(errno);
23 close(test_file_fd);
24 remove(test_file.c_str());
25 return;
26 }
27
28 uint8_t* page_data = new uint8_t[page_size];
29 for (unsigned int i = 0; i < page_size; ++i) {
30 page_data[i] = i + 1;
31 }
32 int pages_to_write = 100;
33 for (int page = 0; page < pages_to_write; ++page) {
34 write(test_file_fd, page_data, page_size);
35 }
36 // fsync to ensure the data is flushed to disk.
37 if (fsync(test_file_fd) == -1) {
38 ADD_FAILURE() << "fsync failed errno: " << std::strerror(errno);
39 close(test_file_fd);
40 remove(test_file.c_str());
41 return;
42 }
43 close(test_file_fd);
44
45 // Drop the pagecache to ensure we do not have memory due to it staying there after write.
46 int drop_cache_fd = open("/proc/sys/vm/drop_caches", O_WRONLY);
47 if (drop_cache_fd == -1) {
48 ADD_FAILURE() << "failed opening drop caches fd errno: " << std::strerror(errno);
49 close(test_file_fd);
50 remove(test_file.c_str());
51 return;
52 }
53 write(drop_cache_fd, "3", 1);
54 fsync(drop_cache_fd);
55 close(drop_cache_fd);
56
57 // Open file and page in some memory
58 test_file_fd = open(test_file.c_str(), O_RDONLY, "r");
59 if (test_file_fd == -1) {
60 ADD_FAILURE() << "Failed to open test file for reading after creation. errno: "
61 << std::strerror(errno);
62 close(test_file_fd);
63 remove(test_file.c_str());
64 return;
65 }
66
67 char* base_address = (char*)mmap(0, page_size * pages_to_write, PROT_READ, MAP_SHARED,
68 test_file_fd, /*offset*/ 0);
69 if (base_address == (char*)-1) {
70 ADD_FAILURE() << "Failed to mmap file for reading after creation. errno: "
71 << std::strerror(errno);
72 close(test_file_fd);
73 remove(test_file.c_str());
74 return;
75 }
76
77 VmaRangeGroup vmas_resident;
78 int res = probe_resident_memory(test_file, vmas_resident, 1);
79 EXPECT_TRUE(res == 0);
80
81 // Probing the file without reading anything yields no resident memory
82 EXPECT_TRUE(vmas_resident.ranges.empty());
83
84 // Clear our to start fresh for next probe.
85 vmas_resident = VmaRangeGroup();
86
87 int pages_to_read = 1;
88 char* read_data = new char[pages_to_read];
89 for (int page = 0; page < pages_to_read; ++page) {
90 // Read 1 byte from each page to page it in.
91 read_data[page] = base_address[page * page_size];
92 }
93 res = probe_resident_memory(test_file, vmas_resident, 1);
94 EXPECT_TRUE(res == 0);
95
96 // The amount of memory paged in is outside our control, but we should have some.
97 uint64_t resident_total_size = vmas_resident.compute_total_size();
98 EXPECT_TRUE(resident_total_size > 0);
99 EXPECT_TRUE(vmas_resident.ranges.size() == 1);
100 EXPECT_TRUE(vmas_resident.ranges[0].offset == 0);
101 EXPECT_TRUE((uint64_t)vmas_resident.ranges[0].length == resident_total_size);
102
103 close(test_file_fd);
104 remove(test_file.c_str());
105 }
106
TEST(meminspect_test,custom_probe_coverage_matches_with_probe)107 TEST(meminspect_test, custom_probe_coverage_matches_with_probe) {
108 ZipMemInspector inspector("");
109 VmaRangeGroup* probe = new VmaRangeGroup();
110 probe->ranges.push_back(VmaRange(0, 500));
111 probe->ranges.push_back(VmaRange(700, 100));
112 probe->ranges.push_back(VmaRange(1000, 500));
113 probe->ranges.push_back(VmaRange(2000, 100));
114 // Probed Resident Memory Offset ranges:
115 // [0,500],[700,800],[1000,1500],[2000,2100]
116 EXPECT_EQ(probe->compute_total_size(), (unsigned long long)1200);
117 inspector.set_existing_probe(probe);
118
119 // Emulate reading some files from the zip to compute their coverages
120 // fake1 memory offset ranges [100,300]
121 ZipEntryInfo info;
122 info.name = "fake1";
123 info.offset_in_zip = 100;
124 info.file_size_bytes = 200;
125 inspector.add_file_info(info);
126
127 // fake2 memory offset ranges [600,1200]
128 ZipEntryInfo info2;
129 info2.name = "fake2";
130 info2.offset_in_zip = 600;
131 info2.file_size_bytes = 600;
132 inspector.add_file_info(info2);
133
134 inspector.compute_per_file_coverage();
135 std::vector<ZipEntryCoverage> coverages = inspector.get_file_coverages();
136 EXPECT_EQ(coverages.size(), (size_t)2);
137
138 // Result coverage for fake1 should be: [100,300]
139 EXPECT_EQ(coverages[0].coverage.ranges[0].offset, (uint32_t)100);
140 EXPECT_EQ(coverages[0].coverage.ranges[0].length, (uint32_t)200);
141 EXPECT_EQ(coverages[0].coverage.compute_total_size(), (unsigned long long)200);
142 EXPECT_EQ(coverages[0].info.name, "fake1");
143 EXPECT_EQ(coverages[0].info.offset_in_zip, (uint32_t)100);
144 EXPECT_EQ(coverages[0].info.file_size_bytes, (uint32_t)200);
145
146 // coverage coverage for fake2 should be: [700,800] and [1000,1200]
147 EXPECT_EQ(coverages[1].coverage.ranges[0].offset, (uint32_t)700);
148 EXPECT_EQ(coverages[1].coverage.ranges[0].length, (uint32_t)100);
149 EXPECT_EQ(coverages[1].coverage.ranges[1].offset, (uint32_t)1000);
150 EXPECT_EQ(coverages[1].coverage.ranges[1].length, (uint32_t)200);
151 EXPECT_EQ(coverages[1].coverage.compute_total_size(), (unsigned long long)300); // 100 +
152 // 200
153 EXPECT_EQ(coverages[1].info.name, "fake2");
154 EXPECT_EQ(coverages[1].info.offset_in_zip, (uint32_t)600);
155 EXPECT_EQ(coverages[1].info.file_size_bytes, (uint32_t)600);
156 }
157
TEST(meminspect_test,whole_file_coverage_against_probe)158 TEST(meminspect_test, whole_file_coverage_against_probe) {
159 ZipMemInspector inspector("");
160
161 // Emulate reading some files from the zip to compute their coverages
162 // fake1 memory offset ranges [100,300]
163 ZipEntryInfo info;
164 info.name = "fake1";
165 info.offset_in_zip = 100;
166 info.file_size_bytes = 200;
167 inspector.add_file_info(info);
168
169 // fake2 memory offset ranges [600,1200]
170 ZipEntryInfo info2;
171 info2.name = "fake2";
172 info2.offset_in_zip = 600;
173 info2.file_size_bytes = 600;
174 inspector.add_file_info(info2);
175
176 inspector.compute_per_file_coverage();
177 std::vector<ZipEntryCoverage> coverages = inspector.get_file_coverages();
178 EXPECT_EQ(coverages.size(), (size_t)2);
179
180 // Check that coverage matches entire file sizes
181 EXPECT_EQ(coverages[0].coverage.ranges[0].offset, (uint32_t)100);
182 EXPECT_EQ(coverages[0].coverage.ranges[0].length, (uint32_t)200);
183 EXPECT_EQ(coverages[0].coverage.compute_total_size(), (unsigned long long)200);
184 EXPECT_EQ(coverages[0].info.name, "fake1");
185 EXPECT_EQ(coverages[0].info.offset_in_zip, (uint32_t)100);
186 EXPECT_EQ(coverages[0].info.file_size_bytes, (uint32_t)200);
187
188 EXPECT_EQ(coverages[1].coverage.ranges[0].offset, (uint32_t)600);
189 EXPECT_EQ(coverages[1].coverage.ranges[0].length, (uint32_t)600);
190 EXPECT_EQ(coverages[1].coverage.compute_total_size(), (unsigned long long)600);
191 EXPECT_EQ(coverages[1].info.name, "fake2");
192 EXPECT_EQ(coverages[1].info.offset_in_zip, (uint32_t)600);
193 EXPECT_EQ(coverages[1].info.file_size_bytes, (uint32_t)600);
194 }
195
TEST(meminspect_test,file_multiple_ranges_matches_probe)196 TEST(meminspect_test, file_multiple_ranges_matches_probe) {
197 VmaRangeGroup probe;
198 probe.ranges.push_back(VmaRange(0, 500));
199 probe.ranges.push_back(VmaRange(700, 100));
200 probe.ranges.push_back(VmaRange(1000, 500));
201 probe.ranges.push_back(VmaRange(2000, 100));
202 // Probed Resident Memory Offset ranges:
203 // [0,500],[700,800],[1000,1500],[2000,2100]
204 EXPECT_EQ(probe.compute_total_size(), (unsigned long long)1200);
205
206 std::vector<ZipEntryCoverage> desired_coverages;
207
208 // fake1 file resides between [100,1100]
209 // desired ranges are [100,200],[400,710],[820,850]
210 ZipEntryCoverage file1_mem;
211 file1_mem.info.name = "fake1";
212 file1_mem.info.offset_in_zip = 100;
213 file1_mem.info.file_size_bytes = 1000;
214 file1_mem.coverage.ranges.push_back(VmaRange(100, 100));
215 file1_mem.coverage.ranges.push_back(VmaRange(400, 310));
216 file1_mem.coverage.ranges.push_back(VmaRange(820, 30));
217 desired_coverages.push_back(file1_mem);
218
219 // fake2 memory offset ranges [1300,2100]
220 // desired ranges are [1400,1500],[1600,1650],[1800,2050]
221 ZipEntryCoverage file2_mem;
222 file2_mem.info.name = "fake2";
223 file2_mem.info.offset_in_zip = 1300;
224 file2_mem.info.file_size_bytes = 750;
225 file2_mem.coverage.ranges.push_back(VmaRange(1400, 100));
226 file2_mem.coverage.ranges.push_back(VmaRange(1600, 50));
227 file2_mem.coverage.ranges.push_back(VmaRange(1800, 250));
228 desired_coverages.push_back(file2_mem);
229
230 std::vector<ZipEntryCoverage> coverages =
231 ZipMemInspector::compute_coverage(desired_coverages, &probe);
232
233 EXPECT_EQ(coverages.size(), (size_t)2);
234
235 // Result coverage for fake1 should be: [100,200],[400,500],[700,710]
236 EXPECT_EQ(coverages[0].coverage.ranges[0].offset, (uint32_t)100);
237 EXPECT_EQ(coverages[0].coverage.ranges[0].length, (uint32_t)100);
238 EXPECT_EQ(coverages[0].coverage.ranges[1].offset, (uint32_t)400);
239 EXPECT_EQ(coverages[0].coverage.ranges[1].length, (uint32_t)100);
240 EXPECT_EQ(coverages[0].coverage.ranges[2].offset, (uint32_t)700);
241 EXPECT_EQ(coverages[0].coverage.ranges[2].length, (uint32_t)10);
242
243 EXPECT_EQ(coverages[0].coverage.compute_total_size(), (unsigned long long)210);
244 EXPECT_EQ(coverages[0].info.name, "fake1");
245 EXPECT_EQ(coverages[0].info.offset_in_zip, (uint32_t)100);
246 EXPECT_EQ(coverages[0].info.file_size_bytes, (uint32_t)1000);
247
248 // coverage coverage for fake2 should be: [1400,1500],[2000,2050]
249 EXPECT_EQ(coverages[1].coverage.ranges[0].offset, (uint32_t)1400);
250 EXPECT_EQ(coverages[1].coverage.ranges[0].length, (uint32_t)100);
251 EXPECT_EQ(coverages[1].coverage.ranges[1].offset, (uint32_t)2000);
252 EXPECT_EQ(coverages[1].coverage.ranges[1].length, (uint32_t)50);
253 EXPECT_EQ(coverages[1].coverage.compute_total_size(), (unsigned long long)150);
254 EXPECT_EQ(coverages[1].info.name, "fake2");
255 EXPECT_EQ(coverages[1].info.offset_in_zip, (uint32_t)1300);
256 EXPECT_EQ(coverages[1].info.file_size_bytes, (uint32_t)750);
257 }
258
TEST(meminspect_test,range_alignment_and_merge_matches)259 TEST(meminspect_test, range_alignment_and_merge_matches) {
260 ZipMemInspector inspector("");
261 VmaRangeGroup* probe = new VmaRangeGroup();
262 probe->ranges.push_back(VmaRange(0, 500));
263 probe->ranges.push_back(VmaRange(700, 100));
264 int page_size = 4096;
265
266 // Probed Resident Memory Offset ranges:
267 // [0,500],[700,800]
268 inspector.set_existing_probe(probe);
269
270 // When we page align, we should end up with [0,500],[0,800]
271 align_ranges(probe->ranges, page_size);
272 EXPECT_EQ(probe->ranges[0].offset, (uint32_t)0);
273 EXPECT_EQ(probe->ranges[0].length, (uint32_t)500);
274 EXPECT_EQ(probe->ranges[1].offset, (uint32_t)0);
275 EXPECT_EQ(probe->ranges[1].length, (uint32_t)800);
276 EXPECT_EQ(probe->ranges.size(), (uint32_t)2);
277
278 // Because we have overlapping ranges, a union-merge should
279 // skip duplication of intersections and end up with [0,800]
280 std::vector<VmaRange> merged = merge_ranges(probe->ranges);
281 EXPECT_EQ(merged[0].offset, (uint32_t)0);
282 EXPECT_EQ(merged[0].length, (uint32_t)800);
283 EXPECT_EQ(merged.size(), (uint32_t)1);
284 }