diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp index a65d49b7e32fe..1d2c597c4c8c7 100644 --- a/libs/androidfw/LoadedArsc.cpp +++ b/libs/androidfw/LoadedArsc.cpp @@ -409,10 +409,14 @@ std::unique_ptr LoadedPackage::Load(const Chunk& chunk, util::ReadUtf16StringFromDevice(header->name, arraysize(header->name), &loaded_package->package_name_); - // A map of TypeSpec builders, each associated with an type index. - // We use these to accumulate the set of Types available for a TypeSpec, and later build a single, - // contiguous block of memory that holds all the Types together with the TypeSpec. - std::unordered_map> type_builder_map; + // A TypeSpec builder. We use this to accumulate the set of Types + // available for a TypeSpec, and later build a single, contiguous block + // of memory that holds all the Types together with the TypeSpec. + std::unique_ptr types_builder; + + // Keep track of the last seen type index. Since type IDs are 1-based, + // this records their index, which is 0-based (type ID - 1). + uint8_t last_type_idx = 0; ChunkIterator iter(chunk.data_ptr(), chunk.data_size()); while (iter.HasNext()) { @@ -446,6 +450,28 @@ std::unique_ptr LoadedPackage::Load(const Chunk& chunk, case RES_TABLE_TYPE_SPEC_TYPE: { ATRACE_NAME("LoadTableTypeSpec"); + // Starting a new TypeSpec, so finish the old one if there was one. + if (types_builder) { + TypeSpecPtr type_spec_ptr = types_builder->Build(); + if (type_spec_ptr == nullptr) { + LOG(ERROR) << "Too many type configurations, overflow detected."; + return {}; + } + + // We only add the type to the package if there is no IDMAP, or if the type is + // overlaying something. + if (loaded_idmap == nullptr || type_spec_ptr->idmap_entries != nullptr) { + // If this is an overlay, insert it at the target type ID. + if (type_spec_ptr->idmap_entries != nullptr) { + last_type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1; + } + loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr); + } + + types_builder = {}; + last_type_idx = 0; + } + const ResTable_typeSpec* type_spec = child_chunk.header(); if (type_spec == nullptr) { LOG(ERROR) << "RES_TABLE_TYPE_SPEC_TYPE too small."; @@ -480,6 +506,8 @@ std::unique_ptr LoadedPackage::Load(const Chunk& chunk, return {}; } + last_type_idx = type_spec->id - 1; + // If this is an overlay, associate the mapping of this type to the target type // from the IDMAP. const IdmapEntry_header* idmap_entry_header = nullptr; @@ -487,13 +515,7 @@ std::unique_ptr LoadedPackage::Load(const Chunk& chunk, idmap_entry_header = loaded_idmap->GetEntryMapForType(type_spec->id); } - std::unique_ptr& builder_ptr = type_builder_map[type_spec->id - 1]; - if (builder_ptr == nullptr) { - builder_ptr = util::make_unique(type_spec, idmap_entry_header); - } else { - LOG(WARNING) << StringPrintf("RES_TABLE_TYPE_SPEC_TYPE already defined for ID %02x", - type_spec->id); - } + types_builder = util::make_unique(type_spec, idmap_entry_header); } break; case RES_TABLE_TYPE_TYPE: { @@ -508,15 +530,12 @@ std::unique_ptr LoadedPackage::Load(const Chunk& chunk, } // Type chunks must be preceded by their TypeSpec chunks. - std::unique_ptr& builder_ptr = type_builder_map[type->id - 1]; - if (builder_ptr != nullptr) { - builder_ptr->AddType(type); - } else { - LOG(ERROR) << StringPrintf( - "RES_TABLE_TYPE_TYPE with ID %02x found without preceding RES_TABLE_TYPE_SPEC_TYPE.", - type->id); + if (!types_builder || type->id - 1 != last_type_idx) { + LOG(ERROR) << "RES_TABLE_TYPE_TYPE found without preceding RES_TABLE_TYPE_SPEC_TYPE."; return {}; } + + types_builder->AddType(type); } break; case RES_TABLE_LIBRARY_TYPE: { @@ -542,7 +561,7 @@ std::unique_ptr LoadedPackage::Load(const Chunk& chunk, arraysize(entry_iter->packageName), &package_name); if (dtohl(entry_iter->packageId) >= std::numeric_limits::max()) { - LOG(ERROR) << StringPrintf( + LOG(ERROR) << base::StringPrintf( "Package ID %02x in RES_TABLE_LIBRARY_TYPE too large for package '%s'.", dtohl(entry_iter->packageId), package_name.c_str()); return {}; @@ -555,20 +574,14 @@ std::unique_ptr LoadedPackage::Load(const Chunk& chunk, } break; default: - LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type()); + LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type()); break; } } - if (iter.HadError()) { - LOG(ERROR) << iter.GetLastError(); - return {}; - } - - // Flatten and construct the TypeSpecs. - for (auto& entry : type_builder_map) { - uint8_t type_idx = static_cast(entry.first); - TypeSpecPtr type_spec_ptr = entry.second->Build(); + // Finish the last TypeSpec. + if (types_builder) { + TypeSpecPtr type_spec_ptr = types_builder->Build(); if (type_spec_ptr == nullptr) { LOG(ERROR) << "Too many type configurations, overflow detected."; return {}; @@ -579,15 +592,20 @@ std::unique_ptr LoadedPackage::Load(const Chunk& chunk, if (loaded_idmap == nullptr || type_spec_ptr->idmap_entries != nullptr) { // If this is an overlay, insert it at the target type ID. if (type_spec_ptr->idmap_entries != nullptr) { - type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1; + last_type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1; } - loaded_package->type_specs_.editItemAt(type_idx) = std::move(type_spec_ptr); + loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr); } } + if (iter.HadError()) { + LOG(ERROR) << iter.GetLastError(); + return {}; + } return std::move(loaded_package); } + bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap, bool load_as_shared_library) { ATRACE_CALL(); @@ -637,7 +655,7 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap, } break; default: - LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type()); + LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type()); break; } } @@ -669,7 +687,7 @@ std::unique_ptr LoadedArsc::Load(const StringPiece& data, break; default: - LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type()); + LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type()); break; } } diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp index cae632ddea300..bedebd66cb2f0 100644 --- a/libs/androidfw/tests/LoadedArsc_test.cpp +++ b/libs/androidfw/tests/LoadedArsc_test.cpp @@ -16,7 +16,6 @@ #include "androidfw/LoadedArsc.h" -#include "android-base/file.h" #include "androidfw/ResourceUtils.h" #include "TestHelpers.h" @@ -30,7 +29,6 @@ namespace basic = com::android::basic; namespace libclient = com::android::libclient; namespace sparse = com::android::sparse; -using ::android::base::ReadFileToString; using ::testing::Eq; using ::testing::Ge; using ::testing::IsNull; @@ -179,46 +177,6 @@ TEST(LoadedArscTest, LoadFeatureSplit) { ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], entry_index), NotNull()); } -// AAPT(2) generates resource tables with chunks in a certain order. The rule is that -// a RES_TABLE_TYPE_TYPE with id `i` must always be preceded by a RES_TABLE_TYPE_SPEC_TYPE with -// id `i`. The RES_TABLE_TYPE_SPEC_TYPE does not need to be directly preceding, however. -// -// AAPT(2) generates something like: -// RES_TABLE_TYPE_SPEC_TYPE id=1 -// RES_TABLE_TYPE_TYPE id=1 -// RES_TABLE_TYPE_SPEC_TYPE id=2 -// RES_TABLE_TYPE_TYPE id=2 -// -// But the following is valid too: -// RES_TABLE_TYPE_SPEC_TYPE id=1 -// RES_TABLE_TYPE_SPEC_TYPE id=2 -// RES_TABLE_TYPE_TYPE id=1 -// RES_TABLE_TYPE_TYPE id=2 -// -TEST(LoadedArscTest, LoadOutOfOrderTypeSpecs) { - std::string contents; - ASSERT_TRUE( - ReadFileFromZipToString(GetTestDataPath() + "/out_of_order_types/out_of_order_types.apk", - "resources.arsc", &contents)); - - std::unique_ptr loaded_arsc = LoadedArsc::Load(StringPiece(contents)); - ASSERT_THAT(loaded_arsc, NotNull()); - - ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u)); - const auto& package = loaded_arsc->GetPackages()[0]; - ASSERT_THAT(package, NotNull()); - - const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0); - ASSERT_THAT(type_spec, NotNull()); - ASSERT_THAT(type_spec->type_count, Ge(1u)); - ASSERT_THAT(type_spec->types[0], NotNull()); - - type_spec = package->GetTypeSpecByTypeIndex(1); - ASSERT_THAT(type_spec, NotNull()); - ASSERT_THAT(type_spec->type_count, Ge(1u)); - ASSERT_THAT(type_spec->types[0], NotNull()); -} - class MockLoadedIdmap : public LoadedIdmap { public: MockLoadedIdmap() : LoadedIdmap() { diff --git a/libs/androidfw/tests/data/out_of_order_types/AndroidManifest.xml b/libs/androidfw/tests/data/out_of_order_types/AndroidManifest.xml deleted file mode 100644 index 34016db8b8082..0000000000000 --- a/libs/androidfw/tests/data/out_of_order_types/AndroidManifest.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - diff --git a/libs/androidfw/tests/data/out_of_order_types/build b/libs/androidfw/tests/data/out_of_order_types/build deleted file mode 100755 index 8496f81038b0c..0000000000000 --- a/libs/androidfw/tests/data/out_of_order_types/build +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2018 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. -# - -set -e - -aapt2 compile --dir res -o compiled.flata -aapt2 link --manifest AndroidManifest.xml -o out_of_order_types.apk compiled.flata -rm compiled.flata diff --git a/libs/androidfw/tests/data/out_of_order_types/edited_resources.arsc.txt b/libs/androidfw/tests/data/out_of_order_types/edited_resources.arsc.txt deleted file mode 100644 index eca8f478c5012..0000000000000 --- a/libs/androidfw/tests/data/out_of_order_types/edited_resources.arsc.txt +++ /dev/null @@ -1,43 +0,0 @@ -00000000: 0200 0c00 ac02 0000 0100 0000 0100 1c00 ................ -00000010: 1c00 0000 0000 0000 0000 0000 0001 0000 ................ -00000020: 1c00 0000 0000 0000 0002 2001 8402 0000 .......... ..... -00000030: 7f00 0000 6300 6f00 6d00 2e00 6100 6e00 ....c.o.m...a.n. -00000040: 6400 7200 6f00 6900 6400 2e00 6100 7000 d.r.o.i.d...a.p. -00000050: 7000 0000 0000 0000 0000 0000 0000 0000 p............... -00000060: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -00000080: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -00000090: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -000000b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -000000c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -000000d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -000000e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -000000f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -00000100: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -00000110: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -00000120: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -00000130: 0000 0000 2001 0000 0000 0000 6401 0000 .... .......d... -00000140: 0000 0000 0000 0000 0100 1c00 4400 0000 ............D... -00000150: 0200 0000 0000 0000 0000 0000 2400 0000 ............$... -00000160: 0000 0000 0000 0000 0c00 0000 0400 6200 ..............b. -00000170: 6f00 6f00 6c00 0000 0700 6900 6e00 7400 o.o.l.....i.n.t. -00000180: 6500 6700 6500 7200 0000 0000 0100 1c00 e.g.e.r......... -00000190: 2800 0000 0100 0000 0000 0000 0001 0000 (............... -000001a0: 2000 0000 0000 0000 0000 0000 0404 7465 .............te -000001b0: 7374 0000 0202 1000 1400 0000 0100 0000 st.............. -000001c0: 0100 0000 0000 0000 0202 1000 1400 0000 -000001d0: 0200 0000 0100 0000 0000 0000 0102 5400 -000001e0: 6800 0000 0100 0000 0100 0000 5800 0000 -000001f0: 4000 0000 0000 0000 0000 0000 0000 0000 -00000200: 0000 0000 0000 0000 0000 0000 0000 0000 -00000210: 0000 0000 0000 0000 0000 0000 0000 0000 -00000220: 0000 0000 0000 0000 0000 0000 0000 0000 -00000230: 0000 0000 0800 0000 0000 0000 0800 0012 -00000240: ffff ffff 0102 5400 6800 0000 0200 0000 ......T.h....... -00000250: 0100 0000 5800 0000 4000 0000 0000 0000 ....X...@....... -00000260: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -00000270: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -00000280: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -00000290: 0000 0000 0000 0000 0000 0000 0800 0000 ................ -000002a0: 0000 0000 0800 0010 0100 0000 ............ diff --git a/libs/androidfw/tests/data/out_of_order_types/out_of_order_types.apk b/libs/androidfw/tests/data/out_of_order_types/out_of_order_types.apk deleted file mode 100644 index 75146e0fc4762..0000000000000 Binary files a/libs/androidfw/tests/data/out_of_order_types/out_of_order_types.apk and /dev/null differ diff --git a/libs/androidfw/tests/data/out_of_order_types/res/values/values.xml b/libs/androidfw/tests/data/out_of_order_types/res/values/values.xml deleted file mode 100644 index 7c54fbae9f210..0000000000000 --- a/libs/androidfw/tests/data/out_of_order_types/res/values/values.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - true - 1 -