Ignore the failure after executing a step nonundoable 34/315334/3
authorIlho Kim <ilho159.kim@samsung.com>
Fri, 24 Nov 2023 03:51:03 +0000 (12:51 +0900)
committerIlho Kim <ilho159.kim@samsung.com>
Mon, 2 Dec 2024 03:54:35 +0000 (12:54 +0900)
Change-Id: Ia563c64918c8e3c9eacbea6a55055c6cd256902f
Signed-off-by: Ilho Kim <ilho159.kim@samsung.com>
14 files changed:
src/common/installer/app_installer.cc
src/common/installer/app_installer.h
src/common/installer_context.cc
src/common/installer_context.h
src/common/recovery_file.cc
src/common/recovery_file.h
src/common/step/configuration/step_fail.cc
src/common/step/configuration/step_fail.h
src/common/step/filesystem/step_remove_files.cc
src/common/step/recovery/step_recovery.cc
src/common/utils/file_util.cc
src/common/utils/file_util.h
src/pkg_recovery/pkg_recovery.cc
test/smoke_tests/common/smoke_utils.cc

index 97245f9ddf2d5b2f64e4fa6da80ab2fd0513ff77..c52ec32a90f45e1abceedd6f0272169346172abf 100644 (file)
 #include "common/installer_context.h"
 #include "common/pkgmgr_interface.h"
 #include "common/pkgmgr_signal.h"
+#include "common/recovery_file.h"
 #include "common/step/configuration/step_fail.h"
 #include "common/utils/file_logbackend.h"
+#include "common/utils/file_util.h"
 
 #include "common/step/backup/step_backup_icons.h"
 #include "common/step/backup/step_backup_manifest.h"
