Refresh existing artifacts in the compilation phase.

This allows odsign to call `odrefresh --check` without refreshing the
existing artifacts.

Bug: 206090748
Test: atest odsign_e2e_tests
Change-Id: I2207330f4eaeed917095e8883816f4c96fdeb4f9
diff --git a/odrefresh/odrefresh.cc b/odrefresh/odrefresh.cc
index b2cab52..822e4f5 100644
--- a/odrefresh/odrefresh.cc
+++ b/odrefresh/odrefresh.cc
@@ -1030,10 +1030,10 @@
   return true;
 }
 
-Result<void> OnDeviceRefresh::RefreshExistingArtifactsAndCleanup(
-    const std::vector<std::string>& artifacts) const {
+Result<void> OnDeviceRefresh::CleanupArtifactDirectory(
+    const std::vector<std::string>& artifacts_to_keep) const {
   const std::string& artifact_dir = config_.GetArtifactDirectory();
-  std::unordered_set<std::string> artifact_set{artifacts.begin(), artifacts.end()};
+  std::unordered_set<std::string> artifact_set{artifacts_to_keep.begin(), artifacts_to_keep.end()};
 
   // When anything unexpected happens, remove all artifacts.
   auto remove_artifact_dir = android::base::make_scope_guard([&]() {
@@ -1049,7 +1049,6 @@
     // undefined behavior;
     entries.push_back(entry);
   }
-
   if (ec) {
     return Errorf("Failed to iterate over entries in the artifact directory: {}", ec.message());
   }
@@ -1057,25 +1056,7 @@
   for (const std::filesystem::directory_entry& entry : entries) {
     std::string path = entry.path().string();
     if (entry.is_regular_file()) {
-      if (ContainsElement(artifact_set, path)) {
-        if (!config_.GetRefresh()) {
-          continue;
-        }
-        LOG(INFO) << "Refreshing " << path;
-        std::string content;
-        if (!android::base::ReadFileToString(path, &content)) {
-          return Errorf("Failed to read file {}", QuotePath(path));
-        }
-        if (unlink(path.c_str()) != 0) {
-          return ErrnoErrorf("Failed to remove file {}", QuotePath(path));
-        }
-        if (!android::base::WriteStringToFile(content, path)) {
-          return Errorf("Failed to write file {}", QuotePath(path));
-        }
-        if (chmod(path.c_str(), kFileMode) != 0) {
-          return ErrnoErrorf("Failed to chmod file {}", QuotePath(path));
-        }
-      } else {
+      if (!ContainsElement(artifact_set, path)) {
         LOG(INFO) << "Removing " << path;
         if (unlink(path.c_str()) != 0) {
           return ErrnoErrorf("Failed to remove file {}", QuotePath(path));
@@ -1094,6 +1075,48 @@
   return {};
 }
 
+Result<void> OnDeviceRefresh::RefreshExistingArtifacts() const {
+  const std::string& artifact_dir = config_.GetArtifactDirectory();
+  if (!OS::DirectoryExists(artifact_dir.c_str())) {
+    return {};
+  }
+
+  std::vector<std::filesystem::directory_entry> entries;
+  std::error_code ec;
+  for (const auto& entry : std::filesystem::recursive_directory_iterator(artifact_dir, ec)) {
+    // Save the entries and use them later because modifications during the iteration will result in
+    // undefined behavior;
+    entries.push_back(entry);
+  }
+  if (ec) {
+    return Errorf("Failed to iterate over entries in the artifact directory: {}", ec.message());
+  }
+
+  for (const std::filesystem::directory_entry& entry : entries) {
+    std::string path = entry.path().string();
+    if (entry.is_regular_file()) {
+      // Unexpected files are already removed by `CleanupArtifactDirectory`. We can safely assume
+      // that all the remaining files are good.
+      LOG(INFO) << "Refreshing " << path;
+      std::string content;
+      if (!android::base::ReadFileToString(path, &content)) {
+        return Errorf("Failed to read file {}", QuotePath(path));
+      }
+      if (unlink(path.c_str()) != 0) {
+        return ErrnoErrorf("Failed to remove file {}", QuotePath(path));
+      }
+      if (!android::base::WriteStringToFile(content, path)) {
+        return Errorf("Failed to write file {}", QuotePath(path));
+      }
+      if (chmod(path.c_str(), kFileMode) != 0) {
+        return ErrnoErrorf("Failed to chmod file {}", QuotePath(path));
+      }
+    }
+  }
+
+  return {};
+}
+
 WARN_UNUSED ExitCode
 OnDeviceRefresh::CheckArtifactsAreUpToDate(OdrMetrics& metrics,
                                            /*out*/ CompilationOptions* compilation_options) const {
@@ -1171,7 +1194,7 @@
     if (!config_.GetPartialCompilation()) {
       return cleanup_and_compile_all();
     }
-    Result<void> result = RefreshExistingArtifactsAndCleanup(checked_artifacts);
+    Result<void> result = CleanupArtifactDirectory(checked_artifacts);
     if (!result.ok()) {
       LOG(ERROR) << result.error();
       return ExitCode::kCleanupFailed;
@@ -1454,6 +1477,14 @@
   const char* staging_dir = nullptr;
   metrics.SetStage(OdrMetrics::Stage::kPreparation);
 
+  if (config_.GetRefresh()) {
+    Result<void> result = RefreshExistingArtifacts();
+    if (!result.ok()) {
+      LOG(ERROR) << "Failed to refresh existing artifacts: " << result.error();
+      return ExitCode::kCleanupFailed;
+    }
+  }
+
   if (!config_.GetStagingDir().empty()) {
     staging_dir = config_.GetStagingDir().c_str();
   } else {
diff --git a/odrefresh/odrefresh.h b/odrefresh/odrefresh.h
index 7969aa4..81704c2 100644
--- a/odrefresh/odrefresh.h
+++ b/odrefresh/odrefresh.h
@@ -101,11 +101,14 @@
 
   std::string GetSystemServerImagePath(bool on_system, const std::string& jar_path) const;
 
-  // Loads artifacts to memory and writes them back. Also cleans up other files in the artifact
-  // directory. This essentially removes the existing artifacts from fs-verity so that odsign will
-  // not encounter "file exists" error when it adds the existing artifacts to fs-verity.
-  android::base::Result<void> RefreshExistingArtifactsAndCleanup(
-      const std::vector<std::string>& artifacts) const;
+  // Removes files that are not in the list.
+  android::base::Result<void> CleanupArtifactDirectory(
+      const std::vector<std::string>& artifacts_to_keep) const;
+
+  // Loads artifacts to memory and writes them back. This essentially removes the existing artifacts
+  // from fs-verity so that odsign will not encounter "file exists" error when it adds the existing
+  // artifacts to fs-verity.
+  android::base::Result<void> RefreshExistingArtifacts() const;
 
   // Checks whether all boot extension artifacts are present. Returns true if all are present, false
   // otherwise.
diff --git a/odrefresh/odrefresh_main.cc b/odrefresh/odrefresh_main.cc
index 315e898..e05e08d 100644
--- a/odrefresh/odrefresh_main.cc
+++ b/odrefresh/odrefresh_main.cc
@@ -339,8 +339,7 @@
       OdrCompilationLog compilation_log;
       if (!compilation_log.ShouldAttemptCompile(metrics.GetTrigger())) {
         LOG(INFO) << "Compilation skipped because it was attempted recently";
-        // Artifacts refreshed. Return `kCompilationFailed` so that odsign will sign them again.
-        return ExitCode::kCompilationFailed;
+        return ExitCode::kOkay;
       }
       ExitCode compile_result = odr.Compile(metrics, compilation_options);
       compilation_log.Log(metrics.GetArtApexVersion(),