SET(EXTRA_OPTIMIZATION_FLAGS "-Wl,--gc-sections -flto -fmerge-all-constants")
SET(CMAKE_C_FLAGS_PROFILING "-O2 ${EXTRA_FLAGS}")
-SET(CMAKE_CXX_FLAGS_PROFILING "-O2 -std=c++11 ${EXTRA_FLAGS}")
+SET(CMAKE_CXX_FLAGS_PROFILING "-O2 -std=c++14 ${EXTRA_FLAGS}")
SET(CMAKE_C_FLAGS_DEBUG "-O0 -g ${EXTRA_FLAGS}")
-SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -std=c++11 -g ${EXTRA_FLAGS}")
+SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -std=c++14 -g ${EXTRA_FLAGS}")
SET(CMAKE_C_FLAGS_RELEASE "-Os ${EXTRA_OPTIMIZATION_FLAGS} ${EXTRA_FLAGS}")
-SET(CMAKE_CXX_FLAGS_RELEASE "-Os -std=c++11 ${EXTRA_OPTIMIZATION_FLAGS} ${EXTRA_FLAGS}")
-SET(CMAKE_CXX_FLAGS_CCOV "-O0 -std=c++11 -g --coverage ${EXTRA_FLAGS}")
+SET(CMAKE_CXX_FLAGS_RELEASE "-Os -std=c++14 ${EXTRA_OPTIMIZATION_FLAGS} ${EXTRA_FLAGS}")
+SET(CMAKE_CXX_FLAGS_CCOV "-O0 -std=c++14 -g --coverage ${EXTRA_FLAGS}")
# Linker flags
SET(EXTRA_LINKER_FLAGS "-Wl,--as-needed ${EXTRA_OPTIMIZATION_FLAGS} -fwhole-program")
int index_;
+ friend class InstallerRunner;
+
SCOPE_LOG_TAG(AppInstaller)
DISALLOW_COPY_AND_ASSIGN(AppInstaller);
--- /dev/null
+// Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#include "common/global_recovery_file.h"
+
+#include <boost/filesystem/path.hpp>
+
+#include <manifest_parser/utils/logging.h>
+
+#include <string>
+
+#include "common/utils/file_util.h"
+#include "common/pkgmgr_interface.h"
+
+namespace bf = boost::filesystem;
+namespace ci = common_installer;
+
+namespace {
+
+const char kGlobalTypeName[] = "unified";
+
+bf::path Backup(const bf::path& filepath) {
+ bf::path backup_path(filepath);
+ backup_path += ".bck";
+
+ if (!ci::MoveFile(filepath, backup_path) ||
+ !ci::CopyFile(backup_path, filepath)) {
+ LOG(ERROR) << "Failed to backup";
+ return {};
+ }
+
+ return backup_path;
+}
+
+} // namespace
+
+namespace common_installer {
+
+GlobalRecoveryFile::GlobalRecoveryFile(
+ std::shared_ptr<PkgMgrInterface> pkgmgr) : pkgmgr_(pkgmgr) {
+}
+
+GlobalRecoveryFile::~GlobalRecoveryFile() {
+ if (bf::exists(recovery_filepath_))
+ ci::Remove(recovery_filepath_);
+ if (bf::exists(backup_path_))
+ ci::Remove(backup_path_);
+}
+
+
+bool GlobalRecoveryFile::Init() {
+ boost::filesystem::path root_path = ci::GetRootAppPath(
+ pkgmgr_->GetIsPreloadRequest(), pkgmgr_->GetUid());
+ recovery_filepath_ = GenerateRecoveryFilePath(root_path, kGlobalTypeName);
+ if (recovery_filepath_.empty())
+ return false;
+
+ return true;
+}
+
+std::string GlobalRecoveryFile::AddPathWithType(
+ const std::string& pkg_type) {
+ boost::filesystem::path root_path = ci::GetRootAppPath(
+ pkgmgr_->GetIsPreloadRequest(), pkgmgr_->GetUid());
+ bf::path recovery_filepath = GenerateRecoveryFilePath(root_path, pkg_type);
+ if (!AppendString(recovery_filepath.string()))
+ return {};
+
+ recovery_list_.emplace_back(recovery_filepath.string());
+ return recovery_filepath.string();
+}
+
+bool GlobalRecoveryFile::AppendPath(
+ const bf::path& additional_path) {
+ return AppendString(additional_path.string());
+}
+
+bool GlobalRecoveryFile::AppendCleanUp() {
+ return AppendString("cleanup");
+}
+
+bool GlobalRecoveryFile::AppendString(const std::string& val) {
+ if (recovery_filepath_.empty())
+ return true;
+
+ if (bf::exists(recovery_filepath_)) {
+ backup_path_ = Backup(recovery_filepath_);
+ if (backup_path_.empty()) {
+ LOG(ERROR) << "Failed to backup";
+ return false;
+ }
+ }
+
+ FILE* handle = fopen(recovery_filepath_.c_str(), "a");
+ if (!handle) {
+ LOG(ERROR) << "Failed to open file :" << recovery_filepath_;
+ return false;
+ }
+
+ fputs(val.c_str(), handle);
+ fputs("\n", handle);
+ fclose(handle);
+ sync();
+
+ ci::Remove(backup_path_);
+ return true;
+}
+
+bf::path GlobalRecoveryFile::GenerateRecoveryFilePath(
+ const bf::path& path, const std::string& type) {
+ bf::path pattern = path;
+ pattern += "/";
+ pattern += type;
+ pattern += "-recovery-%%%%%%";
+ bf::path tmp_path;
+
+ std::vector<std::string>::iterator iter;
+ do {
+ tmp_path = boost::filesystem::unique_path(pattern);
+ iter = std::find(recovery_list_.begin(), recovery_list_.end(),
+ tmp_path.string());
+ } while (boost::filesystem::exists(tmp_path) ||
+ iter != recovery_list_.end());
+
+ return tmp_path;
+}
+
+} // namespace common_installer
--- /dev/null
+// Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef COMMON_GLOBAL_RECOVERY_FILE_H_
+#define COMMON_GLOBAL_RECOVERY_FILE_H_
+
+#include <boost/filesystem/path.hpp>
+
+#include <string>
+#include <vector>
+
+#include "common/pkgmgr_interface.h"
+
+namespace bf = boost::filesystem;
+
+namespace common_installer {
+
+class GlobalRecoveryFile {
+ public:
+ explicit GlobalRecoveryFile(std::shared_ptr<PkgMgrInterface> pkgmgr);
+ ~GlobalRecoveryFile();
+
+ bool Init();
+
+ std::string AddPathWithType(const std::string& pkg_type);
+
+ bool AppendPath(const bf::path& additional_path);
+
+ bool AppendCleanUp();
+
+ private:
+ bool AppendString(const std::string& val);
+ bf::path GenerateRecoveryFilePath(
+ const bf::path& path,
+ const std::string& type);
+ std::shared_ptr<common_installer::PkgMgrInterface> pkgmgr_;
+ bf::path recovery_filepath_;
+ bf::path backup_path_;
+ std::vector<std::string> recovery_list_;
+};
+
+} // namespace common_installer
+
+#endif // COMMON_GLOBAL_RECOVERY_FILE_H_
* \param rf RecoveryFile object (pointer to object)
*/
explicit RecoveryInfo(std::unique_ptr<recovery::RecoveryFile> rf)
- : recovery_file(std::move(rf)) {
+ : recovery_file(std::move(rf)), cleanup(false) {
+ }
+
+ /**
+ * Constructor.
+ *
+ * \param path path of recovery file to be created
+ * \param recovery_cleanup path of recovery file to be created
+ */
+ explicit RecoveryInfo(const boost::filesystem::path& path,
+ bool recovery_cleanup = false)
+ : filepath(path), cleanup(recovery_cleanup) {
}
/** pointer to RecoveryFile */
std::unique_ptr<recovery::RecoveryFile> recovery_file;
+
+ /** path of recovery file to be created */
+ boost::filesystem::path filepath;
+
+ /** cleanup flag delivered by global recovery file */
+ bool cleanup;
};
/**
#include <manifest_parser/utils/logging.h>
#include <list>
+#include <string>
#include <utility>
#include "common/app_installer.h"
+#include "common/installer_context.h"
#include "common/installer_factory.h"
#include "common/pkgmgr_interface.h"
AppInstaller::Result InstallerRunner::Run() {
AppInstaller::Result result = AppInstaller::Result::OK;
+ if (installers_.size() == 0)
+ return result;
+
if (getuid() != 0 && NeedCheckDependency()) {
if (!SortInstallers()) {
if (pi_) {
result = AppInstaller::Result::UNDO_ERROR;
} while (it-- != installers_.begin());
} else {
+ if (pkgmgr_->GetRequestType() != RequestType::Recovery)
+ global_recovery_->AppendCleanUp();
--it;
do {
// Clean operation always succeeds
}
void InstallerRunner::Init() {
+ global_recovery_ = std::make_unique<GlobalRecoveryFile>(pkgmgr_);
+ bool is_global_request = (pkgmgr_->GetRequestInfoCount() > 1) ? true : false;
+ if (pkgmgr_->GetRequestType() != RequestType::Recovery &&
+ is_global_request) {
+ if (!global_recovery_->Init())
+ return;
+ }
for (int i = 0; i < pkgmgr_->GetRequestInfoCount(); i++) {
std::unique_ptr<AppInstaller> installer =
factory_->CreateInstaller(pkgmgr_, i);
+ if (pkgmgr_->GetRequestType() != RequestType::Recovery &&
+ is_global_request) {
+ std::string recovery_filepath =
+ global_recovery_->AddPathWithType(
+ installer->context_->pkg_type.get());
+ installer->context_->recovery_info.set(RecoveryInfo(recovery_filepath));
+ }
installers_.emplace_back(std::move(installer));
}
}
#include "common/app_installer.h"
#include "common/dependency_checker.h"
+#include "common/global_recovery_file.h"
#include "common/pkgmgr_interface.h"
namespace common_installer {
PkgMgrPtr pkgmgr_;
std::list<std::unique_ptr<AppInstaller>> installers_;
std::unique_ptr<PkgmgrSignal> pi_;
+ std::unique_ptr<GlobalRecoveryFile> global_recovery_;
};
} // namespace common_installer
}
RequestType PkgMgrInterface::GetRequestType(int idx) const {
+ // These type could be determined even if there are no query_interface_.
+ switch (pkgmgr_installer_get_request_type(pi_)) {
+ case PKGMGR_REQ_DISABLE_PKG:
+ return RequestType::DisablePkg;
+ case PKGMGR_REQ_ENABLE_PKG:
+ return RequestType::EnablePkg;
+ case PKGMGR_REQ_MIGRATE_EXTIMG:
+ return RequestType::MigrateExtImg;
+ case PKGMGR_REQ_RECOVER_DB:
+ return RequestType::RecoverDB;
+ case PKGMGR_REQ_REINSTALL:
+ return RequestType::Reinstall;
+ case PKGMGR_REQ_RECOVER:
+ return RequestType::Recovery;
+ case PKGMGR_REQ_MOVE:
+ return RequestType::Move;
+ }
+
AppQueryInterface* query_interface = query_interface_;
if (!query_interface) {
auto it = query_interface_map_.find(idx);
else
return RequestType::Uninstall;
}
- case PKGMGR_REQ_REINSTALL:
- return RequestType::Reinstall;
- case PKGMGR_REQ_RECOVER:
- return RequestType::Recovery;
- case PKGMGR_REQ_MOVE:
- return RequestType::Move;
case PKGMGR_REQ_MANIFEST_DIRECT_INSTALL:
if (!is_app_installed_.get()) {
if (GetIsPreloadRequest() && GetIsPartialRW())
return RequestType::MountInstall;
else
return RequestType::MountUpdate;
- case PKGMGR_REQ_DISABLE_PKG:
- return RequestType::DisablePkg;
- case PKGMGR_REQ_ENABLE_PKG:
- return RequestType::EnablePkg;
- case PKGMGR_REQ_MIGRATE_EXTIMG:
- return RequestType::MigrateExtImg;
- case PKGMGR_REQ_RECOVER_DB:
- return RequestType::RecoverDB;
default:
return RequestType::Unknown;
}
return pkgmgr_installer_get_request_info_count(pi_);
}
+bool PkgMgrInterface::GetRecoveryCleanup() const {
+ return (pkgmgr_installer_get_recovery_cleanup(pi_) == 1);
+}
+
} // namespace common_installer
*/
int GetRequestInfoCount() const;
+ /**
+ * Returns whether recovery mode is set to cleanup or not.
+ *
+ * \return True if recovery mode is set to cleanup. Otherwise, return false.
+ */
+ bool GetRecoveryCleanup() const;
+
/**
* Get Raw pointer to pkgmgr_installer object
* NOTE: It should not be used (PkgMgrInterface can destroy it
break;
case RequestType::Recovery:
context_->file_path.set(pkgmgr_->GetRequestInfo(context_->index.get()));
+ context_->recovery_info.set(
+ RecoveryInfo(context_->file_path.get(),
+ pkgmgr_->GetRecoveryCleanup()));
break;
case RequestType::MountInstall:
case RequestType::MountUpdate:
namespace recovery {
Step::Status StepCreateRecoveryFile::process() {
- std::string recovery_filename = context_->pkg_type.get() + "-recovery";
- bf::path recovery_filepath = GenerateTemporaryPath(
- context_->root_application_path.get() / recovery_filename);
+ bf::path recovery_filename = context_->recovery_info.get().filepath;
+
+ if (recovery_filename.empty()) {
+ std::string file_format = context_->pkg_type.get() + "-recovery";
+ recovery_filename = GenerateTemporaryPath(
+ context_->root_application_path.get() / file_format);
+ }
+
auto recovery_file =
- recovery::RecoveryFile::CreateRecoveryFile(recovery_filepath,
- context_->request_type.get());
+ recovery::RecoveryFile::CreateRecoveryFile(recovery_filename,
+ context_->request_type.get());
if (!recovery_file) {
LOG(ERROR) << "Failed to create recovery file";
return Status::CONFIG_ERROR;
}
- context_->recovery_info.set(RecoveryInfo(std::move(recovery_file)));
+
+ if (context_->recovery_info.get().filepath.empty())
+ context_->recovery_info.set(RecoveryInfo(std::move(recovery_file)));
+ else
+ context_->recovery_info.get().recovery_file = std::move(recovery_file);
return Status::OK;
}
if (recovery_file->cleanup())
LOG(INFO) << "Running cleanup operation";
+ bool global_recovery_cleanup = context_->recovery_info.get().cleanup;
context_->recovery_info.set(RecoveryInfo(std::move(recovery_file)));
+ if (global_recovery_cleanup) {
+ LOG(INFO) << "Set recovery cleanup";
+ context_->recovery_info.get().cleanup = true;
+ }
+
return Status::OK;
}
namespace recovery {
Step::Status StepRecovery::process() {
- if (context_->recovery_info.get().recovery_file->cleanup())
+ if (context_->recovery_info.get().recovery_file->cleanup() ||
+ context_->recovery_info.get().cleanup)
return Cleanup();
switch (context_->recovery_info.get().recovery_file->type()) {
#include <glib.h>
#include <common/request.h>
+#include <common/utils/file_util.h>
#include <common/utils/subprocess.h>
#include <common/utils/user_util.h>
#include <manifest_parser/utils/logging.h>
const char kBackupFilePattern[] = "^(.*)-recovery-(.){6}\\.bck$";
const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
+std::string TruncateNewLine(const char* data) {
+ int length = strlen(data);
+ if (data[length - 1] == '\n')
+ --length;
+ return std::string(data, length);
+}
+
+std::vector<std::string> ParseRecoveryFile(const char* file) {
+ FILE* handle = fopen(file, "r");
+ if (!handle) {
+ LOG(ERROR) << "Failed to open recovery file :" << file;
+ return {};
+ }
+
+ std::vector<std::string> arguments;
+ std::array<char, 200> data;
+ data[0] = '\0';
+ while (fgets(data.data(), data.size(), handle)) {
+ std::string line_data = TruncateNewLine(data.data());
+ if (line_data == "cleanup") {
+ arguments.emplace_back("--recovery-cleanup");
+ break;
+ }
+
+ if (!boost::filesystem::exists(line_data))
+ continue;
+
+ arguments.emplace_back(line_data);
+ }
+ fclose(handle);
+
+ return arguments;
+}
+
class PkgRecoveryService {
public:
PkgRecoveryService();
std::string backend_cmd = "/usr/bin/" + std::string(type) + "-backend";
ci::Subprocess backend(backend_cmd);
std::string str_uid = std::to_string(uid);
- backend.Run("-b", file, "-u", str_uid.c_str());
+ if (std::string(type) == "unified") {
+ auto arguments = ParseRecoveryFile(file);
+ if (!arguments.size())
+ return ci::Remove(bf::path(file));
+
+ arguments.emplace(arguments.begin(), "-b");
+ arguments.emplace_back("-u");
+ arguments.emplace_back(str_uid.c_str());
+
+ backend.RunWithArgs(arguments);
+ } else {
+ backend.Run("-b", file, "-u", str_uid.c_str());
+ }
int status = backend.Wait();
if (WIFSIGNALED(status) || WEXITSTATUS(status))
return false;
+
+ ci::Remove(bf::path(file));
+
return true;
}
if (std::regex_search(file, match, recovery_regex)) {
LOG(INFO) << "Found recovery file: " << file;
std::string type(match[1]);
- list.emplace_back(type, iter->path().string());
+ if (type == "unified")
+ list.emplace(list.begin(), type, iter->path().string());
+ else
+ list.emplace_back(type, iter->path().string());
}
} catch (...) {
LOG(WARNING) << "Exception occurred: "
for (auto entry : entries) {
const char* type = entry.first.c_str();
const char* file = entry.second.c_str();
+ if (!bf::exists(file))
+ continue;
+
if (!RunBackend(uid, type, file))
LOG(ERROR) << "Recovery process for " << file << " failed";
}