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

Commit da431a22 authored by Adam Lesinski's avatar Adam Lesinski
Browse files

libandroidfw: Add new support for shared libraries

This adds support for shared resource libraries in the new
ResTable/AssetManager implementation.

The dynamic package map encoded in resources.arsc is parsed
and stored with LoadedArsc, and combined to form a resolved table
in AssetManager2.

Benchmarks show that this implementation is an order of magnitude
faster on angler-userdebug (make libandroidfw_benchmarks).

Test: libandroidfw_tests
Change-Id: I57c80248728b63b162bf8269ac9495b53c3e7fa0
parent 7ad1110e
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -38,6 +38,7 @@ cc_library {
        "ResourceTypes.cpp",
        "ResourceTypes.cpp",
        "StreamingZipInflater.cpp",
        "StreamingZipInflater.cpp",
        "TypeWrappers.cpp",
        "TypeWrappers.cpp",
        "Util.cpp",
        "ZipFileRO.cpp",
        "ZipFileRO.cpp",
        "ZipUtils.cpp",
        "ZipUtils.cpp",
    ],
    ],
@@ -82,6 +83,9 @@ cc_library {
        },
        },
        windows: {
        windows: {
            enabled: true,
            enabled: true,
            cppflags: ["-Wno-missing-field-initializers"],  // The Windows compiler warns
                                                            // incorrectly for value
                                                            // initialization with {}.
        },
        },
    },
    },
}
}
+11 −2
Original line number Original line Diff line number Diff line
@@ -28,7 +28,16 @@
namespace android {
namespace android {


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

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

std::unique_ptr<ApkAssets> ApkAssets::LoadImpl(const std::string& path,
                                               bool load_as_shared_library) {
  ATRACE_CALL();
  ::ZipArchiveHandle unmanaged_handle;
  ::ZipArchiveHandle unmanaged_handle;
  int32_t result = ::OpenArchive(path.c_str(), &unmanaged_handle);
  int32_t result = ::OpenArchive(path.c_str(), &unmanaged_handle);
  if (result != 0) {
  if (result != 0) {
@@ -61,7 +70,7 @@ std::unique_ptr<ApkAssets> ApkAssets::Load(const std::string& path) {
  loaded_apk->path_ = path;
  loaded_apk->path_ = path;
  loaded_apk->loaded_arsc_ =
  loaded_apk->loaded_arsc_ =
      LoadedArsc::Load(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/),
      LoadedArsc::Load(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/),
                       loaded_apk->resources_asset_->getLength());
                       loaded_apk->resources_asset_->getLength(), load_as_shared_library);
  if (loaded_apk->loaded_arsc_ == nullptr) {
  if (loaded_apk->loaded_arsc_ == nullptr) {
    return {};
    return {};
  }
  }
+198 −38
Original line number Original line Diff line number Diff line
@@ -36,13 +36,84 @@ AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration
bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
                                 bool invalidate_caches) {
                                 bool invalidate_caches) {
  apk_assets_ = apk_assets;
  apk_assets_ = apk_assets;
  BuildDynamicRefTable();
  if (invalidate_caches) {
  if (invalidate_caches) {
    InvalidateCaches(static_cast<uint32_t>(-1));
    InvalidateCaches(static_cast<uint32_t>(-1));
  }
  }
  return true;
  return true;
}
}


const std::vector<const ApkAssets*> AssetManager2::GetApkAssets() const { return apk_assets_; }
void AssetManager2::BuildDynamicRefTable() {
  package_groups_.clear();
  package_ids_.fill(0xff);

  // 0x01 is reserved for the android package.
  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()) {
      // Get the package ID or assign one if a shared library.
      int package_id;
      if (package->IsDynamic()) {
        package_id = next_package_id++;
      } else {
        package_id = package->GetPackageId();
      }

      // Add the mapping for package ID to index if not present.
      uint8_t idx = package_ids_[package_id];
      if (idx == 0xff) {
        package_ids_[package_id] = idx = static_cast<uint8_t>(package_groups_.size());
        package_groups_.push_back({});
        package_groups_.back().dynamic_ref_table.mAssignedPackageId = package_id;
      }
      PackageGroup* package_group = &package_groups_[idx];

      // Add the package and to the set of packages with the same ID.
      package_group->packages_.push_back(package.get());
      package_group->cookies_.push_back(static_cast<ApkAssetsCookie>(i));

      // Add the package name -> build time ID mappings.
      for (const DynamicPackageEntry& entry : package->GetDynamicPackageMap()) {
        String16 package_name(entry.package_name.c_str(), entry.package_name.size());
        package_group->dynamic_ref_table.mEntries.replaceValueFor(
            package_name, static_cast<uint8_t>(entry.package_id));
      }
    }
  }

