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

Commit 46b07526 authored by Yurii Zubrytskyi's avatar Yurii Zubrytskyi Committed by Android (Google) Code Review
Browse files

Merge changes Ie5999dda,I2853cd3c,I7d9f1fe3,I19576654,I158af793, ...

* changes:
  [res] Don't stat asset providers on RO filesystems
  [res] Change OverlayableInfo to hold string views
  [res] Change staged alias container to vector
  [res] Change callback from function to function_ref
  [res] Reuse memory in RebuildFilterList()
  [res] Split keys and values in Theme::Entry vector
  [res] Properly create ZipAssetsProvider with fd
parents 7b7f8aba 2ab4447a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ Result<Unit> CheckOverlayable(const TargetResourceContainer& target,
    // If the overlay supplies a target overlayable name, the resource must belong to the
    // overlayable defined with the specified name to be overlaid.
    return Error(R"(<overlay> android:targetName "%s" does not match overlayable name "%s")",
                 overlay_info.target_name.c_str(), (*overlayable_info)->name.c_str());
                 overlay_info.target_name.c_str(), (*overlayable_info)->name.data());
  }

  // Enforce policy restrictions if the resource is declared as overlayable.

libs/androidfw/ApkAssets.cpp

100755 → 100644
+3 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

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

namespace android {

@@ -84,7 +85,7 @@ std::unique_ptr<ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
  }

  std::string overlay_path(loaded_idmap->OverlayApkPath());
  auto fd = unique_fd(::open(overlay_path.c_str(), O_RDONLY|O_CLOEXEC));
  auto fd = unique_fd(base::utf8::open(overlay_path.c_str(), O_RDONLY | O_CLOEXEC));
  std::unique_ptr<AssetsProvider> overlay_assets;
  if (IsFabricatedOverlay(fd)) {
    // Fabricated overlays do not contain resource definitions. All of the overlay resource values
@@ -92,7 +93,7 @@ std::unique_ptr<ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
    overlay_assets = EmptyAssetsProvider::Create(std::move(overlay_path));
  } else {
    // The overlay should be an APK.
    overlay_assets = ZipAssetsProvider::Create(std::move(fd), std::move(overlay_path), flags);
    overlay_assets = ZipAssetsProvider::Create(std::move(overlay_path), flags, std::move(fd));
  }
  if (overlay_assets == nullptr) {
    return {};
+57 −44
Original line number Diff line number Diff line
@@ -374,7 +374,7 @@ bool AssetManager2::GetOverlayablesToString(android::StringPiece package_name,
        const std::string name = ToFormattedResourceString(*res_name);
        output.append(base::StringPrintf(
            "resource='%s' overlayable='%s' actor='%s' policy='0x%08x'\n",
            name.c_str(), info->name.c_str(), info->actor.c_str(), info->policy_flags));
            name.c_str(), info->name.data(), info->actor.data(), info->policy_flags));
      }
    }
  }
@@ -1356,21 +1356,22 @@ base::expected<uint32_t, NullOrIOError> AssetManager2::GetResourceId(

void AssetManager2::RebuildFilterList() {
  for (PackageGroup& group : package_groups_) {
    for (ConfiguredPackage& impl : group.packages_) {
      impl.filtered_configs_.clear();

    for (ConfiguredPackage& package : group.packages_) {
      package.filtered_configs_.forEachItem([](auto, auto& fcg) { fcg.type_entries.clear(); });
      // Create the filters here.
      impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
      package.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
        FilteredConfigGroup* group = nullptr;
        for (const auto& type_entry : type_spec.type_entries) {
          if (type_entry.config.match(configuration_)) {
            if (!group) {
              group = &impl.filtered_configs_.editItemAt(type_id - 1);
              group = &package.filtered_configs_.editItemAt(type_id - 1);
            }
            group->type_entries.push_back(&type_entry);
          }
        }
      });
      package.filtered_configs_.trimBuckets(
          [](const auto& fcg) { return fcg.type_entries.empty(); });
    }
  }
}
@@ -1411,30 +1412,34 @@ uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const
std::unique_ptr<Theme> AssetManager2::NewTheme() {
  constexpr size_t kInitialReserveSize = 32;
  auto theme = std::unique_ptr<Theme>(new Theme(this));
  theme->keys_.reserve(kInitialReserveSize);
  theme->entries_.reserve(kInitialReserveSize);
  return theme;
}

