| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2017 The Android Open Source Project | 
|  | 3 | * | 
|  | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | * you may not use this file except in compliance with the License. | 
|  | 6 | * You may obtain a copy of the License at | 
|  | 7 | * | 
|  | 8 | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | * | 
|  | 10 | * Unless required by applicable law or agreed to in writing, software | 
|  | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | * See the License for the specific language governing permissions and | 
|  | 14 | * limitations under the License. | 
|  | 15 | */ | 
|  | 16 |  | 
|  | 17 | #define ATRACE_TAG ATRACE_TAG_RESOURCES | 
|  | 18 |  | 
|  | 19 | #include "androidfw/Idmap.h" | 
|  | 20 |  | 
|  | 21 | #include "android-base/logging.h" | 
|  | 22 | #include "android-base/stringprintf.h" | 
| Ryan Mitchell | a909305 | 2020-03-26 17:15:01 -0700 | [diff] [blame] | 23 | #include "androidfw/misc.h" | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 24 | #include "androidfw/ResourceTypes.h" | 
|  | 25 | #include "androidfw/Util.h" | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 26 | #include "utils/ByteOrder.h" | 
|  | 27 | #include "utils/Trace.h" | 
|  | 28 |  | 
|  | 29 | #ifdef _WIN32 | 
|  | 30 | #ifdef ERROR | 
|  | 31 | #undef ERROR | 
|  | 32 | #endif | 
|  | 33 | #endif | 
|  | 34 |  | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 35 | using ::android::base::StringPrintf; | 
|  | 36 |  | 
|  | 37 | namespace android { | 
|  | 38 |  | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 39 | // See frameworks/base/cmds/idmap2/include/idmap2/Idmap.h for full idmap file format specification. | 
|  | 40 | struct Idmap_header { | 
|  | 41 | // Always 0x504D4449 ('IDMP') | 
|  | 42 | uint32_t magic; | 
|  | 43 | uint32_t version; | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 44 |  | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 45 | uint32_t target_crc32; | 
|  | 46 | uint32_t overlay_crc32; | 
|  | 47 |  | 
|  | 48 | uint32_t fulfilled_policies; | 
|  | 49 | uint32_t enforce_overlayable; | 
|  | 50 |  | 
|  | 51 | // overlay_path, target_path, and other string values encoded in the idmap header and read and | 
|  | 52 | // stored in separate structures. This allows the idmap header data to be casted to this struct | 
|  | 53 | // without having to read/store each header entry separately. | 
|  | 54 | }; | 
|  | 55 |  | 
|  | 56 | struct Idmap_data_header { | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 57 | uint32_t target_entry_count; | 
|  | 58 | uint32_t target_inline_entry_count; | 
|  | 59 | uint32_t overlay_entry_count; | 
|  | 60 |  | 
|  | 61 | uint32_t string_pool_index_offset; | 
|  | 62 | }; | 
|  | 63 |  | 
|  | 64 | struct Idmap_target_entry { | 
|  | 65 | uint32_t target_id; | 
|  | 66 | uint32_t overlay_id; | 
|  | 67 | }; | 
|  | 68 |  | 
|  | 69 | struct Idmap_target_entry_inline { | 
|  | 70 | uint32_t target_id; | 
|  | 71 | Res_value value; | 
|  | 72 | }; | 
|  | 73 |  | 
|  | 74 | struct Idmap_overlay_entry { | 
|  | 75 | uint32_t overlay_id; | 
|  | 76 | uint32_t target_id; | 
|  | 77 | }; | 
| MÃ¥rten Kongstad | d7e8a53 | 2019-10-11 08:32:04 +0200 | [diff] [blame] | 78 |  | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 79 | OverlayStringPool::OverlayStringPool(const LoadedIdmap* loaded_idmap) | 
| Ryan Mitchell | 73bfe41 | 2019-11-12 16:22:04 -0800 | [diff] [blame] | 80 | : data_header_(loaded_idmap->data_header_), | 
|  | 81 | idmap_string_pool_(loaded_idmap->string_pool_.get()) { }; | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 82 |  | 
|  | 83 | OverlayStringPool::~OverlayStringPool() { | 
|  | 84 | uninit(); | 
|  | 85 | } | 
|  | 86 |  | 
| Ryan Mitchell | db21f09a | 2020-11-16 23:08:18 +0000 | [diff] [blame] | 87 | base::expected<StringPiece16, NullOrIOError> OverlayStringPool::stringAt(size_t idx) const { | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 88 | const size_t offset = dtohl(data_header_->string_pool_index_offset); | 
| Ryan Mitchell | df9e732 | 2019-12-12 10:23:54 -0800 | [diff] [blame] | 89 | if (idmap_string_pool_ != nullptr && idx >= ResStringPool::size() && idx >= offset) { | 
| Ryan Mitchell | db21f09a | 2020-11-16 23:08:18 +0000 | [diff] [blame] | 90 | return idmap_string_pool_->stringAt(idx - offset); | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 91 | } | 
|  | 92 |  | 
| Ryan Mitchell | db21f09a | 2020-11-16 23:08:18 +0000 | [diff] [blame] | 93 | return ResStringPool::stringAt(idx); | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 94 | } | 
|  | 95 |  | 
| Ryan Mitchell | db21f09a | 2020-11-16 23:08:18 +0000 | [diff] [blame] | 96 | base::expected<StringPiece, NullOrIOError> OverlayStringPool::string8At(size_t idx) const { | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 97 | const size_t offset = dtohl(data_header_->string_pool_index_offset); | 
| Ryan Mitchell | df9e732 | 2019-12-12 10:23:54 -0800 | [diff] [blame] | 98 | if (idmap_string_pool_ != nullptr && idx >= ResStringPool::size() && idx >= offset) { | 
| Ryan Mitchell | db21f09a | 2020-11-16 23:08:18 +0000 | [diff] [blame] | 99 | return idmap_string_pool_->string8At(idx - offset); | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 100 | } | 
|  | 101 |  | 
| Ryan Mitchell | db21f09a | 2020-11-16 23:08:18 +0000 | [diff] [blame] | 102 | return ResStringPool::string8At(idx); | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 103 | } | 
|  | 104 |  | 
| Ryan Mitchell | df9e732 | 2019-12-12 10:23:54 -0800 | [diff] [blame] | 105 | size_t OverlayStringPool::size() const { | 
|  | 106 | return ResStringPool::size() + (idmap_string_pool_ != nullptr ? idmap_string_pool_->size() : 0U); | 
|  | 107 | } | 
|  | 108 |  | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 109 | OverlayDynamicRefTable::OverlayDynamicRefTable(const Idmap_data_header* data_header, | 
|  | 110 | const Idmap_overlay_entry* entries, | 
|  | 111 | uint8_t target_assigned_package_id) | 
|  | 112 | : data_header_(data_header), | 
|  | 113 | entries_(entries), | 
|  | 114 | target_assigned_package_id_(target_assigned_package_id) { }; | 
|  | 115 |  | 
|  | 116 | status_t OverlayDynamicRefTable::lookupResourceId(uint32_t* resId) const { | 
|  | 117 | const Idmap_overlay_entry* first_entry = entries_; | 
|  | 118 | const Idmap_overlay_entry* end_entry = entries_ + dtohl(data_header_->overlay_entry_count); | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 119 | auto entry = std::lower_bound(first_entry, end_entry, *resId, | 
|  | 120 | [](const Idmap_overlay_entry& e1, const uint32_t overlay_id) { | 
|  | 121 | return dtohl(e1.overlay_id) < overlay_id; | 
|  | 122 | }); | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 123 |  | 
|  | 124 | if (entry == end_entry || dtohl(entry->overlay_id) != *resId) { | 
|  | 125 | // A mapping for the target resource id could not be found. | 
|  | 126 | return DynamicRefTable::lookupResourceId(resId); | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 127 | } | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 128 |  | 
|  | 129 | *resId = (0x00FFFFFFU & dtohl(entry->target_id)) | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 130 | | (((uint32_t) target_assigned_package_id_) << 24U); | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 131 | return NO_ERROR; | 
|  | 132 | } | 
|  | 133 |  | 
|  | 134 | status_t OverlayDynamicRefTable::lookupResourceIdNoRewrite(uint32_t* resId) const { | 
|  | 135 | return DynamicRefTable::lookupResourceId(resId); | 
|  | 136 | } | 
|  | 137 |  | 
|  | 138 | IdmapResMap::IdmapResMap(const Idmap_data_header* data_header, | 
|  | 139 | const Idmap_target_entry* entries, | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 140 | const Idmap_target_entry_inline* inline_entries, | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 141 | uint8_t target_assigned_package_id, | 
|  | 142 | const OverlayDynamicRefTable* overlay_ref_table) | 
|  | 143 | : data_header_(data_header), | 
|  | 144 | entries_(entries), | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 145 | inline_entries_(inline_entries), | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 146 | target_assigned_package_id_(target_assigned_package_id), | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 147 | overlay_ref_table_(overlay_ref_table) { } | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 148 |  | 
|  | 149 | IdmapResMap::Result IdmapResMap::Lookup(uint32_t target_res_id) const { | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 150 | if ((target_res_id >> 24U) != target_assigned_package_id_) { | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 151 | // The resource id must have the same package id as the target package. | 
|  | 152 | return {}; | 
|  | 153 | } | 
|  | 154 |  | 
| Ryan Mitchell | 2ed8bfa | 2021-01-08 13:34:28 -0800 | [diff] [blame] | 155 | // The resource ids encoded within the idmap are build-time resource ids so do not consider the | 
|  | 156 | // package id when determining if the resource in the target package is overlaid. | 
|  | 157 | target_res_id &= 0x00FFFFFFU; | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 158 |  | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 159 | // Check if the target resource is mapped to an overlay resource. | 
|  | 160 | auto first_entry = entries_; | 
|  | 161 | auto end_entry = entries_ + dtohl(data_header_->target_entry_count); | 
|  | 162 | auto entry = std::lower_bound(first_entry, end_entry, target_res_id, | 
| Ryan Mitchell | 2ed8bfa | 2021-01-08 13:34:28 -0800 | [diff] [blame] | 163 | [](const Idmap_target_entry& e, const uint32_t target_id) { | 
|  | 164 | return (0x00FFFFFFU & dtohl(e.target_id)) < target_id; | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 165 | }); | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 166 |  | 
| Ryan Mitchell | 2ed8bfa | 2021-01-08 13:34:28 -0800 | [diff] [blame] | 167 | if (entry != end_entry && (0x00FFFFFFU & dtohl(entry->target_id)) == target_res_id) { | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 168 | uint32_t overlay_resource_id = dtohl(entry->overlay_id); | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 169 | // Lookup the resource without rewriting the overlay resource id back to the target resource id | 
|  | 170 | // being looked up. | 
|  | 171 | overlay_ref_table_->lookupResourceIdNoRewrite(&overlay_resource_id); | 
|  | 172 | return Result(overlay_resource_id); | 
|  | 173 | } | 
|  | 174 |  | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 175 | // Check if the target resources is mapped to an inline table entry. | 
|  | 176 | auto first_inline_entry = inline_entries_; | 
|  | 177 | auto end_inline_entry = inline_entries_ + dtohl(data_header_->target_inline_entry_count); | 
|  | 178 | auto inline_entry = std::lower_bound(first_inline_entry, end_inline_entry, target_res_id, | 
| Ryan Mitchell | 2ed8bfa | 2021-01-08 13:34:28 -0800 | [diff] [blame] | 179 | [](const Idmap_target_entry_inline& e, | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 180 | const uint32_t target_id) { | 
| Ryan Mitchell | 2ed8bfa | 2021-01-08 13:34:28 -0800 | [diff] [blame] | 181 | return (0x00FFFFFFU & dtohl(e.target_id)) < target_id; | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 182 | }); | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 183 |  | 
| Ryan Mitchell | 2ed8bfa | 2021-01-08 13:34:28 -0800 | [diff] [blame] | 184 | if (inline_entry != end_inline_entry && | 
|  | 185 | (0x00FFFFFFU & dtohl(inline_entry->target_id)) == target_res_id) { | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 186 | return Result(inline_entry->value); | 
|  | 187 | } | 
|  | 188 | return {}; | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 189 | } | 
|  | 190 |  | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 191 | namespace { | 
|  | 192 | template <typename T> | 
|  | 193 | const T* ReadType(const uint8_t** in_out_data_ptr, size_t* in_out_size, const std::string& label, | 
|  | 194 | size_t count = 1) { | 
|  | 195 | if (!util::IsFourByteAligned(*in_out_data_ptr)) { | 
|  | 196 | LOG(ERROR) << "Idmap " << label << " is not word aligned."; | 
|  | 197 | return {}; | 
|  | 198 | } | 
|  | 199 | if ((*in_out_size / sizeof(T)) < count) { | 
|  | 200 | LOG(ERROR) << "Idmap too small for the number of " << label << " entries (" | 
|  | 201 | << count << ")."; | 
|  | 202 | return nullptr; | 
|  | 203 | } | 
|  | 204 | auto data_ptr = *in_out_data_ptr; | 
|  | 205 | const size_t read_size = sizeof(T) * count; | 
|  | 206 | *in_out_data_ptr += read_size; | 
|  | 207 | *in_out_size -= read_size; | 
|  | 208 | return reinterpret_cast<const T*>(data_ptr); | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 209 | } | 
|  | 210 |  | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 211 | std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size_t* in_out_size, | 
|  | 212 | const std::string& label) { | 
|  | 213 | const auto* len = ReadType<uint32_t>(in_out_data_ptr, in_out_size, label + " length"); | 
|  | 214 | if (len == nullptr) { | 
|  | 215 | return {}; | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 216 | } | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 217 | const auto* data = ReadType<char>(in_out_data_ptr, in_out_size, label, *len); | 
|  | 218 | if (data == nullptr) { | 
|  | 219 | return {}; | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 220 | } | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 221 | // Strings are padded to the next 4 byte boundary. | 
|  | 222 | const uint32_t padding_size = (4U - ((size_t)*in_out_data_ptr & 0x3U)) % 4U; | 
|  | 223 | for (uint32_t i = 0; i < padding_size; i++) { | 
|  | 224 | if (**in_out_data_ptr != 0) { | 
|  | 225 | LOG(ERROR) << " Idmap padding of " << label << " is non-zero."; | 
|  | 226 | return {}; | 
|  | 227 | } | 
|  | 228 | *in_out_data_ptr += sizeof(uint8_t); | 
|  | 229 | *in_out_size -= sizeof(uint8_t); | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 230 | } | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 231 | return std::string_view(data, *len); | 
|  | 232 | } | 
| Ryan Mitchell | 2ed8bfa | 2021-01-08 13:34:28 -0800 | [diff] [blame] | 233 | } // namespace | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 234 |  | 
| Ryan Mitchell | a909305 | 2020-03-26 17:15:01 -0700 | [diff] [blame] | 235 | LoadedIdmap::LoadedIdmap(std::string&& idmap_path, | 
| Ryan Mitchell | a909305 | 2020-03-26 17:15:01 -0700 | [diff] [blame] | 236 | const Idmap_header* header, | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 237 | const Idmap_data_header* data_header, | 
|  | 238 | const Idmap_target_entry* target_entries, | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 239 | const Idmap_target_entry_inline* target_inline_entries, | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 240 | const Idmap_overlay_entry* overlay_entries, | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 241 | std::unique_ptr<ResStringPool>&& string_pool, | 
|  | 242 | std::string_view overlay_apk_path, | 
|  | 243 | std::string_view target_apk_path) | 
| Ryan Mitchell | 73bfe41 | 2019-11-12 16:22:04 -0800 | [diff] [blame] | 244 | : header_(header), | 
|  | 245 | data_header_(data_header), | 
|  | 246 | target_entries_(target_entries), | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 247 | target_inline_entries_(target_inline_entries), | 
| Ryan Mitchell | 73bfe41 | 2019-11-12 16:22:04 -0800 | [diff] [blame] | 248 | overlay_entries_(overlay_entries), | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 249 | string_pool_(std::move(string_pool)), | 
| Ryan Mitchell | a909305 | 2020-03-26 17:15:01 -0700 | [diff] [blame] | 250 | idmap_path_(std::move(idmap_path)), | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 251 | overlay_apk_path_(overlay_apk_path), | 
|  | 252 | target_apk_path_(target_apk_path), | 
|  | 253 | idmap_last_mod_time_(getFileModDate(idmap_path_.data())) {} | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 254 |  | 
| Ryan Mitchell | 1a48fa6 | 2021-01-10 08:36:36 -0800 | [diff] [blame] | 255 | std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_path, | 
|  | 256 | const StringPiece& idmap_data) { | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 257 | ATRACE_CALL(); | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 258 | size_t data_size = idmap_data.size(); | 
|  | 259 | auto data_ptr = reinterpret_cast<const uint8_t*>(idmap_data.data()); | 
|  | 260 |  | 
|  | 261 | // Parse the idmap header | 
|  | 262 | auto header = ReadType<Idmap_header>(&data_ptr, &data_size, "header"); | 
|  | 263 | if (header == nullptr) { | 
|  | 264 | return {}; | 
|  | 265 | } | 
|  | 266 | if (dtohl(header->magic) != kIdmapMagic) { | 
|  | 267 | LOG(ERROR) << StringPrintf("Invalid Idmap file: bad magic value (was 0x%08x, expected 0x%08x)", | 
|  | 268 | dtohl(header->magic), kIdmapMagic); | 
|  | 269 | return {}; | 
|  | 270 | } | 
|  | 271 | if (dtohl(header->version) != kIdmapCurrentVersion) { | 
|  | 272 | // We are strict about versions because files with this format are generated at runtime and | 
|  | 273 | // don't need backwards compatibility. | 
|  | 274 | LOG(ERROR) << StringPrintf("Version mismatch in Idmap (was 0x%08x, expected 0x%08x)", | 
|  | 275 | dtohl(header->version), kIdmapCurrentVersion); | 
|  | 276 | return {}; | 
|  | 277 | } | 
|  | 278 | std::optional<std::string_view> overlay_path = ReadString(&data_ptr, &data_size, "overlay path"); | 
|  | 279 | if (!overlay_path) { | 
|  | 280 | return {}; | 
|  | 281 | } | 
|  | 282 | std::optional<std::string_view> target_path = ReadString(&data_ptr, &data_size, "target path"); | 
|  | 283 | if (!target_path) { | 
|  | 284 | return {}; | 
|  | 285 | } | 
| Ryan Mitchell | 30dc2e0 | 2020-12-02 11:43:18 -0800 | [diff] [blame] | 286 | if (!ReadString(&data_ptr, &data_size, "target name") || | 
|  | 287 | !ReadString(&data_ptr, &data_size, "debug info")) { | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 288 | return {}; | 
|  | 289 | } | 
|  | 290 |  | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 291 | // Parse the idmap data blocks. Currently idmap2 can only generate one data block. | 
|  | 292 | auto data_header = ReadType<Idmap_data_header>(&data_ptr, &data_size, "data header"); | 
|  | 293 | if (data_header == nullptr) { | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 294 | return {}; | 
|  | 295 | } | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 296 | auto target_entries = ReadType<Idmap_target_entry>(&data_ptr, &data_size, "target", | 
|  | 297 | dtohl(data_header->target_entry_count)); | 
|  | 298 | if (target_entries == nullptr) { | 
| Ryan Mitchell | bf1f45b | 2020-09-29 17:22:52 -0700 | [diff] [blame] | 299 | return {}; | 
|  | 300 | } | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 301 | auto target_inline_entries = ReadType<Idmap_target_entry_inline>( | 
|  | 302 | &data_ptr, &data_size, "target inline", dtohl(data_header->target_inline_entry_count)); | 
|  | 303 | if (target_inline_entries == nullptr) { | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 304 | return {}; | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 305 | } | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 306 | auto overlay_entries = ReadType<Idmap_overlay_entry>(&data_ptr, &data_size, "target inline", | 
|  | 307 | dtohl(data_header->overlay_entry_count)); | 
|  | 308 | if (overlay_entries == nullptr) { | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 309 | return {}; | 
|  | 310 | } | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 311 | std::optional<std::string_view> string_pool = ReadString(&data_ptr, &data_size, "string pool"); | 
|  | 312 | if (!string_pool) { | 
|  | 313 | return {}; | 
|  | 314 | } | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 315 | auto idmap_string_pool = util::make_unique<ResStringPool>(); | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 316 | if (!string_pool->empty()) { | 
|  | 317 | const status_t err = idmap_string_pool->setTo(string_pool->data(), string_pool->size()); | 
| Ryan Mitchell | 8a891d8 | 2019-07-01 09:48:23 -0700 | [diff] [blame] | 318 | if (err != NO_ERROR) { | 
|  | 319 | LOG(ERROR) << "idmap string pool corrupt."; | 
|  | 320 | return {}; | 
|  | 321 | } | 
|  | 322 | } | 
|  | 323 |  | 
| Ryan Mitchell | 831b072 | 2021-01-13 10:11:18 -0800 | [diff] [blame] | 324 | if (data_size != 0) { | 
|  | 325 | LOG(ERROR) << "idmap parsed with " << data_size << "bytes remaining"; | 
|  | 326 | return {}; | 
|  | 327 | } | 
|  | 328 |  | 
| Ryan Mitchell | 73bfe41 | 2019-11-12 16:22:04 -0800 | [diff] [blame] | 329 | // Can't use make_unique because LoadedIdmap constructor is private. | 
| Ryan Mitchell | 0699f1d | 2020-12-03 15:41:42 -0800 | [diff] [blame] | 330 | return std::unique_ptr<LoadedIdmap>( | 
|  | 331 | new LoadedIdmap(idmap_path.to_string(), header, data_header, target_entries, | 
|  | 332 | target_inline_entries, overlay_entries, std::move(idmap_string_pool), | 
|  | 333 | *target_path, *overlay_path)); | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 334 | } | 
|  | 335 |  | 
| Ryan Mitchell | a909305 | 2020-03-26 17:15:01 -0700 | [diff] [blame] | 336 | bool LoadedIdmap::IsUpToDate() const { | 
|  | 337 | return idmap_last_mod_time_ == getFileModDate(idmap_path_.c_str()); | 
|  | 338 | } | 
|  | 339 |  | 
| Adam Lesinski | 970bd8d | 2017-09-25 13:21:55 -0700 | [diff] [blame] | 340 | }  // namespace android |