  // Now assign the runtime IDs so that we have a build-time to runtime ID map.
  const auto package_groups_end = package_groups_.end();
  for (auto iter = package_groups_.begin(); iter != package_groups_end; ++iter) {
    const std::string& package_name = iter->packages_[0]->GetPackageName();
    for (auto iter2 = package_groups_.begin(); iter2 != package_groups_end; ++iter2) {
      iter2->dynamic_ref_table.addMapping(String16(package_name.c_str(), package_name.size()),
                                          iter->dynamic_ref_table.mAssignedPackageId);
    }
  }
}

void AssetManager2::DumpToLog() const {
  base::ScopedLogSeverity _log(base::INFO);

  std::string list;
  for (size_t i = 0; i < package_ids_.size(); i++) {
    if (package_ids_[i] != 0xff) {
      base::StringAppendF(&list, "%02x -> %d, ", (int) i, package_ids_[i]);
    }
  }
  LOG(INFO) << "Package ID map: " << list;

  for (const auto& package_group: package_groups_) {
      list = "";
      for (const auto& package : package_group.packages_) {
        base::StringAppendF(&list, "%s(%02x), ", package->GetPackageName().c_str(), package->GetPackageId());
      }
      LOG(INFO) << base::StringPrintf("PG (%02x): ", package_group.dynamic_ref_table.mAssignedPackageId) << list;
  }
}


const ResStringPool* AssetManager2::GetStringPoolForCookie(ApkAssetsCookie cookie) const {
const ResStringPool* AssetManager2::GetStringPoolForCookie(ApkAssetsCookie cookie) const {
  if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
  if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
@@ -51,6 +122,18 @@ const ResStringPool* AssetManager2::GetStringPoolForCookie(ApkAssetsCookie cooki
  return apk_assets_[cookie]->GetLoadedArsc()->GetStringPool();
  return apk_assets_[cookie]->GetLoadedArsc()->GetStringPool();
}
}


const DynamicRefTable* AssetManager2::GetDynamicRefTableForPackage(uint32_t package_id) const {
  if (package_id >= package_ids_.size()) {
    return nullptr;
  }

  const size_t idx = package_ids_[package_id];
  if (idx == 0xff) {
    return nullptr;
  }
  return &package_groups_[idx].dynamic_ref_table;
}

void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
  const int diff = configuration_.diff(configuration);
  const int diff = configuration_.diff(configuration);
  configuration_ = configuration;
  configuration_ = configuration;
@@ -60,8 +143,6 @@ void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
  }
  }
}
}


const ResTable_config& AssetManager2::GetConfiguration() const { return configuration_; }

