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

Commit 14e8ade9 authored by Ryan Mitchell's avatar Ryan Mitchell
Browse files

Optimize FilterApkAssets by caching config

ResTable_config of every ResTable_type is read from device every time
AssetManager::RebuildFilterList is invoked. For large APKs (like
framework-res.apk), this causes a large number of page faults
when accessing the config from disk. The configs are also used in the
slow path of AssetManager::FindEntryInternal, which makes it even
slower. Instead cache the config on the TypeSpec of its ApkAsset.

Bug: 177247024
Test: libandroidfw_tests
Change-Id: I66d507c4eeb2399f7558f3d9dfc53c157129ada0
parent fb4d09ca
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -285,14 +285,12 @@ Result<ResourceMapping> ResourceMapping::FromApkAssets(const ApkAssets& target_a
                                                       bool enforce_overlayable,
                                                       LogInfo& log_info) {
  AssetManager2 target_asset_manager;
  if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true /* invalidate_caches */,
                                         false /* filter_incompatible_configs*/)) {
  if (!target_asset_manager.SetApkAssets({&target_apk_assets})) {
    return Error("failed to create target asset manager");
  }

  AssetManager2 overlay_asset_manager;
  if (!overlay_asset_manager.SetApkAssets({&overlay_apk_assets}, true /* invalidate_caches */,
                                          false /* filter_incompatible_configs */)) {
  if (!overlay_asset_manager.SetApkAssets({&overlay_apk_assets})) {
    return Error("failed to create overlay asset manager");
  }

+105 −169
Original line number Diff line number Diff line
@@ -103,10 +103,10 @@ AssetManager2::AssetManager2() {
}

bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
                                 bool invalidate_caches, bool filter_incompatible_configs) {
                                 bool invalidate_caches) {
  apk_assets_ = apk_assets;
  BuildDynamicRefTable();
  RebuildFilterList(filter_incompatible_configs);
  RebuildFilterList();
  if (invalidate_caches) {
    InvalidateCaches(static_cast<uint32_t>(-1));
  }
@@ -623,7 +623,8 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
      if (UNLIKELY(logging_enabled)) {
        last_resolution_.steps.push_back(
            Resolution::Step{Resolution::Step::Type::OVERLAID, overlay_result->config.toString(),
                             overlay_result->package_name});
                             overlay_result->package_name,
                             overlay_result->cookie});
      }
    }
  }
@@ -646,22 +647,21 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
  const LoadedPackage* best_package = nullptr;
  incfs::verified_map_ptr<ResTable_type> best_type;
  const ResTable_config* best_config = nullptr;
  ResTable_config best_config_copy;
  uint32_t best_offset = 0U;
  uint32_t type_flags = 0U;

  auto resolution_type = Resolution::Step::Type::NO_ENTRY;
  std::vector<Resolution::Step> resolution_steps;

  // If desired_config is the same as the set configuration, then we can use our filtered list
  // and we don't need to match the configurations, since they already matched.
  const bool use_fast_path = !ignore_configuration && &desired_config == &configuration_;
  // If `desired_config` is not the same as the set configuration or the caller will accept a value
  // from any configuration, then we cannot use our filtered list of types since it only it contains
  // types matched to the set configuration.
  const bool use_filtered = !ignore_configuration && &desired_config == &configuration_;

  const size_t package_count = package_group.packages_.size();
  for (size_t pi = 0; pi < package_count; pi++) {
    const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi];
    const LoadedPackage* loaded_package = loaded_package_impl.loaded_package_;
    ApkAssetsCookie cookie = package_group.cookies_[pi];
    const ApkAssetsCookie cookie = package_group.cookies_[pi];

    // If the type IDs are offset in this package, we need to take that into account when searching
    // for a type.
