diff options
Diffstat (limited to 'libs/androidfw/include')
-rw-r--r-- | libs/androidfw/include/androidfw/Asset.h | 108 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/AssetManager2.h | 256 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/AttributeResolution.h | 24 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/Chunk.h | 23 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/Errors.h | 47 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/Idmap.h | 4 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/LoadedArsc.h | 37 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/ResourceTypes.h | 70 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/ResourceUtils.h | 9 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/StreamingZipInflater.h | 6 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/Util.h | 8 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/ZipFileRO.h | 27 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/ZipUtils.h | 6 |
13 files changed, 383 insertions, 242 deletions
diff --git a/libs/androidfw/include/androidfw/Asset.h b/libs/androidfw/include/androidfw/Asset.h index 298509eb37a1..80bae20f3419 100644 --- a/libs/androidfw/include/androidfw/Asset.h +++ b/libs/androidfw/include/androidfw/Asset.h @@ -23,18 +23,18 @@ #include <stdio.h> #include <sys/types.h> - #include <memory> +#include <optional> #include <android-base/unique_fd.h> +#include <util/map_ptr.h> + #include <utils/Compat.h> #include <utils/Errors.h> #include <utils/String8.h> namespace android { -class FileMap; - /* * Instances of this class provide read-only operations on a byte stream. * @@ -49,6 +49,8 @@ class FileMap; class Asset { public: virtual ~Asset(void) = default; + Asset(const Asset& src) = delete; + Asset& operator=(const Asset& src) = delete; static int32_t getGlobalCount(); static String8 getAssetAllocations(); @@ -87,8 +89,19 @@ public: /* * Get a pointer to a buffer with the entire contents of the file. + * If `aligned` is true, the buffer data will be aligned to a 4-byte boundary. + * + * Use this function if the asset can never reside on IncFs. */ - virtual const void* getBuffer(bool wordAligned) = 0; + virtual const void* getBuffer(bool aligned) = 0; + + /* + * Get a incfs::map_ptr<void> to a buffer with the entire contents of the file. + * If `aligned` is true, the buffer data will be aligned to a 4-byte boundary. + * + * Use this function if the asset can potentially reside on IncFs. + */ + virtual incfs::map_ptr<void> getIncFsBuffer(bool aligned) = 0; /* * Get the total amount of data that can be read. @@ -152,10 +165,6 @@ protected: AccessMode getAccessMode(void) const { return mAccessMode; } private: - /* these operations are not implemented */ - Asset(const Asset& src); - Asset& operator=(const Asset& src); - /* AssetManager needs access to our "create" functions */ friend class AssetManager; friend class ApkAssets; @@ -169,8 +178,7 @@ private: /* * Create the asset from a named, compressed file on disk (e.g. ".gz"). */ - static Asset* createFromCompressedFile(const char* fileName, - AccessMode mode); + static Asset* createFromCompressedFile(const char* fileName, AccessMode mode); #if 0 /* @@ -200,31 +208,21 @@ private: /* * Create the asset from a memory-mapped file segment. * - * The asset takes ownership of the FileMap. - */ - static Asset* createFromUncompressedMap(FileMap* dataMap, AccessMode mode); - - /* - * Create the asset from a memory-mapped file segment. - * - * The asset takes ownership of the FileMap and the file descriptor "fd". The file descriptor is - * used to request new file descriptors using "openFileDescriptor". + * The asset takes ownership of the incfs::IncFsFileMap and the file descriptor "fd". The + * file descriptor is used to request new file descriptors using "openFileDescriptor". */ - static std::unique_ptr<Asset> createFromUncompressedMap(std::unique_ptr<FileMap> dataMap, - base::unique_fd fd, AccessMode mode); + static std::unique_ptr<Asset> createFromUncompressedMap(incfs::IncFsFileMap&& dataMap, + AccessMode mode, + base::unique_fd fd = {}); /* * Create the asset from a memory-mapped file segment with compressed * data. * - * The asset takes ownership of the FileMap. + * The asset takes ownership of the incfs::IncFsFileMap. */ - static Asset* createFromCompressedMap(FileMap* dataMap, - size_t uncompressedLen, AccessMode mode); - - static std::unique_ptr<Asset> createFromCompressedMap(std::unique_ptr<FileMap> dataMap, - size_t uncompressedLen, AccessMode mode); - + static std::unique_ptr<Asset> createFromCompressedMap(incfs::IncFsFileMap&& dataMap, + size_t uncompressedLen, AccessMode mode); /* * Create from a reference-counted chunk of shared memory. @@ -252,7 +250,7 @@ private: class _FileAsset : public Asset { public: _FileAsset(void); - virtual ~_FileAsset(void); + ~_FileAsset(void) override; /* * Use a piece of an already-open file. @@ -266,21 +264,24 @@ public: * * On success, the object takes ownership of "dataMap" and "fd". */ - status_t openChunk(FileMap* dataMap, base::unique_fd fd); + status_t openChunk(incfs::IncFsFileMap&& dataMap, base::unique_fd fd); /* * Standard Asset interfaces. */ - virtual ssize_t read(void* buf, size_t count); - virtual off64_t seek(off64_t offset, int whence); - virtual void close(void); - virtual const void* getBuffer(bool wordAligned); - virtual off64_t getLength(void) const { return mLength; } - virtual off64_t getRemainingLength(void) const { return mLength-mOffset; } - virtual int openFileDescriptor(off64_t* outStart, off64_t* outLength) const; - virtual bool isAllocated(void) const { return mBuf != NULL; } + ssize_t read(void* buf, size_t count) override; + off64_t seek(off64_t offset, int whence) override; + void close(void) override; + const void* getBuffer(bool aligned) override; + incfs::map_ptr<void> getIncFsBuffer(bool aligned) override; + off64_t getLength(void) const override { return mLength; } + off64_t getRemainingLength(void) const override { return mLength-mOffset; } + int openFileDescriptor(off64_t* outStart, off64_t* outLength) const override; + bool isAllocated(void) const override { return mBuf != NULL; } private: + incfs::map_ptr<void> ensureAlignment(const incfs::IncFsFileMap& map); + off64_t mStart; // absolute file offset of start of chunk off64_t mLength; // length of the chunk off64_t mOffset; // current local offset, 0 == mStart @@ -295,10 +296,8 @@ private: */ enum { kReadVsMapThreshold = 4096 }; - FileMap* mMap; // for memory map - unsigned char* mBuf; // for read - - const void* ensureAlignment(FileMap* map); + unsigned char* mBuf; // for read + std::optional<incfs::IncFsFileMap> mMap; // for memory map }; @@ -323,7 +322,7 @@ public: * * On success, the object takes ownership of "fd". */ - status_t openChunk(FileMap* dataMap, size_t uncompressedLen); + status_t openChunk(incfs::IncFsFileMap&& dataMap, size_t uncompressedLen); /* * Standard Asset interfaces. @@ -331,24 +330,23 @@ public: virtual ssize_t read(void* buf, size_t count); virtual off64_t seek(off64_t offset, int whence); virtual void close(void); - virtual const void* getBuffer(bool wordAligned); + virtual const void* getBuffer(bool aligned); + virtual incfs::map_ptr<void> getIncFsBuffer(bool aligned); virtual off64_t getLength(void) const { return mUncompressedLen; } virtual off64_t getRemainingLength(void) const { return mUncompressedLen-mOffset; } virtual int openFileDescriptor(off64_t* /* outStart */, off64_t* /* outLength */) const { return -1; } virtual bool isAllocated(void) const { return mBuf != NULL; } private: - off64_t mStart; // offset to start of compressed data - off64_t mCompressedLen; // length of the compressed data - off64_t mUncompressedLen; // length of the uncompressed data - off64_t mOffset; // current offset, 0 == start of uncomp data - - FileMap* mMap; // for memory-mapped input - int mFd; // for file input - - class StreamingZipInflater* mZipInflater; // for streaming large compressed assets - - unsigned char* mBuf; // for getBuffer() + off64_t mStart; // offset to start of compressed data + off64_t mCompressedLen; // length of the compressed data + off64_t mUncompressedLen; // length of the uncompressed data + off64_t mOffset; // current offset, 0 == start of uncomp data + int mFd; // for file input + + class StreamingZipInflater* mZipInflater; // for streaming large compressed assets + unsigned char* mBuf; // for getBuffer() + std::optional<incfs::IncFsFileMap> mMap; // for memory-mapped input }; // need: shared mmap version? diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index 30ef25c6a516..4e993b0838a2 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -131,8 +131,8 @@ class AssetManager2 { bool GetOverlayablesToString(const android::StringPiece& package_name, std::string* out) const; - const std::unordered_map<std::string, std::string>* - GetOverlayableMapForPackage(uint32_t package_id) const; + const std::unordered_map<std::string, std::string>* GetOverlayableMapForPackage( + uint32_t package_id) const; // Returns whether the resources.arsc of any loaded apk assets is allocated in RAM (not mmapped). bool ContainsAllocatedTable() const; @@ -145,14 +145,16 @@ class AssetManager2 { return configuration_; } - // Returns all configurations for which there are resources defined. This includes resource - // configurations in all the ApkAssets set for this AssetManager. + // Returns all configurations for which there are resources defined, or an I/O error if reading + // resource data failed. + // + // This includes resource configurations in all the ApkAssets set for this AssetManager. // If `exclude_system` is set to true, resource configurations from system APKs // ('android' package, other libraries) will be excluded from the list. // If `exclude_mipmap` is set to true, resource configurations defined for resource type 'mipmap' // will be excluded from the list. - std::set<ResTable_config> GetResourceConfigurations(bool exclude_system = false, - bool exclude_mipmap = false) const; + base::expected<std::set<ResTable_config>, IOError> GetResourceConfigurations( + bool exclude_system = false, bool exclude_mipmap = false) const; // Returns all the locales for which there are resources defined. This includes resource // locales in all the ApkAssets set for this AssetManager. @@ -194,77 +196,116 @@ class AssetManager2 { std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, ApkAssetsCookie cookie, Asset::AccessMode mode) const; - // Populates the `out_name` parameter with resource name information. - // Utf8 strings are preferred, and only if they are unavailable are - // the Utf16 variants populated. - // Returns false if the resource was not found or the name was missing/corrupt. - bool GetResourceName(uint32_t resid, ResourceName* out_name) const; - - // Populates `out_flags` with the bitmask of configuration axis that this resource varies with. - // See ResTable_config for the list of configuration axis. - // Returns false if the resource was not found. - bool GetResourceFlags(uint32_t resid, uint32_t* out_flags) const; + // Returns the resource name of the specified resource ID. + // + // Utf8 strings are preferred, and only if they are unavailable are the Utf16 variants populated. + // + // Returns a null error if the name is missing/corrupt, or an I/O error if reading resource data + // failed. + base::expected<ResourceName, NullOrIOError> GetResourceName(uint32_t resid) const; // Finds the resource ID assigned to `resource_name`. + // // `resource_name` must be of the form '[package:][type/]entry'. // If no package is specified in `resource_name`, then `fallback_package` is used as the package. // If no type is specified in `resource_name`, then `fallback_type` is used as the type. - // Returns 0x0 if no resource by that name was found. - uint32_t GetResourceId(const std::string& resource_name, const std::string& fallback_type = {}, - const std::string& fallback_package = {}) const; - - // Retrieves the best matching resource with ID `resid`. The resource value is filled into - // `out_value` and the configuration for the selected value is populated in `out_selected_config`. - // `out_flags` holds the same flags as retrieved with GetResourceFlags(). - // If `density_override` is non-zero, the configuration to match against is overridden with that - // density. // - // Returns a valid cookie if the resource was found. If the resource was not found, or if the - // resource was a map/bag type, then kInvalidCookie is returned. If `may_be_bag` is false, - // this function logs if the resource was a map/bag type before returning kInvalidCookie. - ApkAssetsCookie GetResource(uint32_t resid, bool may_be_bag, uint16_t density_override, - Res_value* out_value, ResTable_config* out_selected_config, - uint32_t* out_flags) const; - - // Resolves the resource reference in `in_out_value` if the data type is - // Res_value::TYPE_REFERENCE. - // `cookie` is the ApkAssetsCookie of the reference in `in_out_value`. - // `in_out_value` is the reference to resolve. The result is placed back into this object. - // `in_out_flags` is the type spec flags returned from calls to GetResource() or - // GetResourceFlags(). Configuration flags of the values pointed to by the reference - // are OR'd together with `in_out_flags`. - // `in_out_config` is populated with the configuration for which the resolved value was defined. - // `out_last_reference` is populated with the last reference ID before resolving to an actual - // value. This is only initialized if the passed in `in_out_value` is a reference. - // Returns the cookie of the APK the resolved resource was defined in, or kInvalidCookie if - // it was not found. - ApkAssetsCookie ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value, - ResTable_config* in_out_selected_config, uint32_t* in_out_flags, - uint32_t* out_last_reference) const; + // Returns a null error if no resource by that name was found, or an I/O error if reading resource + // data failed. + base::expected<uint32_t, NullOrIOError> GetResourceId( + const std::string& resource_name, const std::string& fallback_type = {}, + const std::string& fallback_package = {}) const; + + struct SelectedValue { + friend AssetManager2; + friend Theme; + SelectedValue() = default; + SelectedValue(const ResolvedBag* bag, const ResolvedBag::Entry& entry) : + cookie(entry.cookie), data(entry.value.data), type(entry.value.dataType), + flags(bag->type_spec_flags), resid(0U), config({}) {}; + + // The cookie representing the ApkAssets in which the value resides. + ApkAssetsCookie cookie = kInvalidCookie; - // Resets the resource resolution structures in preparation for the next resource retrieval. - void ResetResourceResolution() const; + // The data for this value, as interpreted according to `type`. + Res_value::data_type data; - // Enables or disables resource resolution logging. Clears stored steps when disabled. - void SetResourceResolutionLoggingEnabled(bool enabled); + // Type of the data value. + uint8_t type; - // Returns formatted log of last resource resolution path, or empty if no resource has been - // resolved yet. - std::string GetLastResourceResolution() const; + // The bitmask of configuration axis that this resource varies with. + // See ResTable_config::CONFIG_*. + uint32_t flags; + + // The resource ID from which this value was resolved. + uint32_t resid; - const std::vector<uint32_t> GetBagResIdStack(uint32_t resid); + // The configuration for which the resolved value was defined. + ResTable_config config; + + private: + SelectedValue(uint8_t value_type, Res_value::data_type value_data, ApkAssetsCookie cookie, + uint32_t type_flags, uint32_t resid, const ResTable_config& config) : + cookie(cookie), data(value_data), type(value_type), flags(type_flags), + resid(resid), config(config) {}; + }; + + // Retrieves the best matching resource value with ID `resid`. + // + // If `may_be_bag` is false, this function logs if the resource was a map/bag type and returns a + // null result. If `density_override` is non-zero, the configuration to match against is + // overridden with that density. + // + // Returns a null error if a best match could not be found, or an I/O error if reading resource + // data failed. + base::expected<SelectedValue, NullOrIOError> GetResource(uint32_t resid, bool may_be_bag = false, + uint16_t density_override = 0U) const; + + // Resolves the resource referenced in `value` if the type is Res_value::TYPE_REFERENCE. + // + // If the data type is not Res_value::TYPE_REFERENCE, no work is done. Configuration flags of the + // values pointed to by the reference are OR'd into `value.flags`. + // + // Returns a null error if the resource could not be resolved, or an I/O error if reading + // resource data failed. + base::expected<std::monostate, NullOrIOError> ResolveReference(SelectedValue& value) const; // Retrieves the best matching bag/map resource with ID `resid`. + // // This method will resolve all parent references for this bag and merge keys with the child. // To iterate over the keys, use the following idiom: // - // const AssetManager2::ResolvedBag* bag = asset_manager->GetBag(id); - // if (bag != nullptr) { - // for (auto iter = begin(bag); iter != end(bag); ++iter) { + // base::expected<const ResolvedBag*, NullOrIOError> bag = asset_manager->GetBag(id); + // if (bag.has_value()) { + // for (auto iter = begin(*bag); iter != end(*bag); ++iter) { // ... // } // } - const ResolvedBag* GetBag(uint32_t resid); + // + // Returns a null error if a best match could not be found, or an I/O error if reading resource + // data failed. + base::expected<const ResolvedBag*, NullOrIOError> GetBag(uint32_t resid) const; + + // Retrieves the best matching bag/map resource of the resource referenced in `value`. + // + // If `value.type` is not Res_value::TYPE_REFERENCE, a null result is returned. + // Configuration flags of the bag pointed to by the reference are OR'd into `value.flags`. + // + // Returns a null error if a best match could not be found, or an I/O error if reading resource + // data failed. + base::expected<const ResolvedBag*, NullOrIOError> ResolveBag(SelectedValue& value) const; + + const std::vector<uint32_t> GetBagResIdStack(uint32_t resid) const; + + // Resets the resource resolution structures in preparation for the next resource retrieval. + void ResetResourceResolution() const; + + // Enables or disables resource resolution logging. Clears stored steps when disabled. + void SetResourceResolutionLoggingEnabled(bool enabled); + + // Returns formatted log of last resource resolution path, or empty if no resource has been + // resolved yet. + std::string GetLastResourceResolution() const; // Creates a new Theme from this AssetManager. std::unique_ptr<Theme> NewTheme(); @@ -286,11 +327,15 @@ class AssetManager2 { private: DISALLOW_COPY_AND_ASSIGN(AssetManager2); + struct TypeConfig { + incfs::verified_map_ptr<ResTable_type> type; + ResTable_config config; + }; + // A collection of configurations and their associated ResTable_type that match the current // AssetManager configuration. struct FilteredConfigGroup { - std::vector<ResTable_config> configurations; - std::vector<const ResTable_type*> types; + std::vector<TypeConfig> type_configs; }; // Represents an single package. @@ -331,9 +376,7 @@ class AssetManager2 { }; // Finds the best entry for `resid` from the set of ApkAssets. The entry can be a simple - // Res_value, or a complex map/bag type. If successful, it is available in `out_entry`. - // Returns kInvalidCookie on failure. Otherwise, the return value is the cookie associated with - // the ApkAssets in which the entry was found. + // Res_value, or a complex map/bag type. Returns a null result if a best entry cannot be found. // // `density_override` overrides the density of the current configuration when doing a search. // @@ -347,13 +390,15 @@ class AssetManager2 { // // NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly // bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds. - ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match, - bool ignore_configuration, FindEntryResult* out_entry) const; + base::expected<FindEntryResult, NullOrIOError> FindEntry(uint32_t resid, + uint16_t density_override, + bool stop_at_first_match, + bool ignore_configuration) const; - ApkAssetsCookie FindEntryInternal(const PackageGroup& package_group, uint8_t type_idx, - uint16_t entry_idx, const ResTable_config& desired_config, - bool /*stop_at_first_match*/, - bool ignore_configuration, FindEntryResult* out_entry) const; + base::expected<FindEntryResult, NullOrIOError> FindEntryInternal( + const PackageGroup& package_group, uint8_t type_idx, uint16_t entry_idx, + const ResTable_config& desired_config, bool stop_at_first_match, + bool ignore_configuration) const; // Assigns package IDs to all shared library ApkAssets. // Should be called whenever the ApkAssets are changed. @@ -372,7 +417,8 @@ class AssetManager2 { // AssetManager2::GetBag(resid) wraps this function to track which resource ids have already // been seen while traversing bag parents. - const ResolvedBag* GetBag(uint32_t resid, std::vector<uint32_t>& child_resids); + base::expected<const ResolvedBag*, NullOrIOError> GetBag( + uint32_t resid, std::vector<uint32_t>& child_resids) const; // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must // have a longer lifetime. @@ -394,11 +440,11 @@ class AssetManager2 { // Cached set of bags. These are cached because they can inherit keys from parent bags, // which involves some calculation. - std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_; + mutable std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_; // Cached set of bag resid stacks for each bag. These are cached because they might be requested // a number of times for each view during View inspection. - std::unordered_map<uint32_t, std::vector<uint32_t>> cached_bag_resid_stacks_; + mutable std::unordered_map<uint32_t, std::vector<uint32_t>> cached_bag_resid_stacks_; // Whether or not to save resource resolution steps bool resource_resolution_logging_enabled_ = false; @@ -455,55 +501,53 @@ class Theme { public: ~Theme(); - // Applies the style identified by `resid` to this theme. This can be called - // multiple times with different styles. By default, any theme attributes that - // are already defined before this call are not overridden. If `force` is set - // to true, this behavior is changed and all theme attributes from the style at - // `resid` are applied. - // Returns false if the style failed to apply. - bool ApplyStyle(uint32_t resid, bool force = false); + // Applies the style identified by `resid` to this theme. + // + // This can be called multiple times with different styles. By default, any theme attributes that + // are already defined before this call are not overridden. If `force` is set to true, this + // behavior is changed and all theme attributes from the style at `resid` are applied. + // + // Returns a null error if the style could not be applied, or an I/O error if reading resource + // data failed. + base::expected<std::monostate, NullOrIOError> ApplyStyle(uint32_t resid, bool force = false); - // Sets this Theme to be a copy of `o` if `o` has the same AssetManager as this Theme. - // If `o` does not have the same AssetManager as this theme, only attributes from ApkAssets loaded - // into both AssetManagers will be copied to this theme. - void SetTo(const Theme& o); + // Sets this Theme to be a copy of `other` if `other` has the same AssetManager as this Theme. + // + // If `other` does not have the same AssetManager as this theme, only attributes from ApkAssets + // loaded into both AssetManagers will be copied to this theme. + // + // Returns an I/O error if reading resource data failed. + base::expected<std::monostate, IOError> SetTo(const Theme& other); void Clear(); - void Dump() const; + // Retrieves the value of attribute ID `resid` in the theme. + // + // NOTE: This function does not do reference traversal. If you want to follow references to other + // resources to get the "real" value to use, you need to call ResolveReference() after this + // function. + std::optional<AssetManager2::SelectedValue> GetAttribute(uint32_t resid) const; - inline const AssetManager2* GetAssetManager() const { + // This is like AssetManager2::ResolveReference(), but also takes care of resolving attribute + // references to the theme. + base::expected<std::monostate, NullOrIOError> ResolveAttributeReference( + AssetManager2::SelectedValue& value) const; + + AssetManager2* GetAssetManager() { return asset_manager_; } - inline AssetManager2* GetAssetManager() { + const AssetManager2* GetAssetManager() const { return asset_manager_; } // Returns a bit mask of configuration changes that will impact this // theme (and thus require completely reloading it). - inline uint32_t GetChangingConfigurations() const { + uint32_t GetChangingConfigurations() const { return type_spec_flags_; } - // Retrieve a value in the theme. If the theme defines this value, returns an asset cookie - // indicating which ApkAssets it came from and populates `out_value` with the value. - // `out_flags` is populated with a bitmask of the configuration axis with which the resource - // varies. - // - // If the attribute is not found, returns kInvalidCookie. - // - // NOTE: This function does not do reference traversal. If you want to follow references to other - // resources to get the "real" value to use, you need to call ResolveReference() after this - // function. - ApkAssetsCookie GetAttribute(uint32_t resid, Res_value* out_value, uint32_t* out_flags) const; - - // This is like AssetManager2::ResolveReference(), but also takes - // care of resolving attribute references to the theme. - ApkAssetsCookie ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value, - ResTable_config* in_out_selected_config = nullptr, - uint32_t* in_out_type_spec_flags = nullptr, - uint32_t* out_last_ref = nullptr) const; + void Dump() const; private: DISALLOW_COPY_AND_ASSIGN(Theme); diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h index d71aad29d917..1a69a309d365 100644 --- a/libs/androidfw/include/androidfw/AttributeResolution.h +++ b/libs/androidfw/include/androidfw/AttributeResolution.h @@ -45,20 +45,28 @@ enum { // `out_values` must NOT be nullptr. // `out_indices` may be nullptr. -bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_resid, - uint32_t* src_values, size_t src_values_length, uint32_t* attrs, - size_t attrs_length, uint32_t* out_values, uint32_t* out_indices); +base::expected<std::monostate, IOError> ResolveAttrs(Theme* theme, uint32_t def_style_attr, + uint32_t def_style_resid, uint32_t* src_values, + size_t src_values_length, uint32_t* attrs, + size_t attrs_length, uint32_t* out_values, + uint32_t* out_indices); // `out_values` must NOT be nullptr. // `out_indices` is NOT optional and must NOT be nullptr. -void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, - uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length, - uint32_t* out_values, uint32_t* out_indices); +base::expected<std::monostate, IOError> ApplyStyle(Theme* theme, ResXMLParser* xml_parser, + uint32_t def_style_attr, + uint32_t def_style_resid, + const uint32_t* attrs, size_t attrs_length, + uint32_t* out_values, uint32_t* out_indices); // `out_values` must NOT be nullptr. // `out_indices` may be nullptr. -bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs, - size_t attrs_length, uint32_t* out_values, uint32_t* out_indices); +base::expected<std::monostate, IOError> RetrieveAttributes(AssetManager2* assetmanager, + ResXMLParser* xml_parser, + uint32_t* attrs, + size_t attrs_length, + uint32_t* out_values, + uint32_t* out_indices); } // namespace android diff --git a/libs/androidfw/include/androidfw/Chunk.h b/libs/androidfw/include/androidfw/Chunk.h index a0f23433c676..f1c43b298e53 100644 --- a/libs/androidfw/include/androidfw/Chunk.h +++ b/libs/androidfw/include/androidfw/Chunk.h @@ -36,7 +36,7 @@ namespace android { // of the chunk. class Chunk { public: - explicit Chunk(const ResChunk_header* chunk) : device_chunk_(chunk) {} + explicit Chunk(incfs::verified_map_ptr<ResChunk_header> chunk) : device_chunk_(chunk) {} // Returns the type of the chunk. Caller need not worry about endianness. inline int type() const { return dtohs(device_chunk_->type); } @@ -49,21 +49,18 @@ class Chunk { inline size_t header_size() const { return dtohs(device_chunk_->headerSize); } template <typename T, size_t MinSize = sizeof(T)> - inline const T* header() const { - if (header_size() >= MinSize) { - return reinterpret_cast<const T*>(device_chunk_); - } - return nullptr; + inline incfs::map_ptr<T> header() const { + return (header_size() >= MinSize) ? device_chunk_.convert<T>() : nullptr; } - inline const void* data_ptr() const { - return reinterpret_cast<const uint8_t*>(device_chunk_) + header_size(); + inline incfs::map_ptr<void> data_ptr() const { + return device_chunk_.offset(header_size()); } inline size_t data_size() const { return size() - header_size(); } private: - const ResChunk_header* device_chunk_; + const incfs::verified_map_ptr<ResChunk_header> device_chunk_; }; // Provides a Java style iterator over an array of ResChunk_header's. @@ -84,11 +81,11 @@ class Chunk { // class ChunkIterator { public: - ChunkIterator(const void* data, size_t len) - : next_chunk_(reinterpret_cast<const ResChunk_header*>(data)), + ChunkIterator(incfs::map_ptr<void> data, size_t len) + : next_chunk_(data.convert<ResChunk_header>()), len_(len), last_error_(nullptr) { - CHECK(next_chunk_ != nullptr) << "data can't be nullptr"; + CHECK((bool) next_chunk_) << "data can't be null"; if (len_ != 0) { VerifyNextChunk(); } @@ -113,7 +110,7 @@ class ChunkIterator { // Returns false if there was an error. For legacy purposes. bool VerifyNextChunkNonFatal(); - const ResChunk_header* next_chunk_; + incfs::map_ptr<ResChunk_header> next_chunk_; size_t len_; const char* last_error_; bool last_error_was_fatal_ = true; diff --git a/libs/androidfw/include/androidfw/Errors.h b/libs/androidfw/include/androidfw/Errors.h new file mode 100644 index 000000000000..948162d10480 --- /dev/null +++ b/libs/androidfw/include/androidfw/Errors.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROIDFW_ERRORS_H_ +#define ANDROIDFW_ERRORS_H_ + +#include <optional> +#include <variant> + +#include <android-base/result.h> + +namespace android { + +enum class IOError { + // Used when reading a file residing on an IncFs file-system times out. + PAGES_MISSING = -1, +}; + +// Represents an absent result or an I/O error. +using NullOrIOError = std::variant<std::nullopt_t, IOError>; + +// Checks whether the result holds an unexpected I/O error. +template <typename T> +static inline bool IsIOError(const base::expected<T, NullOrIOError> result) { + return !result.has_value() && std::holds_alternative<IOError>(result.error()); +} + +static inline IOError GetIOError(const NullOrIOError& error) { + return std::get<IOError>(error); +} + +} // namespace android + +#endif //ANDROIDFW_ERRORS_H_ diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h index ab0f47f025d2..fdab03ba2de4 100644 --- a/libs/androidfw/include/androidfw/Idmap.h +++ b/libs/androidfw/include/androidfw/Idmap.h @@ -40,8 +40,8 @@ class IdmapResMap; class OverlayStringPool : public ResStringPool { public: virtual ~OverlayStringPool(); - const char16_t* stringAt(size_t idx, size_t* outLen) const override; - const char* string8At(size_t idx, size_t* outLen) const override; + base::expected<StringPiece16, NullOrIOError> stringAt(size_t idx) const override; + base::expected<StringPiece, NullOrIOError> string8At(size_t idx) const override; size_t size() const override; explicit OverlayStringPool(const LoadedIdmap* loaded_idmap); diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h index 89ff9f52125d..17d97a2a2e73 100644 --- a/libs/androidfw/include/androidfw/LoadedArsc.h +++ b/libs/androidfw/include/androidfw/LoadedArsc.h @@ -23,7 +23,8 @@ #include <unordered_map> #include <unordered_set> -#include "android-base/macros.h" +#include <android-base/macros.h> +#include <android-base/result.h> #include "androidfw/ByteBucketArray.h" #include "androidfw/Chunk.h" @@ -49,7 +50,7 @@ struct TypeSpec { // Pointer to the mmapped data where flags are kept. // Flags denote whether the resource entry is public // and under which configurations it varies. - const ResTable_typeSpec* type_spec; + incfs::verified_map_ptr<ResTable_typeSpec> type_spec; // The number of types that follow this struct. // There is a type for each configuration that entries are defined for. @@ -57,15 +58,17 @@ struct TypeSpec { // Trick to easily access a variable number of Type structs // proceeding this struct, and to ensure their alignment. - const ResTable_type* types[0]; + incfs::verified_map_ptr<ResTable_type> types[0]; - inline uint32_t GetFlagsForEntryIndex(uint16_t entry_index) const { + base::expected<uint32_t, NullOrIOError> GetFlagsForEntryIndex(uint16_t entry_index) const { if (entry_index >= dtohl(type_spec->entryCount)) { - return 0u; + return 0U; } - - const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec + 1); - return flags[entry_index]; + const auto entry_flags_ptr = ((type_spec + 1).convert<uint32_t>() + entry_index); + if (!entry_flags_ptr) { + return base::unexpected(IOError::PAGES_MISSING); + } + return entry_flags_ptr.value(); } }; @@ -161,13 +164,17 @@ class LoadedPackage { // the default policy in AAPT2 is to build UTF-8 string pools, this needs to change. // Returns a partial resource ID, with the package ID left as 0x00. The caller is responsible // for patching the correct package ID to the resource ID. - uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const; + base::expected<uint32_t, NullOrIOError> FindEntryByName(const std::u16string& type_name, + const std::u16string& entry_name) const; - static const ResTable_entry* GetEntry(const ResTable_type* type_chunk, uint16_t entry_index); + static base::expected<incfs::map_ptr<ResTable_entry>, NullOrIOError> GetEntry( + incfs::verified_map_ptr<ResTable_type> type_chunk, uint16_t entry_index); - static uint32_t GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index); + static base::expected<uint32_t, NullOrIOError> GetEntryOffset( + incfs::verified_map_ptr<ResTable_type> type_chunk, uint16_t entry_index); - static const ResTable_entry* GetEntryFromOffset(const ResTable_type* type_chunk, uint32_t offset); + static base::expected<incfs::map_ptr<ResTable_entry>, NullOrIOError> GetEntryFromOffset( + incfs::verified_map_ptr<ResTable_type> type_chunk, uint32_t offset); // Returns the string pool where type names are stored. inline const ResStringPool* GetTypeStringPool() const { @@ -220,7 +227,8 @@ class LoadedPackage { // Populates a set of ResTable_config structs, possibly excluding configurations defined for // the mipmap type. - void CollectConfigurations(bool exclude_mipmap, std::set<ResTable_config>* out_configs) const; + base::expected<std::monostate, IOError> CollectConfigurations( + bool exclude_mipmap, std::set<ResTable_config>* out_configs) const; // Populates a set of strings representing locales. // If `canonicalize` is set to true, each locale is transformed into its canonical format @@ -300,7 +308,8 @@ class LoadedArsc { // If `load_as_shared_library` is set to true, the application package (0x7f) is treated // as a shared library (0x00). When loaded into an AssetManager, the package will be assigned an // ID. - static std::unique_ptr<const LoadedArsc> Load(const StringPiece& data, + static std::unique_ptr<const LoadedArsc> Load(incfs::map_ptr<void> data, + size_t length, const LoadedIdmap* loaded_idmap = nullptr, package_property_t property_flags = 0U); diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 04ba78b6705d..fb5f86473189 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -20,7 +20,10 @@ #ifndef _LIBS_UTILS_RESOURCE_TYPES_H #define _LIBS_UTILS_RESOURCE_TYPES_H +#include <android-base/expected.h> + #include <androidfw/Asset.h> +#include <androidfw/Errors.h> #include <androidfw/LocaleData.h> #include <androidfw/StringPiece.h> #include <utils/Errors.h> @@ -497,7 +500,7 @@ public: virtual ~ResStringPool(); void setToEmpty(); - status_t setTo(const void* data, size_t size, bool copyData=false); + status_t setTo(incfs::map_ptr<void> data, size_t size, bool copyData=false); status_t getError() const; @@ -505,48 +508,49 @@ public: // Return string entry as UTF16; if the pool is UTF8, the string will // be converted before returning. - inline const char16_t* stringAt(const ResStringPool_ref& ref, size_t* outLen) const { - return stringAt(ref.index, outLen); + inline base::expected<StringPiece16, NullOrIOError> stringAt( + const ResStringPool_ref& ref) const { + return stringAt(ref.index); } - virtual const char16_t* stringAt(size_t idx, size_t* outLen) const; + virtual base::expected<StringPiece16, NullOrIOError> stringAt(size_t idx) const; // Note: returns null if the string pool is not UTF8. - virtual const char* string8At(size_t idx, size_t* outLen) const; + virtual base::expected<StringPiece, NullOrIOError> string8At(size_t idx) const; // Return string whether the pool is UTF8 or UTF16. Does not allow you // to distinguish null. - const String8 string8ObjectAt(size_t idx) const; + base::expected<String8, IOError> string8ObjectAt(size_t idx) const; - const ResStringPool_span* styleAt(const ResStringPool_ref& ref) const; - const ResStringPool_span* styleAt(size_t idx) const; + base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> styleAt( + const ResStringPool_ref& ref) const; + base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> styleAt(size_t idx) const; - ssize_t indexOfString(const char16_t* str, size_t strLen) const; + base::expected<size_t, NullOrIOError> indexOfString(const char16_t* str, size_t strLen) const; virtual size_t size() const; size_t styleCount() const; size_t bytes() const; - const void* data() const; - + incfs::map_ptr<void> data() const; bool isSorted() const; bool isUTF8() const; private: - status_t mError; - void* mOwnedData; - const ResStringPool_header* mHeader; - size_t mSize; - mutable Mutex mDecodeLock; - const uint32_t* mEntries; - const uint32_t* mEntryStyles; - const void* mStrings; - char16_t mutable** mCache; - uint32_t mStringPoolSize; // number of uint16_t - const uint32_t* mStyles; - uint32_t mStylePoolSize; // number of uint32_t - - const char* stringDecodeAt(size_t idx, const uint8_t* str, const size_t encLen, - size_t* outLen) const; + status_t mError; + void* mOwnedData; + incfs::verified_map_ptr<ResStringPool_header> mHeader; + size_t mSize; + mutable Mutex mDecodeLock; + incfs::map_ptr<uint32_t> mEntries; + incfs::map_ptr<uint32_t> mEntryStyles; + incfs::map_ptr<void> mStrings; + char16_t mutable** mCache; + uint32_t mStringPoolSize; // number of uint16_t + incfs::map_ptr<uint32_t> mStyles; + uint32_t mStylePoolSize; // number of uint32_t + + base::expected<StringPiece, NullOrIOError> stringDecodeAt( + size_t idx, incfs::map_ptr<uint8_t> str, size_t encLen) const; }; /** @@ -558,8 +562,8 @@ public: StringPoolRef() = default; StringPoolRef(const ResStringPool* pool, uint32_t index); - const char* string8(size_t* outLen) const; - const char16_t* string16(size_t* outLen) const; + base::expected<StringPiece, NullOrIOError> string8() const; + base::expected<StringPiece16, NullOrIOError> string16() const; private: const ResStringPool* mPool = nullptr; @@ -1797,6 +1801,16 @@ private: bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue); +template<typename TChar, typename E> +static const TChar* UnpackOptionalString(base::expected<BasicStringPiece<TChar>, E>&& result, + size_t* outLen) { + if (result.has_value()) { + *outLen = result->size(); + return result->data(); + } + return NULL; +} + /** * Convenience class for accessing data in a ResTable resource. */ diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h index e649940cdde1..bd1c44033b88 100644 --- a/libs/androidfw/include/androidfw/ResourceUtils.h +++ b/libs/androidfw/include/androidfw/ResourceUtils.h @@ -30,13 +30,12 @@ bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, Strin // Convert a type_string_ref, entry_string_ref, and package to AssetManager2::ResourceName. // Useful for getting resource name without re-running AssetManager2::FindEntry searches. -bool ToResourceName(const StringPoolRef& type_string_ref, - const StringPoolRef& entry_string_ref, - const StringPiece& package_name, - AssetManager2::ResourceName* out_name); +base::expected<AssetManager2::ResourceName, NullOrIOError> ToResourceName( + const StringPoolRef& type_string_ref, const StringPoolRef& entry_string_ref, + const StringPiece& package_name); // Formats a ResourceName to "package:type/entry_name". -std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name); +std::string ToFormattedResourceString(const AssetManager2::ResourceName& resource_name); inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) { return (resid & 0x00ffffffu) | (static_cast<uint32_t>(package_id) << 24); diff --git a/libs/androidfw/include/androidfw/StreamingZipInflater.h b/libs/androidfw/include/androidfw/StreamingZipInflater.h index 3ace5d5a83cf..472b794b911c 100644 --- a/libs/androidfw/include/androidfw/StreamingZipInflater.h +++ b/libs/androidfw/include/androidfw/StreamingZipInflater.h @@ -19,6 +19,8 @@ #include <unistd.h> #include <inttypes.h> + +#include <util/map_ptr.h> #include <zlib.h> #include <utils/Compat.h> @@ -34,7 +36,7 @@ public: StreamingZipInflater(int fd, off64_t compDataStart, size_t uncompSize, size_t compSize); // Flavor that gets the compressed data from an in-memory buffer - StreamingZipInflater(class FileMap* dataMap, size_t uncompSize); + StreamingZipInflater(const incfs::IncFsFileMap* dataMap, size_t uncompSize); ~StreamingZipInflater(); @@ -54,7 +56,7 @@ private: // where to find the uncompressed data int mFd; off64_t mInFileStart; // where the compressed data lives in the file - class FileMap* mDataMap; + const incfs::IncFsFileMap* mDataMap; z_stream mInflateState; bool mStreamNeedsInit; diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h index 9a3646b49db8..aceeeccccb61 100644 --- a/libs/androidfw/include/androidfw/Util.h +++ b/libs/androidfw/include/androidfw/Util.h @@ -22,7 +22,8 @@ #include <sstream> #include <vector> -#include "android-base/macros.h" +#include <android-base/macros.h> +#include <util/map_ptr.h> #include "androidfw/StringPiece.h" @@ -126,6 +127,11 @@ std::string Utf16ToUtf8(const StringPiece16& utf16); std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep); +template <typename T> +bool IsFourByteAligned(const incfs::map_ptr<T>& data) { + return ((size_t)data.unsafe_ptr() & 0x3U) == 0; +} + } // namespace util } // namespace android diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h index c221e3b7aeae..10f6d0655bf4 100644 --- a/libs/androidfw/include/androidfw/ZipFileRO.h +++ b/libs/androidfw/include/androidfw/ZipFileRO.h @@ -30,17 +30,20 @@ #ifndef __LIBS_ZIPFILERO_H #define __LIBS_ZIPFILERO_H -#include <utils/Compat.h> -#include <utils/Errors.h> -#include <utils/FileMap.h> -#include <utils/threads.h> - +#include <optional> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> +#include <util/map_ptr.h> + +#include <utils/Compat.h> +#include <utils/Errors.h> +#include <utils/FileMap.h> +#include <utils/threads.h> + struct ZipArchive; typedef ZipArchive* ZipArchiveHandle; @@ -136,14 +139,26 @@ public: uint32_t* pCrc32) const; /* - * Create a new FileMap object that maps a subset of the archive. For + * Create a new FileMap object that maps a subset of the archive. For * an uncompressed entry this effectively provides a pointer to the * actual data, for a compressed entry this provides the input buffer * for inflate(). + * + * Use this function if the archive can never reside on IncFs. */ FileMap* createEntryFileMap(ZipEntryRO entry) const; /* + * Create a new incfs::IncFsFileMap object that maps a subset of the archive. For + * an uncompressed entry this effectively provides a pointer to the + * actual data, for a compressed entry this provides the input buffer + * for inflate(). + * + * Use this function if the archive can potentially reside on IncFs. + */ + std::optional<incfs::IncFsFileMap> createEntryIncFsFileMap(ZipEntryRO entry) const; + + /* * Uncompress the data into a buffer. Depending on the compression * format, this is either an "inflate" operation or a memcpy. * diff --git a/libs/androidfw/include/androidfw/ZipUtils.h b/libs/androidfw/include/androidfw/ZipUtils.h index 4d35e992cc89..dbfec34fda89 100644 --- a/libs/androidfw/include/androidfw/ZipUtils.h +++ b/libs/androidfw/include/androidfw/ZipUtils.h @@ -25,6 +25,8 @@ #include <stdio.h> #include <time.h> +#include "util/map_ptr.h" + namespace android { /* @@ -40,8 +42,8 @@ public: long compressedLen); static bool inflateToBuffer(int fd, void* buf, long uncompressedLen, long compressedLen); - static bool inflateToBuffer(const void *in, void* buf, long uncompressedLen, - long compressedLen); + static bool inflateToBuffer(incfs::map_ptr<void> in, void* buf, + long uncompressedLen, long compressedLen); /* * Someday we might want to make this generic and handle bzip2 ".bz2" |