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

Commit 7d53f190 authored by Ryan Mitchell's avatar Ryan Mitchell
Browse files

Reduce OMS start time

This change attempts to reduce the amount of time initializing the
OMS. The change:
1) Reduces the amount of time between subsequent attempts to connect
   to the idmap2d service when it is not alive.
2) Caches package infos retrieved from getOverlayPackages
3) Caches the crc of the android package to preventing having to
   retrieve it for every overlay package targeting the framework

This chance reduced OMS start up time from ~500ms to ~100ms on a
Pixel 3. If the idmap2d service is running when system sever starts
then start up time will be around ~70ms.

Bug: 151481016
Test: adb shell stop && adb shell start && [capture trace]

Change-Id: I6137c385baf099413b62e98557419fffb9fd2d93
parent ac774e33
Loading
Loading
Loading
Loading
+30 −2
Original line number Diff line number Diff line
@@ -34,11 +34,13 @@
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
#include "idmap2/SysTrace.h"
#include "idmap2/ZipFile.h"
#include "utils/String8.h"

using android::IPCThreadState;
using android::binder::Status;
using android::idmap2::BinaryStreamVisitor;
using android::idmap2::GetPackageCrc;
using android::idmap2::Idmap;
using android::idmap2::IdmapHeader;
using android::idmap2::utils::kIdmapCacheDir;
@@ -49,6 +51,8 @@ using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask

namespace {

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

Status ok() {
  return Status::ok();
}
@@ -109,8 +113,32 @@ Status Idmap2Service::verifyIdmap(const std::string& target_apk_path,
    return error("failed to parse idmap header");
  }

  *_aidl_return =
      strcmp(header->GetTargetPath().data(), target_apk_path.data()) == 0 && header->IsUpToDate();
  if (strcmp(header->GetTargetPath().data(), target_apk_path.data()) != 0) {
    *_aidl_return = false;
    return ok();
  }

  if (target_apk_path != kFrameworkPath) {
    *_aidl_return = (bool) header->IsUpToDate();
  } else {
    if (!android_crc_) {
      // Loading the framework zip can take several milliseconds. Cache the crc of the framework
      // resource APK to reduce repeated work during boot.
      const auto target_zip = idmap2::ZipFile::Open(target_apk_path);
      if (!target_zip) {
        return error(base::StringPrintf("failed to open target %s", target_apk_path.c_str()));
      }

      const auto target_crc = GetPackageCrc(*target_zip);
      if (!target_crc) {
        return error(target_crc.GetErrorMessage());
      }

      android_crc_ = *target_crc;
    }

    *_aidl_return = (bool) header->IsUpToDate(android_crc_.value());
  }

  // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed
  return ok();
+4 −0
Original line number Diff line number Diff line
@@ -46,6 +46,10 @@ class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 {
                             const std::string& overlay_apk_path, int32_t fulfilled_policies,
                             bool enforce_overlayable, int32_t user_id,
                             aidl::nullable<std::string>* _aidl_return) override;

 private:
  // Cache the crc of the android framework package since the crc cannot change without a reboot.
  std::optional<uint32_t> android_crc_;
};

}  // namespace android::os
+5 −0
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
#include "idmap2/ResourceMapping.h"
#include "idmap2/ZipFile.h"

