Merge "idmap2: add debug information to idmap file format"

This commit is contained in:
TreeHugger Robot
2019-12-20 14:38:36 +00:00
committed by Android (Google) Code Review
19 changed files with 280 additions and 92 deletions

View File

@@ -15,4 +15,4 @@
set noparent
linelength=100
root=..
filter=+build/include_alpha
filter=+build/include_alpha,-runtime/references,-build/c++

View File

@@ -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_;
};

View File

@@ -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);

View File

@@ -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_

View File

@@ -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_;

View File

@@ -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_;

View File

@@ -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) {

View File

@@ -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,11 +115,17 @@ 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)};
}

View File

@@ -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_) {

View File

@@ -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)

View File

@@ -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();

View File

@@ -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();

View File

@@ -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("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("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("00000249: 7f020000 overlay id\n"), std::string::npos);
ASSERT_NE(stream.str().find("0000024d: 7f020000 target id\n"), std::string::npos);
}
} // namespace android::idmap2

View File

@@ -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,

View File

@@ -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();

View File

@@ -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);

View File

@@ -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 {