@@ -247,11 +249,20 @@ AppInstaller::Result AppInstaller::Process() {
       status_ = SafeExecute(*it_, &Step::process, "process");
 
     if (status_ != Step::Status::OK) {
-      if (status_ != Step::Status::RECOVERY_DONE) {
-        LOG(ERROR) << "Error during processing(" << (*it_)->name() << ")";
-        result_ = Result::ERROR;
+      if (context_->undoable.get()) {
+        if (status_ != Step::Status::RECOVERY_DONE) {
+          LOG(ERROR) << "Error during processing(" << (*it_)->name() << ")";
+          result_ = Result::ERROR;
+        }
+        break;
       }
-      break;
+
+      LOG(WARNING) << "Error during processing(" << (*it_)->name()
+          << ") but the installation can't undo, installation is ongoing";
+      const auto& recovery_file =
+        context_->recovery_info.get().recovery_file;
+      if (recovery_file)
+        recovery_file->set_keep_recovery_file(true);
     }
     if (!context_->pkgid.get().empty())
       history_logger_.LogHistoryStart(context_->pkgid.get(),
@@ -295,6 +306,8 @@ AppInstaller::Result AppInstaller::Undo() {
 }
 
 AppInstaller::Result AppInstaller::Clean() {
+  RemoveUnnecessaryRecoveryFiles();
+
   const auto& recovery_file =
     context_->recovery_info.get().recovery_file;
   if (recovery_file) {
@@ -414,6 +427,8 @@ void AppInstaller::UninstallSteps() {
   AddStep<ci::security::StepUnregisterTrustAnchor>();
   AddStep<ci::security::StepPrivacyPrivilege>(
       ci::security::StepPrivacyPrivilege::ActionType::Uninstall);
+  // After StepRemoveFiles is performed, the installation can't undo
+  // So the installation proceeds as is, ignoring errors in later steps
   AddStep<ci::filesystem::StepRemoveFiles>();
   AddStep<ci::pkgmgr::StepRemovePrivSharedres>();
   AddStep<ci::filesystem::StepRemoveZipImage>();
@@ -785,6 +800,8 @@ void AppInstaller::ReadonlyUpdateUninstallSteps() {
       ci::security::StepRegisterTrustAnchor::RegisterType::UPDATE);
   AddStep<ci::security::StepPrivacyPrivilege>(
       ci::security::StepPrivacyPrivilege::ActionType::Update);
+  // After StepRemoveFiles is performed, the installation can't undo
+  // So the installation proceeds as is, ignoring errors in later steps
   AddStep<ci::filesystem::StepRemoveFiles>();
   AddStep<ci::pkgmgr::StepRemovePrivSharedres>();
   AddStep<ci::filesystem::StepRemoveZipImage>();
@@ -925,4 +942,35 @@ Step::Status AppInstaller::SafeExecute(std::unique_ptr<Step> const& step_ptr,
   return process_status;
 }
 
+
+void AppInstaller::RemoveUnnecessaryRecoveryFiles() {
+  if (context_->pkgid.get().empty())
+    return;
+
+  const auto& own_recovery_file =
+      context_->recovery_info.get().recovery_file;
+  std::vector<RecoverEntry> entries = SearchRecoveryFiles(context_->uid.get());
+  for (const auto& it : entries) {
+    if (it.first == "unified")
+      continue;
+
+    if (own_recovery_file && own_recovery_file->path() == it.second)
+      continue;
+
+    auto recovery_file = recovery::RecoveryFile::OpenRecoveryFile(it.second);
+    if (!recovery_file) {
+      LOG(ERROR) << "Failed to open recovery file path : " << it.second;
+      continue;
+    }
+
+    if (context_->pkgid.get() == recovery_file->pkgid()) {
+      LOG(WARNING) << "The installation request for package["
+          << context_->pkgid.get()
+          << "] has been completed, so remove unnecessary recovery file["
+          << it.second << "]";
+      Remove(it.second);
+    }
+  }
+}
+
 }  // namespace common_installer
index 6cb06273fab33ebc2980fe4a5000e94ccec34b00..a4695da15a2983a6858bbc7e06f644afb0e3899e 100644 (file)
@@ -297,6 +297,7 @@ class AppInstaller : public Step::IStepErrorSignal {
                            std::string name);
   void HandleStepError(Step::Status result, const std::string& error);
   std::string GetPackageVersion();
+  void RemoveUnnecessaryRecoveryFiles();
 
   std::shared_ptr<utils::FileLogBackend> failure_logger_;
   Step::Status status_;
index 4476abf6352f1758e1d1e9b1718902c163f2e0a5..370390991b5a944e7ab906c270c8ac4139bd0fb6 100644 (file)
@@ -44,7 +44,8 @@ InstallerContext::InstallerContext()
       partial_rw(false),
       force_clean_from_db(false),
       cross_app_rules(false),
-      debug_mode(false) {}
+      debug_mode(false),
+      undoable(true) {}
 
 InstallerContext::~InstallerContext() {
   if (manifest_data.get())
index 2bd0aa5569a1ab0023da86d9aef4a785aca6dd4b..c98b639980f47644aa6381f96fed63b6bdc98adc 100644 (file)
@@ -427,6 +427,11 @@ class InstallerContext {
    *        (needed for rollback operations)
    */
   Property<std::vector<PkgQueryInterface::PluginInfo>> backup_plugin_info;
+
+  /**
+   * @brief Property of indicating if the installer can undo
+   */
+  Property<bool> undoable;
 };
 
 }  // namespace common_installer
index cb8b82a48f9e5a491349853092252bec904a00ff..b742abbfec98022fb0ebd251fa2fc4044647bf1f 100644 (file)
@@ -97,7 +97,7 @@ std::unique_ptr<RecoveryFile> RecoveryFile::OpenRecoveryFile(
 
 RecoveryFile::RecoveryFile(const fs::path& path, RequestType type, bool load)
     : type_(type), path_(path), backup_done_(false), cleanup_(false),
-      security_operation_done_(false) {
+      security_operation_done_(false), keep_recovery_file_(false) {
   backup_path_ = path_.string() + ".bck";
   if (load) {
     if (!ReadFileContent()) {
@@ -115,6 +115,11 @@ RecoveryFile::RecoveryFile(const fs::path& path, RequestType type, bool load)
 }
 
 RecoveryFile::~RecoveryFile() {
+  if (keep_recovery_file_ == true) {
+    LOG(WARNING) << "Keep recovery file";
+    return;
+  }
+
   if (Remove(path_))
     LOG(DEBUG) << "Recovery file " << path_ << " removed";
   if (Remove(backup_path_))
@@ -151,6 +156,10 @@ void RecoveryFile::set_security_operation_done(bool security_operation_done) {
   security_operation_done_ = security_operation_done;
 }
 
+void RecoveryFile::set_keep_recovery_file(bool keep_recovery_file) {
+  keep_recovery_file_ = keep_recovery_file;
+}
+
 const std::filesystem::path& RecoveryFile::unpacked_dir() const {
   return unpacked_dir_;
 }
@@ -175,6 +184,14 @@ bool RecoveryFile::security_operation_done() const {
   return security_operation_done_;
 }
 
+bool RecoveryFile::keep_recovery_file() const {
+  return keep_recovery_file_;
+}
+
+const std::filesystem::path& RecoveryFile::path() const {
+  return path_;
+}
+
 bool RecoveryFile::ReadFileContent() {
   FILE* handle = fopen(path_.c_str(), "r");
   if (!handle) {
index f2d3260812aa315a1a1b3d8f09aee1174cd4147d..ce65d2a0568b8eb1720610b617b0ca04382e3a7b 100644 (file)
@@ -93,6 +93,13 @@ class RecoveryFile {
    */
   void set_security_operation_done(bool security_operation_done);
 
+  /**
+   * setter for keep recovery file
+   *
+   * \param keep_recovery_file boolean value of keep_recovery_file
+   */
+  void set_keep_recovery_file(bool keep_recovery_file);
+
   /**
    * getter for unpacked dir
    *
@@ -135,6 +142,20 @@ class RecoveryFile {
    */
   bool security_operation_done() const;
 
+  /**
+   * getter for recovery file path
+   *
+   * \return true if backup does exist
+   */
+  const std::filesystem::path& path() const;
+
+  /**
+   * getter for keep recovery file flag
+   *
+   * \return true if keep recovery file flag has set
+   */
+  bool keep_recovery_file() const;
+
   /**
    * Transaction of current RecoveryFile content into recovery file
    *
@@ -157,6 +178,7 @@ class RecoveryFile {
   bool backup_done_;
   bool cleanup_;
   bool security_operation_done_;
+  bool keep_recovery_file_;
 };
 
 }  // namespace recovery
index 4cebdfb841b412ad25294ffaf8b24f6b6c7b5d51..554fd226a902034d8c7c6e12bbd2213ab5fb787e 100644 (file)
@@ -7,8 +7,15 @@
 namespace common_installer {
 namespace configuration {
 
+bool StepFail::is_executed_(false);
+
+bool StepFail::IsExecuted() {
+  return is_executed_;
+}
+
 Step::Status StepFail::process() {
   LOG(ERROR) << "Request was expected to fail";
+  is_executed_ = true;
   return Status::ERROR;
 }
 
index b51023ee276ae1eea8db5d6bab62364eb2817020..6975a28acbac04dc8a7bf24412277760fa75da0c 100644 (file)
@@ -22,6 +22,8 @@ class StepFail : public Step {
  public:
   using Step::Step;
 
+  static bool IsExecuted();
+
   /**
    * \brief returns error
    *
@@ -32,6 +34,9 @@ class StepFail : public Step {
   Status undo() override { return Status::OK; }
   Status precheck() override { return Status::OK; }
 
+ private:
+  static bool is_executed_;
+
   STEP_NAME(Fail)
 };
 
index 77f1b90a5df6f56f1933a09be270559fd469675d..7022fb05b13fbe56e197e1ebe297bd851c9e5e8c 100644 (file)
@@ -68,6 +68,8 @@ Step::Status StepRemoveFiles::precheck() {
                << context_->GetPkgPath()
                << ") path does not exist";
 
+  context_->undoable.set(false);
+
   return Step::Status::OK;
 }
 
index 2c541d144dcd75387e7951d3e740890b5af63463..d600a03456cf95b4d3c754831f8b41045186fc14 100644 (file)
@@ -16,6 +16,10 @@ Step::Status StepRecovery::process() {
       RequestType::Uninstall)
     return RecoveryUninstall();
 
+  if (context_->recovery_info.get().recovery_file->type() ==
+      RequestType::ReadonlyUpdateUninstall)
+    return RecoveryReadonlyUpdateUninstall();
+
   if (context_->recovery_info.get().recovery_file->cleanup() ||
       context_->recovery_info.get().cleanup)
     return Cleanup();
index 248db5776800b8c6b1d15d11e5a6cfea011c70c0..45e99eb14baaa62eef1ac4dbf5577f5354691c3a 100644 (file)
 
 #include "common/utils/byte_size_literals.h"
 #include "common/utils/paths.h"
+#include "common/utils/request.h"
 
 namespace fs = std::filesystem;
 
 namespace {
 
-unsigned kZipBufSize = 8_kB;
-unsigned kZipMaxPath = PATH_MAX;
+constexpr unsigned kZipBufSize = 8_kB;
+constexpr unsigned kZipMaxPath = PATH_MAX;
+constexpr const char kRecoveryFilePattern[] = "^(.*)-recovery-(.){6}$";
+constexpr const char kBackupFilePattern[] = "^(.*)-recovery-(.){6}\\.bck$";
 
 int64_t GetBlockSizeForPath(const fs::path& path_in_partition) {
   struct stat stats;
@@ -758,4 +761,64 @@ bool SyncFile(const fs::path& path) {
   return true;
 }
 
+static void SearchBackupFiles(uid_t uid) {
+  const fs::path recovery_dir =
+      GetRecoveryFilePath(GetRootAppPath(false, uid));
+  if (!fs::exists(recovery_dir))
+    return;
+  try {
+    for (fs::directory_iterator iter(recovery_dir);
+        iter != fs::directory_iterator();
+        ++iter) {
+      std::string file = iter->path().filename().string();
+      std::regex backup_regex(kBackupFilePattern);
+      std::smatch match;
+      if (std::regex_search(file, match, backup_regex)) {
+        fs::path orig_file(iter->path().parent_path() / iter->path().stem());
+        if (fs::exists(orig_file))
+          fs::remove(orig_file);
+        fs::rename(iter->path(), orig_file);
+      }
+    }
+  } catch (const std::exception& e) {
+    LOG(WARNING) << "Exception occurred: "
+        << typeid(e).name() << ", " << e.what();
+  }
+}
+
+std::vector<RecoverEntry> SearchRecoveryFiles(uid_t uid) {
+  SearchBackupFiles(uid);
+
+  std::vector<RecoverEntry> list;
+  const fs::path recovery_dir =
+      GetRecoveryFilePath(GetRootAppPath(false, uid));
+  LOG(INFO) << "RootAppPath: " << recovery_dir;
+  if (!fs::exists(recovery_dir))
+    return list;
+
+  for (fs::directory_iterator iter(recovery_dir);
+      iter != fs::directory_iterator();
+      ++iter) {
+    try {
+      std::string file = iter->path().filename().string();
+      std::regex recovery_regex(kRecoveryFilePattern);
+      std::smatch match;
+      if (std::regex_search(file, match, recovery_regex)) {
+        LOG(INFO) << "Found recovery file: " << file;
+        std::string type(match[1]);
+        if (type == "unified")
+          list.emplace(list.begin(), type, iter->path().string());
+        else
+          list.emplace_back(type, iter->path().string());
+      }
+    } catch (const std::exception& e) {
+      LOG(WARNING) << "Exception occurred: "
+          << typeid(e).name() << ", " << e.what();
+      continue;
+    }
+  }
+
+  return list;
+}
+
 }  // namespace common_installer
index 501633ebd6a19ec7de1be24c930561b687948d4d..fbf49188c49f6d55114b4245b101cace94e815cd 100644 (file)
@@ -11,6 +11,8 @@
 
 namespace common_installer {
 
+typedef std::pair<std::string, std::filesystem::path> RecoverEntry;
+
 enum FSFlag : int {
   FS_NONE              = 0,
   FS_MERGE_SKIP        = (1 << 0),
@@ -101,6 +103,8 @@ std::filesystem::path GenerateUniquePathString(const std::string& format) ;
 
 bool SyncFile(const std::filesystem::path& path);
 
+std::vector<RecoverEntry> SearchRecoveryFiles(uid_t uid);
+
 }  // namespace common_installer
 
 #endif  // COMMON_UTILS_FILE_UTIL_H_
index 5fce8e7fa4423cd402771256202107074c5cca6a..c219a7af1b01d63aec213a8e817118bd65d26765 100644 (file)
@@ -23,10 +23,6 @@ namespace fs = std::filesystem;
 
 namespace {
 
-typedef std::pair<std::string, std::string> RecoverEntry;
-
-const char kRecoveryFilePattern[] = "^(.*)-recovery-(.){6}$";
-const char kBackupFilePattern[] = "^(.*)-recovery-(.){6}\\.bck$";
 const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
 
 std::string TruncateNewLine(const char* data) {
@@ -70,9 +66,7 @@ class PkgRecoveryService {
   void Run();
 
  private:
-  void SearchBackupFiles(uid_t uid);
-  std::vector<RecoverEntry> SearchRecoveryFiles(uid_t uid);
-  void ProcessRecovery(uid_t uid, const std::vector<RecoverEntry>& entries);
+  void ProcessRecovery(uid_t uid, const std::vector<ci::RecoverEntry>& entries);
   bool RunBackend(uid_t uid, const char* type, const char* file);
 };
 
@@ -111,9 +105,8 @@ bool PkgRecoveryService::RunBackend(uid_t uid, const char* type,
 
 void PkgRecoveryService::Run() {
   // recover global packages
-  SearchBackupFiles(kGlobalUserUid);
   LOG(INFO) << "Searching recovery files for user " << kGlobalUserUid;
-  std::vector<RecoverEntry> globalentries = SearchRecoveryFiles(kGlobalUserUid);
+  std::vector<ci::RecoverEntry> globalentries = ci::SearchRecoveryFiles(kGlobalUserUid);
   ProcessRecovery(kGlobalUserUid, globalentries);
 
   // recover normal user packages
@@ -121,72 +114,13 @@ void PkgRecoveryService::Run() {
   for (const auto& userinfo : list) {
     uid_t uid = std::get<0>(userinfo);
     LOG(INFO) << "Searching recovery files for user " << std::get<0>(userinfo);
-    SearchBackupFiles(uid);
-    std::vector<RecoverEntry> entries = SearchRecoveryFiles(uid);
+    std::vector<ci::RecoverEntry> entries = ci::SearchRecoveryFiles(uid);
     ProcessRecovery(uid, entries);
   }
 }
 
-void PkgRecoveryService::SearchBackupFiles(uid_t uid) {
-  const fs::path recovery_dir =
-      ci::GetRecoveryFilePath(ci::GetRootAppPath(false, uid));
-  if (!fs::exists(recovery_dir))
-    return;
-  try {
-    for (fs::directory_iterator iter(recovery_dir);
-        iter != fs::directory_iterator();
-        ++iter) {
-      std::string file = iter->path().filename().string();
-      std::regex backup_regex(kBackupFilePattern);
-      std::smatch match;
-      if (std::regex_search(file, match, backup_regex)) {
-        fs::path orig_file(iter->path().parent_path() / iter->path().stem());
-        if (fs::exists(orig_file))
-          fs::remove(orig_file);
-        fs::rename(iter->path(), orig_file);
-      }
-    }
-  } catch (const std::exception& e) {
-    LOG(WARNING) << "Exception occurred: "
-        << typeid(e).name() << ", " << e.what();
-  }
-}
-
-std::vector<RecoverEntry> PkgRecoveryService::SearchRecoveryFiles(uid_t uid) {
-  std::vector<RecoverEntry> list;
-  const fs::path recovery_dir =
-      ci::GetRecoveryFilePath(ci::GetRootAppPath(false, uid));
-  LOG(INFO) << "RootAppPath: " << recovery_dir;
-  if (!fs::exists(recovery_dir))
-    return list;
-
-  for (fs::directory_iterator iter(recovery_dir);
-      iter != fs::directory_iterator();
-      ++iter) {
-    try {
-      std::string file = iter->path().filename().string();
-      std::regex recovery_regex(kRecoveryFilePattern);
-      std::smatch match;
-      if (std::regex_search(file, match, recovery_regex)) {
-        LOG(INFO) << "Found recovery file: " << file;
-        std::string type(match[1]);
-        if (type == "unified")
-          list.emplace(list.begin(), type, iter->path().string());
-        else
-          list.emplace_back(type, iter->path().string());
-      }
-    } catch (const std::exception& e) {
-      LOG(WARNING) << "Exception occurred: "
-          << typeid(e).name() << ", " << e.what();
-      continue;
-    }
-  }
-
-  return list;
-}
-
 void PkgRecoveryService::ProcessRecovery(uid_t uid,
-    const std::vector<RecoverEntry>& entries) {
+    const std::vector<ci::RecoverEntry>& entries) {
   LOG(INFO) << "Process recovery for user " << uid;
   for (const auto& entry : entries) {
     const char* type = entry.first.c_str();
index edc5da831740ca2a515f44d93440dfbb090de895..f6c0cf1df6184332dc679af5e120df06758963ac 100644 (file)
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 
 #include <common/installer/app_installer.h>
+#include <common/step/configuration/step_fail.h>
 #include <common/utils/paths.h>
 #include <common/pkgmgr_interface.h>
 #include <common/utils/pkgmgr_query.h>
@@ -905,11 +906,14 @@ void BackendInterface::TestRollbackAfterEachStep(int argc, const char* argv[],
     }
     AppInstallerPtr backend;
     unsigned int insert_idx = 0;
+    unsigned int step_count = 0;
     do {
       backend = CreateFailExpectedInstaller(pkgmgr, insert_idx);
       LOG(DEBUG) << "StepFail is inserted at: " << insert_idx;
-      ci::AppInstaller::Result ret = backend->Run();
-      if (ret != ci::AppInstaller::Result::ERROR) {
+      backend->Run();
+      step_count = backend->StepCount();
+      backend.reset();
+      if (!ci::configuration::StepFail::IsExecuted()) {
         LOG(ERROR) << "StepFail not executed";
         return 1;
       }
@@ -918,8 +922,8 @@ void BackendInterface::TestRollbackAfterEachStep(int argc, const char* argv[],
         break;
       }
       insert_idx++;
-    } while (insert_idx < backend->StepCount());
-    if (insert_idx != backend->StepCount())
+    } while (insert_idx < step_count);
+    if (insert_idx != step_count)
       return 1;
 
     return 0;