Loading libs/androidfw/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -36,6 +36,7 @@ cc_library { "misc.cpp", "misc.cpp", "ObbFile.cpp", "ObbFile.cpp", "ResourceTypes.cpp", "ResourceTypes.cpp", "ResourceUtils.cpp", "StreamingZipInflater.cpp", "StreamingZipInflater.cpp", "TypeWrappers.cpp", "TypeWrappers.cpp", "Util.cpp", "Util.cpp", Loading libs/androidfw/AssetManager2.cpp +81 −20 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,8 @@ #endif #endif #endif #endif #include "androidfw/ResourceUtils.h" namespace android { namespace android { AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); } AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); } Loading Loading @@ -235,9 +237,9 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri desired_config = &density_override_config; desired_config = &density_override_config; } } const uint32_t package_id = util::get_package_id(resid); const uint32_t package_id = get_package_id(resid); const uint8_t type_id = util::get_type_id(resid); const uint8_t type_id = get_type_id(resid); const uint16_t entry_id = util::get_entry_id(resid); const uint16_t entry_id = get_entry_id(resid); if (type_id == 0) { if (type_id == 0) { LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid); LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid); Loading Loading @@ -452,7 +454,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { ResolvedBag::Entry* new_entry = new_bag->entries; ResolvedBag::Entry* new_entry = new_bag->entries; for (; map_entry != map_entry_end; ++map_entry) { for (; map_entry != map_entry_end; ++map_entry) { uint32_t new_key = dtohl(map_entry->name.ident); uint32_t new_key = dtohl(map_entry->name.ident); if (!util::is_internal_resid(new_key)) { if (!is_internal_resid(new_key)) { // Attributes, arrays, etc don't have a resource id as the name. They specify // Attributes, arrays, etc don't have a resource id as the name. They specify // other data, which would be wrong to change via a lookup. // other data, which would be wrong to change via a lookup. if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) { if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) { Loading Loading @@ -501,7 +503,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { // The keys are expected to be in sorted order. Merge the two bags. // The keys are expected to be in sorted order. Merge the two bags. while (map_entry != map_entry_end && parent_entry != parent_entry_end) { while (map_entry != map_entry_end && parent_entry != parent_entry_end) { uint32_t child_key = dtohl(map_entry->name.ident); uint32_t child_key = dtohl(map_entry->name.ident); if (!util::is_internal_resid(child_key)) { if (!is_internal_resid(child_key)) { if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) { if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) { LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key, resid); LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key, resid); return nullptr; return nullptr; Loading Loading @@ -533,7 +535,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { // Finish the child entries if they exist. // Finish the child entries if they exist. while (map_entry != map_entry_end) { while (map_entry != map_entry_end) { uint32_t new_key = dtohl(map_entry->name.ident); uint32_t new_key = dtohl(map_entry->name.ident); if (!util::is_internal_resid(new_key)) { if (!is_internal_resid(new_key)) { if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) { if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) { LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid); LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid); return nullptr; return nullptr; Loading Loading @@ -571,12 +573,71 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { return result; return result; } } static bool Utf8ToUtf16(const StringPiece& str, std::u16string* out) { ssize_t len = utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str.data()), str.size(), false); if (len < 0) { return false; } out->resize(static_cast<size_t>(len)); utf8_to_utf16(reinterpret_cast<const uint8_t*>(str.data()), str.size(), &*out->begin(), static_cast<size_t>(len + 1)); return true; } uint32_t AssetManager2::GetResourceId(const std::string& resource_name, uint32_t AssetManager2::GetResourceId(const std::string& resource_name, const std::string& fallback_type, const std::string& fallback_type, const std::string& fallback_package) { const std::string& fallback_package) { (void)resource_name; StringPiece package_name, type, entry; (void)fallback_type; if (!ExtractResourceName(resource_name, &package_name, &type, &entry)) { (void)fallback_package; return 0u; } if (entry.empty()) { return 0u; } if (package_name.empty()) { package_name = fallback_package; } if (type.empty()) { type = fallback_type; } std::u16string type16; if (!Utf8ToUtf16(type, &type16)) { return 0u; } std::u16string entry16; if (!Utf8ToUtf16(entry, &entry16)) { return 0u; } const StringPiece16 kAttr16 = u"attr"; const static std::u16string kAttrPrivate16 = u"^attr-private"; for (const PackageGroup& package_group : package_groups_) { for (const LoadedPackage* package : package_group.packages_) { if (package_name != package->GetPackageName()) { // All packages in the same group are expected to have the same package name. break; } uint32_t resid = package->FindEntryByName(type16, entry16); if (resid == 0u && kAttr16 == type16) { // Private attributes in libraries (such as the framework) are sometimes encoded // under the type '^attr-private' in order to leave the ID space of public 'attr' // free for future additions. Check '^attr-private' for the same name. resid = package->FindEntryByName(kAttrPrivate16, entry16); } if (resid != 0u) { return fix_package_id(resid, package_group.dynamic_ref_table.mAssignedPackageId); } } } return 0u; return 0u; } } Loading Loading @@ -619,15 +680,15 @@ bool Theme::ApplyStyle(uint32_t resid, bool force) { // If the resource ID passed in is not a style, the key can be // If the resource ID passed in is not a style, the key can be // some other identifier that is not a resource ID. // some other identifier that is not a resource ID. if (!util::is_valid_resid(attr_resid)) { if (!is_valid_resid(attr_resid)) { return false; return false; } } const uint32_t package_idx = util::get_package_id(attr_resid); const uint32_t package_idx = get_package_id(attr_resid); // The type ID is 1-based, so subtract 1 to get an index. // The type ID is 1-based, so subtract 1 to get an index. const uint32_t type_idx = util::get_type_id(attr_resid) - 1; const uint32_t type_idx = get_type_id(attr_resid) - 1; const uint32_t entry_idx = util::get_entry_id(attr_resid); const uint32_t entry_idx = get_entry_id(attr_resid); std::unique_ptr<Package>& package = packages_[package_idx]; std::unique_ptr<Package>& package = packages_[package_idx]; if (package == nullptr) { if (package == nullptr) { Loading Loading @@ -656,9 +717,9 @@ bool Theme::ApplyStyle(uint32_t resid, bool force) { // and populate the structures. // and populate the structures. for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) { for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) { const uint32_t attr_resid = bag_iter->key; const uint32_t attr_resid = bag_iter->key; const uint32_t package_idx = util::get_package_id(attr_resid); const uint32_t package_idx = get_package_id(attr_resid); const uint32_t type_idx = util::get_type_id(attr_resid) - 1; const uint32_t type_idx = get_type_id(attr_resid) - 1; const uint32_t entry_idx = util::get_entry_id(attr_resid); const uint32_t entry_idx = get_entry_id(attr_resid); Package* package = packages_[package_idx].get(); Package* package = packages_[package_idx].get(); util::unique_cptr<Type>& type = package->types[type_idx]; util::unique_cptr<Type>& type = package->types[type_idx]; if (type->entry_count != type->entry_capacity) { if (type->entry_count != type->entry_capacity) { Loading Loading @@ -691,15 +752,15 @@ ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value, uint32_t type_spec_flags = 0u; uint32_t type_spec_flags = 0u; for (int iterations_left = kMaxIterations; iterations_left > 0; iterations_left--) { for (int iterations_left = kMaxIterations; iterations_left > 0; iterations_left--) { if (!util::is_valid_resid(resid)) { if (!is_valid_resid(resid)) { return kInvalidCookie; return kInvalidCookie; } } const uint32_t package_idx = util::get_package_id(resid); const uint32_t package_idx = get_package_id(resid); // Type ID is 1-based, subtract 1 to get the index. // Type ID is 1-based, subtract 1 to get the index. const uint32_t type_idx = util::get_type_id(resid) - 1; const uint32_t type_idx = get_type_id(resid) - 1; const uint32_t entry_idx = util::get_entry_id(resid); const uint32_t entry_idx = get_entry_id(resid); const Package* package = packages_[package_idx].get(); const Package* package = packages_[package_idx].get(); if (package == nullptr) { if (package == nullptr) { Loading libs/androidfw/LoadedArsc.cpp +44 −4 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include "androidfw/ByteBucketArray.h" #include "androidfw/ByteBucketArray.h" #include "androidfw/Chunk.h" #include "androidfw/Chunk.h" #include "androidfw/ResourceUtils.h" #include "androidfw/Util.h" #include "androidfw/Util.h" using android::base::StringPrintf; using android::base::StringPrintf; Loading Loading @@ -181,9 +182,9 @@ bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config, LoadedArscEntry* out_entry, ResTable_config* out_selected_config, LoadedArscEntry* out_entry, ResTable_config* out_selected_config, uint32_t* out_flags) const { uint32_t* out_flags) const { ATRACE_CALL(); ATRACE_CALL(); const uint8_t package_id = util::get_package_id(resid); const uint8_t package_id = get_package_id(resid); const uint8_t type_id = util::get_type_id(resid); const uint8_t type_id = get_type_id(resid); const uint16_t entry_id = util::get_entry_id(resid); const uint16_t entry_id = get_entry_id(resid); if (type_id == 0) { if (type_id == 0) { LOG(ERROR) << "Invalid ID 0x" << std::hex << resid << std::dec << "."; LOG(ERROR) << "Invalid ID 0x" << std::hex << resid << std::dec << "."; Loading @@ -200,7 +201,7 @@ bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config, } } const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const { const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const { const uint8_t package_id = util::get_package_id(resid); const uint8_t package_id = get_package_id(resid); for (const auto& loaded_package : packages_) { for (const auto& loaded_package : packages_) { if (loaded_package->package_id_ == package_id) { if (loaded_package->package_id_ == package_id) { return loaded_package.get(); return loaded_package.get(); Loading Loading @@ -372,6 +373,45 @@ void LoadedPackage::CollectLocales(bool canonicalize, std::set<std::string>* out } } } } uint32_t LoadedPackage::FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const { ssize_t type_idx = type_string_pool_.indexOfString(type_name.data(), type_name.size()); if (type_idx < 0) { return 0u; } ssize_t key_idx = key_string_pool_.indexOfString(entry_name.data(), entry_name.size()); if (key_idx < 0) { return 0u; } const TypeSpec* type_spec = type_specs_[type_idx].get(); if (type_spec == nullptr) { return 0u; } for (size_t ti = 0; ti < type_spec->type_count; ti++) { const Type* type = &type_spec->types[ti]; size_t entry_count = dtohl(type->type->entryCount); for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) { const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>( reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize)); const uint32_t offset = dtohl(entry_offsets[entry_idx]); if (offset != ResTable_type::NO_ENTRY) { const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type->type) + dtohl(type->type->entriesStart) + offset); if (dtohl(entry->key.index) == static_cast<uint32_t>(key_idx)) { // The package ID will be overridden by the caller (due to runtime assignment of package // IDs for shared libraries). return make_resid(0x00, type_idx + type_id_offset_ + 1, entry_idx); } } } } return 0u; } std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) { std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) { ATRACE_CALL(); ATRACE_CALL(); std::unique_ptr<LoadedPackage> loaded_package{new LoadedPackage()}; std::unique_ptr<LoadedPackage> loaded_package{new LoadedPackage()}; Loading libs/androidfw/ResourceUtils.cpp 0 → 100644 +48 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2017 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 "androidfw/ResourceUtils.h" namespace android { bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type, StringPiece* out_entry) { *out_package = ""; *out_type = ""; bool has_package_separator = false; bool has_type_separator = false; const char* start = str.data(); const char* end = start + str.size(); const char* current = start; while (current != end) { if (out_type->size() == 0 && *current == '/') { has_type_separator = true; out_type->assign(start, current - start); start = current + 1; } else if (out_package->size() == 0 && *current == ':') { has_package_separator = true; out_package->assign(start, current - start); start = current + 1; } current++; } out_entry->assign(start, end - start); return !(has_package_separator && out_package->empty()) && !(has_type_separator && out_type->empty()); } } // namespace android libs/androidfw/include/androidfw/LoadedArsc.h +7 −0 Original line number Original line Diff line number Diff line Loading @@ -101,6 +101,13 @@ class LoadedPackage { // before being inserted into the set. This may cause some equivalent locales to de-dupe. // before being inserted into the set. This may cause some equivalent locales to de-dupe. void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const; void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const; // Finds the entry with the specified type name and entry name. The names are in UTF-16 because // the underlying ResStringPool API expects this. For now this is acceptable, but since // 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; private: private: DISALLOW_COPY_AND_ASSIGN(LoadedPackage); DISALLOW_COPY_AND_ASSIGN(LoadedPackage); Loading Loading
libs/androidfw/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -36,6 +36,7 @@ cc_library { "misc.cpp", "misc.cpp", "ObbFile.cpp", "ObbFile.cpp", "ResourceTypes.cpp", "ResourceTypes.cpp", "ResourceUtils.cpp", "StreamingZipInflater.cpp", "StreamingZipInflater.cpp", "TypeWrappers.cpp", "TypeWrappers.cpp", "Util.cpp", "Util.cpp", Loading
libs/androidfw/AssetManager2.cpp +81 −20 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,8 @@ #endif #endif #endif #endif #include "androidfw/ResourceUtils.h" namespace android { namespace android { AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); } AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); } Loading Loading @@ -235,9 +237,9 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri desired_config = &density_override_config; desired_config = &density_override_config; } } const uint32_t package_id = util::get_package_id(resid); const uint32_t package_id = get_package_id(resid); const uint8_t type_id = util::get_type_id(resid); const uint8_t type_id = get_type_id(resid); const uint16_t entry_id = util::get_entry_id(resid); const uint16_t entry_id = get_entry_id(resid); if (type_id == 0) { if (type_id == 0) { LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid); LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid); Loading Loading @@ -452,7 +454,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { ResolvedBag::Entry* new_entry = new_bag->entries; ResolvedBag::Entry* new_entry = new_bag->entries; for (; map_entry != map_entry_end; ++map_entry) { for (; map_entry != map_entry_end; ++map_entry) { uint32_t new_key = dtohl(map_entry->name.ident); uint32_t new_key = dtohl(map_entry->name.ident); if (!util::is_internal_resid(new_key)) { if (!is_internal_resid(new_key)) { // Attributes, arrays, etc don't have a resource id as the name. They specify // Attributes, arrays, etc don't have a resource id as the name. They specify // other data, which would be wrong to change via a lookup. // other data, which would be wrong to change via a lookup. if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) { if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) { Loading Loading @@ -501,7 +503,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { // The keys are expected to be in sorted order. Merge the two bags. // The keys are expected to be in sorted order. Merge the two bags. while (map_entry != map_entry_end && parent_entry != parent_entry_end) { while (map_entry != map_entry_end && parent_entry != parent_entry_end) { uint32_t child_key = dtohl(map_entry->name.ident); uint32_t child_key = dtohl(map_entry->name.ident); if (!util::is_internal_resid(child_key)) { if (!is_internal_resid(child_key)) { if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) { if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) { LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key, resid); LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key, resid); return nullptr; return nullptr; Loading Loading @@ -533,7 +535,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { // Finish the child entries if they exist. // Finish the child entries if they exist. while (map_entry != map_entry_end) { while (map_entry != map_entry_end) { uint32_t new_key = dtohl(map_entry->name.ident); uint32_t new_key = dtohl(map_entry->name.ident); if (!util::is_internal_resid(new_key)) { if (!is_internal_resid(new_key)) { if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) { if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) { LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid); LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid); return nullptr; return nullptr; Loading Loading @@ -571,12 +573,71 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { return result; return result; } } static bool Utf8ToUtf16(const StringPiece& str, std::u16string* out) { ssize_t len = utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str.data()), str.size(), false); if (len < 0) { return false; } out->resize(static_cast<size_t>(len)); utf8_to_utf16(reinterpret_cast<const uint8_t*>(str.data()), str.size(), &*out->begin(), static_cast<size_t>(len + 1)); return true; } uint32_t AssetManager2::GetResourceId(const std::string& resource_name, uint32_t AssetManager2::GetResourceId(const std::string& resource_name, const std::string& fallback_type, const std::string& fallback_type, const std::string& fallback_package) { const std::string& fallback_package) { (void)resource_name; StringPiece package_name, type, entry; (void)fallback_type; if (!ExtractResourceName(resource_name, &package_name, &type, &entry)) { (void)fallback_package; return 0u; } if (entry.empty()) { return 0u; } if (package_name.empty()) { package_name = fallback_package; } if (type.empty()) { type = fallback_type; } std::u16string type16; if (!Utf8ToUtf16(type, &type16)) { return 0u; } std::u16string entry16; if (!Utf8ToUtf16(entry, &entry16)) { return 0u; } const StringPiece16 kAttr16 = u"attr"; const static std::u16string kAttrPrivate16 = u"^attr-private"; for (const PackageGroup& package_group : package_groups_) { for (const LoadedPackage* package : package_group.packages_) { if (package_name != package->GetPackageName()) { // All packages in the same group are expected to have the same package name. break; } uint32_t resid = package->FindEntryByName(type16, entry16); if (resid == 0u && kAttr16 == type16) { // Private attributes in libraries (such as the framework) are sometimes encoded // under the type '^attr-private' in order to leave the ID space of public 'attr' // free for future additions. Check '^attr-private' for the same name. resid = package->FindEntryByName(kAttrPrivate16, entry16); } if (resid != 0u) { return fix_package_id(resid, package_group.dynamic_ref_table.mAssignedPackageId); } } } return 0u; return 0u; } } Loading Loading @@ -619,15 +680,15 @@ bool Theme::ApplyStyle(uint32_t resid, bool force) { // If the resource ID passed in is not a style, the key can be // If the resource ID passed in is not a style, the key can be // some other identifier that is not a resource ID. // some other identifier that is not a resource ID. if (!util::is_valid_resid(attr_resid)) { if (!is_valid_resid(attr_resid)) { return false; return false; } } const uint32_t package_idx = util::get_package_id(attr_resid); const uint32_t package_idx = get_package_id(attr_resid); // The type ID is 1-based, so subtract 1 to get an index. // The type ID is 1-based, so subtract 1 to get an index. const uint32_t type_idx = util::get_type_id(attr_resid) - 1; const uint32_t type_idx = get_type_id(attr_resid) - 1; const uint32_t entry_idx = util::get_entry_id(attr_resid); const uint32_t entry_idx = get_entry_id(attr_resid); std::unique_ptr<Package>& package = packages_[package_idx]; std::unique_ptr<Package>& package = packages_[package_idx]; if (package == nullptr) { if (package == nullptr) { Loading Loading @@ -656,9 +717,9 @@ bool Theme::ApplyStyle(uint32_t resid, bool force) { // and populate the structures. // and populate the structures. for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) { for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) { const uint32_t attr_resid = bag_iter->key; const uint32_t attr_resid = bag_iter->key; const uint32_t package_idx = util::get_package_id(attr_resid); const uint32_t package_idx = get_package_id(attr_resid); const uint32_t type_idx = util::get_type_id(attr_resid) - 1; const uint32_t type_idx = get_type_id(attr_resid) - 1; const uint32_t entry_idx = util::get_entry_id(attr_resid); const uint32_t entry_idx = get_entry_id(attr_resid); Package* package = packages_[package_idx].get(); Package* package = packages_[package_idx].get(); util::unique_cptr<Type>& type = package->types[type_idx]; util::unique_cptr<Type>& type = package->types[type_idx]; if (type->entry_count != type->entry_capacity) { if (type->entry_count != type->entry_capacity) { Loading Loading @@ -691,15 +752,15 @@ ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value, uint32_t type_spec_flags = 0u; uint32_t type_spec_flags = 0u; for (int iterations_left = kMaxIterations; iterations_left > 0; iterations_left--) { for (int iterations_left = kMaxIterations; iterations_left > 0; iterations_left--) { if (!util::is_valid_resid(resid)) { if (!is_valid_resid(resid)) { return kInvalidCookie; return kInvalidCookie; } } const uint32_t package_idx = util::get_package_id(resid); const uint32_t package_idx = get_package_id(resid); // Type ID is 1-based, subtract 1 to get the index. // Type ID is 1-based, subtract 1 to get the index. const uint32_t type_idx = util::get_type_id(resid) - 1; const uint32_t type_idx = get_type_id(resid) - 1; const uint32_t entry_idx = util::get_entry_id(resid); const uint32_t entry_idx = get_entry_id(resid); const Package* package = packages_[package_idx].get(); const Package* package = packages_[package_idx].get(); if (package == nullptr) { if (package == nullptr) { Loading
libs/androidfw/LoadedArsc.cpp +44 −4 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include "androidfw/ByteBucketArray.h" #include "androidfw/ByteBucketArray.h" #include "androidfw/Chunk.h" #include "androidfw/Chunk.h" #include "androidfw/ResourceUtils.h" #include "androidfw/Util.h" #include "androidfw/Util.h" using android::base::StringPrintf; using android::base::StringPrintf; Loading Loading @@ -181,9 +182,9 @@ bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config, LoadedArscEntry* out_entry, ResTable_config* out_selected_config, LoadedArscEntry* out_entry, ResTable_config* out_selected_config, uint32_t* out_flags) const { uint32_t* out_flags) const { ATRACE_CALL(); ATRACE_CALL(); const uint8_t package_id = util::get_package_id(resid); const uint8_t package_id = get_package_id(resid); const uint8_t type_id = util::get_type_id(resid); const uint8_t type_id = get_type_id(resid); const uint16_t entry_id = util::get_entry_id(resid); const uint16_t entry_id = get_entry_id(resid); if (type_id == 0) { if (type_id == 0) { LOG(ERROR) << "Invalid ID 0x" << std::hex << resid << std::dec << "."; LOG(ERROR) << "Invalid ID 0x" << std::hex << resid << std::dec << "."; Loading @@ -200,7 +201,7 @@ bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config, } } const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const { const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const { const uint8_t package_id = util::get_package_id(resid); const uint8_t package_id = get_package_id(resid); for (const auto& loaded_package : packages_) { for (const auto& loaded_package : packages_) { if (loaded_package->package_id_ == package_id) { if (loaded_package->package_id_ == package_id) { return loaded_package.get(); return loaded_package.get(); Loading Loading @@ -372,6 +373,45 @@ void LoadedPackage::CollectLocales(bool canonicalize, std::set<std::string>* out } } } } uint32_t LoadedPackage::FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const { ssize_t type_idx = type_string_pool_.indexOfString(type_name.data(), type_name.size()); if (type_idx < 0) { return 0u; } ssize_t key_idx = key_string_pool_.indexOfString(entry_name.data(), entry_name.size()); if (key_idx < 0) { return 0u; } const TypeSpec* type_spec = type_specs_[type_idx].get(); if (type_spec == nullptr) { return 0u; } for (size_t ti = 0; ti < type_spec->type_count; ti++) { const Type* type = &type_spec->types[ti]; size_t entry_count = dtohl(type->type->entryCount); for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) { const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>( reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize)); const uint32_t offset = dtohl(entry_offsets[entry_idx]); if (offset != ResTable_type::NO_ENTRY) { const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type->type) + dtohl(type->type->entriesStart) + offset); if (dtohl(entry->key.index) == static_cast<uint32_t>(key_idx)) { // The package ID will be overridden by the caller (due to runtime assignment of package // IDs for shared libraries). return make_resid(0x00, type_idx + type_id_offset_ + 1, entry_idx); } } } } return 0u; } std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) { std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) { ATRACE_CALL(); ATRACE_CALL(); std::unique_ptr<LoadedPackage> loaded_package{new LoadedPackage()}; std::unique_ptr<LoadedPackage> loaded_package{new LoadedPackage()}; Loading
libs/androidfw/ResourceUtils.cpp 0 → 100644 +48 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2017 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 "androidfw/ResourceUtils.h" namespace android { bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type, StringPiece* out_entry) { *out_package = ""; *out_type = ""; bool has_package_separator = false; bool has_type_separator = false; const char* start = str.data(); const char* end = start + str.size(); const char* current = start; while (current != end) { if (out_type->size() == 0 && *current == '/') { has_type_separator = true; out_type->assign(start, current - start); start = current + 1; } else if (out_package->size() == 0 && *current == ':') { has_package_separator = true; out_package->assign(start, current - start); start = current + 1; } current++; } out_entry->assign(start, end - start); return !(has_package_separator && out_package->empty()) && !(has_type_separator && out_type->empty()); } } // namespace android
libs/androidfw/include/androidfw/LoadedArsc.h +7 −0 Original line number Original line Diff line number Diff line Loading @@ -101,6 +101,13 @@ class LoadedPackage { // before being inserted into the set. This may cause some equivalent locales to de-dupe. // before being inserted into the set. This may cause some equivalent locales to de-dupe. void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const; void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const; // Finds the entry with the specified type name and entry name. The names are in UTF-16 because // the underlying ResStringPool API expects this. For now this is acceptable, but since // 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; private: private: DISALLOW_COPY_AND_ASSIGN(LoadedPackage); DISALLOW_COPY_AND_ASSIGN(LoadedPackage); Loading