summaryrefslogtreecommitdiff
path: root/pinner/include/meminspect.h
diff options
context:
space:
mode:
Diffstat (limited to 'pinner/include/meminspect.h')
-rw-r--r--pinner/include/meminspect.h268
1 files changed, 268 insertions, 0 deletions
diff --git a/pinner/include/meminspect.h b/pinner/include/meminspect.h
new file mode 100644
index 00000000..a2e09ec2
--- /dev/null
+++ b/pinner/include/meminspect.h
@@ -0,0 +1,268 @@
+#pragma once
+
+#include <android-base/stringprintf.h>
+#include <fcntl.h>
+#include <sys/endian.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <iostream>
+#include <string>
+#include <vector>
+#include "ziparchive/zip_archive.h"
+
+#define MEMINSPECT_FAIL_OPEN 1
+#define MEMINSPECT_FAIL_FSTAT 2
+#define MEMINSPECT_FAIL_MINCORE 3
+
+#define DEFAULT_PAGES_PER_MINCORE 1
+
+/**
+ * This class stores an offset defined vma which exists
+ * relative to another memory address.
+ */
+class VmaRange {
+ public:
+ uint32_t offset;
+ uint32_t length;
+
+ VmaRange() {}
+ VmaRange(uint32_t off, uint32_t len) : offset(off), length(len) {}
+
+ bool is_empty() const;
+
+ /**
+ * @brief Compute the intersection of this range with another range
+ *
+ * Intersection Operation:
+ *
+ * Example 1:
+ * [ Range A ]
+ * [ Range B ]
+ * Intersection:
+ * [ C ]
+ *
+ * Example 2:
+ * [ Range A ] [ Range B ]
+ * No Intersection
+ *
+ * @param target range to test against
+ * @return the intersection range, if none is found, empty range is returned.
+ */
+ VmaRange intersect(const VmaRange& target) const;
+
+ /**
+ * @brief Merges the current range with a target range using a union operation
+ * that is only successful when overlapping ranges occur.
+ * A visual explanation can be seen as:
+ *
+ * Union-merge Operation:
+ *
+ * Example 1:
+ * [ Range A ]
+ * [ Range B ]
+ * Merged:
+ * [ Range C ]
+ *
+ * Example 2:
+ * [ Range A ] [ Range B ]
+ * Fails, no merge available.
+ *
+ * @param target The range to test against.
+ * @param result Upon successfully merging, contains the resulting range.
+ * @return the merged range, if none is found, empty range is returned.
+ */
+ VmaRange union_merge(const VmaRange& target) const;
+
+ uint32_t end_offset() const;
+};
+
+/**
+ * Represents a set of memory ranges
+ */
+struct VmaRangeGroup {
+ std::vector<VmaRange> ranges;
+
+ /**
+ * Compute intersection coverage between |range| and |this->ranges|
+ * and append it to |out_memres|
+ */
+ void compute_coverage(const VmaRange& range, VmaRangeGroup& out_memres) const;
+
+ /**
+ * Apply an offset to all existing |ranges|.
+ */
+ void apply_offset(uint64_t offset);
+
+ /**
+ * Computes total resident bytes from existing set of memory ranges.
+ */
+ uint64_t compute_total_size();
+};
+
+/**
+ * Represents useful immutable metadata for zip entry
+ */
+struct ZipEntryInfo {
+ std::string name;
+ uint64_t offset_in_zip;
+ uint64_t file_size_bytes;
+ uint64_t uncompressed_size;
+};
+
+/**
+ * Represents the resident memory coverage for a zip entry within a zip file.
+ */
+struct ZipEntryCoverage {
+ ZipEntryInfo info;
+
+ /**
+ * Contains all the coverage ranges if any have been computed with |compute_coverage|
+ * and their offsets will be the absolute global offset from the zip file start.
+ */
+ VmaRangeGroup coverage;
+
+ /**
+ * Computes the intersection coverage for the current zip file entry
+ * resident memory against a provided |probe| representing another set
+ * of ranges.
+ */
+ ZipEntryCoverage compute_coverage(const VmaRangeGroup& probe) const;
+};
+
+// Class used for inspecting resident memory for entries within a zip file
+class ZipMemInspector {
+ /**
+ * Stored probe of resident ranges either computed or provided by user.
+ */
+ VmaRangeGroup* probe_resident_ = nullptr;
+
+ /**
+ * List of file entries within zip file.
+ */
+ std::vector<ZipEntryInfo> entry_infos_;
+
+ /**
+ * Path to zip file.
+ */
+ std::string filename_;
+
+ /**
+ * Result of computing coverage operations.
+ */
+ std::vector<ZipEntryCoverage> entry_coverages_;
+
+ /**
+ * Handle that allows reading the zip entries.
+ */
+ ZipArchiveHandle handle_;
+
+ public:
+ ZipMemInspector(std::string filename) : filename_(filename) {}
+ ~ZipMemInspector();
+
+ /**
+ * Reads zip file and computes resident memory coverage per zip entry if
+ * a probe is provided, if no probe is provided, then whole file coverage
+ * will be assumed.
+ *
+ * Note: If any zip entries have been manually added via |add_file_info|
+ * then coverage will be only computed against manually added entries.
+ *
+ * @return 0 on success and 1 on error
+ */
+ int compute_per_file_coverage();
+
+ /**
+ * Computes resident memory for the entire zip file.
+ *
+ * @return 0 on success, 1 on failure
+ */
+ int probe_resident();
+
+ /**
+ * Retrieves the currently set probe if any exists.
+ */
+ VmaRangeGroup* get_probe();
+
+ /**
+ * Sets probe data in case you decide to pass a previously taken probe instead of a live taken
+ * one.
+ */
+ void set_existing_probe(VmaRangeGroup* probe);
+
+ /**
+ * Returns the result of memory coverage of each file if any has been computed via
+ * |compute_per_file_coverage|.
+ */
+ std::vector<ZipEntryCoverage>& get_file_coverages();
+
+ /**
+ * Returns the file information for each zip entry.
+ */
+ std::vector<ZipEntryInfo>& get_file_infos();
+
+ /**
+ * Add a zip entry manually.
+ *
+ * Note: Zip entries are usually retrieved by reading the |filename_| so
+ * this method is mostly used for cases where client wants control of
+ * zip file reading or for testing.
+ */
+ void add_file_info(ZipEntryInfo& file);
+
+ /**
+ * Computes the intersection coverage between provided |files| and |probe|.
+ *
+ * @return result of coverage computation
+ */
+ static std::vector<ZipEntryCoverage> compute_coverage(
+ const std::vector<ZipEntryCoverage>& files, VmaRangeGroup* probe);
+
+ private:
+ /**
+ * Read files and zip relative offsets for them.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+ int read_files_and_offsets();
+};
+
+/**
+ * Retrieve file size in bytes for |file|
+ *
+ * @return positive value with file size on success, otherwise, returns -1 on error.
+ */
+int64_t get_file_size(const std::string& file);
+
+/**
+ * @brief Probe resident memory for a currently opened file in the system.
+ *
+ * @param probed_file File to probe as defined by its path.
+ * @param out_resident_mem Inspection result. This is populated when called.
+ * @param pages_per_mincore Size of mincore window used, bigger means more memory used
+ * during operation but slightly faster.
+ * @return 0 on success or on failure a non-zero error code from the following list:
+ * MEMINSPECT_FAIL_OPEN, MEMINSPECT_FAIL_FSTAT, MEMINSPECT_FAIL_MINCORE
+ */
+int probe_resident_memory(std::string probed_file, VmaRangeGroup& out_resident_mem,
+ int pages_per_mincore = DEFAULT_PAGES_PER_MINCORE);
+
+/**
+ * @brief Align vma ranges to a certain page size
+ *
+ * @param ranges vma ranges that have to be aligned
+ * @param alignment Desired alignment, this is usually the page size.
+ */
+void align_ranges(std::vector<VmaRange>& ranges, unsigned int alignment);
+
+/**
+ * @brief Merges a list of ranges following a union-like merge which
+ * means that two ranges that overlap will avoid double accounting for
+ * overlaps.
+ *
+ * @param ranges vma ranges that need to be merged.
+ * @return new vector with ranges merged.
+ */
+std::vector<VmaRange> merge_ranges(const std::vector<VmaRange>& ranges); \ No newline at end of file