std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, Asset::AccessMode mode) {
std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, Asset::AccessMode mode) {
  const std::string new_path = "assets/" + filename;
  const std::string new_path = "assets/" + filename;
  return OpenNonAsset(new_path, mode);
  return OpenNonAsset(new_path, mode);
@@ -106,7 +187,7 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
}
}


ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
                                         bool stop_at_first_match, LoadedArsc::Entry* out_entry,
                                         bool stop_at_first_match, LoadedArscEntry* out_entry,
                                         ResTable_config* out_selected_config,
                                         ResTable_config* out_selected_config,
                                         uint32_t* out_flags) {
                                         uint32_t* out_flags) {
  ATRACE_CALL();
  ATRACE_CALL();
@@ -122,48 +203,66 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
    desired_config = &density_override_config;
    desired_config = &density_override_config;
  }
  }


  LoadedArsc::Entry best_entry;
  const uint32_t package_id = util::get_package_id(resid);
  ResTable_config best_config;
  const uint8_t type_id = util::get_type_id(resid);
  int32_t best_index = -1;
  const uint16_t entry_id = util::get_entry_id(resid);
  uint32_t cumulated_flags = 0;

  if (type_id == 0) {
    LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
    return kInvalidCookie;
  }


  const size_t apk_asset_count = apk_assets_.size();
  const uint8_t idx = package_ids_[package_id];
  for (size_t i = 0; i < apk_asset_count; i++) {
  if (idx == 0xff) {
    const LoadedArsc* loaded_arsc = apk_assets_[i]->GetLoadedArsc();
    LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.", package_id, resid);
    return kInvalidCookie;
  }


    LoadedArsc::Entry current_entry;
  LoadedArscEntry best_entry;
  ResTable_config best_config;
  ApkAssetsCookie best_cookie = kInvalidCookie;
  uint32_t cumulated_flags = 0u;

  const PackageGroup& package_group = package_groups_[idx];
  const size_t package_count = package_group.packages_.size();
  for (size_t i = 0; i < package_count; i++) {
    LoadedArscEntry current_entry;
    ResTable_config current_config;
    ResTable_config current_config;
    uint32_t flags = 0;
    uint32_t current_flags = 0;
    if (!loaded_arsc->FindEntry(resid, *desired_config, &current_entry, &current_config, &flags)) {

    const LoadedPackage* loaded_package = package_group.packages_[i];
    if (!loaded_package->FindEntry(type_id - 1, entry_id, *desired_config, &current_entry,
                                   &current_config, &current_flags)) {
      continue;
      continue;
    }
    }


    cumulated_flags |= flags;
    cumulated_flags |= current_flags;


    if (best_index == -1 || current_config.isBetterThan(best_config, desired_config)) {
    if (best_cookie == kInvalidCookie || current_config.isBetterThan(best_config, desired_config)) {
      best_entry = current_entry;
      best_entry = current_entry;
      best_config = current_config;
      best_config = current_config;
      best_index = static_cast<int32_t>(i);
      best_cookie = package_group.cookies_[i];
      if (stop_at_first_match) {
      if (stop_at_first_match) {
        break;
        break;
      }
      }
    }
    }
  }
  }


  if (best_index == -1) {
  if (best_cookie == kInvalidCookie) {
    return kInvalidCookie;
    return kInvalidCookie;
  }
  }


  *out_entry = best_entry;
  *out_entry = best_entry;
  out_entry->dynamic_ref_table = &package_group.dynamic_ref_table;
  *out_selected_config = best_config;
  *out_selected_config = best_config;
  *out_flags = cumulated_flags;
  *out_flags = cumulated_flags;
  return best_index;
  return best_cookie;
}
}


bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
  ATRACE_CALL();
  ATRACE_CALL();


  LoadedArsc::Entry entry;
  LoadedArscEntry entry;
  ResTable_config config;
  ResTable_config config;
  uint32_t flags = 0u;
  uint32_t flags = 0u;
  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
@@ -172,14 +271,13 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
    return false;
    return false;
  }
  }


  const std::string* package_name =
  const LoadedPackage* package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageForId(resid);
      apk_assets_[cookie]->GetLoadedArsc()->GetPackageNameForId(resid);
  if (package == nullptr) {
  if (package_name == nullptr) {
    return false;
    return false;
  }
  }


  out_name->package = package_name->data();
  out_name->package = package->GetPackageName().data();
  out_name->package_len = package_name->size();
  out_name->package_len = package->GetPackageName().size();


  out_name->type = entry.type_string_ref.string8(&out_name->type_len);
  out_name->type = entry.type_string_ref.string8(&out_name->type_len);
  out_name->type16 = nullptr;
  out_name->type16 = nullptr;
@@ -202,7 +300,7 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
}
}


bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) {
bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) {
  LoadedArsc::Entry entry;
  LoadedArscEntry entry;
  ResTable_config config;
  ResTable_config config;
  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
                                     false /* stop_at_first_match */, &entry, &config, out_flags);
                                     false /* stop_at_first_match */, &entry, &config, out_flags);
