LoadedArsc.cpp revision 33af6c730f9f7fc51f04516c7a22cac82cb9823e
1/* 2 * Copyright (C) 2016 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/LoadedArsc.h" 20 21#include <cstddef> 22#include <limits> 23 24#include "android-base/logging.h" 25#include "android-base/stringprintf.h" 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 35#include "androidfw/ByteBucketArray.h" 36#include "androidfw/Chunk.h" 37#include "androidfw/ResourceUtils.h" 38#include "androidfw/Util.h" 39 40using android::base::StringPrintf; 41 42namespace android { 43 44constexpr const static int kAppPackageId = 0x7f; 45 46// Element of a TypeSpec array. See TypeSpec. 47struct Type { 48 // The configuration for which this type defines entries. 49 // This is already converted to host endianness. 50 ResTable_config configuration; 51 52 // Pointer to the mmapped data where entry definitions are kept. 53 const ResTable_type* type; 54}; 55 56// TypeSpec is going to be immediately proceeded by 57// an array of Type structs, all in the same block of memory. 58struct TypeSpec { 59 // Pointer to the mmapped data where flags are kept. 60 // Flags denote whether the resource entry is public 61 // and under which configurations it varies. 62 const ResTable_typeSpec* type_spec; 63 64 // The number of types that follow this struct. 65 // There is a type for each configuration 66 // that entries are defined for. 67 size_t type_count; 68 69 // Trick to easily access a variable number of Type structs 70 // proceeding this struct, and to ensure their alignment. 71 const Type types[0]; 72}; 73 74// TypeSpecPtr points to the block of memory that holds 75// a TypeSpec struct, followed by an array of Type structs. 76// TypeSpecPtr is a managed pointer that knows how to delete 77// itself. 78using TypeSpecPtr = util::unique_cptr<TypeSpec>; 79 80namespace { 81 82// Builder that helps accumulate Type structs and then create a single 83// contiguous block of memory to store both the TypeSpec struct and 84// the Type structs. 85class TypeSpecPtrBuilder { 86 public: 87 TypeSpecPtrBuilder(const ResTable_typeSpec* header) : header_(header) {} 88 89 void AddType(const ResTable_type* type) { 90 ResTable_config config; 91 config.copyFromDtoH(type->config); 92 types_.push_back(Type{config, type}); 93 } 94 95 TypeSpecPtr Build() { 96 // Check for overflow. 97 if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(Type) < types_.size()) { 98 return {}; 99 } 100 TypeSpec* type_spec = (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(Type))); 101 type_spec->type_spec = header_; 102 type_spec->type_count = types_.size(); 103 memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(Type)); 104 return TypeSpecPtr(type_spec); 105 } 106 107 private: 108 DISALLOW_COPY_AND_ASSIGN(TypeSpecPtrBuilder); 109 110 const ResTable_typeSpec* header_; 111 std::vector<Type> types_; 112}; 113 114} // namespace 115 116bool LoadedPackage::FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config, 117 LoadedArscEntry* out_entry, ResTable_config* out_selected_config, 118 uint32_t* out_flags) const { 119 ATRACE_CALL(); 120 121 // If the type IDs are offset in this package, we need to take that into account when searching 122 // for a type. 123 const TypeSpecPtr& ptr = type_specs_[type_idx - type_id_offset_]; 124 if (ptr == nullptr) { 125 return false; 126 } 127 128 // Don't bother checking if the entry ID is larger than 129 // the number of entries. 130 if (entry_idx >= dtohl(ptr->type_spec->entryCount)) { 131 return false; 132 } 133 134 const ResTable_config* best_config = nullptr; 135 const ResTable_type* best_type = nullptr; 136 uint32_t best_offset = 0; 137 138 for (uint32_t i = 0; i < ptr->type_count; i++) { 139 const Type* type = &ptr->types[i]; 140 141 if (type->configuration.match(config) && 142 (best_config == nullptr || type->configuration.isBetterThan(*best_config, &config))) { 143 // The configuration matches and is better than the previous selection. 144 // Find the entry value if it exists for this configuration. 145 size_t entry_count = dtohl(type->type->entryCount); 146 if (entry_idx < entry_count) { 147 const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>( 148 reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize)); 149 const uint32_t offset = dtohl(entry_offsets[entry_idx]); 150 if (offset != ResTable_type::NO_ENTRY) { 151 // There is an entry for this resource, record it. 152 best_config = &type->configuration; 153 best_type = type->type; 154 best_offset = offset + dtohl(type->type->entriesStart); 155 } 156 } 157 } 158 } 159 160 if (best_type == nullptr) { 161 return false; 162 } 163 164 const uint32_t* flags = reinterpret_cast<const uint32_t*>(ptr->type_spec + 1); 165 *out_flags = dtohl(flags[entry_idx]); 166 *out_selected_config = *best_config; 167 168 const ResTable_entry* best_entry = reinterpret_cast<const ResTable_entry*>( 169 reinterpret_cast<const uint8_t*>(best_type) + best_offset); 170 out_entry->entry = best_entry; 171 out_entry->type_string_ref = StringPoolRef(&type_string_pool_, best_type->id - 1); 172 out_entry->entry_string_ref = StringPoolRef(&key_string_pool_, dtohl(best_entry->key.index)); 173 return true; 174} 175 176// The destructor gets generated into arbitrary translation units 177// if left implicit, which causes the compiler to complain about 178// forward declarations and incomplete types. 179LoadedArsc::~LoadedArsc() {} 180 181bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config, 182 LoadedArscEntry* out_entry, ResTable_config* out_selected_config, 183 uint32_t* out_flags) const { 184 ATRACE_CALL(); 185 const uint8_t package_id = get_package_id(resid); 186 const uint8_t type_id = get_type_id(resid); 187 const uint16_t entry_id = get_entry_id(resid); 188 189 if (type_id == 0) { 190 LOG(ERROR) << "Invalid ID 0x" << std::hex << resid << std::dec << "."; 191 return false; 192 } 193 194 for (const auto& loaded_package : packages_) { 195 if (loaded_package->package_id_ == package_id) { 196 return loaded_package->FindEntry(type_id - 1, entry_id, config, out_entry, 197 out_selected_config, out_flags); 198 } 199 } 200 return false; 201} 202 203const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const { 204 const uint8_t package_id = get_package_id(resid); 205 for (const auto& loaded_package : packages_) { 206 if (loaded_package->package_id_ == package_id) { 207 return loaded_package.get(); 208 } 209 } 210 return nullptr; 211} 212 213static bool VerifyType(const Chunk& chunk) { 214 ATRACE_CALL(); 215 const ResTable_type* header = chunk.header<ResTable_type, kResTableTypeMinSize>(); 216 217 const size_t entry_count = dtohl(header->entryCount); 218 if (entry_count > std::numeric_limits<uint16_t>::max()) { 219 LOG(ERROR) << "Too many entries in RES_TABLE_TYPE_TYPE."; 220 return false; 221 } 222 223 // Make sure that there is enough room for the entry offsets. 224 const size_t offsets_offset = chunk.header_size(); 225 const size_t entries_offset = dtohl(header->entriesStart); 226 const size_t offsets_length = sizeof(uint32_t) * entry_count; 227 228 if (offsets_offset + offsets_length > entries_offset) { 229 LOG(ERROR) << "Entry offsets overlap actual entry data."; 230 return false; 231 } 232 233 if (entries_offset > chunk.size()) { 234 LOG(ERROR) << "Entry offsets extend beyond chunk."; 235 return false; 236 } 237 238 if (entries_offset & 0x03) { 239 LOG(ERROR) << "Entries start at unaligned address."; 240 return false; 241 } 242 243 // Check each entry offset. 244 const uint32_t* offsets = 245 reinterpret_cast<const uint32_t*>(reinterpret_cast<const uint8_t*>(header) + offsets_offset); 246 for (size_t i = 0; i < entry_count; i++) { 247 uint32_t offset = dtohl(offsets[i]); 248 if (offset != ResTable_type::NO_ENTRY) { 249 // Check that the offset is aligned. 250 if (offset & 0x03) { 251 LOG(ERROR) << "Entry offset at index " << i << " is not 4-byte aligned."; 252 return false; 253 } 254 255 // Check that the offset doesn't overflow. 256 if (offset > std::numeric_limits<uint32_t>::max() - entries_offset) { 257 // Overflow in offset. 258 LOG(ERROR) << "Entry offset at index " << i << " is too large."; 259 return false; 260 } 261 262 offset += entries_offset; 263 if (offset > chunk.size() - sizeof(ResTable_entry)) { 264 LOG(ERROR) << "Entry offset at index " << i << " is too large. No room for ResTable_entry."; 265 return false; 266 } 267 268 const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>( 269 reinterpret_cast<const uint8_t*>(header) + offset); 270 const size_t entry_size = dtohs(entry->size); 271 if (entry_size < sizeof(*entry)) { 272 LOG(ERROR) << "ResTable_entry size " << entry_size << " is too small."; 273 return false; 274 } 275 276 // Check the declared entrySize. 277 if (entry_size > chunk.size() || offset > chunk.size() - entry_size) { 278 LOG(ERROR) << "ResTable_entry size " << entry_size << " is too large."; 279 return false; 280 } 281 282 // If this is a map entry, then keep validating. 283 if (entry_size >= sizeof(ResTable_map_entry)) { 284 const ResTable_map_entry* map = reinterpret_cast<const ResTable_map_entry*>(entry); 285 const size_t map_entry_count = dtohl(map->count); 286 287 size_t map_entries_start = offset + entry_size; 288 if (map_entries_start & 0x03) { 289 LOG(ERROR) << "Map entries start at unaligned offset."; 290 return false; 291 } 292 293 // Each entry is sizeof(ResTable_map) big. 294 if (map_entry_count > ((chunk.size() - map_entries_start) / sizeof(ResTable_map))) { 295 LOG(ERROR) << "Too many map entries in ResTable_map_entry."; 296 return false; 297 } 298 299 // Great, all the map entries fit!. 300 } else { 301 // There needs to be room for one Res_value struct. 302 if (offset + entry_size > chunk.size() - sizeof(Res_value)) { 303 LOG(ERROR) << "No room for Res_value after ResTable_entry."; 304 return false; 305 } 306 307 const Res_value* value = reinterpret_cast<const Res_value*>( 308 reinterpret_cast<const uint8_t*>(entry) + entry_size); 309 const size_t value_size = dtohs(value->size); 310 if (value_size < sizeof(Res_value)) { 311 LOG(ERROR) << "Res_value is too small."; 312 return false; 313 } 314 315 if (value_size > chunk.size() || offset + entry_size > chunk.size() - value_size) { 316 LOG(ERROR) << "Res_value size is too large."; 317 return false; 318 } 319 } 320 } 321 } 322 return true; 323} 324 325void LoadedPackage::CollectConfigurations(bool exclude_mipmap, 326 std::set<ResTable_config>* out_configs) const { 327 const static std::u16string kMipMap = u"mipmap"; 328 const size_t type_count = type_specs_.size(); 329 for (size_t i = 0; i < type_count; i++) { 330 const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i]; 331 if (type_spec != nullptr) { 332 if (exclude_mipmap) { 333 const int type_idx = type_spec->type_spec->id - 1; 334 size_t type_name_len; 335 const char16_t* type_name16 = type_string_pool_.stringAt(type_idx, &type_name_len); 336 if (type_name16 != nullptr) { 337 if (kMipMap.compare(0, std::u16string::npos, type_name16, type_name_len) == 0) { 338 // This is a mipmap type, skip collection. 339 continue; 340 } 341 } 342 const char* type_name = type_string_pool_.string8At(type_idx, &type_name_len); 343 if (type_name != nullptr) { 344 if (strncmp(type_name, "mipmap", type_name_len) == 0) { 345 // This is a mipmap type, skip collection. 346 continue; 347 } 348 } 349 } 350 351 for (size_t j = 0; j < type_spec->type_count; j++) { 352 out_configs->insert(type_spec->types[j].configuration); 353 } 354 } 355 } 356} 357 358void LoadedPackage::CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const { 359 char temp_locale[RESTABLE_MAX_LOCALE_LEN]; 360 const size_t type_count = type_specs_.size(); 361 for (size_t i = 0; i < type_count; i++) { 362 const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i]; 363 if (type_spec != nullptr) { 364 for (size_t j = 0; j < type_spec->type_count; j++) { 365 const ResTable_config& configuration = type_spec->types[j].configuration; 366 if (configuration.locale != 0) { 367 configuration.getBcp47Locale(temp_locale, canonicalize); 368 std::string locale(temp_locale); 369 out_locales->insert(std::move(locale)); 370 } 371 } 372 } 373 } 374} 375 376uint32_t LoadedPackage::FindEntryByName(const std::u16string& type_name, 377 const std::u16string& entry_name) const { 378 ssize_t type_idx = type_string_pool_.indexOfString(type_name.data(), type_name.size()); 379 if (type_idx < 0) { 380 return 0u; 381 } 382 383 ssize_t key_idx = key_string_pool_.indexOfString(entry_name.data(), entry_name.size()); 384 if (key_idx < 0) { 385 return 0u; 386 } 387 388 const TypeSpec* type_spec = type_specs_[type_idx].get(); 389 if (type_spec == nullptr) { 390 return 0u; 391 } 392 393 for (size_t ti = 0; ti < type_spec->type_count; ti++) { 394 const Type* type = &type_spec->types[ti]; 395 size_t entry_count = dtohl(type->type->entryCount); 396 for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) { 397 const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>( 398 reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize)); 399 const uint32_t offset = dtohl(entry_offsets[entry_idx]); 400 if (offset != ResTable_type::NO_ENTRY) { 401 const ResTable_entry* entry = 402 reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type->type) + 403 dtohl(type->type->entriesStart) + offset); 404 if (dtohl(entry->key.index) == static_cast<uint32_t>(key_idx)) { 405 // The package ID will be overridden by the caller (due to runtime assignment of package 406 // IDs for shared libraries). 407 return make_resid(0x00, type_idx + type_id_offset_ + 1, entry_idx); 408 } 409 } 410 } 411 } 412 return 0u; 413} 414 415std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) { 416 ATRACE_CALL(); 417 std::unique_ptr<LoadedPackage> loaded_package{new LoadedPackage()}; 418 419 constexpr size_t kMinPackageSize = 420 sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset); 421 const ResTable_package* header = chunk.header<ResTable_package, kMinPackageSize>(); 422 if (header == nullptr) { 423 LOG(ERROR) << "Chunk RES_TABLE_PACKAGE_TYPE is too small."; 424 return {}; 425 } 426 427 loaded_package->package_id_ = dtohl(header->id); 428 if (loaded_package->package_id_ == 0) { 429 // Package ID of 0 means this is a shared library. 430 loaded_package->dynamic_ = true; 431 } 432 433 if (header->header.headerSize >= sizeof(ResTable_package)) { 434 uint32_t type_id_offset = dtohl(header->typeIdOffset); 435 if (type_id_offset > std::numeric_limits<uint8_t>::max()) { 436 LOG(ERROR) << "Type ID offset in RES_TABLE_PACKAGE_TYPE is too large."; 437 return {}; 438 } 439 loaded_package->type_id_offset_ = static_cast<int>(type_id_offset); 440 } 441 442 util::ReadUtf16StringFromDevice(header->name, arraysize(header->name), 443 &loaded_package->package_name_); 444 445 // A TypeSpec builder. We use this to accumulate the set of Types 446 // available for a TypeSpec, and later build a single, contiguous block 447 // of memory that holds all the Types together with the TypeSpec. 448 std::unique_ptr<TypeSpecPtrBuilder> types_builder; 449 450 // Keep track of the last seen type index. Since type IDs are 1-based, 451 // this records their index, which is 0-based (type ID - 1). 452 uint8_t last_type_idx = 0; 453 454 ChunkIterator iter(chunk.data_ptr(), chunk.data_size()); 455 while (iter.HasNext()) { 456 const Chunk child_chunk = iter.Next(); 457 switch (child_chunk.type()) { 458 case RES_STRING_POOL_TYPE: { 459 const uintptr_t pool_address = 460 reinterpret_cast<uintptr_t>(child_chunk.header<ResChunk_header>()); 461 const uintptr_t header_address = reinterpret_cast<uintptr_t>(header); 462 if (pool_address == header_address + dtohl(header->typeStrings)) { 463 // This string pool is the type string pool. 464 status_t err = loaded_package->type_string_pool_.setTo( 465 child_chunk.header<ResStringPool_header>(), child_chunk.size()); 466 if (err != NO_ERROR) { 467 LOG(ERROR) << "Corrupt package type string pool."; 468 return {}; 469 } 470 } else if (pool_address == header_address + dtohl(header->keyStrings)) { 471 // This string pool is the key string pool. 472 status_t err = loaded_package->key_string_pool_.setTo( 473 child_chunk.header<ResStringPool_header>(), child_chunk.size()); 474 if (err != NO_ERROR) { 475 LOG(ERROR) << "Corrupt package key string pool."; 476 return {}; 477 } 478 } else { 479 LOG(WARNING) << "Too many string pool chunks found in package."; 480 } 481 } break; 482 483 case RES_TABLE_TYPE_SPEC_TYPE: { 484 ATRACE_NAME("LoadTableTypeSpec"); 485 486 // Starting a new TypeSpec, so finish the old one if there was one. 487 if (types_builder) { 488 TypeSpecPtr type_spec_ptr = types_builder->Build(); 489 if (type_spec_ptr == nullptr) { 490 LOG(ERROR) << "Too many type configurations, overflow detected."; 491 return {}; 492 } 493 loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr); 494 495 types_builder = {}; 496 last_type_idx = 0; 497 } 498 499 const ResTable_typeSpec* type_spec = child_chunk.header<ResTable_typeSpec>(); 500 if (type_spec == nullptr) { 501 LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE is too small."; 502 return {}; 503 } 504 505 if (type_spec->id == 0) { 506 LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE has invalid ID 0."; 507 return {}; 508 } 509 510 if (loaded_package->type_id_offset_ + static_cast<int>(type_spec->id) > 511 std::numeric_limits<uint8_t>::max()) { 512 LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE has out of range ID."; 513 return {}; 514 } 515 516 // The data portion of this chunk contains entry_count 32bit entries, 517 // each one representing a set of flags. 518 // Here we only validate that the chunk is well formed. 519 const size_t entry_count = dtohl(type_spec->entryCount); 520 521 // There can only be 2^16 entries in a type, because that is the ID 522 // space for entries (EEEE) in the resource ID 0xPPTTEEEE. 523 if (entry_count > std::numeric_limits<uint16_t>::max()) { 524 LOG(ERROR) << "Too many entries in RES_TABLE_TYPE_SPEC_TYPE: " << entry_count << "."; 525 return {}; 526 } 527 528 if (entry_count * sizeof(uint32_t) > chunk.data_size()) { 529 LOG(ERROR) << "Chunk too small to hold entries in RES_TABLE_TYPE_SPEC_TYPE."; 530 return {}; 531 } 532 533 last_type_idx = type_spec->id - 1; 534 types_builder = util::make_unique<TypeSpecPtrBuilder>(type_spec); 535 } break; 536 537 case RES_TABLE_TYPE_TYPE: { 538 const ResTable_type* type = child_chunk.header<ResTable_type, kResTableTypeMinSize>(); 539 if (type == nullptr) { 540 LOG(ERROR) << "Chunk RES_TABLE_TYPE_TYPE is too small."; 541 return {}; 542 } 543 544 if (type->id == 0) { 545 LOG(ERROR) << "Chunk RES_TABLE_TYPE_TYPE has invalid ID 0."; 546 return {}; 547 } 548 549 // Type chunks must be preceded by their TypeSpec chunks. 550 if (!types_builder || type->id - 1 != last_type_idx) { 551 LOG(ERROR) << "Found RES_TABLE_TYPE_TYPE chunk without " 552 "RES_TABLE_TYPE_SPEC_TYPE."; 553 return {}; 554 } 555 556 if (!VerifyType(child_chunk)) { 557 return {}; 558 } 559 560 types_builder->AddType(type); 561 } break; 562 563 case RES_TABLE_LIBRARY_TYPE: { 564 const ResTable_lib_header* lib = child_chunk.header<ResTable_lib_header>(); 565 if (lib == nullptr) { 566 LOG(ERROR) << "Chunk RES_TABLE_LIBRARY_TYPE is too small."; 567 return {}; 568 } 569 570 if (child_chunk.data_size() / sizeof(ResTable_lib_entry) < dtohl(lib->count)) { 571 LOG(ERROR) << "Chunk too small to hold entries in RES_TABLE_LIBRARY_TYPE."; 572 return {}; 573 } 574 575 loaded_package->dynamic_package_map_.reserve(dtohl(lib->count)); 576 577 const ResTable_lib_entry* const entry_begin = 578 reinterpret_cast<const ResTable_lib_entry*>(child_chunk.data_ptr()); 579 const ResTable_lib_entry* const entry_end = entry_begin + dtohl(lib->count); 580 for (auto entry_iter = entry_begin; entry_iter != entry_end; ++entry_iter) { 581 std::string package_name; 582 util::ReadUtf16StringFromDevice(entry_iter->packageName, 583 arraysize(entry_iter->packageName), &package_name); 584 585 if (dtohl(entry_iter->packageId) >= std::numeric_limits<uint8_t>::max()) { 586 LOG(ERROR) << base::StringPrintf( 587 "Package ID %02x in RES_TABLE_LIBRARY_TYPE too large for package '%s'.", 588 dtohl(entry_iter->packageId), package_name.c_str()); 589 return {}; 590 } 591 592 loaded_package->dynamic_package_map_.emplace_back(std::move(package_name), 593 dtohl(entry_iter->packageId)); 594 } 595 596 } break; 597 598 default: 599 LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type()); 600 break; 601 } 602 } 603 604 // Finish the last TypeSpec. 605 if (types_builder) { 606 TypeSpecPtr type_spec_ptr = types_builder->Build(); 607 if (type_spec_ptr == nullptr) { 608 LOG(ERROR) << "Too many type configurations, overflow detected."; 609 return {}; 610 } 611 loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr); 612 } 613 614 if (iter.HadError()) { 615 LOG(ERROR) << iter.GetLastError(); 616 return {}; 617 } 618 return loaded_package; 619} 620 621bool LoadedArsc::LoadTable(const Chunk& chunk, bool load_as_shared_library) { 622 ATRACE_CALL(); 623 const ResTable_header* header = chunk.header<ResTable_header>(); 624 if (header == nullptr) { 625 LOG(ERROR) << "Chunk RES_TABLE_TYPE is too small."; 626 return false; 627 } 628 629 const size_t package_count = dtohl(header->packageCount); 630 size_t packages_seen = 0; 631 632 packages_.reserve(package_count); 633 634 ChunkIterator iter(chunk.data_ptr(), chunk.data_size()); 635 while (iter.HasNext()) { 636 const Chunk child_chunk = iter.Next(); 637 switch (child_chunk.type()) { 638 case RES_STRING_POOL_TYPE: 639 // Only use the first string pool. Ignore others. 640 if (global_string_pool_.getError() == NO_INIT) { 641 status_t err = global_string_pool_.setTo(child_chunk.header<ResStringPool_header>(), 642 child_chunk.size()); 643 if (err != NO_ERROR) { 644 LOG(ERROR) << "Corrupt string pool."; 645 return false; 646 } 647 } else { 648 LOG(WARNING) << "Multiple string pool chunks found in resource table."; 649 } 650 break; 651 652 case RES_TABLE_PACKAGE_TYPE: { 653 if (packages_seen + 1 > package_count) { 654 LOG(ERROR) << "More package chunks were found than the " << package_count 655 << " declared in the " 656 "header."; 657 return false; 658 } 659 packages_seen++; 660 661 std::unique_ptr<LoadedPackage> loaded_package = LoadedPackage::Load(child_chunk); 662 if (!loaded_package) { 663 return false; 664 } 665 666 // Mark the package as dynamic if we are forcefully loading the Apk as a shared library. 667 if (loaded_package->package_id_ == kAppPackageId) { 668 loaded_package->dynamic_ = load_as_shared_library; 669 } 670 loaded_package->system_ = system_; 671 packages_.push_back(std::move(loaded_package)); 672 } break; 673 674 default: 675 LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type()); 676 break; 677 } 678 } 679 680 if (iter.HadError()) { 681 LOG(ERROR) << iter.GetLastError(); 682 return false; 683 } 684 return true; 685} 686 687std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const void* data, size_t len, bool system, 688 bool load_as_shared_library) { 689 ATRACE_CALL(); 690 691 // Not using make_unique because the constructor is private. 692 std::unique_ptr<LoadedArsc> loaded_arsc(new LoadedArsc()); 693 loaded_arsc->system_ = system; 694 695 ChunkIterator iter(data, len); 696 while (iter.HasNext()) { 697 const Chunk chunk = iter.Next(); 698 switch (chunk.type()) { 699 case RES_TABLE_TYPE: 700 if (!loaded_arsc->LoadTable(chunk, load_as_shared_library)) { 701 return {}; 702 } 703 break; 704 705 default: 706 LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type()); 707 break; 708 } 709 } 710 711 if (iter.HadError()) { 712 LOG(ERROR) << iter.GetLastError(); 713 return {}; 714 } 715 716 // Need to force a move for mingw32. 717 return std::move(loaded_arsc); 718} 719 720} // namespace android 721