diff options
19 files changed, 281 insertions, 93 deletions
diff --git a/cmds/idmap2/CPPLINT.cfg b/cmds/idmap2/CPPLINT.cfg index 9dc6b4a77380..20ed43c2a76a 100644 --- a/cmds/idmap2/CPPLINT.cfg +++ b/cmds/idmap2/CPPLINT.cfg @@ -15,4 +15,4 @@ set noparent linelength=100 root=.. -filter=+build/include_alpha +filter=+build/include_alpha,-runtime/references,-build/c++ diff --git a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h index 924efe5cfb7b..ff45b1407dea 100644 --- a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h +++ b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h @@ -40,7 +40,8 @@ class BinaryStreamVisitor : public Visitor { void Write8(uint8_t value); void Write16(uint16_t value); void Write32(uint32_t value); - void WriteString(const StringPiece& value); + void WriteString256(const StringPiece& value); + void WriteString(const std::string& value); std::ostream& stream_; }; diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h index 2639c6f470ae..d4a0c3221c20 100644 --- a/cmds/idmap2/include/idmap2/Idmap.h +++ b/cmds/idmap2/include/idmap2/Idmap.h @@ -18,19 +18,21 @@ * # idmap file format (current version) * * idmap := header data* - * header := magic version target_crc overlay_crc target_path overlay_path + * header := magic version target_crc overlay_crc target_path overlay_path debug_info * data := data_header data_block* * data_header := target_package_id types_count * data_block := target_type overlay_type entry_count entry_offset entry* - * overlay_path := string - * target_path := string + * overlay_path := string256 + * target_path := string256 + * debug_info := string + * string := <uint32_t> <uint8_t>+ '\0'+ * entry := <uint32_t> * entry_count := <uint16_t> * entry_offset := <uint16_t> * magic := <uint32_t> * overlay_crc := <uint32_t> * overlay_type := <uint16_t> - * string := <uint8_t>[256] + * string256 := <uint8_t>[256] * target_crc := <uint32_t> * target_package_id := <uint16_t> * target_type := <uint16_t> @@ -41,6 +43,7 @@ * # idmap file format changelog * ## v1 * - Identical to idmap v1. + * * ## v2 * - Entries are no longer separated by type into type specific data blocks. * - Added overlay-indexed target resource id lookup capabilities. @@ -53,6 +56,9 @@ * - Idmap can now encode a type and value to override a resource without needing a table entry. * - A string pool block is included to retrieve the value of strings that do not have a resource * table entry. + * + * ## v3 + * - Add 'debug' block to IdmapHeader. */ #ifndef IDMAP2_INCLUDE_IDMAP2_IDMAP_H_ @@ -116,6 +122,10 @@ class IdmapHeader { return StringPiece(overlay_path_); } + inline const std::string& GetDebugInfo() const { + return debug_info_; + } + // Invariant: anytime the idmap data encoding is changed, the idmap version // field *must* be incremented. Because of this, we know that if the idmap // header is up-to-date the entire file is up-to-date. @@ -133,6 +143,7 @@ class IdmapHeader { uint32_t overlay_crc_; char target_path_[kIdmapStringLength]; char overlay_path_[kIdmapStringLength]; + std::string debug_info_; friend Idmap; DISALLOW_COPY_AND_ASSIGN(IdmapHeader); diff --git a/cmds/idmap2/include/idmap2/LogInfo.h b/cmds/idmap2/include/idmap2/LogInfo.h new file mode 100644 index 000000000000..a6237e6f6ba9 --- /dev/null +++ b/cmds/idmap2/include/idmap2/LogInfo.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 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 IDMAP2_INCLUDE_IDMAP2_LOGINFO_H_ +#define IDMAP2_INCLUDE_IDMAP2_LOGINFO_H_ + +#include <algorithm> +#include <iterator> +#include <sstream> +#include <string> +#include <vector> + +#if __ANDROID__ +#include "android-base/logging.h" +#else +#include <iostream> +#endif + +namespace android::idmap2 { + +class LogMessage { + public: + LogMessage() = default; + + template <typename T> + LogMessage& operator<<(const T& value) { + stream_ << value; + return *this; + } + + std::string GetString() const { + return stream_.str(); + } + + private: + std::stringstream stream_; +}; + +class LogInfo { + public: + LogInfo() = default; + + inline void Info(const LogMessage& msg) { + lines_.push_back("I " + msg.GetString()); + } + + inline void Warning(const LogMessage& msg) { +#ifdef __ANDROID__ + LOG(WARNING) << msg.GetString(); +#else + std::cerr << "W " << msg.GetString() << std::endl; +#endif + lines_.push_back("W " + msg.GetString()); + } + + inline std::string GetString() const { + std::ostringstream stream; + std::copy(lines_.begin(), lines_.end(), std::ostream_iterator<std::string>(stream, "\n")); + return stream.str(); + } + + private: + std::vector<std::string> lines_; +}; + +} // namespace android::idmap2 + +#endif // IDMAP2_INCLUDE_IDMAP2_LOGINFO_H_ diff --git a/cmds/idmap2/include/idmap2/RawPrintVisitor.h b/cmds/idmap2/include/idmap2/RawPrintVisitor.h index 76475ab58731..92c186453611 100644 --- a/cmds/idmap2/include/idmap2/RawPrintVisitor.h +++ b/cmds/idmap2/include/idmap2/RawPrintVisitor.h @@ -44,7 +44,7 @@ class RawPrintVisitor : public Visitor { void print(uint8_t value, const char* fmt, ...); void print(uint16_t value, const char* fmt, ...); void print(uint32_t value, const char* fmt, ...); - void print(const std::string& value, const char* fmt, ...); + void print(const std::string& value, size_t encoded_size, const char* fmt, ...); void print_raw(uint32_t length, const char* fmt, ...); std::ostream& stream_; diff --git a/cmds/idmap2/include/idmap2/ResourceMapping.h b/cmds/idmap2/include/idmap2/ResourceMapping.h index c3e1ef06c20f..86dfab20e448 100644 --- a/cmds/idmap2/include/idmap2/ResourceMapping.h +++ b/cmds/idmap2/include/idmap2/ResourceMapping.h @@ -22,6 +22,7 @@ #include <utility> #include "androidfw/ApkAssets.h" +#include "idmap2/LogInfo.h" #include "idmap2/Policies.h" #include "idmap2/ResourceUtils.h" #include "idmap2/Result.h" @@ -50,7 +51,7 @@ class ResourceMapping { const ApkAssets& overlay_apk_assets, const OverlayManifestInfo& overlay_info, const PolicyBitmask& fulfilled_policies, - bool enforce_overlayable); + bool enforce_overlayable, LogInfo& log_info); // Retrieves the mapping of target resource id to overlay value. inline TargetResourceMap GetTargetToOverlayMap() const { @@ -100,7 +101,8 @@ class ResourceMapping { const LoadedPackage* target_package, const LoadedPackage* overlay_package, size_t string_pool_offset, - const XmlParser& overlay_parser); + const XmlParser& overlay_parser, + LogInfo& log_info); // Generates a ResourceMapping that maps target resources to overlay resources by name. To overlay // a target resource, a resource must exist in the overlay with the same type and entry name as @@ -115,7 +117,7 @@ class ResourceMapping { const LoadedPackage* target_package, const LoadedPackage* overlay_package, const OverlayManifestInfo& overlay_info, - const PolicyBitmask& fulfilled_policies); + const PolicyBitmask& fulfilled_policies, LogInfo& log_info); TargetResourceMap target_map_; std::multimap<ResourceId, ResourceId> overlay_map_; diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp index 3b0940ae06ef..362dcb36007a 100644 --- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp +++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp @@ -42,13 +42,21 @@ void BinaryStreamVisitor::Write32(uint32_t value) { stream_.write(reinterpret_cast<char*>(&x), sizeof(uint32_t)); } -void BinaryStreamVisitor::WriteString(const StringPiece& value) { +void BinaryStreamVisitor::WriteString256(const StringPiece& value) { char buf[kIdmapStringLength]; memset(buf, 0, sizeof(buf)); memcpy(buf, value.data(), std::min(value.size(), sizeof(buf))); stream_.write(buf, sizeof(buf)); } +void BinaryStreamVisitor::WriteString(const std::string& value) { + // pad with null to nearest word boundary; include at least one terminating null + size_t padding_size = 4 - (value.size() % 4); + Write32(value.size() + padding_size); + stream_.write(value.c_str(), value.size()); + stream_.write("\0\0\0\0", padding_size); +} + void BinaryStreamVisitor::visit(const Idmap& idmap ATTRIBUTE_UNUSED) { // nothing to do } @@ -58,8 +66,9 @@ void BinaryStreamVisitor::visit(const IdmapHeader& header) { Write32(header.GetVersion()); Write32(header.GetTargetCrc()); Write32(header.GetOverlayCrc()); - WriteString(header.GetTargetPath()); - WriteString(header.GetOverlayPath()); + WriteString256(header.GetTargetPath()); + WriteString256(header.GetOverlayPath()); + WriteString(header.GetDebugInfo()); } void BinaryStreamVisitor::visit(const IdmapData& data) { diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp index 5cb91d713db7..7f2cd9596c95 100644 --- a/cmds/idmap2/libidmap2/Idmap.cpp +++ b/cmds/idmap2/libidmap2/Idmap.cpp @@ -70,7 +70,7 @@ bool WARN_UNUSED ReadBuffer(std::istream& stream, std::unique_ptr<uint8_t[]>* ou } // a string is encoded as a kIdmapStringLength char array; the array is always null-terminated -bool WARN_UNUSED ReadString(std::istream& stream, char out[kIdmapStringLength]) { +bool WARN_UNUSED ReadString256(std::istream& stream, char out[kIdmapStringLength]) { char buf[kIdmapStringLength]; memset(buf, 0, sizeof(buf)); if (!stream.read(buf, sizeof(buf))) { @@ -83,6 +83,23 @@ bool WARN_UNUSED ReadString(std::istream& stream, char out[kIdmapStringLength]) return true; } +Result<std::string> ReadString(std::istream& stream) { + uint32_t size; + if (!Read32(stream, &size)) { + return Error("failed to read string size"); + } + if (size == 0) { + return std::string(""); + } + std::string buf(size, '\0'); + if (!stream.read(buf.data(), size)) { + return Error("failed to read string of size %u", size); + } + // buf is guaranteed to be null terminated (with enough nulls to end on a word boundary) + buf.resize(strlen(buf.c_str())); + return buf; +} + Result<uint32_t> GetCrc(const ZipFile& zip) { const Result<uint32_t> a = zip.Crc("resources.arsc"); const Result<uint32_t> b = zip.Crc("AndroidManifest.xml"); @@ -98,10 +115,16 @@ std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& s if (!Read32(stream, &idmap_header->magic_) || !Read32(stream, &idmap_header->version_) || !Read32(stream, &idmap_header->target_crc_) || !Read32(stream, &idmap_header->overlay_crc_) || - !ReadString(stream, idmap_header->target_path_) || - !ReadString(stream, idmap_header->overlay_path_)) { + !ReadString256(stream, idmap_header->target_path_) || + !ReadString256(stream, idmap_header->overlay_path_)) { + return nullptr; + } + + auto debug_str = ReadString(stream); + if (!debug_str) { return nullptr; } + idmap_header->debug_info_ = std::move(*debug_str); return std::move(idmap_header); } @@ -307,17 +330,15 @@ Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const ApkAssets& targe memset(header->overlay_path_, 0, sizeof(header->overlay_path_)); memcpy(header->overlay_path_, overlay_apk_path.data(), overlay_apk_path.size()); - std::unique_ptr<Idmap> idmap(new Idmap()); - idmap->header_ = std::move(header); - auto overlay_info = utils::ExtractOverlayManifestInfo(overlay_apk_path); if (!overlay_info) { return overlay_info.GetError(); } + LogInfo log_info; auto resource_mapping = ResourceMapping::FromApkAssets(target_apk_assets, overlay_apk_assets, *overlay_info, - fulfilled_policies, enforce_overlayable); + fulfilled_policies, enforce_overlayable, log_info); if (!resource_mapping) { return resource_mapping.GetError(); } @@ -327,7 +348,11 @@ Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const ApkAssets& targe return idmap_data.GetError(); } + std::unique_ptr<Idmap> idmap(new Idmap()); + header->debug_info_ = log_info.GetString(); + idmap->header_ = std::move(header); idmap->data_.push_back(std::move(*idmap_data)); + return {std::move(idmap)}; } diff --git a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp index a662aa59b615..f6e134580402 100644 --- a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp +++ b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp @@ -34,6 +34,10 @@ void PrettyPrintVisitor::visit(const Idmap& idmap ATTRIBUTE_UNUSED) { void PrettyPrintVisitor::visit(const IdmapHeader& header) { stream_ << "target apk path : " << header.GetTargetPath() << std::endl << "overlay apk path : " << header.GetOverlayPath() << std::endl; + const std::string& debug = header.GetDebugInfo(); + if (!debug.empty()) { + stream_ << debug; // assume newline terminated + } target_apk_ = ApkAssets::Load(header.GetTargetPath().to_string()); if (target_apk_) { diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp index 13973d64fe68..751c60c4add4 100644 --- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp +++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp @@ -16,6 +16,7 @@ #include "idmap2/RawPrintVisitor.h" +#include <algorithm> #include <cstdarg> #include <string> @@ -27,6 +28,15 @@ using android::ApkAssets; +namespace { + +size_t StringSizeWhenEncoded(const std::string& s) { + size_t null_bytes = 4 - (s.size() % 4); + return sizeof(uint32_t) + s.size() + null_bytes; +} + +} // namespace + namespace android::idmap2 { // verbatim copy fomr PrettyPrintVisitor.cpp, move to common utils @@ -40,8 +50,9 @@ void RawPrintVisitor::visit(const IdmapHeader& header) { print(header.GetVersion(), "version"); print(header.GetTargetCrc(), "target crc"); print(header.GetOverlayCrc(), "overlay crc"); - print(header.GetTargetPath().to_string(), "target path"); - print(header.GetOverlayPath().to_string(), "overlay path"); + print(header.GetTargetPath().to_string(), kIdmapStringLength, "target path"); + print(header.GetOverlayPath().to_string(), kIdmapStringLength, "overlay path"); + print("...", StringSizeWhenEncoded(header.GetDebugInfo()), "debug info"); target_apk_ = ApkAssets::Load(header.GetTargetPath().to_string()); if (target_apk_) { @@ -164,7 +175,7 @@ void RawPrintVisitor::print(uint32_t value, const char* fmt, ...) { } // NOLINTNEXTLINE(cert-dcl50-cpp) -void RawPrintVisitor::print(const std::string& value, const char* fmt, ...) { +void RawPrintVisitor::print(const std::string& value, size_t encoded_size, const char* fmt, ...) { va_list ap; va_start(ap, fmt); std::string comment; @@ -174,7 +185,7 @@ void RawPrintVisitor::print(const std::string& value, const char* fmt, ...) { stream_ << base::StringPrintf("%08zx: ", offset_) << "........ " << comment << ": " << value << std::endl; - offset_ += kIdmapStringLength; + offset_ += encoded_size; } // NOLINTNEXTLINE(cert-dcl50-cpp) diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp index 651d20fb7c68..229628c7dd8b 100644 --- a/cmds/idmap2/libidmap2/ResourceMapping.cpp +++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp @@ -146,7 +146,8 @@ Result<ResourceMapping> ResourceMapping::CreateResourceMapping(const AssetManage const LoadedPackage* target_package, const LoadedPackage* overlay_package, size_t string_pool_offset, - const XmlParser& overlay_parser) { + const XmlParser& overlay_parser, + LogInfo& log_info) { ResourceMapping resource_mapping; auto root_it = overlay_parser.tree_iterator(); if (root_it->event() != XmlParser::Event::START_TAG || root_it->name() != "overlay") { @@ -181,7 +182,8 @@ Result<ResourceMapping> ResourceMapping::CreateResourceMapping(const AssetManage ResourceId target_id = target_am->GetResourceId(*target_resource, "", target_package->GetPackageName()); if (target_id == 0U) { - LOG(WARNING) << "failed to find resource \"" << *target_resource << "\" in target resources"; + log_info.Warning(LogMessage() << "failed to find resource \"" << *target_resource + << "\" in target resources"); continue; } @@ -196,7 +198,7 @@ Result<ResourceMapping> ResourceMapping::CreateResourceMapping(const AssetManage overlay_resource->dataType == Res_value::TYPE_DYNAMIC_REFERENCE) ? overlay_package_id == EXTRACT_PACKAGE(overlay_resource->data) : false; - + if (rewrite_overlay_reference) { overlay_resource->dataType = Res_value::TYPE_DYNAMIC_REFERENCE; } @@ -239,7 +241,8 @@ void ResourceMapping::FilterOverlayableResources(const AssetManager2* target_am, const LoadedPackage* target_package, const LoadedPackage* overlay_package, const OverlayManifestInfo& overlay_info, - const PolicyBitmask& fulfilled_policies) { + const PolicyBitmask& fulfilled_policies, + LogInfo& log_info) { std::set<ResourceId> remove_ids; for (const auto& target_map : target_map_) { const ResourceId target_resid = target_map.first; @@ -256,9 +259,9 @@ void ResourceMapping::FilterOverlayableResources(const AssetManager2* target_am, name = StringPrintf("0x%08x", target_resid); } - LOG(WARNING) << "overlay \"" << overlay_package->GetPackageName() - << "\" is not allowed to overlay resource \"" << *name - << "\" in target: " << success.GetErrorMessage(); + log_info.Warning(LogMessage() << "overlay \"" << overlay_package->GetPackageName() + << "\" is not allowed to overlay resource \"" << *name + << "\" in target: " << success.GetErrorMessage()); remove_ids.insert(target_resid); } @@ -272,7 +275,15 @@ Result<ResourceMapping> ResourceMapping::FromApkAssets(const ApkAssets& target_a const ApkAssets& overlay_apk_assets, const OverlayManifestInfo& overlay_info, const PolicyBitmask& fulfilled_policies, - bool enforce_overlayable) { + bool enforce_overlayable, + LogInfo& log_info) { + if (enforce_overlayable) { + log_info.Info(LogMessage() << "fulfilled_policies=" + << ConcatPolicies(BitmaskToPolicies(fulfilled_policies)) + << " enforce_overlayable=" + << (enforce_overlayable ? "true" : "false")); + } + AssetManager2 target_asset_manager; if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true /* invalidate_caches */, false /* filter_incompatible_configs*/)) { @@ -333,7 +344,7 @@ Result<ResourceMapping> ResourceMapping::FromApkAssets(const ApkAssets& target_a string_pool_offset = overlay_arsc->GetStringPool()->size(); resource_mapping = CreateResourceMapping(&target_asset_manager, target_pkg, overlay_pkg, - string_pool_offset, *(*parser)); + string_pool_offset, *(*parser), log_info); } else { // If no file is specified using android:resourcesMap, it is assumed that the overlay only // defines resources intended to override target resources of the same type and name. @@ -349,7 +360,7 @@ Result<ResourceMapping> ResourceMapping::FromApkAssets(const ApkAssets& target_a // Filter out resources the overlay is not allowed to override. (*resource_mapping) .FilterOverlayableResources(&target_asset_manager, target_pkg, overlay_pkg, overlay_info, - fulfilled_policies); + fulfilled_policies, log_info); } resource_mapping->target_package_id_ = target_pkg->GetPackageId(); diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index cd816ddea814..4bc625565144 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -30,6 +30,7 @@ #include "idmap2/BinaryStreamVisitor.h" #include "idmap2/CommandLineOptions.h" #include "idmap2/Idmap.h" +#include "idmap2/LogInfo.h" using android::Res_value; using ::testing::IsNull; @@ -57,11 +58,12 @@ TEST(IdmapTests, CreateIdmapHeaderFromBinaryStream) { std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream); ASSERT_THAT(header, NotNull()); ASSERT_EQ(header->GetMagic(), 0x504d4449U); - ASSERT_EQ(header->GetVersion(), 0x02U); + ASSERT_EQ(header->GetVersion(), 0x03U); ASSERT_EQ(header->GetTargetCrc(), 0x1234U); ASSERT_EQ(header->GetOverlayCrc(), 0x5678U); ASSERT_EQ(header->GetTargetPath().to_string(), "targetX.apk"); ASSERT_EQ(header->GetOverlayPath().to_string(), "overlayX.apk"); + ASSERT_EQ(header->GetDebugInfo(), "debug"); } TEST(IdmapTests, FailToCreateIdmapHeaderFromBinaryStreamIfPathTooLong) { @@ -76,7 +78,7 @@ TEST(IdmapTests, FailToCreateIdmapHeaderFromBinaryStreamIfPathTooLong) { } TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) { - const size_t offset = 0x210; + const size_t offset = 0x21c; std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset), idmap_raw_data_len - offset); std::istringstream stream(raw); @@ -88,7 +90,7 @@ TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) { } TEST(IdmapTests, CreateIdmapDataFromBinaryStream) { - const size_t offset = 0x210; + const size_t offset = 0x21c; std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset), idmap_raw_data_len - offset); std::istringstream stream(raw); @@ -122,7 +124,7 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) { ASSERT_THAT(idmap->GetHeader(), NotNull()); ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U); - ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x02U); + ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x03U); ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x1234U); ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x5678U); ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), "targetX.apk"); @@ -174,7 +176,7 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) { ASSERT_THAT(idmap->GetHeader(), NotNull()); ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U); - ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x02U); + ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x03U); ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x76a20829); ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xc054fb26); ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path); @@ -197,8 +199,9 @@ Result<std::unique_ptr<const IdmapData>> TestIdmapDataFromApkAssets( return Error(R"(Failed to load overlay apk "%s")", overlay_apk_path.data()); } + LogInfo log_info; auto mapping = ResourceMapping::FromApkAssets(*target_apk, *overlay_apk, overlay_info, - fulfilled_policies, enforce_overlayable); + fulfilled_policies, enforce_overlayable, log_info); if (!mapping) { return mapping.GetError(); diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp index d387880cb771..b22fdafb09bb 100644 --- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp +++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp @@ -16,6 +16,7 @@ #include <cstdio> // fclose #include <memory> +#include <regex> #include <sstream> #include <string> @@ -29,7 +30,16 @@ using ::testing::NotNull; namespace android::idmap2 { +#define ASSERT_CONTAINS_REGEX(pattern, str) \ + do { \ + ASSERT_TRUE(std::regex_search(str, std::regex(pattern))) \ + << "pattern '" << pattern << "' not found in\n--------\n" \ + << str << "--------"; \ + } while (0) + TEST(RawPrintVisitorTests, CreateRawPrintVisitor) { + fclose(stderr); // silence expected warnings + const std::string target_apk_path(GetTestDataPath() + "/target/target.apk"); std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path); ASSERT_THAT(target_apk, NotNull()); @@ -46,22 +56,24 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) { RawPrintVisitor visitor(stream); (*idmap)->accept(&visitor); - ASSERT_NE(stream.str().find("00000000: 504d4449 magic\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000004: 00000002 version\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000008: 76a20829 target crc\n"), std::string::npos); - ASSERT_NE(stream.str().find("0000000c: c054fb26 overlay crc\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000210: 7f target package id\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000211: 7f overlay package id\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000212: 00000004 target entry count\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000216: 00000004 overlay entry count\n"), std::string::npos); - ASSERT_NE(stream.str().find("0000021a: 00000008 string pool index offset\n"), std::string::npos); - ASSERT_NE(stream.str().find("0000021e: 000000b4 string pool byte length\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000222: 7f010000 target id: integer/int1\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000226: 07 type: reference (dynamic)\n"), - std::string::npos); - ASSERT_NE(stream.str().find("00000227: 7f010000 value: integer/int1\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000246: 7f010000 overlay id: integer/int1\n"), std::string::npos); - ASSERT_NE(stream.str().find("0000024a: 7f010000 target id: integer/int1\n"), std::string::npos); +#define ADDRESS "[0-9a-f]{8}: " + ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00000003 version\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "76a20829 target crc\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "c054fb26 overlay crc\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS " 7f target package id\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS " 7f overlay package id\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00000004 target entry count\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00000004 overlay entry count\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00000004 overlay entry count\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00000008 string pool index offset\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "000000b4 string pool byte length\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 target id: integer/int1\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS " 07 type: reference \\(dynamic\\)\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 value: integer/int1\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 overlay id: integer/int1\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 target id: integer/int1\n", stream.str()); +#undef ADDRESS } TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) { @@ -78,21 +90,21 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) { (*idmap)->accept(&visitor); ASSERT_NE(stream.str().find("00000000: 504d4449 magic\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000004: 00000002 version\n"), std::string::npos); + ASSERT_NE(stream.str().find("00000004: 00000003 version\n"), std::string::npos); ASSERT_NE(stream.str().find("00000008: 00001234 target crc\n"), std::string::npos); ASSERT_NE(stream.str().find("0000000c: 00005678 overlay crc\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000210: 7f target package id\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000211: 7f overlay package id\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000212: 00000003 target entry count\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000216: 00000003 overlay entry count\n"), std::string::npos); - ASSERT_NE(stream.str().find("0000021a: 00000000 string pool index offset\n"), std::string::npos); - ASSERT_NE(stream.str().find("0000021e: 00000000 string pool byte length\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000222: 7f020000 target id\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000226: 01 type: reference\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000227: 7f020000 value\n"), std::string::npos); - - ASSERT_NE(stream.str().find("0000023d: 7f020000 overlay id\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000241: 7f020000 target id\n"), std::string::npos); + ASSERT_NE(stream.str().find("0000021c: 7f target package id\n"), std::string::npos); + ASSERT_NE(stream.str().find("0000021d: 7f overlay package id\n"), std::string::npos); + ASSERT_NE(stream.str().find("0000021e: 00000003 target entry count\n"), std::string::npos); + ASSERT_NE(stream.str().find("00000222: 00000003 overlay entry count\n"), std::string::npos); + ASSERT_NE(stream.str().find("00000226: 00000000 string pool index offset\n"), std::string::npos); + ASSERT_NE(stream.str().find("0000022a: 00000000 string pool byte length\n"), std::string::npos); + ASSERT_NE(stream.str().find("0000022e: 7f020000 target id\n"), std::string::npos); + ASSERT_NE(stream.str().find("00000232: 01 type: reference\n"), std::string::npos); + ASSERT_NE(stream.str().find("00000233: 7f020000 value\n"), std::string::npos); + + ASSERT_NE(stream.str().find("00000249: 7f020000 overlay id\n"), std::string::npos); + ASSERT_NE(stream.str().find("0000024d: 7f020000 target id\n"), std::string::npos); } } // namespace android::idmap2 diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp index 64304f64d22c..39c4937b0930 100644 --- a/cmds/idmap2/tests/ResourceMappingTests.cpp +++ b/cmds/idmap2/tests/ResourceMappingTests.cpp @@ -25,6 +25,7 @@ #include "TestHelpers.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "idmap2/LogInfo.h" #include "idmap2/ResourceMapping.h" using android::Res_value; @@ -55,8 +56,9 @@ Result<ResourceMapping> TestGetResourceMapping(const android::StringPiece& local return Error(R"(Failed to load overlay apk "%s")", overlay_apk_path.data()); } + LogInfo log_info; return ResourceMapping::FromApkAssets(*target_apk, *overlay_apk, overlay_info, fulfilled_policies, - enforce_overlayable); + enforce_overlayable, log_info); } Result<ResourceMapping> TestGetResourceMapping(const android::StringPiece& local_target_apk_path, diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h index 8868b5376796..e899589c7e61 100644 --- a/cmds/idmap2/tests/TestHelpers.h +++ b/cmds/idmap2/tests/TestHelpers.h @@ -30,7 +30,7 @@ const unsigned char idmap_raw_data[] = { 0x49, 0x44, 0x4d, 0x50, // 0x4: version - 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, // 0x8: target crc 0x34, 0x12, 0x00, 0x00, @@ -74,64 +74,71 @@ const unsigned char idmap_raw_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // 0x210: debug string + // string length, including terminating null + 0x08, 0x00, 0x00, 0x00, + + // string contents "debug\0\0\0" (padded to word alignment) + 0x64, 0x65, 0x62, 0x75, 0x67, 0x00, 0x00, 0x00, + // DATA HEADER - // 0x210: target_package_id + // 0x21c: target_package_id 0x7f, - // 0x211: overlay_package_id + // 0x21d: overlay_package_id 0x7f, - // 0x212: target_entry_count + // 0x21e: target_entry_count 0x03, 0x00, 0x00, 0x00, - // 0x216: overlay_entry_count + // 0x222: overlay_entry_count 0x03, 0x00, 0x00, 0x00, - // 0x21a: string_pool_offset + // 0x226: string_pool_offset 0x00, 0x00, 0x00, 0x00, - // 0x21e: string_pool_byte_length + // 0x22a: string_pool_byte_length 0x00, 0x00, 0x00, 0x00, // TARGET ENTRIES - // 0x222: 0x7f020000 + // 0x22e: 0x7f020000 0x00, 0x00, 0x02, 0x7f, - // 0x226: TYPE_REFERENCE + // 0x232: TYPE_REFERENCE 0x01, - // 0x227: 0x7f020000 + // 0x233: 0x7f020000 0x00, 0x00, 0x02, 0x7f, - // 0x22b: 0x7f030000 + // 0x237: 0x7f030000 0x00, 0x00, 0x03, 0x7f, - // 0x22f: TYPE_REFERENCE + // 0x23b: TYPE_REFERENCE 0x01, - // 0x230: 0x7f030000 + // 0x23c: 0x7f030000 0x00, 0x00, 0x03, 0x7f, - // 0x234: 0x7f030002 + // 0x240: 0x7f030002 0x02, 0x00, 0x03, 0x7f, - // 0x238: TYPE_REFERENCE + // 0x244: TYPE_REFERENCE 0x01, - // 0x239: 0x7f030001 + // 0x245: 0x7f030001 0x01, 0x00, 0x03, 0x7f, // OVERLAY ENTRIES - // 0x23d: 0x7f020000 -> 0x7f020000 + // 0x249: 0x7f020000 -> 0x7f020000 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f, - // 0x245: 0x7f030000 -> 0x7f030000 + // 0x251: 0x7f030000 -> 0x7f030000 0x00, 0x00, 0x03, 0x7f, 0x00, 0x00, 0x03, 0x7f, - // 0x24d: 0x7f030001 -> 0x7f030002 + // 0x259: 0x7f030001 -> 0x7f030002 0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f}; -const unsigned int idmap_raw_data_len = 0x255; +const unsigned int idmap_raw_data_len = 0x261; std::string GetTestDataPath(); diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp index 773353d32d51..ce3bffff0aa5 100644 --- a/libs/androidfw/Idmap.cpp +++ b/libs/androidfw/Idmap.cpp @@ -43,6 +43,10 @@ static bool compare_overlay_entries(const Idmap_overlay_entry& e1, const uint32_ return dtohl(e1.overlay_id) < overlay_id; } +size_t Idmap_header::Size() const { + return sizeof(Idmap_header) + sizeof(uint8_t) * dtohl(debug_info_size); +} + OverlayStringPool::OverlayStringPool(const LoadedIdmap* loaded_idmap) : data_header_(loaded_idmap->data_header_), idmap_string_pool_(loaded_idmap->string_pool_.get()) { }; @@ -211,8 +215,8 @@ std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_da } auto header = reinterpret_cast<const Idmap_header*>(idmap_data.data()); - const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(idmap_data.data()) + sizeof(*header); - size_t data_size = idmap_data.size() - sizeof(*header); + const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(idmap_data.data()) + header->Size(); + size_t data_size = idmap_data.size() - header->Size(); // Currently idmap2 can only generate one data block. auto data_header = reinterpret_cast<const Idmap_data_header*>(data_ptr); diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index b20e6579fda7..b603326cec34 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -39,7 +39,7 @@ namespace android { constexpr const static uint32_t kIdmapMagic = 0x504D4449u; -constexpr const static uint32_t kIdmapCurrentVersion = 0x00000002u; +constexpr const static uint32_t kIdmapCurrentVersion = 0x00000003u; /** * In C++11, char16_t is defined as *at least* 16 bits. We do a lot of @@ -1724,6 +1724,11 @@ struct Idmap_header { uint8_t target_path[256]; uint8_t overlay_path[256]; + + uint32_t debug_info_size; + uint8_t debug_info[0]; + + size_t Size() const; }; struct Idmap_data_header { diff --git a/libs/androidfw/tests/data/overlay/overlay.apk b/libs/androidfw/tests/data/overlay/overlay.apk Binary files differindex c594b8e67f28..62e98662e68d 100644 --- a/libs/androidfw/tests/data/overlay/overlay.apk +++ b/libs/androidfw/tests/data/overlay/overlay.apk diff --git a/libs/androidfw/tests/data/overlay/overlay.idmap b/libs/androidfw/tests/data/overlay/overlay.idmap Binary files differindex 27cf792ff7e2..3759ed650033 100644 --- a/libs/androidfw/tests/data/overlay/overlay.idmap +++ b/libs/androidfw/tests/data/overlay/overlay.idmap |