void AssetManager2::ForEachPackage(base::function_ref<bool(const std::string&, uint8_t)> func,
                                   package_property_t excluded_property_flags) const {
  for (const PackageGroup& package_group : package_groups_) {
    const auto loaded_package = package_group.packages_.front().loaded_package_;
    if ((loaded_package->GetPropertyFlags() & excluded_property_flags) == 0U
        && !func(loaded_package->GetPackageName(),
                 package_group.dynamic_ref_table->mAssignedPackageId)) {
      return;
    }
  }
}

Theme::Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {
}

Theme::~Theme() = default;

struct Theme::Entry {
  uint32_t attr_res_id;
  ApkAssetsCookie cookie;
  uint32_t type_spec_flags;
  Res_value value;
};

namespace {
struct ThemeEntryKeyComparer {
  bool operator() (const Theme::Entry& entry, uint32_t attr_res_id) const noexcept {
    return entry.attr_res_id < attr_res_id;
  }
};
} // namespace

base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid, bool force) {
  ATRACE_NAME("Theme::ApplyStyle");

@@ -1463,18 +1468,20 @@ base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid,
      continue;
    }

    auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), attr_res_id,
                                     ThemeEntryKeyComparer{});
    if (entry_it != entries_.end() && entry_it->attr_res_id == attr_res_id) {
    const auto key_it = std::lower_bound(keys_.begin(), keys_.end(), attr_res_id);
    const auto entry_it = entries_.begin() + (key_it - keys_.begin());
    if (key_it != keys_.end() && *key_it == attr_res_id) {
      if (is_undefined) {
        // DATA_NULL_UNDEFINED clears the value of the attribute in the theme only when `force` is
        /// true.
        // true.
        keys_.erase(key_it);
        entries_.erase(entry_it);
      } else if (force) {
        *entry_it = Entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value};
        *entry_it = Entry{it->cookie, (*bag)->type_spec_flags, it->value};
      }
    } else {
      entries_.insert(entry_it, Entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value});
      keys_.insert(key_it, attr_res_id);
      entries_.insert(entry_it, Entry{it->cookie, (*bag)->type_spec_flags, it->value});
    }
  }
  return {};