namespace android::idmap2 {

@@ -93,6 +94,9 @@ static constexpr const uint32_t kIdmapCurrentVersion = android::kIdmapCurrentVer
// terminating null)
static constexpr const size_t kIdmapStringLength = 256;

// Retrieves a crc generated using all of the files within the zip that can affect idmap generation.
Result<uint32_t> GetPackageCrc(const ZipFile& zip_info);

class IdmapHeader {
 public:
  static std::unique_ptr<const IdmapHeader> FromBinaryStream(std::istream& stream);
@@ -129,6 +133,7 @@ class IdmapHeader {
  // field *must* be incremented. Because of this, we know that if the idmap
  // header is up-to-date the entire file is up-to-date.
  Result<Unit> IsUpToDate() const;
  Result<Unit> IsUpToDate(uint32_t target_crc_) const;

  void accept(Visitor* v) const;

+21 −17
Original line number Diff line number Diff line
@@ -100,7 +100,9 @@ Result<std::string> ReadString(std::istream& stream) {
  return buf;
}

Result<uint32_t> GetCrc(const ZipFile& zip) {
}  // namespace

Result<uint32_t> GetPackageCrc(const ZipFile& zip) {
  const Result<uint32_t> a = zip.Crc("resources.arsc");
  const Result<uint32_t> b = zip.Crc("AndroidManifest.xml");
  return a && b
@@ -108,8 +110,6 @@ Result<uint32_t> GetCrc(const ZipFile& zip) {
             : Error("failed to get CRC for \"%s\"", a ? "AndroidManifest.xml" : "resources.arsc");
}

}  // namespace

std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& stream) {
  std::unique_ptr<IdmapHeader> idmap_header(new IdmapHeader());

@@ -130,27 +130,31 @@ std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& s
}

Result<Unit> IdmapHeader::IsUpToDate() const {
  if (magic_ != kIdmapMagic) {
    return Error("bad magic: actual 0x%08x, expected 0x%08x", magic_, kIdmapMagic);
  }

  if (version_ != kIdmapCurrentVersion) {
    return Error("bad version: actual 0x%08x, expected 0x%08x", version_, kIdmapCurrentVersion);
  }

  const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path_);
  if (!target_zip) {
    return Error("failed to open target %s", GetTargetPath().to_string().c_str());
  }

  Result<uint32_t> target_crc = GetCrc(*target_zip);
  Result<uint32_t> target_crc = GetPackageCrc(*target_zip);
  if (!target_crc) {
    return Error("failed to get target crc");
  }

  if (target_crc_ != *target_crc) {
  return IsUpToDate(*target_crc);
}

Result<Unit> IdmapHeader::IsUpToDate(uint32_t target_crc) const {
  if (magic_ != kIdmapMagic) {
    return Error("bad magic: actual 0x%08x, expected 0x%08x", magic_, kIdmapMagic);
  }

  if (version_ != kIdmapCurrentVersion) {
    return Error("bad version: actual 0x%08x, expected 0x%08x", version_, kIdmapCurrentVersion);
  }

  if (target_crc_ != target_crc) {
    return Error("bad target crc: idmap version 0x%08x, file system version 0x%08x", target_crc_,
                 *target_crc);
                 target_crc);
  }

  const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_path_);
@@ -158,7 +162,7 @@ Result<Unit> IdmapHeader::IsUpToDate() const {
    return Error("failed to open overlay %s", GetOverlayPath().to_string().c_str());
  }

  Result<uint32_t> overlay_crc = GetCrc(*overlay_zip);
  Result<uint32_t> overlay_crc = GetPackageCrc(*overlay_zip);
  if (!overlay_crc) {
    return Error("failed to get overlay crc");
  }
@@ -304,13 +308,13 @@ Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const ApkAssets& targe
  header->magic_ = kIdmapMagic;
  header->version_ = kIdmapCurrentVersion;

  Result<uint32_t> crc = GetCrc(*target_zip);
  Result<uint32_t> crc = GetPackageCrc(*target_zip);
  if (!crc) {
    return Error(crc.GetError(), "failed to get zip CRC for target");
  }
  header->target_crc_ = *crc;

  crc = GetCrc(*overlay_zip);
  crc = GetPackageCrc(*overlay_zip);
  if (!crc) {
    return Error(crc.GetError(), "failed to get zip CRC for overlay");
  }
+1 −1
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ class IdmapDaemon {

    // The amount of time in milliseconds to wait when attempting to connect to idmap service.
    private static final int SERVICE_CONNECT_TIMEOUT_MS = 5000;
    private static final int SERVICE_CONNECT_INTERVAL_SLEEP_MS = 200;
    private static final int SERVICE_CONNECT_INTERVAL_SLEEP_MS = 5;

    private static final String IDMAP_DAEMON = "idmap2d";

Loading