xref: /aosp_15_r20/system/extras/pinner/include/meminspect.h (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker #pragma once
2*288bf522SAndroid Build Coastguard Worker 
3*288bf522SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
4*288bf522SAndroid Build Coastguard Worker #include <fcntl.h>
5*288bf522SAndroid Build Coastguard Worker #include <sys/endian.h>
6*288bf522SAndroid Build Coastguard Worker #include <sys/mman.h>
7*288bf522SAndroid Build Coastguard Worker #include <sys/stat.h>
8*288bf522SAndroid Build Coastguard Worker #include <sys/types.h>
9*288bf522SAndroid Build Coastguard Worker #include <unistd.h>
10*288bf522SAndroid Build Coastguard Worker #include <iostream>
11*288bf522SAndroid Build Coastguard Worker #include <string>
12*288bf522SAndroid Build Coastguard Worker #include <vector>
13*288bf522SAndroid Build Coastguard Worker #include "ziparchive/zip_archive.h"
14*288bf522SAndroid Build Coastguard Worker 
15*288bf522SAndroid Build Coastguard Worker #define MEMINSPECT_FAIL_OPEN 1
16*288bf522SAndroid Build Coastguard Worker #define MEMINSPECT_FAIL_FSTAT 2
17*288bf522SAndroid Build Coastguard Worker #define MEMINSPECT_FAIL_MINCORE 3
18*288bf522SAndroid Build Coastguard Worker 
19*288bf522SAndroid Build Coastguard Worker #define DEFAULT_PAGES_PER_MINCORE 1
20*288bf522SAndroid Build Coastguard Worker 
21*288bf522SAndroid Build Coastguard Worker /**
22*288bf522SAndroid Build Coastguard Worker  * This class stores an offset defined vma which exists
23*288bf522SAndroid Build Coastguard Worker  * relative to another memory address.
24*288bf522SAndroid Build Coastguard Worker  */
25*288bf522SAndroid Build Coastguard Worker class VmaRange {
26*288bf522SAndroid Build Coastguard Worker   public:
27*288bf522SAndroid Build Coastguard Worker     uint32_t offset;
28*288bf522SAndroid Build Coastguard Worker     uint32_t length;
29*288bf522SAndroid Build Coastguard Worker 
VmaRange()30*288bf522SAndroid Build Coastguard Worker     VmaRange() {}
VmaRange(uint32_t off,uint32_t len)31*288bf522SAndroid Build Coastguard Worker     VmaRange(uint32_t off, uint32_t len) : offset(off), length(len) {}
32*288bf522SAndroid Build Coastguard Worker 
33*288bf522SAndroid Build Coastguard Worker     bool is_empty() const;
34*288bf522SAndroid Build Coastguard Worker 
35*288bf522SAndroid Build Coastguard Worker     /**
36*288bf522SAndroid Build Coastguard Worker      * @brief Compute the intersection of this range with another range
37*288bf522SAndroid Build Coastguard Worker      *
38*288bf522SAndroid Build Coastguard Worker      * Intersection Operation:
39*288bf522SAndroid Build Coastguard Worker      *
40*288bf522SAndroid Build Coastguard Worker      * Example 1:
41*288bf522SAndroid Build Coastguard Worker      * [   Range A    ]
42*288bf522SAndroid Build Coastguard Worker      *          [   Range B   ]
43*288bf522SAndroid Build Coastguard Worker      * Intersection:
44*288bf522SAndroid Build Coastguard Worker      *          [  C  ]
45*288bf522SAndroid Build Coastguard Worker      *
46*288bf522SAndroid Build Coastguard Worker      * Example 2:
47*288bf522SAndroid Build Coastguard Worker      * [   Range A    ]    [   Range B   ]
48*288bf522SAndroid Build Coastguard Worker      * No Intersection
49*288bf522SAndroid Build Coastguard Worker      *
50*288bf522SAndroid Build Coastguard Worker      * @param target range to test against
51*288bf522SAndroid Build Coastguard Worker      * @return the intersection range, if none is found, empty range is returned.
52*288bf522SAndroid Build Coastguard Worker      */
53*288bf522SAndroid Build Coastguard Worker     VmaRange intersect(const VmaRange& target) const;
54*288bf522SAndroid Build Coastguard Worker 
55*288bf522SAndroid Build Coastguard Worker     /**
56*288bf522SAndroid Build Coastguard Worker      * @brief Merges the current range with a target range using a union operation
57*288bf522SAndroid Build Coastguard Worker      * that is only successful when overlapping ranges occur.
58*288bf522SAndroid Build Coastguard Worker      * A visual explanation can be seen as:
59*288bf522SAndroid Build Coastguard Worker      *
60*288bf522SAndroid Build Coastguard Worker      * Union-merge Operation:
61*288bf522SAndroid Build Coastguard Worker      *
62*288bf522SAndroid Build Coastguard Worker      * Example 1:
63*288bf522SAndroid Build Coastguard Worker      * [   Range A    ]
64*288bf522SAndroid Build Coastguard Worker      *          [   Range B   ]
65*288bf522SAndroid Build Coastguard Worker      * Merged:
66*288bf522SAndroid Build Coastguard Worker      * [       Range C        ]
67*288bf522SAndroid Build Coastguard Worker      *
68*288bf522SAndroid Build Coastguard Worker      * Example 2:
69*288bf522SAndroid Build Coastguard Worker      * [   Range A    ]    [   Range B   ]
70*288bf522SAndroid Build Coastguard Worker      * Fails, no merge available.
71*288bf522SAndroid Build Coastguard Worker      *
72*288bf522SAndroid Build Coastguard Worker      * @param target The range to test against.
73*288bf522SAndroid Build Coastguard Worker      * @param result Upon successfully merging, contains the resulting range.
74*288bf522SAndroid Build Coastguard Worker      * @return the merged range, if none is found, empty range is returned.
75*288bf522SAndroid Build Coastguard Worker      */
76*288bf522SAndroid Build Coastguard Worker     VmaRange union_merge(const VmaRange& target) const;
77*288bf522SAndroid Build Coastguard Worker 
78*288bf522SAndroid Build Coastguard Worker     uint32_t end_offset() const;
79*288bf522SAndroid Build Coastguard Worker };
80*288bf522SAndroid Build Coastguard Worker 
81*288bf522SAndroid Build Coastguard Worker /**
82*288bf522SAndroid Build Coastguard Worker  * Represents a set of memory ranges
83*288bf522SAndroid Build Coastguard Worker  */
84*288bf522SAndroid Build Coastguard Worker struct VmaRangeGroup {
85*288bf522SAndroid Build Coastguard Worker     std::vector<VmaRange> ranges;
86*288bf522SAndroid Build Coastguard Worker 
87*288bf522SAndroid Build Coastguard Worker     /**
88*288bf522SAndroid Build Coastguard Worker      * Compute intersection coverage between |range| and |this->ranges|
89*288bf522SAndroid Build Coastguard Worker      * and append it to |out_memres|
90*288bf522SAndroid Build Coastguard Worker      */
91*288bf522SAndroid Build Coastguard Worker     void compute_coverage(const VmaRange& range, VmaRangeGroup& out_memres) const;
92*288bf522SAndroid Build Coastguard Worker 
93*288bf522SAndroid Build Coastguard Worker     /**
94*288bf522SAndroid Build Coastguard Worker      * Apply an offset to all existing |ranges|.
95*288bf522SAndroid Build Coastguard Worker      */
96*288bf522SAndroid Build Coastguard Worker     void apply_offset(uint64_t offset);
97*288bf522SAndroid Build Coastguard Worker 
98*288bf522SAndroid Build Coastguard Worker     /**
99*288bf522SAndroid Build Coastguard Worker      * Computes total resident bytes from existing set of memory ranges.
100*288bf522SAndroid Build Coastguard Worker      */
101*288bf522SAndroid Build Coastguard Worker     uint64_t compute_total_size();
102*288bf522SAndroid Build Coastguard Worker };
103*288bf522SAndroid Build Coastguard Worker 
104*288bf522SAndroid Build Coastguard Worker /**
105*288bf522SAndroid Build Coastguard Worker  * Represents useful immutable metadata for zip entry
106*288bf522SAndroid Build Coastguard Worker  */
107*288bf522SAndroid Build Coastguard Worker struct ZipEntryInfo {
108*288bf522SAndroid Build Coastguard Worker     std::string name;
109*288bf522SAndroid Build Coastguard Worker     uint64_t offset_in_zip;
110*288bf522SAndroid Build Coastguard Worker     uint64_t file_size_bytes;
111*288bf522SAndroid Build Coastguard Worker     uint64_t uncompressed_size;
112*288bf522SAndroid Build Coastguard Worker };
113*288bf522SAndroid Build Coastguard Worker 
114*288bf522SAndroid Build Coastguard Worker /**
115*288bf522SAndroid Build Coastguard Worker  * Represents the resident memory coverage for a zip entry within a zip file.
116*288bf522SAndroid Build Coastguard Worker  */
117*288bf522SAndroid Build Coastguard Worker struct ZipEntryCoverage {
118*288bf522SAndroid Build Coastguard Worker     ZipEntryInfo info;
119*288bf522SAndroid Build Coastguard Worker 
120*288bf522SAndroid Build Coastguard Worker     /**
121*288bf522SAndroid Build Coastguard Worker      * Contains all the coverage ranges if any have been computed with |compute_coverage|
122*288bf522SAndroid Build Coastguard Worker      * and their offsets will be the absolute global offset from the zip file start.
123*288bf522SAndroid Build Coastguard Worker      */
124*288bf522SAndroid Build Coastguard Worker     VmaRangeGroup coverage;
125*288bf522SAndroid Build Coastguard Worker 
126*288bf522SAndroid Build Coastguard Worker     /**
127*288bf522SAndroid Build Coastguard Worker      * Computes the intersection coverage for the current zip file entry
128*288bf522SAndroid Build Coastguard Worker      * resident memory against a provided |probe| representing another set
129*288bf522SAndroid Build Coastguard Worker      * of ranges.
130*288bf522SAndroid Build Coastguard Worker      */
131*288bf522SAndroid Build Coastguard Worker     ZipEntryCoverage compute_coverage(const VmaRangeGroup& probe) const;
132*288bf522SAndroid Build Coastguard Worker };
133*288bf522SAndroid Build Coastguard Worker 
134*288bf522SAndroid Build Coastguard Worker // Class used for inspecting resident memory for entries within a zip file
135*288bf522SAndroid Build Coastguard Worker class ZipMemInspector {
136*288bf522SAndroid Build Coastguard Worker     /**
137*288bf522SAndroid Build Coastguard Worker      * Stored probe of resident ranges either computed or provided by user.
138*288bf522SAndroid Build Coastguard Worker      */
139*288bf522SAndroid Build Coastguard Worker     VmaRangeGroup* probe_resident_ = nullptr;
140*288bf522SAndroid Build Coastguard Worker 
141*288bf522SAndroid Build Coastguard Worker     /**
142*288bf522SAndroid Build Coastguard Worker      * List of file entries within zip file.
143*288bf522SAndroid Build Coastguard Worker      */
144*288bf522SAndroid Build Coastguard Worker     std::vector<ZipEntryInfo> entry_infos_;
145*288bf522SAndroid Build Coastguard Worker 
146*288bf522SAndroid Build Coastguard Worker     /**
147*288bf522SAndroid Build Coastguard Worker      * Path to zip file.
148*288bf522SAndroid Build Coastguard Worker      */
149*288bf522SAndroid Build Coastguard Worker     std::string filename_;
150*288bf522SAndroid Build Coastguard Worker 
151*288bf522SAndroid Build Coastguard Worker     /**
152*288bf522SAndroid Build Coastguard Worker      * Result of computing coverage operations.
153*288bf522SAndroid Build Coastguard Worker      */
154*288bf522SAndroid Build Coastguard Worker     std::vector<ZipEntryCoverage> entry_coverages_;
155*288bf522SAndroid Build Coastguard Worker 
156*288bf522SAndroid Build Coastguard Worker     /**
157*288bf522SAndroid Build Coastguard Worker      * Handle that allows reading the zip entries.
158*288bf522SAndroid Build Coastguard Worker      */
159*288bf522SAndroid Build Coastguard Worker     ZipArchiveHandle handle_;
160*288bf522SAndroid Build Coastguard Worker 
161*288bf522SAndroid Build Coastguard Worker   public:
ZipMemInspector(std::string filename)162*288bf522SAndroid Build Coastguard Worker     ZipMemInspector(std::string filename) : filename_(filename) {}
163*288bf522SAndroid Build Coastguard Worker     ~ZipMemInspector();
164*288bf522SAndroid Build Coastguard Worker 
165*288bf522SAndroid Build Coastguard Worker     /**
166*288bf522SAndroid Build Coastguard Worker      * Reads zip file and computes resident memory coverage per zip entry if
167*288bf522SAndroid Build Coastguard Worker      * a probe is provided, if no probe is provided, then whole file coverage
168*288bf522SAndroid Build Coastguard Worker      * will be assumed.
169*288bf522SAndroid Build Coastguard Worker      *
170*288bf522SAndroid Build Coastguard Worker      * Note: If any zip entries have been manually added via |add_file_info|
171*288bf522SAndroid Build Coastguard Worker      * then coverage will be only computed against manually added entries.
172*288bf522SAndroid Build Coastguard Worker      *
173*288bf522SAndroid Build Coastguard Worker      * @return 0 on success and 1 on error
174*288bf522SAndroid Build Coastguard Worker      */
175*288bf522SAndroid Build Coastguard Worker     int compute_per_file_coverage();
176*288bf522SAndroid Build Coastguard Worker 
177*288bf522SAndroid Build Coastguard Worker     /**
178*288bf522SAndroid Build Coastguard Worker      * Computes resident memory for the entire zip file.
179*288bf522SAndroid Build Coastguard Worker      *
180*288bf522SAndroid Build Coastguard Worker      * @return 0 on success, 1 on failure
181*288bf522SAndroid Build Coastguard Worker      */
182*288bf522SAndroid Build Coastguard Worker     int probe_resident();
183*288bf522SAndroid Build Coastguard Worker 
184*288bf522SAndroid Build Coastguard Worker     /**
185*288bf522SAndroid Build Coastguard Worker      * Retrieves the currently set probe if any exists.
186*288bf522SAndroid Build Coastguard Worker      */
187*288bf522SAndroid Build Coastguard Worker     VmaRangeGroup* get_probe();
188*288bf522SAndroid Build Coastguard Worker 
189*288bf522SAndroid Build Coastguard Worker     /**
190*288bf522SAndroid Build Coastguard Worker      * Sets probe data in case you decide to pass a previously taken probe instead of a live taken
191*288bf522SAndroid Build Coastguard Worker      * one.
192*288bf522SAndroid Build Coastguard Worker      */
193*288bf522SAndroid Build Coastguard Worker     void set_existing_probe(VmaRangeGroup* probe);
194*288bf522SAndroid Build Coastguard Worker 
195*288bf522SAndroid Build Coastguard Worker     /**
196*288bf522SAndroid Build Coastguard Worker      * Returns the result of memory coverage of each file if any has been computed via
197*288bf522SAndroid Build Coastguard Worker      * |compute_per_file_coverage|.
198*288bf522SAndroid Build Coastguard Worker      */
199*288bf522SAndroid Build Coastguard Worker     std::vector<ZipEntryCoverage>& get_file_coverages();
200*288bf522SAndroid Build Coastguard Worker 
201*288bf522SAndroid Build Coastguard Worker     /**
202*288bf522SAndroid Build Coastguard Worker      * Returns the file information for each zip entry.
203*288bf522SAndroid Build Coastguard Worker      */
204*288bf522SAndroid Build Coastguard Worker     std::vector<ZipEntryInfo>& get_file_infos();
205*288bf522SAndroid Build Coastguard Worker 
206*288bf522SAndroid Build Coastguard Worker     /**
207*288bf522SAndroid Build Coastguard Worker      * Add a zip entry manually.
208*288bf522SAndroid Build Coastguard Worker      *
209*288bf522SAndroid Build Coastguard Worker      * Note: Zip entries are usually retrieved by reading the |filename_| so
210*288bf522SAndroid Build Coastguard Worker      * this method is mostly used for cases where client wants control of
211*288bf522SAndroid Build Coastguard Worker      * zip file reading or for testing.
212*288bf522SAndroid Build Coastguard Worker      */
213*288bf522SAndroid Build Coastguard Worker     void add_file_info(ZipEntryInfo& file);
214*288bf522SAndroid Build Coastguard Worker 
215*288bf522SAndroid Build Coastguard Worker     /**
216*288bf522SAndroid Build Coastguard Worker      * Computes the intersection coverage between provided |files| and |probe|.
217*288bf522SAndroid Build Coastguard Worker      *
218*288bf522SAndroid Build Coastguard Worker      * @return result of coverage computation
219*288bf522SAndroid Build Coastguard Worker      */
220*288bf522SAndroid Build Coastguard Worker     static std::vector<ZipEntryCoverage> compute_coverage(
221*288bf522SAndroid Build Coastguard Worker             const std::vector<ZipEntryCoverage>& files, VmaRangeGroup* probe);
222*288bf522SAndroid Build Coastguard Worker 
223*288bf522SAndroid Build Coastguard Worker   private:
224*288bf522SAndroid Build Coastguard Worker     /**
225*288bf522SAndroid Build Coastguard Worker      * Read files and zip relative offsets for them.
226*288bf522SAndroid Build Coastguard Worker      *
227*288bf522SAndroid Build Coastguard Worker      * @return 0 on success, 1 on failure.
228*288bf522SAndroid Build Coastguard Worker      */
229*288bf522SAndroid Build Coastguard Worker     int read_files_and_offsets();
230*288bf522SAndroid Build Coastguard Worker };
231*288bf522SAndroid Build Coastguard Worker 
232*288bf522SAndroid Build Coastguard Worker /**
233*288bf522SAndroid Build Coastguard Worker  * Retrieve file size in bytes for |file|
234*288bf522SAndroid Build Coastguard Worker  *
235*288bf522SAndroid Build Coastguard Worker  * @return positive value with file size on success, otherwise, returns -1 on error.
236*288bf522SAndroid Build Coastguard Worker  */
237*288bf522SAndroid Build Coastguard Worker int64_t get_file_size(const std::string& file);
238*288bf522SAndroid Build Coastguard Worker 
239*288bf522SAndroid Build Coastguard Worker /**
240*288bf522SAndroid Build Coastguard Worker  * @brief Probe resident memory for a currently opened file in the system.
241*288bf522SAndroid Build Coastguard Worker  *
242*288bf522SAndroid Build Coastguard Worker  * @param probed_file File to probe as defined by its path.
243*288bf522SAndroid Build Coastguard Worker  * @param out_resident_mem Inspection result. This is populated when called.
244*288bf522SAndroid Build Coastguard Worker  * @param pages_per_mincore Size of mincore window used, bigger means more memory used
245*288bf522SAndroid Build Coastguard Worker  * during operation but slightly faster.
246*288bf522SAndroid Build Coastguard Worker  * @return 0 on success or on failure a non-zero error code from the following list:
247*288bf522SAndroid Build Coastguard Worker  * MEMINSPECT_FAIL_OPEN, MEMINSPECT_FAIL_FSTAT, MEMINSPECT_FAIL_MINCORE
248*288bf522SAndroid Build Coastguard Worker  */
249*288bf522SAndroid Build Coastguard Worker int probe_resident_memory(std::string probed_file, VmaRangeGroup& out_resident_mem,
250*288bf522SAndroid Build Coastguard Worker                           int pages_per_mincore = DEFAULT_PAGES_PER_MINCORE);
251*288bf522SAndroid Build Coastguard Worker 
252*288bf522SAndroid Build Coastguard Worker /**
253*288bf522SAndroid Build Coastguard Worker  * @brief Align vma ranges to a certain page size
254*288bf522SAndroid Build Coastguard Worker  *
255*288bf522SAndroid Build Coastguard Worker  * @param ranges vma ranges that have to be aligned
256*288bf522SAndroid Build Coastguard Worker  * @param alignment Desired alignment, this is usually the page size.
257*288bf522SAndroid Build Coastguard Worker  */
258*288bf522SAndroid Build Coastguard Worker void align_ranges(std::vector<VmaRange>& ranges, unsigned int alignment);
259*288bf522SAndroid Build Coastguard Worker 
260*288bf522SAndroid Build Coastguard Worker /**
261*288bf522SAndroid Build Coastguard Worker  * @brief Merges a list of ranges following a union-like merge which
262*288bf522SAndroid Build Coastguard Worker  * means that two ranges that overlap will avoid double accounting for
263*288bf522SAndroid Build Coastguard Worker  * overlaps.
264*288bf522SAndroid Build Coastguard Worker  *
265*288bf522SAndroid Build Coastguard Worker  * @param ranges vma ranges that need to be merged.
266*288bf522SAndroid Build Coastguard Worker  * @return new vector with ranges merged.
267*288bf522SAndroid Build Coastguard Worker  */
268*288bf522SAndroid Build Coastguard Worker std::vector<VmaRange> merge_ranges(const std::vector<VmaRange>& ranges);