@@ -1485,6 +1492,7 @@ void Theme::Rebase(AssetManager2* am, const uint32_t* style_ids, const uint8_t*
  ATRACE_NAME("Theme::Rebase");
  // Reset the entries without changing the vector capacity to prevent reallocations during
  // ApplyStyle.
  keys_.clear();
  entries_.clear();
  asset_manager_ = am;
  for (size_t i = 0; i < style_count; i++) {
@@ -1493,16 +1501,14 @@ void Theme::Rebase(AssetManager2* am, const uint32_t* style_ids, const uint8_t*
}

std::optional<AssetManager2::SelectedValue> Theme::GetAttribute(uint32_t resid) const {

  constexpr const uint32_t kMaxIterations = 20;
  uint32_t type_spec_flags = 0u;
  for (uint32_t i = 0; i <= kMaxIterations; i++) {
    auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), resid,
                                     ThemeEntryKeyComparer{});
    if (entry_it == entries_.end() || entry_it->attr_res_id != resid) {
    const auto key_it = std::lower_bound(keys_.begin(), keys_.end(), resid);
    if (key_it == keys_.end() || *key_it != resid) {
      return std::nullopt;
    }

    const auto entry_it = entries_.begin() + (key_it - keys_.begin());
    type_spec_flags |= entry_it->type_spec_flags;
    if (entry_it->value.dataType == Res_value::TYPE_ATTRIBUTE) {
      resid = entry_it->value.data;
@@ -1536,6 +1542,7 @@ base::expected<std::monostate, NullOrIOError> Theme::ResolveAttributeReference(
}

void Theme::Clear() {
  keys_.clear();
  entries_.clear();
}

@@ -1547,11 +1554,12 @@ base::expected<std::monostate, IOError> Theme::SetTo(const Theme& source) {
  type_spec_flags_ = source.type_spec_flags_;

  if (asset_manager_ == source.asset_manager_) {
    keys_ = source.keys_;
    entries_ = source.entries_;
  } else {
    std::map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
    typedef std::map<int, int> SourceToDestinationRuntimePackageMap;
    std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
    std::unordered_map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
    using SourceToDestinationRuntimePackageMap = std::unordered_map<int, int>;
    std::unordered_map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;

    // Determine which ApkAssets are loaded in both theme AssetManagers.
    const auto src_assets = source.asset_manager_->GetApkAssets();
@@ -1579,15 +1587,17 @@ base::expected<std::monostate, IOError> Theme::SetTo(const Theme& source) {
        }

        src_to_dest_asset_cookies.insert(std::make_pair(i, j));
        src_asset_cookie_id_map.insert(std::make_pair(i, package_map));
        src_asset_cookie_id_map.insert(std::make_pair(i, std::move(package_map)));
        break;
      }
    }

    // Reset the data in the destination theme.
    keys_.clear();
    entries_.clear();

    for (const auto& entry : source.entries_) {
    for (size_t i = 0, size = source.entries_.size(); i != size; ++i) {
      const auto& entry = source.entries_[i];
      bool is_reference = (entry.value.dataType == Res_value::TYPE_ATTRIBUTE
                           || entry.value.dataType == Res_value::TYPE_REFERENCE
                           || entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
@@ -1627,13 +1637,15 @@ base::expected<std::monostate, IOError> Theme::SetTo(const Theme& source) {
        }
      }

      const auto source_res_id = source.keys_[i];

      // The package id of the attribute needs to be rewritten to the package id of the
      // attribute in the destination.
      int attribute_dest_package_id = get_package_id(entry.attr_res_id);
      int attribute_dest_package_id = get_package_id(source_res_id);
      if (attribute_dest_package_id != 0x01) {
        // Find the cookie of the attribute resource id in the source AssetManager
        base::expected<FindEntryResult, NullOrIOError> attribute_entry_result =
            source.asset_manager_->FindEntry(entry.attr_res_id, 0 /* density_override */ ,
            source.asset_manager_->FindEntry(source_res_id, 0 /* density_override */ ,
                                             true /* stop_at_first_match */,
                                             true /* ignore_configuration */);
        if (UNLIKELY(IsIOError(attribute_entry_result))) {
@@ -1657,16 +1669,15 @@ base::expected<std::monostate, IOError> Theme::SetTo(const Theme& source) {
        attribute_dest_package_id = attribute_dest_package->second;
      }

      auto dest_attr_id = make_resid(attribute_dest_package_id, get_type_id(entry.attr_res_id),
                                     get_entry_id(entry.attr_res_id));
      Theme::Entry new_entry{dest_attr_id, data_dest_cookie, entry.type_spec_flags,
                                            Res_value{.dataType = entry.value.dataType,
                                                      .data = attribute_data}};

      auto dest_attr_id = make_resid(attribute_dest_package_id, get_type_id(source_res_id),
                                     get_entry_id(source_res_id));
      const auto key_it = std::lower_bound(keys_.begin(), keys_.end(), dest_attr_id);
      const auto entry_it = entries_.begin() + (key_it - keys_.begin());
      // Since the entries were cleared, the attribute resource id has yet been mapped to any value.
      auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), dest_attr_id,
                                       ThemeEntryKeyComparer{});
      entries_.insert(entry_it, new_entry);
      keys_.insert(key_it, dest_attr_id);
      entries_.insert(entry_it, Entry{data_dest_cookie, entry.type_spec_flags,
                                      Res_value{.dataType = entry.value.dataType,
                                                .data = attribute_data}});
    }
  }
  return {};
@@ -1674,9 +1685,11 @@ base::expected<std::monostate, IOError> Theme::SetTo(const Theme& source) {

void Theme::Dump() const {
  LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_);
  for (auto& entry : entries_) {
  for (size_t i = 0, size = keys_.size(); i != size; ++i) {
    auto res_id = keys_[i];
    const auto& entry = entries_[i];
    LOG(INFO) << base::StringPrintf("  entry(0x%08x)=(0x%08x) type=(0x%02x), cookie(%d)",
                                    entry.attr_res_id, entry.value.data, entry.value.dataType,
                                    res_id, entry.value.data, entry.value.dataType,
                                    entry.cookie);
  }
}
+35 −19
Original line number Diff line number Diff line
@@ -92,22 +92,28 @@ ZipAssetsProvider::ZipAssetsProvider(ZipArchiveHandle handle, PathOrDebugName&&
      last_mod_time_(last_mod_time) {}

std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path,
                                                             package_property_t flags) {
                                                             package_property_t flags,
                                                             base::unique_fd fd) {
  const auto released_fd = fd.ok() ? fd.release() : -1;
  ZipArchiveHandle handle;
  if (int32_t result = OpenArchive(path.c_str(), &handle); result != 0) {
  if (int32_t result = released_fd < 0 ? OpenArchive(path.c_str(), &handle)
                                       : OpenArchiveFd(released_fd, path.c_str(), &handle)) {
    LOG(ERROR) << "Failed to open APK '" << path << "': " << ::ErrorCodeString(result);
    CloseArchive(handle);
    return {};
  }

  struct stat sb{.st_mtime = -1};
  if (stat(path.c_str(), &sb) < 0) {
  // Skip all up-to-date checks if the file won't ever change.
  if (!isReadonlyFilesystem(path.c_str())) {
    if ((released_fd < 0 ? stat(path.c_str(), &sb) : fstat(released_fd, &sb)) < 0) {
      // Stat requires execute permissions on all directories path to the file. If the process does
      // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
      // always have to return true.
      LOG(WARNING) << "Failed to stat file '" << path << "': "
                   << base::SystemErrorCodeToString(errno);
    }
  }

  return std::unique_ptr<ZipAssetsProvider>(
      new ZipAssetsProvider(handle, PathOrDebugName{std::move(path),
@@ -133,12 +139,15 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd,
  }

  struct stat sb{.st_mtime = -1};
  // Skip all up-to-date checks if the file won't ever change.
  if (!isReadonlyFilesystem(released_fd)) {
    if (fstat(released_fd, &sb) < 0) {
      // Stat requires execute permissions on all directories path to the file. If the process does
      // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
      // always have to return true.
    LOG(WARNING) << "Failed to fstat file '" << friendly_name << "': "
                 << base::SystemErrorCodeToString(errno);
      LOG(WARNING) << "Failed to fstat file '" << friendly_name
                   << "': " << base::SystemErrorCodeToString(errno);
    }
  }

  return std::unique_ptr<ZipAssetsProvider>(
@@ -275,6 +284,9 @@ const std::string& ZipAssetsProvider::GetDebugName() const {
}

bool ZipAssetsProvider::IsUpToDate() const {
  if (last_mod_time_ == -1) {
    return true;
  }
  struct stat sb{};
  if (fstat(GetFileDescriptor(zip_handle_.get()), &sb) < 0) {
    // If fstat fails on the zip archive, return true so the zip archive the resource system does
@@ -288,7 +300,7 @@ DirectoryAssetsProvider::DirectoryAssetsProvider(std::string&& path, time_t last
    : dir_(std::forward<std::string>(path)), last_mod_time_(last_mod_time) {}

std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::string path) {
  struct stat sb{};
  struct stat sb;
  const int result = stat(path.c_str(), &sb);
  if (result == -1) {
    LOG(ERROR) << "Failed to find directory '" << path << "'.";
@@ -304,8 +316,9 @@ std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::st
    path += OS_PATH_SEPARATOR;
  }

  return std::unique_ptr<DirectoryAssetsProvider>(new DirectoryAssetsProvider(std::move(path),
                                                                              sb.st_mtime));
  const bool isReadonly = isReadonlyFilesystem(path.c_str());
  return std::unique_ptr<DirectoryAssetsProvider>(
      new DirectoryAssetsProvider(std::move(path), isReadonly ? -1 : sb.st_mtime));
}

std::unique_ptr<Asset> DirectoryAssetsProvider::OpenInternal(const std::string& path,
@@ -335,7 +348,10 @@ const std::string& DirectoryAssetsProvider::GetDebugName() const {
}

bool DirectoryAssetsProvider::IsUpToDate() const {
  struct stat sb{};
  if (last_mod_time_ == -1) {
    return true;
  }
  struct stat sb;
  if (stat(dir_.c_str(), &sb) < 0) {
    // If stat fails on the zip archive, return true so the zip archive the resource system does
    // attempt to refresh the ApkAsset.
+21 −14
Original line number Diff line number Diff line
@@ -645,16 +645,16 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
        }

        std::string name;
        util::ReadUtf16StringFromDevice(overlayable->name, arraysize(overlayable->name), &name);
        util::ReadUtf16StringFromDevice(overlayable->name, std::size(overlayable->name), &name);
        std::string actor;
        util::ReadUtf16StringFromDevice(overlayable->actor, arraysize(overlayable->actor), &actor);

        if (loaded_package->overlayable_map_.find(name) !=
            loaded_package->overlayable_map_.end()) {
          LOG(ERROR) << "Multiple <overlayable> blocks with the same name '" << name << "'.";
        util::ReadUtf16StringFromDevice(overlayable->actor, std::size(overlayable->actor), &actor);
        auto [name_to_actor_it, inserted] =
            loaded_package->overlayable_map_.emplace(std::move(name), std::move(actor));
        if (!inserted) {
          LOG(ERROR) << "Multiple <overlayable> blocks with the same name '"
                     << name_to_actor_it->first << "'.";
          return {};
        }
        loaded_package->overlayable_map_.emplace(name, actor);

        // Iterate over the overlayable policy chunks contained within the overlayable chunk data
        ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
@@ -669,7 +669,6 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
                LOG(ERROR) << "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small.";
                return {};
              }

              if ((overlayable_child_chunk.data_size() / sizeof(ResTable_ref))
                  < dtohl(policy_header->entry_count)) {
                LOG(ERROR) <<  "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small to hold entries.";
@@ -691,8 +690,8 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,

              // Add the pairing of overlayable properties and resource ids to the package
              OverlayableInfo overlayable_info {
                .name = name,
                .actor = actor,
                .name = name_to_actor_it->first,
                .actor = name_to_actor_it->second,
                .policy_flags = policy_header->policy_flags
              };
              loaded_package->overlayable_infos_.emplace_back(std::move(overlayable_info), std::move(ids));
@@ -736,6 +735,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
        const auto entry_end = entry_begin + dtohl(lib_alias->count);
        std::unordered_set<uint32_t> finalized_ids;
        finalized_ids.reserve(entry_end - entry_begin);
        loaded_package->alias_id_map_.reserve(entry_end - entry_begin);
        for (auto entry_iter = entry_begin; entry_iter != entry_end; ++entry_iter) {
          if (!entry_iter) {
            LOG(ERROR) << "NULL ResTable_staged_alias_entry record??";
@@ -749,13 +749,20 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
          }

          auto staged_id = dtohl(entry_iter->stagedResId);
          auto [_, success] = loaded_package->alias_id_map_.emplace(staged_id, finalized_id);
          if (!success) {
          loaded_package->alias_id_map_.emplace_back(staged_id, finalized_id);
        }

        std::sort(loaded_package->alias_id_map_.begin(), loaded_package->alias_id_map_.end(),
            [](auto&& l, auto&& r) { return l.first < r.first; });
        const auto duplicate_it =
            std::adjacent_find(loaded_package->alias_id_map_.begin(),
                               loaded_package->alias_id_map_.end(),
                               [](auto&& l, auto&& r) { return l.first == r.first; });
          if (duplicate_it != loaded_package->alias_id_map_.end()) {
            LOG(ERROR) << StringPrintf("Repeated staged resource id '%08x' in staged aliases.",
                                       staged_id);
                                       duplicate_it->first);
            return {};
          }
        }
      } break;

      default:
Loading