Remove idmap path 256 length limit
Overlay and target package paths can be longer than 256 characters.
Currently, the idmap will fail to be generated if either path
is longer than 256 characters.
This change removes the 256 character limit and makes parsing variable
length strings easier in libandroidfw.
Bug: 174676094
Test: idmap2_tests && libandroidfw_tests
Change-Id: Ic240cdb8700566b2ac2ade08da58bea852e4ae0c
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index a613095..68844be 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -36,13 +36,51 @@
namespace android {
-uint32_t round_to_4_bytes(uint32_t size) {
- return size + (4U - (size % 4U)) % 4U;
-}
+// See frameworks/base/cmds/idmap2/include/idmap2/Idmap.h for full idmap file format specification.
+struct Idmap_header {
+ // Always 0x504D4449 ('IDMP')
+ uint32_t magic;
+ uint32_t version;
-size_t Idmap_header::Size() const {
- return sizeof(Idmap_header) + sizeof(uint8_t) * round_to_4_bytes(dtohl(debug_info_size));
-}
+ uint32_t target_crc32;
+ uint32_t overlay_crc32;
+
+ uint32_t fulfilled_policies;
+ uint32_t enforce_overlayable;
+
+ // overlay_path, target_path, and other string values encoded in the idmap header and read and
+ // stored in separate structures. This allows the idmap header data to be casted to this struct
+ // without having to read/store each header entry separately.
+};
+
+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;
+};
+
+struct Idmap_target_entry {
+ uint32_t target_id;
+ 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;
+};
OverlayStringPool::OverlayStringPool(const LoadedIdmap* loaded_idmap)
: data_header_(loaded_idmap->data_header_),
@@ -155,140 +193,132 @@
return {};
}
-static bool is_word_aligned(const void* data) {
- return (reinterpret_cast<uintptr_t>(data) & 0x03U) == 0U;
+namespace {
+template <typename T>
+const T* ReadType(const uint8_t** in_out_data_ptr, size_t* in_out_size, const std::string& label,
+ size_t count = 1) {
+ if (!util::IsFourByteAligned(*in_out_data_ptr)) {
+ LOG(ERROR) << "Idmap " << label << " is not word aligned.";
+ return {};
+ }
+ if ((*in_out_size / sizeof(T)) < count) {
+ LOG(ERROR) << "Idmap too small for the number of " << label << " entries ("
+ << count << ").";
+ return nullptr;
+ }
+ auto data_ptr = *in_out_data_ptr;
+ const size_t read_size = sizeof(T) * count;
+ *in_out_data_ptr += read_size;
+ *in_out_size -= read_size;
+ return reinterpret_cast<const T*>(data_ptr);
}
-static bool IsValidIdmapHeader(const StringPiece& data) {
- if (!is_word_aligned(data.data())) {
- LOG(ERROR) << "Idmap header is not word aligned.";
- return false;
+std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size_t* in_out_size,
+ const std::string& label) {
+ const auto* len = ReadType<uint32_t>(in_out_data_ptr, in_out_size, label + " length");
+ if (len == nullptr) {
+ return {};
}
-
- if (data.size() < sizeof(Idmap_header)) {
- LOG(ERROR) << "Idmap header is too small.";
- return false;
+ const auto* data = ReadType<char>(in_out_data_ptr, in_out_size, label, *len);
+ if (data == nullptr) {
+ return {};
}
-
- 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);
- return false;
+ // Strings are padded to the next 4 byte boundary.
+ const uint32_t padding_size = (4U - ((size_t)*in_out_data_ptr & 0x3U)) % 4U;
+ for (uint32_t i = 0; i < padding_size; i++) {
+ if (**in_out_data_ptr != 0) {
+ LOG(ERROR) << " Idmap padding of " << label << " is non-zero.";
+ return {};
+ }
+ *in_out_data_ptr += sizeof(uint8_t);
+ *in_out_size -= sizeof(uint8_t);
}
-
- if (dtohl(header->version) != kIdmapCurrentVersion) {
- // We are strict about versions because files with this format are auto-generated and don't need
- // backwards compatibility.
- LOG(ERROR) << StringPrintf("Version mismatch in Idmap (was 0x%08x, expected 0x%08x)",
- dtohl(header->version), kIdmapCurrentVersion);
- return false;
- }
-
- return true;
+ return std::string_view(data, *len);
+}
}
LoadedIdmap::LoadedIdmap(std::string&& idmap_path,
- const time_t last_mod_time,
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)
+ std::unique_ptr<ResStringPool>&& string_pool,
+ std::string_view overlay_apk_path,
+ std::string_view target_apk_path)
: header_(header),
data_header_(data_header),
target_entries_(target_entries),
target_inline_entries_(target_inline_entries),
overlay_entries_(overlay_entries),
- string_pool_(string_pool),
+ string_pool_(std::move(string_pool)),
idmap_path_(std::move(idmap_path)),
- idmap_last_mod_time_(last_mod_time) {
-
- size_t length = strnlen(reinterpret_cast<const char*>(header_->overlay_path),
- arraysize(header_->overlay_path));
- overlay_apk_path_.assign(reinterpret_cast<const char*>(header_->overlay_path), length);
-
- length = strnlen(reinterpret_cast<const char*>(header_->target_path),
- arraysize(header_->target_path));
- target_apk_path_.assign(reinterpret_cast<const char*>(header_->target_path), length);
-}
+ overlay_apk_path_(overlay_apk_path),
+ target_apk_path_(target_apk_path),
+ idmap_last_mod_time_(getFileModDate(idmap_path_.data())) {}
std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_path,
const StringPiece& idmap_data) {
ATRACE_CALL();
- if (!IsValidIdmapHeader(idmap_data)) {
+ size_t data_size = idmap_data.size();
+ auto data_ptr = reinterpret_cast<const uint8_t*>(idmap_data.data());
+
+ // Parse the idmap header
+ auto header = ReadType<Idmap_header>(&data_ptr, &data_size, "header");
+ if (header == nullptr) {
+ return {};
+ }
+ if (dtohl(header->magic) != kIdmapMagic) {
+ LOG(ERROR) << StringPrintf("Invalid Idmap file: bad magic value (was 0x%08x, expected 0x%08x)",
+ dtohl(header->magic), kIdmapMagic);
+ return {};
+ }
+ if (dtohl(header->version) != kIdmapCurrentVersion) {
+ // We are strict about versions because files with this format are generated at runtime and
+ // don't need backwards compatibility.
+ LOG(ERROR) << StringPrintf("Version mismatch in Idmap (was 0x%08x, expected 0x%08x)",
+ dtohl(header->version), kIdmapCurrentVersion);
+ return {};
+ }
+ std::optional<std::string_view> overlay_path = ReadString(&data_ptr, &data_size, "overlay path");
+ if (!overlay_path) {
+ return {};
+ }
+ std::optional<std::string_view> target_path = ReadString(&data_ptr, &data_size, "target path");
+ if (!target_path) {
+ return {};
+ }
+ if (!ReadString(&data_ptr, &data_size, "debug info")) {
return {};
}
- auto header = reinterpret_cast<const Idmap_header*>(idmap_data.data());
- const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(idmap_data.data()) + header->Size();
- size_t data_size = idmap_data.size() - header->Size();
-
- // Currently idmap2 can only generate one data block.
- auto data_header = reinterpret_cast<const Idmap_data_header*>(data_ptr);
- data_ptr += sizeof(*data_header);
- data_size -= sizeof(*data_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))) {
- LOG(ERROR) << StringPrintf("Idmap too small for the number of target entries (%d)",
- (int)dtohl(data_header->target_entry_count));
+ // Parse the idmap data blocks. Currently idmap2 can only generate one data block.
+ auto data_header = ReadType<Idmap_data_header>(&data_ptr, &data_size, "data header");
+ if (data_header == nullptr) {
return {};
}
-
- // Advance the data pointer past the target entries.
- const size_t target_entry_size_bytes =
- (dtohl(data_header->target_entry_count) * sizeof(Idmap_target_entry));
- 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));
+ auto target_entries = ReadType<Idmap_target_entry>(&data_ptr, &data_size, "target",
+ dtohl(data_header->target_entry_count));
+ if (target_entries == nullptr) {
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) <
- static_cast<size_t>(dtohl(data_header->overlay_entry_count))) {
- LOG(ERROR) << StringPrintf("Idmap too small for the number of overlay entries (%d)",
- (int)dtohl(data_header->overlay_entry_count));
+ auto target_inline_entries = ReadType<Idmap_target_entry_inline>(
+ &data_ptr, &data_size, "target inline", dtohl(data_header->target_inline_entry_count));
+ if (target_inline_entries == nullptr) {
return {};
}
-
- // 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.
- 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)string_pool_size);
+ auto overlay_entries = ReadType<Idmap_overlay_entry>(&data_ptr, &data_size, "target inline",
+ dtohl(data_header->overlay_entry_count));
+ if (overlay_entries == nullptr) {
return {};
}
-
+ std::optional<std::string_view> string_pool = ReadString(&data_ptr, &data_size, "string pool");
+ if (!string_pool) {
+ return {};
+ }
auto idmap_string_pool = util::make_unique<ResStringPool>();
- if (string_pool_size > 0) {
- status_t err = idmap_string_pool->setTo(data_ptr, string_pool_size);
+ if (!string_pool->empty()) {
+ const status_t err = idmap_string_pool->setTo(string_pool->data(), string_pool->size());
if (err != NO_ERROR) {
LOG(ERROR) << "idmap string pool corrupt.";
return {};
@@ -296,12 +326,10 @@
}
// Can't use make_unique because LoadedIdmap constructor is private.
- auto loaded_idmap = std::unique_ptr<LoadedIdmap>(
- new LoadedIdmap(idmap_path.to_string(), getFileModDate(idmap_path.data()), header,
- data_header, target_entries, target_inline_entries, overlay_entries,
- idmap_string_pool.release()));
-
- return std::move(loaded_idmap);
+ return std::unique_ptr<LoadedIdmap>(
+ new LoadedIdmap(idmap_path.to_string(), header, data_header, target_entries,
+ target_inline_entries, overlay_entries, std::move(idmap_string_pool),
+ *target_path, *overlay_path));
}
bool LoadedIdmap::IsUpToDate() const {