Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8a0f0ed4 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes Ia6c335db,Id8079104

* changes:
  AssetManager2: Provide a method for iterating over packages
  AssetManager2: Implement IDMAP support
parents a7963492 d480f7ba
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ cc_library {
        "AssetManager2.cpp",
        "AttributeResolution.cpp",
        "ChunkIterator.cpp",
        "Idmap.cpp",
        "LoadedArsc.cpp",
        "LocaleData.cpp",
        "misc.cpp",
+79 −18
Original line number Diff line number Diff line
@@ -20,64 +20,126 @@

#include <algorithm>

#include "android-base/errors.h"
#include "android-base/file.h"
#include "android-base/logging.h"
#include "android-base/unique_fd.h"
#include "android-base/utf8.h"
#include "utils/Compat.h"
#include "utils/FileMap.h"
#include "utils/Trace.h"
#include "ziparchive/zip_archive.h"

#include "androidfw/Asset.h"
#include "androidfw/Idmap.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/Util.h"

namespace android {

ApkAssets::ApkAssets() : zip_handle_(nullptr, ::CloseArchive) {}
using base::SystemErrorCodeToString;
using base::unique_fd;

static const std::string kResourcesArsc("resources.arsc");

ApkAssets::ApkAssets(void* unmanaged_handle, const std::string& path)
    : zip_handle_(unmanaged_handle, ::CloseArchive), path_(path) {
}

std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system) {
  return ApkAssets::LoadImpl(path, system, false /*load_as_shared_library*/);
  return ApkAssets::LoadImpl(path, nullptr, nullptr, system, false /*load_as_shared_library*/);
}

std::unique_ptr<const ApkAssets> ApkAssets::LoadAsSharedLibrary(const std::string& path,
                                                                bool system) {
  return ApkAssets::LoadImpl(path, system, true /*load_as_shared_library*/);
  return ApkAssets::LoadImpl(path, nullptr, nullptr, system, true /*load_as_shared_library*/);
}

std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
                                                        bool system) {
  std::unique_ptr<Asset> idmap_asset = CreateAssetFromFile(idmap_path);
  if (idmap_asset == nullptr) {
    return {};
  }

  const StringPiece idmap_data(
      reinterpret_cast<const char*>(idmap_asset->getBuffer(true /*wordAligned*/)),
      static_cast<size_t>(idmap_asset->getLength()));
  std::unique_ptr<const LoadedIdmap> loaded_idmap = LoadedIdmap::Load(idmap_data);
  if (loaded_idmap == nullptr) {
    LOG(ERROR) << "failed to load IDMAP " << idmap_path;
    return {};
  }
  return LoadImpl(loaded_idmap->OverlayApkPath(), std::move(idmap_asset), std::move(loaded_idmap),
                  system, false /*load_as_shared_library*/);
}

std::unique_ptr<Asset> ApkAssets::CreateAssetFromFile(const std::string& path) {
  unique_fd fd(base::utf8::open(path.c_str(), O_RDONLY | O_BINARY | O_CLOEXEC));
  if (fd == -1) {
    LOG(ERROR) << "Failed to open file '" << path << "': " << SystemErrorCodeToString(errno);
    return {};
  }

  const off64_t file_len = lseek64(fd, 0, SEEK_END);
  if (file_len < 0) {
    LOG(ERROR) << "Failed to get size of file '" << path << "': " << SystemErrorCodeToString(errno);
    return {};
  }

  std::unique_ptr<FileMap> file_map = util::make_unique<FileMap>();
  if (!file_map->create(path.c_str(), fd, 0, static_cast<size_t>(file_len), true /*readOnly*/)) {
    LOG(ERROR) << "Failed to mmap file '" << path << "': " << SystemErrorCodeToString(errno);
    return {};
  }
  return Asset::createFromUncompressedMap(std::move(file_map), Asset::AccessMode::ACCESS_RANDOM);
}