@@ -670,58 +670,62 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
      continue;
    }

    // Allow custom loader packages to overlay resource values with configurations equivalent to the
    // current best configuration.
    const bool package_is_loader = loaded_package->IsCustomLoader();

    auto entry_flags = type_spec->GetFlagsForEntryIndex(entry_idx);
    if (UNLIKELY(!entry_flags.has_value())) {
      return base::unexpected(entry_flags.error());
    }
    type_flags |= entry_flags.value();

    // If the package is an overlay or custom loader,
    // then even configurations that are the same MUST be chosen.
    const bool package_is_loader = loaded_package->IsCustomLoader();

    if (use_fast_path) {
    const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
      for (const auto& type_config : filtered_group.type_configs) {
        const ResTable_config& this_config = type_config.config;
    const size_t type_entry_count = (use_filtered) ? filtered_group.type_entries.size()
                                                   : type_spec->type_entries.size();
    for (size_t i = 0; i < type_entry_count; i++) {
      const TypeSpec::TypeEntry* type_entry = (use_filtered) ? filtered_group.type_entries[i]
                                                             : &type_spec->type_entries[i];

      // We can skip calling ResTable_config::match() if the caller does not care for the
      // configuration to match or if we're using the list of types that have already had their
      // configuration matched.
      const ResTable_config& this_config = type_entry->config;
      if (!(use_filtered || ignore_configuration || this_config.match(desired_config))) {
        continue;
      }

        // We can skip calling ResTable_config::match() because we know that all candidate
        // configurations that do NOT match have been filtered-out.
      Resolution::Step::Type resolution_type;
      if (best_config == nullptr) {
        resolution_type = Resolution::Step::Type::INITIAL;
      } else if (this_config.isBetterThan(*best_config, &desired_config)) {
          resolution_type = (package_is_loader) ? Resolution::Step::Type::BETTER_MATCH_LOADER
                                                : Resolution::Step::Type::BETTER_MATCH;
        resolution_type = Resolution::Step::Type::BETTER_MATCH;
      } else if (package_is_loader && this_config.compare(*best_config) == 0) {
          resolution_type = Resolution::Step::Type::OVERLAID_LOADER;
        resolution_type = Resolution::Step::Type::OVERLAID;
      } else {
        if (UNLIKELY(logging_enabled)) {
            resolution_type = (package_is_loader) ? Resolution::Step::Type::SKIPPED_LOADER
                                                  : Resolution::Step::Type::SKIPPED;
            resolution_steps.push_back(Resolution::Step{resolution_type,
          resolution_steps.push_back(Resolution::Step{Resolution::Step::Type::SKIPPED,
                                                      this_config.toString(),
                                                        &loaded_package->GetPackageName()});
                                                      &loaded_package->GetPackageName(),
                                                      cookie});
        }
        continue;
      }

      // The configuration matches and is better than the previous selection.
      // Find the entry value if it exists for this configuration.
        const auto& type = type_config.type;
      const auto& type = type_entry->type;
      const auto offset = LoadedPackage::GetEntryOffset(type, entry_idx);
      if (UNLIKELY(IsIOError(offset))) {
        return base::unexpected(offset.error());
      }

      if (!offset.has_value()) {
        if (UNLIKELY(logging_enabled)) {
            if (package_is_loader) {
              resolution_type = Resolution::Step::Type::NO_ENTRY_LOADER;
            } else {
              resolution_type = Resolution::Step::Type::NO_ENTRY;
            }
            resolution_steps.push_back(Resolution::Step{resolution_type,
          resolution_steps.push_back(Resolution::Step{Resolution::Step::Type::NO_ENTRY,
                                                      this_config.toString(),
                                                        &loaded_package->GetPackageName()});
                                                      &loaded_package->GetPackageName(),
                                                      cookie});
        }
        continue;
      }
@@ -735,66 +739,14 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
      if (UNLIKELY(logging_enabled)) {
        last_resolution_.steps.push_back(Resolution::Step{resolution_type,
                                                          this_config.toString(),
                                                            &loaded_package->GetPackageName()});
        }
      }
    } else {
      // This is the slower path, which doesn't use the filtered list of configurations.
      // Here we must read the ResTable_config from the mmapped APK, convert it to host endianness
      // and fill in any new fields that did not exist when the APK was compiled.
      // Furthermore when selecting configurations we can't just record the pointer to the
      // ResTable_config, we must copy it.
      const auto iter_end = type_spec->types + type_spec->type_count;
      for (auto iter = type_spec->types; iter != iter_end; ++iter) {
        const incfs::verified_map_ptr<ResTable_type>& type = *iter;

        ResTable_config this_config{};
        if (!ignore_configuration) {
          this_config.copyFromDtoH(type->config);
          if (!this_config.match(desired_config)) {
            continue;
                                                          &loaded_package->GetPackageName(),
                                                          cookie});
      }

          if (best_config == nullptr) {
            resolution_type = Resolution::Step::Type::INITIAL;
          } else if (this_config.isBetterThan(*best_config, &desired_config)) {
            resolution_type = (package_is_loader) ? Resolution::Step::Type::BETTER_MATCH_LOADER
                                                  : Resolution::Step::Type::BETTER_MATCH;
          } else if (package_is_loader && this_config.compare(*best_config) == 0) {
            resolution_type = Resolution::Step::Type::OVERLAID_LOADER;
          } else {
            continue;
          }
        }

        // The configuration matches and is better than the previous selection.
        // Find the entry value if it exists for this configuration.
        const auto offset = LoadedPackage::GetEntryOffset(type, entry_idx);
        if (UNLIKELY(IsIOError(offset))) {
          return base::unexpected(offset.error());
        }
        if (!offset.has_value()) {
          continue;
        }

        best_cookie = cookie;
        best_package = loaded_package;
        best_type = type;
        best_config_copy = this_config;
        best_config = &best_config_copy;
        best_offset = offset.value();

        if (stop_at_first_match) {
      // Any configuration will suffice, so break.
      if (stop_at_first_match) {
        break;
      }

        if (UNLIKELY(logging_enabled)) {
          last_resolution_.steps.push_back(Resolution::Step{resolution_type,
                                                            this_config.toString(),
                                                            &loaded_package->GetPackageName()});
        }
      }
    }
  }

