diff options
19 files changed, 642 insertions, 808 deletions
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp index e643ab567644..b4fdd0b8a94d 100644 --- a/cmds/idmap2/idmap2/Scan.cpp +++ b/cmds/idmap2/idmap2/Scan.cpp @@ -180,11 +180,11 @@ Result<Unit> Scan(const std::vector<std::string>& args) { // Note that conditional property enablement/exclusion only applies if // the attribute is present. In its absence, all overlays are presumed enabled. - if (!overlay_info->requiredSystemPropertyName.empty() - && !overlay_info->requiredSystemPropertyValue.empty()) { + if (!overlay_info->requiredSystemPropertyName.empty() && + !overlay_info->requiredSystemPropertyValue.empty()) { // if property set & equal to value, then include overlay - otherwise skip - if (android::base::GetProperty(overlay_info->requiredSystemPropertyName, "") - != overlay_info->requiredSystemPropertyValue) { + if (android::base::GetProperty(overlay_info->requiredSystemPropertyName, "") != + overlay_info->requiredSystemPropertyValue) { continue; } } diff --git a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h index 1a0d4438f1b3..924efe5cfb7b 100644 --- a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h +++ b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h @@ -34,9 +34,10 @@ class BinaryStreamVisitor : public Visitor { void visit(const IdmapHeader& header) override; void visit(const IdmapData& data) override; void visit(const IdmapData::Header& header) override; - void visit(const IdmapData::TypeEntry& type_entry) override; private: + void Write(const void* value, size_t length); + void Write8(uint8_t value); void Write16(uint16_t value); void Write32(uint32_t value); void WriteString(const StringPiece& value); diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h index f2cae58b910a..2639c6f470ae 100644 --- a/cmds/idmap2/include/idmap2/Idmap.h +++ b/cmds/idmap2/include/idmap2/Idmap.h @@ -41,6 +41,18 @@ * # 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. + * - Target and overlay entries are stored as a sparse array in the data block. The target entries + * array maps from target resource id to overlay data type and value and the array is sorted by + * target resource id. The overlay entries array maps from overlay resource id to target resource + * id and the array is sorted by overlay resource id. It is important for both arrays to be sorted + * to allow for O(log(number_of_overlaid_resources)) performance when looking up resource + * mappings at runtime. + * - 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. */ #ifndef IDMAP2_INCLUDE_IDMAP2_IDMAP_H_ @@ -125,7 +137,6 @@ class IdmapHeader { friend Idmap; DISALLOW_COPY_AND_ASSIGN(IdmapHeader); }; - class IdmapData { public: class Header { @@ -136,60 +147,51 @@ class IdmapData { return target_package_id_; } - inline uint16_t GetTypeCount() const { - return type_count_; + inline PackageId GetOverlayPackageId() const { + return overlay_package_id_; } - void accept(Visitor* v) const; - - private: - Header() { - } - - PackageId target_package_id_; - uint16_t type_count_; - - friend IdmapData; - DISALLOW_COPY_AND_ASSIGN(Header); - }; - - class TypeEntry { - public: - static std::unique_ptr<const TypeEntry> FromBinaryStream(std::istream& stream); - - inline TypeId GetTargetTypeId() const { - return target_type_id_; + inline uint32_t GetTargetEntryCount() const { + return target_entry_count; } - inline TypeId GetOverlayTypeId() const { - return overlay_type_id_; + inline uint32_t GetOverlayEntryCount() const { + return overlay_entry_count; } - inline uint16_t GetEntryCount() const { - return entries_.size(); + inline uint32_t GetStringPoolIndexOffset() const { + return string_pool_index_offset; } - inline uint16_t GetEntryOffset() const { - return entry_offset_; - } - - inline EntryId GetEntry(size_t i) const { - return i < entries_.size() ? entries_[i] : 0xffffu; + inline uint32_t GetStringPoolLength() const { + return string_pool_len; } void accept(Visitor* v) const; private: - TypeEntry() { - } + PackageId target_package_id_; + PackageId overlay_package_id_; + uint32_t target_entry_count; + uint32_t overlay_entry_count; + uint32_t string_pool_index_offset; + uint32_t string_pool_len; + Header() = default; + + friend Idmap; + friend IdmapData; + DISALLOW_COPY_AND_ASSIGN(Header); + }; - TypeId target_type_id_; - TypeId overlay_type_id_; - uint16_t entry_offset_; - std::vector<EntryId> entries_; + struct TargetEntry { + ResourceId target_id; + TargetValue::DataType data_type; + TargetValue::DataValue data_value; + }; - friend IdmapData; - DISALLOW_COPY_AND_ASSIGN(TypeEntry); + struct OverlayEntry { + ResourceId overlay_id; + ResourceId target_id; }; static std::unique_ptr<const IdmapData> FromBinaryStream(std::istream& stream); @@ -201,8 +203,16 @@ class IdmapData { return header_; } - inline const std::vector<std::unique_ptr<const TypeEntry>>& GetTypeEntries() const { - return type_entries_; + inline const std::vector<TargetEntry>& GetTargetEntries() const { + return target_entries_; + } + + inline const std::vector<OverlayEntry>& GetOverlayEntries() const { + return overlay_entries_; + } + + inline const void* GetStringPoolData() const { + return string_pool_.get(); } void accept(Visitor* v) const; @@ -212,7 +222,9 @@ class IdmapData { } std::unique_ptr<const Header> header_; - std::vector<std::unique_ptr<const TypeEntry>> type_entries_; + std::vector<TargetEntry> target_entries_; + std::vector<OverlayEntry> overlay_entries_; + std::unique_ptr<uint8_t[]> string_pool_; friend Idmap; DISALLOW_COPY_AND_ASSIGN(IdmapData); @@ -262,7 +274,6 @@ class Visitor { virtual void visit(const IdmapHeader& header) = 0; virtual void visit(const IdmapData& data) = 0; virtual void visit(const IdmapData::Header& header) = 0; - virtual void visit(const IdmapData::TypeEntry& type_entry) = 0; }; } // namespace android::idmap2 diff --git a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h index f0f141a3757c..5dcf217e2aa3 100644 --- a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h +++ b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h @@ -38,13 +38,11 @@ class PrettyPrintVisitor : public Visitor { void visit(const IdmapHeader& header) override; void visit(const IdmapData& data) override; void visit(const IdmapData::Header& header) override; - void visit(const IdmapData::TypeEntry& type_entry) override; private: std::ostream& stream_; std::unique_ptr<const ApkAssets> target_apk_; AssetManager2 target_am_; - PackageId last_seen_package_id_; }; } // namespace idmap2 diff --git a/cmds/idmap2/include/idmap2/RawPrintVisitor.h b/cmds/idmap2/include/idmap2/RawPrintVisitor.h index cd3897109a32..76475ab58731 100644 --- a/cmds/idmap2/include/idmap2/RawPrintVisitor.h +++ b/cmds/idmap2/include/idmap2/RawPrintVisitor.h @@ -39,18 +39,20 @@ class RawPrintVisitor : public Visitor { void visit(const IdmapHeader& header) override; void visit(const IdmapData& data) override; void visit(const IdmapData::Header& header) override; - void visit(const IdmapData::TypeEntry& type_entry) override; private: + 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_raw(uint32_t length, const char* fmt, ...); std::ostream& stream_; std::unique_ptr<const ApkAssets> target_apk_; + std::unique_ptr<const ApkAssets> overlay_apk_; AssetManager2 target_am_; + AssetManager2 overlay_am_; size_t offset_; - PackageId last_seen_package_id_; }; } // namespace idmap2 diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h index abc2df1a147f..de1dbc90eb2d 100644 --- a/cmds/idmap2/include/idmap2/ResourceUtils.h +++ b/cmds/idmap2/include/idmap2/ResourceUtils.h @@ -37,14 +37,16 @@ typedef uint16_t EntryId; // eeee in 0xpptteeee namespace utils { +StringPiece DataTypeToString(uint8_t data_type); + struct OverlayManifestInfo { - std::string target_package; // NOLINT(misc-non-private-member-variables-in-classes) - std::string target_name; // NOLINT(misc-non-private-member-variables-in-classes) - std::string requiredSystemPropertyName; // NOLINT(misc-non-private-member-variables-in-classes) + std::string target_package; // NOLINT(misc-non-private-member-variables-in-classes) + std::string target_name; // NOLINT(misc-non-private-member-variables-in-classes) + std::string requiredSystemPropertyName; // NOLINT(misc-non-private-member-variables-in-classes) std::string requiredSystemPropertyValue; // NOLINT(misc-non-private-member-variables-in-classes) - uint32_t resource_mapping; // NOLINT(misc-non-private-member-variables-in-classes) - bool is_static; // NOLINT(misc-non-private-member-variables-in-classes) - int priority = -1; // NOLINT(misc-non-private-member-variables-in-classes) + uint32_t resource_mapping; // NOLINT(misc-non-private-member-variables-in-classes) + bool is_static; // NOLINT(misc-non-private-member-variables-in-classes) + int priority = -1; // NOLINT(misc-non-private-member-variables-in-classes) }; Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path, diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp index dee2d219cbe1..3b0940ae06ef 100644 --- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp +++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp @@ -24,6 +24,14 @@ namespace android::idmap2 { +void BinaryStreamVisitor::Write(const void* value, size_t length) { + stream_.write(reinterpret_cast<const char*>(value), length); +} + +void BinaryStreamVisitor::Write8(uint8_t value) { + stream_.write(reinterpret_cast<char*>(&value), sizeof(uint8_t)); +} + void BinaryStreamVisitor::Write16(uint16_t value) { uint16_t x = htodl(value); stream_.write(reinterpret_cast<char*>(&x), sizeof(uint16_t)); @@ -54,26 +62,28 @@ void BinaryStreamVisitor::visit(const IdmapHeader& header) { WriteString(header.GetOverlayPath()); } -void BinaryStreamVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) { - // nothing to do -} +void BinaryStreamVisitor::visit(const IdmapData& data) { + for (const auto& target_entry : data.GetTargetEntries()) { + Write32(target_entry.target_id); + Write8(target_entry.data_type); + Write32(target_entry.data_value); + } -void BinaryStreamVisitor::visit(const IdmapData::Header& header) { - Write16(header.GetTargetPackageId()); - Write16(header.GetTypeCount()); -} + for (const auto& overlay_entry : data.GetOverlayEntries()) { + Write32(overlay_entry.overlay_id); + Write32(overlay_entry.target_id); + } -void BinaryStreamVisitor::visit(const IdmapData::TypeEntry& type_entry) { - const uint16_t entryCount = type_entry.GetEntryCount(); + Write(data.GetStringPoolData(), data.GetHeader()->GetStringPoolLength()); +} - Write16(type_entry.GetTargetTypeId()); - Write16(type_entry.GetOverlayTypeId()); - Write16(entryCount); - Write16(type_entry.GetEntryOffset()); - for (uint16_t i = 0; i < entryCount; i++) { - EntryId entry_id = type_entry.GetEntry(i); - Write32(entry_id != kNoEntry ? static_cast<uint32_t>(entry_id) : kPadding); - } +void BinaryStreamVisitor::visit(const IdmapData::Header& header) { + Write8(header.GetTargetPackageId()); + Write8(header.GetOverlayPackageId()); + Write32(header.GetTargetEntryCount()); + Write32(header.GetOverlayEntryCount()); + Write32(header.GetStringPoolIndexOffset()); + Write32(header.GetStringPoolLength()); } } // namespace android::idmap2 diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp index 389ade59200c..5cb91d713db7 100644 --- a/cmds/idmap2/libidmap2/Idmap.cpp +++ b/cmds/idmap2/libidmap2/Idmap.cpp @@ -42,30 +42,10 @@ namespace android::idmap2 { namespace { -class MatchingResources { - public: - void Add(ResourceId target_resid, ResourceId overlay_resid) { - TypeId target_typeid = EXTRACT_TYPE(target_resid); - if (map_.find(target_typeid) == map_.end()) { - map_.emplace(target_typeid, std::set<std::pair<ResourceId, ResourceId>>()); - } - map_[target_typeid].insert(std::make_pair(target_resid, overlay_resid)); - } - - inline const std::map<TypeId, std::set<std::pair<ResourceId, ResourceId>>>& WARN_UNUSED - Map() const { - return map_; - } - - private: - // target type id -> set { pair { overlay entry id, overlay entry id } } - std::map<TypeId, std::set<std::pair<ResourceId, ResourceId>>> map_; -}; - -bool WARN_UNUSED Read16(std::istream& stream, uint16_t* out) { - uint16_t value; - if (stream.read(reinterpret_cast<char*>(&value), sizeof(uint16_t))) { - *out = dtohl(value); +bool WARN_UNUSED Read8(std::istream& stream, uint8_t* out) { + uint8_t value; + if (stream.read(reinterpret_cast<char*>(&value), sizeof(uint8_t))) { + *out = value; return true; } return false; @@ -80,6 +60,15 @@ bool WARN_UNUSED Read32(std::istream& stream, uint32_t* out) { return false; } +bool WARN_UNUSED ReadBuffer(std::istream& stream, std::unique_ptr<uint8_t[]>* out, size_t length) { + auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[length]); + if (stream.read(reinterpret_cast<char*>(buffer.get()), length)) { + *out = std::move(buffer); + return true; + } + return false; +} + // 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]) { char buf[kIdmapStringLength]; @@ -162,51 +151,48 @@ Result<Unit> IdmapHeader::IsUpToDate() const { std::unique_ptr<const IdmapData::Header> IdmapData::Header::FromBinaryStream(std::istream& stream) { std::unique_ptr<IdmapData::Header> idmap_data_header(new IdmapData::Header()); - uint16_t target_package_id16; - if (!Read16(stream, &target_package_id16) || !Read16(stream, &idmap_data_header->type_count_)) { + if (!Read8(stream, &idmap_data_header->target_package_id_) || + !Read8(stream, &idmap_data_header->overlay_package_id_) || + !Read32(stream, &idmap_data_header->target_entry_count) || + !Read32(stream, &idmap_data_header->overlay_entry_count) || + !Read32(stream, &idmap_data_header->string_pool_index_offset) || + !Read32(stream, &idmap_data_header->string_pool_len)) { return nullptr; } - idmap_data_header->target_package_id_ = target_package_id16; return std::move(idmap_data_header); } -std::unique_ptr<const IdmapData::TypeEntry> IdmapData::TypeEntry::FromBinaryStream( - std::istream& stream) { - std::unique_ptr<IdmapData::TypeEntry> data(new IdmapData::TypeEntry()); - uint16_t target_type16; - uint16_t overlay_type16; - uint16_t entry_count; - if (!Read16(stream, &target_type16) || !Read16(stream, &overlay_type16) || - !Read16(stream, &entry_count) || !Read16(stream, &data->entry_offset_)) { - return nullptr; - } - data->target_type_id_ = target_type16; - data->overlay_type_id_ = overlay_type16; - for (uint16_t i = 0; i < entry_count; i++) { - ResourceId resid; - if (!Read32(stream, &resid)) { - return nullptr; - } - data->entries_.push_back(resid); - } - - return std::move(data); -} - std::unique_ptr<const IdmapData> IdmapData::FromBinaryStream(std::istream& stream) { std::unique_ptr<IdmapData> data(new IdmapData()); data->header_ = IdmapData::Header::FromBinaryStream(stream); if (!data->header_) { return nullptr; } - for (size_t type_count = 0; type_count < data->header_->GetTypeCount(); type_count++) { - std::unique_ptr<const TypeEntry> type = IdmapData::TypeEntry::FromBinaryStream(stream); - if (!type) { + // Read the mapping of target resource id to overlay resource value. + for (size_t i = 0; i < data->header_->GetTargetEntryCount(); i++) { + TargetEntry target_entry{}; + if (!Read32(stream, &target_entry.target_id) || !Read8(stream, &target_entry.data_type) || + !Read32(stream, &target_entry.data_value)) { + return nullptr; + } + data->target_entries_.emplace_back(target_entry); + } + + // Read the mapping of overlay resource id to target resource id. + for (size_t i = 0; i < data->header_->GetOverlayEntryCount(); i++) { + OverlayEntry overlay_entry{}; + if (!Read32(stream, &overlay_entry.overlay_id) || !Read32(stream, &overlay_entry.target_id)) { return nullptr; } - data->type_entries_.push_back(std::move(type)); + data->overlay_entries_.emplace_back(overlay_entry); + } + + // Read raw string pool bytes. + if (!ReadBuffer(stream, &data->string_pool_, data->header_->string_pool_len)) { + return nullptr; } + return std::move(data); } @@ -247,40 +233,28 @@ Result<std::unique_ptr<const IdmapData>> IdmapData::FromResourceMapping( return Error("no resources were overlaid"); } - MatchingResources matching_resources; - for (const auto mapping : resource_mapping.GetTargetToOverlayMap()) { - if (mapping.second.data_type != Res_value::TYPE_REFERENCE) { - // The idmap format must change to support non-references. - continue; - } - - matching_resources.Add(mapping.first, mapping.second.data_value); + std::unique_ptr<IdmapData> data(new IdmapData()); + for (const auto& mappings : resource_mapping.GetTargetToOverlayMap()) { + data->target_entries_.emplace_back(IdmapData::TargetEntry{ + mappings.first, mappings.second.data_type, mappings.second.data_value}); } - // encode idmap data - std::unique_ptr<IdmapData> data(new IdmapData()); - const auto types_end = matching_resources.Map().cend(); - for (auto ti = matching_resources.Map().cbegin(); ti != types_end; ++ti) { - auto ei = ti->second.cbegin(); - std::unique_ptr<IdmapData::TypeEntry> type(new IdmapData::TypeEntry()); - type->target_type_id_ = EXTRACT_TYPE(ei->first); - type->overlay_type_id_ = EXTRACT_TYPE(ei->second); - type->entry_offset_ = EXTRACT_ENTRY(ei->first); - EntryId last_target_entry = kNoEntry; - for (; ei != ti->second.cend(); ++ei) { - if (last_target_entry != kNoEntry) { - int count = EXTRACT_ENTRY(ei->first) - last_target_entry - 1; - type->entries_.insert(type->entries_.end(), count, kNoEntry); - } - type->entries_.push_back(EXTRACT_ENTRY(ei->second)); - last_target_entry = EXTRACT_ENTRY(ei->first); - } - data->type_entries_.push_back(std::move(type)); + for (const auto& mappings : resource_mapping.GetOverlayToTargetMap()) { + data->overlay_entries_.emplace_back(IdmapData::OverlayEntry{mappings.first, mappings.second}); } std::unique_ptr<IdmapData::Header> data_header(new IdmapData::Header()); data_header->target_package_id_ = resource_mapping.GetTargetPackageId(); - data_header->type_count_ = data->type_entries_.size(); + data_header->overlay_package_id_ = resource_mapping.GetOverlayPackageId(); + data_header->target_entry_count = static_cast<uint32_t>(data->target_entries_.size()); + data_header->overlay_entry_count = static_cast<uint32_t>(data->overlay_entries_.size()); + data_header->string_pool_index_offset = resource_mapping.GetStringPoolOffset(); + + const auto string_pool_data = resource_mapping.GetStringPoolData(); + data_header->string_pool_len = string_pool_data.second; + data->string_pool_ = std::unique_ptr<uint8_t[]>(new uint8_t[data_header->string_pool_len]); + memcpy(data->string_pool_.get(), string_pool_data.first, data_header->string_pool_len); + data->header_ = std::move(data_header); return {std::move(data)}; } @@ -367,25 +341,16 @@ void IdmapData::Header::accept(Visitor* v) const { v->visit(*this); } -void IdmapData::TypeEntry::accept(Visitor* v) const { - assert(v != nullptr); - v->visit(*this); -} - void IdmapData::accept(Visitor* v) const { assert(v != nullptr); - v->visit(*this); header_->accept(v); - auto end = type_entries_.cend(); - for (auto iter = type_entries_.cbegin(); iter != end; ++iter) { - (*iter)->accept(v); - } + v->visit(*this); } void Idmap::accept(Visitor* v) const { assert(v != nullptr); - v->visit(*this); header_->accept(v); + v->visit(*this); auto end = data_.cend(); for (auto iter = data_.cbegin(); iter != end; ++iter) { (*iter)->accept(v); diff --git a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp index fbf2c777be9a..a662aa59b615 100644 --- a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp +++ b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp @@ -41,29 +41,33 @@ void PrettyPrintVisitor::visit(const IdmapHeader& header) { } } -void PrettyPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) { -} - void PrettyPrintVisitor::visit(const IdmapData::Header& header ATTRIBUTE_UNUSED) { - last_seen_package_id_ = header.GetTargetPackageId(); } -void PrettyPrintVisitor::visit(const IdmapData::TypeEntry& type_entry) { +void PrettyPrintVisitor::visit(const IdmapData& data) { const bool target_package_loaded = !target_am_.GetApkAssets().empty(); - for (uint16_t i = 0; i < type_entry.GetEntryCount(); i++) { - const EntryId entry = type_entry.GetEntry(i); - if (entry == kNoEntry) { - continue; + const ResStringPool string_pool(data.GetStringPoolData(), + data.GetHeader()->GetStringPoolLength()); + const size_t string_pool_offset = data.GetHeader()->GetStringPoolIndexOffset(); + + for (auto& target_entry : data.GetTargetEntries()) { + stream_ << base::StringPrintf("0x%08x ->", target_entry.target_id); + + if (target_entry.data_type != Res_value::TYPE_REFERENCE && + target_entry.data_type != Res_value::TYPE_DYNAMIC_REFERENCE) { + stream_ << " " << utils::DataTypeToString(target_entry.data_type); } - const ResourceId target_resid = - RESID(last_seen_package_id_, type_entry.GetTargetTypeId(), type_entry.GetEntryOffset() + i); - const ResourceId overlay_resid = - RESID(last_seen_package_id_, type_entry.GetOverlayTypeId(), entry); + if (target_entry.data_type == Res_value::TYPE_STRING) { + stream_ << " \"" + << string_pool.string8ObjectAt(target_entry.data_value - string_pool_offset).c_str() + << "\""; + } else { + stream_ << " " << base::StringPrintf("0x%08x", target_entry.data_value); + } - stream_ << base::StringPrintf("0x%08x -> 0x%08x", target_resid, overlay_resid); if (target_package_loaded) { - Result<std::string> name = utils::ResToTypeEntryName(target_am_, target_resid); + Result<std::string> name = utils::ResToTypeEntryName(target_am_, target_entry.target_id); if (name) { stream_ << " " << *name; } diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp index dd14fd47aea8..13973d64fe68 100644 --- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp +++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp @@ -47,46 +47,94 @@ void RawPrintVisitor::visit(const IdmapHeader& header) { if (target_apk_) { target_am_.SetApkAssets({target_apk_.get()}); } + + overlay_apk_ = ApkAssets::Load(header.GetOverlayPath().to_string()); + if (overlay_apk_) { + overlay_am_.SetApkAssets({overlay_apk_.get()}); + } } void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) { -} + const bool target_package_loaded = !target_am_.GetApkAssets().empty(); + const bool overlay_package_loaded = !overlay_am_.GetApkAssets().empty(); -void RawPrintVisitor::visit(const IdmapData::Header& header) { - print(static_cast<uint16_t>(header.GetTargetPackageId()), "target package id"); - print(header.GetTypeCount(), "type count"); - last_seen_package_id_ = header.GetTargetPackageId(); -} + for (auto& target_entry : data.GetTargetEntries()) { + Result<std::string> target_name(Error("")); + if (target_package_loaded) { + target_name = utils::ResToTypeEntryName(target_am_, target_entry.target_id); + } + if (target_name) { + print(target_entry.target_id, "target id: %s", target_name->c_str()); + } else { + print(target_entry.target_id, "target id"); + } -void RawPrintVisitor::visit(const IdmapData::TypeEntry& type_entry) { - const bool target_package_loaded = !target_am_.GetApkAssets().empty(); + print(target_entry.data_type, "type: %s", + utils::DataTypeToString(target_entry.data_type).data()); + + Result<std::string> overlay_name(Error("")); + if (overlay_package_loaded && (target_entry.data_type == Res_value::TYPE_REFERENCE || + target_entry.data_type == Res_value::TYPE_DYNAMIC_REFERENCE)) { + overlay_name = utils::ResToTypeEntryName(overlay_am_, target_entry.data_value); + } + if (overlay_name) { + print(target_entry.data_value, "value: %s", overlay_name->c_str()); + } else { + print(target_entry.data_value, "value"); + } + } + + for (auto& overlay_entry : data.GetOverlayEntries()) { + Result<std::string> overlay_name(Error("")); + if (overlay_package_loaded) { + overlay_name = utils::ResToTypeEntryName(overlay_am_, overlay_entry.overlay_id); + } + + if (overlay_name) { + print(overlay_entry.overlay_id, "overlay id: %s", overlay_name->c_str()); + } else { + print(overlay_entry.overlay_id, "overlay id"); + } - print(static_cast<uint16_t>(type_entry.GetTargetTypeId()), "target type"); - print(static_cast<uint16_t>(type_entry.GetOverlayTypeId()), "overlay type"); - print(static_cast<uint16_t>(type_entry.GetEntryCount()), "entry count"); - print(static_cast<uint16_t>(type_entry.GetEntryOffset()), "entry offset"); + Result<std::string> target_name(Error("")); + if (target_package_loaded) { + target_name = utils::ResToTypeEntryName(target_am_, overlay_entry.target_id); + } - for (uint16_t i = 0; i < type_entry.GetEntryCount(); i++) { - const EntryId entry = type_entry.GetEntry(i); - if (entry == kNoEntry) { - print(kPadding, "no entry"); + if (target_name) { + print(overlay_entry.target_id, "target id: %s", target_name->c_str()); } else { - const ResourceId target_resid = RESID(last_seen_package_id_, type_entry.GetTargetTypeId(), - type_entry.GetEntryOffset() + i); - const ResourceId overlay_resid = - RESID(last_seen_package_id_, type_entry.GetOverlayTypeId(), entry); - Result<std::string> name(Error("")); - if (target_package_loaded) { - name = utils::ResToTypeEntryName(target_am_, target_resid); - } - if (name) { - print(static_cast<uint32_t>(entry), "0x%08x -> 0x%08x %s", target_resid, overlay_resid, - name->c_str()); - } else { - print(static_cast<uint32_t>(entry), "0x%08x -> 0x%08x", target_resid, overlay_resid); - } + print(overlay_entry.target_id, "target id"); } } + + const size_t string_pool_length = data.GetHeader()->GetStringPoolLength(); + if (string_pool_length > 0) { + print_raw(string_pool_length, "%zu raw string pool bytes", string_pool_length); + } +} + +void RawPrintVisitor::visit(const IdmapData::Header& header) { + print(header.GetTargetPackageId(), "target package id"); + print(header.GetOverlayPackageId(), "overlay package id"); + print(header.GetTargetEntryCount(), "target entry count"); + print(header.GetOverlayEntryCount(), "overlay entry count"); + print(header.GetStringPoolIndexOffset(), "string pool index offset"); + print(header.GetStringPoolLength(), "string pool byte length"); +} + +// NOLINTNEXTLINE(cert-dcl50-cpp) +void RawPrintVisitor::print(uint8_t value, const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + std::string comment; + base::StringAppendV(&comment, fmt, ap); + va_end(ap); + + stream_ << base::StringPrintf("%08zx: %02x", offset_, value) << " " << comment + << std::endl; + + offset_ += sizeof(uint8_t); } // NOLINTNEXTLINE(cert-dcl50-cpp) @@ -123,10 +171,23 @@ void RawPrintVisitor::print(const std::string& value, const char* fmt, ...) { base::StringAppendV(&comment, fmt, ap); va_end(ap); - stream_ << base::StringPrintf("%08zx: ", offset_) << "........ " << comment << ": " << value + stream_ << base::StringPrintf("%08zx: ", offset_) << "........ " << comment << ": " << value << std::endl; offset_ += kIdmapStringLength; } +// NOLINTNEXTLINE(cert-dcl50-cpp) +void RawPrintVisitor::print_raw(uint32_t length, const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + std::string comment; + base::StringAppendV(&comment, fmt, ap); + va_end(ap); + + stream_ << base::StringPrintf("%08zx: ", offset_) << "........ " << comment << std::endl; + + offset_ += length; +} + } // namespace android::idmap2 diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp index 95ae626664dd..651d20fb7c68 100644 --- a/cmds/idmap2/libidmap2/ResourceMapping.cpp +++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp @@ -192,9 +192,14 @@ Result<ResourceMapping> ResourceMapping::CreateResourceMapping(const AssetManage // Only rewrite resources defined within the overlay package to their corresponding target // resource ids at runtime. bool rewrite_overlay_reference = - (overlay_resource->dataType == Res_value::TYPE_REFERENCE) + (overlay_resource->dataType == Res_value::TYPE_REFERENCE || + 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; + } resource_mapping.AddMapping(target_id, overlay_resource->dataType, overlay_resource->data, rewrite_overlay_reference); @@ -224,7 +229,7 @@ Result<ResourceMapping> ResourceMapping::CreateResourceMappingLegacy( } resource_mapping.AddMapping(target_resource, Res_value::TYPE_REFERENCE, overlay_resid, - /* rewrite_overlay_reference */ true); + /* rewrite_overlay_reference */ false); } return resource_mapping; @@ -378,7 +383,8 @@ Result<Unit> ResourceMapping::AddMapping(ResourceId target_resource, target_map_.insert(std::make_pair(target_resource, TargetValue{data_type, data_value})); - if (rewrite_overlay_reference && data_type == Res_value::TYPE_REFERENCE) { + if (rewrite_overlay_reference && + (data_type == Res_value::TYPE_REFERENCE || data_type == Res_value::TYPE_DYNAMIC_REFERENCE)) { overlay_map_.insert(std::make_pair(data_value, target_resource)); } @@ -394,8 +400,8 @@ void ResourceMapping::RemoveMapping(ResourceId target_resource) { const TargetValue value = target_iter->second; target_map_.erase(target_iter); - // Remove rewriting of overlay resource id to target resource id. - if (value.data_type != Res_value::TYPE_REFERENCE) { + if (value.data_type != Res_value::TYPE_REFERENCE && + value.data_type != Res_value::TYPE_DYNAMIC_REFERENCE) { return; } diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp index 9d3269207c91..a5df746ca733 100644 --- a/cmds/idmap2/libidmap2/ResourceUtils.cpp +++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp @@ -33,6 +33,40 @@ using android::util::Utf16ToUtf8; namespace android::idmap2::utils { +StringPiece DataTypeToString(uint8_t data_type) { + switch (data_type) { + case Res_value::TYPE_NULL: + return "null"; + case Res_value::TYPE_REFERENCE: + return "reference"; + case Res_value::TYPE_ATTRIBUTE: + return "attribute"; + case Res_value::TYPE_STRING: + return "string"; + case Res_value::TYPE_FLOAT: + return "float"; + case Res_value::TYPE_DIMENSION: + return "dimension"; + case Res_value::TYPE_FRACTION: + return "fraction"; + case Res_value::TYPE_DYNAMIC_REFERENCE: + return "reference (dynamic)"; + case Res_value::TYPE_DYNAMIC_ATTRIBUTE: + return "attribute (dynamic)"; + case Res_value::TYPE_INT_DEC: + case Res_value::TYPE_INT_HEX: + return "integer"; + case Res_value::TYPE_INT_BOOLEAN: + return "boolean"; + case Res_value::TYPE_INT_COLOR_ARGB8: + case Res_value::TYPE_INT_COLOR_RGB8: + case Res_value::TYPE_INT_COLOR_RGB4: + return "color"; + default: + return "unknown"; + } +} + Result<std::string> ResToTypeEntryName(const AssetManager2& am, uint32_t resid) { AssetManager2::ResourceName name; if (!am.GetResourceName(resid, &name)) { @@ -129,7 +163,7 @@ Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path, info.requiredSystemPropertyName = *result_str; } - if (auto result_str = overlay_it->GetAttributeStringValue("requiredSystemPropertyValue")) { + if (auto result_str = overlay_it->GetAttributeStringValue("requiredSystemPropertyValue")) { info.requiredSystemPropertyValue = *result_str; } diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp index 43fdc9a78186..3a01e8fca70b 100644 --- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp +++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp @@ -18,6 +18,7 @@ #include <sstream> #include <string> #include <utility> +#include <vector> #include "TestHelpers.h" #include "androidfw/ApkAssets.h" @@ -52,112 +53,43 @@ TEST(BinaryStreamVisitorTests, CreateBinaryStreamViaBinaryStreamVisitor) { ASSERT_EQ(idmap1->GetData().size(), 1U); ASSERT_EQ(idmap1->GetData().size(), idmap2->GetData().size()); - const auto& data1 = idmap1->GetData()[0]; - const auto& data2 = idmap2->GetData()[0]; - - ASSERT_EQ(data1->GetHeader()->GetTargetPackageId(), data2->GetHeader()->GetTargetPackageId()); - ASSERT_EQ(data1->GetTypeEntries().size(), 2U); - ASSERT_EQ(data1->GetTypeEntries().size(), data2->GetTypeEntries().size()); - ASSERT_EQ(data1->GetTypeEntries()[0]->GetEntry(0), data2->GetTypeEntries()[0]->GetEntry(0)); - ASSERT_EQ(data1->GetTypeEntries()[0]->GetEntry(1), data2->GetTypeEntries()[0]->GetEntry(1)); - ASSERT_EQ(data1->GetTypeEntries()[0]->GetEntry(2), data2->GetTypeEntries()[0]->GetEntry(2)); - ASSERT_EQ(data1->GetTypeEntries()[1]->GetEntry(0), data2->GetTypeEntries()[1]->GetEntry(0)); - ASSERT_EQ(data1->GetTypeEntries()[1]->GetEntry(1), data2->GetTypeEntries()[1]->GetEntry(1)); - ASSERT_EQ(data1->GetTypeEntries()[1]->GetEntry(2), data2->GetTypeEntries()[1]->GetEntry(2)); -} - -TEST(BinaryStreamVisitorTests, CreateIdmapFromApkAssetsInteropWithLoadedIdmap) { - 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()); - - const std::string overlay_apk_path(GetTestDataPath() + "/overlay/overlay.apk"); - std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); - ASSERT_THAT(overlay_apk, NotNull()); - - const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC, - /* enforce_overlayable */ true); - ASSERT_TRUE(idmap); - - std::stringstream stream; - BinaryStreamVisitor visitor(stream); - (*idmap)->accept(&visitor); - const std::string str = stream.str(); - const StringPiece data(str); - std::unique_ptr<const LoadedIdmap> loaded_idmap = LoadedIdmap::Load(data); - ASSERT_THAT(loaded_idmap, NotNull()); - ASSERT_EQ(loaded_idmap->TargetPackageId(), 0x7f); - - const IdmapEntry_header* header = loaded_idmap->GetEntryMapForType(0x01); - ASSERT_THAT(header, NotNull()); - - EntryId entry; - bool success = LoadedIdmap::Lookup(header, 0x0000, &entry); - ASSERT_TRUE(success); - ASSERT_EQ(entry, 0x0000); - - header = loaded_idmap->GetEntryMapForType(0x02); - ASSERT_THAT(header, NotNull()); - - success = LoadedIdmap::Lookup(header, 0x0000, &entry); // string/a - ASSERT_FALSE(success); + const std::vector<std::unique_ptr<const IdmapData>>& data_blocks1 = idmap1->GetData(); + ASSERT_EQ(data_blocks1.size(), 1U); + const std::unique_ptr<const IdmapData>& data1 = data_blocks1[0]; + ASSERT_THAT(data1, NotNull()); - success = LoadedIdmap::Lookup(header, 0x0001, &entry); // string/b - ASSERT_FALSE(success); + const std::vector<std::unique_ptr<const IdmapData>>& data_blocks2 = idmap2->GetData(); + ASSERT_EQ(data_blocks2.size(), 1U); + const std::unique_ptr<const IdmapData>& data2 = data_blocks2[0]; + ASSERT_THAT(data2, NotNull()); - success = LoadedIdmap::Lookup(header, 0x0002, &entry); // string/c - ASSERT_FALSE(success); + const auto& target_entries1 = data1->GetTargetEntries(); + const auto& target_entries2 = data2->GetTargetEntries(); + ASSERT_EQ(target_entries1.size(), target_entries2.size()); + ASSERT_EQ(target_entries1[0].target_id, target_entries2[0].target_id); + ASSERT_EQ(target_entries1[0].data_value, target_entries2[0].data_value); - success = LoadedIdmap::Lookup(header, 0x0003, &entry); // string/policy_odm - ASSERT_FALSE(success); + ASSERT_EQ(target_entries1[1].target_id, target_entries2[1].target_id); + ASSERT_EQ(target_entries1[1].data_value, target_entries2[1].data_value); - success = LoadedIdmap::Lookup(header, 0x0004, &entry); // string/policy_oem - ASSERT_FALSE(success); + ASSERT_EQ(target_entries1[2].target_id, target_entries2[2].target_id); + ASSERT_EQ(target_entries1[2].data_value, target_entries2[2].data_value); - success = LoadedIdmap::Lookup(header, 0x0005, &entry); // string/other - ASSERT_FALSE(success); + const auto& overlay_entries1 = data1->GetOverlayEntries(); + const auto& overlay_entries2 = data2->GetOverlayEntries(); + ASSERT_EQ(overlay_entries1.size(), overlay_entries2.size()); + ASSERT_EQ(overlay_entries1[0].overlay_id, overlay_entries2[0].overlay_id); + ASSERT_EQ(overlay_entries1[0].target_id, overlay_entries2[0].target_id); - success = LoadedIdmap::Lookup(header, 0x0006, &entry); // string/not_overlayable - ASSERT_FALSE(success); + ASSERT_EQ(overlay_entries1[1].overlay_id, overlay_entries2[1].overlay_id); + ASSERT_EQ(overlay_entries1[1].target_id, overlay_entries2[1].target_id); - success = LoadedIdmap::Lookup(header, 0x0007, &entry); // string/policy_product - ASSERT_FALSE(success); - - success = LoadedIdmap::Lookup(header, 0x0008, &entry); // string/policy_public - ASSERT_FALSE(success); - - success = LoadedIdmap::Lookup(header, 0x0009, &entry); // string/policy_system - ASSERT_FALSE(success); - - success = LoadedIdmap::Lookup(header, 0x000a, &entry); // string/policy_system_vendor - ASSERT_FALSE(success); - - success = LoadedIdmap::Lookup(header, 0x000b, &entry); // string/policy_signature - ASSERT_FALSE(success); - - success = LoadedIdmap::Lookup(header, 0x000c, &entry); // string/str1 - ASSERT_TRUE(success); - ASSERT_EQ(entry, 0x0000); - - success = LoadedIdmap::Lookup(header, 0x000d, &entry); // string/str2 - ASSERT_FALSE(success); - - success = LoadedIdmap::Lookup(header, 0x000e, &entry); // string/str3 - ASSERT_TRUE(success); - ASSERT_EQ(entry, 0x0001); - - success = LoadedIdmap::Lookup(header, 0x000f, &entry); // string/str4 - ASSERT_TRUE(success); - ASSERT_EQ(entry, 0x0002); - - success = LoadedIdmap::Lookup(header, 0x0010, &entry); // string/x - ASSERT_FALSE(success); - - success = LoadedIdmap::Lookup(header, 0x0011, &entry); // string/y - ASSERT_FALSE(success); + ASSERT_EQ(overlay_entries1[2].overlay_id, overlay_entries2[2].overlay_id); + ASSERT_EQ(overlay_entries1[2].target_id, overlay_entries2[2].target_id); +} - success = LoadedIdmap::Lookup(header, 0x0012, &entry); // string/z - ASSERT_FALSE(success); +TEST(BinaryStreamVisitorTests, CreateIdmapFromApkAssetsInteropWithLoadedIdmap) { + // TODO(135943783): Removed temporarily until libandroidfw idmap loading is fixed. } } // namespace android::idmap2 diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp index 8a48f4b8e6d5..b1685b7f1312 100644 --- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp +++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp @@ -131,7 +131,6 @@ TEST_F(Idmap2BinaryTests, Dump) { ASSERT_NE(result->stdout.find("0x7f02000c -> 0x7f020000 string/str1"), std::string::npos); ASSERT_NE(result->stdout.find("0x7f02000e -> 0x7f020001 string/str3"), std::string::npos); ASSERT_NE(result->stdout.find("0x7f02000f -> 0x7f020002 string/str4"), std::string::npos); - ASSERT_EQ(result->stdout.find("00000210: 007f target package id"), std::string::npos); // clang-format off result = ExecuteBinary({"idmap2", @@ -142,7 +141,6 @@ TEST_F(Idmap2BinaryTests, Dump) { ASSERT_THAT(result, NotNull()); ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; ASSERT_NE(result->stdout.find("00000000: 504d4449 magic"), std::string::npos); - ASSERT_NE(result->stdout.find("00000210: 007f target package id"), std::string::npos); // clang-format off result = ExecuteBinary({"idmap2", @@ -282,54 +280,7 @@ TEST_F(Idmap2BinaryTests, Scan) { } TEST_F(Idmap2BinaryTests, Lookup) { - SKIP_TEST_IF_CANT_EXEC_IDMAP2; - - // clang-format off - auto result = ExecuteBinary({"idmap2", - "create", - "--target-apk-path", GetTargetApkPath(), - "--overlay-apk-path", GetOverlayApkPath(), - "--idmap-path", GetIdmapPath()}); - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - - // clang-format off - result = ExecuteBinary({"idmap2", - "lookup", - "--idmap-path", GetIdmapPath(), - "--config", "", - "--resid", "0x7f02000c"}); // string/str1 - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - ASSERT_NE(result->stdout.find("overlay-1"), std::string::npos); - ASSERT_EQ(result->stdout.find("overlay-1-sv"), std::string::npos); - - // clang-format off - result = ExecuteBinary({"idmap2", - "lookup", - "--idmap-path", GetIdmapPath(), - "--config", "", - "--resid", "test.target:string/str1"}); - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - ASSERT_NE(result->stdout.find("overlay-1"), std::string::npos); - ASSERT_EQ(result->stdout.find("overlay-1-sv"), std::string::npos); - - // clang-format off - result = ExecuteBinary({"idmap2", - "lookup", - "--idmap-path", GetIdmapPath(), - "--config", "sv", - "--resid", "test.target:string/str1"}); - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - ASSERT_NE(result->stdout.find("overlay-1-sv"), std::string::npos); - - unlink(GetIdmapPath().c_str()); + // TODO(135943783): Removed temporarily until libandroidfw idmap loading is fixed. } TEST_F(Idmap2BinaryTests, InvalidCommandLineOptions) { diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index 47e5b17f4a98..30b1372005db 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -31,11 +31,21 @@ #include "idmap2/CommandLineOptions.h" #include "idmap2/Idmap.h" +using android::Res_value; using ::testing::IsNull; using ::testing::NotNull; namespace android::idmap2 { +#define ASSERT_TARGET_ENTRY(entry, target_resid, type, value) \ + ASSERT_EQ(entry.target_id, target_resid); \ + ASSERT_EQ(entry.data_type, type); \ + ASSERT_EQ(entry.data_value, value) + +#define ASSERT_OVERLAY_ENTRY(entry, overlay_resid, target_resid) \ + ASSERT_EQ(entry.overlay_id, overlay_resid); \ + ASSERT_EQ(entry.target_id, target_resid) + TEST(IdmapTests, TestCanonicalIdmapPathFor) { ASSERT_EQ(Idmap::CanonicalIdmapPathFor("/foo", "/vendor/overlay/bar.apk"), "/foo/vendor@overlay@bar.apk@idmap"); @@ -47,11 +57,11 @@ 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(), 0x01U); + ASSERT_EQ(header->GetVersion(), 0x02U); ASSERT_EQ(header->GetTargetCrc(), 0x1234U); ASSERT_EQ(header->GetOverlayCrc(), 0x5678U); - ASSERT_EQ(header->GetTargetPath().to_string(), "target.apk"); - ASSERT_EQ(header->GetOverlayPath().to_string(), "overlay.apk"); + ASSERT_EQ(header->GetTargetPath().to_string(), "targetX.apk"); + ASSERT_EQ(header->GetOverlayPath().to_string(), "overlayX.apk"); } TEST(IdmapTests, FailToCreateIdmapHeaderFromBinaryStreamIfPathTooLong) { @@ -73,23 +83,8 @@ TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) { std::unique_ptr<const IdmapData::Header> header = IdmapData::Header::FromBinaryStream(stream); ASSERT_THAT(header, NotNull()); - ASSERT_EQ(header->GetTargetPackageId(), 0x7fU); - ASSERT_EQ(header->GetTypeCount(), 2U); -} - -TEST(IdmapTests, CreateIdmapDataResourceTypeFromBinaryStream) { - const size_t offset = 0x214; - std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset), - idmap_raw_data_len - offset); - std::istringstream stream(raw); - - std::unique_ptr<const IdmapData::TypeEntry> data = IdmapData::TypeEntry::FromBinaryStream(stream); - ASSERT_THAT(data, NotNull()); - ASSERT_EQ(data->GetTargetTypeId(), 0x02U); - ASSERT_EQ(data->GetOverlayTypeId(), 0x02U); - ASSERT_EQ(data->GetEntryCount(), 1U); - ASSERT_EQ(data->GetEntryOffset(), 0U); - ASSERT_EQ(data->GetEntry(0), 0U); + ASSERT_EQ(header->GetTargetEntryCount(), 0x03); + ASSERT_EQ(header->GetOverlayEntryCount(), 0x03); } TEST(IdmapTests, CreateIdmapDataFromBinaryStream) { @@ -100,24 +95,21 @@ TEST(IdmapTests, CreateIdmapDataFromBinaryStream) { std::unique_ptr<const IdmapData> data = IdmapData::FromBinaryStream(stream); ASSERT_THAT(data, NotNull()); - ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU); - ASSERT_EQ(data->GetHeader()->GetTypeCount(), 2U); - const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries(); - ASSERT_EQ(types.size(), 2U); - - ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U); - ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x02U); - ASSERT_EQ(types[0]->GetEntryCount(), 1U); - ASSERT_EQ(types[0]->GetEntryOffset(), 0U); - ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); - - ASSERT_EQ(types[1]->GetTargetTypeId(), 0x03U); - ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x03U); - ASSERT_EQ(types[1]->GetEntryCount(), 3U); - ASSERT_EQ(types[1]->GetEntryOffset(), 3U); - ASSERT_EQ(types[1]->GetEntry(0), 0x0000U); - ASSERT_EQ(types[1]->GetEntry(1), kNoEntry); - ASSERT_EQ(types[1]->GetEntry(2), 0x0001U); + + const auto& target_entries = data->GetTargetEntries(); + ASSERT_EQ(target_entries.size(), 3U); + ASSERT_TARGET_ENTRY(target_entries[0], 0x7f020000, 0x01 /* Res_value::TYPE_REFERENCE */, + 0x7f020000); + ASSERT_TARGET_ENTRY(target_entries[1], 0x7f030000, 0x01 /* Res_value::TYPE_REFERENCE */, + 0x7f030000); + ASSERT_TARGET_ENTRY(target_entries[2], 0x7f030002, 0x01 /* Res_value::TYPE_REFERENCE */, + 0x7f030001); + + const auto& overlay_entries = data->GetOverlayEntries(); + ASSERT_EQ(target_entries.size(), 3U); + ASSERT_OVERLAY_ENTRY(overlay_entries[0], 0x7f020000, 0x7f020000); + ASSERT_OVERLAY_ENTRY(overlay_entries[1], 0x7f030000, 0x7f030000); + ASSERT_OVERLAY_ENTRY(overlay_entries[2], 0x7f030001, 0x7f030002); } TEST(IdmapTests, CreateIdmapFromBinaryStream) { @@ -130,34 +122,29 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) { ASSERT_THAT(idmap->GetHeader(), NotNull()); ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U); - ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x01U); + ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x02U); ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x1234U); ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x5678U); - ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), "target.apk"); - ASSERT_EQ(idmap->GetHeader()->GetOverlayPath().to_string(), "overlay.apk"); + ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), "targetX.apk"); + ASSERT_EQ(idmap->GetHeader()->GetOverlayPath().to_string(), "overlayX.apk"); const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData(); ASSERT_EQ(dataBlocks.size(), 1U); const std::unique_ptr<const IdmapData>& data = dataBlocks[0]; - ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU); - ASSERT_EQ(data->GetHeader()->GetTypeCount(), 2U); - const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries(); - ASSERT_EQ(types.size(), 2U); - - ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U); - ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x02U); - ASSERT_EQ(types[0]->GetEntryCount(), 1U); - ASSERT_EQ(types[0]->GetEntryOffset(), 0U); - ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); - - ASSERT_EQ(types[1]->GetTargetTypeId(), 0x03U); - ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x03U); - ASSERT_EQ(types[1]->GetEntryCount(), 3U); - ASSERT_EQ(types[1]->GetEntryOffset(), 3U); - ASSERT_EQ(types[1]->GetEntry(0), 0x0000U); - ASSERT_EQ(types[1]->GetEntry(1), kNoEntry); - ASSERT_EQ(types[1]->GetEntry(2), 0x0001U); + ASSERT_THAT(data, NotNull()); + + const auto& target_entries = data->GetTargetEntries(); + ASSERT_EQ(target_entries.size(), 3U); + ASSERT_TARGET_ENTRY(target_entries[0], 0x7f020000, Res_value::TYPE_REFERENCE, 0x7f020000); + ASSERT_TARGET_ENTRY(target_entries[1], 0x7f030000, Res_value::TYPE_REFERENCE, 0x7f030000); + ASSERT_TARGET_ENTRY(target_entries[2], 0x7f030002, Res_value::TYPE_REFERENCE, 0x7f030001); + + const auto& overlay_entries = data->GetOverlayEntries(); + ASSERT_EQ(target_entries.size(), 3U); + ASSERT_OVERLAY_ENTRY(overlay_entries[0], 0x7f020000, 0x7f020000); + ASSERT_OVERLAY_ENTRY(overlay_entries[1], 0x7f030000, 0x7f030000); + ASSERT_OVERLAY_ENTRY(overlay_entries[2], 0x7f030001, 0x7f030002); } TEST(IdmapTests, GracefullyFailToCreateIdmapFromCorruptBinaryStream) { @@ -169,300 +156,140 @@ TEST(IdmapTests, GracefullyFailToCreateIdmapFromCorruptBinaryStream) { ASSERT_FALSE(result); } -void CreateIdmap(const StringPiece& target_apk_path, const StringPiece& overlay_apk_path, - const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, - std::unique_ptr<const Idmap>* out_idmap) { - std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path.to_string()); +TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) { + std::string target_apk_path = GetTestDataPath() + "/target/target.apk"; + std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay.apk"; + + std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path); ASSERT_THAT(target_apk, NotNull()); - std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path.to_string()); + std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); ASSERT_THAT(overlay_apk, NotNull()); - auto result = - Idmap::FromApkAssets(*target_apk, *overlay_apk, fulfilled_policies, enforce_overlayable); - *out_idmap = result ? std::move(*result) : nullptr; -} - -TEST(IdmapTests, CreateIdmapFromApkAssets) { - std::unique_ptr<const Idmap> idmap; - std::string target_apk_path = GetTestDataPath() + "/target/target.apk"; - std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay.apk"; - CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_PUBLIC, - /* enforce_overlayable */ true, &idmap); + auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC, + /* enforce_overlayable */ true); + ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage(); + auto& idmap = *idmap_result; + ASSERT_THAT(idmap, NotNull()); ASSERT_THAT(idmap->GetHeader(), NotNull()); ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U); - ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x01U); + ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x02U); ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x76a20829); ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xc054fb26); ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path); ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path); - ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path); - - const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData(); - ASSERT_EQ(dataBlocks.size(), 1U); - - const std::unique_ptr<const IdmapData>& data = dataBlocks[0]; - - ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU); - ASSERT_EQ(data->GetHeader()->GetTypeCount(), 2U); - - const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries(); - ASSERT_EQ(types.size(), 2U); - - ASSERT_EQ(types[0]->GetTargetTypeId(), 0x01U); - ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U); - ASSERT_EQ(types[0]->GetEntryCount(), 1U); - ASSERT_EQ(types[0]->GetEntryOffset(), 0U); - ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); - - ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U); - ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U); - ASSERT_EQ(types[1]->GetEntryCount(), 4U); - ASSERT_EQ(types[1]->GetEntryOffset(), 12U); - ASSERT_EQ(types[1]->GetEntry(0), 0x0000U); - ASSERT_EQ(types[1]->GetEntry(1), kNoEntry); - ASSERT_EQ(types[1]->GetEntry(2), 0x0001U); - ASSERT_EQ(types[1]->GetEntry(3), 0x0002U); } -// Overlays should abide by all overlayable restrictions if enforcement of overlayable is enabled. -TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublic) { - std::unique_ptr<const Idmap> idmap; - std::string target_apk_path = GetTestDataPath() + "/target/target.apk"; - std::string overlay_apk_path = GetTestDataPath() + "/system-overlay/system-overlay.apk"; - CreateIdmap(target_apk_path, overlay_apk_path, - PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC, - /* enforce_overlayable */ true, &idmap); - ASSERT_THAT(idmap, NotNull()); - - const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData(); - ASSERT_EQ(dataBlocks.size(), 1U); - - const std::unique_ptr<const IdmapData>& data = dataBlocks[0]; - - ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU); - ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U); - - const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries(); - ASSERT_EQ(types.size(), 1U); - - ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U); - ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U); - ASSERT_EQ(types[0]->GetEntryCount(), 4U); - ASSERT_EQ(types[0]->GetEntryOffset(), 8U); - ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/policy_public - ASSERT_EQ(types[0]->GetEntry(1), kNoEntry); // string/policy_signature - ASSERT_EQ(types[0]->GetEntry(2), 0x0001U); // string/policy_system - ASSERT_EQ(types[0]->GetEntry(3), 0x0002U); // string/policy_system_vendor -} - -TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySignature) { - std::unique_ptr<const Idmap> idmap; - std::string target_apk_path = GetTestDataPath() + "/target/target.apk"; - std::string overlay_apk_path = GetTestDataPath() + "/signature-overlay/signature-overlay.apk"; - CreateIdmap(target_apk_path, overlay_apk_path, - PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_SIGNATURE, - /* enforce_overlayable */ true, &idmap); - ASSERT_THAT(idmap, NotNull()); - - const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData(); - ASSERT_EQ(dataBlocks.size(), 1U); - - const std::unique_ptr<const IdmapData>& data = dataBlocks[0]; - - ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU); - ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U); - - const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries(); - ASSERT_EQ(types.size(), 1U); - - ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U); - ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U); - ASSERT_EQ(types[0]->GetEntryCount(), 1U); - ASSERT_EQ(types[0]->GetEntryOffset(), 9U); - ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/policy_signature -} - -// Overlays should abide by all overlayable restrictions if enforcement of overlayable is enabled. -TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) { - std::unique_ptr<const Idmap> idmap; - std::string target_apk_path = GetTestDataPath() + "/target/target.apk"; - std::string overlay_apk_path = - GetTestDataPath() + "/system-overlay-invalid/system-overlay-invalid.apk"; - CreateIdmap(target_apk_path, overlay_apk_path, - PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC, - /* enforce_overlayable */ true, &idmap); - ASSERT_THAT(idmap, NotNull()); - - const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData(); - ASSERT_EQ(dataBlocks.size(), 1U); +Result<std::unique_ptr<const IdmapData>> TestIdmapDataFromApkAssets( + const android::StringPiece& local_target_apk_path, + const android::StringPiece& local_overlay_apk_path, const OverlayManifestInfo& overlay_info, + const PolicyBitmask& fulfilled_policies, bool enforce_overlayable) { + const std::string target_apk_path(GetTestDataPath() + local_target_apk_path.data()); + std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path); + if (!target_apk) { + return Error(R"(Failed to load target apk "%s")", target_apk_path.data()); + } - const std::unique_ptr<const IdmapData>& data = dataBlocks[0]; + const std::string overlay_apk_path(GetTestDataPath() + local_overlay_apk_path.data()); + std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); + if (!overlay_apk) { + return Error(R"(Failed to load overlay apk "%s")", overlay_apk_path.data()); + } - ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU); - ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U); + auto mapping = ResourceMapping::FromApkAssets(*target_apk, *overlay_apk, overlay_info, + fulfilled_policies, enforce_overlayable); - const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries(); - ASSERT_EQ(types.size(), 1U); + if (!mapping) { + return mapping.GetError(); + } - ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U); - ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U); - ASSERT_EQ(types[0]->GetEntryCount(), 4U); - ASSERT_EQ(types[0]->GetEntryOffset(), 8U); - ASSERT_EQ(types[0]->GetEntry(0), 0x0005U); // string/policy_public - ASSERT_EQ(types[0]->GetEntry(1), kNoEntry); // string/policy_signature - ASSERT_EQ(types[0]->GetEntry(2), 0x0007U); // string/policy_system - ASSERT_EQ(types[0]->GetEntry(3), 0x0008U); // string/policy_system_vendor + return IdmapData::FromResourceMapping(*mapping); } -// Overlays should ignore all overlayable restrictions if enforcement of overlayable is disabled. -TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) { - std::unique_ptr<const Idmap> idmap; +TEST(IdmapTests, CreateIdmapDataFromApkAssets) { std::string target_apk_path = GetTestDataPath() + "/target/target.apk"; - std::string overlay_apk_path = - GetTestDataPath() + "/system-overlay-invalid/system-overlay-invalid.apk"; - CreateIdmap(target_apk_path, overlay_apk_path, - PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC, - /* enforce_overlayable */ false, &idmap); - ASSERT_THAT(idmap, NotNull()); - - const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData(); - ASSERT_EQ(dataBlocks.size(), 1U); + std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay.apk"; - const std::unique_ptr<const IdmapData>& data = dataBlocks[0]; + std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path); + ASSERT_THAT(target_apk, NotNull()); - ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU); - ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U); - - const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries(); - ASSERT_EQ(types.size(), 1U); - - ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U); - ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U); - ASSERT_EQ(types[0]->GetEntryCount(), 9U); - ASSERT_EQ(types[0]->GetEntryOffset(), 3U); - ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/not_overlayable - ASSERT_EQ(types[0]->GetEntry(1), 0x0001U); // string/policy_odm - ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_oem - ASSERT_EQ(types[0]->GetEntry(3), 0x0003U); // string/other - ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/policy_product - ASSERT_EQ(types[0]->GetEntry(5), 0x0005U); // string/policy_public - ASSERT_EQ(types[0]->GetEntry(6), 0x0006U); // string/policy_signature - ASSERT_EQ(types[0]->GetEntry(7), 0x0007U); // string/policy_system - ASSERT_EQ(types[0]->GetEntry(8), 0x0008U); // string/policy_system_vendor -} + std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); + ASSERT_THAT(overlay_apk, NotNull()); -// Overlays that do not specify a target <overlayable> can overlay resources defined as overlayable. -TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsNoDefinedOverlayableAndNoTargetName) { - std::unique_ptr<const Idmap> idmap; - std::string target_apk_path = GetTestDataPath() + "/target/target-no-overlayable.apk"; - std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay-no-name.apk"; - CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_PUBLIC, - /* enforce_overlayable */ false, &idmap); + auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC, + /* enforce_overlayable */ true); + ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage(); + auto& idmap = *idmap_result; ASSERT_THAT(idmap, NotNull()); const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData(); ASSERT_EQ(dataBlocks.size(), 1U); const std::unique_ptr<const IdmapData>& data = dataBlocks[0]; + ASSERT_THAT(data, NotNull()); - ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU); - ASSERT_EQ(data->GetHeader()->GetTypeCount(), 2U); - - const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries(); - ASSERT_EQ(types.size(), 2U); - - ASSERT_EQ(types[0]->GetTargetTypeId(), 0x01U); - ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U); - ASSERT_EQ(types[0]->GetEntryCount(), 1U); - ASSERT_EQ(types[0]->GetEntryOffset(), 0U); - ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/int1 - - ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U); - ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U); - ASSERT_EQ(types[1]->GetEntryCount(), 4U); - ASSERT_EQ(types[1]->GetEntryOffset(), 12U); - ASSERT_EQ(types[1]->GetEntry(0), 0x0000U); // string/str1 - ASSERT_EQ(types[1]->GetEntry(1), kNoEntry); // string/str2 - ASSERT_EQ(types[1]->GetEntry(2), 0x0001U); // string/str3 - ASSERT_EQ(types[1]->GetEntry(3), 0x0002U); // string/str4 + const auto& target_entries = data->GetTargetEntries(); + ASSERT_EQ(target_entries.size(), 4U); + ASSERT_TARGET_ENTRY(target_entries[0], 0x7f010000, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f010000); + ASSERT_TARGET_ENTRY(target_entries[1], 0x7f02000c, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020000); + ASSERT_TARGET_ENTRY(target_entries[2], 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020001); + ASSERT_TARGET_ENTRY(target_entries[3], 0x7f02000f, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020002); + + const auto& overlay_entries = data->GetOverlayEntries(); + ASSERT_EQ(target_entries.size(), 4U); + ASSERT_OVERLAY_ENTRY(overlay_entries[0], 0x7f010000, 0x7f010000); + ASSERT_OVERLAY_ENTRY(overlay_entries[1], 0x7f020000, 0x7f02000c); + ASSERT_OVERLAY_ENTRY(overlay_entries[2], 0x7f020001, 0x7f02000e); + ASSERT_OVERLAY_ENTRY(overlay_entries[3], 0x7f020002, 0x7f02000f); } -// Overlays that are not pre-installed and are not signed with the same signature as the target -// cannot overlay packages that have not defined overlayable resources. -TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsDefaultPoliciesPublicFail) { - std::unique_ptr<const Idmap> idmap; - std::string target_apk_path = GetTestDataPath() + "/target/target-no-overlayable.apk"; - std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay-no-name.apk"; - CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_PUBLIC, - /* enforce_overlayable */ true, &idmap); - ASSERT_THAT(idmap, IsNull()); +TEST(IdmapTests, CreateIdmapDataDoNotRewriteNonOverlayResourceId) { + OverlayManifestInfo info{}; + info.target_package = "test.target"; + info.target_name = "TestResources"; + info.resource_mapping = 0x7f030002; // xml/overlays_different_packages + auto idmap_data = TestIdmapDataFromApkAssets("/target/target.apk", "/overlay/overlay.apk", info, + PolicyFlags::POLICY_PUBLIC, + /* enforce_overlayable */ false); + + ASSERT_TRUE(idmap_data) << idmap_data.GetErrorMessage(); + auto& data = *idmap_data; + + const auto& target_entries = data->GetTargetEntries(); + ASSERT_EQ(target_entries.size(), 2U); + ASSERT_TARGET_ENTRY(target_entries[0], 0x7f02000c, Res_value::TYPE_REFERENCE, + 0x0104000a); // string/str1 -> android:string/ok + ASSERT_TARGET_ENTRY(target_entries[1], 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, + 0x7f020001); // string/str3 -> string/str4 + + const auto& overlay_entries = data->GetOverlayEntries(); + ASSERT_EQ(overlay_entries.size(), 1U); + ASSERT_OVERLAY_ENTRY(overlay_entries[0], 0x7f020001, 0x7f02000e); // string/str3 <- string/str4 } -// Overlays that are pre-installed or are signed with the same signature as the target can overlay -// packages that have not defined overlayable resources. -TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsDefaultPolicies) { - std::unique_ptr<const Idmap> idmap; - std::string target_apk_path = GetTestDataPath() + "/target/target-no-overlayable.apk"; - std::string overlay_apk_path = - GetTestDataPath() + "/system-overlay-invalid/system-overlay-invalid.apk"; - - auto CheckEntries = [&]() -> void { - const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData(); - ASSERT_EQ(dataBlocks.size(), 1U); - - const std::unique_ptr<const IdmapData>& data = dataBlocks[0]; - ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU); - ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U); - - const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries(); - ASSERT_EQ(types.size(), 1U); - - ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U); - ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U); - ASSERT_EQ(types[0]->GetEntryCount(), 9U); - ASSERT_EQ(types[0]->GetEntryOffset(), 3U); - ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/not_overlayable - ASSERT_EQ(types[0]->GetEntry(1), 0x0001U); // string/policy_odm - ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_oem - ASSERT_EQ(types[0]->GetEntry(3), 0x0003U); // string/other - ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/policy_product - ASSERT_EQ(types[0]->GetEntry(5), 0x0005U); // string/policy_public - ASSERT_EQ(types[0]->GetEntry(6), 0x0006U); // string/policy_signature - ASSERT_EQ(types[0]->GetEntry(7), 0x0007U); // string/policy_system - ASSERT_EQ(types[0]->GetEntry(8), 0x0008U); // string/policy_system_vendor - }; - - CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_SIGNATURE, - /* enforce_overlayable */ true, &idmap); - ASSERT_THAT(idmap, NotNull()); - CheckEntries(); - - CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_PRODUCT_PARTITION, - /* enforce_overlayable */ true, &idmap); - ASSERT_THAT(idmap, NotNull()); - CheckEntries(); - - CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_SYSTEM_PARTITION, - /* enforce_overlayable */ true, &idmap); - ASSERT_THAT(idmap, NotNull()); - CheckEntries(); - - CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_VENDOR_PARTITION, - /* enforce_overlayable */ true, &idmap); - ASSERT_THAT(idmap, NotNull()); - CheckEntries(); - - CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_ODM_PARTITION, - /* enforce_overlayable */ true, &idmap); - ASSERT_THAT(idmap, NotNull()); - CheckEntries(); - - CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_OEM_PARTITION, - /* enforce_overlayable */ true, &idmap); - ASSERT_THAT(idmap, NotNull()); - CheckEntries(); +TEST(IdmapTests, CreateIdmapDataInlineResources) { + OverlayManifestInfo info{}; + info.target_package = "test.target"; + info.target_name = "TestResources"; + info.resource_mapping = 0x7f030000; // xml/overlays_inline + auto idmap_data = TestIdmapDataFromApkAssets("/target/target.apk", "/overlay/overlay.apk", info, + PolicyFlags::POLICY_PUBLIC, + /* enforce_overlayable */ false); + + ASSERT_TRUE(idmap_data) << idmap_data.GetErrorMessage(); + auto& data = *idmap_data; + + constexpr size_t overlay_string_pool_size = 8U; + const auto& target_entries = data->GetTargetEntries(); + ASSERT_EQ(target_entries.size(), 2U); + ASSERT_TARGET_ENTRY(target_entries[0], 0x7f010000, Res_value::TYPE_INT_DEC, + 73U); // integer/int1 -> 73 + ASSERT_TARGET_ENTRY(target_entries[1], 0x7f02000c, Res_value::TYPE_STRING, + overlay_string_pool_size + 0U); // string/str1 -> "Hello World" + + const auto& overlay_entries = data->GetOverlayEntries(); + ASSERT_EQ(overlay_entries.size(), 0U); } TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) { @@ -602,10 +429,6 @@ class TestVisitor : public Visitor { stream_ << "TestVisitor::visit(IdmapData::Header)" << std::endl; } - void visit(const IdmapData::TypeEntry& idmap ATTRIBUTE_UNUSED) override { - stream_ << "TestVisitor::visit(IdmapData::TypeEntry)" << std::endl; - } - private: std::ostream& stream_; }; @@ -622,12 +445,10 @@ TEST(IdmapTests, TestVisitor) { (*idmap)->accept(&visitor); ASSERT_EQ(test_stream.str(), - "TestVisitor::visit(Idmap)\n" "TestVisitor::visit(IdmapHeader)\n" - "TestVisitor::visit(IdmapData)\n" + "TestVisitor::visit(Idmap)\n" "TestVisitor::visit(IdmapData::Header)\n" - "TestVisitor::visit(IdmapData::TypeEntry)\n" - "TestVisitor::visit(IdmapData::TypeEntry)\n"); + "TestVisitor::visit(IdmapData)\n"); } } // namespace android::idmap2 diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp index c243d745e568..24f9845df87b 100644 --- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp +++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp @@ -47,11 +47,21 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) { (*idmap)->accept(&visitor); ASSERT_NE(stream.str().find("00000000: 504d4449 magic\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000004: 00000001 version\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("0000021c: 00000000 0x7f010000 -> 0x7f010000 integer/int1\n"), + ASSERT_NE(stream.str().find("0000000c: e3c188b6 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); } TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) { @@ -68,10 +78,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: 00000001 version\n"), std::string::npos); + ASSERT_NE(stream.str().find("00000004: 00000002 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("0000021c: 00000000 0x7f020000 -> 0x7f020000\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); } } // namespace android::idmap2 diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp index 1ef41de4410d..64304f64d22c 100644 --- a/cmds/idmap2/tests/ResourceMappingTests.cpp +++ b/cmds/idmap2/tests/ResourceMappingTests.cpp @@ -27,6 +27,7 @@ #include "gtest/gtest.h" #include "idmap2/ResourceMapping.h" +using android::Res_value; using android::idmap2::utils::ExtractOverlayManifestInfo; namespace android::idmap2 { @@ -109,14 +110,14 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsLegacy) { ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U); - ASSERT_RESULT(MappingExists(res, 0x7f010000, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000, - true /* rewrite */)); // integer/int1 - ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020000, - true /* rewrite */)); // string/str1 - ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001, - true /* rewrite */)); // string/str3 - ASSERT_RESULT(MappingExists(res, 0x7f02000f, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020002, - true /* rewrite */)); // string/str4 + ASSERT_RESULT(MappingExists(res, 0x7f010000, Res_value::TYPE_REFERENCE, 0x7f010000, + false /* rewrite */)); // integer/int1 + ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_REFERENCE, 0x7f020000, + false /* rewrite */)); // string/str1 + ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_REFERENCE, 0x7f020001, + false /* rewrite */)); // string/str3 + ASSERT_RESULT(MappingExists(res, 0x7f02000f, Res_value::TYPE_REFERENCE, 0x7f020002, + false /* rewrite */)); // string/str4 } TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) { @@ -131,15 +132,15 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) { ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U); - ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020002, + ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020002, true /* rewrite */)); // string/str1 -> string/str4 - ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020000, + ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020000, true /* rewrite */)); // string/str3 -> string/str1 - ASSERT_RESULT(MappingExists(res, 0x7f02000f, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001, + ASSERT_RESULT(MappingExists(res, 0x7f02000f, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020001, true /* rewrite */)); // string/str4 -> string/str3 } -TEST(ResourceMappingTests, DoNotRewriteNonResourceMapping) { +TEST(ResourceMappingTests, DoNotRewriteNonOverlayResourceId) { OverlayManifestInfo info{}; info.target_package = "test.target"; info.target_name = "TestResources"; @@ -152,9 +153,9 @@ TEST(ResourceMappingTests, DoNotRewriteNonResourceMapping) { auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U); ASSERT_EQ(res.GetOverlayToTargetMap().size(), 1U); - ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x0104000a, + ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_REFERENCE, 0x0104000a, false /* rewrite */)); // string/str1 -> android:string/ok - ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001, + ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020001, true /* rewrite */)); // string/str3 -> string/str4 } @@ -172,10 +173,10 @@ TEST(ResourceMappingTests, InlineResources) { auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U); ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U); - ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x03 /* Res_value::TYPE_STRING */, + ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_STRING, overlay_string_pool_size + 0U, false /* rewrite */)); // string/str1 -> "Hello World" - ASSERT_RESULT(MappingExists(res, 0x7f010000, 0x10 /* Res_value::TYPE_INT_DEC */, 73U, + ASSERT_RESULT(MappingExists(res, 0x7f010000, Res_value::TYPE_INT_DEC, 73U, false /* rewrite */)); // string/str1 -> "Hello World" } @@ -188,12 +189,12 @@ TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublic) { ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U); - ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000, - true /* rewrite */)); // string/policy_public - ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010001, - true /* rewrite */)); // string/policy_system - ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010002, - true /* rewrite */)); // string/policy_system_vendor + ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010000, + false /* rewrite */)); // string/policy_public + ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010001, + false /* rewrite */)); // string/policy_system + ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010002, + false /* rewrite */)); // string/policy_system_vendor } // Resources that are not declared as overlayable and resources that a protected by policies the @@ -207,12 +208,12 @@ TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) { ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U); - ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010005, - true /* rewrite */)); // string/policy_public - ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010007, - true /* rewrite */)); // string/policy_system - ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010008, - true /* rewrite */)); // string/policy_system_vendor + ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010005, + false /* rewrite */)); // string/policy_public + ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010007, + false /* rewrite */)); // string/policy_system + ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010008, + false /* rewrite */)); // string/policy_system_vendor } // Resources that are not declared as overlayable and resources that a protected by policies the @@ -227,24 +228,24 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnore ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 9U); - ASSERT_RESULT(MappingExists(res, 0x7f020003, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000, - true /* rewrite */)); // string/not_overlayable - ASSERT_RESULT(MappingExists(res, 0x7f020004, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010001, - true /* rewrite */)); // string/other - ASSERT_RESULT(MappingExists(res, 0x7f020005, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010002, - true /* rewrite */)); // string/policy_odm - ASSERT_RESULT(MappingExists(res, 0x7f020006, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010003, - true /* rewrite */)); // string/policy_oem - ASSERT_RESULT(MappingExists(res, 0x7f020007, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010004, - true /* rewrite */)); // string/policy_product - ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010005, - true /* rewrite */)); // string/policy_public - ASSERT_RESULT(MappingExists(res, 0x7f020009, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010006, - true /* rewrite */)); // string/policy_signature - ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010007, - true /* rewrite */)); // string/policy_system - ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010008, - true /* rewrite */)); // string/policy_system_vendor + ASSERT_RESULT(MappingExists(res, 0x7f020003, Res_value::TYPE_REFERENCE, 0x7f010000, + false /* rewrite */)); // string/not_overlayable + ASSERT_RESULT(MappingExists(res, 0x7f020004, Res_value::TYPE_REFERENCE, 0x7f010001, + false /* rewrite */)); // string/other + ASSERT_RESULT(MappingExists(res, 0x7f020005, Res_value::TYPE_REFERENCE, 0x7f010002, + false /* rewrite */)); // string/policy_odm + ASSERT_RESULT(MappingExists(res, 0x7f020006, Res_value::TYPE_REFERENCE, 0x7f010003, + false /* rewrite */)); // string/policy_oem + ASSERT_RESULT(MappingExists(res, 0x7f020007, Res_value::TYPE_REFERENCE, 0x7f010004, + false /* rewrite */)); // string/policy_product + ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010005, + false /* rewrite */)); // string/policy_public + ASSERT_RESULT(MappingExists(res, 0x7f020009, Res_value::TYPE_REFERENCE, 0x7f010006, + false /* rewrite */)); // string/policy_signature + ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010007, + false /* rewrite */)); // string/policy_system + ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010008, + false /* rewrite */)); // string/policy_system_vendor } // Overlays that do not target an <overlayable> tag can overlay resources defined within any @@ -257,14 +258,14 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTarget ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U); - ASSERT_RESULT(MappingExists(res, 0x7f010000, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000, - true /* rewrite */)); // integer/int1 - ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020000, - true /* rewrite */)); // string/str1 - ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001, - true /* rewrite */)); // string/str3 - ASSERT_RESULT(MappingExists(res, 0x7f02000f, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020002, - true /* rewrite */)); // string/str4 + ASSERT_RESULT(MappingExists(res, 0x7f010000, Res_value::TYPE_REFERENCE, 0x7f010000, + false /* rewrite */)); // integer/int1 + ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_REFERENCE, 0x7f020000, + false /* rewrite */)); // string/str1 + ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_REFERENCE, 0x7f020001, + false /* rewrite */)); // string/str3 + ASSERT_RESULT(MappingExists(res, 0x7f02000f, Res_value::TYPE_REFERENCE, 0x7f020002, + false /* rewrite */)); // string/str4 } // Overlays that are neither pre-installed nor signed with the same signature as the target cannot @@ -291,24 +292,24 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 9U); - ASSERT_RESULT(MappingExists(res, 0x7f020003, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000, - true /* rewrite */)); // string/not_overlayable - ASSERT_RESULT(MappingExists(res, 0x7f020004, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010001, - true /* rewrite */)); // string/other - ASSERT_RESULT(MappingExists(res, 0x7f020005, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010002, - true /* rewrite */)); // string/policy_odm - ASSERT_RESULT(MappingExists(res, 0x7f020006, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010003, - true /* rewrite */)); // string/policy_oem - ASSERT_RESULT(MappingExists(res, 0x7f020007, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010004, - true /* rewrite */)); // string/policy_product - ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010005, - true /* rewrite */)); // string/policy_public - ASSERT_RESULT(MappingExists(res, 0x7f020009, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010006, - true /* rewrite */)); // string/policy_signature - ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010007, - true /* rewrite */)); // string/policy_system - ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010008, - true /* rewrite */)); // string/policy_system_vendor + ASSERT_RESULT(MappingExists(res, 0x7f020003, Res_value::TYPE_REFERENCE, 0x7f010000, + false /* rewrite */)); // string/not_overlayable + ASSERT_RESULT(MappingExists(res, 0x7f020004, Res_value::TYPE_REFERENCE, 0x7f010001, + false /* rewrite */)); // string/other + ASSERT_RESULT(MappingExists(res, 0x7f020005, Res_value::TYPE_REFERENCE, 0x7f010002, + false /* rewrite */)); // string/policy_odm + ASSERT_RESULT(MappingExists(res, 0x7f020006, Res_value::TYPE_REFERENCE, 0x7f010003, + false /* rewrite */)); // string/policy_oem + ASSERT_RESULT(MappingExists(res, 0x7f020007, Res_value::TYPE_REFERENCE, 0x7f010004, + false /* rewrite */)); // string/policy_product + ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010005, + false /* rewrite */)); // string/policy_public + ASSERT_RESULT(MappingExists(res, 0x7f020009, Res_value::TYPE_REFERENCE, 0x7f010006, + false /* rewrite */)); // string/policy_signature + ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010007, + false /* rewrite */)); // string/policy_system + ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010008, + false /* rewrite */)); // string/policy_system_vendor }; CheckEntries(PolicyFlags::POLICY_SIGNATURE); diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h index a7c2f284e7c5..8868b5376796 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 - 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, // 0x8: target crc 0x34, 0x12, 0x00, 0x00, @@ -38,8 +38,8 @@ const unsigned char idmap_raw_data[] = { // 0xc: overlay crc 0x78, 0x56, 0x00, 0x00, - // 0x10: target path "target.apk" - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x61, 0x70, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // 0x10: target path "targetX.apk" + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x58, 0x2e, 0x61, 0x70, 0x6b, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -56,8 +56,8 @@ 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, - // 0x110: overlay path "overlay.apk" - 0x6f, 0x76, 0x65, 0x72, 0x6c, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, + // 0x110: overlay path "overlayX.apk" + 0x6f, 0x76, 0x65, 0x72, 0x6c, 0x61, 0x79, 0x58, 0x2e, 0x61, 0x70, 0x6b, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -75,49 +75,63 @@ const unsigned char idmap_raw_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DATA HEADER - // 0x210: target package id - 0x7f, 0x00, + // 0x210: target_package_id + 0x7f, - // 0x212: types count - 0x02, 0x00, + // 0x211: overlay_package_id + 0x7f, - // DATA BLOCK - // 0x214: target type - 0x02, 0x00, + // 0x212: target_entry_count + 0x03, 0x00, 0x00, 0x00, - // 0x216: overlay type - 0x02, 0x00, + // 0x216: overlay_entry_count + 0x03, 0x00, 0x00, 0x00, - // 0x218: entry count - 0x01, 0x00, - - // 0x21a: entry offset - 0x00, 0x00, + // 0x21a: string_pool_offset + 0x00, 0x00, 0x00, 0x00, - // 0x21c: entries + // 0x21e: string_pool_byte_length 0x00, 0x00, 0x00, 0x00, - // DATA BLOCK - // 0x220: target type - 0x03, 0x00, + // TARGET ENTRIES + // 0x222: 0x7f020000 + 0x00, 0x00, 0x02, 0x7f, - // 0x222: overlay type - 0x03, 0x00, + // 0x226: TYPE_REFERENCE + 0x01, - // 0x224: entry count - 0x03, 0x00, + // 0x227: 0x7f020000 + 0x00, 0x00, 0x02, 0x7f, - // 0x226: entry offset - 0x03, 0x00, + // 0x22b: 0x7f030000 + 0x00, 0x00, 0x03, 0x7f, - // 0x228, 0x22c, 0x230: entries - 0x00, 0x00, 0x00, 0x00, + // 0x22f: TYPE_REFERENCE + 0x01, + + // 0x230: 0x7f030000 + 0x00, 0x00, 0x03, 0x7f, + + // 0x234: 0x7f030002 + 0x02, 0x00, 0x03, 0x7f, + + // 0x238: TYPE_REFERENCE + 0x01, + + // 0x239: 0x7f030001 + 0x01, 0x00, 0x03, 0x7f, + + // OVERLAY ENTRIES + // 0x23d: 0x7f020000 -> 0x7f020000 + 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f, - 0xff, 0xff, 0xff, 0xff, + // 0x245: 0x7f030000 -> 0x7f030000 + 0x00, 0x00, 0x03, 0x7f, 0x00, 0x00, 0x03, 0x7f, - 0x01, 0x00, 0x00, 0x00}; + // 0x24d: 0x7f030001 -> 0x7f030002 + 0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f}; -const unsigned int idmap_raw_data_len = 565; +const unsigned int idmap_raw_data_len = 0x255; std::string GetTestDataPath(); diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index c8ace90e6515..2efa65a009e1 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 = 0x00000001u; +constexpr const static uint32_t kIdmapCurrentVersion = 0x00000002u; /** * In C++11, char16_t is defined as *at least* 16 bits. We do a lot of |