summaryrefslogtreecommitdiff
path: root/libs/androidfw/Idmap.cpp
diff options
context:
space:
mode:
authorRyan Mitchell <rtmitchell@google.com>2021-01-10 18:01:49 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2021-01-10 18:01:49 +0000
commit3d91609e47d43f8796b1f4989cdfe5081ba23e4b (patch)
treeb72d7954a37d61e244aba7c43600e9e2c8bd2579 /libs/androidfw/Idmap.cpp
parentd5d79830ad7506b36bfc2cbf823b3bb05d415653 (diff)
parentfb4d09cadd27a3fb1a2e268417f0f511aa92e344 (diff)
Merge changes I09965e58,I02316d0b,Ic240cdb8
* changes: Read manifest values using resource id in idmap2 Accept --overlay-name flag in idmap2 Remove idmap path 256 length limit
Diffstat (limited to 'libs/androidfw/Idmap.cpp')
-rw-r--r--libs/androidfw/Idmap.cpp251
1 files changed, 140 insertions, 111 deletions
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index a61309514143..73e040c42826 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -36,13 +36,51 @@ using ::android::base::StringPrintf;
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,133 @@ IdmapResMap::Result IdmapResMap::Lookup(uint32_t target_res_id) const {
return {};
}
-static bool is_word_aligned(const void* data) {
- return (reinterpret_cast<uintptr_t>(data) & 0x03U) == 0U;
-}
-
-static bool IsValidIdmapHeader(const StringPiece& data) {
- if (!is_word_aligned(data.data())) {
- LOG(ERROR) << "Idmap header is not word aligned.";
- return false;
+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 (data.size() < sizeof(Idmap_header)) {
- LOG(ERROR) << "Idmap header is too small.";
- return false;
+ 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);
+}
- 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;
+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 (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;
+ const auto* data = ReadType<char>(in_out_data_ptr, in_out_size, label, *len);
+ if (data == nullptr) {
+ return {};
}
-
- return true;
+ // 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);
+ }
+ 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 {};
}
-
- 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));
+ 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 {};
}
-
- // 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));
+ 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 {};
}
-
- // 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));
+ std::optional<std::string_view> overlay_path = ReadString(&data_ptr, &data_size, "overlay path");
+ if (!overlay_path) {
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);
+ std::optional<std::string_view> target_path = ReadString(&data_ptr, &data_size, "target path");
+ if (!target_path) {
+ return {};
+ }
+ if (!ReadString(&data_ptr, &data_size, "target name") ||
+ !ReadString(&data_ptr, &data_size, "debug info")) {
return {};
}
+ // 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 {};
+ }
+ auto target_entries = ReadType<Idmap_target_entry>(&data_ptr, &data_size, "target",
+ dtohl(data_header->target_entry_count));
+ if (target_entries == nullptr) {
+ return {};
+ }
+ 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 {};
+ }
+ 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 +327,10 @@ std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_pa
}
// 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 {