diff options
| author | 2017-01-27 22:30:22 +0000 | |
|---|---|---|
| committer | 2017-01-27 22:30:24 +0000 | |
| commit | 90572a4ab8ac393c57e896be3c608e634866ed38 (patch) | |
| tree | 524319d2edfd555f3b637bd332f1a494bf4c1114 /libs/androidfw/include | |
| parent | 904aca762c7e1c1ac5c005134ca802dba0ceed5b (diff) | |
| parent | da431a22da38f9c4085b5d71ed9a9c6122c6a5a6 (diff) | |
Merge "libandroidfw: Add new support for shared libraries"
Diffstat (limited to 'libs/androidfw/include')
| -rw-r--r-- | libs/androidfw/include/androidfw/ApkAssets.h | 3 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/AssetManager2.h | 36 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/Chunk.h | 113 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/LoadedArsc.h | 104 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/ResourceTypes.h | 12 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/Util.h | 8 |
6 files changed, 244 insertions, 32 deletions
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h index a3d67f04eb90..9d4fd29d30d7 100644 --- a/libs/androidfw/include/androidfw/ApkAssets.h +++ b/libs/androidfw/include/androidfw/ApkAssets.h @@ -32,6 +32,7 @@ namespace android { class ApkAssets { public: static std::unique_ptr<ApkAssets> Load(const std::string& path); + static std::unique_ptr<ApkAssets> LoadAsSharedLibrary(const std::string& path); std::unique_ptr<Asset> Open(const std::string& path, Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const; @@ -43,6 +44,8 @@ class ApkAssets { private: DISALLOW_COPY_AND_ASSIGN(ApkAssets); + static std::unique_ptr<ApkAssets> LoadImpl(const std::string& path, bool load_as_shared_library); + ApkAssets() = default; struct ZipArchivePtrCloser { diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index 66d5034463a5..86553390dadf 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -19,6 +19,7 @@ #include "android-base/macros.h" +#include <array> #include <limits> #include <unordered_map> @@ -95,18 +96,21 @@ class AssetManager2 : public ::AAssetManager { // new resource IDs. bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true); - const std::vector<const ApkAssets*> GetApkAssets() const; + inline const std::vector<const ApkAssets*> GetApkAssets() const { return apk_assets_; } // Returns the string pool for the given asset cookie. // Use the string pool returned here with a valid Res_value object of // type Res_value::TYPE_STRING. const ResStringPool* GetStringPoolForCookie(ApkAssetsCookie cookie) const; + // Returns the DynamicRefTable for the given package ID. + const DynamicRefTable* GetDynamicRefTableForPackage(uint32_t package_id) 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); - const ResTable_config& GetConfiguration() const; + inline const ResTable_config& GetConfiguration() const { return configuration_; } // Searches the set of APKs loaded by this AssetManager and opens the first one found located // in the assets/ directory. @@ -173,6 +177,8 @@ class AssetManager2 : public ::AAssetManager { // Creates a new Theme from this AssetManager. std::unique_ptr<Theme> NewTheme(); + void DumpToLog() const; + private: DISALLOW_COPY_AND_ASSIGN(AssetManager2); @@ -189,9 +195,13 @@ class AssetManager2 : public ::AAssetManager { // `out_flags` stores the resulting bitmask of configuration axis with which the resource // value varies. ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match, - LoadedArsc::Entry* out_entry, ResTable_config* out_selected_config, + LoadedArscEntry* out_entry, ResTable_config* out_selected_config, uint32_t* out_flags); + // Assigns package IDs to all shared library ApkAssets. + // Should be called whenever the ApkAssets are changed. + void BuildDynamicRefTable(); + // Purge all resources that are cached and vary by the configuration axis denoted by the // bitmask `diff`. void InvalidateCaches(uint32_t diff); @@ -200,6 +210,22 @@ class AssetManager2 : public ::AAssetManager { // have a longer lifetime. std::vector<const ApkAssets*> apk_assets_; + struct PackageGroup { + std::vector<const LoadedPackage*> packages_; + std::vector<ApkAssetsCookie> cookies_; + 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 + // immutable ApkAssets class. + std::vector<PackageGroup> package_groups_; + + // An array mapping package ID to index into package_groups. This keeps the lookup fast + // without taking too much memory. + std::array<uint8_t, std::numeric_limits<uint8_t>::max() + 1> package_ids_; + // The current configuration set for this AssetManager. When this changes, cached resources // may need to be purged. ResTable_config configuration_; @@ -279,12 +305,12 @@ class Theme { struct Package { // Each element of Type will be a dynamically sized object // allocated to have the entries stored contiguously with the Type. - util::unique_cptr<Type> types[kTypeCount]; + std::array<util::unique_cptr<Type>, kTypeCount> types; }; AssetManager2* asset_manager_; uint32_t type_spec_flags_ = 0u; - std::unique_ptr<Package> packages_[kPackageCount]; + std::array<std::unique_ptr<Package>, kPackageCount> packages_; }; inline const ResolvedBag::Entry* begin(const ResolvedBag* bag) { return bag->entries; } diff --git a/libs/androidfw/include/androidfw/Chunk.h b/libs/androidfw/include/androidfw/Chunk.h new file mode 100644 index 000000000000..e87b94087450 --- /dev/null +++ b/libs/androidfw/include/androidfw/Chunk.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2016 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 CHUNK_H_ +#define CHUNK_H_ + +#include "android-base/logging.h" +#include "android-base/macros.h" +#include "utils/ByteOrder.h" + +#ifdef _WIN32 +#ifdef ERROR +#undef ERROR +#endif +#endif + +#include "androidfw/ResourceTypes.h" + +namespace android { + +// Helpful wrapper around a ResChunk_header that provides getter methods +// that handle endianness conversions and provide access to the data portion +// of the chunk. +class Chunk { + public: + explicit Chunk(const 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); } + + // Returns the size of the entire chunk. This can be useful for skipping + // over the entire chunk. Caller need not worry about endianness. + inline size_t size() const { return dtohl(device_chunk_->size); } + + // Returns the size of the header. Caller need not worry about endianness. + inline size_t header_size() const { return dtohs(device_chunk_->headerSize); } + + template <typename T> + inline const T* header() const { + if (header_size() >= sizeof(T)) { + return reinterpret_cast<const T*>(device_chunk_); + } + return nullptr; + } + + inline const void* data_ptr() const { + return reinterpret_cast<const uint8_t*>(device_chunk_) + header_size(); + } + + inline size_t data_size() const { return size() - header_size(); } + + private: + const ResChunk_header* device_chunk_; +}; + +// Provides a Java style iterator over an array of ResChunk_header's. +// Validation is performed while iterating. +// The caller should check if there was an error during chunk validation +// by calling HadError() and GetLastError() to get the reason for failure. +// Example: +// +// ChunkIterator iter(data_ptr, data_len); +// while (iter.HasNext()) { +// const Chunk chunk = iter.Next(); +// ... +// } +// +// if (iter.HadError()) { +// LOG(ERROR) << iter.GetLastError(); +// } +// +class ChunkIterator { + public: + ChunkIterator(const void* data, size_t len) + : next_chunk_(reinterpret_cast<const ResChunk_header*>(data)), + len_(len), + last_error_(nullptr) { + CHECK(next_chunk_ != nullptr) << "data can't be nullptr"; + VerifyNextChunk(); + } + + Chunk Next(); + inline bool HasNext() const { return !HadError() && len_ != 0; }; + inline bool HadError() const { return last_error_ != nullptr; } + inline std::string GetLastError() const { return last_error_; } + + private: + DISALLOW_COPY_AND_ASSIGN(ChunkIterator); + + // Returns false if there was an error. + bool VerifyNextChunk(); + + const ResChunk_header* next_chunk_; + size_t len_; + const char* last_error_; +}; + +} // namespace android + +#endif /* CHUNK_H_ */ diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h index e2e56c88ee1d..8362008eccc7 100644 --- a/libs/androidfw/include/androidfw/LoadedArsc.h +++ b/libs/androidfw/include/androidfw/LoadedArsc.h @@ -22,12 +22,82 @@ #include "android-base/macros.h" +#include "androidfw/ByteBucketArray.h" +#include "androidfw/Chunk.h" #include "androidfw/ResourceTypes.h" +#include "androidfw/Util.h" namespace android { -class Chunk; -class LoadedPackage; +class DynamicPackageEntry { + public: + DynamicPackageEntry() = default; + DynamicPackageEntry(std::string&& package_name, int package_id) + : package_name(std::move(package_name)), package_id(package_id) {} + + std::string package_name; + int package_id = 0; +}; + +struct LoadedArscEntry { + // A pointer to the resource table entry for this resource. + // If the size of the entry is > sizeof(ResTable_entry), it can be cast to + // a ResTable_map_entry and processed as a bag/map. + const ResTable_entry* entry = nullptr; + + // The dynamic package ID map for the package from which this resource came from. + const DynamicRefTable* dynamic_ref_table = nullptr; + + // The string pool reference to the type's name. This uses a different string pool than + // the global string pool, but this is hidden from the caller. + StringPoolRef type_string_ref; + + // The string pool reference to the entry's name. This uses a different string pool than + // the global string pool, but this is hidden from the caller. + StringPoolRef entry_string_ref; +}; + +struct TypeSpec; +class LoadedArsc; + +class LoadedPackage { + friend class LoadedArsc; + + public: + bool FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config, + LoadedArscEntry* out_entry, ResTable_config* out_selected_config, + uint32_t* out_flags) const; + + inline const ResStringPool* GetTypeStringPool() const { return &type_string_pool_; } + + inline const ResStringPool* GetKeyStringPool() const { return &key_string_pool_; } + + inline const std::string& GetPackageName() const { return package_name_; } + + inline int GetPackageId() const { return package_id_; } + + inline bool IsDynamic() const { return dynamic_; } + + inline const std::vector<DynamicPackageEntry>& GetDynamicPackageMap() const { + return dynamic_package_map_; + } + + private: + DISALLOW_COPY_AND_ASSIGN(LoadedPackage); + + static std::unique_ptr<LoadedPackage> Load(const Chunk& chunk); + + LoadedPackage() = default; + + ResStringPool type_string_pool_; + ResStringPool key_string_pool_; + std::string package_name_; + int package_id_ = -1; + bool dynamic_ = false; + + ByteBucketArray<util::unique_cptr<TypeSpec>> type_specs_; + std::vector<DynamicPackageEntry> dynamic_package_map_; +}; // Read-only view into a resource table. This class validates all data // when loading, including offsets and lengths. @@ -35,7 +105,8 @@ class LoadedArsc { public: // Load the resource table from memory. The data's lifetime must out-live the // object returned from this method. - static std::unique_ptr<LoadedArsc> Load(const void* data, size_t len); + static std::unique_ptr<LoadedArsc> Load(const void* data, size_t len, + bool load_as_shared_library = false); ~LoadedArsc(); @@ -43,39 +114,28 @@ class LoadedArsc { // (Res_value::dataType == Res_value::TYPE_STRING) are indexed. inline const ResStringPool* GetStringPool() const { return &global_string_pool_; } - struct Entry { - // A pointer to the resource table entry for this resource. - // If the size of the entry is > sizeof(ResTable_entry), it can be cast to - // a ResTable_map_entry and processed as a bag/map. - const ResTable_entry* entry = nullptr; - - // The string pool reference to the type's name. This uses a different string pool than - // the global string pool, but this is hidden from the caller. - StringPoolRef type_string_ref; - - // The string pool reference to the entry's name. This uses a different string pool than - // the global string pool, but this is hidden from the caller. - StringPoolRef entry_string_ref; - }; - // Finds the resource with ID `resid` with the best value for configuration `config`. // The parameter `out_entry` will be filled with the resulting resource entry. // The resource entry can be a simple entry (ResTable_entry) or a complex bag // (ResTable_entry_map). - bool FindEntry(uint32_t resid, const ResTable_config& config, Entry* out_entry, + bool FindEntry(uint32_t resid, const ResTable_config& config, LoadedArscEntry* out_entry, ResTable_config* selected_config, uint32_t* out_flags) const; // Gets a pointer to the name of the package in `resid`, or nullptr if the package doesn't exist. - const std::string* GetPackageNameForId(uint32_t resid) const; + const LoadedPackage* GetPackageForId(uint32_t resid) const; + + inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const { + return packages_; + } private: DISALLOW_COPY_AND_ASSIGN(LoadedArsc); LoadedArsc() = default; - bool LoadTable(const Chunk& chunk); + bool LoadTable(const Chunk& chunk, bool load_as_shared_library); ResStringPool global_string_pool_; - std::vector<std::unique_ptr<LoadedPackage>> packages_; + std::vector<std::unique_ptr<const LoadedPackage>> packages_; }; } // namespace android diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 86ab123ff064..56c22e60e30b 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1538,6 +1538,8 @@ struct ResTable_lib_entry uint16_t packageName[128]; }; +class AssetManager2; + /** * Holds the shared library ID table. Shared libraries are assigned package IDs at * build time, but they may be loaded in a different order, so we need to maintain @@ -1548,7 +1550,9 @@ struct ResTable_lib_entry */ class DynamicRefTable { + friend class AssetManager2; public: + DynamicRefTable() = default; DynamicRefTable(uint8_t packageId, bool appAsLib); // Loads an unmapped reference table from the package. @@ -1563,18 +1567,18 @@ public: // Performs the actual conversion of build-time resource ID to run-time // resource ID. - inline status_t lookupResourceId(uint32_t* resId) const; - inline status_t lookupResourceValue(Res_value* value) const; + status_t lookupResourceId(uint32_t* resId) const; + status_t lookupResourceValue(Res_value* value) const; inline const KeyedVector<String16, uint8_t>& entries() const { return mEntries; } private: - const uint8_t mAssignedPackageId; + uint8_t mAssignedPackageId = 0; uint8_t mLookupTable[256]; KeyedVector<String16, uint8_t> mEntries; - bool mAppAsLib; + bool mAppAsLib = false; }; bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue); diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h index 5266d09e84e3..fd96730d2398 100644 --- a/libs/androidfw/include/androidfw/Util.h +++ b/libs/androidfw/include/androidfw/Util.h @@ -102,6 +102,10 @@ class unique_cptr { pointer ptr_; }; +inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) { + return resid | (static_cast<uint32_t>(package_id) << 24); +} + inline uint8_t get_package_id(uint32_t resid) { return static_cast<uint8_t>((resid >> 24) & 0x000000ffu); } @@ -113,7 +117,7 @@ inline uint8_t get_type_id(uint32_t resid) { inline uint16_t get_entry_id(uint32_t resid) { return static_cast<uint16_t>(resid & 0x0000ffffu); } -inline bool is_internal_id(uint32_t resid) { +inline bool is_internal_resid(uint32_t resid) { return (resid & 0xffff0000u) != 0 && (resid & 0x00ff0000u) == 0; } @@ -121,6 +125,8 @@ inline bool is_valid_resid(uint32_t resid) { return (resid & 0x00ff0000u) != 0 && (resid & 0xff000000u) != 0; } +void ReadUtf16StringFromDevice(const uint16_t* src, size_t len, std::string* out); + } // namespace util } // namespace android |