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
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index 75fc7f7..a93184f 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -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 @@
 
 namespace {
 
+constexpr const char* kFrameworkPath = "/system/framework/framework-res.apk";
+
 Status ok() {
   return Status::ok();
 }
@@ -109,8 +113,32 @@
     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();
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index 0ed55a1..55fb5ad 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -46,6 +46,10 @@
                              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
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index 2e4836e..77a7b30 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -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 @@
 // 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 @@
   // 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;
 
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 7f2cd959..706b842 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -100,7 +100,9 @@
   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 @@
              : 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,6 +130,20 @@
 }
 
 Result<Unit> IdmapHeader::IsUpToDate() const {
+  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 = GetPackageCrc(*target_zip);
+  if (!target_crc) {
+    return Error("failed to get 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);
   }
@@ -138,19 +152,9 @@
     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);
-  if (!target_crc) {
-    return Error("failed to get target crc");
-  }
-
-  if (target_crc_ != *target_crc) {
+  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 @@
     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 @@
   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");
   }