odrefresh: add test for samegrade ART APEX install

Adds a test that a samegrade ART APEX installation triggers
recompilation of AOT artifacts.

The test exposed situation where the first log entry is incorrectly
logged as zero which is also fixed here.

Bug: 192647837
Test: atest odsign_e2e_tests
Test: atest art_odrefresh_tests
Change-Id: Iefb0fbbca119ed3e47bc17caa2ef8467b241b26c
diff --git a/odrefresh/odrefresh.cc b/odrefresh/odrefresh.cc
index 7ecbe06..6f8fbb8 100644
--- a/odrefresh/odrefresh.cc
+++ b/odrefresh/odrefresh.cc
@@ -501,6 +501,21 @@
       return cleanup_return(ExitCode::kCompilationRequired);
     }
 
+    // Generate current module info for the current ART APEX.
+    const auto current_info = GenerateArtModuleInfo();
+    if (!current_info.has_value()) {
+      // This should never happen, further up-to-date checks are not possible if it does.
+      LOG(ERROR) << "Failed to generate cache provenance.";
+      metrics.SetTrigger(OdrMetrics::Trigger::kUnknown);
+      return cleanup_return(ExitCode::kCompilationRequired);
+    }
+
+    // Record ART APEX version for metrics reporting.
+    metrics.SetArtApexVersion(current_info->getVersionCode());
+
+    // Record ART APEX last update milliseconds (used in compilation log).
+    metrics.SetArtApexLastUpdateMillis(current_info->getLastUpdateMillis());
+
     if (apex_info->getIsFactory()) {
       // Remove any artifacts on /data as they are not necessary and no compilation is necessary.
       LOG(INFO) << "Factory APEX mounted.";
@@ -524,21 +539,6 @@
       return cleanup_return(ExitCode::kCompilationRequired);
     }
 
-    // Generate current module info for the current ART APEX.
-    const auto current_info = GenerateArtModuleInfo();
-    if (!current_info.has_value()) {
-      // This should never happen, further up-to-date checks are not possible if it does.
-      LOG(ERROR) << "Failed to generate cache provenance.";
-      metrics.SetTrigger(OdrMetrics::Trigger::kUnknown);
-      return cleanup_return(ExitCode::kCompilationRequired);
-    }
-
-    // Record ART APEX version for metrics reporting.
-    metrics.SetArtApexVersion(current_info->getVersionCode());
-
-    // Record ART APEX last update milliseconds (used in compilation log).
-    metrics.SetArtApexLastUpdateMillis(current_info->getLastUpdateMillis());
-
     // Check whether the current cache ART module info differs from the current ART module info.
     // Always check APEX version.
     const auto cached_info = cache_info->getFirstArtModuleInfo();
diff --git a/test/odsign/test-src/com/android/tests/odsign/OnDeviceSigningHostTest.java b/test/odsign/test-src/com/android/tests/odsign/OnDeviceSigningHostTest.java
index e44bc80..5245698 100644
--- a/test/odsign/test-src/com/android/tests/odsign/OnDeviceSigningHostTest.java
+++ b/test/odsign/test-src/com/android/tests/odsign/OnDeviceSigningHostTest.java
@@ -228,6 +228,62 @@
         verifySystemServerLoadedArtifacts();
     }
 
+    @Test
+    public void verifyGeneratedArtifactsLoadedForSamegradeUpdate() throws Exception {
+        // Install the same APEX effecting a samegrade update. The setUp method has installed it
+        // before us.
+        mInstallUtils.installApexes(APEX_FILENAME);
+        reboot();
+
+        final boolean adbEnabled = getDevice().enableAdbRoot();
+        assertTrue("ADB root failed and required to get odrefresh compilation log", adbEnabled);
+
+        // Check that odrefresh logged a compilation attempt due to samegrade ART APEX install.
+        String[] logLines = getDevice().pullFileContents(ODREFRESH_COMPILATION_LOG).split("\n");
+        assertTrue(
+                "Expected 3 lines in " + ODREFRESH_COMPILATION_LOG + ", found " + logLines.length,
+                logLines.length == 3);
+
+        // Check that the compilation log entries are reasonable, ie times move forward.
+        // The first line of the log is the log format version number.
+        String[] firstUpdateEntry = logLines[1].split(" ");
+        String[] secondUpdateEntry = logLines[2].split(" ");
+        final int LOG_ENTRY_FIELDS = 5;
+        assertTrue(
+                "Unexpected number of fields: " + firstUpdateEntry.length + " != " +
+                LOG_ENTRY_FIELDS,
+                firstUpdateEntry.length == LOG_ENTRY_FIELDS);
+        assertTrue(firstUpdateEntry.length == secondUpdateEntry.length);
+
+        final int LAST_UPDATE_MILLIS_INDEX = 1;
+        final int COMPILATION_TIME_INDEX = 3;
+        for (int i = 0; i < firstUpdateEntry.length; ++i) {
+            final long firstField = Long.parseLong(firstUpdateEntry[i]);
+            final long secondField = Long.parseLong(secondUpdateEntry[i]);
+            if (i == LAST_UPDATE_MILLIS_INDEX) {
+                // The second APEX lastUpdateMillis should be after the first.
+                assertTrue(
+                        "Last update time same or wrong relation" +
+                        firstField + " >= " + secondField,
+                        firstField < secondField);
+            } else if (i == COMPILATION_TIME_INDEX) {
+                // Second compilation time should be after the first compilation time.
+                assertTrue(
+                        "Compilation time same or wrong relation" +
+                        firstField + " >= " + secondField,
+                        firstField < secondField);
+            } else {
+                // The remaining fields should be the same, ie trigger for compilation, status, etc
+                assertTrue(
+                        "Compilation entries differ for position " + i + ": " +
+                        firstField + " != " + secondField,
+                        firstField == secondField);
+            }
+        }
+
+        verifyGeneratedArtifactsLoaded();
+    }
+
     private boolean haveCompilationLog() throws Exception {
         CommandResult result =
                 getDevice().executeShellV2Command("stat " + ODREFRESH_COMPILATION_LOG);