Merge changes I1d3e5e66,I86b869af,Iab4d3902,I645ee722 am: 72864d2930
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1461087 Change-Id: I573b7ca2340c71afe3be78ab92e91f37a4266695
This commit is contained in:
@@ -20,6 +20,8 @@
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <binder/BinderService.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "android/os/BnIdmap2.h"
|
||||
|
||||
namespace android::os {
|
||||
|
||||
@@ -36,12 +36,11 @@ class BinaryStreamVisitor : public Visitor {
|
||||
void visit(const IdmapData::Header& header) 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 WriteString256(const StringPiece& value);
|
||||
void WriteString(const std::string& value);
|
||||
void WriteString(const StringPiece& value);
|
||||
std::ostream& stream_;
|
||||
};
|
||||
|
||||
|
||||
@@ -17,48 +17,45 @@
|
||||
/*
|
||||
* # idmap file format (current version)
|
||||
*
|
||||
* idmap := header data*
|
||||
* 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 := 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>
|
||||
* string256 := <uint8_t>[256]
|
||||
* target_crc := <uint32_t>
|
||||
* target_package_id := <uint16_t>
|
||||
* target_type := <uint16_t>
|
||||
* types_count := <uint16_t>
|
||||
* version := <uint32_t>
|
||||
* idmap := header data*
|
||||
* header := magic version target_crc overlay_crc fulfilled_policies
|
||||
* enforce_overlayable target_path overlay_path debug_info
|
||||
* data := data_header target_entry* target_inline_entry* overlay_entry*
|
||||
* string_pool
|
||||
* data_header := target_package_id overlay_package_id padding(2) target_entry_count
|
||||
* target_inline_entry_count overlay_entry_count string_pool_index
|
||||
* target_entry := target_id overlay_id
|
||||
* target_inline_entry := target_id Res_value::size padding(1) Res_value::type
|
||||
* Res_value::value
|
||||
* overlay_entry := overlay_id target_id
|
||||
*
|
||||
*
|
||||
* # 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.
|
||||
*
|
||||
* ## v3
|
||||
* - Add 'debug' block to IdmapHeader.
|
||||
* debug_info := string
|
||||
* enforce_overlayable := <uint32_t>
|
||||
* fulfilled_policies := <uint32_t>
|
||||
* magic := <uint32_t>
|
||||
* overlay_crc := <uint32_t>
|
||||
* overlay_entry_count := <uint32_t>
|
||||
* overlay_id := <uint32_t>
|
||||
* overlay_package_id := <uint8_t>
|
||||
* overlay_path := string256
|
||||
* padding(n) := <uint8_t>[n]
|
||||
* Res_value::size := <uint16_t>
|
||||
* Res_value::type := <uint8_t>
|
||||
* Res_value::value := <uint32_t>
|
||||
* string := <uint32_t> <uint8_t>+ padding(n)
|
||||
* string256 := <uint8_t>[256]
|
||||
* string_pool := string
|
||||
* string_pool_index := <uint32_t>
|
||||
* string_pool_length := <uint32_t>
|
||||
* target_crc := <uint32_t>
|
||||
* target_entry_count := <uint32_t>
|
||||
* target_inline_entry_count := <uint32_t>
|
||||
* target_id := <uint32_t>
|
||||
* target_package_id := <uint8_t>
|
||||
* target_path := string256
|
||||
* value_type := <uint8_t>
|
||||
* value_data := <uint32_t>
|
||||
* version := <uint32_t>
|
||||
*/
|
||||
|
||||
#ifndef IDMAP2_INCLUDE_IDMAP2_IDMAP_H_
|
||||
@@ -183,6 +180,10 @@ class IdmapData {
|
||||
return target_entry_count;
|
||||
}
|
||||
|
||||
inline uint32_t GetTargetInlineEntryCount() const {
|
||||
return target_entry_inline_count;
|
||||
}
|
||||
|
||||
inline uint32_t GetOverlayEntryCount() const {
|
||||
return overlay_entry_count;
|
||||
}
|
||||
@@ -191,19 +192,15 @@ class IdmapData {
|
||||
return string_pool_index_offset;
|
||||
}
|
||||
|
||||
inline uint32_t GetStringPoolLength() const {
|
||||
return string_pool_len;
|
||||
}
|
||||
|
||||
void accept(Visitor* v) const;
|
||||
|
||||
private:
|
||||
PackageId target_package_id_;
|
||||
PackageId overlay_package_id_;
|
||||
uint32_t target_entry_count;
|
||||
uint32_t target_entry_inline_count;
|
||||
uint32_t overlay_entry_count;
|
||||
uint32_t string_pool_index_offset;
|
||||
uint32_t string_pool_len;
|
||||
Header() = default;
|
||||
|
||||
friend Idmap;
|
||||
@@ -213,8 +210,12 @@ class IdmapData {
|
||||
|
||||
struct TargetEntry {
|
||||
ResourceId target_id;
|
||||
TargetValue::DataType data_type;
|
||||
TargetValue::DataValue data_value;
|
||||
ResourceId overlay_id;
|
||||
};
|
||||
|
||||
struct TargetInlineEntry {
|
||||
ResourceId target_id;
|
||||
TargetValue value;
|
||||
};
|
||||
|
||||
struct OverlayEntry {
|
||||
@@ -227,20 +228,24 @@ class IdmapData {
|
||||
static Result<std::unique_ptr<const IdmapData>> FromResourceMapping(
|
||||
const ResourceMapping& resource_mapping);
|
||||
|
||||
inline const std::unique_ptr<const Header>& GetHeader() const {
|
||||
const std::unique_ptr<const Header>& GetHeader() const {
|
||||
return header_;
|
||||
}
|
||||
|
||||
inline const std::vector<TargetEntry>& GetTargetEntries() const {
|
||||
const std::vector<TargetEntry>& GetTargetEntries() const {
|
||||
return target_entries_;
|
||||
}
|
||||
|
||||
inline const std::vector<OverlayEntry>& GetOverlayEntries() const {
|
||||
const std::vector<TargetInlineEntry>& GetTargetInlineEntries() const {
|
||||
return target_inline_entries_;
|
||||
}
|
||||
|
||||
const std::vector<OverlayEntry>& GetOverlayEntries() const {
|
||||
return overlay_entries_;
|
||||
}
|
||||
|
||||
inline const void* GetStringPoolData() const {
|
||||
return string_pool_.get();
|
||||
const std::string& GetStringPoolData() const {
|
||||
return string_pool_data_;
|
||||
}
|
||||
|
||||
void accept(Visitor* v) const;
|
||||
@@ -251,8 +256,9 @@ class IdmapData {
|
||||
|
||||
std::unique_ptr<const Header> header_;
|
||||
std::vector<TargetEntry> target_entries_;
|
||||
std::vector<TargetInlineEntry> target_inline_entries_;
|
||||
std::vector<OverlayEntry> overlay_entries_;
|
||||
std::unique_ptr<uint8_t[]> string_pool_;
|
||||
std::string string_pool_data_;
|
||||
|
||||
friend Idmap;
|
||||
DISALLOW_COPY_AND_ASSIGN(IdmapData);
|
||||
@@ -304,6 +310,10 @@ class Visitor {
|
||||
virtual void visit(const IdmapData::Header& header) = 0;
|
||||
};
|
||||
|
||||
inline size_t CalculatePadding(size_t data_length) {
|
||||
return (4 - (data_length % 4)) % 4;
|
||||
}
|
||||
|
||||
} // namespace android::idmap2
|
||||
|
||||
#endif // IDMAP2_INCLUDE_IDMAP2_IDMAP_H_
|
||||
|
||||
@@ -41,8 +41,9 @@ class PrettyPrintVisitor : public Visitor {
|
||||
|
||||
private:
|
||||
std::ostream& stream_;
|
||||
std::unique_ptr<const ApkAssets> target_apk_;
|
||||
AssetManager2 target_am_;
|
||||
AssetManager2 overlay_am_;
|
||||
std::vector<std::unique_ptr<const ApkAssets>> apk_assets_;
|
||||
};
|
||||
|
||||
} // namespace idmap2
|
||||
|
||||
@@ -45,11 +45,9 @@ class RawPrintVisitor : public Visitor {
|
||||
void print(uint16_t value, const char* fmt, ...);
|
||||
void print(uint32_t 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_;
|
||||
std::unique_ptr<const ApkAssets> target_apk_;
|
||||
std::unique_ptr<const ApkAssets> overlay_apk_;
|
||||
std::vector<std::unique_ptr<const ApkAssets>> apk_assets_;
|
||||
AssetManager2 target_am_;
|
||||
AssetManager2 overlay_am_;
|
||||
size_t offset_;
|
||||
|
||||
@@ -41,7 +41,7 @@ struct TargetValue {
|
||||
DataValue data_value;
|
||||
};
|
||||
|
||||
using TargetResourceMap = std::map<ResourceId, TargetValue>;
|
||||
using TargetResourceMap = std::map<ResourceId, std::variant<ResourceId, TargetValue>>;
|
||||
using OverlayResourceMap = std::map<ResourceId, ResourceId>;
|
||||
|
||||
class ResourceMapping {
|
||||
@@ -56,7 +56,7 @@ class ResourceMapping {
|
||||
bool enforce_overlayable, LogInfo& log_info);
|
||||
|
||||
// Retrieves the mapping of target resource id to overlay value.
|
||||
inline TargetResourceMap GetTargetToOverlayMap() const {
|
||||
inline const TargetResourceMap& GetTargetToOverlayMap() const {
|
||||
return target_map_;
|
||||
}
|
||||
|
||||
@@ -81,19 +81,24 @@ class ResourceMapping {
|
||||
}
|
||||
|
||||
// Retrieves the raw string pool data from the xml referenced in android:resourcesMap.
|
||||
inline const std::pair<const uint8_t*, uint32_t> GetStringPoolData() const {
|
||||
return std::make_pair(string_pool_data_.get(), string_pool_data_length_);
|
||||
inline const StringPiece GetStringPoolData() const {
|
||||
return StringPiece(reinterpret_cast<const char*>(string_pool_data_.get()),
|
||||
string_pool_data_length_);
|
||||
}
|
||||
|
||||
private:
|
||||
ResourceMapping() = default;
|
||||
|
||||
// Apps a mapping of target resource id to the type and value of the data that overlays the
|
||||
// target resource. The data_type is the runtime format of the data value (see
|
||||
// Res_value::dataType). If rewrite_overlay_reference is `true` then references to an overlay
|
||||
// Maps a target resource id to an overlay resource id.
|
||||
// If rewrite_overlay_reference is `true` then references to the overlay
|
||||
// resource should appear as a reference to its corresponding target resource at runtime.
|
||||
Result<Unit> AddMapping(ResourceId target_resource, ResourceId overlay_resource,
|
||||
bool rewrite_overlay_reference);
|
||||
|
||||
// Maps a target resource id to a data type and value combination.
|
||||
// The `data_type` is the runtime format of the data value (see Res_value::dataType).
|
||||
Result<Unit> AddMapping(ResourceId target_resource, TargetValue::DataType data_type,
|
||||
TargetValue::DataValue data_value, bool rewrite_overlay_reference);
|
||||
TargetValue::DataValue data_value);
|
||||
|
||||
// Removes the overlay value mapping for the target resource.
|
||||
void RemoveMapping(ResourceId target_resource);
|
||||
|
||||
@@ -24,10 +24,6 @@
|
||||
|
||||
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));
|
||||
}
|
||||
@@ -49,11 +45,11 @@ void BinaryStreamVisitor::WriteString256(const StringPiece& value) {
|
||||
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());
|
||||
void BinaryStreamVisitor::WriteString(const StringPiece& value) {
|
||||
// pad with null to nearest word boundary;
|
||||
size_t padding_size = CalculatePadding(value.size());
|
||||
Write32(value.size());
|
||||
stream_.write(value.data(), value.size());
|
||||
stream_.write("\0\0\0\0", padding_size);
|
||||
}
|
||||
|
||||
@@ -67,7 +63,7 @@ void BinaryStreamVisitor::visit(const IdmapHeader& header) {
|
||||
Write32(header.GetTargetCrc());
|
||||
Write32(header.GetOverlayCrc());
|
||||
Write32(header.GetFulfilledPolicies());
|
||||
Write8(static_cast<uint8_t>(header.GetEnforceOverlayable()));
|
||||
Write32(static_cast<uint8_t>(header.GetEnforceOverlayable()));
|
||||
WriteString256(header.GetTargetPath());
|
||||
WriteString256(header.GetOverlayPath());
|
||||
WriteString(header.GetDebugInfo());
|
||||
@@ -76,8 +72,16 @@ void BinaryStreamVisitor::visit(const IdmapHeader& header) {
|
||||
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);
|
||||
Write32(target_entry.overlay_id);
|
||||
}
|
||||
|
||||
static constexpr uint16_t kValueSize = 8U;
|
||||
for (const auto& target_entry : data.GetTargetInlineEntries()) {
|
||||
Write32(target_entry.target_id);
|
||||
Write16(kValueSize);
|
||||
Write8(0U); // padding
|
||||
Write8(target_entry.value.data_type);
|
||||
Write32(target_entry.value.data_value);
|
||||
}
|
||||
|
||||
for (const auto& overlay_entry : data.GetOverlayEntries()) {
|
||||
@@ -85,16 +89,18 @@ void BinaryStreamVisitor::visit(const IdmapData& data) {
|
||||
Write32(overlay_entry.target_id);
|
||||
}
|
||||
|
||||
Write(data.GetStringPoolData(), data.GetHeader()->GetStringPoolLength());
|
||||
WriteString(data.GetStringPoolData());
|
||||
}
|
||||
|
||||
void BinaryStreamVisitor::visit(const IdmapData::Header& header) {
|
||||
Write8(header.GetTargetPackageId());
|
||||
Write8(header.GetOverlayPackageId());
|
||||
Write8(0U); // padding
|
||||
Write8(0U); // padding
|
||||
Write32(header.GetTargetEntryCount());
|
||||
Write32(header.GetTargetInlineEntryCount());
|
||||
Write32(header.GetOverlayEntryCount());
|
||||
Write32(header.GetStringPoolIndexOffset());
|
||||
Write32(header.GetStringPoolLength());
|
||||
}
|
||||
|
||||
} // namespace android::idmap2
|
||||
|
||||
@@ -51,19 +51,19 @@ bool WARN_UNUSED Read8(std::istream& stream, uint8_t* out) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WARN_UNUSED Read32(std::istream& stream, uint32_t* out) {
|
||||
uint32_t value;
|
||||
if (stream.read(reinterpret_cast<char*>(&value), sizeof(uint32_t))) {
|
||||
*out = dtohl(value);
|
||||
bool WARN_UNUSED Read16(std::istream& stream, uint16_t* out) {
|
||||
uint16_t value;
|
||||
if (stream.read(reinterpret_cast<char*>(&value), sizeof(uint16_t))) {
|
||||
*out = dtohs(value);
|
||||
return true;
|
||||
}
|
||||
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);
|
||||
bool WARN_UNUSED Read32(std::istream& stream, uint32_t* out) {
|
||||
uint32_t value;
|
||||
if (stream.read(reinterpret_cast<char*>(&value), sizeof(uint32_t))) {
|
||||
*out = dtohl(value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -95,8 +95,11 @@ Result<std::string> ReadString(std::istream& stream) {
|
||||
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()));
|
||||
uint32_t padding_size = CalculatePadding(size);
|
||||
std::string padding(padding_size, '\0');
|
||||
if (!stream.read(padding.data(), padding_size)) {
|
||||
return Error("failed to read string padding of size %u", padding_size);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -112,16 +115,16 @@ Result<uint32_t> GetPackageCrc(const ZipFile& zip) {
|
||||
|
||||
std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& stream) {
|
||||
std::unique_ptr<IdmapHeader> idmap_header(new IdmapHeader());
|
||||
uint8_t enforce_overlayable;
|
||||
uint32_t enforce_overlayable;
|
||||
if (!Read32(stream, &idmap_header->magic_) || !Read32(stream, &idmap_header->version_) ||
|
||||
!Read32(stream, &idmap_header->target_crc_) || !Read32(stream, &idmap_header->overlay_crc_) ||
|
||||
!Read32(stream, &idmap_header->fulfilled_policies_) || !Read8(stream, &enforce_overlayable) ||
|
||||
!ReadString256(stream, idmap_header->target_path_) ||
|
||||
!Read32(stream, &idmap_header->fulfilled_policies_) ||
|
||||
!Read32(stream, &enforce_overlayable) || !ReadString256(stream, idmap_header->target_path_) ||
|
||||
!ReadString256(stream, idmap_header->overlay_path_)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
idmap_header->enforce_overlayable_ = static_cast<bool>(enforce_overlayable);
|
||||
idmap_header->enforce_overlayable_ = enforce_overlayable != 0U;
|
||||
|
||||
auto debug_str = ReadString(stream);
|
||||
if (!debug_str) {
|
||||
@@ -207,12 +210,13 @@ Result<Unit> IdmapHeader::IsUpToDate(const char* target_path, const char* overla
|
||||
std::unique_ptr<const IdmapData::Header> IdmapData::Header::FromBinaryStream(std::istream& stream) {
|
||||
std::unique_ptr<IdmapData::Header> idmap_data_header(new IdmapData::Header());
|
||||
|
||||
uint8_t padding;
|
||||
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) ||
|
||||
!Read8(stream, &idmap_data_header->overlay_package_id_) || !Read8(stream, &padding) ||
|
||||
!Read8(stream, &padding) || !Read32(stream, &idmap_data_header->target_entry_count) ||
|
||||
!Read32(stream, &idmap_data_header->target_entry_inline_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)) {
|
||||
!Read32(stream, &idmap_data_header->string_pool_index_offset)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -225,14 +229,27 @@ std::unique_ptr<const IdmapData> IdmapData::FromBinaryStream(std::istream& strea
|
||||
if (!data->header_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
if (!Read32(stream, &target_entry.target_id) || !Read32(stream, &target_entry.overlay_id)) {
|
||||
return nullptr;
|
||||
}
|
||||
data->target_entries_.emplace_back(target_entry);
|
||||
data->target_entries_.push_back(target_entry);
|
||||
}
|
||||
|
||||
// Read the mapping of target resource id to inline overlay values.
|
||||
uint8_t unused1;
|
||||
uint16_t unused2;
|
||||
for (size_t i = 0; i < data->header_->GetTargetInlineEntryCount(); i++) {
|
||||
TargetInlineEntry target_entry{};
|
||||
if (!Read32(stream, &target_entry.target_id) || !Read16(stream, &unused2) ||
|
||||
!Read8(stream, &unused1) || !Read8(stream, &target_entry.value.data_type) ||
|
||||
!Read32(stream, &target_entry.value.data_value)) {
|
||||
return nullptr;
|
||||
}
|
||||
data->target_inline_entries_.push_back(target_entry);
|
||||
}
|
||||
|
||||
// Read the mapping of overlay resource id to target resource id.
|
||||
@@ -245,9 +262,11 @@ std::unique_ptr<const IdmapData> IdmapData::FromBinaryStream(std::istream& strea
|
||||
}
|
||||
|
||||
// Read raw string pool bytes.
|
||||
if (!ReadBuffer(stream, &data->string_pool_, data->header_->string_pool_len)) {
|
||||
auto string_pool_data = ReadString(stream);
|
||||
if (!string_pool_data) {
|
||||
return nullptr;
|
||||
}
|
||||
data->string_pool_data_ = std::move(*string_pool_data);
|
||||
|
||||
return std::move(data);
|
||||
}
|
||||
@@ -290,27 +309,28 @@ Result<std::unique_ptr<const IdmapData>> IdmapData::FromResourceMapping(
|
||||
}
|
||||
|
||||
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});
|
||||
data->string_pool_data_ = resource_mapping.GetStringPoolData().to_string();
|
||||
for (const auto& mapping : resource_mapping.GetTargetToOverlayMap()) {
|
||||
if (auto overlay_resource = std::get_if<ResourceId>(&mapping.second)) {
|
||||
data->target_entries_.push_back({mapping.first, *overlay_resource});
|
||||
} else {
|
||||
data->target_inline_entries_.push_back(
|
||||
{mapping.first, std::get<TargetValue>(mapping.second)});
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& mappings : resource_mapping.GetOverlayToTargetMap()) {
|
||||
data->overlay_entries_.emplace_back(IdmapData::OverlayEntry{mappings.first, mappings.second});
|
||||
for (const auto& mapping : resource_mapping.GetOverlayToTargetMap()) {
|
||||
data->overlay_entries_.emplace_back(IdmapData::OverlayEntry{mapping.first, mapping.second});
|
||||
}
|
||||
|
||||
std::unique_ptr<IdmapData::Header> data_header(new IdmapData::Header());
|
||||
data_header->target_package_id_ = resource_mapping.GetTargetPackageId();
|
||||
data_header->overlay_package_id_ = resource_mapping.GetOverlayPackageId();
|
||||
data_header->target_entry_count = static_cast<uint32_t>(data->target_entries_.size());
|
||||
data_header->target_entry_inline_count =
|
||||
static_cast<uint32_t>(data->target_inline_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)};
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ void PrettyPrintVisitor::visit(const IdmapHeader& header) {
|
||||
stream_ << "Paths:" << std::endl
|
||||
<< TAB "target apk path : " << header.GetTargetPath() << std::endl
|
||||
<< TAB "overlay apk path : " << header.GetOverlayPath() << std::endl;
|
||||
|
||||
const std::string& debug = header.GetDebugInfo();
|
||||
if (!debug.empty()) {
|
||||
std::istringstream debug_stream(debug);
|
||||
@@ -48,10 +49,16 @@ void PrettyPrintVisitor::visit(const IdmapHeader& header) {
|
||||
}
|
||||
}
|
||||
|
||||
target_apk_ = ApkAssets::Load(header.GetTargetPath().to_string());
|
||||
if (target_apk_) {
|
||||
if (auto target_apk_ = ApkAssets::Load(header.GetTargetPath().to_string())) {
|
||||
target_am_.SetApkAssets({target_apk_.get()});
|
||||
apk_assets_.push_back(std::move(target_apk_));
|
||||
}
|
||||
|
||||
if (auto overlay_apk = ApkAssets::Load(header.GetOverlayPath().to_string())) {
|
||||
overlay_am_.SetApkAssets({overlay_apk.get()});
|
||||
apk_assets_.push_back(std::move(overlay_apk));
|
||||
}
|
||||
|
||||
stream_ << "Mapping:" << std::endl;
|
||||
}
|
||||
|
||||
@@ -59,34 +66,56 @@ void PrettyPrintVisitor::visit(const IdmapData::Header& header ATTRIBUTE_UNUSED)
|
||||
}
|
||||
|
||||
void PrettyPrintVisitor::visit(const IdmapData& data) {
|
||||
static constexpr const char* kUnknownResourceName = "???";
|
||||
|
||||
const bool target_package_loaded = !target_am_.GetApkAssets().empty();
|
||||
const ResStringPool string_pool(data.GetStringPoolData(),
|
||||
data.GetHeader()->GetStringPoolLength());
|
||||
const bool overlay_package_loaded = !overlay_am_.GetApkAssets().empty();
|
||||
|
||||
const ResStringPool string_pool(data.GetStringPoolData().data(), data.GetStringPoolData().size());
|
||||
const size_t string_pool_offset = data.GetHeader()->GetStringPoolIndexOffset();
|
||||
|
||||
for (auto& target_entry : data.GetTargetEntries()) {
|
||||
stream_ << TAB << 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
for (const auto& target_entry : data.GetTargetEntries()) {
|
||||
std::string target_name = kUnknownResourceName;
|
||||
if (target_package_loaded) {
|
||||
Result<std::string> name = utils::ResToTypeEntryName(target_am_, target_entry.target_id);
|
||||
if (name) {
|
||||
stream_ << " " << *name;
|
||||
if (auto name = utils::ResToTypeEntryName(target_am_, target_entry.target_id)) {
|
||||
target_name = *name;
|
||||
}
|
||||
}
|
||||
stream_ << std::endl;
|
||||
|
||||
std::string overlay_name = kUnknownResourceName;
|
||||
if (overlay_package_loaded) {
|
||||
if (auto name = utils::ResToTypeEntryName(overlay_am_, target_entry.overlay_id)) {
|
||||
overlay_name = *name;
|
||||
}
|
||||
}
|
||||
|
||||
stream_ << TAB
|
||||
<< base::StringPrintf("0x%08x -> 0x%08x (%s -> %s)", target_entry.target_id,
|
||||
target_entry.overlay_id, target_name.c_str(),
|
||||
overlay_name.c_str())
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
for (auto& target_entry : data.GetTargetInlineEntries()) {
|
||||
stream_ << TAB << base::StringPrintf("0x%08x -> ", target_entry.target_id)
|
||||
<< utils::DataTypeToString(target_entry.value.data_type);
|
||||
|
||||
size_t unused;
|
||||
if (target_entry.value.data_type == Res_value::TYPE_STRING) {
|
||||
auto str = string_pool.stringAt(target_entry.value.data_value - string_pool_offset, &unused);
|
||||
stream_ << " \"" << StringPiece16(str) << "\"";
|
||||
} else {
|
||||
stream_ << " " << base::StringPrintf("0x%08x", target_entry.value.data_value);
|
||||
}
|
||||
|
||||
std::string target_name = kUnknownResourceName;
|
||||
if (target_package_loaded) {
|
||||
if (auto name = utils::ResToTypeEntryName(target_am_, target_entry.target_id)) {
|
||||
target_name = *name;
|
||||
}
|
||||
}
|
||||
|
||||
stream_ << " (" << target_name << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,15 +30,6 @@
|
||||
using android::ApkAssets;
|
||||
using android::idmap2::policy::PoliciesToDebugString;
|
||||
|
||||
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 {
|
||||
|
||||
void RawPrintVisitor::visit(const Idmap& idmap ATTRIBUTE_UNUSED) {
|
||||
@@ -51,19 +42,24 @@ void RawPrintVisitor::visit(const IdmapHeader& header) {
|
||||
print(header.GetOverlayCrc(), "overlay crc");
|
||||
print(header.GetFulfilledPolicies(), "fulfilled policies: %s",
|
||||
PoliciesToDebugString(header.GetFulfilledPolicies()).c_str());
|
||||
print(static_cast<uint8_t>(header.GetEnforceOverlayable()), "enforce overlayable");
|
||||
print(static_cast<uint32_t>(header.GetEnforceOverlayable()), "enforce overlayable");
|
||||
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());
|
||||
uint32_t debug_info_size = header.GetDebugInfo().size();
|
||||
print(debug_info_size, "debug info size");
|
||||
print("...", debug_info_size + CalculatePadding(debug_info_size), "debug info");
|
||||
|
||||
auto target_apk_ = ApkAssets::Load(header.GetTargetPath().to_string());
|
||||
if (target_apk_) {
|
||||
target_am_.SetApkAssets({target_apk_.get()});
|
||||
apk_assets_.push_back(std::move(target_apk_));
|
||||
}
|
||||
|
||||
overlay_apk_ = ApkAssets::Load(header.GetOverlayPath().to_string());
|
||||
auto overlay_apk_ = ApkAssets::Load(header.GetOverlayPath().to_string());
|
||||
if (overlay_apk_) {
|
||||
overlay_am_.SetApkAssets({overlay_apk_.get()});
|
||||
apk_assets_.push_back(std::move(overlay_apk_));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,18 +78,44 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
|
||||
print(target_entry.target_id, "target id");
|
||||
}
|
||||
|
||||
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_package_loaded) {
|
||||
overlay_name = utils::ResToTypeEntryName(overlay_am_, target_entry.overlay_id);
|
||||
}
|
||||
if (overlay_name) {
|
||||
print(target_entry.data_value, "value: %s", overlay_name->c_str());
|
||||
print(target_entry.overlay_id, "overlay id: %s", overlay_name->c_str());
|
||||
} else {
|
||||
print(target_entry.data_value, "value");
|
||||
print(target_entry.overlay_id, "overlay id");
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& target_entry : data.GetTargetInlineEntries()) {
|
||||
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");
|
||||
}
|
||||
|
||||
print("...", sizeof(Res_value::size) + sizeof(Res_value::res0), "padding");
|
||||
|
||||
print(target_entry.value.data_type, "type: %s",
|
||||
utils::DataTypeToString(target_entry.value.data_type).data());
|
||||
|
||||
Result<std::string> overlay_name(Error(""));
|
||||
if (overlay_package_loaded &&
|
||||
(target_entry.value.data_value == Res_value::TYPE_REFERENCE ||
|
||||
target_entry.value.data_value == Res_value::TYPE_DYNAMIC_REFERENCE)) {
|
||||
overlay_name = utils::ResToTypeEntryName(overlay_am_, target_entry.value.data_value);
|
||||
}
|
||||
|
||||
if (overlay_name) {
|
||||
print(target_entry.value.data_value, "data: %s", overlay_name->c_str());
|
||||
} else {
|
||||
print(target_entry.value.data_value, "data");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,19 +143,19 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
uint32_t string_pool_size = data.GetStringPoolData().size();
|
||||
print(string_pool_size, "string pool size");
|
||||
print("...", string_pool_size + CalculatePadding(string_pool_size), "string pool");
|
||||
}
|
||||
|
||||
void RawPrintVisitor::visit(const IdmapData::Header& header) {
|
||||
print(header.GetTargetPackageId(), "target package id");
|
||||
print(header.GetOverlayPackageId(), "overlay package id");
|
||||
print("...", sizeof(Idmap_data_header::p0), "padding");
|
||||
print(header.GetTargetEntryCount(), "target entry count");
|
||||
print(header.GetTargetInlineEntryCount(), "target inline 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)
|
||||
@@ -190,17 +212,4 @@ void RawPrintVisitor::print(const std::string& value, size_t encoded_size, const
|
||||
offset_ += encoded_size;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
@@ -71,9 +71,9 @@ Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
|
||||
if (!target_package.DefinesOverlayable()) {
|
||||
return (sDefaultPolicies & fulfilled_policies) != 0
|
||||
? Result<Unit>({})
|
||||
: Error(
|
||||
"overlay must be preinstalled or signed with the same signature as the "
|
||||
"target");
|
||||
: Error("overlay must be preinstalled, signed with the same signature as the target,"
|
||||
" or signed with the same signature as the package referenced through"
|
||||
" <overlay-config-signature>.");
|
||||
}
|
||||
|
||||
const OverlayableInfo* overlayable_info = target_package.GetOverlayableInfo(target_resource);
|
||||
@@ -205,19 +205,14 @@ Result<ResourceMapping> ResourceMapping::CreateResourceMapping(const AssetManage
|
||||
overlay_resource->data += string_pool_offset;
|
||||
}
|
||||
|
||||
// Only rewrite resources defined within the overlay package to their corresponding target
|
||||
// resource ids at runtime.
|
||||
bool rewrite_overlay_reference =
|
||||
IsReference(overlay_resource->dataType)
|
||||
? overlay_package_id == EXTRACT_PACKAGE(overlay_resource->data)
|
||||
: false;
|
||||
|
||||
if (rewrite_overlay_reference) {
|
||||
overlay_resource->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
|
||||
if (IsReference(overlay_resource->dataType)) {
|
||||
// Only rewrite resources defined within the overlay package to their corresponding target
|
||||
// resource ids at runtime.
|
||||
bool rewrite_reference = overlay_package_id == EXTRACT_PACKAGE(overlay_resource->data);
|
||||
resource_mapping.AddMapping(target_id, overlay_resource->data, rewrite_reference);
|
||||
} else {
|
||||
resource_mapping.AddMapping(target_id, overlay_resource->dataType, overlay_resource->data);
|
||||
}
|
||||
|
||||
resource_mapping.AddMapping(target_id, overlay_resource->dataType, overlay_resource->data,
|
||||
rewrite_overlay_reference);
|
||||
}
|
||||
|
||||
return resource_mapping;
|
||||
@@ -246,9 +241,8 @@ Result<ResourceMapping> ResourceMapping::CreateResourceMappingLegacy(
|
||||
|
||||
// Retrieve the compile-time resource id of the target resource.
|
||||
target_resource = REWRITE_PACKAGE(target_resource, target_package_id);
|
||||
|
||||
resource_mapping.AddMapping(target_resource, Res_value::TYPE_REFERENCE, overlay_resid,
|
||||
/* rewrite_overlay_reference */ false);
|
||||
resource_mapping.AddMapping(target_resource, overlay_resid,
|
||||
false /* rewrite_overlay_reference */);
|
||||
}
|
||||
|
||||
return resource_mapping;
|
||||
@@ -396,9 +390,7 @@ OverlayResourceMap ResourceMapping::GetOverlayToTargetMap() const {
|
||||
return map;
|
||||
}
|
||||
|
||||
Result<Unit> ResourceMapping::AddMapping(ResourceId target_resource,
|
||||
TargetValue::DataType data_type,
|
||||
TargetValue::DataValue data_value,
|
||||
Result<Unit> ResourceMapping::AddMapping(ResourceId target_resource, ResourceId overlay_resource,
|
||||
bool rewrite_overlay_reference) {
|
||||
if (target_map_.find(target_resource) != target_map_.end()) {
|
||||
return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
|
||||
@@ -407,13 +399,26 @@ Result<Unit> ResourceMapping::AddMapping(ResourceId target_resource,
|
||||
// TODO(141485591): Ensure that the overlay type is compatible with the target type. If the
|
||||
// runtime types are not compatible, it could cause runtime crashes when the resource is resolved.
|
||||
|
||||
target_map_.insert(std::make_pair(target_resource, TargetValue{data_type, data_value}));
|
||||
target_map_.insert(std::make_pair(target_resource, overlay_resource));
|
||||
|
||||
if (rewrite_overlay_reference && IsReference(data_type)) {
|
||||
overlay_map_.insert(std::make_pair(data_value, target_resource));
|
||||
if (rewrite_overlay_reference) {
|
||||
overlay_map_.insert(std::make_pair(overlay_resource, target_resource));
|
||||
}
|
||||
return Unit{};
|
||||
}
|
||||
|
||||
Result<Unit> ResourceMapping::AddMapping(ResourceId target_resource,
|
||||
TargetValue::DataType data_type,
|
||||
TargetValue::DataValue data_value) {
|
||||
if (target_map_.find(target_resource) != target_map_.end()) {
|
||||
return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
|
||||
}
|
||||
|
||||
return Result<Unit>({});
|
||||
// TODO(141485591): Ensure that the overlay type is compatible with the target type. If the
|
||||
// runtime types are not compatible, it could cause runtime crashes when the resource is resolved.
|
||||
|
||||
target_map_.insert(std::make_pair(target_resource, TargetValue{data_type, data_value}));
|
||||
return Unit{};
|
||||
}
|
||||
|
||||
void ResourceMapping::RemoveMapping(ResourceId target_resource) {
|
||||
@@ -422,14 +427,15 @@ void ResourceMapping::RemoveMapping(ResourceId target_resource) {
|
||||
return;
|
||||
}
|
||||
|
||||
const TargetValue value = target_iter->second;
|
||||
const auto value = target_iter->second;
|
||||
target_map_.erase(target_iter);
|
||||
|
||||
if (!IsReference(value.data_type)) {
|
||||
const ResourceId* overlay_resource = std::get_if<ResourceId>(&value);
|
||||
if (overlay_resource == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto overlay_iter = overlay_map_.equal_range(value.data_value);
|
||||
auto overlay_iter = overlay_map_.equal_range(*overlay_resource);
|
||||
for (auto i = overlay_iter.first; i != overlay_iter.second; ++i) {
|
||||
if (i->second == target_resource) {
|
||||
overlay_map_.erase(i);
|
||||
|
||||
@@ -72,13 +72,20 @@ TEST(BinaryStreamVisitorTests, CreateBinaryStreamViaBinaryStreamVisitor) {
|
||||
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);
|
||||
ASSERT_EQ(target_entries1[0].overlay_id, target_entries2[0].overlay_id);
|
||||
|
||||
ASSERT_EQ(target_entries1[1].target_id, target_entries2[1].target_id);
|
||||
ASSERT_EQ(target_entries1[1].data_value, target_entries2[1].data_value);
|
||||
ASSERT_EQ(target_entries1[1].overlay_id, target_entries2[1].overlay_id);
|
||||
|
||||
ASSERT_EQ(target_entries1[2].target_id, target_entries2[2].target_id);
|
||||
ASSERT_EQ(target_entries1[2].data_value, target_entries2[2].data_value);
|
||||
ASSERT_EQ(target_entries1[2].overlay_id, target_entries2[2].overlay_id);
|
||||
|
||||
const auto& target_inline_entries1 = data1->GetTargetInlineEntries();
|
||||
const auto& target_inline_entries2 = data2->GetTargetInlineEntries();
|
||||
ASSERT_EQ(target_inline_entries1.size(), target_inline_entries2.size());
|
||||
ASSERT_EQ(target_inline_entries1[0].target_id, target_inline_entries2[0].target_id);
|
||||
ASSERT_EQ(target_inline_entries1[0].value.data_type, target_inline_entries2[0].value.data_type);
|
||||
ASSERT_EQ(target_inline_entries1[0].value.data_value, target_inline_entries2[0].value.data_value);
|
||||
|
||||
const auto& overlay_entries1 = data1->GetOverlayEntries();
|
||||
const auto& overlay_entries2 = data2->GetOverlayEntries();
|
||||
|
||||
@@ -128,13 +128,13 @@ TEST_F(Idmap2BinaryTests, Dump) {
|
||||
// clang-format on
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
|
||||
ASSERT_NE(result->stdout.find(R::target::integer::literal::int1 + " -> 0x7f010000 integer/int1"),
|
||||
ASSERT_NE(result->stdout.find(R::target::integer::literal::int1 + " -> 0x7f010000"),
|
||||
std::string::npos);
|
||||
ASSERT_NE(result->stdout.find(R::target::string::literal::str1 + " -> 0x7f020000 string/str1"),
|
||||
ASSERT_NE(result->stdout.find(R::target::string::literal::str1 + " -> 0x7f020000"),
|
||||
std::string::npos);
|
||||
ASSERT_NE(result->stdout.find(R::target::string::literal::str3 + " -> 0x7f020001 string/str3"),
|
||||
ASSERT_NE(result->stdout.find(R::target::string::literal::str3 + " -> 0x7f020001"),
|
||||
std::string::npos);
|
||||
ASSERT_NE(result->stdout.find(R::target::string::literal::str4 + " -> 0x7f020002 string/str4"),
|
||||
ASSERT_NE(result->stdout.find(R::target::string::literal::str4 + " -> 0x7f020002"),
|
||||
std::string::npos);
|
||||
|
||||
// clang-format off
|
||||
|
||||
@@ -42,14 +42,18 @@ using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
|
||||
|
||||
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_TARGET_ENTRY(entry, target_resid, overlay_resid) \
|
||||
ASSERT_EQ((entry).target_id, (target_resid)); \
|
||||
ASSERT_EQ((entry).overlay_id, (overlay_resid))
|
||||
|
||||
#define ASSERT_TARGET_INLINE_ENTRY(entry, target_resid, expected_type, expected_value) \
|
||||
ASSERT_EQ((entry).target_id, target_resid); \
|
||||
ASSERT_EQ((entry).value.data_type, (expected_type)); \
|
||||
ASSERT_EQ((entry).value.data_value, (expected_value))
|
||||
|
||||
#define ASSERT_OVERLAY_ENTRY(entry, overlay_resid, target_resid) \
|
||||
ASSERT_EQ(entry.overlay_id, overlay_resid); \
|
||||
ASSERT_EQ(entry.target_id, 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"),
|
||||
@@ -62,7 +66,7 @@ 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(), 0x04U);
|
||||
ASSERT_EQ(header->GetVersion(), 0x05U);
|
||||
ASSERT_EQ(header->GetTargetCrc(), 0x1234U);
|
||||
ASSERT_EQ(header->GetOverlayCrc(), 0x5678U);
|
||||
ASSERT_EQ(header->GetFulfilledPolicies(), 0x11);
|
||||
@@ -75,7 +79,7 @@ TEST(IdmapTests, CreateIdmapHeaderFromBinaryStream) {
|
||||
TEST(IdmapTests, FailToCreateIdmapHeaderFromBinaryStreamIfPathTooLong) {
|
||||
std::string raw(reinterpret_cast<const char*>(idmap_raw_data), idmap_raw_data_len);
|
||||
// overwrite the target path string, including the terminating null, with '.'
|
||||
for (size_t i = 0x15; i < 0x115; i++) {
|
||||
for (size_t i = 0x18; i < 0x118; i++) {
|
||||
raw[i] = '.';
|
||||
}
|
||||
std::istringstream stream(raw);
|
||||
@@ -84,7 +88,7 @@ TEST(IdmapTests, FailToCreateIdmapHeaderFromBinaryStreamIfPathTooLong) {
|
||||
}
|
||||
|
||||
TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) {
|
||||
const size_t offset = 0x221;
|
||||
const size_t offset = 0x224;
|
||||
std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset),
|
||||
idmap_raw_data_len - offset);
|
||||
std::istringstream stream(raw);
|
||||
@@ -96,7 +100,7 @@ TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) {
|
||||
}
|
||||
|
||||
TEST(IdmapTests, CreateIdmapDataFromBinaryStream) {
|
||||
const size_t offset = 0x221;
|
||||
const size_t offset = 0x224;
|
||||
std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset),
|
||||
idmap_raw_data_len - offset);
|
||||
std::istringstream stream(raw);
|
||||
@@ -106,12 +110,14 @@ TEST(IdmapTests, CreateIdmapDataFromBinaryStream) {
|
||||
|
||||
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);
|
||||
ASSERT_TARGET_ENTRY(target_entries[0], 0x7f020000, 0x7f020000);
|
||||
ASSERT_TARGET_ENTRY(target_entries[1], 0x7f030000, 0x7f030000);
|
||||
ASSERT_TARGET_ENTRY(target_entries[2], 0x7f030002, 0x7f030001);
|
||||
|
||||
const auto& target_inline_entries = data->GetTargetInlineEntries();
|
||||
ASSERT_EQ(target_inline_entries.size(), 1U);
|
||||
ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], 0x7f040000, Res_value::TYPE_INT_HEX,
|
||||
0x12345678);
|
||||
|
||||
const auto& overlay_entries = data->GetOverlayEntries();
|
||||
ASSERT_EQ(target_entries.size(), 3U);
|
||||
@@ -130,7 +136,7 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) {
|
||||
|
||||
ASSERT_THAT(idmap->GetHeader(), NotNull());
|
||||
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x04U);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x05U);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x1234U);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x5678U);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), 0x11);
|
||||
@@ -146,9 +152,14 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) {
|
||||
|
||||
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);
|
||||
ASSERT_TARGET_ENTRY(target_entries[0], 0x7f020000, 0x7f020000);
|
||||
ASSERT_TARGET_ENTRY(target_entries[1], 0x7f030000, 0x7f030000);
|
||||
ASSERT_TARGET_ENTRY(target_entries[2], 0x7f030002, 0x7f030001);
|
||||
|
||||
const auto& target_inline_entries = data->GetTargetInlineEntries();
|
||||
ASSERT_EQ(target_inline_entries.size(), 1U);
|
||||
ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], 0x7f040000, Res_value::TYPE_INT_HEX,
|
||||
0x12345678);
|
||||
|
||||
const auto& overlay_entries = data->GetOverlayEntries();
|
||||
ASSERT_EQ(target_entries.size(), 3U);
|
||||
@@ -184,7 +195,7 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) {
|
||||
|
||||
ASSERT_THAT(idmap->GetHeader(), NotNull());
|
||||
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x04U);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x05U);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), android::idmap2::TestConstants::TARGET_CRC);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), android::idmap2::TestConstants::OVERLAY_CRC);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), PolicyFlags::PUBLIC);
|
||||
@@ -244,14 +255,13 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssets) {
|
||||
|
||||
const auto& target_entries = data->GetTargetEntries();
|
||||
ASSERT_EQ(target_entries.size(), 4U);
|
||||
ASSERT_TARGET_ENTRY(target_entries[0], R::target::integer::int1,
|
||||
Res_value::TYPE_DYNAMIC_REFERENCE, R::overlay::integer::int1);
|
||||
ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str1, Res_value::TYPE_DYNAMIC_REFERENCE,
|
||||
R::overlay::string::str1);
|
||||
ASSERT_TARGET_ENTRY(target_entries[2], R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE,
|
||||
R::overlay::string::str3);
|
||||
ASSERT_TARGET_ENTRY(target_entries[3], R::target::string::str4, Res_value::TYPE_DYNAMIC_REFERENCE,
|
||||
R::overlay::string::str4);
|
||||
ASSERT_TARGET_ENTRY(target_entries[0], R::target::integer::int1, R::overlay::integer::int1);
|
||||
ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str1, R::overlay::string::str1);
|
||||
ASSERT_TARGET_ENTRY(target_entries[2], R::target::string::str3, R::overlay::string::str3);
|
||||
ASSERT_TARGET_ENTRY(target_entries[3], R::target::string::str4, R::overlay::string::str4);
|
||||
|
||||
const auto& target_inline_entries = data->GetTargetInlineEntries();
|
||||
ASSERT_EQ(target_inline_entries.size(), 0U);
|
||||
|
||||
const auto& overlay_entries = data->GetOverlayEntries();
|
||||
ASSERT_EQ(target_entries.size(), 4U);
|
||||
@@ -286,13 +296,13 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssetsSharedLibOverlay) {
|
||||
const auto& target_entries = data->GetTargetEntries();
|
||||
ASSERT_EQ(target_entries.size(), 4U);
|
||||
ASSERT_TARGET_ENTRY(target_entries[0], R::target::integer::int1,
|
||||
Res_value::TYPE_DYNAMIC_REFERENCE, R::overlay_shared::integer::int1);
|
||||
ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str1, Res_value::TYPE_DYNAMIC_REFERENCE,
|
||||
R::overlay_shared::string::str1);
|
||||
ASSERT_TARGET_ENTRY(target_entries[2], R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE,
|
||||
R::overlay_shared::string::str3);
|
||||
ASSERT_TARGET_ENTRY(target_entries[3], R::target::string::str4, Res_value::TYPE_DYNAMIC_REFERENCE,
|
||||
R::overlay_shared::string::str4);
|
||||
R::overlay_shared::integer::int1);
|
||||
ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str1, R::overlay_shared::string::str1);
|
||||
ASSERT_TARGET_ENTRY(target_entries[2], R::target::string::str3, R::overlay_shared::string::str3);
|
||||
ASSERT_TARGET_ENTRY(target_entries[3], R::target::string::str4, R::overlay_shared::string::str4);
|
||||
|
||||
const auto& target_inline_entries = data->GetTargetInlineEntries();
|
||||
ASSERT_EQ(target_inline_entries.size(), 0U);
|
||||
|
||||
const auto& overlay_entries = data->GetOverlayEntries();
|
||||
ASSERT_EQ(target_entries.size(), 4U);
|
||||
@@ -320,10 +330,12 @@ TEST(IdmapTests, CreateIdmapDataDoNotRewriteNonOverlayResourceId) {
|
||||
|
||||
const auto& target_entries = data->GetTargetEntries();
|
||||
ASSERT_EQ(target_entries.size(), 2U);
|
||||
ASSERT_TARGET_ENTRY(target_entries[0], R::target::string::str1, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_TARGET_ENTRY(target_entries[0], R::target::string::str1,
|
||||
0x0104000a); // -> android:string/ok
|
||||
ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE,
|
||||
R::overlay::string::str3);
|
||||
ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str3, R::overlay::string::str3);
|
||||
|
||||
const auto& target_inline_entries = data->GetTargetInlineEntries();
|
||||
ASSERT_EQ(target_inline_entries.size(), 0U);
|
||||
|
||||
const auto& overlay_entries = data->GetOverlayEntries();
|
||||
ASSERT_EQ(overlay_entries.size(), 1U);
|
||||
@@ -342,13 +354,17 @@ TEST(IdmapTests, CreateIdmapDataInlineResources) {
|
||||
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], R::target::integer::int1, Res_value::TYPE_INT_DEC,
|
||||
73U); // -> 73
|
||||
ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str1, Res_value::TYPE_STRING,
|
||||
overlay_string_pool_size + 0U); // -> "Hello World"
|
||||
ASSERT_EQ(target_entries.size(), 0U);
|
||||
|
||||
constexpr size_t overlay_string_pool_size = 8U;
|
||||
const auto& target_inline_entries = data->GetTargetInlineEntries();
|
||||
ASSERT_EQ(target_inline_entries.size(), 2U);
|
||||
ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::integer::int1,
|
||||
Res_value::TYPE_INT_DEC, 73U); // -> 73
|
||||
ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::string::str1,
|
||||
Res_value::TYPE_STRING,
|
||||
overlay_string_pool_size + 0U); // -> "Hello World"
|
||||
|
||||
const auto& overlay_entries = data->GetOverlayEntries();
|
||||
ASSERT_EQ(overlay_entries.size(), 0U);
|
||||
@@ -479,9 +495,9 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
|
||||
ASSERT_FALSE(bad_enforce_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
|
||||
PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
|
||||
|
||||
// target path: bytes (0x15, 0x114)
|
||||
// target path: bytes (0x18, 0x117)
|
||||
std::string bad_target_path_string(stream.str());
|
||||
bad_target_path_string[0x15] = '\0';
|
||||
bad_target_path_string[0x18] = '\0';
|
||||
std::stringstream bad_target_path_stream(bad_target_path_string);
|
||||
std::unique_ptr<const IdmapHeader> bad_target_path_header =
|
||||
IdmapHeader::FromBinaryStream(bad_target_path_stream);
|
||||
@@ -490,9 +506,9 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
|
||||
ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
|
||||
PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
|
||||
|
||||
// overlay path: bytes (0x115, 0x214)
|
||||
// overlay path: bytes (0x118, 0x217)
|
||||
std::string bad_overlay_path_string(stream.str());
|
||||
bad_overlay_path_string[0x115] = '\0';
|
||||
bad_overlay_path_string[0x118] = '\0';
|
||||
std::stringstream bad_overlay_path_stream(bad_overlay_path_string);
|
||||
std::unique_ptr<const IdmapHeader> bad_overlay_path_header =
|
||||
IdmapHeader::FromBinaryStream(bad_overlay_path_stream);
|
||||
|
||||
@@ -56,7 +56,8 @@ TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitor) {
|
||||
|
||||
ASSERT_NE(stream.str().find("target apk path : "), std::string::npos);
|
||||
ASSERT_NE(stream.str().find("overlay apk path : "), std::string::npos);
|
||||
ASSERT_NE(stream.str().find(R::target::integer::literal::int1 + " -> 0x7f010000 integer/int1\n"),
|
||||
ASSERT_NE(stream.str().find(R::target::integer::literal::int1 +
|
||||
" -> 0x7f010000 (integer/int1 -> integer/int1)\n"),
|
||||
std::string::npos);
|
||||
}
|
||||
|
||||
@@ -75,7 +76,7 @@ TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitorWithoutAccessToApks) {
|
||||
|
||||
ASSERT_NE(stream.str().find("target apk path : "), std::string::npos);
|
||||
ASSERT_NE(stream.str().find("overlay apk path : "), std::string::npos);
|
||||
ASSERT_NE(stream.str().find("0x7f020000 -> 0x7f020000\n"), std::string::npos);
|
||||
ASSERT_NE(stream.str().find("0x7f020000 -> 0x7f020000 (\?\?\? -> \?\?\?)\n"), std::string::npos);
|
||||
}
|
||||
|
||||
} // namespace android::idmap2
|
||||
|
||||
@@ -65,7 +65,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
|
||||
(*idmap)->accept(&visitor);
|
||||
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00000004 version\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00000005 version\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(
|
||||
StringPrintf(ADDRESS "%s target crc\n", android::idmap2::TestConstants::TARGET_CRC_STRING),
|
||||
stream.str());
|
||||
@@ -73,19 +73,19 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
|
||||
StringPrintf(ADDRESS "%s overlay crc\n", android::idmap2::TestConstants::OVERLAY_CRC_STRING),
|
||||
stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00000001 fulfilled policies: public\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS " 01 enforce overlayable\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00000001 enforce overlayable\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 overlay id: integer/int1\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 target id: integer/int1\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "000000b4 string pool size\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX("000002bc: ........ string pool: ...\n", stream.str());
|
||||
}
|
||||
|
||||
TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
|
||||
@@ -102,22 +102,26 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
|
||||
(*idmap)->accept(&visitor);
|
||||
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00000004 version\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00000005 version\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00001234 target crc\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00005678 overlay crc\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00000011 fulfilled policies: public|signature\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS " 01 enforce overlayable\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00000001 enforce overlayable\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 "00000003 target entry count\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00000001 target inline entry count\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00000003 overlay entry count\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00000000 string pool index offset\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00000000 string pool byte length\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS " 01 type: reference\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 value\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 overlay id\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS " 11 type: integer\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "12345678 data\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 overlay id\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "7f030002 target id\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX(ADDRESS "00000004 string pool size\n", stream.str());
|
||||
ASSERT_CONTAINS_REGEX("00000278: ........ string pool: ...\n", stream.str());
|
||||
}
|
||||
|
||||
} // namespace android::idmap2
|
||||
|
||||
@@ -77,30 +77,61 @@ Result<ResourceMapping> TestGetResourceMapping(const android::StringPiece& local
|
||||
fulfilled_policies, enforce_overlayable);
|
||||
}
|
||||
|
||||
Result<Unit> MappingExists(const ResourceMapping& mapping, const ResourceId& target_resource,
|
||||
const uint8_t type, const uint32_t value, bool rewrite) {
|
||||
Result<Unit> MappingExists(const ResourceMapping& mapping, ResourceId target_resource,
|
||||
ResourceId overlay_resource, bool rewrite) {
|
||||
auto target_map = mapping.GetTargetToOverlayMap();
|
||||
auto entry_map = target_map.find(target_resource);
|
||||
if (entry_map == target_map.end()) {
|
||||
return Error("Failed to find mapping for target resource");
|
||||
}
|
||||
|
||||
if (entry_map->second.data_type != type) {
|
||||
return Error(R"(Expected type: "0x%02x" Actual type: "0x%02x")", type,
|
||||
entry_map->second.data_type);
|
||||
auto actual_overlay_resource = std::get_if<ResourceId>(&entry_map->second);
|
||||
if (actual_overlay_resource == nullptr) {
|
||||
return Error("Target resource is not mapped to an overlay resource id");
|
||||
}
|
||||
|
||||
if (entry_map->second.data_value != value) {
|
||||
return Error(R"(Expected value: "0x%08x" Actual value: "0x%08x")", type,
|
||||
entry_map->second.data_value);
|
||||
if (*actual_overlay_resource != overlay_resource) {
|
||||
return Error(R"(Expected id: "0x%02x" Actual id: "0x%02x")", overlay_resource,
|
||||
*actual_overlay_resource);
|
||||
}
|
||||
|
||||
auto overlay_map = mapping.GetOverlayToTargetMap();
|
||||
auto overlay_iter = overlay_map.find(entry_map->second.data_value);
|
||||
auto overlay_iter = overlay_map.find(overlay_resource);
|
||||
if ((overlay_iter != overlay_map.end()) != rewrite) {
|
||||
return Error(R"(Expected rewriting: "%s")", rewrite ? "true" : "false");
|
||||
}
|
||||
|
||||
if (rewrite && overlay_iter->second != target_resource) {
|
||||
return Error(R"(Expected rewrite id: "0x%02x" Actual id: "0x%02x")", target_resource,
|
||||
overlay_iter->second);
|
||||
}
|
||||
|
||||
return Result<Unit>({});
|
||||
}
|
||||
|
||||
Result<Unit> MappingExists(const ResourceMapping& mapping, const ResourceId& target_resource,
|
||||
const uint8_t type, const uint32_t value) {
|
||||
auto target_map = mapping.GetTargetToOverlayMap();
|
||||
auto entry_map = target_map.find(target_resource);
|
||||
if (entry_map == target_map.end()) {
|
||||
return Error("Failed to find mapping for target resource");
|
||||
}
|
||||
|
||||
auto actual_overlay_value = std::get_if<TargetValue>(&entry_map->second);
|
||||
if (actual_overlay_value == nullptr) {
|
||||
return Error("Target resource is not mapped to an inline value");
|
||||
}
|
||||
|
||||
if (actual_overlay_value->data_type != type) {
|
||||
return Error(R"(Expected type: "0x%02x" Actual type: "0x%02x")", type,
|
||||
actual_overlay_value->data_type);
|
||||
}
|
||||
|
||||
if (actual_overlay_value->data_value != value) {
|
||||
return Error(R"(Expected value: "0x%08x" Actual value: "0x%08x")", type,
|
||||
actual_overlay_value->data_value);
|
||||
}
|
||||
|
||||
return Result<Unit>({});
|
||||
}
|
||||
|
||||
@@ -116,14 +147,14 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsLegacy) {
|
||||
ASSERT_TRUE(resources) << resources.GetErrorMessage();
|
||||
auto& res = *resources;
|
||||
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
|
||||
ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_REFERENCE,
|
||||
R::overlay::integer::int1, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE,
|
||||
R::overlay::string::str1, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str3, Res_value::TYPE_REFERENCE,
|
||||
R::overlay::string::str3, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str4, Res_value::TYPE_REFERENCE,
|
||||
R::overlay::string::str4, false /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::integer::int1, R::overlay::integer::int1, false /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::string::str1, R::overlay::string::str1, false /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::string::str3, R::overlay::string::str3, false /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::string::str4, R::overlay::string::str4, false /* rewrite */));
|
||||
}
|
||||
|
||||
TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) {
|
||||
@@ -138,12 +169,12 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) {
|
||||
ASSERT_TRUE(resources) << resources.GetErrorMessage();
|
||||
auto& res = *resources;
|
||||
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_DYNAMIC_REFERENCE,
|
||||
R::overlay::string::str4, true /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE,
|
||||
R::overlay::string::str1, true /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str4, Res_value::TYPE_DYNAMIC_REFERENCE,
|
||||
R::overlay::string::str3, true /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::string::str1, R::overlay::string::str4, true /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::string::str3, R::overlay::string::str1, true /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::string::str4, R::overlay::string::str3, true /* rewrite */));
|
||||
}
|
||||
|
||||
TEST(ResourceMappingTests, DoNotRewriteNonOverlayResourceId) {
|
||||
@@ -159,10 +190,9 @@ TEST(ResourceMappingTests, DoNotRewriteNonOverlayResourceId) {
|
||||
auto& res = *resources;
|
||||
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
|
||||
ASSERT_EQ(res.GetOverlayToTargetMap().size(), 1U);
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE, 0x0104000a,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str1, 0x0104000a,
|
||||
false /* rewrite */)); // -> android:string/ok
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE,
|
||||
0x7f020001, true /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str3, 0x7f020001, true /* rewrite */));
|
||||
}
|
||||
|
||||
TEST(ResourceMappingTests, InlineResources) {
|
||||
@@ -180,10 +210,8 @@ TEST(ResourceMappingTests, InlineResources) {
|
||||
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
|
||||
ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U);
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_STRING,
|
||||
overlay_string_pool_size + 0U,
|
||||
false /* rewrite */)); // -> "Hello World"
|
||||
ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 73U,
|
||||
false /* rewrite */)); // -> 73
|
||||
overlay_string_pool_size + 0U)); // -> "Hello World"
|
||||
ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 73U));
|
||||
}
|
||||
|
||||
TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
|
||||
@@ -195,13 +223,13 @@ TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
|
||||
ASSERT_TRUE(resources) << resources.GetErrorMessage();
|
||||
auto& res = *resources;
|
||||
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_public,
|
||||
R::system_overlay::string::policy_public, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_system,
|
||||
R::system_overlay::string::policy_system, false /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE,
|
||||
R::system_overlay::string::policy_system_vendor, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_system_vendor,
|
||||
R::system_overlay::string::policy_system_vendor,
|
||||
false /* rewrite */));
|
||||
}
|
||||
|
||||
// Resources that are not declared as overlayable and resources that a protected by policies the
|
||||
@@ -215,15 +243,15 @@ TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
|
||||
ASSERT_TRUE(resources) << resources.GetErrorMessage();
|
||||
auto& res = *resources;
|
||||
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_public,
|
||||
R::system_overlay_invalid::string::policy_public,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_system,
|
||||
R::system_overlay_invalid::string::policy_system,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE,
|
||||
R::system_overlay_invalid::string::policy_system_vendor, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_system_vendor,
|
||||
R::system_overlay_invalid::string::policy_system_vendor,
|
||||
false /* rewrite */));
|
||||
}
|
||||
|
||||
// Resources that are not declared as overlayable and resources that a protected by policies the
|
||||
@@ -238,37 +266,36 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnore
|
||||
ASSERT_TRUE(resources) << resources.GetErrorMessage();
|
||||
auto& res = *resources;
|
||||
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 11U);
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable,
|
||||
R::system_overlay_invalid::string::not_overlayable,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::other, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::other,
|
||||
R::system_overlay_invalid::string::other, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor,
|
||||
R::system_overlay_invalid::string::policy_actor,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm,
|
||||
R::system_overlay_invalid::string::policy_odm, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem,
|
||||
R::system_overlay_invalid::string::policy_oem, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_product, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_product,
|
||||
R::system_overlay_invalid::string::policy_product,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_public,
|
||||
R::system_overlay_invalid::string::policy_public,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature,
|
||||
Res_value::TYPE_REFERENCE,
|
||||
R::system_overlay_invalid::string::policy_config_signature,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature,
|
||||
R::system_overlay_invalid::string::policy_signature,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_system,
|
||||
R::system_overlay_invalid::string::policy_system,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE,
|
||||
R::system_overlay_invalid::string::policy_system_vendor, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_system_vendor,
|
||||
R::system_overlay_invalid::string::policy_system_vendor,
|
||||
false /* rewrite */));
|
||||
}
|
||||
|
||||
// Overlays that do not target an <overlayable> tag can overlay resources defined within any
|
||||
@@ -281,14 +308,14 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTarget
|
||||
ASSERT_TRUE(resources) << resources.GetErrorMessage();
|
||||
auto& res = *resources;
|
||||
ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
|
||||
ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_REFERENCE,
|
||||
R::overlay::integer::int1, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE,
|
||||
R::overlay::string::str1, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str3, Res_value::TYPE_REFERENCE,
|
||||
R::overlay::string::str3, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::str4, Res_value::TYPE_REFERENCE,
|
||||
R::overlay::string::str4, false /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::integer::int1, R::overlay::integer::int1, false /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::string::str1, R::overlay::string::str1, false /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::string::str3, R::overlay::string::str3, false /* rewrite */));
|
||||
ASSERT_RESULT(
|
||||
MappingExists(res, R::target::string::str4, R::overlay::string::str4, false /* rewrite */));
|
||||
}
|
||||
|
||||
// Overlays that are neither pre-installed nor signed with the same signature as the target cannot
|
||||
@@ -302,9 +329,9 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) {
|
||||
ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U);
|
||||
}
|
||||
|
||||
// Overlays that are pre-installed or are signed with the same signature as the target or are signed
|
||||
// with the same signature as the reference package can overlay packages that have not defined
|
||||
// overlayable resources.
|
||||
// Overlays that are pre-installed or are signed with the same signature as the target or are
|
||||
// signed with the same signature as the reference package can overlay packages that have not
|
||||
// defined overlayable resources.
|
||||
TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
|
||||
auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void {
|
||||
auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk",
|
||||
@@ -315,39 +342,38 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
|
||||
ASSERT_TRUE(resources) << resources.GetErrorMessage();
|
||||
auto& res = *resources;
|
||||
ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 11U);
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable,
|
||||
R::system_overlay_invalid::string::not_overlayable,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::other, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::other,
|
||||
R::system_overlay_invalid::string::other, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor,
|
||||
R::system_overlay_invalid::string::policy_actor,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm,
|
||||
R::system_overlay_invalid::string::policy_odm,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem,
|
||||
R::system_overlay_invalid::string::policy_oem,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_product, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_product,
|
||||
R::system_overlay_invalid::string::policy_product,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_public,
|
||||
R::system_overlay_invalid::string::policy_public,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature,
|
||||
Res_value::TYPE_REFERENCE,
|
||||
R::system_overlay_invalid::string::policy_config_signature,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature,
|
||||
R::system_overlay_invalid::string::policy_signature,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE,
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_system,
|
||||
R::system_overlay_invalid::string::policy_system,
|
||||
false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(
|
||||
res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE,
|
||||
R::system_overlay_invalid::string::policy_system_vendor, false /* rewrite */));
|
||||
ASSERT_RESULT(MappingExists(res, R::target::string::policy_system_vendor,
|
||||
R::system_overlay_invalid::string::policy_system_vendor,
|
||||
false /* rewrite */));
|
||||
};
|
||||
|
||||
CheckEntries(PolicyFlags::SIGNATURE);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
namespace android::idmap2::TestConstants {
|
||||
|
||||
constexpr const auto TARGET_CRC = 0x7c2d4719;
|
||||
constexpr const auto TARGET_CRC = 0x7c2d4719;
|
||||
constexpr const auto TARGET_CRC_STRING = "7c2d4719";
|
||||
|
||||
constexpr const auto OVERLAY_CRC = 0x5afff726;
|
||||
|
||||
@@ -30,7 +30,7 @@ const unsigned char idmap_raw_data[] = {
|
||||
0x49, 0x44, 0x4d, 0x50,
|
||||
|
||||
// 0x4: version
|
||||
0x04, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00,
|
||||
|
||||
// 0x8: target crc
|
||||
0x34, 0x12, 0x00, 0x00,
|
||||
@@ -42,9 +42,9 @@ const unsigned char idmap_raw_data[] = {
|
||||
0x11, 0x00, 0x00, 0x00,
|
||||
|
||||
// 0x14: enforce overlayable
|
||||
0x01,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
|
||||
// 0x15: target path "targetX.apk"
|
||||
// 0x18: 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,
|
||||
@@ -62,7 +62,7 @@ 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,
|
||||
|
||||
// 0x115: overlay path "overlayX.apk"
|
||||
// 0x118: 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,
|
||||
@@ -80,71 +80,89 @@ 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,
|
||||
|
||||
// 0x215: debug string
|
||||
// string length, including terminating null
|
||||
0x08, 0x00, 0x00, 0x00,
|
||||
// 0x218: debug string
|
||||
// string length,
|
||||
0x05, 0x00, 0x00, 0x00,
|
||||
|
||||
// string contents "debug\0\0\0" (padded to word alignment)
|
||||
// 0x21c string contents "debug\0\0\0" (padded to word alignment)
|
||||
0x64, 0x65, 0x62, 0x75, 0x67, 0x00, 0x00, 0x00,
|
||||
|
||||
// DATA HEADER
|
||||
// 0x221: target_package_id
|
||||
// 0x224: target_package_id
|
||||
0x7f,
|
||||
|
||||
// 0x222: overlay_package_id
|
||||
// 0x225: overlay_package_id
|
||||
0x7f,
|
||||
|
||||
// 0x223: target_entry_count
|
||||
// 0x226: padding
|
||||
0x00, 0x00,
|
||||
|
||||
// 0x228: target_entry_count
|
||||
0x03, 0x00, 0x00, 0x00,
|
||||
|
||||
// 0x227: overlay_entry_count
|
||||
// 0x22c: target_inline_entry_count
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
|
||||
// 0x230: overlay_entry_count
|
||||
0x03, 0x00, 0x00, 0x00,
|
||||
|
||||
// 0x22b: string_pool_offset
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
// 0x22f: string_pool_byte_length
|
||||
// 0x234: string_pool_offset
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
// TARGET ENTRIES
|
||||
// 0x233: 0x7f020000
|
||||
// 0x238: target id (0x7f020000)
|
||||
0x00, 0x00, 0x02, 0x7f,
|
||||
|
||||
// 0x237: TYPE_REFERENCE
|
||||
0x01,
|
||||
|
||||
// 0x238: 0x7f020000
|
||||
// 0x23c: overlay_id (0x7f020000)
|
||||
0x00, 0x00, 0x02, 0x7f,
|
||||
|
||||
// 0x23c: 0x7f030000
|
||||
// 0x240: target id (0x7f030000)
|
||||
0x00, 0x00, 0x03, 0x7f,
|
||||
|
||||
// 0x240: TYPE_REFERENCE
|
||||
0x01,
|
||||
|
||||
// 0x241: 0x7f030000
|
||||
// 0x244: overlay_id (0x7f030000)
|
||||
0x00, 0x00, 0x03, 0x7f,
|
||||
|
||||
// 0x245: 0x7f030002
|
||||
// 0x248: target id (0x7f030002)
|
||||
0x02, 0x00, 0x03, 0x7f,
|
||||
|
||||
// 0x249: TYPE_REFERENCE
|
||||
0x01,
|
||||
|
||||
// 0x24a: 0x7f030001
|
||||
// 0x24c: overlay_id (0x7f030001)
|
||||
0x01, 0x00, 0x03, 0x7f,
|
||||
|
||||
// INLINE TARGET ENTRIES
|
||||
|
||||
// 0x250: target_id
|
||||
0x00, 0x00, 0x04, 0x7f,
|
||||
|
||||
// 0x254: Res_value::size (value ignored by idmap)
|
||||
0x08, 0x00,
|
||||
|
||||
// 0x256: Res_value::res0 (value ignored by idmap)
|
||||
0x00,
|
||||
|
||||
// 0x257: Res_value::dataType (TYPE_INT_HEX)
|
||||
0x11,
|
||||
|
||||
// 0x258: Res_value::data
|
||||
0x78, 0x56, 0x34, 0x12,
|
||||
|
||||
// OVERLAY ENTRIES
|
||||
// 0x24e: 0x7f020000 -> 0x7f020000
|
||||
// 0x25c: 0x7f020000 -> 0x7f020000
|
||||
0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f,
|
||||
|
||||
// 0x256: 0x7f030000 -> 0x7f030000
|
||||
// 0x264: 0x7f030000 -> 0x7f030000
|
||||
0x00, 0x00, 0x03, 0x7f, 0x00, 0x00, 0x03, 0x7f,
|
||||
|
||||
// 0x25e: 0x7f030001 -> 0x7f030002
|
||||
0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f};
|
||||
// 0x26c: 0x7f030001 -> 0x7f030002
|
||||
0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f,
|
||||
|
||||
const unsigned int idmap_raw_data_len = 0x266;
|
||||
// 0x274: string pool
|
||||
// string length,
|
||||
0x04, 0x00, 0x00, 0x00,
|
||||
|
||||
// 0x278 string contents "test" (padded to word alignment)
|
||||
0x74, 0x65, 0x73, 0x74};
|
||||
|
||||
const unsigned int idmap_raw_data_len = 0x27c;
|
||||
|
||||
std::string GetTestDataPath();
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ public class SystemConfig {
|
||||
// partition that is used to verify if an overlay package fulfills
|
||||
// the 'config_signature' policy by comparing their signatures:
|
||||
// if the overlay package is signed with the same certificate as
|
||||
// the package declared in 'config-signature' tag, then the
|
||||
// the package declared in 'overlay-config-signature' tag, then the
|
||||
// overlay package fulfills the 'config_signature' policy.
|
||||
private String mOverlayConfigSignaturePackage;
|
||||
|
||||
|
||||
@@ -39,10 +39,8 @@
|
||||
namespace android {
|
||||
|
||||
struct FindEntryResult {
|
||||
// A pointer to the resource table entry for this resource.
|
||||
// If the size of the entry is > sizeof(ResTable_entry), it can be cast to
|
||||
// a ResTable_map_entry and processed as a bag/map.
|
||||
ResTable_entry_handle entry;
|
||||
// A pointer to the value of the resource table entry.
|
||||
std::variant<Res_value, const ResTable_map_entry*> entry;
|
||||
|
||||
// The configuration for which the resulting entry was defined. This is already swapped to host
|
||||
// endianness.
|
||||
@@ -554,11 +552,9 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
|
||||
if (!overlay_entry) {
|
||||
// No id map entry exists for this target resource.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (overlay_entry.IsTableEntry()) {
|
||||
} else if (overlay_entry.IsInlineValue()) {
|
||||
// The target resource is overlaid by an inline value not represented by a resource.
|
||||
out_entry->entry = overlay_entry.GetTableEntry();
|
||||
out_entry->entry = overlay_entry.GetInlineValue();
|
||||
out_entry->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
|
||||
cookie = id_map.cookie;
|
||||
continue;
|
||||
@@ -580,7 +576,7 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
|
||||
}
|
||||
|
||||
cookie = overlay_cookie;
|
||||
out_entry->entry = std::move(overlay_result.entry);
|
||||
out_entry->entry = overlay_result.entry;
|
||||
out_entry->config = overlay_result.config;
|
||||
out_entry->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
|
||||
if (resource_resolution_logging_enabled_) {
|
||||
@@ -761,7 +757,19 @@ ApkAssetsCookie AssetManager2::FindEntryInternal(const PackageGroup& package_gro
|
||||
return kInvalidCookie;
|
||||
}
|
||||
|
||||
out_entry->entry = ResTable_entry_handle::unmanaged(best_entry);
|
||||
const uint16_t entry_size = dtohs(best_entry->size);
|
||||
if (entry_size >= sizeof(ResTable_map_entry) &&
|
||||
(dtohs(best_entry->flags) & ResTable_entry::FLAG_COMPLEX)) {
|
||||
// The entry represents a bag/map.
|
||||
out_entry->entry = reinterpret_cast<const ResTable_map_entry*>(best_entry);
|
||||
} else {
|
||||
// The entry represents a value.
|
||||
Res_value value;
|
||||
value.copyFrom_dtoh(*reinterpret_cast<const Res_value*>(
|
||||
reinterpret_cast<const uint8_t*>(best_entry) + entry_size));
|
||||
out_entry->entry = value;
|
||||
}
|
||||
|
||||
out_entry->config = *best_config;
|
||||
out_entry->type_flags = type_flags;
|
||||
out_entry->package_name = &best_package->GetPackageName();
|
||||
@@ -905,8 +913,8 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
|
||||
return kInvalidCookie;
|
||||
}
|
||||
|
||||
const ResTable_entry* table_entry = *entry.entry;
|
||||
if (dtohs(table_entry->flags) & ResTable_entry::FLAG_COMPLEX) {
|
||||
auto result_map_entry = std::get_if<const ResTable_map_entry*>(&entry.entry);
|
||||
if (result_map_entry != nullptr) {
|
||||
if (!may_be_bag) {
|
||||
LOG(ERROR) << base::StringPrintf("Resource %08x is a complex map type.", resid);
|
||||
return kInvalidCookie;
|
||||
@@ -920,11 +928,8 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
|
||||
return cookie;
|
||||
}
|
||||
|
||||
const Res_value* device_value = reinterpret_cast<const Res_value*>(
|
||||
reinterpret_cast<const uint8_t*>(table_entry) + dtohs(table_entry->size));
|
||||
out_value->copyFrom_dtoh(*device_value);
|
||||
|
||||
// Convert the package ID to the runtime assigned package ID.
|
||||
*out_value = std::get<Res_value>(entry.entry);
|
||||
entry.dynamic_ref_table->lookupResourceValue(out_value);
|
||||
|
||||
*out_selected_config = entry.config;
|
||||
@@ -1004,19 +1009,15 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check that the size of the entry header is at least as big as
|
||||
// the desired ResTable_map_entry. Also verify that the entry
|
||||
// was intended to be a map.
|
||||
const ResTable_entry* table_entry = *entry.entry;
|
||||
if (dtohs(table_entry->size) < sizeof(ResTable_map_entry) ||
|
||||
(dtohs(table_entry->flags) & ResTable_entry::FLAG_COMPLEX) == 0) {
|
||||
auto result_map_entry = std::get_if<const ResTable_map_entry*>(&entry.entry);
|
||||
if (result_map_entry == nullptr) {
|
||||
// Not a bag, nothing to do.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ResTable_map_entry* map = reinterpret_cast<const ResTable_map_entry*>(table_entry);
|
||||
const ResTable_map* map_entry =
|
||||
reinterpret_cast<const ResTable_map*>(reinterpret_cast<const uint8_t*>(map) + map->size);
|
||||
auto map = reinterpret_cast<const ResTable_map_entry*>(*result_map_entry);
|
||||
auto map_entry = reinterpret_cast<const ResTable_map*>(
|
||||
reinterpret_cast<const uint8_t*>(map) + map->size);
|
||||
const ResTable_map* const map_entry_end = map_entry + dtohl(map->count);
|
||||
|
||||
// Keep track of ids that have already been seen to prevent infinite loops caused by circular
|
||||
|
||||
@@ -36,16 +36,12 @@ using ::android::base::StringPrintf;
|
||||
|
||||
namespace android {
|
||||
|
||||
static bool compare_target_entries(const Idmap_target_entry &e1, const uint32_t target_id) {
|
||||
return dtohl(e1.target_id) < target_id;
|
||||
}
|
||||
|
||||
static bool compare_overlay_entries(const Idmap_overlay_entry& e1, const uint32_t overlay_id) {
|
||||
return dtohl(e1.overlay_id) < overlay_id;
|
||||
uint32_t round_to_4_bytes(uint32_t size) {
|
||||
return size + (4U - (size % 4U)) % 4U;
|
||||
}
|
||||
|
||||
size_t Idmap_header::Size() const {
|
||||
return sizeof(Idmap_header) + sizeof(uint8_t) * dtohl(debug_info_size);
|
||||
return sizeof(Idmap_header) + sizeof(uint8_t) * round_to_4_bytes(dtohl(debug_info_size));
|
||||
}
|
||||
|
||||
OverlayStringPool::OverlayStringPool(const LoadedIdmap* loaded_idmap)
|
||||
@@ -88,7 +84,10 @@ OverlayDynamicRefTable::OverlayDynamicRefTable(const Idmap_data_header* data_hea
|
||||
status_t OverlayDynamicRefTable::lookupResourceId(uint32_t* resId) const {
|
||||
const Idmap_overlay_entry* first_entry = entries_;
|
||||
const Idmap_overlay_entry* end_entry = entries_ + dtohl(data_header_->overlay_entry_count);
|
||||
auto entry = std::lower_bound(first_entry, end_entry, *resId, compare_overlay_entries);
|
||||
auto entry = std::lower_bound(first_entry, end_entry, *resId,
|
||||
[](const Idmap_overlay_entry& e1, const uint32_t overlay_id) {
|
||||
return dtohl(e1.overlay_id) < overlay_id;
|
||||
});
|
||||
|
||||
if (entry == end_entry || dtohl(entry->overlay_id) != *resId) {
|
||||
// A mapping for the target resource id could not be found.
|
||||
@@ -96,7 +95,7 @@ status_t OverlayDynamicRefTable::lookupResourceId(uint32_t* resId) const {
|
||||
}
|
||||
|
||||
*resId = (0x00FFFFFFU & dtohl(entry->target_id))
|
||||
| (((uint32_t) target_assigned_package_id_) << 24);
|
||||
| (((uint32_t) target_assigned_package_id_) << 24U);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -106,62 +105,58 @@ status_t OverlayDynamicRefTable::lookupResourceIdNoRewrite(uint32_t* resId) cons
|
||||
|
||||
IdmapResMap::IdmapResMap(const Idmap_data_header* data_header,
|
||||
const Idmap_target_entry* entries,
|
||||
const Idmap_target_entry_inline* inline_entries,
|
||||
uint8_t target_assigned_package_id,
|
||||
const OverlayDynamicRefTable* overlay_ref_table)
|
||||
: data_header_(data_header),
|
||||
entries_(entries),
|
||||
inline_entries_(inline_entries),
|
||||
target_assigned_package_id_(target_assigned_package_id),
|
||||
overlay_ref_table_(overlay_ref_table) { };
|
||||
overlay_ref_table_(overlay_ref_table) { }
|
||||
|
||||
IdmapResMap::Result IdmapResMap::Lookup(uint32_t target_res_id) const {
|
||||
if ((target_res_id >> 24) != target_assigned_package_id_) {
|
||||
if ((target_res_id >> 24U) != target_assigned_package_id_) {
|
||||
// The resource id must have the same package id as the target package.
|
||||
return {};
|
||||
}
|
||||
|
||||
// The resource ids encoded within the idmap are build-time resource ids.
|
||||
target_res_id = (0x00FFFFFFU & target_res_id)
|
||||
| (((uint32_t) data_header_->target_package_id) << 24);
|
||||
| (((uint32_t) data_header_->target_package_id) << 24U);
|
||||
|
||||
const Idmap_target_entry* first_entry = entries_;
|
||||
const Idmap_target_entry* end_entry = entries_ + dtohl(data_header_->target_entry_count);
|
||||
auto entry = std::lower_bound(first_entry, end_entry, target_res_id, compare_target_entries);
|
||||
|
||||
if (entry == end_entry || dtohl(entry->target_id) != target_res_id) {
|
||||
// A mapping for the target resource id could not be found.
|
||||
return {};
|
||||
}
|
||||
|
||||
// A reference should be treated as an alias of the resource. Instead of returning the table
|
||||
// entry, return the alias resource id to look up. The alias resource might not reside within the
|
||||
// overlay package, so the resource id must be fixed with the dynamic reference table of the
|
||||
// overlay before returning.
|
||||
if (entry->type == Res_value::TYPE_REFERENCE
|
||||
|| entry->type == Res_value::TYPE_DYNAMIC_REFERENCE) {
|
||||
uint32_t overlay_resource_id = dtohl(entry->value);
|
||||
// Check if the target resource is mapped to an overlay resource.
|
||||
auto first_entry = entries_;
|
||||
auto end_entry = entries_ + dtohl(data_header_->target_entry_count);
|
||||
auto entry = std::lower_bound(first_entry, end_entry, target_res_id,
|
||||
[](const Idmap_target_entry &e, const uint32_t target_id) {
|
||||
return dtohl(e.target_id) < target_id;
|
||||
});
|
||||
|
||||
if (entry != end_entry && dtohl(entry->target_id) == target_res_id) {
|
||||
uint32_t overlay_resource_id = dtohl(entry->overlay_id);
|
||||
// Lookup the resource without rewriting the overlay resource id back to the target resource id
|
||||
// being looked up.
|
||||
overlay_ref_table_->lookupResourceIdNoRewrite(&overlay_resource_id);
|
||||
return Result(overlay_resource_id);
|
||||
}
|
||||
|
||||
// Copy the type and value into the ResTable_entry structure needed by asset manager.
|
||||
uint16_t malloc_size = sizeof(ResTable_entry) + sizeof(Res_value);
|
||||
auto table_entry = reinterpret_cast<ResTable_entry*>(malloc(malloc_size));
|
||||
memset(table_entry, 0, malloc_size);
|
||||
table_entry->size = htods(sizeof(ResTable_entry));
|
||||
// Check if the target resources is mapped to an inline table entry.
|
||||
auto first_inline_entry = inline_entries_;
|
||||
auto end_inline_entry = inline_entries_ + dtohl(data_header_->target_inline_entry_count);
|
||||
auto inline_entry = std::lower_bound(first_inline_entry, end_inline_entry, target_res_id,
|
||||
[](const Idmap_target_entry_inline &e,
|
||||
const uint32_t target_id) {
|
||||
return dtohl(e.target_id) < target_id;
|
||||
});
|
||||
|
||||
auto table_value = reinterpret_cast<Res_value*>(reinterpret_cast<uint8_t*>(table_entry)
|
||||
+ sizeof(ResTable_entry));
|
||||
table_value->dataType = entry->type;
|
||||
table_value->data = entry->value;
|
||||
|
||||
return Result(ResTable_entry_handle::managed(table_entry, [](auto p) { free(p); }));
|
||||
if (inline_entry != end_inline_entry && dtohl(inline_entry->target_id) == target_res_id) {
|
||||
return Result(inline_entry->value);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static bool is_word_aligned(const void* data) {
|
||||
return (reinterpret_cast<uintptr_t>(data) & 0x03) == 0;
|
||||
return (reinterpret_cast<uintptr_t>(data) & 0x03U) == 0U;
|
||||
}
|
||||
|
||||
static bool IsValidIdmapHeader(const StringPiece& data) {
|
||||
@@ -175,7 +170,7 @@ static bool IsValidIdmapHeader(const StringPiece& data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Idmap_header* header = reinterpret_cast<const Idmap_header*>(data.data());
|
||||
auto header = reinterpret_cast<const Idmap_header*>(data.data());
|
||||
if (dtohl(header->magic) != kIdmapMagic) {
|
||||
LOG(ERROR) << StringPrintf("Invalid Idmap file: bad magic value (was 0x%08x, expected 0x%08x)",
|
||||
dtohl(header->magic), kIdmapMagic);
|
||||
@@ -198,11 +193,13 @@ LoadedIdmap::LoadedIdmap(std::string&& idmap_path,
|
||||
const Idmap_header* header,
|
||||
const Idmap_data_header* data_header,
|
||||
const Idmap_target_entry* target_entries,
|
||||
const Idmap_target_entry_inline* target_inline_entries,
|
||||
const Idmap_overlay_entry* overlay_entries,
|
||||
ResStringPool* string_pool)
|
||||
: header_(header),
|
||||
data_header_(data_header),
|
||||
target_entries_(target_entries),
|
||||
target_inline_entries_(target_inline_entries),
|
||||
overlay_entries_(overlay_entries),
|
||||
string_pool_(string_pool),
|
||||
idmap_path_(std::move(idmap_path)),
|
||||
@@ -233,7 +230,7 @@ std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_pa
|
||||
data_ptr += sizeof(*data_header);
|
||||
data_size -= sizeof(*data_header);
|
||||
|
||||
// Make sure there is enough space for the target entries declared in the header.
|
||||
// Make sure there is enough space for the target entries declared in the header
|
||||
const auto target_entries = reinterpret_cast<const Idmap_target_entry*>(data_ptr);
|
||||
if (data_size / sizeof(Idmap_target_entry) <
|
||||
static_cast<size_t>(dtohl(data_header->target_entry_count))) {
|
||||
@@ -248,6 +245,21 @@ std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_pa
|
||||
data_ptr += target_entry_size_bytes;
|
||||
data_size -= target_entry_size_bytes;
|
||||
|
||||
// Make sure there is enough space for the target entries declared in the header.
|
||||
const auto target_inline_entries = reinterpret_cast<const Idmap_target_entry_inline*>(data_ptr);
|
||||
if (data_size / sizeof(Idmap_target_entry_inline) <
|
||||
static_cast<size_t>(dtohl(data_header->target_inline_entry_count))) {
|
||||
LOG(ERROR) << StringPrintf("Idmap too small for the number of target inline entries (%d)",
|
||||
(int)dtohl(data_header->target_inline_entry_count));
|
||||
return {};
|
||||
}
|
||||
|
||||
// Advance the data pointer past the target entries.
|
||||
const size_t target_inline_entry_size_bytes =
|
||||
(dtohl(data_header->target_inline_entry_count) * sizeof(Idmap_target_entry_inline));
|
||||
data_ptr += target_inline_entry_size_bytes;
|
||||
data_size -= target_inline_entry_size_bytes;
|
||||
|
||||
// Make sure there is enough space for the overlay entries declared in the header.
|
||||
const auto overlay_entries = reinterpret_cast<const Idmap_overlay_entry*>(data_ptr);
|
||||
if (data_size / sizeof(Idmap_overlay_entry) <
|
||||
@@ -257,22 +269,26 @@ std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_pa
|
||||
return {};
|
||||
}
|
||||
|
||||
// Advance the data pointer past the target entries.
|
||||
// Advance the data pointer past the overlay entries.
|
||||
const size_t overlay_entry_size_bytes =
|
||||
(dtohl(data_header->overlay_entry_count) * sizeof(Idmap_overlay_entry));
|
||||
data_ptr += overlay_entry_size_bytes;
|
||||
data_size -= overlay_entry_size_bytes;
|
||||
|
||||
// Read the idmap string pool that holds the value of inline string entries.
|
||||
if (data_size < dtohl(data_header->string_pool_length)) {
|
||||
uint32_t string_pool_size = dtohl(*reinterpret_cast<const uint32_t*>(data_ptr));
|
||||
data_ptr += sizeof(uint32_t);
|
||||
data_size -= sizeof(uint32_t);
|
||||
|
||||
if (data_size < string_pool_size) {
|
||||
LOG(ERROR) << StringPrintf("Idmap too small for string pool (length %d)",
|
||||
(int)dtohl(data_header->string_pool_length));
|
||||
(int)string_pool_size);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto idmap_string_pool = util::make_unique<ResStringPool>();
|
||||
if (dtohl(data_header->string_pool_length) > 0) {
|
||||
status_t err = idmap_string_pool->setTo(data_ptr, dtohl(data_header->string_pool_length));
|
||||
if (string_pool_size > 0) {
|
||||
status_t err = idmap_string_pool->setTo(data_ptr, string_pool_size);
|
||||
if (err != NO_ERROR) {
|
||||
LOG(ERROR) << "idmap string pool corrupt.";
|
||||
return {};
|
||||
@@ -280,9 +296,10 @@ std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_pa
|
||||
}
|
||||
|
||||
// Can't use make_unique because LoadedIdmap constructor is private.
|
||||
std::unique_ptr<LoadedIdmap> loaded_idmap = std::unique_ptr<LoadedIdmap>(
|
||||
auto loaded_idmap = std::unique_ptr<LoadedIdmap>(
|
||||
new LoadedIdmap(idmap_path.to_string(), getFileModDate(idmap_path.data()), header,
|
||||
data_header, target_entries, overlay_entries, idmap_string_pool.release()));
|
||||
data_header, target_entries, target_inline_entries, overlay_entries,
|
||||
idmap_string_pool.release()));
|
||||
|
||||
return std::move(loaded_idmap);
|
||||
}
|
||||
|
||||
@@ -77,40 +77,40 @@ class OverlayDynamicRefTable : public DynamicRefTable {
|
||||
// A mapping of target resource ids to a values or resource ids that should overlay the target.
|
||||
class IdmapResMap {
|
||||
public:
|
||||
// Represents the result of a idmap lookup. The result can be one of three possibillities:
|
||||
// Represents the result of a idmap lookup. The result can be one of three possibilities:
|
||||
// 1) The result is a resource id which represents the overlay resource that should act as an
|
||||
// alias of the target resource.
|
||||
// 2) The result is a table entry which overlays the type and value of the target resource.
|
||||
// 3) The result is neither and the target resource is not overlaid.
|
||||
class Result {
|
||||
public:
|
||||
Result() : data_(nullptr) {};
|
||||
Result() = default;
|
||||
explicit Result(uint32_t value) : data_(value) {};
|
||||
explicit Result(ResTable_entry_handle&& value) : data_(value) { };
|
||||
explicit Result(const Res_value& value) : data_(value) { };
|
||||
|
||||
// Returns `true` if the resource is overlaid.
|
||||
inline explicit operator bool() const {
|
||||
return !std::get_if<nullptr_t>(&data_);
|
||||
explicit operator bool() const {
|
||||
return std::get_if<std::monostate>(&data_) == nullptr;
|
||||
}
|
||||
|
||||
inline bool IsResourceId() const {
|
||||
return std::get_if<uint32_t>(&data_);
|
||||
bool IsResourceId() const {
|
||||
return std::get_if<uint32_t>(&data_) != nullptr;
|
||||
}
|
||||
|
||||
inline uint32_t GetResourceId() const {
|
||||
return *std::get_if<uint32_t>(&data_);
|
||||
uint32_t GetResourceId() const {
|
||||
return std::get<uint32_t>(data_);
|
||||
}
|
||||
|
||||
inline bool IsTableEntry() const {
|
||||
return std::get_if<ResTable_entry_handle>(&data_);
|
||||
bool IsInlineValue() const {
|
||||
return std::get_if<Res_value>(&data_) != nullptr;
|
||||
}
|
||||
|
||||
inline const ResTable_entry_handle& GetTableEntry() const {
|
||||
return *std::get_if<ResTable_entry_handle>(&data_);
|
||||
const Res_value& GetInlineValue() const {
|
||||
return std::get<Res_value>(data_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::variant<uint32_t, nullptr_t, ResTable_entry_handle> data_;
|
||||
std::variant<std::monostate, uint32_t, Res_value> data_;
|
||||
};
|
||||
|
||||
// Looks up the value that overlays the target resource id.
|
||||
@@ -123,11 +123,13 @@ class IdmapResMap {
|
||||
private:
|
||||
explicit IdmapResMap(const Idmap_data_header* data_header,
|
||||
const Idmap_target_entry* entries,
|
||||
const Idmap_target_entry_inline* inline_entries,
|
||||
uint8_t target_assigned_package_id,
|
||||
const OverlayDynamicRefTable* overlay_ref_table);
|
||||
|
||||
const Idmap_data_header* data_header_;
|
||||
const Idmap_target_entry* entries_;
|
||||
const Idmap_target_entry_inline* inline_entries_;
|
||||
const uint8_t target_assigned_package_id_;
|
||||
const OverlayDynamicRefTable* overlay_ref_table_;
|
||||
|
||||
@@ -163,8 +165,8 @@ class LoadedIdmap {
|
||||
// Returns a mapping from target resource ids to overlay values.
|
||||
inline const IdmapResMap GetTargetResourcesMap(
|
||||
uint8_t target_assigned_package_id, const OverlayDynamicRefTable* overlay_ref_table) const {
|
||||
return IdmapResMap(data_header_, target_entries_, target_assigned_package_id,
|
||||
overlay_ref_table);
|
||||
return IdmapResMap(data_header_, target_entries_, target_inline_entries_,
|
||||
target_assigned_package_id, overlay_ref_table);
|
||||
}
|
||||
|
||||
// Returns a dynamic reference table for a loaded overlay package.
|
||||
@@ -184,6 +186,7 @@ class LoadedIdmap {
|
||||
const Idmap_header* header_;
|
||||
const Idmap_data_header* data_header_;
|
||||
const Idmap_target_entry* target_entries_;
|
||||
const Idmap_target_entry_inline* target_inline_entries_;
|
||||
const Idmap_overlay_entry* overlay_entries_;
|
||||
const std::unique_ptr<ResStringPool> string_pool_;
|
||||
|
||||
@@ -200,6 +203,7 @@ class LoadedIdmap {
|
||||
const Idmap_header* header,
|
||||
const Idmap_data_header* data_header,
|
||||
const Idmap_target_entry* target_entries,
|
||||
const Idmap_target_entry_inline* target_inline_entries,
|
||||
const Idmap_overlay_entry* overlay_entries,
|
||||
ResStringPool* string_pool);
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
namespace android {
|
||||
|
||||
constexpr const static uint32_t kIdmapMagic = 0x504D4449u;
|
||||
constexpr const static uint32_t kIdmapCurrentVersion = 0x00000004u;
|
||||
constexpr const static uint32_t kIdmapCurrentVersion = 0x00000005u;
|
||||
|
||||
/**
|
||||
* In C++11, char16_t is defined as *at least* 16 bits. We do a lot of
|
||||
@@ -1476,7 +1476,7 @@ struct ResTable_entry
|
||||
// If set, this is a weak resource and may be overriden by strong
|
||||
// resources of the same name/type. This is only useful during
|
||||
// linking with other resource tables.
|
||||
FLAG_WEAK = 0x0004
|
||||
FLAG_WEAK = 0x0004,
|
||||
};
|
||||
uint16_t flags;
|
||||
|
||||
@@ -1586,50 +1586,6 @@ struct ResTable_map
|
||||
Res_value value;
|
||||
};
|
||||
|
||||
|
||||
// A ResTable_entry variant that either holds an unmanaged pointer to a constant ResTable_entry or
|
||||
// holds a ResTable_entry which is tied to the lifetime of the handle.
|
||||
class ResTable_entry_handle {
|
||||
public:
|
||||
ResTable_entry_handle() = default;
|
||||
|
||||
ResTable_entry_handle(const ResTable_entry_handle& handle) {
|
||||
entry_ = handle.entry_;
|
||||
}
|
||||
|
||||
ResTable_entry_handle(ResTable_entry_handle&& handle) noexcept {
|
||||
entry_ = handle.entry_;
|
||||
}
|
||||
|
||||
inline static ResTable_entry_handle managed(ResTable_entry* entry, void (*deleter)(void *)) {
|
||||
return ResTable_entry_handle(std::shared_ptr<const ResTable_entry>(entry, deleter));
|
||||
}
|
||||
|
||||
inline static ResTable_entry_handle unmanaged(const ResTable_entry* entry) {
|
||||
return ResTable_entry_handle(std::shared_ptr<const ResTable_entry>(entry, [](auto /*p */){}));
|
||||
}
|
||||
|
||||
inline ResTable_entry_handle& operator=(const ResTable_entry_handle& handle) noexcept {
|
||||
entry_ = handle.entry_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline ResTable_entry_handle& operator=(ResTable_entry_handle&& handle) noexcept {
|
||||
entry_ = handle.entry_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const ResTable_entry* operator*() & {
|
||||
return entry_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
explicit ResTable_entry_handle(std::shared_ptr<const ResTable_entry> entry)
|
||||
: entry_(std::move(entry)) { }
|
||||
|
||||
std::shared_ptr<const ResTable_entry> entry_;
|
||||
};
|
||||
|
||||
/**
|
||||
* A package-id to package name mapping for any shared libraries used
|
||||
* in this resource table. The package-id's encoded in this resource
|
||||
@@ -1740,7 +1696,6 @@ inline ResTable_overlayable_policy_header::PolicyFlags& operator |=(
|
||||
return first;
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Idmap_header {
|
||||
// Always 0x504D4449 ('IDMP')
|
||||
uint32_t magic;
|
||||
@@ -1751,7 +1706,7 @@ struct Idmap_header {
|
||||
uint32_t overlay_crc32;
|
||||
|
||||
uint32_t fulfilled_policies;
|
||||
uint8_t enforce_overlayable;
|
||||
uint32_t enforce_overlayable;
|
||||
|
||||
uint8_t target_path[256];
|
||||
uint8_t overlay_path[256];
|
||||
@@ -1765,23 +1720,31 @@ struct Idmap_header {
|
||||
struct Idmap_data_header {
|
||||
uint8_t target_package_id;
|
||||
uint8_t overlay_package_id;
|
||||
|
||||
// Padding to ensure 4 byte alignment for target_entry_count
|
||||
uint16_t p0;
|
||||
|
||||
uint32_t target_entry_count;
|
||||
uint32_t target_inline_entry_count;
|
||||
uint32_t overlay_entry_count;
|
||||
|
||||
uint32_t string_pool_index_offset;
|
||||
uint32_t string_pool_length;
|
||||
};
|
||||
|
||||
struct Idmap_target_entry {
|
||||
uint32_t target_id;
|
||||
uint8_t type;
|
||||
uint32_t value;
|
||||
uint32_t overlay_id;
|
||||
};
|
||||
|
||||
struct Idmap_target_entry_inline {
|
||||
uint32_t target_id;
|
||||
Res_value value;
|
||||
};
|
||||
|
||||
struct Idmap_overlay_entry {
|
||||
uint32_t overlay_id;
|
||||
uint32_t target_id;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class AssetManager2;
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -57,7 +57,7 @@ final class IdmapManager {
|
||||
private final PackageManagerHelper mPackageManager;
|
||||
|
||||
/**
|
||||
* Package name of the reference package defined in 'config-signature' tag of
|
||||
* Package name of the reference package defined in 'overlay-config-signature' tag of
|
||||
* SystemConfig or empty String if tag not defined. This package is vetted on scan by
|
||||
* PackageManagerService that it's a system package and is used to check if overlay matches
|
||||
* its signature in order to fulfill the config_signature policy.
|
||||
@@ -159,7 +159,7 @@ final class IdmapManager {
|
||||
fulfilledPolicies |= OverlayablePolicy.ACTOR_SIGNATURE;
|
||||
}
|
||||
|
||||
// If SystemConfig defines 'config-signature' package, given that
|
||||
// If SystemConfig defines 'overlay-config-signature' package, given that
|
||||
// this package is vetted by OverlayManagerService that it's a
|
||||
// preinstalled package, check if overlay matches its signature.
|
||||
if (!TextUtils.isEmpty(mConfigSignaturePackage)
|
||||
|
||||
@@ -12165,9 +12165,10 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
// A non-preloaded overlay package, without <overlay android:targetName>, will
|
||||
// only be used if it is signed with the same certificate as its target OR if
|
||||
// it is signed with the same certificate as a reference package declared
|
||||
// in 'config-signature' tag of SystemConfig.
|
||||
// If the target is already installed or 'config-signature' tag in SystemConfig
|
||||
// is set, check this here to augment the last line of defence which is OMS.
|
||||
// in 'overlay-config-signature' tag of SystemConfig.
|
||||
// If the target is already installed or 'overlay-config-signature' tag in
|
||||
// SystemConfig is set, check this here to augment the last line of defense
|
||||
// which is OMS.
|
||||
if (pkg.getOverlayTargetName() == null) {
|
||||
final PackageSetting targetPkgSetting =
|
||||
mSettings.getPackageLPr(pkg.getOverlayTarget());
|
||||
|
||||
@@ -35,8 +35,8 @@ import java.util.function.BiConsumer;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceImplTestsBase {
|
||||
|
||||
private static final String OVERLAY = "com.dummy.overlay";
|
||||
private static final String TARGET = "com.dummy.target";
|
||||
private static final String OVERLAY = "com.test.overlay";
|
||||
private static final String TARGET = "com.test.target";
|
||||
private static final int USER = 0;
|
||||
|
||||
private static final String OVERLAY2 = OVERLAY + "2";
|
||||
|
||||
@@ -39,8 +39,8 @@ import java.util.Map;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTestsBase {
|
||||
|
||||
private static final String OVERLAY = "com.dummy.overlay";
|
||||
private static final String TARGET = "com.dummy.target";
|
||||
private static final String OVERLAY = "com.test.overlay";
|
||||
private static final String TARGET = "com.test.target";
|
||||
private static final int USER = 0;
|
||||
|
||||
private static final String OVERLAY2 = OVERLAY + "2";
|
||||
@@ -50,7 +50,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
|
||||
private static final String OVERLAY3 = OVERLAY + "3";
|
||||
private static final int USER3 = USER2 + 1;
|
||||
|
||||
private static final String CONFIG_SIGNATURE_REFERENCE_PKG = "com.dummy.ref";
|
||||
private static final String CONFIG_SIGNATURE_REFERENCE_PKG = "com.test.ref";
|
||||
private static final String CERT_CONFIG_OK = "config_certificate_ok";
|
||||
private static final String CERT_CONFIG_NOK = "config_certificate_nok";
|
||||
|
||||
@@ -149,7 +149,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
|
||||
installNewPackage(overlay(OVERLAY, TARGET), USER);
|
||||
assertState(STATE_MISSING_TARGET, OVERLAY, USER);
|
||||
|
||||
final DummyDeviceState.PackageBuilder target = target(TARGET);
|
||||
final FakeDeviceState.PackageBuilder target = target(TARGET);
|
||||
installNewPackage(target, USER);
|
||||
assertState(STATE_DISABLED, OVERLAY, USER);
|
||||
|
||||
@@ -169,9 +169,9 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
|
||||
|
||||
@Test
|
||||
public void testOnOverlayPackageUpgraded() {
|
||||
final DummyListener listener = getListener();
|
||||
final DummyDeviceState.PackageBuilder target = target(TARGET);
|
||||
final DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET);
|
||||
final FakeListener listener = getListener();
|
||||
final FakeDeviceState.PackageBuilder target = target(TARGET);
|
||||
final FakeDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET);
|
||||
installNewPackage(target, USER);
|
||||
installNewPackage(overlay, USER);
|
||||
listener.count = 0;
|
||||
@@ -181,7 +181,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
|
||||
// upgrade to a version where the overlay has changed its target
|
||||
// expect once for the old target package, once for the new target package
|
||||
listener.count = 0;
|
||||
final DummyDeviceState.PackageBuilder overlay2 = overlay(OVERLAY, "some.other.target");
|
||||
final FakeDeviceState.PackageBuilder overlay2 = overlay(OVERLAY, "some.other.target");
|
||||
upgradePackage(overlay2, USER);
|
||||
assertEquals(3, listener.count);
|
||||
|
||||
@@ -193,7 +193,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
|
||||
@Test
|
||||
public void testListener() {
|
||||
final OverlayManagerServiceImpl impl = getImpl();
|
||||
final DummyListener listener = getListener();
|
||||
final FakeListener listener = getListener();
|
||||
installNewPackage(overlay(OVERLAY, TARGET), USER);
|
||||
assertEquals(1, listener.count);
|
||||
listener.count = 0;
|
||||
@@ -219,12 +219,12 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
|
||||
installNewPackage(target(TARGET), USER);
|
||||
installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_OK), USER);
|
||||
|
||||
final DummyIdmapDaemon idmapd = getIdmapd();
|
||||
final DummyDeviceState state = getState();
|
||||
final FakeIdmapDaemon idmapd = getIdmapd();
|
||||
final FakeDeviceState state = getState();
|
||||
String overlayPath = state.select(OVERLAY, USER).apkPath;
|
||||
assertTrue(idmapd.idmapExists(overlayPath, USER));
|
||||
|
||||
DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
|
||||
FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
|
||||
assertTrue((CONFIG_SIGNATURE & idmap.policies) == CONFIG_SIGNATURE);
|
||||
}
|
||||
|
||||
@@ -237,12 +237,12 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
|
||||
installNewPackage(target(TARGET), USER);
|
||||
installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
|
||||
|
||||
final DummyIdmapDaemon idmapd = getIdmapd();
|
||||
final DummyDeviceState state = getState();
|
||||
final FakeIdmapDaemon idmapd = getIdmapd();
|
||||
final FakeDeviceState state = getState();
|
||||
String overlayPath = state.select(OVERLAY, USER).apkPath;
|
||||
assertTrue(idmapd.idmapExists(overlayPath, USER));
|
||||
|
||||
DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
|
||||
FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
|
||||
assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
|
||||
}
|
||||
|
||||
@@ -252,12 +252,12 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
|
||||
installNewPackage(target(TARGET), USER);
|
||||
installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
|
||||
|
||||
final DummyIdmapDaemon idmapd = getIdmapd();
|
||||
final DummyDeviceState state = getState();
|
||||
final FakeIdmapDaemon idmapd = getIdmapd();
|
||||
final FakeDeviceState state = getState();
|
||||
String overlayPath = state.select(OVERLAY, USER).apkPath;
|
||||
assertTrue(idmapd.idmapExists(overlayPath, USER));
|
||||
|
||||
DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
|
||||
FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
|
||||
assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
|
||||
}
|
||||
|
||||
@@ -266,12 +266,12 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
|
||||
installNewPackage(target(TARGET), USER);
|
||||
installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
|
||||
|
||||
final DummyIdmapDaemon idmapd = getIdmapd();
|
||||
final DummyDeviceState state = getState();
|
||||
final FakeIdmapDaemon idmapd = getIdmapd();
|
||||
final FakeDeviceState state = getState();
|
||||
String overlayPath = state.select(OVERLAY, USER).apkPath;
|
||||
assertTrue(idmapd.idmapExists(overlayPath, USER));
|
||||
|
||||
DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
|
||||
FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
|
||||
assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
|
||||
}
|
||||
|
||||
@@ -284,12 +284,12 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
|
||||
installNewPackage(target(TARGET), USER);
|
||||
installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
|
||||
|
||||
final DummyIdmapDaemon idmapd = getIdmapd();
|
||||
final DummyDeviceState state = getState();
|
||||
final FakeIdmapDaemon idmapd = getIdmapd();
|
||||
final FakeDeviceState state = getState();
|
||||
String overlayPath = state.select(OVERLAY, USER).apkPath;
|
||||
assertTrue(idmapd.idmapExists(overlayPath, USER));
|
||||
|
||||
DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
|
||||
FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
|
||||
assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,19 +48,19 @@ import java.util.stream.Collectors;
|
||||
/** Base class for creating {@link OverlayManagerServiceImplTests} tests. */
|
||||
class OverlayManagerServiceImplTestsBase {
|
||||
private OverlayManagerServiceImpl mImpl;
|
||||
private DummyDeviceState mState;
|
||||
private DummyListener mListener;
|
||||
private DummyPackageManagerHelper mPackageManager;
|
||||
private DummyIdmapDaemon mIdmapDaemon;
|
||||
private FakeDeviceState mState;
|
||||
private FakeListener mListener;
|
||||
private FakePackageManagerHelper mPackageManager;
|
||||
private FakeIdmapDaemon mIdmapDaemon;
|
||||
private OverlayConfig mOverlayConfig;
|
||||
private String mConfigSignaturePackageName;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mState = new DummyDeviceState();
|
||||
mListener = new DummyListener();
|
||||
mPackageManager = new DummyPackageManagerHelper(mState);
|
||||
mIdmapDaemon = new DummyIdmapDaemon(mState);
|
||||
mState = new FakeDeviceState();
|
||||
mListener = new FakeListener();
|
||||
mPackageManager = new FakePackageManagerHelper(mState);
|
||||
mIdmapDaemon = new FakeIdmapDaemon(mState);
|
||||
mOverlayConfig = mock(OverlayConfig.class);
|
||||
when(mOverlayConfig.getPriority(any())).thenReturn(OverlayConfig.DEFAULT_PRIORITY);
|
||||
when(mOverlayConfig.isEnabled(any())).thenReturn(false);
|
||||
@@ -81,15 +81,15 @@ class OverlayManagerServiceImplTestsBase {
|
||||
return mImpl;
|
||||
}
|
||||
|
||||
DummyListener getListener() {
|
||||
FakeListener getListener() {
|
||||
return mListener;
|
||||
}
|
||||
|
||||
DummyIdmapDaemon getIdmapd() {
|
||||
FakeIdmapDaemon getIdmapd() {
|
||||
return mIdmapDaemon;
|
||||
}
|
||||
|
||||
DummyDeviceState getState() {
|
||||
FakeDeviceState getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
@@ -116,27 +116,27 @@ class OverlayManagerServiceImplTestsBase {
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
DummyDeviceState.PackageBuilder app(String packageName) {
|
||||
return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
|
||||
FakeDeviceState.PackageBuilder app(String packageName) {
|
||||
return new FakeDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
|
||||
null /* targetOverlayableName */, "data");
|
||||
}
|
||||
|
||||
DummyDeviceState.PackageBuilder target(String packageName) {
|
||||
return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
|
||||
FakeDeviceState.PackageBuilder target(String packageName) {
|
||||
return new FakeDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
|
||||
null /* targetOverlayableName */, "");
|
||||
}
|
||||
|
||||
DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName) {
|
||||
FakeDeviceState.PackageBuilder overlay(String packageName, String targetPackageName) {
|
||||
return overlay(packageName, targetPackageName, null /* targetOverlayableName */);
|
||||
}
|
||||
|
||||
DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName,
|
||||
FakeDeviceState.PackageBuilder overlay(String packageName, String targetPackageName,
|
||||
String targetOverlayableName) {
|
||||
return new DummyDeviceState.PackageBuilder(packageName, targetPackageName,
|
||||
return new FakeDeviceState.PackageBuilder(packageName, targetPackageName,
|
||||
targetOverlayableName, "");
|
||||
}
|
||||
|
||||
void addPackage(DummyDeviceState.PackageBuilder pkg, int userId) {
|
||||
void addPackage(FakeDeviceState.PackageBuilder pkg, int userId) {
|
||||
mState.add(pkg, userId);
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ class OverlayManagerServiceImplTestsBase {
|
||||
*
|
||||
* @throws IllegalStateException if the package is currently installed
|
||||
*/
|
||||
void installNewPackage(DummyDeviceState.PackageBuilder pkg, int userId) {
|
||||
void installNewPackage(FakeDeviceState.PackageBuilder pkg, int userId) {
|
||||
if (mState.select(pkg.packageName, userId) != null) {
|
||||
throw new IllegalStateException("package " + pkg.packageName + " already installed");
|
||||
}
|
||||
@@ -178,8 +178,8 @@ class OverlayManagerServiceImplTestsBase {
|
||||
*
|
||||
* @throws IllegalStateException if the package is not currently installed
|
||||
*/
|
||||
void upgradePackage(DummyDeviceState.PackageBuilder pkg, int userId) {
|
||||
final DummyDeviceState.Package replacedPackage = mState.select(pkg.packageName, userId);
|
||||
void upgradePackage(FakeDeviceState.PackageBuilder pkg, int userId) {
|
||||
final FakeDeviceState.Package replacedPackage = mState.select(pkg.packageName, userId);
|
||||
if (replacedPackage == null) {
|
||||
throw new IllegalStateException("package " + pkg.packageName + " not installed");
|
||||
}
|
||||
@@ -204,7 +204,7 @@ class OverlayManagerServiceImplTestsBase {
|
||||
* @throws IllegalStateException if the package is not currently installed
|
||||
*/
|
||||
void uninstallPackage(String packageName, int userId) {
|
||||
final DummyDeviceState.Package pkg = mState.select(packageName, userId);
|
||||
final FakeDeviceState.Package pkg = mState.select(packageName, userId);
|
||||
if (pkg == null) {
|
||||
throw new IllegalStateException("package " + packageName+ " not installed");
|
||||
}
|
||||
@@ -217,7 +217,7 @@ class OverlayManagerServiceImplTestsBase {
|
||||
}
|
||||
|
||||
/** Represents the state of packages installed on a fake device. */
|
||||
static class DummyDeviceState {
|
||||
static class FakeDeviceState {
|
||||
private ArrayMap<String, Package> mPackages = new ArrayMap<>();
|
||||
|
||||
void add(PackageBuilder pkgBuilder, int userId) {
|
||||
@@ -333,16 +333,16 @@ class OverlayManagerServiceImplTestsBase {
|
||||
}
|
||||
}
|
||||
|
||||
final class DummyPackageManagerHelper implements PackageManagerHelper {
|
||||
private final DummyDeviceState mState;
|
||||
final class FakePackageManagerHelper implements PackageManagerHelper {
|
||||
private final FakeDeviceState mState;
|
||||
|
||||
private DummyPackageManagerHelper(DummyDeviceState state) {
|
||||
private FakePackageManagerHelper(FakeDeviceState state) {
|
||||
mState = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackageInfo getPackageInfo(@NonNull String packageName, int userId) {
|
||||
final DummyDeviceState.Package pkg = mState.select(packageName, userId);
|
||||
final FakeDeviceState.Package pkg = mState.select(packageName, userId);
|
||||
if (pkg == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -353,15 +353,15 @@ class OverlayManagerServiceImplTestsBase {
|
||||
pi.packageName = pkg.packageName;
|
||||
pi.overlayTarget = pkg.targetPackageName;
|
||||
pi.targetOverlayableName = pkg.targetOverlayableName;
|
||||
pi.overlayCategory = "dummy-category-" + pkg.targetPackageName;
|
||||
pi.overlayCategory = "Fake-category-" + pkg.targetPackageName;
|
||||
return pi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean signaturesMatching(@NonNull String packageName1,
|
||||
@NonNull String packageName2, int userId) {
|
||||
final DummyDeviceState.Package pkg1 = mState.select(packageName1, userId);
|
||||
final DummyDeviceState.Package pkg2 = mState.select(packageName2, userId);
|
||||
final FakeDeviceState.Package pkg1 = mState.select(packageName1, userId);
|
||||
final FakeDeviceState.Package pkg2 = mState.select(packageName2, userId);
|
||||
return pkg1 != null && pkg2 != null && pkg1.certificate.equals(pkg2.certificate);
|
||||
}
|
||||
|
||||
@@ -382,7 +382,7 @@ class OverlayManagerServiceImplTestsBase {
|
||||
@Override
|
||||
public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
|
||||
@NonNull String targetOverlayableName, int userId) {
|
||||
final DummyDeviceState.Package pkg = mState.select(packageName, userId);
|
||||
final FakeDeviceState.Package pkg = mState.select(packageName, userId);
|
||||
if (pkg == null || !pkg.overlayableNames.contains(targetOverlayableName)) {
|
||||
return null;
|
||||
}
|
||||
@@ -403,7 +403,7 @@ class OverlayManagerServiceImplTestsBase {
|
||||
|
||||
@Override
|
||||
public boolean doesTargetDefineOverlayable(String targetPackageName, int userId) {
|
||||
final DummyDeviceState.Package pkg = mState.select(targetPackageName, userId);
|
||||
final FakeDeviceState.Package pkg = mState.select(targetPackageName, userId);
|
||||
return pkg != null && pkg.overlayableNames.contains(targetPackageName);
|
||||
}
|
||||
|
||||
@@ -413,16 +413,16 @@ class OverlayManagerServiceImplTestsBase {
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyIdmapDaemon extends IdmapDaemon {
|
||||
private final DummyDeviceState mState;
|
||||
static class FakeIdmapDaemon extends IdmapDaemon {
|
||||
private final FakeDeviceState mState;
|
||||
private final ArrayMap<String, IdmapHeader> mIdmapFiles = new ArrayMap<>();
|
||||
|
||||
DummyIdmapDaemon(DummyDeviceState state) {
|
||||
FakeIdmapDaemon(FakeDeviceState state) {
|
||||
this.mState = state;
|
||||
}
|
||||
|
||||
private int getCrc(@NonNull final String path) {
|
||||
final DummyDeviceState.Package pkg = mState.selectFromPath(path);
|
||||
final FakeDeviceState.Package pkg = mState.selectFromPath(path);
|
||||
Assert.assertNotNull(pkg);
|
||||
return pkg.versionCode;
|
||||
}
|
||||
@@ -486,7 +486,7 @@ class OverlayManagerServiceImplTestsBase {
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyListener implements OverlayManagerServiceImpl.OverlayChangeListener {
|
||||
static class FakeListener implements OverlayManagerServiceImpl.OverlayChangeListener {
|
||||
public int count;
|
||||
|
||||
public void onOverlaysChanged(@NonNull String targetPackage, int userId) {
|
||||
|
||||
@@ -50,55 +50,55 @@ public class OverlayManagerSettingsTests {
|
||||
private OverlayManagerSettings mSettings;
|
||||
|
||||
private static final OverlayInfo OVERLAY_A0 = new OverlayInfo(
|
||||
"com.dummy.overlay_a",
|
||||
"com.dummy.target",
|
||||
"com.test.overlay_a",
|
||||
"com.test.target",
|
||||
null,
|
||||
"some-category",
|
||||
"/data/app/com.dummy.overlay_a-1/base.apk",
|
||||
"/data/app/com.test.overlay_a-1/base.apk",
|
||||
STATE_DISABLED,
|
||||
0,
|
||||
0,
|
||||
true);
|
||||
|
||||
private static final OverlayInfo OVERLAY_B0 = new OverlayInfo(
|
||||
"com.dummy.overlay_b",
|
||||
"com.dummy.target",
|
||||
"com.test.overlay_b",
|
||||
"com.test.target",
|
||||
null,
|
||||
"some-category",
|
||||
"/data/app/com.dummy.overlay_b-1/base.apk",
|
||||
"/data/app/com.test.overlay_b-1/base.apk",
|
||||
STATE_DISABLED,
|
||||
0,
|
||||
0,
|
||||
true);
|
||||
|
||||
private static final OverlayInfo OVERLAY_C0 = new OverlayInfo(
|
||||
"com.dummy.overlay_c",
|
||||
"com.dummy.target",
|
||||
"com.test.overlay_c",
|
||||
"com.test.target",
|
||||
null,
|
||||
"some-category",
|
||||
"/data/app/com.dummy.overlay_c-1/base.apk",
|
||||
"/data/app/com.test.overlay_c-1/base.apk",
|
||||
STATE_DISABLED,
|
||||
0,
|
||||
0,
|
||||
true);
|
||||
|
||||
private static final OverlayInfo OVERLAY_A1 = new OverlayInfo(
|
||||
"com.dummy.overlay_a",
|
||||
"com.dummy.target",
|
||||
"com.test.overlay_a",
|
||||
"com.test.target",
|
||||
null,
|
||||
"some-category",
|
||||
"/data/app/com.dummy.overlay_a-1/base.apk",
|
||||
"/data/app/com.test.overlay_a-1/base.apk",
|
||||
STATE_DISABLED,
|
||||
1,
|
||||
0,
|
||||
true);
|
||||
|
||||
private static final OverlayInfo OVERLAY_B1 = new OverlayInfo(
|
||||
"com.dummy.overlay_b",
|
||||
"com.dummy.target",
|
||||
"com.test.overlay_b",
|
||||
"com.test.target",
|
||||
null,
|
||||
"some-category",
|
||||
"/data/app/com.dummy.overlay_b-1/base.apk",
|
||||
"/data/app/com.test.overlay_b-1/base.apk",
|
||||
STATE_DISABLED,
|
||||
1,
|
||||
0,
|
||||
@@ -230,11 +230,11 @@ public class OverlayManagerSettingsTests {
|
||||
assertListsAreEqual(list, OVERLAY_A0, OVERLAY_C0, OVERLAY_B0);
|
||||
|
||||
OverlayInfo otherTarget = new OverlayInfo(
|
||||
"com.dummy.overlay_other",
|
||||
"com.dummy.some.other.target",
|
||||
"com.test.overlay_other",
|
||||
"com.test.some.other.target",
|
||||
null,
|
||||
"some-category",
|
||||
"/data/app/com.dummy.overlay_other-1/base.apk",
|
||||
"/data/app/com.test.overlay_other-1/base.apk",
|
||||
STATE_DISABLED,
|
||||
0,
|
||||
0,
|
||||
@@ -350,7 +350,7 @@ public class OverlayManagerSettingsTests {
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
|
||||
|
||||
mSettings.restore(is);
|
||||
assertDoesNotContain(mSettings, "com.dummy.overlay", 0);
|
||||
assertDoesNotContain(mSettings, "com.test.overlay", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -359,27 +359,27 @@ public class OverlayManagerSettingsTests {
|
||||
final String xml =
|
||||
"<?xml version='1.0' encoding='utf-8' standalone='yes'?>\n"
|
||||
+ "<overlays version='" + version + "'>\n"
|
||||
+ "<item packageName='com.dummy.overlay'\n"
|
||||
+ "<item packageName='com.test.overlay'\n"
|
||||
+ " userId='1234'\n"
|
||||
+ " targetPackageName='com.dummy.target'\n"
|
||||
+ " baseCodePath='/data/app/com.dummy.overlay-1/base.apk'\n"
|
||||
+ " targetPackageName='com.test.target'\n"
|
||||
+ " baseCodePath='/data/app/com.test.overlay-1/base.apk'\n"
|
||||
+ " state='" + STATE_DISABLED + "'\n"
|
||||
+ " isEnabled='false'\n"
|
||||
+ " category='dummy-category'\n"
|
||||
+ " category='test-category'\n"
|
||||
+ " isStatic='false'\n"
|
||||
+ " priority='0' />\n"
|
||||
+ "</overlays>\n";
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
|
||||
|
||||
mSettings.restore(is);
|
||||
OverlayInfo oi = mSettings.getOverlayInfo("com.dummy.overlay", 1234);
|
||||
OverlayInfo oi = mSettings.getOverlayInfo("com.test.overlay", 1234);
|
||||
assertNotNull(oi);
|
||||
assertEquals("com.dummy.overlay", oi.packageName);
|
||||
assertEquals("com.dummy.target", oi.targetPackageName);
|
||||
assertEquals("/data/app/com.dummy.overlay-1/base.apk", oi.baseCodePath);
|
||||
assertEquals("com.test.overlay", oi.packageName);
|
||||
assertEquals("com.test.target", oi.targetPackageName);
|
||||
assertEquals("/data/app/com.test.overlay-1/base.apk", oi.baseCodePath);
|
||||
assertEquals(1234, oi.userId);
|
||||
assertEquals(STATE_DISABLED, oi.state);
|
||||
assertFalse(mSettings.getEnabled("com.dummy.overlay", 1234));
|
||||
assertFalse(mSettings.getEnabled("com.test.overlay", 1234));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user