@@ -215,7 +313,7 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
                                           uint32_t* out_flags) {
                                           uint32_t* out_flags) {
  ATRACE_CALL();
  ATRACE_CALL();


  LoadedArsc::Entry entry;
  LoadedArscEntry entry;
  ResTable_config config;
  ResTable_config config;
  uint32_t flags = 0u;
  uint32_t flags = 0u;
  ApkAssetsCookie cookie =
  ApkAssetsCookie cookie =
@@ -234,6 +332,10 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
  const Res_value* device_value = reinterpret_cast<const Res_value*>(
  const Res_value* device_value = reinterpret_cast<const Res_value*>(
      reinterpret_cast<const uint8_t*>(entry.entry) + dtohs(entry.entry->size));
      reinterpret_cast<const uint8_t*>(entry.entry) + dtohs(entry.entry->size));
  out_value->copyFrom_dtoh(*device_value);
  out_value->copyFrom_dtoh(*device_value);

  // Convert the package ID to the runtime assigned package ID.
  entry.dynamic_ref_table->lookupResourceValue(out_value);

  *out_selected_config = config;
  *out_selected_config = config;
  *out_flags = flags;
  *out_flags = flags;
  return cookie;
  return cookie;
@@ -247,7 +349,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
    return cached_iter->second.get();
    return cached_iter->second.get();
  }
  }


  LoadedArsc::Entry entry;
  LoadedArscEntry entry;
  ResTable_config config;
  ResTable_config config;
  uint32_t flags = 0u;
  uint32_t flags = 0u;
  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
@@ -270,8 +372,8 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
      reinterpret_cast<const ResTable_map*>(reinterpret_cast<const uint8_t*>(map) + map->size);
      reinterpret_cast<const ResTable_map*>(reinterpret_cast<const uint8_t*>(map) + map->size);
  const ResTable_map* const map_entry_end = map_entry + dtohl(map->count);
  const ResTable_map* const map_entry_end = map_entry + dtohl(map->count);


  const uint32_t parent = dtohl(map->parent.ident);
  uint32_t parent_resid = dtohl(map->parent.ident);
  if (parent == 0) {
  if (parent_resid == 0) {
    // There is no parent, meaning there is nothing to inherit and we can do a simple
    // There is no parent, meaning there is nothing to inherit and we can do a simple
    // copy of the entries in the map.
    // copy of the entries in the map.
    const size_t entry_count = map_entry_end - map_entry;
    const size_t entry_count = map_entry_end - map_entry;
@@ -279,9 +381,18 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
        malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag::Entry))))};
        malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag::Entry))))};
    ResolvedBag::Entry* new_entry = new_bag->entries;
    ResolvedBag::Entry* new_entry = new_bag->entries;
    for (; map_entry != map_entry_end; ++map_entry) {
    for (; map_entry != map_entry_end; ++map_entry) {
      uint32_t new_key = dtohl(map_entry->name.ident);
      if (!util::is_internal_resid(new_key)) {
        // Attributes, arrays, etc don't have a resource id as the name. They specify
        // other data, which would be wrong to change via a lookup.
        if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
          LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid);
          return nullptr;
        }
      }
      new_entry->cookie = cookie;
      new_entry->cookie = cookie;
      new_entry->value.copyFrom_dtoh(map_entry->value);
      new_entry->value.copyFrom_dtoh(map_entry->value);
      new_entry->key = dtohl(map_entry->name.ident);
      new_entry->key = new_key;
      new_entry->key_pool = nullptr;
      new_entry->key_pool = nullptr;
      new_entry->type_pool = nullptr;
      new_entry->type_pool = nullptr;
      ++new_entry;
      ++new_entry;
@@ -293,10 +404,14 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
    return result;
    return result;
  }
  }


  // In case the parent is a dynamic reference, resolve it.
  entry.dynamic_ref_table->lookupResourceId(&parent_resid);

  // Get the parent and do a merge of the keys.
  // Get the parent and do a merge of the keys.
  const ResolvedBag* parent_bag = GetBag(parent);
  const ResolvedBag* parent_bag = GetBag(parent_resid);
  if (parent_bag == nullptr) {
  if (parent_bag == nullptr) {
    // Failed to get the parent that should exist.
    // Failed to get the parent that should exist.
    LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid, resid);
    return nullptr;
    return nullptr;
  }
  }


