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);