@@ -851,19 +803,16 @@ std::string AssetManager2::GetLastResourceResolution() const {
    return {};
  }

  auto cookie = last_resolution_.cookie;
  const ApkAssetsCookie cookie = last_resolution_.cookie;
  if (cookie == kInvalidCookie) {
    LOG(ERROR) << "AssetManager hasn't resolved a resource to read resolution path.";
    return {};
  }

  uint32_t resid = last_resolution_.resid;
  std::vector<Resolution::Step>& steps = last_resolution_.steps;
  std::string resource_name_string;

  const LoadedPackage* package =
          apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
  const uint32_t resid = last_resolution_.resid;
  const auto package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));

  std::string resource_name_string;
  if (package != nullptr) {
    auto resource_name = ToResourceName(last_resolution_.type_string_ref,
                                        last_resolution_.entry_string_ref,
@@ -878,46 +827,26 @@ std::string AssetManager2::GetLastResourceResolution() const {
            << "\n\tFor config -"
            << configuration_.toString();

  std::string prefix;
  for (Resolution::Step step : steps) {
    switch (step.type) {
      case Resolution::Step::Type::INITIAL:
        prefix = "Found initial";
        break;
      case Resolution::Step::Type::BETTER_MATCH:
        prefix = "Found better";
        break;
      case Resolution::Step::Type::BETTER_MATCH_LOADER:
        prefix = "Found better in loader";
        break;
      case Resolution::Step::Type::OVERLAID:
        prefix = "Overlaid";
        break;
      case Resolution::Step::Type::OVERLAID_LOADER:
        prefix = "Overlaid by loader";
        break;
      case Resolution::Step::Type::SKIPPED:
        prefix = "Skipped";
        break;
      case Resolution::Step::Type::SKIPPED_LOADER:
        prefix = "Skipped loader";
        break;
      case Resolution::Step::Type::NO_ENTRY:
        prefix = "No entry";
        break;
      case Resolution::Step::Type::NO_ENTRY_LOADER:
        prefix = "No entry for loader";
        break;
    }
  for (const Resolution::Step& step : last_resolution_.steps) {
    const static std::unordered_map<Resolution::Step::Type, const char*> kStepStrings = {
        {Resolution::Step::Type::INITIAL, "Found initial"},
        {Resolution::Step::Type::BETTER_MATCH, "Found better"},
        {Resolution::Step::Type::OVERLAID, "Overlaid"},
        {Resolution::Step::Type::SKIPPED, "Skipped"},
        {Resolution::Step::Type::NO_ENTRY, "No entry"}
    };

    if (!prefix.empty()) {
      log_stream << "\n\t" << prefix << ": " << *step.package_name;
    const auto prefix = kStepStrings.find(step.type);
    if (prefix == kStepStrings.end()) {
      continue;
    }

    log_stream << "\n\t" << prefix->second << ": " << *step.package_name << " ("
               << apk_assets_[step.cookie]->GetPath() << ")";
    if (!step.config_name.isEmpty()) {
      log_stream << " -" << step.config_name;
    }
  }
  }

  return log_stream.str();
}
@@ -935,6 +864,16 @@ base::expected<AssetManager2::ResourceName, NullOrIOError> AssetManager2::GetRes
                        *result->package_name);
}

base::expected<uint32_t, NullOrIOError> AssetManager2::GetResourceTypeSpecFlags(
    uint32_t resid) const {
  auto result = FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */,
                          true /* ignore_configuration */);
  if (!result.has_value()) {
    return base::unexpected(result.error());
  }
  return result->type_flags;
}

