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

Commit 70ded194 authored by Yurii Zubrytskyi's avatar Yurii Zubrytskyi
Browse files

[idmap] Cache target apks as they are often reused

idmap2d is being often called for the same targets, e.g. system
apps. Caching those apks makes idmap verification and creation
much faster e.g. for user switching

Test: build + boot + UTs
Bug: 271904589
Change-Id: Ib6f7af385c2389b50d5c74aa08b4bab290580809
parent f834821e
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -28,11 +28,14 @@ cc_defaults {
    tidy_checks: [
        "modernize-*",
        "-modernize-avoid-c-arrays",
        "-modernize-use-nodiscard",
        "-modernize-use-trailing-return-type",
        "android-*",
        "misc-*",
        "-misc-const-correctness",
        "readability-*",
        "-readability-identifier-length",
        "-readability-implicit-bool-conversion",
    ],
    tidy_checks_as_errors: [
        "modernize-*",
@@ -56,6 +59,7 @@ cc_defaults {
        "-readability-const-return-type",
        "-readability-convert-member-functions-to-static",
        "-readability-duplicate-include",
        "-readability-implicit-bool-conversion",
        "-readability-else-after-return",
        "-readability-named-parameter",
        "-readability-redundant-access-specifiers",
+34 −10
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask

namespace {

constexpr const char* kFrameworkPath = "/system/framework/framework-res.apk";
constexpr std::string_view kFrameworkPath = "/system/framework/framework-res.apk";

Status ok() {
  return Status::ok();
@@ -207,25 +207,49 @@ Status Idmap2Service::createIdmap(const std::string& target_path, const std::str

idmap2::Result<Idmap2Service::TargetResourceContainerPtr> Idmap2Service::GetTargetContainer(
    const std::string& target_path) {
  if (target_path == kFrameworkPath) {
    if (framework_apk_cache_ == nullptr) {
      // Initialize the framework APK cache.
      auto target = TargetResourceContainer::FromPath(target_path);
      if (!target) {
        return target.GetError();
  const bool is_framework = target_path == kFrameworkPath;
  bool use_cache;
  struct stat st = {};
  if (is_framework || !::stat(target_path.c_str(), &st)) {
    use_cache = true;
  } else {
    LOG(WARNING) << "failed to stat target path '" << target_path << "' for the cache";
    use_cache = false;
  }
      framework_apk_cache_ = std::move(*target);

  if (use_cache) {
    std::lock_guard lock(container_cache_mutex_);
    if (auto cache_it = container_cache_.find(target_path); cache_it != container_cache_.end()) {
      const auto& item = cache_it->second;
      if (is_framework ||
        (item.dev == st.st_dev && item.inode == st.st_ino && item.size == st.st_size
          && item.mtime.tv_sec == st.st_mtim.tv_sec && item.mtime.tv_nsec == st.st_mtim.tv_nsec)) {
        return {item.apk.get()};
      }
      container_cache_.erase(cache_it);
    }
    return {framework_apk_cache_.get()};
  }

  auto target = TargetResourceContainer::FromPath(target_path);
  if (!target) {
    return target.GetError();
  }
  if (!use_cache) {
    return {std::move(*target)};
  }

  const auto res = target->get();
  std::lock_guard lock(container_cache_mutex_);
  container_cache_.emplace(target_path, CachedContainer {
    .dev = dev_t(st.st_dev),
    .inode = ino_t(st.st_ino),
    .size = st.st_size,
    .mtime = st.st_mtim,
    .apk = std::move(*target)
  });
  return {res};
}

Status Idmap2Service::createFabricatedOverlay(
    const os::FabricatedOverlayInternal& overlay,
    std::optional<os::FabricatedOverlayInfo>* _aidl_return) {
+14 −1
Original line number Diff line number Diff line
@@ -75,7 +75,20 @@ class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 {
 private:
  // idmap2d is killed after a period of inactivity, so any information stored on this class should
  // be able to be recalculated if idmap2 dies and restarts.
  std::unique_ptr<idmap2::TargetResourceContainer> framework_apk_cache_;

  // A cache item for the resource containers (apks or frros), with all information needed to
  // detect if it has changed since it was parsed:
  //  - (dev, inode) pair uniquely identifies a file on a particular device partition (see stat(2)).
  //  - (mtime, size) ensure the file data hasn't changed inside that file.
  struct CachedContainer {
    dev_t dev;
    ino_t inode;
    int64_t size;
    struct timespec mtime;
    std::unique_ptr<idmap2::TargetResourceContainer> apk;
  };
  std::unordered_map<std::string, CachedContainer> container_cache_;
  std::mutex container_cache_mutex_;

  int32_t frro_iter_id_ = 0;
  std::optional<std::filesystem::directory_iterator> frro_iter_;