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

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

Merge "Optimize FilterApkAssets by caching config"

parents 41903dfe 14e8ade9
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