base::expected<AssetManager2::SelectedValue, NullOrIOError> AssetManager2::GetResource(
    uint32_t resid, bool may_be_bag, uint16_t density_override) const {
  auto result = FindEntry(resid, density_override, false /* stop_at_first_match */,
@@ -1333,7 +1272,7 @@ base::expected<uint32_t, NullOrIOError> AssetManager2::GetResourceId(
  return base::unexpected(std::nullopt);
}

void AssetManager2::RebuildFilterList(bool filter_incompatible_configs) {
void AssetManager2::RebuildFilterList() {
  for (PackageGroup& group : package_groups_) {
    for (ConfiguredPackage& impl : group.packages_) {
      // Destroy it.
@@ -1343,14 +1282,11 @@ void AssetManager2::RebuildFilterList(bool filter_incompatible_configs) {
      new (&impl.filtered_configs_) ByteBucketArray<FilteredConfigGroup>();

      // Create the filters here.
      impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec* spec, uint8_t type_index) {
        FilteredConfigGroup& group = impl.filtered_configs_.editItemAt(type_index);
        const auto iter_end = spec->types + spec->type_count;
        for (auto iter = spec->types; iter != iter_end; ++iter) {
          ResTable_config this_config;
          this_config.copyFromDtoH((*iter)->config);
          if (!filter_incompatible_configs || this_config.match(configuration_)) {
            group.type_configs.push_back(TypeConfig{*iter, this_config});
      impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
        FilteredConfigGroup& group = impl.filtered_configs_.editItemAt(type_id - 1);
        for (const auto& type_entry : type_spec.type_entries) {
          if (type_entry.config.match(configuration_)) {
            group.type_entries.push_back(&type_entry);
          }
        }
      });
+30 −64
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@
#endif
#endif

#include "androidfw/ByteBucketArray.h"
#include "androidfw/Chunk.h"
#include "androidfw/ResourceUtils.h"
#include "androidfw/Util.h"
@@ -49,36 +48,24 @@ namespace {
// Builder that helps accumulate Type structs and then create a single
// contiguous block of memory to store both the TypeSpec struct and
// the Type structs.
class TypeSpecPtrBuilder {
 public:
  explicit TypeSpecPtrBuilder(incfs::verified_map_ptr<ResTable_typeSpec> header)
      : header_(header) {
  }
struct TypeSpecBuilder {
  explicit TypeSpecBuilder(incfs::verified_map_ptr<ResTable_typeSpec> header) : header_(header) {}

  void AddType(incfs::verified_map_ptr<ResTable_type> type) {
    types_.push_back(type);
    TypeSpec::TypeEntry& entry = type_entries.emplace_back();
    entry.config.copyFromDtoH(type->config);
    entry.type = type;
  }

  TypeSpecPtr Build() {
    // Check for overflow.
    using ElementType = incfs::verified_map_ptr<ResTable_type>;
    if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(ElementType) <
        types_.size()) {
      return {};
    }
    TypeSpec* type_spec =
        (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(ElementType)));
    type_spec->type_spec = header_;
    type_spec->type_count = types_.size();
    memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(ElementType));
    return TypeSpecPtr(type_spec);
  TypeSpec Build() {
    return {header_, std::move(type_entries)};
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(TypeSpecPtrBuilder);
  DISALLOW_COPY_AND_ASSIGN(TypeSpecBuilder);

  incfs::verified_map_ptr<ResTable_typeSpec> header_;
  std::vector<incfs::verified_map_ptr<ResTable_type>> types_;
  std::vector<TypeSpec::TypeEntry> type_entries;
};

}  // namespace
@@ -322,15 +309,10 @@ base::expected<incfs::map_ptr<ResTable_entry>, NullOrIOError> LoadedPackage::Get
}

base::expected<std::monostate, IOError> LoadedPackage::CollectConfigurations(
    bool exclude_mipmap, std::set<ResTable_config>* out_configs) const {
  const size_t type_count = type_specs_.size();
  for (size_t i = 0; i < type_count; i++) {
    const TypeSpecPtr& type_spec = type_specs_[i];
    if (type_spec == nullptr) {
      continue;
    }
    bool exclude_mipmap, std::set<ResTable_config>* out_configs) const {\
  for (const auto& type_spec : type_specs_) {
    if (exclude_mipmap) {
      const int type_idx = type_spec->type_spec->id - 1;
      const int type_idx = type_spec.first - 1;
      const auto type_name16 = type_string_pool_.stringAt(type_idx);
      if (UNLIKELY(IsIOError(type_name16))) {
        return base::unexpected(GetIOError(type_name16.error()));
@@ -354,11 +336,8 @@ base::expected<std::monostate, IOError> LoadedPackage::CollectConfigurations(
      }
    }

    const auto iter_end = type_spec->types + type_spec->type_count;
    for (auto iter = type_spec->types; iter != iter_end; ++iter) {
      ResTable_config config;
      config.copyFromDtoH((*iter)->config);
      out_configs->insert(config);
    for (const auto& type_entry : type_spec.second.type_entries) {
      out_configs->insert(type_entry.config);
    }
  }
  return {};
@@ -366,23 +345,16 @@ base::expected<std::monostate, IOError> LoadedPackage::CollectConfigurations(

void LoadedPackage::CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const {
  char temp_locale[RESTABLE_MAX_LOCALE_LEN];
  const size_t type_count = type_specs_.size();
  for (size_t i = 0; i < type_count; i++) {
    const TypeSpecPtr& type_spec = type_specs_[i];
    if (type_spec != nullptr) {
      const auto iter_end = type_spec->types + type_spec->type_count;
      for (auto iter = type_spec->types; iter != iter_end; ++iter) {
        ResTable_config configuration;
        configuration.copyFromDtoH((*iter)->config);
        if (configuration.locale != 0) {
          configuration.getBcp47Locale(temp_locale, canonicalize);
  for (const auto& type_spec : type_specs_) {
    for (const auto& type_entry : type_spec.second.type_entries) {
      if (type_entry.config.locale != 0) {
        type_entry.config.getBcp47Locale(temp_locale, canonicalize);
        std::string locale(temp_locale);
        out_locales->insert(std::move(locale));
      }
    }
  }
}
}

base::expected<uint32_t, NullOrIOError> LoadedPackage::FindEntryByName(
    const std::u16string& type_name, const std::u16string& entry_name) const {
@@ -398,14 +370,13 @@ base::expected<uint32_t, NullOrIOError> LoadedPackage::FindEntryByName(
    return base::unexpected(key_idx.error());
  }

  const TypeSpec* type_spec = type_specs_[*type_idx].get();
  const TypeSpec* type_spec = GetTypeSpecByTypeIndex(*type_idx);
  if (type_spec == nullptr) {
    return base::unexpected(std::nullopt);
  }

  const auto iter_end = type_spec->types + type_spec->type_count;
  for (auto iter = type_spec->types; iter != iter_end; ++iter) {
    const incfs::verified_map_ptr<ResTable_type>& type = *iter;
  for (const auto& type_entry : type_spec->type_entries) {
    const incfs::verified_map_ptr<ResTable_type>& type = type_entry.type;

    size_t entry_count = dtohl(type->entryCount);
    for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
@@ -492,7 +463,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
  // A map of TypeSpec builders, each associated with an type index.
  // We use these to accumulate the set of Types available for a TypeSpec, and later build a single,
  // contiguous block of memory that holds all the Types together with the TypeSpec.
  std::unordered_map<int, std::unique_ptr<TypeSpecPtrBuilder>> type_builder_map;
  std::unordered_map<int, std::unique_ptr<TypeSpecBuilder>> type_builder_map;

  ChunkIterator iter(chunk.data_ptr(), chunk.data_size());
  while (iter.HasNext()) {
@@ -562,9 +533,9 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
          return {};
        }

        std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type_spec->id - 1];
        std::unique_ptr<TypeSpecBuilder>& builder_ptr = type_builder_map[type_spec->id];
        if (builder_ptr == nullptr) {
          builder_ptr = util::make_unique<TypeSpecPtrBuilder>(type_spec.verified());
          builder_ptr = util::make_unique<TypeSpecBuilder>(type_spec.verified());
          loaded_package->resource_ids_.set(type_spec->id, entry_count);
        } else {
          LOG(WARNING) << StringPrintf("RES_TABLE_TYPE_SPEC_TYPE already defined for ID %02x",
@@ -584,7 +555,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
        }

        // Type chunks must be preceded by their TypeSpec chunks.
        std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type->id - 1];
        std::unique_ptr<TypeSpecBuilder>& builder_ptr = type_builder_map[type->id];
        if (builder_ptr != nullptr) {
          builder_ptr->AddType(type.verified());
        } else {
@@ -722,14 +693,9 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,

  // Flatten and construct the TypeSpecs.
  for (auto& entry : type_builder_map) {
    uint8_t type_idx = static_cast<uint8_t>(entry.first);
    TypeSpecPtr type_spec_ptr = entry.second->Build();
    if (type_spec_ptr == nullptr) {
      LOG(ERROR) << "Too many type configurations, overflow detected.";
      return {};
    }

    loaded_package->type_specs_.editItemAt(type_idx) = std::move(type_spec_ptr);
    TypeSpec type_spec = entry.second->Build();
    uint8_t type_id = static_cast<uint8_t>(entry.first);
    loaded_package->type_specs_[type_id] = std::move(type_spec);
  }

  return std::move(loaded_package);
+12 −17
Original line number Diff line number Diff line
@@ -101,12 +101,7 @@ class AssetManager2 {
  // Only pass invalidate_caches=false when it is known that the structure
  // change in ApkAssets is due to a safe addition of resources with completely
  // new resource IDs.
  //
  // Only pass in filter_incompatible_configs=false when you want to load all
  // configurations (including incompatible ones) such as when constructing an
  // idmap.
  bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true,
          bool filter_incompatible_configs = true);
  bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true);

  inline const std::vector<const ApkAssets*> GetApkAssets() const {
    return apk_assets_;
@@ -298,6 +293,12 @@ class AssetManager2 {
  // data failed.
  base::expected<const ResolvedBag*, NullOrIOError> ResolveBag(SelectedValue& value) const;

  // Returns the android::ResTable_typeSpec flags of the resource ID.
  //
  // Returns a null error if the resource could not be resolved, or an I/O error if reading
  // resource data failed.
  base::expected<uint32_t, NullOrIOError> GetResourceTypeSpecFlags(uint32_t resid) const;

  const std::vector<uint32_t> GetBagResIdStack(uint32_t resid) const;

  // Resets the resource resolution structures in preparation for the next resource retrieval.
@@ -330,15 +331,10 @@ class AssetManager2 {
 private:
  DISALLOW_COPY_AND_ASSIGN(AssetManager2);

  struct TypeConfig {
    incfs::verified_map_ptr<ResTable_type> type;
    ResTable_config config;
  };

  // A collection of configurations and their associated ResTable_type that match the current
  // AssetManager configuration.
  struct FilteredConfigGroup {
      std::vector<TypeConfig> type_configs;
      std::vector<const TypeSpec::TypeEntry*> type_entries;
  };

  // Represents an single package.
@@ -413,7 +409,7 @@ class AssetManager2 {

  // Triggers the re-construction of lists of types that match the set configuration.
  // This should always be called when mutating the AssetManager's configuration or ApkAssets set.
  void RebuildFilterList(bool filter_incompatible_configs = true);
  void RebuildFilterList();

  // Retrieves the APK paths of overlays that overlay non-system packages.
  std::set<std::string> GetNonSystemOverlayPaths() const;
@@ -460,13 +456,9 @@ class AssetManager2 {
      enum class Type {
        INITIAL,
        BETTER_MATCH,
        BETTER_MATCH_LOADER,
        OVERLAID,
        OVERLAID_LOADER,
        SKIPPED,
        SKIPPED_LOADER,
        NO_ENTRY,
        NO_ENTRY_LOADER,
      };

      // Marks what kind of override this step was.
@@ -477,6 +469,9 @@ class AssetManager2 {

      // Marks the package name of the better resource found in this step.
      const std::string* package_name;

      //
      ApkAssetsCookie cookie = kInvalidCookie;
    };

    // Last resolved resource ID.
+19 −23

File changed.

Preview size limit exceeded, changes collapsed.

Loading