Loading libs/androidfw/LoadedArsc.cpp +66 −20 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "androidfw/LoadedArsc.h" #include <algorithm> #include <cstddef> #include <limits> Loading Loading @@ -244,31 +245,63 @@ bool LoadedPackage::FindEntry(const TypeSpecPtr& type_spec_ptr, uint16_t entry_i for (uint32_t i = 0; i < type_spec_ptr->type_count; i++) { const Type* type = &type_spec_ptr->types[i]; const ResTable_type* type_chunk = type->type; if (type->configuration.match(config) && (best_config == nullptr || type->configuration.isBetterThan(*best_config, &config))) { // The configuration matches and is better than the previous selection. // Find the entry value if it exists for this configuration. const size_t entry_count = dtohl(type->type->entryCount); const size_t offsets_offset = dtohs(type->type->header.headerSize); if (entry_idx < entry_count) { const size_t entry_count = dtohl(type_chunk->entryCount); const size_t offsets_offset = dtohs(type_chunk->header.headerSize); // If the package hasn't been verified, do bounds checking. if (!Verified) { if (!VerifyResTableType(type->type)) { if (!VerifyResTableType(type_chunk)) { continue; } } // Check if there is the desired entry in this type. if (type_chunk->flags & ResTable_type::FLAG_SPARSE) { // This is encoded as a sparse map, so perform a binary search. const ResTable_sparseTypeEntry* sparse_indices = reinterpret_cast<const ResTable_sparseTypeEntry*>( reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset); const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count; const ResTable_sparseTypeEntry* result = std::lower_bound(sparse_indices, sparse_indices_end, entry_idx, [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) { return dtohs(entry.idx) < entry_idx; }); if (result == sparse_indices_end || dtohs(result->idx) != entry_idx) { // No entry found. continue; } // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as // the real offset divided by 4. best_offset = dtohs(result->offset) * 4u; } else { if (entry_idx >= entry_count) { // This entry cannot be here. continue; } const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>( reinterpret_cast<const uint8_t*>(type->type) + offsets_offset); reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset); const uint32_t offset = dtohl(entry_offsets[entry_idx]); if (offset != ResTable_type::NO_ENTRY) { if (offset == ResTable_type::NO_ENTRY) { continue; } // There is an entry for this resource, record it. best_config = &type->configuration; best_type = type->type; best_offset = offset; } } best_config = &type->configuration; best_type = type_chunk; } } Loading Loading @@ -335,9 +368,21 @@ static bool VerifyType(const Chunk& chunk) { const size_t entry_count = dtohl(header->entryCount); const size_t offsets_offset = chunk.header_size(); if (header->flags & ResTable_type::FLAG_SPARSE) { // This is encoded as a sparse map, so perform a binary search. const ResTable_sparseTypeEntry* sparse_indices = reinterpret_cast<const ResTable_sparseTypeEntry*>(reinterpret_cast<const uint8_t*>(header) + offsets_offset); for (size_t i = 0; i < entry_count; i++) { const uint32_t offset = uint32_t{dtohs(sparse_indices[i].offset)} * 4u; if (!VerifyResTableEntry(header, offset, i)) { return false; } } } else { // Check each entry offset. const uint32_t* offsets = reinterpret_cast<const uint32_t*>(reinterpret_cast<const uint8_t*>(header) + offsets_offset); const uint32_t* offsets = reinterpret_cast<const uint32_t*>( reinterpret_cast<const uint8_t*>(header) + offsets_offset); for (size_t i = 0; i < entry_count; i++) { uint32_t offset = dtohl(offsets[i]); if (offset != ResTable_type::NO_ENTRY) { Loading @@ -346,6 +391,7 @@ static bool VerifyType(const Chunk& chunk) { } } } } return true; } Loading libs/androidfw/tests/AssetManager2_bench.cpp +0 −31 Original line number Diff line number Diff line Loading @@ -83,37 +83,6 @@ static void BM_AssetManagerLoadFrameworkAssetsOld(benchmark::State& state) { } BENCHMARK(BM_AssetManagerLoadFrameworkAssetsOld); static void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_config* config, uint32_t resid, benchmark::State& state) { std::vector<std::unique_ptr<const ApkAssets>> apk_assets; std::vector<const ApkAssets*> apk_assets_ptrs; for (const std::string& path : paths) { std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path); if (apk == nullptr) { state.SkipWithError(base::StringPrintf("Failed to load assets %s", path.c_str()).c_str()); return; } apk_assets_ptrs.push_back(apk.get()); apk_assets.push_back(std::move(apk)); } AssetManager2 assetmanager; assetmanager.SetApkAssets(apk_assets_ptrs); if (config != nullptr) { assetmanager.SetConfiguration(*config); } Res_value value; ResTable_config selected_config; uint32_t flags; while (state.KeepRunning()) { assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value, &selected_config, &flags); } } static void BM_AssetManagerGetResource(benchmark::State& state) { GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, basic::R::integer::number1, state); Loading libs/androidfw/tests/BenchmarkHelpers.cpp +31 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "android-base/stringprintf.h" #include "androidfw/AssetManager.h" #include "androidfw/AssetManager2.h" namespace android { Loading Loading @@ -48,4 +49,34 @@ void GetResourceBenchmarkOld(const std::vector<std::string>& paths, const ResTab } } void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_config* config, uint32_t resid, benchmark::State& state) { std::vector<std::unique_ptr<const ApkAssets>> apk_assets; std::vector<const ApkAssets*> apk_assets_ptrs; for (const std::string& path : paths) { std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path); if (apk == nullptr) { state.SkipWithError(base::StringPrintf("Failed to load assets %s", path.c_str()).c_str()); return; } apk_assets_ptrs.push_back(apk.get()); apk_assets.push_back(std::move(apk)); } AssetManager2 assetmanager; assetmanager.SetApkAssets(apk_assets_ptrs); if (config != nullptr) { assetmanager.SetConfiguration(*config); } Res_value value; ResTable_config selected_config; uint32_t flags; while (state.KeepRunning()) { assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value, &selected_config, &flags); } } } // namespace android libs/androidfw/tests/BenchmarkHelpers.h +3 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,9 @@ namespace android { void GetResourceBenchmarkOld(const std::vector<std::string>& paths, const ResTable_config* config, uint32_t resid, ::benchmark::State& state); void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_config* config, uint32_t resid, benchmark::State& state); } // namespace android #endif // ANDROIDFW_TESTS_BENCHMARKHELPERS_H libs/androidfw/tests/LoadedArsc_test.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -19,11 +19,13 @@ #include "TestHelpers.h" #include "data/basic/R.h" #include "data/libclient/R.h" #include "data/sparse/R.h" #include "data/styles/R.h" namespace app = com::android::app; namespace basic = com::android::basic; namespace libclient = com::android::libclient; namespace sparse = com::android::sparse; namespace android { Loading Loading @@ -68,6 +70,23 @@ TEST(LoadedArscTest, FindDefaultEntry) { ASSERT_NE(nullptr, entry.entry); } TEST(LoadedArscTest, LoadSparseEntryApp) { std::string contents; ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc", &contents)); std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents)); ASSERT_NE(nullptr, loaded_arsc); ResTable_config config; memset(&config, 0, sizeof(config)); config.sdkVersion = 26; FindEntryResult entry; ASSERT_TRUE(loaded_arsc->FindEntry(sparse::R::integer::foo_9, config, &entry)); ASSERT_NE(nullptr, entry.entry); } TEST(LoadedArscTest, LoadSharedLibrary) { std::string contents; ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc", Loading Loading
libs/androidfw/LoadedArsc.cpp +66 −20 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "androidfw/LoadedArsc.h" #include <algorithm> #include <cstddef> #include <limits> Loading Loading @@ -244,31 +245,63 @@ bool LoadedPackage::FindEntry(const TypeSpecPtr& type_spec_ptr, uint16_t entry_i for (uint32_t i = 0; i < type_spec_ptr->type_count; i++) { const Type* type = &type_spec_ptr->types[i]; const ResTable_type* type_chunk = type->type; if (type->configuration.match(config) && (best_config == nullptr || type->configuration.isBetterThan(*best_config, &config))) { // The configuration matches and is better than the previous selection. // Find the entry value if it exists for this configuration. const size_t entry_count = dtohl(type->type->entryCount); const size_t offsets_offset = dtohs(type->type->header.headerSize); if (entry_idx < entry_count) { const size_t entry_count = dtohl(type_chunk->entryCount); const size_t offsets_offset = dtohs(type_chunk->header.headerSize); // If the package hasn't been verified, do bounds checking. if (!Verified) { if (!VerifyResTableType(type->type)) { if (!VerifyResTableType(type_chunk)) { continue; } } // Check if there is the desired entry in this type. if (type_chunk->flags & ResTable_type::FLAG_SPARSE) { // This is encoded as a sparse map, so perform a binary search. const ResTable_sparseTypeEntry* sparse_indices = reinterpret_cast<const ResTable_sparseTypeEntry*>( reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset); const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count; const ResTable_sparseTypeEntry* result = std::lower_bound(sparse_indices, sparse_indices_end, entry_idx, [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) { return dtohs(entry.idx) < entry_idx; }); if (result == sparse_indices_end || dtohs(result->idx) != entry_idx) { // No entry found. continue; } // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as // the real offset divided by 4. best_offset = dtohs(result->offset) * 4u; } else { if (entry_idx >= entry_count) { // This entry cannot be here. continue; } const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>( reinterpret_cast<const uint8_t*>(type->type) + offsets_offset); reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset); const uint32_t offset = dtohl(entry_offsets[entry_idx]); if (offset != ResTable_type::NO_ENTRY) { if (offset == ResTable_type::NO_ENTRY) { continue; } // There is an entry for this resource, record it. best_config = &type->configuration; best_type = type->type; best_offset = offset; } } best_config = &type->configuration; best_type = type_chunk; } } Loading Loading @@ -335,9 +368,21 @@ static bool VerifyType(const Chunk& chunk) { const size_t entry_count = dtohl(header->entryCount); const size_t offsets_offset = chunk.header_size(); if (header->flags & ResTable_type::FLAG_SPARSE) { // This is encoded as a sparse map, so perform a binary search. const ResTable_sparseTypeEntry* sparse_indices = reinterpret_cast<const ResTable_sparseTypeEntry*>(reinterpret_cast<const uint8_t*>(header) + offsets_offset); for (size_t i = 0; i < entry_count; i++) { const uint32_t offset = uint32_t{dtohs(sparse_indices[i].offset)} * 4u; if (!VerifyResTableEntry(header, offset, i)) { return false; } } } else { // Check each entry offset. const uint32_t* offsets = reinterpret_cast<const uint32_t*>(reinterpret_cast<const uint8_t*>(header) + offsets_offset); const uint32_t* offsets = reinterpret_cast<const uint32_t*>( reinterpret_cast<const uint8_t*>(header) + offsets_offset); for (size_t i = 0; i < entry_count; i++) { uint32_t offset = dtohl(offsets[i]); if (offset != ResTable_type::NO_ENTRY) { Loading @@ -346,6 +391,7 @@ static bool VerifyType(const Chunk& chunk) { } } } } return true; } Loading
libs/androidfw/tests/AssetManager2_bench.cpp +0 −31 Original line number Diff line number Diff line Loading @@ -83,37 +83,6 @@ static void BM_AssetManagerLoadFrameworkAssetsOld(benchmark::State& state) { } BENCHMARK(BM_AssetManagerLoadFrameworkAssetsOld); static void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_config* config, uint32_t resid, benchmark::State& state) { std::vector<std::unique_ptr<const ApkAssets>> apk_assets; std::vector<const ApkAssets*> apk_assets_ptrs; for (const std::string& path : paths) { std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path); if (apk == nullptr) { state.SkipWithError(base::StringPrintf("Failed to load assets %s", path.c_str()).c_str()); return; } apk_assets_ptrs.push_back(apk.get()); apk_assets.push_back(std::move(apk)); } AssetManager2 assetmanager; assetmanager.SetApkAssets(apk_assets_ptrs); if (config != nullptr) { assetmanager.SetConfiguration(*config); } Res_value value; ResTable_config selected_config; uint32_t flags; while (state.KeepRunning()) { assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value, &selected_config, &flags); } } static void BM_AssetManagerGetResource(benchmark::State& state) { GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, basic::R::integer::number1, state); Loading
libs/androidfw/tests/BenchmarkHelpers.cpp +31 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "android-base/stringprintf.h" #include "androidfw/AssetManager.h" #include "androidfw/AssetManager2.h" namespace android { Loading Loading @@ -48,4 +49,34 @@ void GetResourceBenchmarkOld(const std::vector<std::string>& paths, const ResTab } } void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_config* config, uint32_t resid, benchmark::State& state) { std::vector<std::unique_ptr<const ApkAssets>> apk_assets; std::vector<const ApkAssets*> apk_assets_ptrs; for (const std::string& path : paths) { std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path); if (apk == nullptr) { state.SkipWithError(base::StringPrintf("Failed to load assets %s", path.c_str()).c_str()); return; } apk_assets_ptrs.push_back(apk.get()); apk_assets.push_back(std::move(apk)); } AssetManager2 assetmanager; assetmanager.SetApkAssets(apk_assets_ptrs); if (config != nullptr) { assetmanager.SetConfiguration(*config); } Res_value value; ResTable_config selected_config; uint32_t flags; while (state.KeepRunning()) { assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value, &selected_config, &flags); } } } // namespace android
libs/androidfw/tests/BenchmarkHelpers.h +3 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,9 @@ namespace android { void GetResourceBenchmarkOld(const std::vector<std::string>& paths, const ResTable_config* config, uint32_t resid, ::benchmark::State& state); void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_config* config, uint32_t resid, benchmark::State& state); } // namespace android #endif // ANDROIDFW_TESTS_BENCHMARKHELPERS_H
libs/androidfw/tests/LoadedArsc_test.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -19,11 +19,13 @@ #include "TestHelpers.h" #include "data/basic/R.h" #include "data/libclient/R.h" #include "data/sparse/R.h" #include "data/styles/R.h" namespace app = com::android::app; namespace basic = com::android::basic; namespace libclient = com::android::libclient; namespace sparse = com::android::sparse; namespace android { Loading Loading @@ -68,6 +70,23 @@ TEST(LoadedArscTest, FindDefaultEntry) { ASSERT_NE(nullptr, entry.entry); } TEST(LoadedArscTest, LoadSparseEntryApp) { std::string contents; ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc", &contents)); std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents)); ASSERT_NE(nullptr, loaded_arsc); ResTable_config config; memset(&config, 0, sizeof(config)); config.sdkVersion = 26; FindEntryResult entry; ASSERT_TRUE(loaded_arsc->FindEntry(sparse::R::integer::foo_9, config, &entry)); ASSERT_NE(nullptr, entry.entry); } TEST(LoadedArscTest, LoadSharedLibrary) { std::string contents; ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc", Loading