diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/androidfw/Android.bp | 5 | ||||
| -rw-r--r-- | libs/androidfw/ApkAssets.cpp | 93 | ||||
| -rw-r--r-- | libs/androidfw/Asset.cpp | 20 | ||||
| -rw-r--r-- | libs/androidfw/AssetManager2.cpp | 72 | ||||
| -rw-r--r-- | libs/androidfw/LoadedArsc.cpp | 29 | ||||
| -rw-r--r-- | libs/androidfw/ResourceTypes.cpp | 5 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/ApkAssets.h | 38 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/Asset.h | 5 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/AssetManager2.h | 8 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/LoadedArsc.h | 26 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/ResourceTypes.h | 2 | ||||
| -rw-r--r-- | libs/androidfw/tests/LoadedArsc_test.cpp | 34 | ||||
| -rw-r--r-- | libs/androidfw/tests/data/loader/resources.arsc | bin | 0 -> 620 bytes | |||
| -rw-r--r-- | libs/androidfw/tests/data/system/R.h | 6 |
14 files changed, 301 insertions, 42 deletions
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp index eeaefc5b157c..a34a6c0b3724 100644 --- a/libs/androidfw/Android.bp +++ b/libs/androidfw/Android.bp @@ -166,7 +166,10 @@ cc_test { static_libs: common_test_libs + ["liblog", "libz"], }, }, - data: ["tests/data/**/*.apk"], + data: [ + "tests/data/**/*.apk", + "tests/data/**/*.arsc", + ], test_suites: ["device-tests"], } diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp index cf2ef3070385..b309621435b5 100644 --- a/libs/androidfw/ApkAssets.cpp +++ b/libs/androidfw/ApkAssets.cpp @@ -42,12 +42,16 @@ static const std::string kResourcesArsc("resources.arsc"); ApkAssets::ApkAssets(ZipArchiveHandle unmanaged_handle, const std::string& path, - time_t last_mod_time) - : zip_handle_(unmanaged_handle, ::CloseArchive), path_(path), last_mod_time_(last_mod_time) { + time_t last_mod_time, + bool for_loader) + : zip_handle_(unmanaged_handle, ::CloseArchive), path_(path), last_mod_time_(last_mod_time), + for_loader(for_loader) { } -std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system) { - return LoadImpl({} /*fd*/, path, nullptr, nullptr, system, false /*load_as_shared_library*/); +std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system, + bool for_loader) { + return LoadImpl({} /*fd*/, path, nullptr, nullptr, system, false /*load_as_shared_library*/, + for_loader); } std::unique_ptr<const ApkAssets> ApkAssets::LoadAsSharedLibrary(const std::string& path, @@ -76,9 +80,21 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap std::unique_ptr<const ApkAssets> ApkAssets::LoadFromFd(unique_fd fd, const std::string& friendly_name, - bool system, bool force_shared_lib) { + bool system, bool force_shared_lib, + bool for_loader) { return LoadImpl(std::move(fd), friendly_name, nullptr /*idmap_asset*/, nullptr /*loaded_idmap*/, - system, force_shared_lib); + system, force_shared_lib, for_loader); +} + +std::unique_ptr<const ApkAssets> ApkAssets::LoadArsc(const std::string& path, + bool for_loader) { + return LoadArscImpl({} /*fd*/, path, for_loader); +} + +std::unique_ptr<const ApkAssets> ApkAssets::LoadArsc(unique_fd fd, + const std::string& friendly_name, + bool for_loader) { + return LoadArscImpl(std::move(fd), friendly_name, for_loader); } std::unique_ptr<Asset> ApkAssets::CreateAssetFromFile(const std::string& path) { @@ -104,7 +120,8 @@ std::unique_ptr<Asset> ApkAssets::CreateAssetFromFile(const std::string& path) { std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl( 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) { + std::unique_ptr<const LoadedIdmap> loaded_idmap, bool system, bool load_as_shared_library, + bool for_loader) { ::ZipArchiveHandle unmanaged_handle; int32_t result; if (fd >= 0) { @@ -123,7 +140,8 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl( time_t last_mod_time = getFileModDate(path.c_str()); // Wrap the handle in a unique_ptr so it gets automatically closed. - std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(unmanaged_handle, path, last_mod_time)); + std::unique_ptr<ApkAssets> + loaded_apk(new ApkAssets(unmanaged_handle, path, last_mod_time, for_loader)); // Find the resource table. ::ZipEntry entry; @@ -152,7 +170,7 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl( reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)), loaded_apk->resources_asset_->getLength()); loaded_apk->loaded_arsc_ = - LoadedArsc::Load(data, loaded_idmap.get(), system, load_as_shared_library); + LoadedArsc::Load(data, loaded_idmap.get(), system, load_as_shared_library, for_loader); if (loaded_apk->loaded_arsc_ == nullptr) { LOG(ERROR) << "Failed to load '" << kResourcesArsc << "' in APK '" << path << "'."; return {}; @@ -162,8 +180,53 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl( return std::move(loaded_apk); } +std::unique_ptr<const ApkAssets> ApkAssets::LoadArscImpl(unique_fd fd, + const std::string& path, + bool for_loader) { + std::unique_ptr<Asset> resources_asset; + + if (fd >= 0) { + resources_asset = std::unique_ptr<Asset>(Asset::createFromFd(fd.release(), nullptr, + Asset::AccessMode::ACCESS_BUFFER)); + } else { + resources_asset = CreateAssetFromFile(path); + } + + if (resources_asset == nullptr) { + LOG(ERROR) << "Failed to open ARSC '" << path; + return {}; + } + + time_t last_mod_time = getFileModDate(path.c_str()); + + std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(nullptr, path, last_mod_time, for_loader)); + loaded_apk->resources_asset_ = std::move(resources_asset); + + const StringPiece data( + reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)), + loaded_apk->resources_asset_->getLength()); + loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, nullptr, false, false, for_loader); + if (loaded_apk->loaded_arsc_ == nullptr) { + LOG(ERROR) << "Failed to load '" << kResourcesArsc << path; + return {}; + } + + // Need to force a move for mingw32. + return std::move(loaded_apk); +} + +std::unique_ptr<const ApkAssets> ApkAssets::LoadEmpty(bool for_loader) { + std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(nullptr, "", -1, for_loader)); + loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty(); + // Need to force a move for mingw32. + return std::move(loaded_apk); +} + std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMode mode) const { - CHECK(zip_handle_ != nullptr); + // If this is a resource loader from an .arsc, there will be no zip handle + if (zip_handle_ == nullptr) { + return {}; + } ::ZipEntry entry; int32_t result = ::FindEntry(zip_handle_.get(), path, &entry); @@ -205,7 +268,10 @@ std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMod bool ApkAssets::ForEachFile(const std::string& root_path, const std::function<void(const StringPiece&, FileType)>& f) const { - CHECK(zip_handle_ != nullptr); + // If this is a resource loader from an .arsc, there will be no zip handle + if (zip_handle_ == nullptr) { + return false; + } std::string root_path_full = root_path; if (root_path_full.back() != '/') { @@ -252,6 +318,11 @@ bool ApkAssets::ForEachFile(const std::string& root_path, } bool ApkAssets::IsUpToDate() const { + // Loaders are invalidated by the app, not the system, so assume up to date + if (for_loader) { + return true; + } + return last_mod_time_ == getFileModDate(path_.c_str()); } diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp index 92125c9da8bb..c132f343713f 100644 --- a/libs/androidfw/Asset.cpp +++ b/libs/androidfw/Asset.cpp @@ -133,14 +133,24 @@ Asset::Asset(void) */ /*static*/ Asset* Asset::createFromFile(const char* fileName, AccessMode mode) { + return createFromFd(open(fileName, O_RDONLY | O_BINARY), fileName, mode); +} + +/* + * Create a new Asset from a file on disk. There is a fair chance that + * the file doesn't actually exist. + * + * We can use "mode" to decide how we want to go about it. + */ +/*static*/ Asset* Asset::createFromFd(const int fd, const char* fileName, AccessMode mode) +{ + if (fd < 0) { + return NULL; + } + _FileAsset* pAsset; status_t result; off64_t length; - int fd; - - fd = open(fileName, O_RDONLY | O_BINARY); - if (fd < 0) - return NULL; /* * Under Linux, the lseek fails if we actually opened a directory. To diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index eec49df79630..e914f37bcac4 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -493,8 +493,12 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri type_flags |= type_spec->GetFlagsForEntryIndex(local_entry_idx); - // If the package is an overlay, then even configurations that are the same MUST be chosen. + + // If the package is an overlay or custom loader, + // then even configurations that are the same MUST be chosen. const bool package_is_overlay = loaded_package->IsOverlay(); + const bool package_is_loader = loaded_package->IsCustomLoader(); + const bool should_overlay = package_is_overlay || package_is_loader; if (use_fast_path) { const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx]; @@ -508,10 +512,28 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri if (best_config == nullptr) { resolution_type = Resolution::Step::Type::INITIAL; } else if (this_config.isBetterThan(*best_config, desired_config)) { - resolution_type = Resolution::Step::Type::BETTER_MATCH; - } else if (package_is_overlay && this_config.compare(*best_config) == 0) { - resolution_type = Resolution::Step::Type::OVERLAID; + if (package_is_loader) { + resolution_type = Resolution::Step::Type::BETTER_MATCH_LOADER; + } else { + resolution_type = Resolution::Step::Type::BETTER_MATCH; + } + } else if (should_overlay && this_config.compare(*best_config) == 0) { + if (package_is_loader) { + resolution_type = Resolution::Step::Type::OVERLAID_LOADER; + } else if (package_is_overlay) { + resolution_type = Resolution::Step::Type::OVERLAID; + } } else { + if (resource_resolution_logging_enabled_) { + if (package_is_loader) { + resolution_type = Resolution::Step::Type::SKIPPED_LOADER; + } else { + resolution_type = Resolution::Step::Type::SKIPPED; + } + resolution_steps.push_back(Resolution::Step{resolution_type, + this_config.toString(), + &loaded_package->GetPackageName()}); + } continue; } @@ -520,6 +542,16 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri const ResTable_type* type = filtered_group.types[i]; const uint32_t offset = LoadedPackage::GetEntryOffset(type, local_entry_idx); if (offset == ResTable_type::NO_ENTRY) { + if (resource_resolution_logging_enabled_) { + if (package_is_loader) { + resolution_type = Resolution::Step::Type::NO_ENTRY_LOADER; + } else { + resolution_type = Resolution::Step::Type::NO_ENTRY; + } + resolution_steps.push_back(Resolution::Step{Resolution::Step::Type::NO_ENTRY, + this_config.toString(), + &loaded_package->GetPackageName()}); + } continue; } @@ -554,9 +586,17 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri if (best_config == nullptr) { resolution_type = Resolution::Step::Type::INITIAL; } else if (this_config.isBetterThan(*best_config, desired_config)) { - resolution_type = Resolution::Step::Type::BETTER_MATCH; - } else if (package_is_overlay && this_config.compare(*best_config) == 0) { - resolution_type = Resolution::Step::Type::OVERLAID; + if (package_is_loader) { + resolution_type = Resolution::Step::Type::BETTER_MATCH_LOADER; + } else { + resolution_type = Resolution::Step::Type::BETTER_MATCH; + } + } else if (should_overlay && this_config.compare(*best_config) == 0) { + if (package_is_overlay) { + resolution_type = Resolution::Step::Type::OVERLAID; + } else if (package_is_loader) { + resolution_type = Resolution::Step::Type::OVERLAID_LOADER; + } } else { continue; } @@ -678,9 +718,27 @@ std::string AssetManager2::GetLastResourceResolution() const { case Resolution::Step::Type::BETTER_MATCH: prefix = "Found better"; break; + case Resolution::Step::Type::BETTER_MATCH_LOADER: + prefix = "Found better in loader"; + break; case Resolution::Step::Type::OVERLAID: prefix = "Overlaid"; break; + case Resolution::Step::Type::OVERLAID_LOADER: + prefix = "Overlaid by loader"; + break; + case Resolution::Step::Type::SKIPPED: + prefix = "Skipped"; + break; + case Resolution::Step::Type::SKIPPED_LOADER: + prefix = "Skipped loader"; + break; + case Resolution::Step::Type::NO_ENTRY: + prefix = "No entry"; + break; + case Resolution::Step::Type::NO_ENTRY_LOADER: + prefix = "No entry for loader"; + break; } if (!prefix.empty()) { diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp index 72873abc6a42..882dc0d71759 100644 --- a/libs/androidfw/LoadedArsc.cpp +++ b/libs/androidfw/LoadedArsc.cpp @@ -401,7 +401,9 @@ const LoadedPackage* LoadedArsc::GetPackageById(uint8_t package_id) const { std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, const LoadedIdmap* loaded_idmap, - bool system, bool load_as_shared_library) { + bool system, + bool load_as_shared_library, + bool for_loader) { ATRACE_NAME("LoadedPackage::Load"); std::unique_ptr<LoadedPackage> loaded_package(new LoadedPackage()); @@ -430,6 +432,10 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, loaded_package->overlay_ = true; } + if (for_loader) { + loaded_package->custom_loader_ = true; + } + if (header->header.headerSize >= sizeof(ResTable_package)) { uint32_t type_id_offset = dtohl(header->typeIdOffset); if (type_id_offset > std::numeric_limits<uint8_t>::max()) { @@ -696,7 +702,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, } bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap, - bool load_as_shared_library) { + bool load_as_shared_library, bool for_loader) { const ResTable_header* header = chunk.header<ResTable_header>(); if (header == nullptr) { LOG(ERROR) << "RES_TABLE_TYPE too small."; @@ -735,7 +741,11 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap, packages_seen++; std::unique_ptr<const LoadedPackage> loaded_package = - LoadedPackage::Load(child_chunk, loaded_idmap, system_, load_as_shared_library); + LoadedPackage::Load(child_chunk, + loaded_idmap, + system_, + load_as_shared_library, + for_loader); if (!loaded_package) { return false; } @@ -758,9 +768,11 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap, } std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const StringPiece& data, - const LoadedIdmap* loaded_idmap, bool system, - bool load_as_shared_library) { - ATRACE_NAME("LoadedArsc::LoadTable"); + const LoadedIdmap* loaded_idmap, + bool system, + bool load_as_shared_library, + bool for_loader) { + ATRACE_NAME("LoadedArsc::Load"); // Not using make_unique because the constructor is private. std::unique_ptr<LoadedArsc> loaded_arsc(new LoadedArsc()); @@ -771,7 +783,10 @@ std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const StringPiece& data, const Chunk chunk = iter.Next(); switch (chunk.type()) { case RES_TABLE_TYPE: - if (!loaded_arsc->LoadTable(chunk, loaded_idmap, load_as_shared_library)) { + if (!loaded_arsc->LoadTable(chunk, + loaded_idmap, + load_as_shared_library, + for_loader)) { return {}; } break; diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 535386920265..3fe2c5b0e21a 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -1063,6 +1063,11 @@ size_t ResStringPool::bytes() const return (mError == NO_ERROR) ? mHeader->header.size : 0; } +const void* ResStringPool::data() const +{ + return mHeader; +} + bool ResStringPool::isSorted() const { return (mHeader->flags&ResStringPool_header::SORTED_FLAG)!=0; diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h index 49fc82bff11e..625b68207d83 100644 --- a/libs/androidfw/include/androidfw/ApkAssets.h +++ b/libs/androidfw/include/androidfw/ApkAssets.h @@ -40,7 +40,8 @@ class ApkAssets { // 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, bool system = false, + bool for_loader = false); // 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 @@ -63,7 +64,21 @@ class ApkAssets { // 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); + bool force_shared_lib, + bool for_loader = false); + + // Creates an empty wrapper ApkAssets from the given path which points to an .arsc. + static std::unique_ptr<const ApkAssets> LoadArsc(const std::string& path, + bool for_loader = false); + + // Creates an empty wrapper ApkAssets from the given file descriptor which points to an .arsc, + // Takes ownership of the file descriptor. + static std::unique_ptr<const ApkAssets> LoadArsc(base::unique_fd fd, + const std::string& friendly_name, + bool resource_loader = false); + + // Creates a totally empty ApkAssets with no resources table and no file entries. + static std::unique_ptr<const ApkAssets> LoadEmpty(bool resource_loader = false); std::unique_ptr<Asset> Open(const std::string& path, Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const; @@ -86,24 +101,33 @@ class ApkAssets { bool IsUpToDate() const; + // Creates an Asset from any file on the file system. + static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path); + 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); + bool system, bool load_as_shared_library, + bool resource_loader = false); - // 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> LoadArscImpl(base::unique_fd fd, + const std::string& path, + bool resource_loader = false); - ApkAssets(ZipArchiveHandle unmanaged_handle, const std::string& path, time_t last_mod_time); + ApkAssets(ZipArchiveHandle unmanaged_handle, + const std::string& path, + time_t last_mod_time, + bool for_loader = false); - using ZipArchivePtr = std::unique_ptr<ZipArchive, void(*)(ZipArchiveHandle)>; + using ZipArchivePtr = std::unique_ptr<ZipArchive, void (*)(ZipArchiveHandle)>; ZipArchivePtr zip_handle_; const std::string path_; time_t last_mod_time_; + bool for_loader; std::unique_ptr<Asset> resources_asset_; std::unique_ptr<Asset> idmap_asset_; std::unique_ptr<const LoadedArsc> loaded_arsc_; diff --git a/libs/androidfw/include/androidfw/Asset.h b/libs/androidfw/include/androidfw/Asset.h index 9d12a35395c9..053dbb7864c6 100644 --- a/libs/androidfw/include/androidfw/Asset.h +++ b/libs/androidfw/include/androidfw/Asset.h @@ -121,6 +121,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 diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index de46081a6aa3..c7348b180648 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -382,7 +382,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. diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h index 950f5413f550..1a56876b9686 100644 --- a/libs/androidfw/include/androidfw/LoadedArsc.h +++ b/libs/androidfw/include/androidfw/LoadedArsc.h @@ -137,7 +137,8 @@ class LoadedPackage { static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk, const LoadedIdmap* loaded_idmap, bool system, - bool load_as_shared_library); + bool load_as_shared_library, + bool load_as_custom_loader); ~LoadedPackage(); @@ -187,6 +188,11 @@ class LoadedPackage { return overlay_; } + // Returns true if this package is a custom loader and should behave like an overlay + inline bool IsCustomLoader() const { + return custom_loader_; + } + // Returns the map of package name to package ID used in this LoadedPackage. At runtime, a // package could have been assigned a different package ID than what this LoadedPackage was // compiled with. AssetManager rewrites the package IDs so that they are compatible at runtime. @@ -260,6 +266,7 @@ class LoadedPackage { bool dynamic_ = false; bool system_ = false; bool overlay_ = false; + bool custom_loader_ = false; bool defines_overlayable_ = false; ByteBucketArray<TypeSpecPtr> type_specs_; @@ -282,7 +289,8 @@ class LoadedArsc { static std::unique_ptr<const LoadedArsc> Load(const StringPiece& data, const LoadedIdmap* loaded_idmap = nullptr, bool system = false, - bool load_as_shared_library = false); + bool load_as_shared_library = false, + bool for_loader = false); // Create an empty LoadedArsc. This is used when an APK has no resources.arsc. static std::unique_ptr<const LoadedArsc> CreateEmpty(); @@ -311,7 +319,19 @@ class LoadedArsc { 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, + bool load_as_shared_library, + bool for_loader + ); + + static std::unique_ptr<const LoadedArsc> LoadData(std::unique_ptr<LoadedArsc>& loaded_arsc, + const char* data, + size_t length, + const LoadedIdmap* loaded_idmap = nullptr, + bool load_as_shared_library = false, + bool for_loader = false); ResStringPool global_string_pool_; std::vector<std::unique_ptr<const LoadedPackage>> packages_; diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index fc635aaeb0d8..c8ace90e6515 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -523,6 +523,8 @@ public: size_t size() const; size_t styleCount() const; size_t bytes() const; + const void* data() const; + bool isSorted() const; bool isUTF8() const; diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp index d58e8d20c8aa..fd57a92c216b 100644 --- a/libs/androidfw/tests/LoadedArsc_test.cpp +++ b/libs/androidfw/tests/LoadedArsc_test.cpp @@ -25,6 +25,7 @@ #include "data/overlayable/R.h" #include "data/sparse/R.h" #include "data/styles/R.h" +#include "data/system/R.h" namespace app = com::android::app; namespace basic = com::android::basic; @@ -387,6 +388,39 @@ TEST(LoadedArscTest, GetOverlayableMap) { ASSERT_EQ(map.at("OverlayableResources2"), "overlay://com.android.overlayable"); } +TEST(LoadedArscTest, LoadCustomLoader) { + std::string contents; + + std::unique_ptr<Asset> + asset = ApkAssets::CreateAssetFromFile(GetTestDataPath() + "/loader/resources.arsc"); + + MockLoadedIdmap loaded_idmap; + const StringPiece data( + reinterpret_cast<const char*>(asset->getBuffer(true /*wordAligned*/)), + asset->getLength()); + + std::unique_ptr<const LoadedArsc> loaded_arsc = + LoadedArsc::Load(data, nullptr, false, false, true); + ASSERT_THAT(loaded_arsc, NotNull()); + + const LoadedPackage* package = + loaded_arsc->GetPackageById(get_package_id(android::R::string::cancel)); + ASSERT_THAT(package, NotNull()); + EXPECT_THAT(package->GetPackageName(), StrEq("android")); + EXPECT_THAT(package->GetPackageId(), Eq(0x01)); + + const uint8_t type_index = get_type_id(android::R::string::cancel) - 1; + const uint16_t entry_index = get_entry_id(android::R::string::cancel); + + const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index); + ASSERT_THAT(type_spec, NotNull()); + ASSERT_THAT(type_spec->type_count, Ge(1u)); + + const ResTable_type* type = type_spec->types[0]; + ASSERT_THAT(type, NotNull()); + ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull()); +} + // structs with size fields (like Res_value, ResTable_entry) should be // backwards and forwards compatible (aka checking the size field against // sizeof(Res_value) might not be backwards compatible. diff --git a/libs/androidfw/tests/data/loader/resources.arsc b/libs/androidfw/tests/data/loader/resources.arsc Binary files differnew file mode 100644 index 000000000000..2c881f2cdfe5 --- /dev/null +++ b/libs/androidfw/tests/data/loader/resources.arsc diff --git a/libs/androidfw/tests/data/system/R.h b/libs/androidfw/tests/data/system/R.h index becb38830fb3..374107484784 100644 --- a/libs/androidfw/tests/data/system/R.h +++ b/libs/androidfw/tests/data/system/R.h @@ -40,6 +40,12 @@ struct R { number = 0x01030000, // sv }; }; + + struct string { + enum : uint32_t { + cancel = 0x01040000, + }; + }; }; } // namespace android |