@@ -315,7 +430,14 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {


  // The keys are expected to be in sorted order. Merge the two bags.
  // The keys are expected to be in sorted order. Merge the two bags.
  while (map_entry != map_entry_end && parent_entry != parent_entry_end) {
  while (map_entry != map_entry_end && parent_entry != parent_entry_end) {
    const uint32_t child_key = dtohl(map_entry->name.ident);
    uint32_t child_key = dtohl(map_entry->name.ident);
    if (!util::is_internal_resid(child_key)) {
      if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) {
        LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key, resid);
        return nullptr;
      }
    }

    if (child_key <= parent_entry->key) {
    if (child_key <= parent_entry->key) {
      // Use the child key if it comes before the parent
      // Use the child key if it comes before the parent
      // or is equal to the parent (overrides).
      // or is equal to the parent (overrides).
@@ -340,9 +462,16 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {


  // Finish the child entries if they exist.
  // Finish the child entries if they exist.
  while (map_entry != map_entry_end) {
  while (map_entry != map_entry_end) {
    uint32_t new_key = dtohl(map_entry->name.ident);
    if (!util::is_internal_resid(new_key)) {
      if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
        LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid);
        return nullptr;
      }
    }
    new_entry->cookie = cookie;
    new_entry->cookie = cookie;
    new_entry->value.copyFrom_dtoh(map_entry->value);
    new_entry->value.copyFrom_dtoh(map_entry->value);
    new_entry->key = dtohl(map_entry->name.ident);
    new_entry->key = new_key;
    new_entry->key_pool = nullptr;
    new_entry->key_pool = nullptr;
    new_entry->type_pool = nullptr;
    new_entry->type_pool = nullptr;
    ++map_entry;
    ++map_entry;
@@ -511,12 +640,43 @@ ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value,
    type_spec_flags |= entry.type_spec_flags;
    type_spec_flags |= entry.type_spec_flags;


    switch (entry.value.dataType) {
    switch (entry.value.dataType) {
      case Res_value::TYPE_NULL:
        return kInvalidCookie;

      case Res_value::TYPE_ATTRIBUTE:
      case Res_value::TYPE_ATTRIBUTE:
        resid = entry.value.data;
        resid = entry.value.data;
        break;
        break;


      case Res_value::TYPE_NULL:
      case Res_value::TYPE_DYNAMIC_ATTRIBUTE: {
        // Resolve the dynamic attribute to a normal attribute
        // (with the right package ID).
        resid = entry.value.data;
        const DynamicRefTable* ref_table =
            asset_manager_->GetDynamicRefTableForPackage(package_idx);
        if (ref_table == nullptr || ref_table->lookupResourceId(&resid) != NO_ERROR) {
          LOG(ERROR) << base::StringPrintf("Failed to resolve dynamic attribute 0x%08x", resid);
          return kInvalidCookie;
        }
      } break;

      case Res_value::TYPE_DYNAMIC_REFERENCE: {
        // Resolve the dynamic reference to a normal reference
        // (with the right package ID).
        out_value->dataType = Res_value::TYPE_REFERENCE;
        out_value->data = entry.value.data;
        const DynamicRefTable* ref_table =
            asset_manager_->GetDynamicRefTableForPackage(package_idx);
        if (ref_table == nullptr || ref_table->lookupResourceId(&out_value->data) != NO_ERROR) {
          LOG(ERROR) << base::StringPrintf("Failed to resolve dynamic reference 0x%08x",
                                           out_value->data);
          return kInvalidCookie;
          return kInvalidCookie;
        }

        if (out_flags != nullptr) {
          *out_flags = type_spec_flags;
        }
        return entry.cookie;
      }


      default:
      default:
        *out_value = entry.value;
        *out_value = entry.value;
@@ -550,14 +710,14 @@ bool Theme::SetTo(const Theme& o) {


  type_spec_flags_ = o.type_spec_flags_;
  type_spec_flags_ = o.type_spec_flags_;


  for (size_t p = 0; p < arraysize(packages_); p++) {
  for (size_t p = 0; p < packages_.size(); p++) {
    const Package* package = o.packages_[p].get();
    const Package* package = o.packages_[p].get();
    if (package == nullptr) {
    if (package == nullptr) {
      packages_[p].reset();
      packages_[p].reset();
      continue;
      continue;
    }
    }


    for (size_t t = 0; t < arraysize(package->types); t++) {
    for (size_t t = 0; t < package->types.size(); t++) {
      const Type* type = package->types[t].get();
      const Type* type = package->types[t].get();
      if (type == nullptr) {
      if (type == nullptr) {
        packages_[p]->types[t].reset();
        packages_[p]->types[t].reset();
+1 −1
Original line number Original line Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 * limitations under the License.
 */
 */


#include "Chunk.h"
#include "androidfw/Chunk.h"


#include "android-base/logging.h"
#include "android-base/logging.h"


+89 −55

File changed.

Preview size limit exceeded, changes collapsed.

Loading