diff options
Diffstat (limited to 'libs/androidfw/include')
-rw-r--r-- | libs/androidfw/include/androidfw/ApkAssets.h | 158 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/Asset.h | 30 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/AssetManager2.h | 128 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/DisplayEventDispatcher.h | 51 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/Idmap.h | 173 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/LoadedArsc.h | 73 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/ResourceTypes.h | 156 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/Util.h | 7 |
8 files changed, 554 insertions, 222 deletions
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h index 49fc82bff11e..e57490aab2d8 100644 --- a/libs/androidfw/include/androidfw/ApkAssets.h +++ b/libs/androidfw/include/androidfw/ApkAssets.h @@ -24,6 +24,7 @@ #include "android-base/unique_fd.h" #include "androidfw/Asset.h" +#include "androidfw/Idmap.h" #include "androidfw/LoadedArsc.h" #include "androidfw/misc.h" @@ -34,79 +35,162 @@ namespace android { class LoadedIdmap; +// Interface for retrieving assets provided by an ApkAssets. +class AssetsProvider { + public: + virtual ~AssetsProvider() = default; + + // Opens a file for reading. + std::unique_ptr<Asset> Open(const std::string& path, + Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM, + bool* file_exists = nullptr) const { + return OpenInternal(path, mode, file_exists); + } + + // Iterate over all files and directories provided by the zip. The order of iteration is stable. + virtual bool ForEachFile(const std::string& /* path */, + const std::function<void(const StringPiece&, FileType)>& /* f */) const { + return true; + } + + protected: + AssetsProvider() = default; + + virtual std::unique_ptr<Asset> OpenInternal(const std::string& path, + Asset::AccessMode mode, + bool* file_exists) const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(AssetsProvider); +}; + +class ZipAssetsProvider; + // Holds an APK. class ApkAssets { public: + // This means the data extends to the end of the file. + static constexpr off64_t kUnknownLength = -1; + // Creates an ApkAssets. // If `system` is true, the package is marked as a system package, and allows some functions to // filter out this package when computing what configurations/resources are available. - static std::unique_ptr<const ApkAssets> Load(const std::string& path, bool system = false); + static std::unique_ptr<const ApkAssets> Load( + const std::string& path, package_property_t flags = 0U, + std::unique_ptr<const AssetsProvider> override_asset = nullptr); - // Creates an ApkAssets, but forces any package with ID 0x7f to be loaded as a shared library. - // If `system` is true, the package is marked as a system package, and allows some functions to - // filter out this package when computing what configurations/resources are available. - static std::unique_ptr<const ApkAssets> LoadAsSharedLibrary(const std::string& path, - bool system = false); + // Creates an ApkAssets from the given file descriptor, and takes ownership of the file + // descriptor. The `friendly_name` is some name that will be used to identify the source of + // this ApkAssets in log messages and other debug scenarios. + // If `length` equals kUnknownLength, offset must equal 0; otherwise, the apk data will be read + // using the `offset` into the file descriptor and will be `length` bytes long. + static std::unique_ptr<const ApkAssets> LoadFromFd( + base::unique_fd fd, const std::string& friendly_name, package_property_t flags = 0U, + std::unique_ptr<const AssetsProvider> override_asset = nullptr, off64_t offset = 0, + off64_t length = kUnknownLength); + + // Creates an ApkAssets from the given path which points to a resources.arsc. + static std::unique_ptr<const ApkAssets> LoadTable( + const std::string& path, package_property_t flags = 0U, + std::unique_ptr<const AssetsProvider> override_asset = nullptr); + + // Creates an ApkAssets from the given file descriptor which points to an resources.arsc, and + // takes ownership of the file descriptor. + // If `length` equals kUnknownLength, offset must equal 0; otherwise, the .arsc data will be read + // using the `offset` into the file descriptor and will be `length` bytes long. + static std::unique_ptr<const ApkAssets> LoadTableFromFd( + base::unique_fd fd, const std::string& friendly_name, package_property_t flags = 0U, + std::unique_ptr<const AssetsProvider> override_asset = nullptr, off64_t offset = 0, + off64_t length = kUnknownLength); // Creates an ApkAssets from an IDMAP, which contains the original APK path, and the overlay // data. - // If `system` is true, the package is marked as a system package, and allows some functions to - // filter out this package when computing what configurations/resources are available. static std::unique_ptr<const ApkAssets> LoadOverlay(const std::string& idmap_path, - bool system = false); - - // Creates an ApkAssets from the given file descriptor, and takes ownership of the file - // descriptor. The `friendly_name` is some name that will be used to identify the source of - // this ApkAssets in log messages and other debug scenarios. - // If `system` is true, the package is marked as a system package, and allows some functions to - // filter out this package when computing what configurations/resources are available. - // If `force_shared_lib` is true, any package with ID 0x7f is loaded as a shared library. - static std::unique_ptr<const ApkAssets> LoadFromFd(base::unique_fd fd, - const std::string& friendly_name, bool system, - bool force_shared_lib); + package_property_t flags = 0U); - std::unique_ptr<Asset> Open(const std::string& path, - Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const; + // Creates an ApkAssets from the directory path. File-based resources are read within the + // directory as if the directory is an APK. + static std::unique_ptr<const ApkAssets> LoadFromDir( + const std::string& path, package_property_t flags = 0U, + std::unique_ptr<const AssetsProvider> override_asset = nullptr); - bool ForEachFile(const std::string& path, - const std::function<void(const StringPiece&, FileType)>& f) const; + // Creates a totally empty ApkAssets with no resources table and no file entries. + static std::unique_ptr<const ApkAssets> LoadEmpty( + package_property_t flags = 0U, + std::unique_ptr<const AssetsProvider> override_asset = nullptr); - inline const std::string& GetPath() const { + const std::string& GetPath() const { return path_; } + const AssetsProvider* GetAssetsProvider() const { + return assets_provider_.get(); + } + // This is never nullptr. - inline const LoadedArsc* GetLoadedArsc() const { + const LoadedArsc* GetLoadedArsc() const { return loaded_arsc_.get(); } - inline bool IsOverlay() const { - return idmap_asset_.get() != nullptr; + const LoadedIdmap* GetLoadedIdmap() const { + return loaded_idmap_.get(); + } + + bool IsLoader() const { + return (property_flags_ & PROPERTY_LOADER) != 0; + } + + bool IsOverlay() const { + return loaded_idmap_ != nullptr; + } + + // Returns whether the resources.arsc is allocated in RAM (not mmapped). + bool IsTableAllocated() const { + return resources_asset_ && resources_asset_->isAllocated(); } bool IsUpToDate() const; + // Creates an Asset from a file on disk. + static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path); + + // Creates an Asset from a file descriptor. + // + // The asset takes ownership of the file descriptor. If `length` equals kUnknownLength, offset + // must equal 0; otherwise, the asset data will be read using the `offset` into the file + // descriptor and will be `length` bytes long. + static std::unique_ptr<Asset> CreateAssetFromFd(base::unique_fd fd, + const char* path, + off64_t offset = 0, + off64_t length = kUnknownLength); private: DISALLOW_COPY_AND_ASSIGN(ApkAssets); - static std::unique_ptr<const ApkAssets> LoadImpl(base::unique_fd fd, const std::string& path, - std::unique_ptr<Asset> idmap_asset, - std::unique_ptr<const LoadedIdmap> loaded_idmap, - bool system, bool load_as_shared_library); - - // Creates an Asset from any file on the file system. - static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path); + static std::unique_ptr<const ApkAssets> LoadImpl( + std::unique_ptr<const AssetsProvider> assets, const std::string& path, + package_property_t property_flags, + std::unique_ptr<const AssetsProvider> override_assets = nullptr, + std::unique_ptr<Asset> idmap_asset = nullptr, + std::unique_ptr<const LoadedIdmap> idmap = nullptr); - ApkAssets(ZipArchiveHandle unmanaged_handle, const std::string& path, time_t last_mod_time); + static std::unique_ptr<const ApkAssets> LoadTableImpl( + std::unique_ptr<Asset> resources_asset, const std::string& path, + package_property_t property_flags, + std::unique_ptr<const AssetsProvider> override_assets = nullptr); - using ZipArchivePtr = std::unique_ptr<ZipArchive, void(*)(ZipArchiveHandle)>; + ApkAssets(std::unique_ptr<const AssetsProvider> assets_provider, + std::string path, + time_t last_mod_time, + package_property_t property_flags); - ZipArchivePtr zip_handle_; + std::unique_ptr<const AssetsProvider> assets_provider_; const std::string path_; time_t last_mod_time_; + package_property_t property_flags_ = 0U; std::unique_ptr<Asset> resources_asset_; std::unique_ptr<Asset> idmap_asset_; std::unique_ptr<const LoadedArsc> loaded_arsc_; + std::unique_ptr<const LoadedIdmap> loaded_idmap_; }; } // namespace android diff --git a/libs/androidfw/include/androidfw/Asset.h b/libs/androidfw/include/androidfw/Asset.h index 9d12a35395c9..298509eb37a1 100644 --- a/libs/androidfw/include/androidfw/Asset.h +++ b/libs/androidfw/include/androidfw/Asset.h @@ -26,6 +26,7 @@ #include <memory> +#include <android-base/unique_fd.h> #include <utils/Compat.h> #include <utils/Errors.h> #include <utils/String8.h> @@ -121,6 +122,11 @@ public: */ const char* getAssetSource(void) const { return mAssetSource.string(); } + /* + * Create the asset from a file descriptor. + */ + static Asset* createFromFd(const int fd, const char* fileName, AccessMode mode); + protected: /* * Adds this Asset to the global Asset list for debugging and @@ -153,6 +159,7 @@ private: /* AssetManager needs access to our "create" functions */ friend class AssetManager; friend class ApkAssets; + friend class ZipAssetsProvider; /* * Create the asset from a named file on disk. @@ -197,8 +204,14 @@ private: */ 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". + */ static std::unique_ptr<Asset> createFromUncompressedMap(std::unique_ptr<FileMap> dataMap, - AccessMode mode); + base::unique_fd fd, AccessMode mode); /* * Create the asset from a memory-mapped file segment with compressed @@ -251,9 +264,9 @@ public: /* * Use a memory-mapped region. * - * On success, the object takes ownership of "dataMap". + * On success, the object takes ownership of "dataMap" and "fd". */ - status_t openChunk(FileMap* dataMap); + status_t openChunk(FileMap* dataMap, base::unique_fd fd); /* * Standard Asset interfaces. @@ -268,11 +281,12 @@ public: virtual bool isAllocated(void) const { return mBuf != NULL; } private: - 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 - FILE* mFp; // for read/seek - char* mFileName; // for opening + 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 + FILE* mFp; // for read/seek + char* mFileName; // for opening + base::unique_fd mFd; // for opening file descriptors /* * To support getBuffer() we either need to read the entire thing into diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index 1e2b36cb1703..30ef25c6a516 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -122,11 +122,21 @@ class AssetManager2 { // Returns the DynamicRefTable for the ApkAssets represented by the cookie. // This may be nullptr if the APK represented by `cookie` has no resource table. - const DynamicRefTable* GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const; + std::shared_ptr<const DynamicRefTable> GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const; + + // Retrieve the assigned package id of the package if loaded into this AssetManager + uint8_t GetAssignedPackageId(const LoadedPackage* package) const; + + // Returns a string representation of the overlayable API of a package. + 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; + // Returns whether the resources.arsc of any loaded apk assets is allocated in RAM (not mmapped). + bool ContainsAllocatedTable() const; + // Sets/resets the configuration for this AssetManager. This will cause all // caches that are related to the configuration change to be invalidated. void SetConfiguration(const ResTable_config& configuration); @@ -232,12 +242,14 @@ class AssetManager2 { ResTable_config* in_out_selected_config, uint32_t* in_out_flags, uint32_t* out_last_reference) const; - // Enables or disables resource resolution logging. Clears stored steps when - // disabled. + // 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. + // Returns formatted log of last resource resolution path, or empty if no resource has been + // resolved yet. std::string GetLastResourceResolution() const; const std::vector<uint32_t> GetBagResIdStack(uint32_t resid); @@ -257,10 +269,13 @@ class AssetManager2 { // Creates a new Theme from this AssetManager. std::unique_ptr<Theme> NewTheme(); - void ForEachPackage(const std::function<bool(const std::string&, uint8_t)> func) const { + void ForEachPackage(const std::function<bool(const std::string&, uint8_t)> func, + package_property_t excluded_property_flags = 0U) const { for (const PackageGroup& package_group : package_groups_) { - if (!func(package_group.packages_.front().loaded_package_->GetPackageName(), - package_group.dynamic_ref_table.mAssignedPackageId)) { + const auto loaded_package = package_group.packages_.front().loaded_package_; + if ((loaded_package->GetPropertyFlags() & excluded_property_flags) == 0U + && !func(loaded_package->GetPackageName(), + package_group.dynamic_ref_table->mAssignedPackageId)) { return; } } @@ -271,6 +286,50 @@ class AssetManager2 { private: DISALLOW_COPY_AND_ASSIGN(AssetManager2); + // 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; + }; + + // Represents an single package. + struct ConfiguredPackage { + // A pointer to the immutable, loaded package info. + const LoadedPackage* loaded_package_; + + // A mutable AssetManager-specific list of configurations that match the AssetManager's + // current configuration. This is used as an optimization to avoid checking every single + // candidate configuration when looking up resources. + ByteBucketArray<FilteredConfigGroup> filtered_configs_; + }; + + // Represents a Runtime Resource Overlay that overlays resources in the logical package. + struct ConfiguredOverlay { + // The set of package groups that overlay this package group. + IdmapResMap overlay_res_maps_; + + // The cookie of the overlay assets. + ApkAssetsCookie cookie; + }; + + // Represents a logical package, which can be made up of many individual packages. Each package + // in a PackageGroup shares the same package name and package ID. + struct PackageGroup { + // The set of packages that make-up this group. + std::vector<ConfiguredPackage> packages_; + + // The cookies associated with each package in the group. They share the same order as + // packages_. + std::vector<ApkAssetsCookie> cookies_; + + // Runtime Resource Overlays that overlay resources in this package group. + std::vector<ConfiguredOverlay> overlays_; + + // A library reference table that contains build-package ID to runtime-package ID mappings. + std::shared_ptr<DynamicRefTable> dynamic_ref_table = std::make_shared<DynamicRefTable>(); + }; + // 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 @@ -291,6 +350,11 @@ class AssetManager2 { ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match, bool ignore_configuration, FindEntryResult* out_entry) 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; + // Assigns package IDs to all shared library ApkAssets. // Should be called whenever the ApkAssets are changed. void BuildDynamicRefTable(); @@ -303,49 +367,17 @@ class AssetManager2 { // This should always be called when mutating the AssetManager's configuration or ApkAssets set. void RebuildFilterList(bool filter_incompatible_configs = true); + // Retrieves the APK paths of overlays that overlay non-system packages. + std::set<std::string> GetNonSystemOverlayPaths() const; + // 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); - // Retrieve the assigned package id of the package if loaded into this AssetManager - uint8_t GetAssignedPackageId(const LoadedPackage* package); - // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must // have a longer lifetime. std::vector<const ApkAssets*> apk_assets_; - // 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; - }; - - // Represents an single package. - struct ConfiguredPackage { - // A pointer to the immutable, loaded package info. - const LoadedPackage* loaded_package_; - - // A mutable AssetManager-specific list of configurations that match the AssetManager's - // current configuration. This is used as an optimization to avoid checking every single - // candidate configuration when looking up resources. - ByteBucketArray<FilteredConfigGroup> filtered_configs_; - }; - - // Represents a logical package, which can be made up of many individual packages. Each package - // in a PackageGroup shares the same package name and package ID. - struct PackageGroup { - // The set of packages that make-up this group. - std::vector<ConfiguredPackage> packages_; - - // The cookies associated with each package in the group. They share the same order as - // packages_. - std::vector<ApkAssetsCookie> cookies_; - - // A library reference table that contains build-package ID to runtime-package ID mappings. - DynamicRefTable dynamic_ref_table; - }; - // DynamicRefTables for shared library package resolution. // These are ordered according to apk_assets_. The mappings may change depending on what is // in apk_assets_, therefore they must be stored in the AssetManager and not in the @@ -378,7 +410,13 @@ class AssetManager2 { enum class Type { INITIAL, BETTER_MATCH, - OVERLAID + BETTER_MATCH_LOADER, + OVERLAID, + OVERLAID_LOADER, + SKIPPED, + SKIPPED_LOADER, + NO_ENTRY, + NO_ENTRY_LOADER, }; // Marks what kind of override this step was. @@ -408,7 +446,7 @@ class AssetManager2 { }; // Record of the last resolved resource's resolution path. - mutable Resolution last_resolution; + mutable Resolution last_resolution_; }; class Theme { diff --git a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h deleted file mode 100644 index 8bc25202b3ab..000000000000 --- a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#include <gui/DisplayEventReceiver.h> -#include <utils/Log.h> -#include <utils/Looper.h> - -namespace android { - -class DisplayEventDispatcher : public LooperCallback { -public: - explicit DisplayEventDispatcher(const sp<Looper>& looper, - ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp, - ISurfaceComposer::ConfigChanged configChanged = ISurfaceComposer::eConfigChangedSuppress); - - status_t initialize(); - void dispose(); - status_t scheduleVsync(); - -protected: - virtual ~DisplayEventDispatcher() = default; - -private: - sp<Looper> mLooper; - DisplayEventReceiver mReceiver; - bool mWaitingForVsync; - - virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0; - virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, - bool connected) = 0; - virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, - int32_t configId) = 0; - - virtual int handleEvent(int receiveFd, int events, void* data); - bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, - uint32_t* outCount); -}; -} diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h index fd02e6f63b74..ecc1ce65d124 100644 --- a/libs/androidfw/include/androidfw/Idmap.h +++ b/libs/androidfw/include/androidfw/Idmap.h @@ -20,55 +20,190 @@ #include <memory> #include <string> #include <unordered_map> +#include <variant> #include "android-base/macros.h" - #include "androidfw/StringPiece.h" +#include "androidfw/ResourceTypes.h" +#include "utils/ByteOrder.h" namespace android { -struct Idmap_header; -struct IdmapEntry_header; +class LoadedIdmap; +class IdmapResMap; + +// A string pool for overlay apk assets. The string pool holds the strings of the overlay resources +// table and additionally allows for loading strings from the idmap string pool. The idmap string +// pool strings are offset after the end of the overlay resource table string pool entries so +// queries for strings defined inline in the idmap do not conflict with queries for overlay +// resource table strings. +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; + size_t size() const override; + + explicit OverlayStringPool(const LoadedIdmap* loaded_idmap); + private: + const Idmap_data_header* data_header_; + const ResStringPool* idmap_string_pool_; +}; + +// A dynamic reference table for loaded overlay packages that rewrites the resource id of overlay +// resources to the resource id of corresponding target resources. +class OverlayDynamicRefTable : public DynamicRefTable { + public: + ~OverlayDynamicRefTable() override = default; + status_t lookupResourceId(uint32_t* resId) const override; + + private: + explicit OverlayDynamicRefTable(const Idmap_data_header* data_header, + const Idmap_overlay_entry* entries, + uint8_t target_assigned_package_id); + + // Rewrites a compile-time overlay resource id to the runtime resource id of corresponding target + // resource. + virtual status_t lookupResourceIdNoRewrite(uint32_t* resId) const; + + const Idmap_data_header* data_header_; + const Idmap_overlay_entry* entries_; + const int8_t target_assigned_package_id_; + + friend LoadedIdmap; + friend IdmapResMap; +}; + +// A mapping of target resource ids to a values or resource ids that should overlay the target. +class IdmapResMap { + public: + // Represents the result of a idmap lookup. The result can be one of three possibillities: + // 1) The result is a resource id which represents the overlay resource that should act as an + // alias of the target resource. + // 2) The result is a table entry which overlays the type and value of the target resource. + // 3) The result is neither and the target resource is not overlaid. + class Result { + public: + Result() : data_(nullptr) {}; + explicit Result(uint32_t value) : data_(value) {}; + explicit Result(ResTable_entry_handle&& value) : data_(value) { }; + + // Returns `true` if the resource is overlaid. + inline explicit operator bool() const { + return !std::get_if<nullptr_t>(&data_); + } + + inline bool IsResourceId() const { + return std::get_if<uint32_t>(&data_); + } + + inline uint32_t GetResourceId() const { + return *std::get_if<uint32_t>(&data_); + } + + inline bool IsTableEntry() const { + return std::get_if<ResTable_entry_handle>(&data_); + } + + inline const ResTable_entry_handle& GetTableEntry() const { + return *std::get_if<ResTable_entry_handle>(&data_); + } + + private: + std::variant<uint32_t, nullptr_t, ResTable_entry_handle> data_; + }; + + // Looks up the value that overlays the target resource id. + Result Lookup(uint32_t target_res_id) const; + + inline const OverlayDynamicRefTable* GetOverlayDynamicRefTable() const { + return overlay_ref_table_; + } + + private: + explicit IdmapResMap(const Idmap_data_header* data_header, + const Idmap_target_entry* entries, + uint8_t target_assigned_package_id, + const OverlayDynamicRefTable* overlay_ref_table); + + const Idmap_data_header* data_header_; + const Idmap_target_entry* entries_; + const uint8_t target_assigned_package_id_; + const OverlayDynamicRefTable* overlay_ref_table_; + + friend LoadedIdmap; +}; // Represents a loaded/parsed IDMAP for a Runtime Resource Overlay (RRO). -// An RRO and its target APK have different resource IDs assigned to their resources. Overlaying -// a resource is done by resource name. An IDMAP is a generated mapping between the resource IDs -// of the RRO and the target APK for each resource with the same name. +// An RRO and its target APK have different resource IDs assigned to their resources. +// An IDMAP is a generated mapping between the resource IDs of the RRO and the target APK. // A LoadedIdmap can be set alongside the overlay's LoadedArsc to allow the overlay ApkAssets to // masquerade as the target ApkAssets resources. class LoadedIdmap { public: // Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed. - static std::unique_ptr<const LoadedIdmap> Load(const StringPiece& idmap_data); - - // Performs a lookup of the expected entry ID for the given IDMAP entry header. - // Returns true if the mapping exists and fills `output_entry_id` with the result. - static bool Lookup(const IdmapEntry_header* header, uint16_t input_entry_id, - uint16_t* output_entry_id); + static std::unique_ptr<const LoadedIdmap> Load(const StringPiece& idmap_path, + const StringPiece& idmap_data); - // Returns the package ID for which this overlay should apply. - uint8_t TargetPackageId() const; + // Returns the path to the IDMAP. + inline const std::string& IdmapPath() const { + return idmap_path_; + } // Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated. inline const std::string& OverlayApkPath() const { return overlay_apk_path_; } - // Returns the mapping of target entry ID to overlay entry ID for the given target type. - const IdmapEntry_header* GetEntryMapForType(uint8_t type_id) const; + // Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated. + inline const std::string& TargetApkPath() const { + return target_apk_path_; + } + + // Returns a mapping from target resource ids to overlay values. + inline const IdmapResMap GetTargetResourcesMap( + uint8_t target_assigned_package_id, const OverlayDynamicRefTable* overlay_ref_table) const { + return IdmapResMap(data_header_, target_entries_, target_assigned_package_id, + overlay_ref_table); + } + + // Returns a dynamic reference table for a loaded overlay package. + inline const OverlayDynamicRefTable GetOverlayDynamicRefTable( + uint8_t target_assigned_package_id) const { + return OverlayDynamicRefTable(data_header_, overlay_entries_, target_assigned_package_id); + } + + // Returns whether the idmap file on disk has not been modified since the construction of this + // LoadedIdmap. + bool IsUpToDate() const; protected: // Exposed as protected so that tests can subclass and mock this class out. LoadedIdmap() = default; - const Idmap_header* header_ = nullptr; + const Idmap_header* header_; + const Idmap_data_header* data_header_; + const Idmap_target_entry* target_entries_; + const Idmap_overlay_entry* overlay_entries_; + const std::unique_ptr<ResStringPool> string_pool_; + + const std::string idmap_path_; std::string overlay_apk_path_; - std::unordered_map<uint8_t, const IdmapEntry_header*> type_map_; + std::string target_apk_path_; + const time_t idmap_last_mod_time_; private: DISALLOW_COPY_AND_ASSIGN(LoadedIdmap); - explicit LoadedIdmap(const Idmap_header* header); + explicit LoadedIdmap(std::string&& idmap_path, + time_t last_mod_time, + const Idmap_header* header, + const Idmap_data_header* data_header, + const Idmap_target_entry* target_entries, + const Idmap_overlay_entry* overlay_entries, + ResStringPool* string_pool); + + friend OverlayStringPool; }; } // namespace android diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h index 950f5413f550..89ff9f52125d 100644 --- a/libs/androidfw/include/androidfw/LoadedArsc.h +++ b/libs/androidfw/include/androidfw/LoadedArsc.h @@ -51,10 +51,6 @@ struct TypeSpec { // and under which configurations it varies. const ResTable_typeSpec* type_spec; - // Pointer to the mmapped data where the IDMAP mappings for this type - // exist. May be nullptr if no IDMAP exists. - const IdmapEntry_header* idmap_entries; - // The number of types that follow this struct. // There is a type for each configuration that entries are defined for. size_t type_count; @@ -73,6 +69,26 @@ struct TypeSpec { } }; +// Flags that change the behavior of loaded packages. +// Keep in sync with f/b/android/content/res/ApkAssets.java +using package_property_t = uint32_t; +enum : package_property_t { + // The package contains framework resource values specified by the system. + // This allows some functions to filter out this package when computing + // what configurations/resources are available. + PROPERTY_SYSTEM = 1U << 0U, + + // The package is a shared library or has a package id of 7f and is loaded as a shared library by + // force. + PROPERTY_DYNAMIC = 1U << 1U, + + // The package has been loaded dynamically using a ResourcesProvider. + PROPERTY_LOADER = 1U << 2U, + + // The package is a RRO. + PROPERTY_OVERLAY = 1U << 3U, +}; + // TypeSpecPtr points to a block of memory that holds a TypeSpec struct, followed by an array of // ResTable_type pointers. // TypeSpecPtr is a managed pointer that knows how to delete itself. @@ -136,8 +152,7 @@ class LoadedPackage { } static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk, - const LoadedIdmap* loaded_idmap, bool system, - bool load_as_shared_library); + package_property_t property_flags); ~LoadedPackage(); @@ -174,17 +189,26 @@ class LoadedPackage { // Returns true if this package is dynamic (shared library) and needs to have an ID assigned. inline bool IsDynamic() const { - return dynamic_; + return (property_flags_ & PROPERTY_DYNAMIC) != 0; + } + + // Returns true if this package is a Runtime Resource Overlay. + inline bool IsOverlay() const { + return (property_flags_ & PROPERTY_OVERLAY) != 0; } // Returns true if this package originates from a system provided resource. inline bool IsSystem() const { - return system_; + return (property_flags_ & PROPERTY_SYSTEM) != 0; } - // Returns true if this package is from an overlay ApkAssets. - inline bool IsOverlay() const { - return overlay_; + // Returns true if this package is a custom loader and should behave like an overlay. + inline bool IsCustomLoader() const { + return (property_flags_ & PROPERTY_LOADER) != 0; + } + + inline package_property_t GetPropertyFlags() const { + return property_flags_; } // Returns the map of package name to package ID used in this LoadedPackage. At runtime, a @@ -216,9 +240,6 @@ class LoadedPackage { const TypeSpecPtr& ptr = type_specs_[i]; if (ptr != nullptr) { uint8_t type_id = ptr->type_spec->id; - if (ptr->idmap_entries != nullptr) { - type_id = ptr->idmap_entries->target_type_id; - } f(ptr.get(), type_id - 1); } } @@ -255,17 +276,17 @@ class LoadedPackage { ResStringPool type_string_pool_; ResStringPool key_string_pool_; std::string package_name_; + bool defines_overlayable_ = false; int package_id_ = -1; int type_id_offset_ = 0; - bool dynamic_ = false; - bool system_ = false; - bool overlay_ = false; - bool defines_overlayable_ = false; + package_property_t property_flags_ = 0U; ByteBucketArray<TypeSpecPtr> type_specs_; ByteBucketArray<uint32_t> resource_ids_; std::vector<DynamicPackageEntry> dynamic_package_map_; std::vector<const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_; + + // A map of overlayable name to actor std::unordered_map<std::string, std::string> overlayable_map_; }; @@ -281,8 +302,7 @@ class LoadedArsc { // ID. static std::unique_ptr<const LoadedArsc> Load(const StringPiece& data, const LoadedIdmap* loaded_idmap = nullptr, - bool system = false, - bool load_as_shared_library = false); + package_property_t property_flags = 0U); // Create an empty LoadedArsc. This is used when an APK has no resources.arsc. static std::unique_ptr<const LoadedArsc> CreateEmpty(); @@ -290,7 +310,7 @@ class LoadedArsc { // Returns the string pool where all string resource values // (Res_value::dataType == Res_value::TYPE_STRING) are indexed. inline const ResStringPool* GetStringPool() const { - return &global_string_pool_; + return global_string_pool_.get(); } // Gets a pointer to the package with the specified package ID, or nullptr if no such package @@ -302,20 +322,15 @@ class LoadedArsc { return packages_; } - // Returns true if this is a system provided resource. - inline bool IsSystem() const { - return system_; - } - private: DISALLOW_COPY_AND_ASSIGN(LoadedArsc); LoadedArsc() = default; - bool LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap, bool load_as_shared_library); + bool LoadTable( + const Chunk& chunk, const LoadedIdmap* loaded_idmap, package_property_t property_flags); - ResStringPool global_string_pool_; + std::unique_ptr<ResStringPool> global_string_pool_ = util::make_unique<ResStringPool>(); std::vector<std::unique_ptr<const LoadedPackage>> packages_; - bool system_ = false; }; } // namespace android diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index fc635aaeb0d8..e351a46d633a 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -22,6 +22,7 @@ #include <androidfw/Asset.h> #include <androidfw/LocaleData.h> +#include <androidfw/StringPiece.h> #include <utils/Errors.h> #include <utils/String16.h> #include <utils/Vector.h> @@ -34,12 +35,13 @@ #include <android/configuration.h> +#include <array> #include <memory> namespace android { constexpr const static uint32_t kIdmapMagic = 0x504D4449u; -constexpr const static uint32_t kIdmapCurrentVersion = 0x00000001u; +constexpr const static uint32_t kIdmapCurrentVersion = 0x00000004u; /** * In C++11, char16_t is defined as *at least* 16 bits. We do a lot of @@ -492,7 +494,7 @@ class ResStringPool public: ResStringPool(); ResStringPool(const void* data, size_t size, bool copyData=false); - ~ResStringPool(); + virtual ~ResStringPool(); void setToEmpty(); status_t setTo(const void* data, size_t size, bool copyData=false); @@ -506,10 +508,10 @@ public: inline const char16_t* stringAt(const ResStringPool_ref& ref, size_t* outLen) const { return stringAt(ref.index, outLen); } - const char16_t* stringAt(size_t idx, size_t* outLen) const; + virtual const char16_t* stringAt(size_t idx, size_t* outLen) const; // Note: returns null if the string pool is not UTF8. - const char* string8At(size_t idx, size_t* outLen) const; + virtual const char* string8At(size_t idx, size_t* outLen) const; // Return string whether the pool is UTF8 or UTF16. Does not allow you // to distinguish null. @@ -520,9 +522,11 @@ public: ssize_t indexOfString(const char16_t* str, size_t strLen) const; - size_t size() const; + virtual size_t size() const; size_t styleCount() const; size_t bytes() const; + const void* data() const; + bool isSorted() const; bool isUTF8() const; @@ -810,7 +814,7 @@ public: * The tree stores a clone of the specified DynamicRefTable, so any changes to the original * DynamicRefTable will not affect this tree after instantiation. **/ - explicit ResXMLTree(const DynamicRefTable* dynamicRefTable); + explicit ResXMLTree(std::shared_ptr<const DynamicRefTable> dynamicRefTable); ResXMLTree(); ~ResXMLTree(); @@ -825,7 +829,7 @@ private: status_t validateNode(const ResXMLTree_node* node) const; - std::unique_ptr<const DynamicRefTable> mDynamicRefTable; + std::shared_ptr<const DynamicRefTable> mDynamicRefTable; status_t mError; void* mOwnedData; @@ -1582,6 +1586,50 @@ struct ResTable_map Res_value value; }; + +// A ResTable_entry variant that either holds an unmanaged pointer to a constant ResTable_entry or +// holds a ResTable_entry which is tied to the lifetime of the handle. +class ResTable_entry_handle { + public: + ResTable_entry_handle() = default; + + ResTable_entry_handle(const ResTable_entry_handle& handle) { + entry_ = handle.entry_; + } + + ResTable_entry_handle(ResTable_entry_handle&& handle) noexcept { + entry_ = handle.entry_; + } + + inline static ResTable_entry_handle managed(ResTable_entry* entry, void (*deleter)(void *)) { + return ResTable_entry_handle(std::shared_ptr<const ResTable_entry>(entry, deleter)); + } + + inline static ResTable_entry_handle unmanaged(const ResTable_entry* entry) { + return ResTable_entry_handle(std::shared_ptr<const ResTable_entry>(entry, [](auto /*p */){})); + } + + inline ResTable_entry_handle& operator=(const ResTable_entry_handle& handle) noexcept { + entry_ = handle.entry_; + return *this; + } + + inline ResTable_entry_handle& operator=(ResTable_entry_handle&& handle) noexcept { + entry_ = handle.entry_; + return *this; + } + + inline const ResTable_entry* operator*() & { + return entry_.get(); + } + + private: + explicit ResTable_entry_handle(std::shared_ptr<const ResTable_entry> entry) + : entry_(std::move(entry)) { } + + std::shared_ptr<const ResTable_entry> entry_; +}; + /** * A package-id to package name mapping for any shared libraries used * in this resource table. The package-id's encoded in this resource @@ -1630,43 +1678,66 @@ struct ResTable_overlayable_header */ struct ResTable_overlayable_policy_header { - struct ResChunk_header header; - + /** + * Flags for a bitmask for all possible overlayable policy options. + * + * Any changes to this set should also update aidl/android/os/OverlayablePolicy.aidl + */ enum PolicyFlags : uint32_t { + // Base + NONE = 0x00000000, + // Any overlay can overlay these resources. - POLICY_PUBLIC = 0x00000001, + PUBLIC = 0x00000001, // The overlay must reside of the system partition or must have existed on the system partition // before an upgrade to overlay these resources. - POLICY_SYSTEM_PARTITION = 0x00000002, + SYSTEM_PARTITION = 0x00000002, // The overlay must reside of the vendor partition or must have existed on the vendor partition // before an upgrade to overlay these resources. - POLICY_VENDOR_PARTITION = 0x00000004, + VENDOR_PARTITION = 0x00000004, // The overlay must reside of the product partition or must have existed on the product // partition before an upgrade to overlay these resources. - POLICY_PRODUCT_PARTITION = 0x00000008, + PRODUCT_PARTITION = 0x00000008, - // The overlay must be signed with the same signature as the actor of the target resource, - // which can be separate or the same as the target package with the resource. - POLICY_SIGNATURE = 0x00000010, + // The overlay must be signed with the same signature as the package containing the target + // resource + SIGNATURE = 0x00000010, // The overlay must reside of the odm partition or must have existed on the odm // partition before an upgrade to overlay these resources. - POLICY_ODM_PARTITION = 0x00000020, + ODM_PARTITION = 0x00000020, // The overlay must reside of the oem partition or must have existed on the oem // partition before an upgrade to overlay these resources. - POLICY_OEM_PARTITION = 0x00000040, + OEM_PARTITION = 0x00000040, + + // The overlay must be signed with the same signature as the actor declared for the target + // resource + ACTOR_SIGNATURE = 0x00000080, }; - uint32_t policy_flags; + + using PolicyBitmask = uint32_t; + + struct ResChunk_header header; + + PolicyFlags policy_flags; // The number of ResTable_ref that follow this header. uint32_t entry_count; }; -struct alignas(uint32_t) Idmap_header { +inline ResTable_overlayable_policy_header::PolicyFlags& operator |=( + ResTable_overlayable_policy_header::PolicyFlags& first, + ResTable_overlayable_policy_header::PolicyFlags second) { + first = static_cast<ResTable_overlayable_policy_header::PolicyFlags>(first | second); + return first; +} + +#pragma pack(push, 1) +struct Idmap_header { // Always 0x504D4449 ('IDMP') uint32_t magic; @@ -1675,20 +1746,38 @@ struct alignas(uint32_t) Idmap_header { uint32_t target_crc32; uint32_t overlay_crc32; + uint32_t fulfilled_policies; + uint8_t enforce_overlayable; + uint8_t target_path[256]; uint8_t overlay_path[256]; - uint16_t target_package_id; - uint16_t type_count; -} __attribute__((packed)); + uint32_t debug_info_size; + uint8_t debug_info[0]; -struct alignas(uint32_t) IdmapEntry_header { - uint16_t target_type_id; - uint16_t overlay_type_id; - uint16_t entry_count; - uint16_t entry_id_offset; - uint32_t entries[0]; -} __attribute__((packed)); + size_t Size() const; +}; + +struct Idmap_data_header { + uint8_t target_package_id; + uint8_t overlay_package_id; + uint32_t target_entry_count; + uint32_t overlay_entry_count; + uint32_t string_pool_index_offset; + uint32_t string_pool_length; +}; + +struct Idmap_target_entry { + uint32_t target_id; + uint8_t type; + uint32_t value; +}; + +struct Idmap_overlay_entry { + uint32_t overlay_id; + uint32_t target_id; +}; +#pragma pack(pop) class AssetManager2; @@ -1706,6 +1795,7 @@ class DynamicRefTable public: DynamicRefTable(); DynamicRefTable(uint8_t packageId, bool appAsLib); + virtual ~DynamicRefTable() = default; // Loads an unmapped reference table from the package. status_t load(const ResTable_lib_header* const header); @@ -1719,12 +1809,12 @@ public: void addMapping(uint8_t buildPackageId, uint8_t runtimePackageId); - // Creates a new clone of the reference table - std::unique_ptr<DynamicRefTable> clone() const; + // Returns whether or not the value must be looked up. + bool requiresLookup(const Res_value* value) const; // Performs the actual conversion of build-time resource ID to run-time // resource ID. - status_t lookupResourceId(uint32_t* resId) const; + virtual status_t lookupResourceId(uint32_t* resId) const; status_t lookupResourceValue(Res_value* value) const; inline const KeyedVector<String16, uint8_t>& entries() const { diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h index aa1466fde778..9a3646b49db8 100644 --- a/libs/androidfw/include/androidfw/Util.h +++ b/libs/androidfw/include/androidfw/Util.h @@ -19,12 +19,19 @@ #include <cstdlib> #include <memory> +#include <sstream> #include <vector> #include "android-base/macros.h" #include "androidfw/StringPiece.h" +#ifdef __ANDROID__ +#define ANDROID_LOG(x) LOG(x) +#else +#define ANDROID_LOG(x) std::stringstream() +#endif + namespace android { namespace util { |