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(),