Delete staged SEPolicy files if the session is aborted

Bug: 218672709
Test: manual tests and ApexdMountTest#AbortSepolicyApexInstall

Change-Id: I09116b95866b93ddf65a2713b1961477b4529312
diff --git a/apexd/apexd.cpp b/apexd/apexd.cpp
index 52d31da..055c641 100644
--- a/apexd/apexd.cpp
+++ b/apexd/apexd.cpp
@@ -905,6 +905,8 @@
   return {};
 }
 
+static constexpr auto kSepolicyApexName = "com.android.sepolicy.apex";
+
 // A version of apex verification that happens on SubmitStagedSession.
 // This function contains checks that might be expensive to perform, e.g. temp
 // mounting a package and reading entire dm-verity device, and shouldn't be run
@@ -916,7 +918,7 @@
   }
 
   const auto validate_fn = [&apex_file](const std::string& mount_point) {
-    if (apex_file.GetManifest().name() == "com.android.sepolicy.apex") {
+    if (apex_file.GetManifest().name() == kSepolicyApexName) {
       return CopySepolicyToMetadata(mount_point);
     }
     return Result<void>{};
@@ -1675,17 +1677,40 @@
   return ErrnoError() << "Cannot find matching package for: " << packageName;
 }
 
+Result<void> DeleteStagedSepolicy() {
+  const auto staged_dir =
+      std::string(gConfig->metadata_sepolicy_staged_dir) + "/";
+  LOG(DEBUG) << "Deleting " << staged_dir;
+  std::error_code ec;
+  auto removed = std::filesystem::remove_all(staged_dir, ec);
+  if (removed == 0) {
+    LOG(INFO) << staged_dir << " already deleted.";
+  } else if (ec) {
+    return Error() << "Failed to clear " << staged_dir << ": " << ec.message();
+  }
+  return {};
+}
+
 /**
  * Abort individual staged session.
  *
  * Returns without error only if session was successfully aborted.
  **/
 Result<void> AbortStagedSession(int session_id) {
-  // TODO(b/218672709): Delete staged SEPolicy file if the session is aborted.
   auto session = ApexSession::GetSession(session_id);
   if (!session.ok()) {
     return Error() << "No session found with id " << session_id;
   }
+
+  const auto& apex_names = session->GetApexNames();
+  if (std::find(std::begin(apex_names), std::end(apex_names),
+                kSepolicyApexName) != std::end(apex_names)) {
+    const auto result = DeleteStagedSepolicy();
+    if (!result.ok()) {
+      return result.error();
+    }
+  }
+
   switch (session->GetState()) {
     case SessionState::VERIFIED:
       [[clang::fallthrough]];
@@ -2196,7 +2221,6 @@
         LOG(ERROR) << "Cannot open apex file during staging: " << apex;
         continue;
       }
-      session.AddApexName(apex_file->GetManifest().name());
     }
 
     const Result<void> result = StagePackages(apexes);
@@ -3100,6 +3124,9 @@
   session->SetHasRollbackEnabled(has_rollback_enabled);
   session->SetIsRollback(is_rollback);
   session->SetRollbackId(rollback_id);
+  for (const auto& apex_file : ret) {
+    session->AddApexName(apex_file.GetManifest().name());
+  }
   Result<void> commit_status =
       (*session).UpdateStateAndCommit(SessionState::VERIFIED);
   if (!commit_status.ok()) {
diff --git a/apexd/apexd_test.cpp b/apexd/apexd_test.cpp
index e2fe9e7..327ceaf 100644
--- a/apexd/apexd_test.cpp
+++ b/apexd/apexd_test.cpp
@@ -139,7 +139,8 @@
     ota_reserved_dir_ = StringPrintf("%s/ota-reserved", td_.path);
     hash_tree_dir_ = StringPrintf("%s/apex-hash-tree", td_.path);
     staged_session_dir_ = StringPrintf("%s/staged-session-dir", td_.path);
-    metadata_sepolicy_dir_ = StringPrintf("%s/metadata-sepolicy-dir", td_.path);
+    metadata_sepolicy_staged_dir_ =
+        StringPrintf("%s/metadata-sepolicy-staged-dir", td_.path);
 
     vm_payload_disk_ = StringPrintf("%s/vm-payload", td_.path);
 
@@ -150,7 +151,7 @@
                ota_reserved_dir_.c_str(),
                hash_tree_dir_.c_str(),
                staged_session_dir_.c_str(),
-               metadata_sepolicy_dir_.c_str(),
+               metadata_sepolicy_staged_dir_.c_str(),
                kTestVmPayloadMetadataPartitionProp,
                kTestActiveApexSelinuxCtx};
   }
