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/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index cb56a51..011a0de 100755
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -385,7 +385,7 @@
return {};
}
- auto overlay_path = loaded_idmap->OverlayApkPath();
+ auto overlay_path = std::string(loaded_idmap->OverlayApkPath());
auto assets = ZipAssetsProvider::Create(overlay_path);
return (assets) ? LoadImpl(std::move(assets), overlay_path, flags | PROPERTY_OVERLAY,
nullptr /* override_asset */, std::move(idmap_asset),
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index bec80a7..3f06000 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -157,7 +157,8 @@
// The target package must precede the overlay package in the apk assets paths in order
// to take effect.
const auto& loaded_idmap = apk_assets->GetLoadedIdmap();
- auto target_package_iter = apk_assets_package_ids.find(loaded_idmap->TargetApkPath());
+ auto target_package_iter = apk_assets_package_ids.find(
+ std::string(loaded_idmap->TargetApkPath()));
if (target_package_iter == apk_assets_package_ids.end()) {
LOG(INFO) << "failed to find target package for overlay "
<< loaded_idmap->OverlayApkPath();
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 {
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index fdab03b..fd9a8d13 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -31,6 +31,11 @@
class LoadedIdmap;
class IdmapResMap;
+struct Idmap_header;
+struct Idmap_data_header;
+struct Idmap_target_entry;
+struct Idmap_target_entry_inline;
+struct Idmap_overlay_entry;
// A string pool for overlay apk assets. The string pool holds the strings of the overlay resources
// table and additionally allows for loading strings from the idmap string pool. The idmap string
@@ -148,29 +153,29 @@
const StringPiece& idmap_data);
// Returns the path to the IDMAP.
- inline const std::string& IdmapPath() const {
+ std::string_view IdmapPath() const {
return idmap_path_;
}
// Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated.
- inline const std::string& OverlayApkPath() const {
+ std::string_view OverlayApkPath() const {
return overlay_apk_path_;
}
// Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated.
- inline const std::string& TargetApkPath() const {
+ std::string_view TargetApkPath() const {
return target_apk_path_;
}
// Returns a mapping from target resource ids to overlay values.
- inline const IdmapResMap GetTargetResourcesMap(
+ const IdmapResMap GetTargetResourcesMap(
uint8_t target_assigned_package_id, const OverlayDynamicRefTable* overlay_ref_table) const {
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.
- inline const OverlayDynamicRefTable GetOverlayDynamicRefTable(
+ const OverlayDynamicRefTable GetOverlayDynamicRefTable(
uint8_t target_assigned_package_id) const {
return OverlayDynamicRefTable(data_header_, overlay_entries_, target_assigned_package_id);
}
@@ -190,22 +195,23 @@
const Idmap_overlay_entry* overlay_entries_;
const std::unique_ptr<ResStringPool> string_pool_;
- const std::string idmap_path_;
- std::string overlay_apk_path_;
- std::string target_apk_path_;
- const time_t idmap_last_mod_time_;
+ std::string idmap_path_;
+ std::string_view overlay_apk_path_;
+ std::string_view target_apk_path_;
+ time_t idmap_last_mod_time_;
private:
DISALLOW_COPY_AND_ASSIGN(LoadedIdmap);
explicit LoadedIdmap(std::string&& idmap_path,
- 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);
friend OverlayStringPool;
};
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index fb5f864..d1622a0 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -44,7 +44,7 @@
namespace android {
constexpr const static uint32_t kIdmapMagic = 0x504D4449u;
-constexpr const static uint32_t kIdmapCurrentVersion = 0x00000005u;
+constexpr const static uint32_t kIdmapCurrentVersion = 0x00000006u;
/**
* In C++11, char16_t is defined as *at least* 16 bits. We do a lot of
@@ -1700,56 +1700,6 @@
return first;
}
-struct Idmap_header {
- // Always 0x504D4449 ('IDMP')
- uint32_t magic;
-
- uint32_t version;
-
- uint32_t target_crc32;
- uint32_t overlay_crc32;
-
- uint32_t fulfilled_policies;
- uint32_t enforce_overlayable;
-
- uint8_t target_path[256];
- uint8_t overlay_path[256];
-
- uint32_t debug_info_size;
- uint8_t debug_info[0];
-
- size_t Size() const;
-};
-
-struct Idmap_data_header {
- 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;
-};
-
class AssetManager2;
/**
diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h
index aceeecc..c59b5b6 100644
--- a/libs/androidfw/include/androidfw/Util.h
+++ b/libs/androidfw/include/androidfw/Util.h
@@ -128,10 +128,14 @@
std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep);
template <typename T>
-bool IsFourByteAligned(const incfs::map_ptr<T>& data) {
+inline bool IsFourByteAligned(const incfs::map_ptr<T>& data) {
return ((size_t)data.unsafe_ptr() & 0x3U) == 0;
}
+inline bool IsFourByteAligned(const void* data) {
+ return ((size_t)data & 0x3U) == 0;
+}
+
} // namespace util
} // namespace android
diff --git a/libs/androidfw/tests/data/overlay/overlay.idmap b/libs/androidfw/tests/data/overlay/overlay.idmap
index 3ab244e..6f0104a 100644
--- a/libs/androidfw/tests/data/overlay/overlay.idmap
+++ b/libs/androidfw/tests/data/overlay/overlay.idmap
Binary files differ