std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(const std::string& path, bool system,
                                                     bool load_as_shared_library) {
std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
    const std::string& path, std::unique_ptr<Asset> idmap_asset,
    std::unique_ptr<const LoadedIdmap> loaded_idmap, bool system, bool load_as_shared_library) {
  ATRACE_CALL();
  ::ZipArchiveHandle unmanaged_handle;
  int32_t result = ::OpenArchive(path.c_str(), &unmanaged_handle);
  if (result != 0) {
    LOG(ERROR) << ::ErrorCodeString(result);
    LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result);
    return {};
  }

  // Wrap the handle in a unique_ptr so it gets automatically closed.
  std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets());
  loaded_apk->zip_handle_.reset(unmanaged_handle);
  std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(unmanaged_handle, path));

  ::ZipString entry_name("resources.arsc");
  // Find the resource table.
  ::ZipString entry_name(kResourcesArsc.c_str());
  ::ZipEntry entry;
  result = ::FindEntry(loaded_apk->zip_handle_.get(), entry_name, &entry);
  if (result != 0) {
    LOG(ERROR) << ::ErrorCodeString(result);
    return {};
    // There is no resources.arsc, so create an empty LoadedArsc and return.
    loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty();
    return std::move(loaded_apk);
  }

  if (entry.method == kCompressDeflated) {
    LOG(WARNING) << "resources.arsc is compressed.";
    LOG(WARNING) << kResourcesArsc << " in APK '" << path << "' is compressed.";
  }

  loaded_apk->path_ = path;
  loaded_apk->resources_asset_ =
      loaded_apk->Open("resources.arsc", Asset::AccessMode::ACCESS_BUFFER);
  // Open the resource table via mmap unless it is compressed. This logic is taken care of by Open.
  loaded_apk->resources_asset_ = loaded_apk->Open(kResourcesArsc, Asset::AccessMode::ACCESS_BUFFER);
  if (loaded_apk->resources_asset_ == nullptr) {
    LOG(ERROR) << "Failed to open '" << kResourcesArsc << "' in APK '" << path << "'.";
    return {};
  }

  // Must retain ownership of the IDMAP Asset so that all pointers to its mmapped data remain valid.
  loaded_apk->idmap_asset_ = std::move(idmap_asset);

  const StringPiece data(
      reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)),
      loaded_apk->resources_asset_->getLength());
  loaded_apk->loaded_arsc_ =
      LoadedArsc::Load(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/),
                       loaded_apk->resources_asset_->getLength(), system, load_as_shared_library);
      LoadedArsc::Load(data, loaded_idmap.get(), system, load_as_shared_library);
  if (loaded_apk->loaded_arsc_ == nullptr) {
    LOG(ERROR) << "Failed to load '" << kResourcesArsc << "' in APK '" << path << "'.";
    return {};
  }

@@ -93,7 +155,6 @@ std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMod
  ::ZipEntry entry;
  int32_t result = ::FindEntry(zip_handle_.get(), name, &entry);
  if (result != 0) {
    LOG(ERROR) << "No entry '" << path << "' found in APK '" << path_ << "'";
    return {};
  }

+8 −5
Original line number Diff line number Diff line
@@ -35,7 +35,9 @@

namespace android {

AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); }
AssetManager2::AssetManager2() {
  memset(&configuration_, 0, sizeof(configuration_));
}

bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
                                 bool invalidate_caches) {
@@ -55,9 +57,9 @@ void AssetManager2::BuildDynamicRefTable() {
  int next_package_id = 0x02;
  const size_t apk_assets_count = apk_assets_.size();
  for (size_t i = 0; i < apk_assets_count; i++) {
    const ApkAssets* apk_asset = apk_assets_[i];
    for (const std::unique_ptr<const LoadedPackage>& package :
         apk_asset->GetLoadedArsc()->GetPackages()) {
    const LoadedArsc* loaded_arsc = apk_assets_[i]->GetLoadedArsc();

    for (const std::unique_ptr<const LoadedPackage>& package : loaded_arsc->GetPackages()) {
      // Get the package ID or assign one if a shared library.
      int package_id;
      if (package->IsDynamic()) {
@@ -312,7 +314,8 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri

    cumulated_flags |= current_flags;

    if (best_cookie == kInvalidCookie || current_config.isBetterThan(best_config, desired_config)) {
    if (best_cookie == kInvalidCookie || current_config.isBetterThan(best_config, desired_config) ||
        (loaded_package->IsOverlay() && current_config.compare(best_config) == 0)) {
      best_entry = current_entry;
      best_config = current_config;
      best_cookie = package_group.cookies_[i];
+190 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define ATRACE_TAG ATRACE_TAG_RESOURCES

#include "androidfw/Idmap.h"

#include "android-base/logging.h"
#include "android-base/stringprintf.h"
#include "utils/ByteOrder.h"
#include "utils/Trace.h"

#ifdef _WIN32
#ifdef ERROR
#undef ERROR
#endif
#endif

#include "androidfw/ResourceTypes.h"

using ::android::base::StringPrintf;

namespace android {

constexpr static inline bool is_valid_package_id(uint16_t id) {
  return id != 0 && id <= 255;
}

constexpr static inline bool is_valid_type_id(uint16_t id) {
  // Type IDs and package IDs have the same constraints in the IDMAP.
  return is_valid_package_id(id);
}

bool LoadedIdmap::Lookup(const IdmapEntry_header* header, uint16_t input_entry_id,
                         uint16_t* output_entry_id) {
  if (input_entry_id < dtohs(header->entry_id_offset)) {
    // After applying the offset, the entry is not present.
    return false;
  }

  input_entry_id -= dtohs(header->entry_id_offset);
  if (input_entry_id >= dtohs(header->entry_count)) {
    // The entry is not present.
    return false;
  }

  uint32_t result = dtohl(header->entries[input_entry_id]);
  if (result == 0xffffffffu) {
    return false;
  }
  *output_entry_id = static_cast<uint16_t>(result);
  return true;
}

static bool is_word_aligned(const void* data) {
  return (reinterpret_cast<uintptr_t>(data) & 0x03) == 0;
}

static bool IsValidIdmapHeader(const StringPiece& data) {
  if (!is_word_aligned(data.data())) {
    LOG(ERROR) << "Idmap header is not word aligned.";
    return false;
  }

  if (data.size() < sizeof(Idmap_header)) {
    LOG(ERROR) << "Idmap header is too small.";
    return false;
  }

  const Idmap_header* 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;
  }

  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;
  }

  if (!is_valid_package_id(dtohs(header->target_package_id))) {
    LOG(ERROR) << StringPrintf("Target package ID in Idmap is invalid: 0x%02x",
                               dtohs(header->target_package_id));
    return false;
  }

  if (dtohs(header->type_count) > 255) {
    LOG(ERROR) << StringPrintf("Idmap has too many type mappings (was %d, max 255)",
                               (int)dtohs(header->type_count));
    return false;
  }
  return true;
}

LoadedIdmap::LoadedIdmap(const Idmap_header* header) : header_(header) {
  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);
}

std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_data) {
  ATRACE_CALL();
  if (!IsValidIdmapHeader(idmap_data)) {
    return {};
  }

  const Idmap_header* header = reinterpret_cast<const Idmap_header*>(idmap_data.data());

  // Can't use make_unique because LoadedImpl constructor is private.
  std::unique_ptr<LoadedIdmap> loaded_idmap = std::unique_ptr<LoadedIdmap>(new LoadedIdmap(header));

  const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(idmap_data.data()) + sizeof(*header);
  size_t data_size = idmap_data.size() - sizeof(*header);

  size_t type_maps_encountered = 0u;
  while (data_size >= sizeof(IdmapEntry_header)) {
    if (!is_word_aligned(data_ptr)) {
      LOG(ERROR) << "Type mapping in Idmap is not word aligned";
      return {};
    }

    // Validate the type IDs.
    const IdmapEntry_header* entry_header = reinterpret_cast<const IdmapEntry_header*>(data_ptr);
    if (!is_valid_type_id(dtohs(entry_header->target_type_id)) || !is_valid_type_id(dtohs(entry_header->overlay_type_id))) {
      LOG(ERROR) << StringPrintf("Invalid type map (0x%02x -> 0x%02x)",
                                 dtohs(entry_header->target_type_id),
                                 dtohs(entry_header->overlay_type_id));
      return {};
    }

    // Make sure there is enough space for the entries declared in the header.
    if ((data_size - sizeof(*entry_header)) / sizeof(uint32_t) <
        static_cast<size_t>(dtohs(entry_header->entry_count))) {
      LOG(ERROR) << StringPrintf("Idmap too small for the number of entries (%d)",
                                 (int)dtohs(entry_header->entry_count));
      return {};
    }

    // Only add a non-empty overlay.
    if (dtohs(entry_header->entry_count != 0)) {
      loaded_idmap->type_map_[static_cast<uint8_t>(dtohs(entry_header->overlay_type_id))] =
          entry_header;
    }

    const size_t entry_size_bytes =
        sizeof(*entry_header) + (dtohs(entry_header->entry_count) * sizeof(uint32_t));
    data_ptr += entry_size_bytes;
    data_size -= entry_size_bytes;
    type_maps_encountered++;
  }

  // Verify that we parsed all the type maps.
  if (type_maps_encountered != static_cast<size_t>(dtohs(header->type_count))) {
    LOG(ERROR) << "Parsed " << type_maps_encountered << " type maps but expected "
               << (int)dtohs(header->type_count);
    return {};
  }
  return std::move(loaded_idmap);
}

uint8_t LoadedIdmap::TargetPackageId() const {
  return static_cast<uint8_t>(dtohs(header_->target_package_id));
}

const IdmapEntry_header* LoadedIdmap::GetEntryMapForType(uint8_t type_id) const {
  auto iter = type_map_.find(type_id);
  if (iter != type_map_.end()) {
    return iter->second;
  }
  return nullptr;
}

}  // namespace android
+81 −21
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@
#include "androidfw/ResourceUtils.h"
#include "androidfw/Util.h"

using android::base::StringPrintf;
using ::android::base::StringPrintf;

namespace android {

@@ -61,6 +61,10 @@ struct TypeSpec {
  // and under which configurations it varies.
  const ResTable_typeSpec* type_spec;

  // Pointer to the mmapped data where the IDMAP mappings for this type
  // exist. May be nullptr if no IDMAP exists.
  const IdmapEntry_header* idmap_entries;

  // The number of types that follow this struct.
  // There is a type for each configuration
  // that entries are defined for.
@@ -84,7 +88,10 @@ namespace {
// the Type structs.
class TypeSpecPtrBuilder {
 public:
  TypeSpecPtrBuilder(const ResTable_typeSpec* header) : header_(header) {}
  explicit TypeSpecPtrBuilder(const ResTable_typeSpec* header,
                              const IdmapEntry_header* idmap_header)
      : header_(header), idmap_header_(idmap_header) {
  }

  void AddType(const ResTable_type* type) {
    ResTable_config config;
@@ -99,6 +106,7 @@ class TypeSpecPtrBuilder {
    }
    TypeSpec* type_spec = (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(Type)));
    type_spec->type_spec = header_;
    type_spec->idmap_entries = idmap_header_;
    type_spec->type_count = types_.size();
    memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(Type));
    return TypeSpecPtr(type_spec);
@@ -108,6 +116,7 @@ class TypeSpecPtrBuilder {
  DISALLOW_COPY_AND_ASSIGN(TypeSpecPtrBuilder);

  const ResTable_typeSpec* header_;
  const IdmapEntry_header* idmap_header_;
  std::vector<Type> types_;
};

@@ -125,6 +134,14 @@ bool LoadedPackage::FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTab
    return false;
  }

  // If there is an IDMAP supplied with this package, translate the entry ID.
  if (ptr->idmap_entries != nullptr) {
    if (!LoadedIdmap::Lookup(ptr->idmap_entries, entry_idx, &entry_idx)) {
      // There is no mapping, so the resource is not meant to be in this overlay package.
      return false;
    }
  }

  // Don't bother checking if the entry ID is larger than
  // the number of entries.
  if (entry_idx >= dtohl(ptr->type_spec->entryCount)) {
@@ -225,7 +242,7 @@ static bool VerifyType(const Chunk& chunk) {
  const size_t entries_offset = dtohl(header->entriesStart);
  const size_t offsets_length = sizeof(uint32_t) * entry_count;

  if (offsets_offset + offsets_length > entries_offset) {
  if (offsets_offset > entries_offset || entries_offset - offsets_offset < offsets_length) {
    LOG(ERROR) << "Entry offsets overlap actual entry data.";
    return false;
  }
@@ -269,13 +286,13 @@ static bool VerifyType(const Chunk& chunk) {
          reinterpret_cast<const uint8_t*>(header) + offset);
      const size_t entry_size = dtohs(entry->size);
      if (entry_size < sizeof(*entry)) {
        LOG(ERROR) << "ResTable_entry size " << entry_size << " is too small.";
        LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << i << " is too small.";
        return false;
      }

      // Check the declared entrySize.
      if (entry_size > chunk.size() || offset > chunk.size() - entry_size) {
        LOG(ERROR) << "ResTable_entry size " << entry_size << " is too large.";
        LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << i << " is too large.";
        return false;
      }

@@ -286,13 +303,13 @@ static bool VerifyType(const Chunk& chunk) {

        size_t map_entries_start = offset + entry_size;
        if (map_entries_start & 0x03) {
          LOG(ERROR) << "Map entries start at unaligned offset.";
          LOG(ERROR) << "Map entries at index " << i << " start at unaligned offset.";
          return false;
        }

        // Each entry is sizeof(ResTable_map) big.
        if (map_entry_count > ((chunk.size() - map_entries_start) / sizeof(ResTable_map))) {
          LOG(ERROR) << "Too many map entries in ResTable_map_entry.";
          LOG(ERROR) << "Too many map entries in ResTable_map_entry at index " << i << ".";
          return false;
        }

@@ -300,7 +317,9 @@ static bool VerifyType(const Chunk& chunk) {
      } else {
        // There needs to be room for one Res_value struct.
        if (offset + entry_size > chunk.size() - sizeof(Res_value)) {
          LOG(ERROR) << "No room for Res_value after ResTable_entry.";
          LOG(ERROR) << "No room for Res_value after ResTable_entry at index " << i << " for type "
                     << (int)header->id << " with config " << header->config.toString().string()
                     << ".";
          return false;
        }

@@ -308,12 +327,12 @@ static bool VerifyType(const Chunk& chunk) {
            reinterpret_cast<const uint8_t*>(entry) + entry_size);
        const size_t value_size = dtohs(value->size);
        if (value_size < sizeof(Res_value)) {
          LOG(ERROR) << "Res_value is too small.";
          LOG(ERROR) << "Res_value at index " << i << " is too small.";
          return false;
        }

        if (value_size > chunk.size() || offset + entry_size > chunk.size() - value_size) {
          LOG(ERROR) << "Res_value size is too large.";
          LOG(ERROR) << "Res_value size " << value_size << " at index " << i << " is too large.";
          return false;
        }
      }
@@ -412,10 +431,13 @@ uint32_t LoadedPackage::FindEntryByName(const std::u16string& type_name,
  return 0u;
}

std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) {
std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
                                                   const LoadedIdmap* loaded_idmap) {
  ATRACE_CALL();
  std::unique_ptr<LoadedPackage> loaded_package{new LoadedPackage()};

  // typeIdOffset was added at some point, but we still must recognize apps built before this
  // was added.
  constexpr size_t kMinPackageSize =
      sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset);
  const ResTable_package* header = chunk.header<ResTable_package, kMinPackageSize>();
@@ -430,6 +452,12 @@ std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) {
    loaded_package->dynamic_ = true;
  }

  if (loaded_idmap != nullptr) {
    // This is an overlay and so it needs to pretend to be the target package.
    loaded_package->package_id_ = loaded_idmap->TargetPackageId();
    loaded_package->overlay_ = true;
  }

  if (header->header.headerSize >= sizeof(ResTable_package)) {
    uint32_t type_id_offset = dtohl(header->typeIdOffset);
    if (type_id_offset > std::numeric_limits<uint8_t>::max()) {
@@ -490,7 +518,16 @@ std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) {
            LOG(ERROR) << "Too many type configurations, overflow detected.";
            return {};
          }

          // We only add the type to the package if there is no IDMAP, or if the type is
          // overlaying something.
          if (loaded_idmap == nullptr || type_spec_ptr->idmap_entries != nullptr) {
            // If this is an overlay, insert it at the target type ID.
            if (type_spec_ptr->idmap_entries != nullptr) {
              last_type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1;
            }
            loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
          }

          types_builder = {};
          last_type_idx = 0;
@@ -531,7 +568,15 @@ std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) {
        }

        last_type_idx = type_spec->id - 1;
        types_builder = util::make_unique<TypeSpecPtrBuilder>(type_spec);

        // If this is an overlay, associate the mapping of this type to the target type
        // from the IDMAP.
        const IdmapEntry_header* idmap_entry_header = nullptr;
        if (loaded_idmap != nullptr) {
          idmap_entry_header = loaded_idmap->GetEntryMapForType(type_spec->id);
        }

        types_builder = util::make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
      } break;

      case RES_TABLE_TYPE_TYPE: {
@@ -608,8 +653,17 @@ std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) {
      LOG(ERROR) << "Too many type configurations, overflow detected.";
      return {};
    }

    // We only add the type to the package if there is no IDMAP, or if the type is
    // overlaying something.
    if (loaded_idmap == nullptr || type_spec_ptr->idmap_entries != nullptr) {
      // If this is an overlay, insert it at the target type ID.
      if (type_spec_ptr->idmap_entries != nullptr) {
        last_type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1;
      }
      loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
    }
  }

  if (iter.HadError()) {
    LOG(ERROR) << iter.GetLastError();
@@ -618,7 +672,8 @@ std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) {
  return loaded_package;
}

bool LoadedArsc::LoadTable(const Chunk& chunk, bool load_as_shared_library) {
bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
                           bool load_as_shared_library) {
  ATRACE_CALL();
  const ResTable_header* header = chunk.header<ResTable_header>();
  if (header == nullptr) {
@@ -652,13 +707,13 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, bool load_as_shared_library) {
      case RES_TABLE_PACKAGE_TYPE: {
        if (packages_seen + 1 > package_count) {
          LOG(ERROR) << "More package chunks were found than the " << package_count
                     << " declared in the "
                        "header.";
                     << " declared in the header.";
          return false;
        }
        packages_seen++;

        std::unique_ptr<LoadedPackage> loaded_package = LoadedPackage::Load(child_chunk);
        std::unique_ptr<LoadedPackage> loaded_package =
            LoadedPackage::Load(child_chunk, loaded_idmap);
        if (!loaded_package) {
          return false;
        }
@@ -684,7 +739,8 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, bool load_as_shared_library) {
  return true;
}

std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const void* data, size_t len, bool system,
std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const StringPiece& data,
                                                   const LoadedIdmap* loaded_idmap, bool system,
                                                   bool load_as_shared_library) {
  ATRACE_CALL();

@@ -692,12 +748,12 @@ std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const void* data, size_t len,
  std::unique_ptr<LoadedArsc> loaded_arsc(new LoadedArsc());
  loaded_arsc->system_ = system;

  ChunkIterator iter(data, len);
  ChunkIterator iter(data.data(), data.size());
  while (iter.HasNext()) {
    const Chunk chunk = iter.Next();
    switch (chunk.type()) {
      case RES_TABLE_TYPE:
        if (!loaded_arsc->LoadTable(chunk, load_as_shared_library)) {
        if (!loaded_arsc->LoadTable(chunk, loaded_idmap, load_as_shared_library)) {
          return {};
        }
        break;
@@ -717,4 +773,8 @@ std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const void* data, size_t len,
  return std::move(loaded_arsc);
}

std::unique_ptr<const LoadedArsc> LoadedArsc::CreateEmpty() {
  return std::unique_ptr<LoadedArsc>(new LoadedArsc());
}

}  // namespace android
Loading