• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }