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

Commit 1ebcbc67 authored by Yurii Zubrytskyi's avatar Yurii Zubrytskyi
Browse files

[res] Optimize Idmap verification - use mtime as crc

Idmap.verifyIdmap() is called for every apk-rro combination
on boot, and is one of the slowest operations in the service.

It used to verify that the idmap version, the target/overlay
paths, and their content are unchanged, and used the whole
file's resources CRC for that (resources.arsc + the manifest).

The calculation requres opening and parsing both apks as zip
files, then reading the resources from disk to get the CRC.
Later, if it's determined to be out of date, the next "create"
call does the same work again.

This CL changes the crc field in idmap to store the file's
stat.st_mtime value, which is a good indicator if the file has
changed since the idmap creation. Given that we also check the
path, the old code was already invalidating idmaps on apk moves
(like staging -> final directory during installation), so this
won't add any extra invalidations because of that. It still
would invalidate the idmap when an apk changes but its resources
don't, but that is such a rare case (updating the whole
partition so the paths are the same, and only changing the non-
resource parts of the apks), that the overall speedup of the
verification totally outweighs it.

OMS total startup time on P11 reduces 110ms -> 60ms, at a
cost of one-time idmap regeneration on the first boot

Test: build + boot + atest idmap2_tests
Bug: b/422474410
Flag: android.content.res.idmap_crc_is_mtime
Change-Id: Ia35a01f999acf09a668221102dccb455feec3851
parent b9496aa9
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -797,6 +797,17 @@ java_aconfig_library {
    defaults: ["framework-minus-apex-aconfig-java-defaults"],
}

cc_aconfig_library {
    name: "android.content.res.flags-aconfig-cc",
    aconfig_declarations: "android.content.res.flags-aconfig",
}

cc_aconfig_library {
    name: "android.content.res.flags-aconfig-cc-host",
    aconfig_declarations: "android.content.res.flags-aconfig",
    host_supported: true,
}

// Media BetterTogether
aconfig_declarations {
    name: "com.android.media.flags.bettertogether-aconfig",
+26 −1
Original line number Diff line number Diff line
@@ -86,16 +86,20 @@ cc_library {
            static_libs: [
                "libidmap2_policies",
                "libidmap2_protos",
                "libpng",
                "android.content.res.flags-aconfig-cc",
            ],
            shared_libs: [
                "libaconfig_storage_read_api_cc",
                "libandroidfw",
                "libbase",
                "libcutils",
                "liblog",
                "libpng",
                "libprotobuf-cpp-lite",
                "libutils",
                "libz",
                "libziparchive",
                "server_configurable_flags",
            ],
        },
        host: {
@@ -103,16 +107,20 @@ cc_library {
                enabled: false,
            },
            static_libs: [
                "android.content.res.flags-aconfig-cc-host",
                "libaconfig_storage_read_api_cc",
                "libandroidfw",
                "libbase",
                "libcutils",
                "libidmap2_policies",
                "libidmap2_protos",
                "liblog",
                "libpng",
                "libprotobuf-cpp-lite",
                "libutils",
                "libz",
                "libziparchive",
                "server_configurable_flags",
            ],
        },
    },
@@ -193,6 +201,7 @@ cc_test {
    target: {
        android: {
            shared_libs: [
                "libaconfig_storage_read_api_cc",
                "libandroidfw",
                "libbase",
                "libidmap2",
@@ -202,13 +211,17 @@ cc_test {
                "libz",
                "libz",
                "libziparchive",
                "server_configurable_flags",
            ],
            static_libs: [
                "libidmap2_policies",
                "android.content.res.flags-aconfig-cc",
            ],
        },
        host: {
            static_libs: [
                "android.content.res.flags-aconfig-cc-host",
                "libaconfig_storage_read_api_cc",
                "libandroidfw",
                "libbase",
                "libcutils",
@@ -218,6 +231,7 @@ cc_test {
                "libprotobuf-cpp-lite",
                "libutils",
                "libziparchive",
                "server_configurable_flags",
            ],
            shared_libs: [
                "libz",
@@ -258,22 +272,28 @@ cc_binary {
    target: {
        android: {
            shared_libs: [
                "libaconfig_storage_read_api_cc",
                "libandroidfw",
                "libbase",
                "libcutils",
                "libidmap2",
                "liblog",
                "libpng",
                "libprotobuf-cpp-lite",
                "libutils",
                "libz",
                "libziparchive",
                "server_configurable_flags",
            ],
            static_libs: [
                "android.content.res.flags-aconfig-cc",
                "libidmap2_policies",
            ],
        },
        host: {
            static_libs: [
                "android.content.res.flags-aconfig-cc-host",
                "libaconfig_storage_read_api_cc",
                "libandroidfw",
                "libbase",
                "libcutils",
@@ -284,6 +304,7 @@ cc_binary {
                "libprotobuf-cpp-lite",
                "libutils",
                "libziparchive",
                "server_configurable_flags",
            ],
            shared_libs: [
                "libz",
@@ -304,16 +325,20 @@ cc_binary {
        "idmap2d/Main.cpp",
    ],
    shared_libs: [
        "libaconfig_storage_read_api_cc",
        "libandroidfw",
        "libbase",
        "libbinder",
        "libcutils",
        "libidmap2",
        "liblog",
        "libprotobuf-cpp-lite",
        "libutils",
        "libziparchive",
        "server_configurable_flags",
    ],
    static_libs: [
        "android.content.res.flags-aconfig-cc",
        "libidmap2_policies",
        "libidmap2_protos",
        "libidmap2daidl",
+23 −14
Original line number Diff line number Diff line
@@ -16,15 +16,20 @@

#include "idmap2/CommandUtils.h"

#include <android_content_res.h>

#include <fstream>
#include <memory>
#include <string>
#include <vector>

#include "androidfw/misc.h"
#include "idmap2/Idmap.h"
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"

using android::getFileModDate;
using android::toTimeT;
using android::idmap2::Error;
using android::idmap2::IdmapHeader;
using android::idmap2::OverlayResourceContainer;
@@ -42,21 +47,25 @@ Result<Unit> Verify(const std::string& idmap_path, const std::string& target_pat
  if (!header) {
    return Error("failed to parse idmap header");
  }

  std::optional<Result<Unit>> header_ok;
  if (android_content_res_idmap_crc_is_mtime()) {
    header_ok = header->IsUpToDate(
        target_path, overlay_path, overlay_name, toTimeT(getFileModDate(target_path.c_str())),
        toTimeT(getFileModDate(overlay_path.c_str())), fulfilled_policies, enforce_overlayable);
  } else {
    auto target = TargetResourceContainer::FromPath(target_path);
    if (!target) {
      return Error("failed to load target '%s'", target_path.c_str());
    }

    auto overlay = OverlayResourceContainer::FromPath(overlay_path);
    if (!overlay) {
      return Error("failed to load overlay '%s'", overlay_path.c_str());
    }

  const auto header_ok = header->IsUpToDate(**target, **overlay, overlay_name, fulfilled_policies,
    header_ok = header->IsUpToDate(**target, **overlay, overlay_name, fulfilled_policies,
                                   enforce_overlayable);
  if (!header_ok) {
    return Error(header_ok.GetError(), "idmap not up to date");
  }
  if (!*header_ok) {
    return Error(header_ok->GetError(), "idmap not up to date");
  }
  return Unit{};
}
+29 −20
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

#include "idmap2d/Idmap2Service.h"

#include <android_content_res.h>
#include <fcntl.h>
#include <sys/stat.h>   // umask
#include <sys/types.h>  // umask

@@ -39,7 +41,6 @@
#include "idmap2/PrettyPrintVisitor.h"
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
#include <fcntl.h>

using android::base::StringPrintf;
using android::binder::Status;
@@ -51,7 +52,9 @@ using android::idmap2::IdmapConstraints;
using android::idmap2::IdmapHeader;
using android::idmap2::OverlayResourceContainer;
using android::idmap2::PrettyPrintVisitor;
using android::idmap2::Result;
using android::idmap2::TargetResourceContainer;
using android::idmap2::Unit;
using android::idmap2::utils::kIdmapCacheDir;
using android::idmap2::utils::kIdmapFilePermissionMask;
using android::idmap2::utils::RandomStringForPath;
@@ -149,31 +152,37 @@ Status Idmap2Service::verifyIdmap(const std::string& target_path, const std::str
    return ok();
  }

  std::optional<Result<Unit>> up_to_date;
  if (android_content_res_idmap_crc_is_mtime()) {
    up_to_date = header->IsUpToDate(
        target_path, overlay_path, overlay_name, toTimeT(getFileModDate(target_path.c_str())),
        toTimeT(getFileModDate(overlay_path.c_str())),
        ConvertAidlArgToPolicyBitmask(fulfilled_policies), enforce_overlayable);
  } else {
    const auto target = GetTargetContainer(target_path);
    if (!target) {
      *_aidl_return = false;
      LOG(WARNING) << "failed to load target '" << target_path << "'";
      return ok();
    }

    const auto overlay = OverlayResourceContainer::FromPath(overlay_path);
    if (!overlay) {
      *_aidl_return = false;
      LOG(WARNING) << "failed to load overlay '" << overlay_path << "'";
      return ok();
    }

  auto up_to_date =
    up_to_date =
        header->IsUpToDate(*GetPointer(*target), **overlay, overlay_name,
                           ConvertAidlArgToPolicyBitmask(fulfilled_policies), enforce_overlayable);
  }

  std::unique_ptr<const IdmapConstraints> newConstraints =
          ConvertAidlConstraintsToIdmapConstraints(constraints);

  *_aidl_return = static_cast<bool>(up_to_date && (*oldConstraints == *newConstraints));
  if (!up_to_date) {
  *_aidl_return = static_cast<bool>(*up_to_date && (*oldConstraints == *newConstraints));
  if (!*up_to_date) {
    LOG(WARNING) << "idmap '" << idmap_path
                 << "' not up to date : " << up_to_date.GetErrorMessage();
                 << "' not up to date : " << up_to_date->GetErrorMessage();
  }
  return ok();
}
+7 −0
Original line number Diff line number Diff line
@@ -113,6 +113,13 @@ class IdmapHeader {
    return version_;
  }

  // NOTE: The CRC fields used to be literal crc32, but now are just a way to identify if the
  // corresponding file has changed, so it's a stat.st_mtime now.
  // This means we may get false positives when the file changes, but the resources inside stay
  // the same. But it is so much faster to get and verify (a single stat() call instead of fully
  // parsing a zip archive and calculating a crc of the resources inside), that it is worth it:
  // false positives just make us re-create the idmaps occasionally and cause no correctness bugs.

  inline uint32_t GetTargetCrc() const {
    return target_crc_;
  }
Loading