@@ -164,7 +165,9 @@
     return StringPrintf("%s/session_%d", staged_session_dir_.c_str(),
                         session_id);
   }
-  const std::string& GetMetadataSepolicyDir() { return metadata_sepolicy_dir_; }
+  const std::string& GetMetadataSepolicyStagedDir() {
+    return metadata_sepolicy_staged_dir_;
+  }
 
   std::string GetRootDigest(const ApexFile& apex) {
     if (apex.IsCompressed()) {
@@ -247,7 +250,7 @@
     ASSERT_EQ(mkdir(ota_reserved_dir_.c_str(), 0755), 0);
     ASSERT_EQ(mkdir(hash_tree_dir_.c_str(), 0755), 0);
     ASSERT_EQ(mkdir(staged_session_dir_.c_str(), 0755), 0);
-    ASSERT_EQ(mkdir(metadata_sepolicy_dir_.c_str(), 0755), 0);
+    ASSERT_EQ(mkdir(metadata_sepolicy_staged_dir_.c_str(), 0755), 0);
 
     DeleteDirContent(ApexSession::GetSessionsDir());
   }
@@ -287,7 +290,7 @@
   std::string vm_payload_disk_;
   std::string vm_payload_metadata_path_;
   std::string staged_session_dir_;
-  std::string metadata_sepolicy_dir_;
+  std::string metadata_sepolicy_staged_dir_;
   ApexdConfig config_;
   std::vector<loop::LoopbackDeviceUniqueFd> loop_devices_;  // to be cleaned up
 };
@@ -4295,11 +4298,27 @@
                           /* is_rollback= */ false, /* rollback_id= */ -1),
       Ok());
 
-  auto metadata_dir = GetMetadataSepolicyDir();
-  ASSERT_THAT(PathExists(metadata_dir + "/SEPolicy.zip"), HasValue(true));
-  ASSERT_THAT(PathExists(metadata_dir + "/SEPolicy.zip.sig"), HasValue(true));
-  ASSERT_THAT(PathExists(metadata_dir + "/SEPolicy.zip.fsv_sig"),
-              HasValue(true));
+  auto staged_dir = GetMetadataSepolicyStagedDir();
+  ASSERT_THAT(PathExists(staged_dir + "/SEPolicy.zip"), HasValue(true));
+  ASSERT_THAT(PathExists(staged_dir + "/SEPolicy.zip.sig"), HasValue(true));
+  ASSERT_THAT(PathExists(staged_dir + "/SEPolicy.zip.fsv_sig"), HasValue(true));
+}
+
+TEST_F(ApexdMountTest, AbortSepolicyApexInstall) {
+  std::string file_path = AddPreInstalledApex("com.android.sepolicy.apex");
+  ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
+  ASSERT_THAT(CreateStagedSession("com.android.sepolicy.apex", 666), Ok());
+  ASSERT_THAT(
+      SubmitStagedSession(666, {}, /* has_rollback_enabled= */ false,
+                          /* is_rollback= */ false, /* rollback_id= */ -1),
+      Ok());
+
+  auto staged_dir = GetMetadataSepolicyStagedDir();
+  ASSERT_THAT(PathExists(staged_dir), HasValue(true));
+  ASSERT_FALSE(IsEmptyDirectory(staged_dir));
+
+  ASSERT_THAT(AbortStagedSession(666), Ok());
+  ASSERT_THAT(PathExists(staged_dir), HasValue(false));
 }
 
 class ApexActivationFailureTests : public ApexdMountTest {};