Refactor pkg_upgrade tool 96/246996/13
authorJunghoon Park <jh9216.park@samsung.com>
Fri, 6 Nov 2020 01:50:35 +0000 (10:50 +0900)
committerJunghoon Park <jh9216.park@samsung.com>
Mon, 23 Nov 2020 05:15:15 +0000 (14:15 +0900)
- Redesigned
- Changed language (c to c++)

Change-Id: I726102f2d84ddda80046d07a40e01ba7c55dff70
Signed-off-by: Junghoon Park <jh9216.park@samsung.com>
57 files changed:
CMakeLists.txt
packaging/pkgmgr-tool.spec
src/install_preload_pkg/install_preload_pkg.c
src/pkg_upgrade/CMakeLists.txt [changed mode: 0644->0755]
src/pkg_upgrade/include/backend_invoker.hh [new file with mode: 0644]
src/pkg_upgrade/include/common_type.hh [new file with mode: 0644]
src/pkg_upgrade/include/file_logbackend.hh [new file with mode: 0644]
src/pkg_upgrade/include/logging.hh [new file with mode: 0644]
src/pkg_upgrade/include/pkg_finder.hh [new file with mode: 0644]
src/pkg_upgrade/include/pkg_upgrade.h [deleted file]
src/pkg_upgrade/include/pkg_upgrader.hh [new file with mode: 0644]
src/pkg_upgrade/include/pkg_upgrader_factory.hh [new file with mode: 0644]
src/pkg_upgrade/include/ro2rw_upgrader.hh [new file with mode: 0644]
src/pkg_upgrade/include/rw2ro_upgrader.hh [new file with mode: 0644]
src/pkg_upgrade/include/rw_upgrader.hh [new file with mode: 0644]
src/pkg_upgrade/include/simple_upgrader.hh [new file with mode: 0644]
src/pkg_upgrade/include/upgrader.hh [new file with mode: 0644]
src/pkg_upgrade/pkg_upgrade.c [deleted file]
src/pkg_upgrade/src/backend_invoker.cc [new file with mode: 0644]
src/pkg_upgrade/src/file_logbackend.cc [new file with mode: 0644]
src/pkg_upgrade/src/logging.cc [new file with mode: 0644]
src/pkg_upgrade/src/main.cc [new file with mode: 0644]
src/pkg_upgrade/src/pkg_finder.cc [new file with mode: 0644]
src/pkg_upgrade/src/pkg_upgrader.cc [new file with mode: 0644]
src/pkg_upgrade/src/pkg_upgrader_factory.cc [new file with mode: 0644]
src/pkg_upgrade/src/ro2rw_upgrader.cc [new file with mode: 0644]
src/pkg_upgrade/src/rw2ro_upgrader.cc [new file with mode: 0644]
src/pkg_upgrade/src/simple_upgrader.cc [new file with mode: 0644]
src/pkg_upgrade/src/upgrader.cc [new file with mode: 0644]
tests/CMakeLists.txt [new file with mode: 0644]
tests/mock/mock_hook.h [new file with mode: 0644]
tests/mock/module_mock.h [new file with mode: 0644]
tests/mock/os_mock.cc [new file with mode: 0644]
tests/mock/os_mock.h [new file with mode: 0644]
tests/mock/pkgmgr_info_mock.cc [new file with mode: 0644]
tests/mock/pkgmgr_info_mock.h [new file with mode: 0644]
tests/mock/test_fixture.cc [new file with mode: 0644]
tests/mock/test_fixture.h [new file with mode: 0644]
tests/unit_tests/CMakeLists.txt [new file with mode: 0644]
tests/unit_tests/data/db/.pkgmgr_cert.db [new file with mode: 0644]
tests/unit_tests/data/db/.pkgmgr_cert.db-journal [new file with mode: 0644]
tests/unit_tests/data/db/.pkgmgr_parser.db [new file with mode: 0644]
tests/unit_tests/data/db/.pkgmgr_parser.db-journal [new file with mode: 0644]
tests/unit_tests/data/db_bck/.pkgmgr_cert.db [new file with mode: 0644]
tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal [new file with mode: 0644]
tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal.bck [new file with mode: 0644]
tests/unit_tests/data/db_bck/.pkgmgr_cert.db.bck [new file with mode: 0644]
tests/unit_tests/data/db_bck/.pkgmgr_parser.db [new file with mode: 0644]
tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal [new file with mode: 0644]
tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal.bck [new file with mode: 0644]
tests/unit_tests/data/db_bck/.pkgmgr_parser.db.bck [new file with mode: 0644]
tests/unit_tests/data/packages/org.tizen.alarm.xml [new file with mode: 0644]
tests/unit_tests/data/packages/org.tizen.app-selector.xml [new file with mode: 0644]
tests/unit_tests/data/packages/org.tizen.bluetooth.xml [new file with mode: 0644]
tests/unit_tests/data/rw/list.txt [new file with mode: 0644]
tests/unit_tests/src/test_main.cc [new file with mode: 0644]
tests/unit_tests/src/test_pkg_upgrader.cc [new file with mode: 0644]

index 6b4891e3cc704096137a2729a37f84fc857ee36b..c0181bb71a544558e2f2445fb60f5155fc6488ab 100644 (file)
@@ -45,6 +45,13 @@ SET(CMAKE_C_FLAGS_DEBUG "-O0 -g -fPIE")
 SET(CMAKE_C_FLAGS_RELEASE "-O2 -fPIE")
 
 ADD_SUBDIRECTORY(src)
+ADD_SUBDIRECTORY(tests)
+
+IF(NOT DEFINED MINIMUM_BUILD)
+ENABLE_TESTING()
+SET(PKGMGR_TOOL_UNIT_TESTS pkgmgr-tool_unittests)
+ADD_TEST(NAME ${PKGMGR_TOOL_UNIT_TESTS} COMMAND ${PKGMGR_TOOL_UNIT_TESTS})
+ENDIF(NOT DEFINED MINIMUM_BUILD)
 
 INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/mime.wac.xml DESTINATION /usr/share/mime/packages/)
 INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/mime.tpk.xml DESTINATION /usr/share/mime/packages/)
index 2de373692b6a66f8114b7214b754021f9611cbd3..a5677cffd2dcf421d38446f6a3a2dbe602aeb80a 100644 (file)
@@ -26,26 +26,71 @@ BuildRequires:  pkgconfig(pkgmgr-installer)
 BuildRequires:  pkgconfig(aul)
 BuildRequires:  pkgconfig(storage)
 BuildRequires:  pkgconfig(sqlite3)
+BuildRequires:  pkgconfig(gmock)
 BuildRequires:  pkgmgr-info-parser-devel
 BuildRequires:  pkgmgr-info-parser
 BuildRequires:  fdupes
+%if 0%{?gcov:1}
+BuildRequires:  lcov
+BuildRequires:  zip
+%endif
 Requires(posttrans):  /usr/bin/pkg_initdb
 
 %description
 Packager Manager Tool for packaging
 
+%package -n pkgmgr-tool_unittests
+Summary:    GTest for pkgmgr-tool
+Group:      Development/Libraries
+Requires:   %{name}
+
+%description -n pkgmgr-tool_unittests
+GTest for pkgmgr-tool
+
+%if 0%{?gcov:1}
+%package gcov
+Summary:  pkgmgr-tool API(gcov)
+Group:    System/API
+
+%description gcov
+gcov objects of an pkgmgr-tool
+%endif
+
 %prep
 %setup -q
 cp %{SOURCE1001} .
 
 %build
-%cmake .
+%if 0%{?gcov:1}
+export CFLAGS+=" -fprofile-arcs -ftest-coverage"
+export CXXFLAGS+=" -fprofile-arcs -ftest-coverage"
+export FFLAGS+=" -fprofile-arcs -ftest-coverage"
+export LDFLAGS+=" -lgcov"
+%endif
 
+%cmake .
 %__make %{?_smp_mflags}
+%if 0%{?gcov:1}
+mkdir -p gcov-obj
+find . -name '*.gcno' -exec cp '{}' gcov-obj ';'
+%endif
+
+%check
+ctest -V
+%if 0%{?gcov:1}
+lcov -c --ignore-errors graph --no-external -q -d . -o pkgmgr-tool.info
+genhtml pkgmgr-tool.info -o pkgmgr-tool.out
+zip -r pkgmgr-tool.zip pkgmgr-tool.out
+install -m 0644 pkgmgr-tool.zip %{buildroot}%{_datadir}/gcov/pkgmgr-tool.zip
+%endif
 
 %install
 %make_install
 mkdir -p %{buildroot}%{_sysconfdir}/opt/upgrade
+%if 0%{?gcov:1}
+mkdir -p %{buildroot}%{_datadir}/gcov/obj
+install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj
+%endif
 
 %fdupes %{buildroot}
 
@@ -82,3 +127,11 @@ update-mime-database %{_datadir}/mime
 %attr(0700,root,root) %{_sysconfdir}/opt/upgrade/pkgmgr.patch.sh
 %attr(0700,root,root) /usr/share/fixed_multiuser/scripts/pkgmgr-clear-skel.sh
 %attr(0700,root,root) %{_sysconfdir}/package-manager/pkgmgr-label-initial-image.sh
+
+%files -n pkgmgr-tool_unittests
+%{_bindir}/pkgmgr-tool_unittests
+%{_datadir}/pkgmgr-tool_unittests/*
+%if 0%{?gcov:1}
+%files gcov
+%{_datadir}/gcov/*
+%endif
index a99ab6088db081ee5bad595b942c62795b709f0e..ab2396a618c4e2224b1dc8f436691b0438fd752a 100644 (file)
@@ -110,8 +110,8 @@ static void __make_preload_rw_list(GList *pkg_list)
                info = (struct pkginfo *)pkg_list->data;
                _D("Add [%s][%s][%s] to preload-rw list", info->pkgid,
                                info->version, info->type);
-               snprintf(pkg_info, BUFSZE, "package=\"%s\"\tversion=\"%s\"\t"
-                               "type=\"%s\":\n",
+               snprintf(pkg_info, BUFSZE, "\"package=%s\":\"version=%s\":"
+                               "\"type=%s\":\"removable=true\"\n",
                                info->pkgid, info->version, info->type);
                fwrite(pkg_info, 1, strlen(pkg_info), file);
        }
old mode 100644 (file)
new mode 100755 (executable)
index 6688c88..21fe1ac
@@ -1,22 +1,19 @@
 # Target - sources
-SET(SRCS
-  pkg_upgrade.c
-)
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src SRCS)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)
 
 # Target - definition
 ADD_EXECUTABLE(${TARGET_PKG_UPGRADE} ${SRCS})
 
 # Dependency
 APPLY_PKG_CONFIG(${TARGET_PKG_UPGRADE} PUBLIC
-  INIPARSER_DEPS
-  SQLITE_DEPS
   PKGMGR_INFO_DEPS
-  PKGMGR_DEPS
   PKGMGR_PARSER_DEPS
-  STORAGE_DEPS
   TZPLATFORM_DEPS
   SMACK_DEPS
+  DLOG_DEPS
 )
 
 # Install
-INSTALL(TARGETS ${TARGET_PKG_UPGRADE} DESTINATION bin)
\ No newline at end of file
+INSTALL(TARGETS ${TARGET_PKG_UPGRADE} DESTINATION bin)
+
diff --git a/src/pkg_upgrade/include/backend_invoker.hh b/src/pkg_upgrade/include/backend_invoker.hh
new file mode 100644 (file)
index 0000000..aca83ac
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BACKEND_INVOKER_H_
+#define BACKEND_INVOKER_H_
+
+#include <list>
+#include <string>
+
+#include "common_type.hh"
+
+namespace common_fota {
+
+class BackendInvoker {
+ public:
+  BackendInvoker(std::string pkgid, PkgType type, PkgLocation loc,
+      PkgOperation op, bool removable);
+  BackendInvoker() {}
+
+  int Run() const;
+
+  static int XSystem(const char *argv[]);
+
+ private:
+  std::list<std::string> parameters_;
+};
+
+}  // common_fota
+
+#endif  // BACKEND_INVOKER_H_
diff --git a/src/pkg_upgrade/include/common_type.hh b/src/pkg_upgrade/include/common_type.hh
new file mode 100644 (file)
index 0000000..2e657e1
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMMON_TYPE_H_
+#define COMMON_TYPE_H_
+
+#include <memory>
+#include <string>
+
+namespace common_fota {
+
+enum class PkgType {
+  TPK,
+  WGT,
+  UNKNOWN
+};
+
+enum class PkgLocation {
+  RO,
+  RW,
+  UNKNOWN
+};
+
+enum class PkgOperation {
+  INSTALL,
+  UPDATE,
+  UNINSTALL,
+  UNINSTALL_KEEP_RW_DATA,
+  COMPLEX
+};
+
+class PkgContext {
+ public:
+  PkgContext(std::string id, std::string version, std::string type,
+      bool read_only, bool removable = false)
+      : id_(std::move(id)), version_(std::move(version)),
+        type_(std::move(type)), read_only_(read_only), removable_(removable) {
+    if (read_only)
+      removable_ = false;
+  }
+
+  const std::string& GetId() const { return id_; }
+  const std::string& GetVersion() const { return version_; }
+  PkgType GetType() const {
+    if (type_ == "wgt" )
+      return PkgType::WGT;
+    return PkgType::TPK;
+  }
+  PkgLocation GetLocation() const {
+    if (read_only_)
+      return PkgLocation::RO;
+    return PkgLocation::RW;
+  }
+  bool IsReadOnly() const { return read_only_; }
+  bool IsRemovable() const { return removable_; }
+
+ private:
+  std::string id_;
+  std::string version_;
+  std::string type_;
+  bool read_only_;
+  bool removable_;
+};
+
+}  // common_fota
+
+#endif  // COMMON_TYPE_H_
diff --git a/src/pkg_upgrade/include/file_logbackend.hh b/src/pkg_upgrade/include/file_logbackend.hh
new file mode 100644 (file)
index 0000000..0c23b6e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FILE_LOGBACKEND_H_
+#define FILE_LOGBACKEND_H_
+
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include "logging.hh"
+
+namespace utils {
+
+class FileLogBackend : public ILogBackend {
+ public:
+  FileLogBackend(std::string file_name, int rotation_size, int max_rotation);
+  void WriteLog(LogLevel level, const std::string& tag,
+      const std::string& logstr) override;
+  void WriteLogToFile();
+
+ private:
+  bool Rotate();
+  int GetFileSize(const std::string& file_name);
+  std::string GetTimeStamp();
+  std::string GetPid();
+
+  std::string file_name_;
+  int rotation_size_;
+  int max_rotation_;
+  std::unique_ptr<std::ostringstream> log_stream_;
+};
+
+}  // namespace utils
+
+#endif  // FILE_LOGBACKEND_H_
diff --git a/src/pkg_upgrade/include/logging.hh b/src/pkg_upgrade/include/logging.hh
new file mode 100644 (file)
index 0000000..6ed63bc
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOGGING_H_
+#define LOGGING_H_
+
+#include <dlog.h>
+
+#ifndef PROJECT_TAG
+#define PROJECT_TAG ""
+#endif
+
+#ifdef LOG
+#undef LOG
+#endif
+
+#include <cassert>
+#include <climits>
+#include <cstdio>
+#include <cstring>
+#include <iomanip>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#ifndef __FILENAME__
+#define __FILENAME__                                                           \
+    (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
+#endif
+
+namespace utils {
+
+enum class LogLevel {
+  LOG_ERROR,
+  LOG_WARNING,
+  LOG_INFO,
+  LOG_DEBUG,
+};
+
+log_priority LogLevelToPriority(LogLevel level);
+
+template<LogLevel> struct LogTag;
+template<> struct LogTag<LogLevel::LOG_ERROR> {
+  static constexpr const char* value = "\033[1;31m| ERROR   |\033[0m";
+};
+template<> struct LogTag<LogLevel::LOG_WARNING> {
+  static constexpr const char* value = "\033[1;33m| WARNING |\033[0m";
+};
+template<> struct LogTag<LogLevel::LOG_INFO>  {
+  static constexpr const char* value = "\033[1;32m| INFO    |\033[0m";
+};
+template<> struct LogTag<LogLevel::LOG_DEBUG> {
+  static constexpr const char* value = "\033[0m| DEBUG   |\033[0m";
+};
+
+template <class charT, class traits = std::char_traits<charT>>
+class StringStream : private std::basic_ostringstream<charT, traits> {
+ public:
+  using std::basic_ostringstream<charT, traits>::str;
+
+  template <class T>
+  StringStream&  operator<<(const T& value) {
+    static_cast<std::basic_ostringstream<charT, traits> &>(*this) << value;
+    return *this;
+  }
+};
+
+// Interface class for logging backends. The custom LogBackend which wants
+// log using LOG() macro should be implement following interface.
+class ILogBackend {
+ public:
+  virtual void WriteLog(LogLevel level, const std::string& tag,
+      const std::string& logstr) = 0;
+};
+
+class DLogBackend : public ILogBackend {
+ public:
+  void WriteLog(LogLevel level, const std::string& tag,
+      const std::string& logstr) override {
+    dlog_print(LogLevelToPriority(level), tag.c_str(), "%s",
+        Escape(logstr).c_str());
+  }
+
+ private:
+  // Since LogCatcher passes input to dlog_print(), the input which contains
+  // format string(such as %d, %n) can cause unexpected result.
+  // This is simple function to escape '%'.
+  // NOTE: Is there any gorgeous way instead of this?
+  std::string Escape(const std::string& str) const {
+    std::string escaped = std::string(str);
+    size_t start_pos = 0;
+    std::string from = "%";
+    std::string to = "%%";
+    while ((start_pos = escaped.find(from, start_pos)) != std::string::npos) {
+      escaped.replace(start_pos, from.length(), to);
+      start_pos += to.length();
+    }
+    return escaped;
+  }
+};
+
+class LogCore {
+ public:
+  // Do not call this function at destructor of global object
+  static LogCore& GetCore() {
+    static LogCore core;
+    return core;
+  }
+
+  void AddLogBackend(std::shared_ptr<ILogBackend> backend) {
+    backend_list_.emplace_back(backend);
+  }
+
+  void Log(LogLevel level, const std::string& tag, const std::string& log) {
+    for (auto backend : backend_list_)
+      backend->WriteLog(level, tag, log);
+  }
+
+ private:
+  LogCore() {
+    // add default dlog backend
+    AddLogBackend(std::shared_ptr<ILogBackend>(new DLogBackend()));
+  }
+  ~LogCore() = default;
+  LogCore(const LogCore&) = delete;
+  LogCore& operator=(const LogCore&) = delete;
+
+  std::vector<std::shared_ptr<ILogBackend>> backend_list_;
+};
+
+class LogCatcher {
+ public:
+  LogCatcher(LogLevel level, const char* tag)
+    : level_(level), tag_(tag) { }
+
+  void operator&(const StringStream<char>& str) const {
+    LogCore::GetCore().Log(level_, tag_, str.str());
+  }
+
+ private:
+  LogLevel level_;
+  std::string tag_;
+};
+
+}  // namespace utils
+
+
+inline static const constexpr char* __tag_for_logging() {
+  return "";
+}
+
+inline static const constexpr char* __tag_for_project() {
+  return PROJECT_TAG;
+}
+
+// To be defined in class namespace if user want different log tag for given
+// scope
+#define SCOPE_LOG_TAG(TAG)                                                     \
+  inline static const constexpr char* __tag_for_logging() {                    \
+    return #TAG;                                                               \
+  }                                                                            \
+
+// Simple logging macro of following usage:
+//   LOG(LEVEL) << object_1 << object_2 << object_n;
+//     where:
+//       LEVEL = ERROR | WARNING | INFO | DEBUG
+#define LOG(LEVEL)                                                             \
+    ::utils::LogCatcher(                                                       \
+      ::utils::LogLevel::LOG_ ## LEVEL, __tag_for_project())                   \
+      & ::utils::StringStream<char>()                                          \
+      << std::string(::utils::LogTag<::utils::LogLevel::LOG_ ## LEVEL>::value) \
+      << " " << std::setw(25) << std::left << __tag_for_logging()              \
+      << " : " << std::setw(36)                                                \
+      << (std::string(__FILENAME__) + ":" + std::to_string(__LINE__)).c_str()  \
+      << std::setw(0) << " : "                                                 \
+
+#endif  // LOGGING_H_
diff --git a/src/pkg_upgrade/include/pkg_finder.hh b/src/pkg_upgrade/include/pkg_finder.hh
new file mode 100644 (file)
index 0000000..5259c3b
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PKG_FINDER_H_
+#define PKG_FINDER_H_
+
+#include <memory>
+#include <list>
+#include <string>
+
+#include <pkgmgr-info.h>
+#include <libxml/xmlreader.h>
+
+#include "common_type.hh"
+
+namespace common_fota {
+
+class PkgFinder {
+ public:
+  PkgFinder();
+  ~PkgFinder();
+  int Find();
+  const std::list<PkgContext>& GetOldPkgs() { return old_pkgs_; }
+  const std::list<PkgContext>& GetNewPkgs() { return new_pkgs_; }
+  void SetManifestDir(std::string dir);
+  void SetPreloadRwListPath(std::string path);
+
+ private:
+  static int PkgidListCb(const pkgmgrinfo_pkginfo_h handle, void* user_data);
+  int FindPreloadPkgidFromDb(bool read_only = true);
+  int FindPreloadPkgidFromXml(const std::string& xml_directory);
+  int FindPreloadPkgidFromFile();
+  std::string GetValidManifest(std::string manifest);
+  std::string FindInfoFromXml(const std::string& manifest,
+      const std::string& find_info);
+  int MoveToChildElement(xmlTextReaderPtr reader, int depth);
+  void AddRwPkgInfoFromFile(const char* info_str);
+  std::string GetToken(const char* pBuf, const char* pKey);
+  void StrTrim(char *input);
+  int UnzipFileOnlyToPath(const char* dest_path, const char* unzip_to);
+
+ private:
+  std::list<PkgContext> old_pkgs_;
+  std::list<PkgContext> new_pkgs_;
+  bool read_only_ = true;
+  std::string manifest_dir_;
+  std::string preload_rw_list_path_;
+};
+
+}  // common_fota
+
+#endif  // PKG_FINDER_H_
diff --git a/src/pkg_upgrade/include/pkg_upgrade.h b/src/pkg_upgrade/include/pkg_upgrade.h
deleted file mode 100644 (file)
index de1e8de..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef PKG_FOTA_H_
-#define PKG_FOTA_H_
-
-
-#define TOKEN_TYPE_STR         "type="
-#define TOKEN_PKGID_STR                "package="
-#define TOKEN_VERSION_STR      "version="
-#define TOKEN_OPERATION_STR    "op="
-#define TOKEN_REMOVE_STR       "removable="
-#define TOKEN_UPDATE_STR       "update="
-
-#define SEPERATOR_END          '"'
-#define SEPERATOR_MID          ':'
-
-
-#define ASCII(s) (const char *)s
-#define XMLCHAR(s) (const xmlChar *)s
-
-#define BUF_SIZE 1024
-#define DIRECTORY_PERMISSION_755 0755
-#define FOTA_RESULT_FILE       tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \
-       "pkgmgr/fota/result.txt")
-
-#ifndef FREE_AND_NULL
-#define        FREE_AND_NULL(ptr) do { \
-               if (ptr) {      \
-                       free((void *)ptr);      \
-                       ptr = NULL;     \
-               } \
-} while (0)
-#endif
-
-#ifndef FREE_AND_STRDUP
-#define        FREE_AND_STRDUP(from, to) do {  \
-               if (to) free((void *)to);       \
-               if (from) to = strdup(from);    \
-} while (0)
-#endif
-
-#define _LOGE(fmt, arg...) do { \
-       int fd = 0;\
-       FILE* file = NULL;\
-       file = fopen(FOTA_RESULT_FILE, "a");\
-       if (file == NULL) break;\
-       fprintf(file, "[PKG_FOTA][%5d][err]  "fmt"", getpid(), ##arg); \
-       fflush(file);\
-       fd = fileno(file);\
-       fsync(fd);\
-       fclose(file);\
-       fprintf(stderr, "[PKG_FOTA][%5d][err]  "fmt"", getpid(), ##arg); \
-} while (0)
-
-#define        retvm_if(expr, val, fmt, arg...) do {   \
-       if (expr) {     \
-               _LOGE("(%s)"fmt, #expr, ##arg); \
-               return (val);   \
-       }       \
-} while (0)
-
-#define        err_if(expr, fmt, arg...) do {  \
-       if (expr) { \
-               _LOGE("(%s)"fmt, #expr, ##arg); \
-       }       \
-} while (0)
-
-#define tryvm_if(expr, val, fmt, arg...) do { \
-       if (expr) { \
-               _LOGE("(%s)"fmt, #expr, ##arg); \
-               val; \
-               goto catch; \
-       } \
-} while (0)
-
-typedef enum {
-       PKG_IS_NOT_EXIST = 0,
-       PKG_IS_SAME,
-       PKG_IS_UPDATED,
-       PKG_IS_INSERTED,
-       PKG_IS_OLD
-} COMPARE_RESULT;
-
-typedef enum {
-       PKG_NEED_NOTHING = 0,
-       PKG_NEED_INSTALL,
-       PKG_NEED_UNINSTALL,
-       PKG_NEED_ROUPDATE,
-       PKG_NEED_UPDATE_TO_RW,
-       PKG_NEED_RWUNINSTALL,
-       PKG_NEED_UPDATE_TO_RO,
-       PKG_NEED_RO_DBREMOVE,
-       PKG_NEED_RO_UNINSTALL_KEEPRWDATA,
-       PKG_NEED_PRELOADRW_INSTALL
-} UPGRADE_OPRATION;
-
-enum rpm_request_type {
-       INSTALL_REQ,
-       UNINSTALL_REQ,
-       UPGRADE_REQ
-};
-
-#endif /* PKG_FOTA_H_ */
diff --git a/src/pkg_upgrade/include/pkg_upgrader.hh b/src/pkg_upgrade/include/pkg_upgrader.hh
new file mode 100644 (file)
index 0000000..96f446d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PKG_UPGRADER_H_
+#define PKG_UPGRADER_H_
+
+#include <string>
+
+#include "backend_invoker.hh"
+#include "common_type.hh"
+
+namespace common_fota {
+
+class PkgUpgrader {
+ public:
+  PkgUpgrader(const PkgContext& context, PkgOperation pkg_op);
+  PkgUpgrader(std::string id);
+  virtual ~PkgUpgrader() = default;
+
+  PkgType GetType() const;
+  PkgLocation GetLocation() const;
+  PkgOperation GetOperation() const;
+  std::string GetId() const;
+  std::string GetVersion() const;
+  const BackendInvoker& GetBackendInvoker() const;
+  int CompareVersion(const PkgUpgrader& pkg) const;
+
+  virtual bool Upgrade() = 0;
+
+ private:
+  PkgType type_;
+  PkgLocation loc_;
+  PkgOperation op_;
+  std::string id_;
+  std::string version_;
+  BackendInvoker backend_;
+};
+
+}  // namespace common_fota
+
+#endif  // PKG_UPGRADER_H_
diff --git a/src/pkg_upgrade/include/pkg_upgrader_factory.hh b/src/pkg_upgrade/include/pkg_upgrader_factory.hh
new file mode 100644 (file)
index 0000000..580a3fa
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PKG_UPGRADER_FACTORY_H_
+#define PKG_UPGRADER_FACTORY_H_
+
+#include <list>
+#include <memory>
+#include <string>
+
+#include "pkg_finder.hh"
+#include "pkg_upgrader.hh"
+#include "common_type.hh"
+
+namespace common_fota {
+
+class PkgUpgraderFactory {
+ public:
+  std::list<std::unique_ptr<PkgUpgrader>> MakeList(PkgFinder* finder);
+
+ private:
+  std::list<std::unique_ptr<PkgUpgrader>> Merge(
+      const std::list<PkgContext>& old_pkgs,
+      const std::list<PkgContext>& new_pkgs);
+  const PkgContext* FindPkgById(const std::list<PkgContext>& pkgs,
+      std::string id);
+};
+
+}  // common_fota
+
+#endif  // PKG_UPGRADER_FACTORY_H_
diff --git a/src/pkg_upgrade/include/ro2rw_upgrader.hh b/src/pkg_upgrade/include/ro2rw_upgrader.hh
new file mode 100644 (file)
index 0000000..8a30a85
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RO2RW_UPGRADER_H_
+#define RO2RW_UPGRADER_H_
+
+#include "pkg_upgrader.hh"
+
+namespace common_fota {
+
+class Ro2RwUpgrader : public PkgUpgrader {
+ public:
+  Ro2RwUpgrader(std::unique_ptr<PkgUpgrader> old_pkg,
+      std::unique_ptr<PkgUpgrader> new_pkg);
+  virtual ~Ro2RwUpgrader() = default;
+  bool Upgrade() override;
+
+ private:
+  int UnzipFiles(const char* dest_path);
+  int UnzipXml(const std::string& pkgid);
+  int UnzipData(const std::string& pkgid, const std::string& dest);
+  int UnzipPkgFromZip(const std::string& pkgid);
+
+ private:
+  std::unique_ptr<PkgUpgrader> old_pkg_;
+  std::unique_ptr<PkgUpgrader> new_pkg_;
+};
+
+}  // common_fota
+
+#endif  // RO2RW_UPGRADER_H_
diff --git a/src/pkg_upgrade/include/rw2ro_upgrader.hh b/src/pkg_upgrade/include/rw2ro_upgrader.hh
new file mode 100644 (file)
index 0000000..1fb0d01
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RW2RO_UPGRADER_H_
+#define RW2RO_UPGRADER_H_
+
+#include "pkg_upgrader.hh"
+
+namespace common_fota {
+
+class Rw2RoUpgrader : public PkgUpgrader {
+ public:
+  Rw2RoUpgrader(std::unique_ptr<PkgUpgrader> old_pkg,
+      std::unique_ptr<PkgUpgrader> new_pkg);
+  virtual ~Rw2RoUpgrader() = default;
+  bool Upgrade() override;
+
+ private:
+  std::unique_ptr<PkgUpgrader> old_pkg_;
+  std::unique_ptr<PkgUpgrader> new_pkg_;
+};
+
+}  // common_fota
+
+#endif  // RW2RO_UPGRADER_H_
diff --git a/src/pkg_upgrade/include/rw_upgrader.hh b/src/pkg_upgrade/include/rw_upgrader.hh
new file mode 100644 (file)
index 0000000..b2a03bc
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RW_UPGRADER_H_
+#define RW_UPGRADER_H_
+
+#include "ro2rw_upgrader.hh"
+
+namespace common_fota {
+
+class RwUpgrader : public Ro2RwUpgrader {
+ public:
+  RwUpgrader(std::unique_ptr<PkgUpgrader> new_pkg)
+      : Ro2RwUpgrader(nullptr, std::move(new_pkg)) {}
+  virtual ~RwUpgrader() = default;
+};
+
+}  // common_fota
+
+#endif  // RW_UPGRADER_H_
diff --git a/src/pkg_upgrade/include/simple_upgrader.hh b/src/pkg_upgrade/include/simple_upgrader.hh
new file mode 100644 (file)
index 0000000..0d12388
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SIMPLE_UPGRADER_H_
+#define SIMPLE_UPGRADER_H_
+
+#include "pkg_upgrader.hh"
+#include "pkg_finder.hh"
+
+namespace common_fota {
+
+class SimpleUpgrader : public PkgUpgrader {
+ public:
+  SimpleUpgrader(const PkgContext& context, PkgOperation pkg_op);
+  bool Upgrade() override;
+};
+
+}  // common_fota
+
+#endif  // SIMPLE_UPGRADER_H_
\ No newline at end of file
diff --git a/src/pkg_upgrade/include/upgrader.hh b/src/pkg_upgrade/include/upgrader.hh
new file mode 100644 (file)
index 0000000..f4eeb51
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UPGRADER_H_
+#define UPGRADER_H_
+
+#include <list>
+#include <memory>
+
+#include "file_logbackend.hh"
+#include "pkg_finder.hh"
+#include "pkg_upgrader.hh"
+
+namespace common_fota {
+
+class Upgrader {
+ public:
+  Upgrader();
+  bool Process(PkgFinder* finder);
+  const std::list<std::unique_ptr<PkgUpgrader>>& GetSuccessList() const;
+  const std::list<std::unique_ptr<PkgUpgrader>>& GetFailureList() const;
+  void SetDbPath(const std::string& path);
+
+ private:
+  int CheckAndRestoreBackupDbs();
+  int CheckAndRestoreBackup(const std::string& origin_path);
+  int BackupDb(const std::string& src_path, const std::string& dest_path);
+  int MakeBackupDbs();
+  void RemoveBackupPath(const std::string& origin_path);
+  void RemoveBackupDbs();
+  int SetDbPermission(const std::string& path);
+  int BackupFile(const std::string& src_path, const std::string& dest_path);
+  int CreateBackupFlag(const std::string& path);
+  int CheckBackupFlag(const std::string& path);
+  int RemoveBackupFlag(const std::string& path);
+
+ private:
+  std::shared_ptr<utils::FileLogBackend> logger_;
+  std::list<std::unique_ptr<PkgUpgrader>> success_list_;
+  std::list<std::unique_ptr<PkgUpgrader>> failure_list_;
+  std::string parser_db_;
+  std::string parser_db_journal_;
+  std::string cert_db_;
+  std::string cert_db_journal_;
+};
+
+}  // common_fota
+
+#endif  // UPGRADER_H_
diff --git a/src/pkg_upgrade/pkg_upgrade.c b/src/pkg_upgrade/pkg_upgrade.c
deleted file mode 100644 (file)
index 96d628f..0000000
+++ /dev/null
@@ -1,1864 +0,0 @@
-/*
- * pkg-fota
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#define _GNU_SOURCE
-
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <sys/smack.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <iniparser.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <libxml/xmlreader.h>
-#include <sqlite3.h>
-#include <pwd.h>
-
-#include <package-manager-types.h>
-#include <package-manager.h>
-#include <pkgmgr_parser.h>
-#include <pkgmgr-info.h>
-#include "include/pkg_upgrade.h"
-
-#include <tzplatform_config.h>
-
-#define USR_MANIFEST_DIRECTORY tzplatform_getenv(TZ_SYS_RO_PACKAGES)
-#define OPT_USR_MANIFEST_DIRECTORY     tzplatform_getenv(TZ_SYS_RW_PACKAGES)
-#define RW_PKG_DIRECTORY       tzplatform_getenv(TZ_SYS_RW_APP)
-#define SKEL_DIRECTORY tzplatform_mkpath(TZ_SYS_ETC, "skel/apps_rw")
-
-#define PKGMGR_FOTA_PATH       tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \
-       "pkgmgr/fota")
-#define PKGID_LIST_FROM_DB_FILE        tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \
-       "pkgmgr/fota/pkgid_list_from_db.txt")
-#define PKGID_LIST_FROM_XML_FILE \
-       tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \
-       "pkgmgr/fota/pkgid_list_from_xml.txt")
-#define PRELOAD_RW_PKG_LIST \
-       tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \
-       "pkgmgr/fota/.all_preload_rw_list")
-#define DBPATH tzplatform_mkpath(TZ_SYS_DB, "/.pkgmgr_parser.db")
-#define JOURNAL_DBPATH tzplatform_mkpath(TZ_SYS_DB, \
-       "/.pkgmgr_parser.db-journal")
-#define CERT_DBPATH tzplatform_mkpath(TZ_SYS_DB, "/.pkgmgr_cert.db")
-#define JOURNAL_CERT_DBPATH tzplatform_mkpath(TZ_SYS_DB, \
-       "/.pkgmgr_cert.db-journal")
-#define OPT_ZIP_FILE                   "/usr/system/RestoreDir/opt.zip"
-#define ALL_PRELOAD_RW_PKG_LIST "/opt/usr/share/.all_preload_rw_list"
-#define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)
-#define APPFW_USER "app_fw"
-
-struct pkginfo {
-       char *pkgid;
-       char *version;
-       char *type;
-};
-
-static char *unzip_path[BUF_SIZE] = {
-       "opt/usr/globalapps",
-       "opt/etc/skel/apps_rw",
-       NULL
-};
-
-static void __free_pkginfo(gpointer data)
-{
-       struct pkginfo *info = (struct pkginfo *)data;
-       free(info->pkgid);
-       free(info->version);
-       free(info->type);
-       free(info);
-}
-
-float __get_elapsed_time()
-{
-       static long start_time = 0;
-       long endtime = 0;
-       struct timeval tv;
-
-       if (start_time == 0) {
-               gettimeofday(&tv, NULL);
-               start_time = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
-       }
-
-       gettimeofday(&tv, NULL);
-       endtime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
-
-       return (endtime - start_time)/1000.0;
-}
-
-#define _LOG(fmt, arg...) do { \
-       int fd = 0; \
-       FILE *file = NULL; \
-       file = fopen(FOTA_RESULT_FILE, "a"); \
-       if (file == NULL) break; \
-       fprintf(file, "[PKG_FOTA][%5d][%10.3fs]  "fmt"", getpid(), \
-               __get_elapsed_time(), ##arg); \
-       fflush(file); \
-       fd = fileno(file); \
-       fsync(fd); \
-       fclose(file); \
-       fprintf(stderr, "[PKG_FOTA][%5d][%10.3fs]  "fmt"", getpid(), \
-               __get_elapsed_time(), ##arg); \
-} while (0)
-
-int remove_directory(const char *path)
-{
-       DIR *dir;
-       struct dirent *entry;
-       size_t path_len = strlen(path);
-       int ret = 0;
-       int iterate_ret;
-       char buf[BUF_SIZE] = {0};
-       size_t len;
-       struct stat statbuf;
-
-       dir = opendir(path);
-       if (!dir)
-               return -1;
-
-       while (!ret && (entry = readdir(dir))) {
-               iterate_ret = -1;
-
-               if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
-                       continue;
-
-               len = path_len + strlen(entry->d_name) + 2;
-               snprintf(buf, len, "%s/%s", path, entry->d_name);
-
-               if (!stat(buf, &statbuf)) {
-                       if (S_ISDIR(statbuf.st_mode))
-                               iterate_ret = remove_directory(buf);
-                       else
-                               iterate_ret = unlink(buf);
-               }
-               ret = iterate_ret;
-       }
-
-       closedir(dir);
-       if (!ret)
-               ret = rmdir(path);
-
-       return ret;
-}
-
-static void __iter_cb(gpointer key, gpointer value, gpointer user_data)
-{
-
-       FILE *file;
-       char *pkgid;
-       char *version;
-       char *type;
-       char pkg_info[BUF_SIZE];
-       pkgmgrinfo_pkginfo_h info;
-
-       if (user_data == NULL || key == NULL)
-               return;
-
-       file = user_data;
-       pkgid = key;
-
-       if (pkgmgrinfo_pkginfo_get_pkginfo(pkgid, &info)) {
-               _LOGE("failed to get pkginfo of %s\n", pkgid);
-               return;
-       }
-
-       if (pkgmgrinfo_pkginfo_get_version(info, &version)) {
-               pkgmgrinfo_pkginfo_destroy_pkginfo(info);
-               return;
-       }
-
-       if (pkgmgrinfo_pkginfo_get_type(info, &type)) {
-               pkgmgrinfo_pkginfo_destroy_pkginfo(info);
-               return;
-       }
-
-       snprintf(pkg_info, BUF_SIZE,
-                       "package=\"%s\"\tversion=\"%s\"\ttype=\"%s\":\n",
-                       pkgid, version, type);
-       fwrite(pkg_info, 1, strlen(pkg_info), file);
-       pkgmgrinfo_pkginfo_destroy_pkginfo(info);
-}
-
-static void __make_preload_rw_list(GHashTable *preload_rw_table)
-{
-       if (preload_rw_table == NULL) {
-               _LOG("preload_rw_table is null\n");
-               return;
-       }
-       FILE *file = NULL;
-
-       char buf[BUF_SIZE];
-       char tmp_path[BUF_SIZE];
-       snprintf(tmp_path, BUF_SIZE, "%s.tmp", ALL_PRELOAD_RW_PKG_LIST);
-
-       if (rename(ALL_PRELOAD_RW_PKG_LIST, tmp_path)) {
-               if (errno != ENOENT)
-                       _LOG("can not backup preload rw pkg list: %d", errno);
-       }
-
-       file = fopen(ALL_PRELOAD_RW_PKG_LIST, "w");
-       if (file == NULL) {
-               _LOG("can not open [%s]: %s\n", ALL_PRELOAD_RW_PKG_LIST,
-                               strerror_r(errno, buf, sizeof(buf)));
-               return;
-       }
-       g_hash_table_foreach(preload_rw_table, __iter_cb, file);
-       fsync(fileno(file));
-       fclose(file);
-       if (remove(tmp_path))
-               _LOG("cannot remove backup file(%s): %d", tmp_path, errno);
-}
-
-static int __is_dir(const char *dirname)
-{
-       struct stat stFileInfo;
-
-       retvm_if(dirname == NULL, -1, "dirname == NULL\n");
-       retvm_if(stat(dirname, &stFileInfo) < 0, -1,
-               "stFileInfo is not enough\n");
-
-       if (S_ISDIR(stFileInfo.st_mode))
-               return 0;
-       return -1;
-}
-
-static int __xsystem(const char *argv[])
-{
-       int status = 0;
-       pid_t pid;
-       pid = fork();
-       switch (pid) {
-       case -1:
-               perror("fork failed");
-               return -1;
-       case 0:
-               /* child */
-               execvp(argv[0], (char *const *)argv);
-               _exit(-1);
-       default:
-               /* parent */
-               break;
-       }
-       if (waitpid(pid, &status, 0) == -1) {
-               perror("waitpid failed");
-               return -1;
-       }
-       if (WIFSIGNALED(status)) {
-               perror("signal");
-               return -1;
-       }
-       if (!WIFEXITED(status)) {
-               /* shouldn't happen */
-               perror("should not happen");
-               return -1;
-       }
-       return WEXITSTATUS(status);
-}
-
-static int __check_pkgmgr_fota_dir()
-{
-       int ret = 0;
-
-       if (__is_dir(PKGMGR_FOTA_PATH) < 0) {
-               const char *mkdir_argv[] =  { "/bin/mkdir",
-                       "-p", PKGMGR_FOTA_PATH, NULL };
-               ret = __xsystem(mkdir_argv);
-               retvm_if(ret != 0, -1, "mkdir_argv error [%d]\n", ret);
-       }
-
-       return 0;
-}
-
-static int __remove_pkgid_list()
-{
-       int ret = 0;
-
-       if (access(FOTA_RESULT_FILE, R_OK) == 0) {
-               ret = remove(FOTA_RESULT_FILE);
-               err_if(ret < 0, "remove[%s] failed", FOTA_RESULT_FILE);
-       }
-
-       if (access(PKGID_LIST_FROM_DB_FILE, R_OK) == 0) {
-               ret = remove(PKGID_LIST_FROM_DB_FILE);
-               err_if(ret < 0, "remove[%s] failed", PKGID_LIST_FROM_DB_FILE);
-       }
-
-       if (access(PKGID_LIST_FROM_XML_FILE, R_OK) == 0) {
-               ret = remove(PKGID_LIST_FROM_XML_FILE);
-               err_if(ret < 0, "remove[%s] failed", PKGID_LIST_FROM_XML_FILE);
-       }
-
-       return 0;
-}
-
-static int __make_pkgid_list(const char *file_path, char *pkgid,
-               char *version, char *type, bool is_update)
-{
-       FILE *fp;
-
-       if (NULL == pkgid)
-               return 0;
-
-       fp = fopen(file_path, "a+");
-       if (NULL == fp)
-               return -1;
-
-       fprintf(fp, "%s\"%s\"   %s\"%s\"   %s\"%s\"   %s\"%s\":\n",
-                       TOKEN_PKGID_STR, pkgid,
-                       TOKEN_VERSION_STR, version,
-                       TOKEN_TYPE_STR, type,
-                       TOKEN_UPDATE_STR, (is_update) ? "true" : "false");
-
-       fclose(fp);
-
-       return 0;
-}
-
-static int __insert_preload_rw_table(GHashTable *preload_rw_table,
-               const char *pkgid, const char *version, const char *type)
-{
-       struct pkginfo *info;
-       char *package;
-
-       info = calloc(1, sizeof(struct pkginfo));
-       if (info == NULL) {
-               _LOGE("out of memory");
-               return -1;
-       }
-
-       info->pkgid = strdup(pkgid);
-       if (info->pkgid == NULL) {
-               _LOGE("out of memory");
-               __free_pkginfo((struct pkginfo *)info);
-               return -1;
-       }
-
-       info->version = strdup(version);
-       if (info->version == NULL) {
-               _LOGE("out of memory");
-               __free_pkginfo((struct pkginfo *)info);
-               return -1;
-       }
-
-       info->type = strdup(type);
-       if (info->type == NULL) {
-               _LOGE("out of memory");
-               __free_pkginfo((struct pkginfo *)info);
-               return -1;
-       }
-
-       package = strdup(pkgid);
-       if (package == NULL) {
-               _LOGE("out of memory");
-               __free_pkginfo((struct pkginfo *)info);
-               return -1;
-       }
-
-       g_hash_table_insert(preload_rw_table, package, info);
-       return 0;
-}
-
-static int __delete_preload_rw_table(GHashTable *preload_rw_table,
-               const char *pkgid)
-{
-       gboolean removed;
-       removed = g_hash_table_remove(preload_rw_table, pkgid);
-       return removed ? 0 : -1;
-}
-
-static int __pkgid_list_cb(const pkgmgrinfo_pkginfo_h handle, void *user_data)
-{
-       int ret = -1;
-       char *pkgid = NULL;
-       char *version = NULL;
-       char *type = NULL;
-       bool is_update = false;
-
-       ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid);
-       err_if(ret < 0, "pkgmgrinfo_pkginfo_get_pkgid failed");
-
-       ret = pkgmgrinfo_pkginfo_get_version(handle, &version);
-       err_if(ret < 0, "pkgmgrinfo_pkginfo_get_version failed");
-
-       ret = pkgmgrinfo_pkginfo_get_type(handle, &type);
-       err_if(ret < 0, "pkgmgrinfo_pkginfo_get_type failed");
-
-       ret = pkgmgrinfo_pkginfo_is_update(handle, &is_update);
-       err_if(ret < 0, "pkgmgrinfo_pkginfo_is_update failed");
-
-       ret = __make_pkgid_list((char *)user_data, pkgid,
-                       version, type, is_update);
-       return ret;
-}
-
-static int __preload_rw_pkgid_list_cb(const pkgmgrinfo_pkginfo_h handle,
-               void *user_data)
-{
-       int ret;
-       char *pkgid;
-       char *version;
-       char *type;
-       GHashTable *preload_rw_table = (GHashTable *)user_data;
-
-       ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid);
-       if (ret < 0) {
-               _LOGE("pkgmgrinfo_pkginfo_get_pkgid failed\n");
-               return -1;
-       }
-
-       ret = pkgmgrinfo_pkginfo_get_version(handle, &version);
-       if (ret < 0) {
-               _LOGE("pkgmgrinfo_pkginfo_get_version failed\n");
-               return -1;
-       }
-
-       ret = pkgmgrinfo_pkginfo_get_type(handle, &type);
-       if (ret < 0) {
-               _LOGE("pkgmgrinfo_pkginfo_get_type failed\n");
-               return -1;
-       }
-
-       ret = __insert_preload_rw_table(preload_rw_table, pkgid, version, type);
-       if (ret < 0) {
-               _LOGE("__insert_preload_rw_table failed\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-static void __str_trim(char *input)
-{
-       char *trim_str = input;
-
-       if (input == NULL)
-               return;
-
-       while (*input != 0) {
-               if (!isspace(*input)) {
-                       *trim_str = *input;
-                       trim_str++;
-               }
-               input++;
-       }
-
-       *trim_str = 0;
-       return;
-}
-
-static char *__getvalue(const char *pBuf, const char *pKey, int depth)
-{
-       const char *p = NULL;
-       const char *pStart = NULL;
-       const char *pEnd = NULL;
-
-       p = strstr(pBuf, pKey);
-       if (p == NULL)
-               return NULL;
-
-       pStart = p + strlen(pKey) + depth;
-       pEnd = strchr(pStart, SEPERATOR_END);
-       if (pEnd == NULL) {
-               pEnd = strchr(pStart, SEPERATOR_MID);
-               if (pEnd == NULL)
-                       return NULL;
-       }
-
-       size_t len = pEnd - pStart;
-       if (len <= 0)
-               return NULL;
-
-       char *pRes = (char *)malloc(len + 1);
-       if (pRes == NULL) {
-               _LOG("malloc failed.\n");
-               return NULL;
-       }
-       strncpy(pRes, pStart, len);
-       pRes[len] = 0;
-
-       return pRes;
-}
-
-static int __compare_pkgid(char *file_path, char *fota_pkgid,
-               char *fota_version, bool *is_updated)
-{
-       retvm_if(file_path == NULL, -1, "file_path is null.\n");
-       retvm_if(fota_pkgid == NULL, -1, "fota_pkgid is null.\n");
-       retvm_if(fota_version == NULL, -1, "fota_version is null.\n");
-
-       int ret = PKG_IS_NOT_EXIST;
-       FILE *fp = NULL;
-       char buf[BUF_SIZE] = {0};
-       char *pkgid = NULL;
-       char *version = NULL;
-       char *update = NULL;
-       int compare = PMINFO_VERSION_SAME;
-
-       fp = fopen(file_path, "r");
-       retvm_if(fp == NULL, -1, "Fail get : %s\n", file_path);
-
-       while (fgets(buf, BUF_SIZE, fp) != NULL) {
-               __str_trim(buf);
-
-               pkgid = __getvalue(buf, TOKEN_PKGID_STR, 1);
-               if (pkgid == NULL) {
-                       _LOG("pkgid is null\n");
-                       continue;
-               }
-
-               version = __getvalue(buf, TOKEN_VERSION_STR, 1);
-               if (version == NULL) {
-                       FREE_AND_NULL(pkgid);
-                       _LOG("compare_data is null\n");
-                       continue;
-               }
-
-               update = __getvalue(buf, TOKEN_UPDATE_STR, 1);
-               if (update == NULL) {
-                       FREE_AND_NULL(pkgid);
-                       FREE_AND_NULL(version);
-                       _LOG("compare_data is null\n");
-                       continue;
-               }
-               if (!strncmp(update, "true", strlen("true")))
-                       *is_updated = true;
-               else
-                       *is_updated = false;
-
-               if (strcmp(pkgid, fota_pkgid) == 0) {
-                       ret = pkgmgrinfo_compare_package_version(version,
-                               fota_version, &compare);
-                       if (compare == PMINFO_VERSION_NEW) {
-                               _LOG("pkgid = %s, db version = %s, new package"
-                                       " version = %s\n", pkgid, version,
-                                               fota_version);
-                               _LOG("pkg is updated, need to upgrade\n");
-
-                               ret = PKG_IS_UPDATED;
-                               FREE_AND_NULL(pkgid);
-                               FREE_AND_NULL(version);
-                               FREE_AND_NULL(update);
-                               break;
-                       } else if (compare == PMINFO_VERSION_OLD) {
-                               ret = PKG_IS_OLD;
-                               FREE_AND_NULL(pkgid);
-                               FREE_AND_NULL(version);
-                               FREE_AND_NULL(update);
-                               break;
-                       }
-
-                       FREE_AND_NULL(pkgid);
-                       FREE_AND_NULL(version);
-                       FREE_AND_NULL(update);
-                       ret =  PKG_IS_SAME;
-                       break;
-               }
-
-               FREE_AND_NULL(pkgid);
-               FREE_AND_NULL(version);
-               FREE_AND_NULL(update);
-               memset(buf, 0x00, BUF_SIZE);
-       }
-
-       if (fp != NULL)
-               fclose(fp);
-
-       return ret;
-}
-
-static bool __check_deleted_pkg(GHashTable *preload_rw_table,
-               const char *fota_pkgid)
-{
-       if (g_hash_table_contains(preload_rw_table, fota_pkgid))
-               return true;
-       return false;
-}
-
-char *__manifest_to_package(const char *manifest)
-{
-       char *package;
-
-       if (manifest == NULL)
-               return NULL;
-
-       package = strdup(manifest);
-       if (package == NULL)
-               return NULL;
-
-       if (!strstr(package, ".xml")) {
-               _LOG("%s is not a manifest file \n", manifest);
-               free(package);
-               return NULL;
-       }
-
-       return package;
-}
-
-static void __send_args_to_backend(const char *pkgid, const char *pkgtype,
-               int operation)
-{
-       int ret = 0;
-
-       long starttime;
-       long endtime;
-       struct timeval tv;
-       gettimeofday(&tv, NULL);
-       starttime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
-       char *query;
-       char backend_cmd[BUF_SIZE];
-       const char *new_pkgtype;
-       const char tpk_pkgtype[] = "tpk";
-
-       const char *preload_rw[] = { backend_cmd, "-y", pkgid,
-                               "--preload-rw", NULL };
-       const char *install_ro[] = { backend_cmd, "-y", pkgid,
-                               "--preload", "--partial-rw", NULL };
-       const char *uninstall_ro[] = { backend_cmd, "-d", pkgid,
-                               "--preload", "--force-remove",
-                               "--partial-rw", NULL };
-       const char *uninstall_ro_keeprwdata[] = { backend_cmd, "-d", pkgid,
-                               "--preload", "--force-remove",
-                               "--keep-rwdata", NULL };
-       const char *uninstall_ro_update[] = { backend_cmd, "-d",
-                               pkgid, "--keep-rwdata", NULL };
-       const char *db_cmd[] = {"/usr/bin/sqlite3",
-                               NULL, NULL, NULL};
-
-       if (operation == PKG_NEED_NOTHING)
-               return;
-
-       if (!strcmp(pkgtype, "rpm"))
-               new_pkgtype = tpk_pkgtype;
-       else
-               new_pkgtype = pkgtype;
-
-       snprintf(backend_cmd, sizeof(backend_cmd), "/usr/bin/%s-backend",
-                       new_pkgtype);
-
-       switch (operation) {
-       case PKG_NEED_INSTALL:
-       case PKG_NEED_ROUPDATE:
-               ret = __xsystem(install_ro);
-               break;
-       case PKG_NEED_UNINSTALL:
-               ret = __xsystem(uninstall_ro);
-               break;
-       case PKG_NEED_UPDATE_TO_RW:
-               query = sqlite3_mprintf(
-                               "UPDATE package_info SET " \
-                               "package_preload='false', " \
-                               "package_system='false' "\
-                               "WHERE package=%Q", pkgid);
-               db_cmd[1] = strdup(DBPATH);
-               db_cmd[2] = query;
-               ret = __xsystem(db_cmd);
-               FREE_AND_NULL(db_cmd[1]);
-               sqlite3_free(query);
-               break;
-       case PKG_NEED_RWUNINSTALL:
-       case PKG_NEED_UPDATE_TO_RO:
-               ret = __xsystem(uninstall_ro_update);
-               break;
-       case PKG_NEED_RO_DBREMOVE:
-               query = sqlite3_mprintf(
-                               "PRAGMA foreign_keys=on; " \
-                               "DELETE FROM package_info " \
-                               "WHERE package=%Q", pkgid);
-               db_cmd[1] = strdup(DBPATH);
-               db_cmd[2] = query;
-               ret = __xsystem(db_cmd);
-               FREE_AND_NULL(db_cmd[1]);
-               sqlite3_free(query);
-               break;
-       case PKG_NEED_PRELOADRW_INSTALL:
-               ret = __xsystem(preload_rw);
-               break;
-       case PKG_NEED_RO_UNINSTALL_KEEPRWDATA:
-               ret = __xsystem(uninstall_ro_keeprwdata);
-               break;
-       }
-
-       gettimeofday(&tv, NULL);
-       endtime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
-
-       _LOG("result[%ld ms, %d] \t Pkgid[%s]  \n",
-               (endtime - starttime), ret, pkgid);
-}
-
-int __child_element(xmlTextReaderPtr reader, int depth)
-{
-       int ret = xmlTextReaderRead(reader);
-       int cur = xmlTextReaderDepth(reader);
-       while (ret == 1) {
-               switch (xmlTextReaderNodeType(reader)) {
-               case XML_READER_TYPE_ELEMENT:
-                       if (cur == depth + 1)
-                               return 1;
-                       break;
-               case XML_READER_TYPE_TEXT:
-                       /*text is handled by each function separately*/
-                       if (cur == depth + 1)
-                               return 0;
-                       break;
-               case XML_READER_TYPE_END_ELEMENT:
-                       if (cur == depth)
-                               return 0;
-                       break;
-               default:
-                       if (cur <= depth)
-                               return 0;
-                       break;
-               }
-
-               ret = xmlTextReaderRead(reader);
-               cur = xmlTextReaderDepth(reader);
-       }
-       return ret;
-}
-
-char *__find_info_from_xml(const char *manifest, const char *find_info)
-{
-       retvm_if(manifest == NULL, NULL, "manifest is null.\n");
-       retvm_if(find_info == NULL, NULL, "find_info is null.\n");
-
-       const xmlChar *node;
-       xmlTextReaderPtr reader;
-       char *info_val = NULL;
-       xmlChar *tmp = NULL;
-
-       reader = xmlReaderForFile(manifest, NULL, 0);
-
-       if (reader) {
-               if (__child_element(reader, -1)) {
-                       node = xmlTextReaderConstName(reader);
-                       if (!node) {
-                               printf("xmlTextReaderConstName value is NULL\n");
-                               goto end;
-                       }
-
-                       if (!strcmp(ASCII(node), "manifest")) {
-                               tmp = xmlTextReaderGetAttribute(reader,
-                                       XMLCHAR(find_info));
-                               if (tmp) {
-                                       FREE_AND_STRDUP(ASCII(tmp), info_val);
-                                       if (info_val == NULL)
-                                               printf("Malloc Failed\n");
-                                       FREE_AND_NULL(tmp);
-                               }
-                       } else {
-                               printf("Manifest Node is not found\n");
-                       }
-               }
-       } else {
-               printf("xmlReaderForFile value is NULL\n");
-       }
-
-end:
-       if (reader)
-               xmlFreeTextReader(reader);
-
-       return info_val;
-}
-
-static int __find_preload_pkgid_from_xml(const char *file_path,
-               const char *xml_directory)
-{
-       retvm_if(file_path == NULL, -1, "file_path is NULL.\n");
-       retvm_if(xml_directory == NULL, -1, "xml_directory is NULL.\n");
-
-       int ret = 0;
-       char buf[BUF_SIZE] = {0};
-       DIR *dir;
-       struct dirent *entry = NULL;
-
-       dir = opendir(xml_directory);
-       if (!dir) {
-               if (strerror_r(errno, buf, sizeof(buf)) == 0)
-                       _LOG("Failed to access the [%s] because %s\n",
-                               xml_directory, buf);
-               return -1;
-       }
-
-       while ((entry = readdir(dir)) != NULL) {
-               char *manifest = NULL;
-               char *pkgid = NULL;
-               char *version = NULL;
-               char *type = NULL;
-
-               if (entry->d_name[0] == '.') continue;
-
-               manifest = __manifest_to_package(entry->d_name);
-               if (!manifest) {
-                       _LOG("Failed to convert file to xml[%s]\n",
-                               entry->d_name);
-                       continue;
-               }
-
-               snprintf(buf, sizeof(buf), "%s/%s", xml_directory, manifest);
-
-               /*Get the package name from manifest file*/
-               pkgid = __find_info_from_xml(buf, "package");
-               if (pkgid == NULL) {
-                       FREE_AND_NULL(manifest);
-                       continue;
-               }
-
-               version = __find_info_from_xml(buf, "version");
-               if (version == NULL)
-                       version = strdup("0.0.1");
-
-               type = __find_info_from_xml(buf, "type");
-               if (type == NULL)
-                       type = strdup("tpk");
-
-               ret = __make_pkgid_list((char *)file_path, pkgid,
-                       version, type, false);
-               if (ret < 0)
-                       _LOG("Make file Fail : %s => %s, %s\n",
-                               buf, pkgid, version);
-
-               FREE_AND_NULL(pkgid);
-               FREE_AND_NULL(version);
-               FREE_AND_NULL(manifest);
-               FREE_AND_NULL(type);
-       }
-
-       closedir(dir);
-
-       return 0;
-}
-
-static int __find_preload_pkgid_from_db(const char *file_path)
-{
-       retvm_if(file_path == NULL, -1, "file_path is NULL.\n");
-
-       int ret = 0;
-       pkgmgrinfo_pkginfo_filter_h handle = NULL;
-
-       ret = pkgmgrinfo_pkginfo_filter_create(&handle);
-       retvm_if(ret != PMINFO_R_OK, -1,
-               "pkginfo filter handle create failed\n");
-
-       ret = pkgmgrinfo_pkginfo_filter_add_bool(handle,
-               PMINFO_PKGINFO_PROP_PACKAGE_PRELOAD, 1);
-       tryvm_if(ret < 0, ret = -1, "pkgmgrinfo_pkginfo_filter_add_bool"
-               "(PMINFO_PKGINFO_PROP_PACKAGE_PRELOAD) failed\n");
-
-       ret = pkgmgrinfo_pkginfo_filter_add_bool(handle,
-               PMINFO_PKGINFO_PROP_PACKAGE_SYSTEM, 1);
-       tryvm_if(ret < 0, ret = -1, "pkgmgrinfo_pkginfo_filter_add_bool"
-               "(PMINFO_PKGINFO_PROP_PACKAGE_SYSTEM) failed\n");
-
-       ret = pkgmgrinfo_pkginfo_filter_foreach_pkginfo(handle,
-               __pkgid_list_cb, (void *)file_path);
-       err_if(ret < 0,
-               "pkgmgrinfo_pkginfo_filter_foreach_pkginfo() failed\n");
-
-catch:
-       pkgmgrinfo_pkginfo_filter_destroy(handle);
-       return ret;
-}
-
-static int __find_preload_rw_pkgid_from_db(GHashTable *preload_rw_table)
-{
-       int ret;
-       pkgmgrinfo_pkginfo_filter_h handle;
-
-       ret = pkgmgrinfo_pkginfo_filter_create(&handle);
-       retvm_if(ret != PMINFO_R_OK, -1,
-                       "pkginfo filter handle create failed\n");
-
-       ret = pkgmgrinfo_pkginfo_filter_add_bool(handle,
-               PMINFO_PKGINFO_PROP_PACKAGE_PRELOAD, 1);
-       tryvm_if(ret != PMINFO_R_OK, ret = -1, "pkgmgrinfo_pkginfo_filter_add_bool"
-                       "(PMINFO_PKGINFO_PROP_PACKAGE_PRELOAD) failed\n");
-
-       ret = pkgmgrinfo_pkginfo_filter_add_bool(handle,
-               PMINFO_PKGINFO_PROP_PACKAGE_REMOVABLE, 1);
-       tryvm_if(ret != PMINFO_R_OK, ret = -1, "pkgmgrinfo_pkginfo_filter_add_bool"
-                       "(PMINFO_PKGINFO_PROP_PACKAGE_REMOVABLE) failed\n");
-
-       ret = pkgmgrinfo_pkginfo_filter_add_bool(handle,
-               PMINFO_PKGINFO_PROP_PACKAGE_READONLY, 0);
-       tryvm_if(ret != PMINFO_R_OK, ret = -1, "pkgmgrinfo_pkginfo_filter_add_bool"
-                       "(PMINFO_PKGINFO_PROP_PACKAGE_READONLY) failed\n");
-
-       ret = pkgmgrinfo_pkginfo_filter_add_bool(handle,
-               PMINFO_PKGINFO_PROP_PACKAGE_SYSTEM, 0);
-       tryvm_if(ret != PMINFO_R_OK, ret = -1, "pkgmgrinfo_pkginfo_filter_add_bool"
-                       "(PMINFO_PKGINFO_PROP_PACKAGE_SYSTEM) failed\n");
-
-       ret = pkgmgrinfo_pkginfo_filter_foreach_pkginfo(handle,
-               __preload_rw_pkgid_list_cb, (void *)preload_rw_table);
-       err_if(ret != PMINFO_R_OK,
-                       "pkgmgrinfo_pkginfo_filter_foreach_pkginfo() failed\n");
-
-       ret = 0;
-catch:
-       pkgmgrinfo_pkginfo_filter_destroy(handle);
-       return ret;
-}
-
-static int __find_matched_pkgid_from_list(const char *source_file,
-               const char *target_file)
-{
-       retvm_if(source_file == NULL, -1, "source_file is NULL.\n");
-       retvm_if(target_file == NULL, -1, "target_file is NULL.\n");
-
-       FILE *fp = NULL;
-       char buf[BUF_SIZE] = {0};
-       char *pkgid = NULL;
-       char *version = NULL;
-       char *pkgtype = NULL;
-
-       int same_pkg_cnt = 0;
-       int update_pkg_cnt = 0;
-       int insert_pkg_cnt = 0;
-       int total_pkg_cnt = 0;
-
-       int compare_result = 0;
-       int operation;
-
-       bool db_update;
-
-       fp = fopen(source_file, "r");
-       retvm_if(fp == NULL, -1, "Fail get : %s\n", source_file);
-
-       _LOG("Searching...... inserted  or  Updated package \n");
-
-       while (fgets(buf, BUF_SIZE, fp) != NULL) {
-               __str_trim(buf);
-
-               pkgid = __getvalue(buf, TOKEN_PKGID_STR, 1);
-               if (pkgid == NULL)
-                       continue;
-
-               version = __getvalue(buf, TOKEN_VERSION_STR, 1);
-               if (version == NULL) {
-                       free(pkgid);
-                       continue;
-               }
-               pkgtype = __getvalue(buf, TOKEN_TYPE_STR, 1);
-               if (pkgtype == NULL) {
-                       free(version);
-                       free(pkgid);
-                       continue;
-               }
-
-               operation = PKG_NEED_NOTHING;
-               compare_result = __compare_pkgid((char *)target_file, pkgid,
-                                               version, &db_update);
-               if (compare_result == PKG_IS_NOT_EXIST) {
-                       _LOG("pkgid[%s] is installed, Start install\n", pkgid);
-                       operation = PKG_NEED_INSTALL;
-                       insert_pkg_cnt++;
-               } else if (compare_result == PKG_IS_SAME) {
-                       if (db_update) {
-                               operation = PKG_NEED_RWUNINSTALL;
-                               update_pkg_cnt++;
-                       } else {
-                               operation = PKG_NEED_NOTHING;
-                               same_pkg_cnt++;
-                       }
-               } else if (compare_result == PKG_IS_UPDATED) {
-                       if (db_update) {
-                               operation = PKG_NEED_UPDATE_TO_RO;
-                       } else {
-                               operation = PKG_NEED_ROUPDATE;
-                       }
-                       update_pkg_cnt++;
-               }
-
-               total_pkg_cnt++;
-               __send_args_to_backend(pkgid, pkgtype, operation);
-
-               memset(buf, 0x00, BUF_SIZE);
-               FREE_AND_NULL(pkgid);
-               FREE_AND_NULL(version);
-               FREE_AND_NULL(pkgtype);
-       }
-
-       _LOG("-------------------------------------------------------\n");
-       _LOG("[Total pkg=%d, same pkg=%d, updated pkg=%d, "
-               "inserted package=%d]\n",
-               total_pkg_cnt, same_pkg_cnt, update_pkg_cnt, insert_pkg_cnt);
-       _LOG("-------------------------------------------------------\n");
-
-       if (fp != NULL)
-               fclose(fp);
-
-       return 0;
-}
-
-static bool __find_pkgid_from_rw_list(const char *pkgid)
-{
-       if (pkgid == NULL)
-               return false;
-
-       bool ret = false;
-       FILE *fp = NULL;
-       char buf[BUF_SIZE] = {0};
-       char *preload_rw_pkgid = NULL;
-
-       fp = fopen(PRELOAD_RW_PKG_LIST, "r");
-       retvm_if(fp == NULL, -1, "Failed to open : %s\n", PRELOAD_RW_PKG_LIST);
-
-       while (fgets(buf, BUF_SIZE, fp) != NULL) {
-               __str_trim(buf);
-
-               preload_rw_pkgid = __getvalue(buf, TOKEN_PKGID_STR, 1);
-               if (preload_rw_pkgid == NULL) {
-                       _LOG("Failed to get pkgidstring[%s]\n", buf);
-                       continue;
-               }
-
-               if (strcmp(pkgid, preload_rw_pkgid) == 0) {
-                       _LOG("pkgid[%s] is converted to preload rw pkg\n", pkgid);
-                       FREE_AND_NULL(preload_rw_pkgid);
-                       ret = true;
-                       break;
-               }
-               FREE_AND_NULL(preload_rw_pkgid);
-       }
-
-       fclose(fp);
-       return ret;
-}
-
-static int __unzip_file_only_to_path(char *dest_path, char *unzip_to)
-{
-       const char *unzip_argv[] = { "/usr/bin/unzip", "-joXqq",
-                       OPT_ZIP_FILE, dest_path, "-d", unzip_to, NULL };
-       int ret = __xsystem(unzip_argv);
-
-       return ret;
-}
-
-static int __unzip_files(char *dest_path)
-{
-       const char *unzip_argv[] = { "/usr/bin/unzip", "-oXqq",
-                       OPT_ZIP_FILE, dest_path, "-d", "/", NULL };
-       int ret = __xsystem(unzip_argv);
-
-       return ret;
-}
-
-static int __install_preload_rw(const char *pkgid, const char *version,
-               const char *pkgtype, GHashTable *preload_rw_table)
-{
-       if (pkgid == NULL || version == NULL || pkgtype == NULL)
-               return -1;
-
-       int index;
-       int ret;
-       char buf[BUF_SIZE] = {0};
-
-       /* copy modified manifest */
-       snprintf(buf, BUF_SIZE, "%s/%s.xml",
-                       (tzplatform_getenv(TZ_SYS_RW_PACKAGES) + 1), pkgid);
-       ret = __unzip_files(buf);
-       if (ret != 0) {
-               _LOG("Failed to unzip file from backup[%s]\n", buf);
-               return ret;
-       }
-
-       /* copy stored signature */
-       snprintf(buf, BUF_SIZE, "%s/signatures/%s.txt",
-                       (tzplatform_getenv(TZ_SYS_SHARE) + 1), pkgid);
-       ret = __unzip_files(buf);
-       if (ret != 0) {
-               _LOG("Failed to unzip file from backup[%s]\n", buf);
-               return ret;
-       }
-
-       /* copy RO and RW components */
-       for (index = 0; index < BUF_SIZE; index++) {
-               if (unzip_path[index] == NULL)
-                       break;
-
-               snprintf(buf, BUF_SIZE, "%s/%s/*", unzip_path[index], pkgid);
-               ret = __unzip_files(buf);
-               if (ret != 0) {
-                       _LOG("Failed to unzip file from backup[%s]\n", buf);
-                       return ret;
-               }
-       }
-
-       ret = __insert_preload_rw_table(preload_rw_table, pkgid, version,
-                       pkgtype);
-       retvm_if(ret < 0, -1, "__insert_preload_rw_table fail\n");
-
-       __send_args_to_backend(pkgid, pkgtype, PKG_NEED_PRELOADRW_INSTALL);
-       return ret;
-}
-
-static void __convert_preload_to_rw(const char *pkgid, const char *version,
-               const char *pkgtype, GHashTable *preload_rw_table)
-{
-       if (pkgid == NULL || version == NULL || pkgtype == NULL)
-               return;
-       char buf[BUF_SIZE] = {0};
-       int ret;
-
-       snprintf(buf, BUF_SIZE, "%s/skel/apps_rw/%s",
-                       tzplatform_getenv(TZ_SYS_ETC), pkgid);
-
-       __send_args_to_backend(pkgid, pkgtype, PKG_NEED_RO_UNINSTALL_KEEPRWDATA);
-       ret = remove_directory(buf);
-       if (ret != 0)
-               _LOG("Failed to remove directory[%s]\n", buf);
-
-       ret = __install_preload_rw(pkgid, version, pkgtype, preload_rw_table);
-       if (ret != 0) {
-               _LOG("Failed install preload rw pkg[%s]\n", pkgid);
-               return;
-       }
-}
-
-static int __find_deleted_pkgid_from_list(const char *source_file,
-               const char *target_file, GHashTable *preload_rw_table)
-{
-       retvm_if(source_file == NULL, -1, "source_file is NULL.\n");
-       retvm_if(target_file == NULL, -1, "target_file is NULL.\n");
-
-       FILE *fp = NULL;
-       char buf[BUF_SIZE] = {0};
-       char *pkgid;
-       char *version;
-       char *pkgtype = NULL;
-       char *update = NULL;
-       bool is_preload_rw_pkg;
-       bool xml_update;
-       int deleted_pkg_cnt = 0;
-       int modified_pkg_cnt = 0;
-       int total_pkg_cnt = 0;
-       int compare_result = 0;
-
-       fp = fopen(source_file, "r");
-       retvm_if(fp == NULL, -1, "Fail get : %s\n", source_file);
-
-       _LOG("Searching...... deleted package \n");
-
-       while (fgets(buf, BUF_SIZE, fp) != NULL) {
-               __str_trim(buf);
-
-               pkgid = __getvalue(buf, TOKEN_PKGID_STR, 1);
-               version = __getvalue(buf, TOKEN_VERSION_STR, 1);
-               pkgtype = __getvalue(buf, TOKEN_TYPE_STR, 1);
-               if (pkgid == NULL || version == NULL || pkgtype == NULL) {
-                       _LOG("Failed to get pkg info from string[%s]\n", buf);
-                       FREE_AND_NULL(pkgid);
-                       FREE_AND_NULL(version);
-                       FREE_AND_NULL(pkgtype);
-                       continue;
-               }
-
-               compare_result = __compare_pkgid((char *)target_file, pkgid,
-                                               version, &xml_update);
-               if (compare_result == PKG_IS_NOT_EXIST) {
-                       update = __getvalue(buf, TOKEN_UPDATE_STR, 1);
-                       if (update == NULL) {
-                               FREE_AND_NULL(pkgid);
-                               FREE_AND_NULL(version);
-                               FREE_AND_NULL(pkgtype);
-                               continue;
-                       }
-
-                       is_preload_rw_pkg = __find_pkgid_from_rw_list(pkgid);
-
-                       if (!strncmp(update, "false", strlen("false"))) {
-                               if (is_preload_rw_pkg) {
-                                       __convert_preload_to_rw(pkgid, version,
-                                                       pkgtype,
-                                                       preload_rw_table);
-                                       modified_pkg_cnt++;
-                               } else {
-                                       __send_args_to_backend(pkgid, pkgtype,
-                                                       PKG_NEED_UNINSTALL);
-                                       deleted_pkg_cnt++;
-                               }
-                       } else {
-                               __send_args_to_backend(pkgid, pkgtype,
-                                                       PKG_NEED_UPDATE_TO_RW);
-                               modified_pkg_cnt++;
-                               if (is_preload_rw_pkg) {
-                                       __send_args_to_backend(pkgid, pkgtype,
-                                                       PKG_NEED_RWUNINSTALL);
-                                       __install_preload_rw(pkgid, version,
-                                                       pkgtype,
-                                                       preload_rw_table);
-                               }
-                       }
-               }
-               total_pkg_cnt++;
-
-               memset(buf, 0x00, BUF_SIZE);
-               FREE_AND_NULL(pkgid);
-               FREE_AND_NULL(version);
-               FREE_AND_NULL(pkgtype);
-               FREE_AND_NULL(update);
-       }
-
-       _LOG("-------------------------------------------------------\n");
-       _LOG("[Total pkg=%d, deleted package=%d, modified package=%d]\n",
-               total_pkg_cnt, deleted_pkg_cnt, modified_pkg_cnt);
-       _LOG("-------------------------------------------------------\n");
-
-       if (fp != NULL)
-               fclose(fp);
-
-       return 0;
-
-}
-
-static int __get_pkgid_list_from_db_and_xml()
-{
-       _LOG("=======================================================\n");
-       _LOG("RO preload package fota\n");
-       _LOG("=======================================================\n");
-
-       int ret = 0;
-       char updated_preload_rw_list[BUF_SIZE];
-
-       /*get pkg info on pkgmgr db, it means old version */
-       ret = __find_preload_pkgid_from_db(PKGID_LIST_FROM_DB_FILE);
-       retvm_if(ret < 0, -1, "__find_preload_pkgid_from_db fail.\n");
-
-       _LOG("Make pkgid list from db success!! \n");
-
-       /*get pkg info on xml, it means new version */
-       ret = __find_preload_pkgid_from_xml(PKGID_LIST_FROM_XML_FILE,
-               USR_MANIFEST_DIRECTORY);
-       retvm_if(ret < 0, -1, "__find_preload_pkgid_from_xml fail.\n");
-
-       _LOG("Make pkgid list from xml success!! \n");
-
-
-       /*get preload rw pkg info on xml from opt.zip, it means new version */
-       snprintf(updated_preload_rw_list, sizeof(updated_preload_rw_list), "%s",
-                       ALL_PRELOAD_RW_PKG_LIST);
-       ret = __unzip_file_only_to_path(updated_preload_rw_list + 1,
-                       (char *)PKGMGR_FOTA_PATH);
-       if (ret != 0) {
-               _LOG("Failed to unzip file from backup[%s]\n",
-                               updated_preload_rw_list);
-               return ret;
-       }
-
-       _LOG("Make rw pkgid list from xml success!! \n");
-
-       return 0;
-}
-
-static int __process_ro_fota(GHashTable *preload_rw_table)
-{
-       int ret;
-       long starttime;
-       long endtime;
-       struct timeval tv;
-
-       xmlInitParser();
-
-       gettimeofday(&tv, NULL);
-       starttime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
-
-       /* find deleted pkgid */
-       ret = __find_deleted_pkgid_from_list(PKGID_LIST_FROM_DB_FILE,
-               PKGID_LIST_FROM_XML_FILE, preload_rw_table);
-       err_if(ret < 0, "__find_deleted_pkgid_from_list fail.\n");
-
-       /* find updated, inserted pkgid */
-       ret = __find_matched_pkgid_from_list(PKGID_LIST_FROM_XML_FILE,
-               PKGID_LIST_FROM_DB_FILE);
-       err_if(ret < 0, "__find_matched_pkgid_from_list fail.\n");
-
-       gettimeofday(&tv, NULL);
-       endtime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
-
-       _LOG("=======================================================\n");
-       _LOG("End RO process[time : %ld ms]\n", endtime - starttime);
-       _LOG("=======================================================\n");
-
-       xmlCleanupParser();
-
-       return 0;
-}
-
-static void __remove_pkg_directories(const char *pkgid)
-{
-       int i;
-       int ret;
-       char buf[BUF_SIZE];
-       const char *base_dirs[] = {
-               OPT_USR_MANIFEST_DIRECTORY,
-               RW_PKG_DIRECTORY,
-               SKEL_DIRECTORY,
-               NULL
-       };
-
-       for (i = 0; base_dirs[i] != NULL; i++) {
-               ret = snprintf(buf, sizeof(buf), "%s/%s", base_dirs[i], pkgid);
-               if (ret < 0 || ret > sizeof(buf)) {
-                       printf("snprintf fail\n");
-                       continue;
-               }
-               if (!access(buf, F_OK)) {
-                       if (remove_directory(buf))
-                               _LOGE("failed to remove directory: %s", buf);
-               }
-       }
-}
-
-static int __process_rw_fota(GHashTable *preload_rw_table)
-{
-       FILE *fp = NULL;
-       char buf[BUF_SIZE] = {0};
-       int ret = -1;
-       char *pkgid = NULL;
-       char *list_version = NULL;
-       char *db_stored_version = NULL;
-       char *pkgtype = NULL;
-       char *version = NULL;
-       pkgmgrinfo_pkginfo_h handle = NULL;
-       int compare = PMINFO_VERSION_SAME;
-       long total_time = 0;
-
-       long starttime;
-       long endtime;
-       struct timeval tv;
-       bool is_deleted_pkg;
-
-       _LOG("=======================================================\n");
-       _LOG("RW preload package fota\n");
-       _LOG("=======================================================\n");
-
-       fp = fopen(PRELOAD_RW_PKG_LIST, "r");
-       retvm_if(fp == NULL, -1, "Fail get : %s\n", PRELOAD_RW_PKG_LIST);
-
-       while (fgets(buf, BUF_SIZE, fp) != NULL) {
-               __str_trim(buf);
-
-               gettimeofday(&tv, NULL);
-               starttime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
-
-               pkgid = __getvalue(buf, TOKEN_PKGID_STR, 1);
-               if (pkgid == NULL)
-                       continue;
-
-               ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgid, &handle);
-               if (ret == PMINFO_R_OK) {
-                       list_version = __getvalue(buf, TOKEN_VERSION_STR, 1);
-                       if (list_version == NULL) {
-                               FREE_AND_NULL(pkgid);
-                               continue;
-                       }
-                       ret = pkgmgrinfo_pkginfo_get_version(handle, &db_stored_version);
-                       ret = pkgmgrinfo_compare_package_version(db_stored_version,
-                                       list_version, &compare);
-                       if (ret != PMINFO_R_OK) {
-                               _LOG("can not compare pkg version[%s]\n", pkgid);
-                               pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
-                               handle = NULL;
-                               FREE_AND_NULL(pkgid);
-                               FREE_AND_NULL(list_version);
-                               continue;
-                       }
-
-                       if (compare != PMINFO_VERSION_NEW) {
-                               /* package version is not update on FOTA. */
-                               _LOG("pkgid[%s] is not updated\n", pkgid);
-                               pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
-                               handle = NULL;
-                               FREE_AND_NULL(pkgid);
-                               FREE_AND_NULL(list_version);
-                               continue;
-                       }
-
-                       _LOG("pkgid[%s] is updated, need to upgrade "
-                                       "from version [%s] to [%s]\n",
-                                       pkgid, db_stored_version, list_version);
-               } else {
-                       is_deleted_pkg = __check_deleted_pkg(preload_rw_table, pkgid);
-                       if (is_deleted_pkg) {
-                               _LOG("pkgid[%s] is deleted pkg\n", pkgid);
-                               __delete_preload_rw_table(preload_rw_table,
-                                               pkgid);
-                               /* maybe there are pkg directories which are
-                                * extracted from opt.zip by FOTA
-                                */
-                               __remove_pkg_directories(pkgid);
-                               FREE_AND_NULL(pkgid);
-                               continue;
-                       }
-                       _LOG("pkgid[%s] is new\n", pkgid);
-               }
-
-               version = __getvalue(buf, TOKEN_VERSION_STR, 1);
-               pkgtype = __getvalue(buf, TOKEN_TYPE_STR, 1);
-               __install_preload_rw(pkgid, version, pkgtype, preload_rw_table);
-
-               FREE_AND_NULL(pkgid);
-               FREE_AND_NULL(pkgtype);
-               FREE_AND_NULL(version);
-
-               if (handle)
-                       pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
-
-               gettimeofday(&tv, NULL);
-               endtime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
-               total_time += (int)(endtime - starttime);
-               _LOG("finish request [time : %d ms]\n",
-                       (int)(endtime - starttime));
-       }
-       fclose(fp);
-
-       return 0;
-}
-
-static int __check_tmp_all_preload_rw_pkg_list()
-{
-       char buf[BUF_SIZE];
-       char tmp_path[BUF_SIZE];
-       snprintf(tmp_path, BUF_SIZE, "%s.tmp", ALL_PRELOAD_RW_PKG_LIST);
-       if (access(tmp_path, F_OK) == 0) {
-               if (rename(tmp_path, ALL_PRELOAD_RW_PKG_LIST)) {
-                       _LOG("rename tmp all preload rw pkg list fail : %s\n",
-                                       strerror_r(errno, buf, sizeof(buf)));
-                       return -1;
-               }
-       }
-       return 0;
-}
-
-static int __fill_preload_rw_table(GHashTable *preload_rw_table)
-{
-       FILE *fp;
-       char buf[BUF_SIZE];
-       char *pkgid;
-       char *version;
-       char *type;
-
-       fp = fopen(ALL_PRELOAD_RW_PKG_LIST, "r");
-       retvm_if(fp == NULL, -1, "Fail get : %s\n", ALL_PRELOAD_RW_PKG_LIST);
-
-       while (fgets(buf, BUF_SIZE, fp) != NULL) {
-               __str_trim(buf);
-
-               pkgid = __getvalue(buf, TOKEN_PKGID_STR, 1);
-               if (pkgid == NULL) {
-                       _LOG("pkgid is null\n");
-                       continue;
-               }
-
-               version = __getvalue(buf, TOKEN_VERSION_STR, 1);
-               if (version == NULL) {
-                       _LOG("version is null\n");
-                       version = strdup("");
-                       if (version == NULL) {
-                               _LOGE("out of memory\n");
-                               FREE_AND_NULL(pkgid);
-                               continue;
-                       }
-               }
-
-               type = __getvalue(buf, TOKEN_TYPE_STR, 1);
-               if (type == NULL) {
-                       _LOG("type is null\n");
-                       type = strdup("");
-                       if (type == NULL) {
-                               _LOGE("out of memory\n");
-                               FREE_AND_NULL(version);
-                               FREE_AND_NULL(pkgid);
-                               continue;
-                       }
-               }
-
-               __insert_preload_rw_table(preload_rw_table, pkgid, version,
-                               type);
-               FREE_AND_NULL(pkgid);
-               FREE_AND_NULL(version);
-               FREE_AND_NULL(type);
-       }
-       fclose(fp);
-
-       return 0;
-}
-
-#define DB_LABEL "User::Home"
-#define SET_SMACK_LABEL(x)                                                     \
-do {                                                                           \
-       if (smack_setlabel((x), DB_LABEL, SMACK_LABEL_ACCESS))                 \
-               _LOGE("failed chsmack -a %s %s", DB_LABEL, x);                 \
-       else                                                                   \
-               _LOG("chsmack -a %s %s", DB_LABEL, x);                         \
-} while (0)
-
-static int __set_db_permission(const char *path)
-{
-       int fd;
-       struct stat sb;
-       mode_t mode;
-       uid_t uid;
-       struct passwd pwd;
-       struct passwd *result;
-       char buf[BUF_SIZE];
-       int ret;
-
-       ret = getpwnam_r(APPFW_USER, &pwd, buf, sizeof(buf), &result);
-       if (result == NULL) {
-               if (ret == 0)
-                       _LOGE("no such user: %s", APPFW_USER);
-               else
-                       _LOGE("getpwnam_r failed: %d", errno);
-               return -1;
-       }
-       uid = pwd.pw_uid;
-
-       ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
-       if (result == NULL) {
-               if (ret == 0)
-                       _LOGE("no such user: %d", uid);
-               else
-                       _LOGE("getpwuid_r failed: %d", errno);
-               return -1;
-       }
-       fd = open(path, O_RDONLY);
-       if (fd == -1) {
-               _LOGE("open %s failed: %d", path, errno);
-               return -1;
-       }
-       ret = fstat(fd, &sb);
-       if (ret == -1) {
-               _LOGE("stat %s failed: %d", path, errno);
-               close(fd);
-       return -1;
-       }
-       if (S_ISLNK(sb.st_mode)) {
-               _LOGE("%s is symlink!", path);
-               close(fd);
-               return -1;
-       }
-       ret = fchown(fd, uid, pwd.pw_gid);
-       if (ret == -1) {
-               _LOGE("fchown %s failed: %d", path, errno);
-               close(fd);
-               return -1;
-       }
-
-       mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
-       if (strstr(path, CERT_DBPATH))
-               mode |= S_IWOTH;
-       ret = fchmod(fd, mode);
-       if (ret == -1) {
-               _LOGE("fchmod %s failed: %d", path, errno);
-               close(fd);
-               return -1;
-       }
-       fsync(fd);
-       close(fd);
-       SET_SMACK_LABEL(path);
-
-       return 0;
-}
-
-static int __create_backup_flag(const char *path)
-{
-       int fd;
-       char temp_buf[8192] = {'\0', };
-
-       snprintf(temp_buf, sizeof(temp_buf), "%s.bck.flag", path);
-
-       fd = open(temp_buf, O_CREAT | O_WRONLY, 0644);
-       if (fd == -1) {
-               _LOG("failed to create flag file %s, %d", temp_buf, errno);
-               return -1;
-       }
-       close(fd);
-
-       return 0;
-}
-
-static int __check_backup_flag(const char *path)
-{
-       char temp_buf[8192] = {'\0', };
-
-       snprintf(temp_buf, sizeof(temp_buf), "%s.bck.flag", path);
-       if (access(temp_buf, F_OK) != 0)
-               return -1;
-
-       return 0;
-}
-
-static int __remove_backup_flag(const char *path)
-{
-       char temp_buf[8192] = {'\0', };
-
-       snprintf(temp_buf, sizeof(temp_buf), "%s.bck.flag", path);
-       if (remove(temp_buf)) {
-               _LOG("cannot remove flag file(%s): %d", temp_buf, errno);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int __check_and_restore_backup(const char *origin_path) {
-       char backup_path[BUF_SIZE];
-       char buf[BUF_SIZE];
-       snprintf(backup_path, BUF_SIZE, "%s.bck", origin_path);
-
-       // if backup flag exists, it means the previous backup process aborted.
-       if (access(backup_path, F_OK) && __check_backup_flag(origin_path))
-               return 0;
-
-       if (access(origin_path, F_OK) == 0) {
-               if (remove(origin_path)) {
-                       _LOG("cannot remove path(%s) : %s\n", origin_path,
-                                       strerror_r(errno, buf, sizeof(buf)));
-                       return -1;
-               }
-       }
-
-       if (rename(backup_path, origin_path)) {
-               _LOG("fail to rename %s to %s : %s\n", backup_path, origin_path,
-                               strerror_r(errno, buf, sizeof(buf)));
-               return -1;
-       }
-
-       return 0;
-}
-
-static int __check_and_restore_backup_dbs() {
-       if (__check_and_restore_backup(DBPATH))
-               return -1;
-
-       if (__check_and_restore_backup(JOURNAL_DBPATH))
-               return -1;
-
-       if (__check_and_restore_backup(CERT_DBPATH))
-               return -1;
-
-       if (__check_and_restore_backup(JOURNAL_CERT_DBPATH))
-               return -1;
-
-       return 0;
-}
-
-static int __backup_file(const char *src_path, const char *dest_path)
-{
-       int ret = 0;
-       int rc;
-       FILE *src = NULL;
-       FILE *dest = NULL;
-       char temp_buf[8192] = {'\0', };
-       size_t size_of_char = sizeof(char);
-       size_t size_of_temp_buf = sizeof(temp_buf);
-
-       retvm_if(src_path == NULL || dest_path == NULL,
-                       -1, "Invalid parameters");
-
-       retvm_if(access(src_path, F_OK) != 0, -1,
-                       "File(%s) is not exist", src_path);
-
-       // if backup flag exists, it means the previous backup process aborted.
-       if (__check_backup_flag(src_path)) {
-               if (access(dest_path, F_OK) == 0) {
-                       if (remove(dest_path))
-                               _LOG("Failed to remove uncompleted backup file "
-                                               "%s: %d", dest_path, errno);
-                       return -1;
-               }
-       } else {
-               if (__create_backup_flag(src_path)) {
-                       _LOG("failed to create backup flag");
-                       return -1;
-               }
-       }
-
-       src = fopen(src_path, "r");
-       tryvm_if(src == NULL, ret = -1, "Failed to open : %s\n", src_path);
-
-       dest = fopen(dest_path, "w");
-       tryvm_if(dest == NULL, ret = -1, "Failed to open : %s\n", dest_path);
-
-       while (!feof(src)) {
-               rc = fread(temp_buf, size_of_char, size_of_temp_buf, src);
-               fwrite(temp_buf, size_of_char, rc, dest);
-       }
-
-       fsync(fileno(dest));
-
-catch:
-       if (src)
-               fclose(src);
-
-       if (dest)
-               fclose(dest);
-
-       __remove_backup_flag(src_path);
-
-       return ret;
-}
-
-static int __backup_db(const char *src_path, const char *dest_path) {
-       if (__backup_file(src_path, dest_path) != 0)
-               return -1;
-
-       if (__set_db_permission(dest_path) != 0)
-               return -1;
-
-       return 0;
-}
-
-static int __make_backup_dbs() {
-       int ret = 0;
-       char parser_db_bck[BUF_SIZE];
-       char parser_db_journal_bck[BUF_SIZE];
-       char cert_db_bck[BUF_SIZE];
-       char cert_db_journal_bck[BUF_SIZE];
-
-       snprintf(parser_db_bck, BUF_SIZE, "%s.bck", DBPATH);
-       snprintf(parser_db_journal_bck, BUF_SIZE, "%s.bck", JOURNAL_DBPATH);
-       snprintf(cert_db_bck, BUF_SIZE, "%s.bck", CERT_DBPATH);
-       snprintf(cert_db_journal_bck, BUF_SIZE, "%s.bck", JOURNAL_CERT_DBPATH);
-
-       tryvm_if(__backup_db(DBPATH, parser_db_bck) == -1,
-                       ret = -1, "Fail to backup [%s] to [%s]\n",
-                       DBPATH, parser_db_bck);
-
-       tryvm_if(__backup_db(JOURNAL_DBPATH, parser_db_journal_bck) == -1,
-                       ret = -1, "Fail to backup [%s] to [%s]\n",
-                       JOURNAL_DBPATH, parser_db_journal_bck);
-
-       tryvm_if(__backup_db(CERT_DBPATH, cert_db_bck) == -1,
-                       ret = -1, "Fail to backup [%s] to [%s]\n",
-                       CERT_DBPATH, cert_db_bck);
-
-       tryvm_if(__backup_db(JOURNAL_CERT_DBPATH, cert_db_journal_bck) == -1,
-                       ret = -1, "Fail to backup [%s] to [%s]\n",
-                       JOURNAL_CERT_DBPATH, cert_db_journal_bck);
-
-       return 0;
-
-catch:
-       remove(parser_db_bck);
-       remove(parser_db_journal_bck);
-       remove(cert_db_bck);
-       remove(cert_db_journal_bck);
-
-       return ret;
-}
-
-static void __remove_backup_path(const char *origin_path) {
-       char backup_path[BUF_SIZE];
-
-       snprintf(backup_path, BUF_SIZE, "%s.bck", origin_path);
-
-       if (remove(backup_path))
-               _LOG("cannot remove backup file(%s): %d", backup_path, errno);
-}
-
-static void __remove_backup_dbs() {
-       __remove_backup_path(DBPATH);
-       __remove_backup_path(JOURNAL_DBPATH);
-       __remove_backup_path(CERT_DBPATH);
-       __remove_backup_path(JOURNAL_CERT_DBPATH);
-}
-
-int main(int argc, char *argv[])
-{
-       GHashTable *preload_rw_table;
-       int ret = 0;
-
-       ret = __check_and_restore_backup_dbs();
-       retvm_if(ret < 0, -1, "__check_and_restore_backup_dbs is failed.\n");
-
-       ret = __make_backup_dbs();
-       retvm_if(ret < 0, -1, "__make_backup_dbs is failed.\n");
-
-       /* check pkgmgr-fota dir, if it is not, then exit */
-       ret = __check_pkgmgr_fota_dir();
-       retvm_if(ret < 0, -1, "__check_pkgmgr_fota_dir is failed.\n");
-
-       /* clean pkgid list file */
-       ret = __remove_pkgid_list();
-       err_if(ret < 0, "remove[%s] failed\n", FOTA_RESULT_FILE);
-
-       /* get pkgid from orginal pkgmgr db */
-       ret = __get_pkgid_list_from_db_and_xml();
-       retvm_if(ret < 0, -1, "__get_pkgid_list_from_db_and_xml is failed.\n");
-
-       //__get_pkginfo_from_opt();
-
-       ret = __check_tmp_all_preload_rw_pkg_list();
-       retvm_if(ret < 0, -1,
-                       "__check_tmp_all_preload_rw_pkg_list is failed.\n");
-
-       preload_rw_table = g_hash_table_new_full(
-                               g_str_hash, g_str_equal, free, __free_pkginfo);
-       if (__fill_preload_rw_table(preload_rw_table) < 0) {
-               ret = __find_preload_rw_pkgid_from_db(preload_rw_table);
-               retvm_if(ret < 0, -1, "__find_preload_rw_pkgid_from_db is failed\n");
-       }
-
-       if (argc == 1) {
-               ret = __process_ro_fota(preload_rw_table);
-               if (ret < 0) {
-                       g_hash_table_destroy(preload_rw_table);
-                       _LOGE("__process_ro_fota is failed.\n");
-                       return EXIT_FAILURE;
-               }
-               ret = __process_rw_fota(preload_rw_table);
-               if (ret < 0) {
-                       g_hash_table_destroy(preload_rw_table);
-                       _LOGE("__process_rw_fota is failed.\n");
-                       return EXIT_FAILURE;
-               }
-       } else {
-               if (strcmp(argv[1], "-rof") == 0) {
-                       ret = __process_ro_fota(preload_rw_table);
-                       if (ret < 0) {
-                               g_hash_table_destroy(preload_rw_table);
-                               _LOGE("__process_ro_fota is failed.\n");
-                               return EXIT_FAILURE;
-                       }
-               } else if (strcmp(argv[1], "-rwf") == 0) {
-                       ret = __process_rw_fota(preload_rw_table);
-                       if (ret < 0) {
-                               g_hash_table_destroy(preload_rw_table);
-                               _LOGE("__process_rw_fota is failed.\n");
-                               return EXIT_FAILURE;
-                       }
-               } else {
-                       fprintf(stderr, "not supported operand\n");
-               }
-       }
-       __make_preload_rw_list(preload_rw_table);
-       g_hash_table_destroy(preload_rw_table);
-       __remove_backup_dbs();
-
-       return EXIT_SUCCESS;
-}
diff --git a/src/pkg_upgrade/src/backend_invoker.cc b/src/pkg_upgrade/src/backend_invoker.cc
new file mode 100644 (file)
index 0000000..d5db0f1
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "backend_invoker.hh"
+#include "logging.hh"
+
+namespace common_fota {
+
+BackendInvoker::BackendInvoker(std::string pkgid, PkgType type, PkgLocation loc,
+    PkgOperation op, bool removable) {
+  if (type == PkgType::WGT) {
+    parameters_.push_back("/usr/bin/wgt-backend");
+  } else {
+    parameters_.push_back("/usr/bin/tpk-backend");
+  }
+
+  if (op == PkgOperation::INSTALL || op == PkgOperation::UPDATE) {
+    parameters_.push_back("-y");
+    parameters_.push_back(std::move(pkgid));
+    if (loc == PkgLocation::RO) {
+      parameters_.push_back("--preload");
+      parameters_.push_back("--partial-rw");
+    } else {
+      if (!removable)
+        parameters_.push_back("--no-remove");
+      parameters_.push_back("--preload-rw");
+    }
+    parameters_.push_back("--skip-check-reference");
+  } else if (op == PkgOperation::UNINSTALL) {
+    parameters_.push_back("-d");
+    parameters_.push_back(std::move(pkgid));
+    if (loc == PkgLocation::RO)
+      parameters_.push_back("--preload");
+    parameters_.push_back("--force-remove");
+    parameters_.push_back("--partial-rw");
+  } else if (op == PkgOperation::UNINSTALL_KEEP_RW_DATA) {
+    parameters_.push_back("-d");
+    parameters_.push_back(std::move(pkgid));
+    if (loc == PkgLocation::RO)
+      parameters_.push_back("--preload");
+    parameters_.push_back("--force-remove");
+    parameters_.push_back("--keep-rwdata");
+  }
+}
+
+int BackendInvoker::Run() const {
+  const char* param[parameters_.size() + 1] = { nullptr, };
+
+  int i = 0;
+  for (auto& str : parameters_) {
+    param[i++] = str.c_str();
+  }
+
+  return XSystem(param);
+}
+
+int BackendInvoker::XSystem(const char *argv[]) {
+  int status = 0;
+  pid_t pid;
+
+  std::string cmd;
+  for (int i = 0; argv[i] != nullptr; i++) {
+    cmd += argv[i];
+    cmd += " ";
+  }
+  LOG(DEBUG) << "Cmd: " << cmd;
+
+  pid = fork();
+  switch (pid) {
+  case -1:
+    LOG(ERROR) << "fork failed ";
+    return -1;
+  case 0:
+    /* child */
+    execvp(argv[0], (char *const *)argv);
+    _exit(-1);
+  default:
+    /* parent */
+    break;
+  }
+  if (waitpid(pid, &status, 0) == -1) {
+    LOG(ERROR) << "waitpid failed";
+    return -1;
+  }
+  if (WIFSIGNALED(status)) {
+    LOG(ERROR) << "signal";
+    return -1;
+  }
+  if (!WIFEXITED(status)) {
+    LOG(ERROR) << "should not happen";
+    return -1;
+  }
+
+  return WEXITSTATUS(status);
+}
+
+}  // namespace common_fota
\ No newline at end of file
diff --git a/src/pkg_upgrade/src/file_logbackend.cc b/src/pkg_upgrade/src/file_logbackend.cc
new file mode 100644 (file)
index 0000000..48c41dd
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <utility>
+
+#include "logging.hh"
+#include "file_logbackend.hh"
+
+
+namespace utils {
+
+FileLogBackend::FileLogBackend(std::string file_name, int rotation_size,
+    int max_rotation)
+    : file_name_(std::move(file_name)), rotation_size_(rotation_size),
+      max_rotation_(max_rotation), log_stream_(
+          std::unique_ptr<std::ostringstream>(new std::ostringstream())) {
+}
+
+
+void FileLogBackend::WriteLog(LogLevel level, const std::string& /* tag */,
+    const std::string& logstr) {
+  if (level != LogLevel::LOG_DEBUG)
+    *log_stream_ << GetTimeStamp() << GetPid() << logstr << std::endl;
+}
+
+void FileLogBackend::WriteLogToFile() {
+  if (file_name_.empty())
+    return;
+
+  int size = GetFileSize(file_name_);
+  if (size > rotation_size_)
+    if (!Rotate())
+      return;
+
+  std::ofstream ofs(file_name_.c_str(), std::ios::app);
+  ofs << log_stream_->str();
+  ofs.close();
+
+  // clean the log stream
+  log_stream_->str("");
+  log_stream_->clear();
+}
+
+bool FileLogBackend::Rotate() {
+  for (int i = max_rotation_; i > 0; i--) {
+    std::string old_log = file_name_ + "." + std::to_string(i);
+    // the oldest log will be removed
+    if (i == max_rotation_) {
+      if (std::remove(old_log.c_str()) != 0)
+        return false;
+    } else {
+      std::string new_log = file_name_ + "." + std::to_string(i + 1);
+      if (std::rename(old_log.c_str(), new_log.c_str()) != 0)
+        return false;
+    }
+  }
+  std::string new_log = file_name_ + ".1";
+  if (std::rename(file_name_.c_str(), new_log.c_str()) != 0)
+    return false;
+
+  return true;
+}
+
+int FileLogBackend::GetFileSize(const std::string& file_name) {
+  struct stat sb;
+  int ret = stat(file_name.c_str(), &sb);
+  return ret == 0 ? sb.st_size : -1;
+}
+
+std::string FileLogBackend::GetTimeStamp() {
+  struct timespec ts;
+  clock_gettime(CLOCK_REALTIME, &ts);
+
+  time_t seconds = ts.tv_sec;
+  struct tm gmt;
+  if (!gmtime_r(&seconds, &gmt))
+    return "|";
+  int32_t miliseconds = ts.tv_nsec / 1000000;
+
+  char buf[32];
+  strftime(buf, sizeof(buf), "%Y%m%d.%H%M%S", &gmt);
+  char timestamp[64];
+  snprintf(timestamp, sizeof(timestamp), "%s.%03dUTC|", buf, miliseconds);
+
+  return timestamp;
+}
+
+std::string FileLogBackend::GetPid() {
+  return std::to_string(getpid()) + "|";
+}
+
+}  // namespace utils
diff --git a/src/pkg_upgrade/src/logging.cc b/src/pkg_upgrade/src/logging.cc
new file mode 100644 (file)
index 0000000..6da958c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "logging.hh"
+
+namespace utils {
+
+log_priority LogLevelToPriority(LogLevel level) {
+  switch (level) {
+    case LogLevel::LOG_ERROR:
+      return log_priority::DLOG_ERROR;
+    case LogLevel::LOG_WARNING:
+      return log_priority::DLOG_WARN;
+    case LogLevel::LOG_INFO:
+      return log_priority::DLOG_INFO;
+    case LogLevel::LOG_DEBUG:
+      return log_priority::DLOG_DEBUG;
+    default:
+      return log_priority::DLOG_UNKNOWN;
+  }
+}
+
+}  // namespace utils
diff --git a/src/pkg_upgrade/src/main.cc b/src/pkg_upgrade/src/main.cc
new file mode 100644 (file)
index 0000000..9d2eea2
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pkg_finder.hh"
+#include "upgrader.hh"
+
+int main(int argc, char *argv[]) {
+  common_fota::PkgFinder finder;
+  common_fota::Upgrader upgrader;
+
+  if (!upgrader.Process(&finder))
+    return -1;
+
+  return 0;
+}
diff --git a/src/pkg_upgrade/src/pkg_finder.cc b/src/pkg_upgrade/src/pkg_finder.cc
new file mode 100644 (file)
index 0000000..923378a
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <cstring>
+
+#include <algorithm>
+#include <cctype>
+
+#include <tzplatform_config.h>
+
+#include "logging.hh"
+#include "pkg_finder.hh"
+#include "backend_invoker.hh"
+
+#define ASCII(s) reinterpret_cast<const char*>(s)
+#define XMLCHAR(s) reinterpret_cast<const xmlChar*>(s)
+#define USR_MANIFEST_DIRECTORY tzplatform_getenv(TZ_SYS_RO_PACKAGES)
+#define PRELOAD_RW_LIST_FILE \
+    tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \
+    "pkgmgr/fota/.all_preload_rw_list")
+#define ALL_PRELOAD_RW_PKG_LIST "opt/usr/share/.all_preload_rw_list"
+#define PKGMGR_FOTA_PATH        tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \
+    "pkgmgr/fota")
+
+
+using namespace std;
+
+namespace {
+constexpr char kOptZipFile[] = "/usr/system/RestoreDir/opt.zip";
+constexpr int kBufSize = 1024;
+constexpr char kSeperatorEnd = '"';
+constexpr char kSeperatorMid = ':';
+constexpr char kTokenTypeStr[] = "type=";
+constexpr char kTokenPkgidStr[] = "package=";
+constexpr char kTokenVersionStr[] = "version=";
+constexpr char kTokenRemoveStr[] = "removable=";
+}  // namespace
+
+namespace common_fota {
+
+PkgFinder::PkgFinder() {
+  xmlInitParser();
+  manifest_dir_ = USR_MANIFEST_DIRECTORY;
+  preload_rw_list_path_ = PRELOAD_RW_LIST_FILE;
+  if (access(kOptZipFile, F_OK) != 0)
+    return;
+
+  int ret = UnzipFileOnlyToPath(ALL_PRELOAD_RW_PKG_LIST, PKGMGR_FOTA_PATH);
+  if (ret != 0) {
+      LOG(ERROR) << "Failed to unzip file from backup";
+      return;
+  }
+}
+
+PkgFinder::~PkgFinder() {
+  xmlCleanupParser();
+}
+
+int PkgFinder::UnzipFileOnlyToPath(const char* dest_path, const char* unzip_to) {
+  const char* unzip_argv[] = { "/usr/bin/unzip", "-joXqq",
+      kOptZipFile, dest_path, "-d", unzip_to, nullptr };
+  return BackendInvoker::XSystem(unzip_argv);
+}
+
+int PkgFinder::Find() {
+  if (FindPreloadPkgidFromDb(true) != 0) {
+    LOG(ERROR) << "FindPreloadPkgidFromDb(true) failed";
+    return -1;
+  }
+
+  if (FindPreloadPkgidFromDb(false) != 0) {
+    LOG(ERROR) << "FindPreloadPkgidFromDb(false) failed";
+    return -1;
+  }
+
+  if (FindPreloadPkgidFromXml(manifest_dir_) != 0) {
+    LOG(ERROR) << "FindPreloadPkgidFromXml(" << manifest_dir_ << ") failed";
+    return -1;
+  }
+
+  if (FindPreloadPkgidFromFile() != 0) {
+    LOG(ERROR) << "FindPreloadPkgidFromFile failed";
+    return -1;
+  }
+
+  return 0;
+}
+
+void PkgFinder::SetManifestDir(std::string dir) {
+  manifest_dir_ = std::move(dir);
+}
+
+void PkgFinder::SetPreloadRwListPath(std::string path) {
+  preload_rw_list_path_ = std::move(path);
+}
+
+int PkgFinder::PkgidListCb(const pkgmgrinfo_pkginfo_h handle, void* user_data) {
+  char* pkgid = nullptr;
+  int ret = -1;
+  ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid);
+  if (ret < 0)
+    return 0;
+
+  char* version = nullptr;
+  ret = pkgmgrinfo_pkginfo_get_version(handle, &version);
+  if (ret < 0)
+    return 0;
+
+  char* type = nullptr;
+  ret = pkgmgrinfo_pkginfo_get_type(handle, &type);
+  if (ret < 0)
+    return 0;
+
+  PkgFinder* finder = static_cast<PkgFinder*>(user_data);
+  finder->old_pkgs_.emplace_back(pkgid, version, type, finder->read_only_);
+  return 0;
+}
+
+int PkgFinder::FindPreloadPkgidFromDb(bool read_only) {
+  int ret = 0;
+  pkgmgrinfo_pkginfo_filter_h handle = nullptr;
+
+  ret = pkgmgrinfo_pkginfo_filter_create(&handle);
+  if (ret != PMINFO_R_OK) {
+    LOG(ERROR) << "pkgmgrinfo_pkginfo_filter_create failed " << ret;
+    return -1;
+  }
+
+  ret = pkgmgrinfo_pkginfo_filter_add_bool(handle,
+    PMINFO_PKGINFO_PROP_PACKAGE_PRELOAD, 1);
+  if (ret != PMINFO_R_OK) {
+    LOG(ERROR) << "pkgmgrinfo_pkginfo_filter_add_bool failed " << ret;
+    return -1;
+  }
+
+  ret = pkgmgrinfo_pkginfo_filter_add_bool(handle,
+    PMINFO_PKGINFO_PROP_PACKAGE_READONLY, read_only ? 1 : 0);
+  if (ret != PMINFO_R_OK) {
+    LOG(ERROR) << "pkgmgrinfo_pkginfo_filter_add_bool failed " << ret;
+    return -1;
+  }
+
+  read_only_ = read_only;
+  ret = pkgmgrinfo_pkginfo_filter_foreach_pkginfo(handle,
+    PkgidListCb, this);
+  if (ret != PMINFO_R_OK) {
+    LOG(ERROR) << "pkgmgrinfo_pkginfo_filter_foreach_pkginfo failed " << ret;
+    return -1;
+  }
+
+  ret = pkgmgrinfo_pkginfo_filter_destroy(handle);
+  if (ret != PMINFO_R_OK) {
+    LOG(ERROR) << "pkgmgrinfo_pkginfo_filter_destroy failed " << ret;
+    return -1;
+  }
+
+  return 0;
+}
+
+int PkgFinder::FindPreloadPkgidFromXml(
+    const string& xml_directory) {
+  DIR* dir;
+  struct dirent* entry = nullptr;
+
+  dir = opendir(xml_directory.c_str());
+  if (!dir) {
+    LOG(ERROR) << "opendir(" << xml_directory << ") failed ";
+    return -1;
+  }
+
+  while ((entry = readdir(dir)) != nullptr) {
+    if (entry->d_name[0] == '.') continue;
+
+    string manifest = GetValidManifest(entry->d_name);
+    if (manifest.empty()) {
+      continue;
+    }
+
+    string buf = xml_directory + "/" + manifest;
+    string pkgid = FindInfoFromXml(buf, "package");
+    string version = FindInfoFromXml(buf, "version");
+
+    if (version.empty())
+      version = "0.0.1";
+
+    string type = FindInfoFromXml(buf, "type");
+    if (type.empty())
+      type = "tpk";
+
+    new_pkgs_.emplace_back(pkgid, version, type, true);
+  }
+
+  closedir(dir);
+
+  return 0;
+}
+
+string PkgFinder::GetValidManifest(string manifest) {
+  size_t found = manifest.rfind(".xml");
+  if (found == string::npos)
+    return "";
+
+  return manifest;
+}
+
+string PkgFinder::FindInfoFromXml(const string& manifest,
+    const string& find_info) {
+  const xmlChar* node;
+  xmlTextReaderPtr reader;
+  string info_val;
+  xmlChar* tmp = nullptr;
+
+  reader = xmlReaderForFile(manifest.c_str(), nullptr, 0);
+
+  if (reader) {
+    if (MoveToChildElement(reader, -1)) {
+      node = xmlTextReaderConstName(reader);
+      if (!node) {
+        LOG(ERROR) << "xmlTextReaderConstName value is NULL";
+        goto end;
+      }
+
+      if (!strcmp(ASCII(node), "manifest")) {
+        tmp = xmlTextReaderGetAttribute(reader,
+          XMLCHAR(find_info.c_str()));
+        if (tmp) {
+          info_val = ASCII(tmp);
+          free(tmp);
+          tmp = nullptr;
+        }
+      } else {
+        LOG(ERROR) << "Manifest Node is not found";
+      }
+    }
+  } else {
+    LOG(ERROR) << "xmlReaderForFile value is NULL";
+  }
+
+end:
+  if (reader)
+    xmlFreeTextReader(reader);
+
+  return info_val;
+}
+
+int PkgFinder::MoveToChildElement(xmlTextReaderPtr reader,
+    int depth) {
+  int ret = xmlTextReaderRead(reader);
+  int cur = xmlTextReaderDepth(reader);
+  while (ret == 1) {
+    switch (xmlTextReaderNodeType(reader)) {
+    case XML_READER_TYPE_ELEMENT:
+      if (cur == depth + 1)
+        return 1;
+      break;
+    case XML_READER_TYPE_TEXT:
+      if (cur == depth + 1)
+        return 0;
+      break;
+    case XML_READER_TYPE_END_ELEMENT:
+      if (cur == depth)
+        return 0;
+      break;
+    default:
+      if (cur <= depth)
+        return 0;
+      break;
+    }
+
+    ret = xmlTextReaderRead(reader);
+    cur = xmlTextReaderDepth(reader);
+  }
+  return ret;
+}
+
+int PkgFinder::FindPreloadPkgidFromFile() {
+  char buf[kBufSize] = {0};
+  FILE *fp = nullptr;
+
+  fp = fopen(preload_rw_list_path_.c_str(), "r");
+  if (fp == nullptr) {
+    LOG(INFO) << "no preload rw list file";
+    return 0;
+  }
+
+  while (fgets(buf, kBufSize, fp) != NULL) {
+    StrTrim(buf);
+    AddRwPkgInfoFromFile(buf);
+  }
+
+  fclose(fp);
+  return 0;
+}
+
+void PkgFinder::AddRwPkgInfoFromFile(const char* info_str) {
+  if (info_str == nullptr)
+    return;
+
+  string pkgid = GetToken(info_str, kTokenPkgidStr);
+  string version = GetToken(info_str, kTokenVersionStr);
+  string type = GetToken(info_str, kTokenTypeStr);
+  string removable = GetToken(info_str, kTokenRemoveStr);
+
+  transform(type.begin(), type.end(), type.begin(),
+      [](unsigned char c) {
+        return tolower(c);
+      });
+
+  transform(removable.begin(), removable.end(), removable.begin(),
+      [](unsigned char c) {
+        return tolower(c);
+      });
+
+  if (removable == "false")
+    new_pkgs_.emplace_back(pkgid, version, type, false, false);
+  else
+    new_pkgs_.emplace_back(pkgid, version, type, false, true);
+}
+
+string PkgFinder::GetToken(const char* pBuf, const char* pKey) {
+  const char *p = nullptr;
+  const char *pStart = nullptr;
+  const char *pEnd = nullptr;
+
+  p = strstr(pBuf, pKey);
+  if (p == nullptr)
+    return "";
+
+  pStart = p + strlen(pKey);
+  pEnd = strchr(pStart, kSeperatorEnd);
+  if (pEnd == nullptr) {
+    pEnd = strchr(pStart, kSeperatorMid);
+    if (pEnd == nullptr)
+      return "";
+  }
+
+  size_t len = pEnd - pStart;
+  if (len <= 0)
+    return "";
+
+  string res(pStart, len);
+
+  return res;
+}
+
+void PkgFinder::StrTrim(char *input) {
+  char *trim_str = input;
+
+  if (input == nullptr)
+    return;
+
+  while (*input != 0) {
+    if (!isspace(*input)) {
+      *trim_str = *input;
+      trim_str++;
+    }
+    input++;
+  }
+
+  *trim_str = 0;
+  return;
+}
+
+}  // common_fota
\ No newline at end of file
diff --git a/src/pkg_upgrade/src/pkg_upgrader.cc b/src/pkg_upgrade/src/pkg_upgrader.cc
new file mode 100644 (file)
index 0000000..2987e93
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <pkgmgr-info.h>
+
+#include "pkg_upgrader.hh"
+
+namespace common_fota {
+
+PkgUpgrader::PkgUpgrader(const PkgContext& context, PkgOperation pkg_op)
+  : type_(context.GetType()), loc_(context.GetLocation()), op_(pkg_op),
+    id_(context.GetId()), version_(context.GetVersion()),
+    backend_(context.GetId(), context.GetType(), context.GetLocation(),
+        pkg_op, context.IsRemovable()) {
+}
+
+PkgUpgrader::PkgUpgrader(std::string id)
+    : type_(PkgType::UNKNOWN), loc_(PkgLocation::UNKNOWN),
+      op_(PkgOperation::COMPLEX), id_(std::move(id)) {
+}
+
+PkgType PkgUpgrader::GetType() const {
+  return type_;
+}
+
+PkgLocation PkgUpgrader::GetLocation() const {
+  return loc_;
+}
+
+PkgOperation PkgUpgrader::GetOperation() const {
+  return op_;
+}
+
+std::string PkgUpgrader::GetId() const {
+  return id_;
+}
+
+std::string PkgUpgrader::GetVersion() const {
+  return version_;
+}
+
+const BackendInvoker& PkgUpgrader::GetBackendInvoker() const {
+  return backend_;
+}
+
+int PkgUpgrader::CompareVersion(const PkgUpgrader& pkg) const {
+  pkgmgrinfo_version_compare_type compare = PMINFO_VERSION_OLD;
+  int ret = pkgmgrinfo_compare_package_version(version_.c_str(),
+          pkg.GetVersion().c_str(), &compare);
+  if (ret != 0)
+    return -1;
+
+  if (compare == PMINFO_VERSION_NEW)
+    return -1;
+  else if (compare == PMINFO_VERSION_OLD)
+    return 1;
+
+  return 0;
+}
+
+
+}  // common_fota
\ No newline at end of file
diff --git a/src/pkg_upgrade/src/pkg_upgrader_factory.cc b/src/pkg_upgrade/src/pkg_upgrader_factory.cc
new file mode 100644 (file)
index 0000000..0c8848e
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "logging.hh"
+#include "pkg_upgrader_factory.hh"
+#include "ro2rw_upgrader.hh"
+#include "rw2ro_upgrader.hh"
+#include "rw_upgrader.hh"
+#include "simple_upgrader.hh"
+
+using namespace std;
+
+namespace common_fota {
+
+list<unique_ptr<PkgUpgrader>> PkgUpgraderFactory::MakeList(PkgFinder* finder) {
+  if (finder->Find() != 0) {
+    LOG(ERROR) << "PkgFinder::Find() failed";
+    return {};
+  }
+  return Merge(finder->GetOldPkgs(), finder->GetNewPkgs());
+}
+
+list<unique_ptr<PkgUpgrader>> PkgUpgraderFactory::Merge(
+    const list<PkgContext>& old_pkgs, const list<PkgContext>& new_pkgs) {
+  list<unique_ptr<PkgUpgrader>> pkgs;
+
+  for (auto& new_pkg : new_pkgs) {
+    const auto* old_pkg = FindPkgById(old_pkgs, new_pkg.GetId());
+    if (old_pkg != nullptr) {
+      // UPDATE
+      if (old_pkg->IsReadOnly() && new_pkg.IsReadOnly()) {
+        // RO to RO
+        pkgs.emplace_back(new SimpleUpgrader(new_pkg, PkgOperation::UPDATE));
+      } else if (!old_pkg->IsReadOnly() && !new_pkg.IsReadOnly()) {
+        // RW to RW
+        pkgs.emplace_back(new RwUpgrader(
+            unique_ptr<PkgUpgrader>(new SimpleUpgrader(new_pkg,
+                PkgOperation::UPDATE))));
+      } else if (!old_pkg->IsReadOnly() && new_pkg.IsReadOnly()) {
+        // RW to RO
+        pkgs.emplace_back(new Rw2RoUpgrader(
+          unique_ptr<PkgUpgrader>(new SimpleUpgrader(*old_pkg,
+              PkgOperation::UNINSTALL_KEEP_RW_DATA)),
+          unique_ptr<PkgUpgrader>(new SimpleUpgrader(new_pkg,
+              PkgOperation::INSTALL))
+        ));
+      } else if (old_pkg->IsReadOnly() && !new_pkg.IsReadOnly()) {
+        // RO to RW
+        pkgs.emplace_back(new Ro2RwUpgrader(
+          unique_ptr<PkgUpgrader>(new SimpleUpgrader(*old_pkg,
+              PkgOperation::UNINSTALL_KEEP_RW_DATA)),
+          unique_ptr<PkgUpgrader>(new SimpleUpgrader(new_pkg,
+              PkgOperation::INSTALL))
+        ));
+      }
+    } else {
+      // INSTALL
+      if (new_pkg.IsReadOnly()) {
+        // RO
+        pkgs.emplace_back(new SimpleUpgrader(new_pkg, PkgOperation::INSTALL));
+      } else {
+        // RW
+        pkgs.emplace_back(new RwUpgrader(
+            unique_ptr<PkgUpgrader>(new SimpleUpgrader(new_pkg,
+                PkgOperation::INSTALL))));
+      }
+    }
+  }
+
+  for (auto& old_pkg : old_pkgs) {
+    const auto* new_pkg = FindPkgById(new_pkgs, old_pkg.GetId());
+    if (new_pkg == nullptr) {
+      // UNINSTALL
+      if (old_pkg.IsReadOnly()) {
+        pkgs.emplace_back(new SimpleUpgrader(old_pkg,
+            PkgOperation::UNINSTALL));
+      }
+    }
+  }
+
+  return pkgs;
+}
+
+const PkgContext* PkgUpgraderFactory::FindPkgById(
+    const list<PkgContext>& pkgs, string id) {
+  for (auto& pkg : pkgs) {
+    if (pkg.GetId() == id)
+      return &pkg;
+  }
+
+  return nullptr;
+}
+
+}  // common_fota
\ No newline at end of file
diff --git a/src/pkg_upgrade/src/ro2rw_upgrader.cc b/src/pkg_upgrade/src/ro2rw_upgrader.cc
new file mode 100644 (file)
index 0000000..192ad67
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "logging.hh"
+#include "ro2rw_upgrader.hh"
+
+namespace {
+constexpr char kOptZipFile[] = "/usr/system/RestoreDir/opt.zip";
+}  // namespace
+
+namespace common_fota {
+
+Ro2RwUpgrader::Ro2RwUpgrader(std::unique_ptr<PkgUpgrader> old_pkg,
+    std::unique_ptr<PkgUpgrader> new_pkg)
+    : PkgUpgrader(new_pkg->GetId()), old_pkg_(std::move(old_pkg)),
+      new_pkg_(std::move(new_pkg)) {
+}
+
+bool Ro2RwUpgrader::Upgrade() {
+  if (old_pkg_.get() != nullptr) {
+    if (!old_pkg_->Upgrade()) {
+      LOG(ERROR) << "old_pkg_->Upgrade() failed";
+      return false;
+    }
+  }
+
+  if (UnzipPkgFromZip(new_pkg_->GetId().c_str()) != 0) {
+    LOG(ERROR) << "UnzipPkgFromZip(" << new_pkg_->GetId() << ") failed";
+    return false;
+  }
+
+  if (new_pkg_.get() != nullptr) {
+    if (!new_pkg_->Upgrade()) {
+      LOG(ERROR) << "new_pkg_->Upgrade() failed";
+      return false;
+    }
+  }
+
+  return true;
+}
+
+int Ro2RwUpgrader::UnzipFiles(const char* dest_path) {
+  const char* unzip_argv[] = { "/usr/bin/unzip", "-oXqq", kOptZipFile,
+      dest_path, "-d", "/", nullptr };
+  int ret = BackendInvoker::XSystem(unzip_argv);
+
+  return ret;
+}
+
+int Ro2RwUpgrader::UnzipXml(const std::string& pkgid) {
+  std::string path = "opt/share/packages/" + pkgid + ".xml";
+  int ret = UnzipFiles(path.c_str());
+
+  return ret;
+}
+
+int Ro2RwUpgrader::UnzipData(const std::string& pkgid, const std::string& dest) {
+  std::string path = dest + pkgid + "/*";
+  int ret = UnzipFiles(path.c_str());
+  if (ret != 0)
+    return -1;
+
+  return 0;
+}
+
+int Ro2RwUpgrader::UnzipPkgFromZip(const std::string& pkgid) {
+  int ret = -1;
+
+  ret = UnzipXml(pkgid);
+  if (ret != 0) {
+    LOG(ERROR) << "UnzipXml(" << pkgid << ") failed";
+    return ret;
+  }
+
+  ret = UnzipData(pkgid, "opt/usr/globalapps/");
+  if (ret != 0) {
+    LOG(ERROR) << "UnzipData(" << pkgid << ") failed";
+    return ret;
+  }
+
+  ret = UnzipData(pkgid, "opt/etc/skel/apps_rw/");
+  if (ret != 0) {
+    LOG(ERROR) << "UnzipData(" << pkgid << ") failed";
+    return ret;
+  }
+
+  return 0;
+}
+
+}  // common_fota
\ No newline at end of file
diff --git a/src/pkg_upgrade/src/rw2ro_upgrader.cc b/src/pkg_upgrade/src/rw2ro_upgrader.cc
new file mode 100644 (file)
index 0000000..b1f200a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "logging.hh"
+#include "rw2ro_upgrader.hh"
+
+namespace common_fota {
+
+Rw2RoUpgrader::Rw2RoUpgrader(std::unique_ptr<PkgUpgrader> old_pkg,
+    std::unique_ptr<PkgUpgrader> new_pkg)
+    : PkgUpgrader(new_pkg->GetId()), old_pkg_(std::move(old_pkg)),
+      new_pkg_(std::move(new_pkg)) {
+}
+
+bool Rw2RoUpgrader::Upgrade() {
+  if (new_pkg_->CompareVersion(*old_pkg_) >= 0) {
+    if (!old_pkg_->Upgrade()) {
+      LOG(ERROR) << "old_pkg_->Upgrade() failed";
+      return false;
+    }
+
+    if (!new_pkg_->Upgrade()) {
+      LOG(ERROR) << "new_pkg_->Upgrade() failed";
+      return false;
+    }
+  } else {
+    LOG(DEBUG) << "new_pkg version < old_pkg version";
+  }
+
+  return true;
+}
+
+}  // common_fota
\ No newline at end of file
diff --git a/src/pkg_upgrade/src/simple_upgrader.cc b/src/pkg_upgrade/src/simple_upgrader.cc
new file mode 100644 (file)
index 0000000..5ee0ef2
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "simple_upgrader.hh"
+
+namespace common_fota {
+
+SimpleUpgrader::SimpleUpgrader(const PkgContext& context,
+    PkgOperation pkg_op)
+    : PkgUpgrader(context, pkg_op) {
+}
+
+bool SimpleUpgrader::Upgrade() {
+  if (GetBackendInvoker().Run() == 0)
+    return true;
+  return false;
+}
+
+}  // common_fota
\ No newline at end of file
diff --git a/src/pkg_upgrade/src/upgrader.cc b/src/pkg_upgrade/src/upgrader.cc
new file mode 100644 (file)
index 0000000..9e83b98
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/smack.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <pwd.h>
+#include <tzplatform_config.h>
+
+#include "logging.hh"
+#include "pkg_upgrader_factory.hh"
+#include "upgrader.hh"
+
+using namespace std;
+
+namespace {
+constexpr char kLogFileName[] = "/var/log/appfw/app-installers/fota.log";
+constexpr int kLogRotationSize = 1024 * 1024;  // 1MB
+constexpr int kLogMaximumRotation = 3;
+constexpr int kBufSize = 1024;
+constexpr char kDbLabel[] = "User::Home";
+constexpr char kAppfwUser[] = "app_fw";
+
+class File {
+ public:
+  File(const string& path) {
+    fd_ = open(path.c_str(), O_RDONLY);
+  }
+
+  File(const string& path, int flags, mode_t mode) {
+    fd_ = open(path.c_str(), flags, mode);
+  }
+
+  ~File() {
+    if (fd_ != -1)
+      close(fd_);
+  }
+
+  int GetFd() const {
+    return fd_;
+  }
+
+  int FStat(struct stat* statbuf) {
+    return fstat(fd_, statbuf);
+  }
+
+  int FChOwn(uid_t owner, gid_t group) {
+    return fchown(fd_, owner, group);
+  }
+
+  int FChMod(mode_t mode) {
+    return fchmod(fd_, mode);
+  }
+
+  int FSync() {
+    return fsync(fd_);
+  }
+
+ private:
+  int fd_ = -1;
+};
+
+}
+
+namespace common_fota {
+
+Upgrader::Upgrader() {
+  logger_ = shared_ptr<utils::FileLogBackend>(new utils::FileLogBackend(
+      ::kLogFileName, ::kLogRotationSize, ::kLogMaximumRotation));
+  ::utils::LogCore::GetCore().AddLogBackend(logger_);
+  string path = tzplatform_getenv(TZ_SYS_DB);
+  SetDbPath(path);
+}
+
+void Upgrader::SetDbPath(const string& path) {
+  parser_db_ = path + "/.pkgmgr_parser.db";
+  parser_db_journal_ = path + "/.pkgmgr_parser.db-journal";
+  cert_db_ = path + "/.pkgmgr_cert.db";
+  cert_db_journal_ = path + "/.pkgmgr_cert.db-journal";
+}
+
+bool Upgrader::Process(PkgFinder* finder) {
+  if (CheckAndRestoreBackupDbs() != 0) {
+    LOG(ERROR) << "CheckAndRestoreBackupDbs failed";
+    return false;
+  }
+
+  if (MakeBackupDbs() != 0) {
+    LOG(ERROR) << "MakeBackupDbs failed";
+    return false;
+  }
+
+  PkgUpgraderFactory factory;
+  auto list = factory.MakeList(finder);
+
+  for(auto& pkg : list) {
+    if(pkg->Upgrade()) {
+      LOG(DEBUG) << "upgrade success (" << pkg->GetId() << ")";
+      success_list_.push_back(move(pkg));
+    } else {
+      LOG(ERROR) << "upgrade failed (" << pkg->GetId() << ")";
+      failure_list_.push_back(move(pkg));
+    }
+  }
+
+  RemoveBackupDbs();
+
+  logger_->WriteLog(::utils::LogLevel::LOG_INFO, "", "Upgrade Done");
+  logger_->WriteLogToFile();
+  return true;
+}
+
+const list<unique_ptr<PkgUpgrader>>& Upgrader::GetSuccessList() const {
+  return success_list_;
+}
+
+const list<unique_ptr<PkgUpgrader>>& Upgrader::GetFailureList() const {
+  return failure_list_;
+}
+
+int Upgrader::CheckAndRestoreBackupDbs() {
+  if (CheckAndRestoreBackup(parser_db_))
+    return -1;
+
+  if (CheckAndRestoreBackup(parser_db_journal_))
+    return -1;
+
+  if (CheckAndRestoreBackup(cert_db_))
+    return -1;
+
+  if (CheckAndRestoreBackup(cert_db_journal_))
+    return -1;
+
+  return 0;
+}
+
+int Upgrader::CheckAndRestoreBackup(const string& origin_path) {
+  string backup_path = origin_path + ".bck";
+
+  // if backup flag exists, it means the previous backup process aborted.
+  if (access(backup_path.c_str(), F_OK) && CheckBackupFlag(origin_path))
+    return 0;
+
+  if (access(origin_path.c_str(), F_OK) == 0) {
+    if (remove(origin_path.c_str())) {
+      LOG(ERROR) << "cannot remove path(" << origin_path << " : " << errno;
+      return -1;
+    }
+  }
+
+  if (rename(backup_path.c_str(), origin_path.c_str())) {
+    LOG(ERROR) << "fail to rename " << backup_path << " to " <<
+        origin_path << errno;
+    return -1;
+  }
+
+  return 0;
+}
+
+int Upgrader::SetDbPermission(const string& path) {
+  struct stat sb;
+  struct passwd pwd;
+  struct passwd *result;
+  char buf[kBufSize];
+
+  int ret = getpwnam_r(kAppfwUser, &pwd, buf, sizeof(buf), &result);
+  if (result == NULL) {
+    LOG(ERROR) << "getpwnam_r failed: " << errno;
+    return -1;
+  }
+  uid_t uid = pwd.pw_uid;
+
+  ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
+  if (result == NULL) {
+    LOG(ERROR) << "getpwuid_r failed: " << errno;
+    return -1;
+  }
+
+  ::File file(path);
+
+  if (file.GetFd() == -1) {
+    LOG(ERROR) << "open(" << path << "failed: " << errno;
+    return -1;
+  }
+
+  ret = file.FStat(&sb);
+  if (ret == -1) {
+    LOG(ERROR) << "stat " << path << "failed: " << errno;
+    return -1;
+  }
+  if (S_ISLNK(sb.st_mode)) {
+    LOG(ERROR) << path << " is symlink!";
+    return -1;
+  }
+  ret = file.FChOwn(uid, pwd.pw_gid);
+  if (ret == -1) {
+    LOG(ERROR) << "fchown " << path << " failed: " << errno;
+    return -1;
+  }
+
+  mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
+  if (path.find(cert_db_) != string::npos)
+    mode |= S_IWOTH;
+  ret = file.FChMod(mode);
+  if (ret == -1) {
+    LOG(ERROR) << "fchmod " << path << " failed: " << errno;
+    return -1;
+  }
+  file.FSync();
+  if (smack_setlabel(path.c_str(), kDbLabel, SMACK_LABEL_ACCESS))
+    LOG(ERROR) << "failed chsmack -a " << kDbLabel << " " << path;
+
+  return 0;
+}
+
+int Upgrader::CreateBackupFlag(const string& path) {
+  string flag = path + ".bck.flag";
+
+  ::File file(flag, O_CREAT | O_WRONLY, 0644);
+  if (file.GetFd() == -1) {
+    LOG(ERROR) << "failed to create flag file " << flag << ", " << errno;
+    return -1;
+  }
+
+  return 0;
+}
+
+int Upgrader::CheckBackupFlag(const string& path) {
+  string flag = path + ".bck.flag";
+
+  if (access(flag.c_str(), F_OK) != 0)
+    return -1;
+
+  return 0;
+}
+
+int Upgrader::RemoveBackupFlag(const string& path) {
+  string flag = path + ".bck.flag";
+
+  if (remove(flag.c_str())) {
+    LOG(ERROR) << "cannot remove flag file(" << flag << ") " << errno;
+    return -1;
+  }
+
+  return 0;
+}
+
+int Upgrader::BackupFile(const string& src_path, const string& dest_path) {
+  char temp_buf[8192] = {'\0', };
+  size_t size_of_char = sizeof(char);
+  size_t size_of_temp_buf = sizeof(temp_buf);
+
+  if (access(src_path.c_str(), F_OK) != 0) {
+    LOG(ERROR) << "File(" << src_path << ") is not exist";
+    return -1;
+  }
+
+  // if backup flag exists, it means the previous backup process aborted.
+  if (CheckBackupFlag(src_path)) {
+    if (access(dest_path.c_str(), F_OK) == 0) {
+      if (remove(dest_path.c_str())) {
+        LOG(ERROR) << "Failed to remove uncompleted backup file " <<
+            dest_path << " : " << errno;
+        return -1;
+      }
+    }
+  } else {
+    if (CreateBackupFlag(src_path)) {
+      LOG(ERROR) << "failed to create backup flag";
+      return -1;
+    }
+  }
+
+  FILE* src = fopen(src_path.c_str(), "r");
+  unique_ptr<FILE, decltype(fclose)*> src_auto(src, fclose);
+  if (src == nullptr) {
+    LOG(ERROR) << "Failed to open : " << src_path;
+    return -1;
+  }
+
+  FILE* dest = fopen(dest_path.c_str(), "w");
+  unique_ptr<FILE, decltype(fclose)*> dest_auto(dest, fclose);
+  if (dest == nullptr) {
+    LOG(ERROR) << "Failed to open : " << dest_path;
+    return -1;
+  }
+
+  while (!feof(src)) {
+    int rc = fread(temp_buf, size_of_char, size_of_temp_buf, src);
+    fwrite(temp_buf, size_of_char, rc, dest);
+  }
+
+  fsync(fileno(dest));
+  RemoveBackupFlag(src_path);
+
+  return 0;
+}
+
+int Upgrader::BackupDb(const string& src_path, const string& dest_path) {
+  if (BackupFile(src_path, dest_path) != 0)
+    return -1;
+
+  if (SetDbPermission(dest_path) != 0)
+    return -1;
+
+  return 0;
+}
+
+int Upgrader::MakeBackupDbs() {
+  string parser_db_bck = parser_db_ + ".bck";
+  string parser_db_journal_bck = parser_db_journal_ + ".bck";
+  string cert_db_bck = cert_db_ + ".bck";
+  string cert_db_journal_bck = cert_db_journal_ + ".bck";
+
+  if (BackupDb(parser_db_, parser_db_bck) == -1 ) {
+    LOG(ERROR) << "Fail to backup [" << parser_db_ << "] to [" << parser_db_bck <<
+        "]";
+    goto CATCH;
+  }
+
+  if (BackupDb(parser_db_journal_, parser_db_journal_bck) == -1) {
+    LOG(ERROR) << "Fail to backup [" << parser_db_journal_ << "] to [" <<
+        parser_db_journal_bck << "]";
+    goto CATCH;
+  }
+
+  if (BackupDb(cert_db_, cert_db_bck) == -1) {
+    LOG(ERROR) << "Fail to backup [" << cert_db_ << "] to [" <<
+        cert_db_bck << "]";
+    goto CATCH;
+  }
+
+  if (BackupDb(cert_db_journal_, cert_db_journal_bck) == -1) {
+    LOG(ERROR) << "Fail to backup [" << cert_db_journal_ << "] to [" <<
+        cert_db_journal_bck << "]";
+    goto CATCH;
+  }
+
+  return 0;
+
+CATCH:
+  remove(parser_db_bck.c_str());
+  remove(parser_db_journal_bck.c_str());
+  remove(cert_db_bck.c_str());
+  remove(cert_db_journal_bck.c_str());
+
+  return -1;
+}
+
+void Upgrader::RemoveBackupPath(const string& origin_path) {
+  string backup_path = origin_path + ".bck";
+
+  if (remove(origin_path.c_str()))
+    LOG(ERROR) << "cannot remove backup file(" << backup_path << ") " << errno;
+}
+
+void Upgrader::RemoveBackupDbs() {
+  RemoveBackupPath(parser_db_);
+  RemoveBackupPath(parser_db_journal_);
+  RemoveBackupPath(cert_db_);
+  RemoveBackupPath(cert_db_journal_);
+}
+
+}  // common_fota
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c90fac8
--- /dev/null
@@ -0,0 +1 @@
+ADD_SUBDIRECTORY(unit_tests)
diff --git a/tests/mock/mock_hook.h b/tests/mock/mock_hook.h
new file mode 100644 (file)
index 0000000..79831d7
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_MOCK_HOOK_H_
+#define MOCK_MOCK_HOOK_H_
+
+#define MOCK_HOOK_P0(MOCK_CLASS, f)                                            \
+    TestFixture::GetMock<MOCK_CLASS>().f()
+#define MOCK_HOOK_P1(MOCK_CLASS, f, p1)                                        \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1)
+#define MOCK_HOOK_P2(MOCK_CLASS, f, p1, p2)                                    \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2)
+#define MOCK_HOOK_P3(MOCK_CLASS, f, p1, p2, p3)                                \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3)
+#define MOCK_HOOK_P4(MOCK_CLASS, f, p1, p2, p3, p4)                            \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3, p4)
+#define MOCK_HOOK_P5(MOCK_CLASS, f, p1, p2, p3, p4, p5)                        \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3, p4, p5)
+#define MOCK_HOOK_P6(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6)                    \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3, p4, p5, p6)
+#define MOCK_HOOK_P7(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6, p7)                \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3, p4, p5, p6, p7)
+#define MOCK_HOOK_P8(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6, p7, p8)            \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3, p4, p5, p6, p7, p8)
+#define MOCK_HOOK_P10(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)  \
+    TestFixture::GetMock<MOCK_CLASS>().f(                                      \
+        p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
+
+#endif  // MOCK_MOCK_HOOK_H_
diff --git a/tests/mock/module_mock.h b/tests/mock/module_mock.h
new file mode 100644 (file)
index 0000000..0934014
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_MODULE_MOCK_H_
+#define MOCK_MODULE_MOCK_H_
+
+class ModuleMock {
+ public:
+  virtual ~ModuleMock() {}
+};
+
+#endif  // MOCK_MODULE_MOCK_H_
diff --git a/tests/mock/os_mock.cc b/tests/mock/os_mock.cc
new file mode 100644 (file)
index 0000000..009f4ed
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os_mock.h"
+#include "mock_hook.h"
+#include "test_fixture.h"
+
+extern "C" pid_t fork(void) {
+  return MOCK_HOOK_P0(OsMock, fork);
+}
+
+extern "C" pid_t waitpid(pid_t pid, int *status, int options) {
+  return MOCK_HOOK_P3(OsMock, waitpid, pid, status, options);
+}
+
+extern "C" int fchown(int fd, uid_t owner, gid_t group) {
+  return MOCK_HOOK_P3(OsMock, fchown, fd, owner, group);
+}
+
+extern "C" int fchmod(int fd, mode_t mode) {
+  return MOCK_HOOK_P2(OsMock, fchmod, fd, mode);
+}
+
+extern "C" int smack_setlabel(const char *path, const char* label,
+    enum smack_label_type type) {
+  return MOCK_HOOK_P3(OsMock, smack_setlabel, path, label, type);
+}
\ No newline at end of file
diff --git a/tests/mock/os_mock.h b/tests/mock/os_mock.h
new file mode 100644 (file)
index 0000000..64970b3
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_OS_MOCK_H_
+#define MOCK_OS_MOCK_H_
+
+#include <gmock/gmock.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/smack.h>
+
+#include "module_mock.h"
+
+class OsMock : public virtual ModuleMock {
+ public:
+  virtual ~OsMock() {}
+
+  MOCK_METHOD0(fork, pid_t());
+  MOCK_METHOD3(waitpid, pid_t(pid_t, int*, int));
+  MOCK_METHOD3(fchown, int(int, uid_t, gid_t));
+  MOCK_METHOD2(fchmod, int(int, mode_t));
+  MOCK_METHOD3(smack_setlabel, int(const char*, const char*, smack_label_type));
+};
+
+#endif  // MOCK_OS_MOCK_H_
diff --git a/tests/mock/pkgmgr_info_mock.cc b/tests/mock/pkgmgr_info_mock.cc
new file mode 100644 (file)
index 0000000..2e0896b
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pkgmgr_info_mock.h"
+#include "mock_hook.h"
+#include "test_fixture.h"
+
+extern "C" int pkgmgrinfo_pkginfo_filter_create(
+    pkgmgrinfo_pkginfo_filter_h *handle) {
+  return MOCK_HOOK_P1(PkgMgrInfoMock, pkgmgrinfo_pkginfo_filter_create, handle);
+}
+
+extern "C" int pkgmgrinfo_pkginfo_filter_destroy(
+    pkgmgrinfo_pkginfo_filter_h handle) {
+  return MOCK_HOOK_P1(PkgMgrInfoMock, pkgmgrinfo_pkginfo_filter_destroy,
+      handle);
+}
+
+extern "C" int pkgmgrinfo_pkginfo_filter_add_bool(
+    pkgmgrinfo_pkginfo_filter_h handle,
+    const char *property, const bool value) {
+  return MOCK_HOOK_P3(PkgMgrInfoMock, pkgmgrinfo_pkginfo_filter_add_bool,
+      handle, property, value);
+}
+
+extern "C" int pkgmgrinfo_pkginfo_filter_foreach_pkginfo(
+    pkgmgrinfo_pkginfo_filter_h handle,
+    pkgmgrinfo_pkg_list_cb pkg_cb, void *user_data) {
+  return MOCK_HOOK_P3(PkgMgrInfoMock, pkgmgrinfo_pkginfo_filter_foreach_pkginfo,
+      handle, pkg_cb, user_data);
+}
+
+extern "C" int pkgmgrinfo_pkginfo_get_pkgid(pkgmgrinfo_pkginfo_h handle,
+    char **pkgid) {
+  return MOCK_HOOK_P2(PkgMgrInfoMock, pkgmgrinfo_pkginfo_get_pkgid,
+      handle, pkgid);
+}
+
+extern "C" int pkgmgrinfo_pkginfo_get_type(pkgmgrinfo_pkginfo_h handle,
+    char **type) {
+  return MOCK_HOOK_P2(PkgMgrInfoMock, pkgmgrinfo_pkginfo_get_type,
+      handle, type);
+}
+
+extern "C" int pkgmgrinfo_pkginfo_get_version(pkgmgrinfo_pkginfo_h handle,
+    char **version) {
+  return MOCK_HOOK_P2(PkgMgrInfoMock, pkgmgrinfo_pkginfo_get_version,
+      handle, version);
+}
\ No newline at end of file
diff --git a/tests/mock/pkgmgr_info_mock.h b/tests/mock/pkgmgr_info_mock.h
new file mode 100644 (file)
index 0000000..2c4e47b
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_PKGMGR_INFO_MOCK_H_
+#define MOCK_PKGMGR_INFO_MOCK_H_
+
+#include <tizen.h>
+#include <gmock/gmock.h>
+#include <pkgmgr-info.h>
+
+#include "module_mock.h"
+
+class PkgMgrInfoMock : public virtual ModuleMock {
+ public:
+  virtual ~PkgMgrInfoMock() {}
+
+  MOCK_METHOD1(pkgmgrinfo_pkginfo_filter_create,
+      int(pkgmgrinfo_pkginfo_filter_h*));
+  MOCK_METHOD1(pkgmgrinfo_pkginfo_filter_destroy,
+      int(pkgmgrinfo_pkginfo_filter_h));
+  MOCK_METHOD3(pkgmgrinfo_pkginfo_filter_add_bool,
+      int(pkgmgrinfo_pkginfo_filter_h, const char*, const bool));
+  MOCK_METHOD3(pkgmgrinfo_pkginfo_filter_foreach_pkginfo,
+      int(pkgmgrinfo_pkginfo_filter_h, pkgmgrinfo_pkg_list_cb, void*));
+  MOCK_METHOD2(pkgmgrinfo_pkginfo_get_pkgid, int(pkgmgrinfo_pkginfo_h, char**));
+  MOCK_METHOD2(pkgmgrinfo_pkginfo_get_type, int(pkgmgrinfo_pkginfo_h, char**));
+  MOCK_METHOD2(pkgmgrinfo_pkginfo_get_version, int(pkgmgrinfo_pkginfo_h, char**));
+};
+
+#endif  // MOCK_PKGMGR_INFO_MOCK_H_
diff --git a/tests/mock/test_fixture.cc b/tests/mock/test_fixture.cc
new file mode 100644 (file)
index 0000000..27f5666
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test_fixture.h"
+
+#include <memory>
+
+std::unique_ptr<ModuleMock> TestFixture::mock_;
diff --git a/tests/mock/test_fixture.h b/tests/mock/test_fixture.h
new file mode 100644 (file)
index 0000000..db223f1
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_TEST_FIXTURE_H_
+#define MOCK_TEST_FIXTURE_H_
+
+#include <gtest/gtest.h>
+
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include "module_mock.h"
+
+class TestFixture : public ::testing::Test {
+ public:
+  explicit TestFixture(std::unique_ptr<ModuleMock>&& mock) {
+    mock_ = std::move(mock);
+  }
+  virtual ~TestFixture() {
+    mock_.reset();
+  }
+
+  virtual void SetUp() {}
+  virtual void TearDown() {}
+
+  template <typename T>
+  static T& GetMock() {
+    auto ptr = dynamic_cast<T*>(mock_.get());
+    if (!ptr)
+      throw std::invalid_argument("The test does not provide mock of \"" +
+          std::string(typeid(T).name()) + "\"");
+    return *ptr;
+  }
+
+  static std::unique_ptr<ModuleMock> mock_;
+};
+
+#endif  // MOCK_TEST_FIXTURE_H_
diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b946e29
--- /dev/null
@@ -0,0 +1,45 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)\r
+PROJECT(pkgmgr-tool_unittests C CXX)\r
+\r
+INCLUDE(FindPkgConfig)\r
+PKG_CHECK_MODULES(pkgmgr-tool_unittests REQUIRED\r
+  dlog\r
+  gmock\r
+  pkgmgr-parser\r
+  pkgmgr-info\r
+  libtzplatform-config\r
+  libsmack\r
+)\r
+\r
+FOREACH(flag ${pkgmgr-tool_unittests_CFLAGS})\r
+    SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")\r
+ENDFOREACH(flag)\r
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Werror -fPIE")\r
+\r
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -std=c++14")\r
+SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")\r
+SET(CMAKE_CXX_FLAGS_RELEASE "-O2")\r
+\r
+ADD_DEFINITIONS("-DDB_PATH=\"${DB_PATH}\"")\r
+\r
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../../src/pkg_upgrade/include)\r
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../mock)\r
+\r
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src SOURCES)\r
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../../src/pkg_upgrade/src LIB_SOURCES)\r
+LIST(REMOVE_ITEM LIB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../../src/pkg_upgrade/src/main.cc)\r
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../mock MOCK_SOURCES)\r
+\r
+ADD_EXECUTABLE(${PROJECT_NAME}\r
+       ${SOURCES}\r
+       ${MOCK_SOURCES}\r
+       ${LIB_SOURCES}\r
+)\r
+\r
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")\r
+TARGET_LINK_LIBRARIES(${PROJECT_NAME}\r
+    ${pkgmgr-tool_unittests_LDFLAGS}\r
+)\r
+\r
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/bin/)\r
+INSTALL(DIRECTORY data/ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}/data)
\ No newline at end of file
diff --git a/tests/unit_tests/data/db/.pkgmgr_cert.db b/tests/unit_tests/data/db/.pkgmgr_cert.db
new file mode 100644 (file)
index 0000000..86d5ef2
Binary files /dev/null and b/tests/unit_tests/data/db/.pkgmgr_cert.db differ
diff --git a/tests/unit_tests/data/db/.pkgmgr_cert.db-journal b/tests/unit_tests/data/db/.pkgmgr_cert.db-journal
new file mode 100644 (file)
index 0000000..a79929d
Binary files /dev/null and b/tests/unit_tests/data/db/.pkgmgr_cert.db-journal differ
diff --git a/tests/unit_tests/data/db/.pkgmgr_parser.db b/tests/unit_tests/data/db/.pkgmgr_parser.db
new file mode 100644 (file)
index 0000000..95bb964
Binary files /dev/null and b/tests/unit_tests/data/db/.pkgmgr_parser.db differ
diff --git a/tests/unit_tests/data/db/.pkgmgr_parser.db-journal b/tests/unit_tests/data/db/.pkgmgr_parser.db-journal
new file mode 100644 (file)
index 0000000..b20e4d3
Binary files /dev/null and b/tests/unit_tests/data/db/.pkgmgr_parser.db-journal differ
diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_cert.db b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db
new file mode 100644 (file)
index 0000000..86d5ef2
Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db differ
diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal
new file mode 100644 (file)
index 0000000..a79929d
Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal differ
diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal.bck b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal.bck
new file mode 100644 (file)
index 0000000..a79929d
Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal.bck differ
diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_cert.db.bck b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db.bck
new file mode 100644 (file)
index 0000000..86d5ef2
Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db.bck differ
diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_parser.db b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db
new file mode 100644 (file)
index 0000000..95bb964
Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db differ
diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal
new file mode 100644 (file)
index 0000000..b20e4d3
Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal differ
diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal.bck b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal.bck
new file mode 100644 (file)
index 0000000..b20e4d3
Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal.bck differ
diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_parser.db.bck b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db.bck
new file mode 100644 (file)
index 0000000..95bb964
Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db.bck differ
diff --git a/tests/unit_tests/data/packages/org.tizen.alarm.xml b/tests/unit_tests/data/packages/org.tizen.alarm.xml
new file mode 100644 (file)
index 0000000..39e4cad
--- /dev/null
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="4.0" package="org.tizen.alarm" version="2.0.0" type="tpk" readonly="true" preload="true" removable="false">
+    <profile name="wearable"/>
+    <ui-application appid="org.tizen.alarm" exec="/usr/apps/org.tizen.alarm/bin/alarm-app" hw-acceleration="on" multiple="false" nodisplay="false" taskmanage="true" type="capp">
+        <label>Alarm</label>
+        <label xml:lang="ar-ae">تنبيه</label>
+        <label xml:lang="az-az">Siqnal</label>
+        <label xml:lang="bg-bg">Аларма</label>
+        <label xml:lang="ca-es">Alarma</label>
+        <label xml:lang="cs-cz">Upozornění</label>
+        <label xml:lang="da-dk">Alarm</label>
+        <label xml:lang="de-de">Alarm</label>
+        <label xml:lang="el-gr">Ξυπνητήρι</label>
+        <label xml:lang="en-gb">Alarm</label>
+        <label xml:lang="en-ph">Alarm</label>
+        <label xml:lang="en-us">Alarm</label>
+        <label xml:lang="es-es">Alarma</label>
+        <label xml:lang="es-mx">Alarma</label>
+        <label xml:lang="et-ee">Märguanne</label>
+        <label xml:lang="eu-es">Alarma</label>
+        <label xml:lang="fi-fi">Hälytys</label>
+        <label xml:lang="fr-ca">Alarme</label>
+        <label xml:lang="fr-fr">Alarme</label>
+        <label xml:lang="ga-ie">Aláram</label>
+        <label xml:lang="gl-es">Alarma</label>
+        <label xml:lang="hr-hr">Alarm</label>
+        <label xml:lang="hu-hu">Jelzés</label>
+        <label xml:lang="hy-am">Տագնապ</label>
+        <label xml:lang="is-is">Vekjari</label>
+        <label xml:lang="it-it">Sveglia</label>
+        <label xml:lang="ja-jp">アラーム</label>
+        <label xml:lang="ka-ge">სიგნალი</label>
+        <label xml:lang="kk-kz">Оятар</label>
+        <label xml:lang="ko-kr">알람</label>
+        <label xml:lang="lt-lt">Signalas</label>
+        <label xml:lang="lv-lv">Signāls</label>
+        <label xml:lang="mk-mk">Аларм</label>
+        <label xml:lang="nb-no">Alarm</label>
+        <label xml:lang="nl-nl">Alarm</label>
+        <label xml:lang="pl-pl">Alarm</label>
+        <label xml:lang="pt-br">Alarme</label>
+        <label xml:lang="pt-pt">Alarme</label>
+        <label xml:lang="ro-ro">Alarmă</label>
+        <label xml:lang="ru-ru">Будильник</label>
+        <label xml:lang="sk-sk">Budík</label>
+        <label xml:lang="sl-si">Alarm</label>
+        <label xml:lang="sr-rs">Beleška</label>
+        <label xml:lang="sv-se">Alarm</label>
+        <label xml:lang="tr-tr">Alarm</label>
+        <label xml:lang="uk-ua">Будильник</label>
+        <label xml:lang="uz-uz">Uyg‘otgich</label>
+        <label xml:lang="zh-cn">闹钟</label>
+        <label xml:lang="zh-hk">鬧鐘</label>
+        <label xml:lang="zh-tw">鬧鐘</label>
+        <icon>org.tizen.alarm.png</icon>
+    </ui-application>
+    <ui-application appid="org.tizen.alarm.app-control" exec="/usr/apps/org.tizen.alarm/bin/alarm-app" hw-acceleration="on" multiple="true" nodisplay="true" taskmanage="false" type="capp">
+        <label>Alarm</label>
+        <label xml:lang="ar-ae">تنبيه</label>
+        <label xml:lang="az-az">Siqnal</label>
+        <label xml:lang="bg-bg">Аларма</label>
+        <label xml:lang="ca-es">Alarma</label>
+        <label xml:lang="cs-cz">Upozornění</label>
+        <label xml:lang="da-dk">Alarm</label>
+        <label xml:lang="de-de">Alarm</label>
+        <label xml:lang="el-gr">Ξυπνητήρι</label>
+        <label xml:lang="en-gb">Alarm</label>
+        <label xml:lang="en-ph">Alarm</label>
+        <label xml:lang="en-us">Alarm</label>
+        <label xml:lang="es-es">Alarma</label>
+        <label xml:lang="es-mx">Alarma</label>
+        <label xml:lang="et-ee">Märguanne</label>
+        <label xml:lang="eu-es">Alarma</label>
+        <label xml:lang="fi-fi">Hälytys</label>
+        <label xml:lang="fr-ca">Alarme</label>
+        <label xml:lang="fr-fr">Alarme</label>
+        <label xml:lang="ga-ie">Aláram</label>
+        <label xml:lang="gl-es">Alarma</label>
+        <label xml:lang="hr-hr">Alarm</label>
+        <label xml:lang="hu-hu">Jelzés</label>
+        <label xml:lang="hy-am">Տագնապ</label>
+        <label xml:lang="is-is">Vekjari</label>
+        <label xml:lang="it-it">Sveglia</label>
+        <label xml:lang="ja-jp">アラーム</label>
+        <label xml:lang="ka-ge">სიგნალი</label>
+        <label xml:lang="kk-kz">Оятар</label>
+        <label xml:lang="ko-kr">알람</label>
+        <label xml:lang="lt-lt">Signalas</label>
+        <label xml:lang="lv-lv">Signāls</label>
+        <label xml:lang="mk-mk">Аларм</label>
+        <label xml:lang="nb-no">Alarm</label>
+        <label xml:lang="nl-nl">Alarm</label>
+        <label xml:lang="pl-pl">Alarm</label>
+        <label xml:lang="pt-br">Alarme</label>
+        <label xml:lang="pt-pt">Alarme</label>
+        <label xml:lang="ro-ro">Alarmă</label>
+        <label xml:lang="ru-ru">Будильник</label>
+        <label xml:lang="sk-sk">Budík</label>
+        <label xml:lang="sl-si">Alarm</label>
+        <label xml:lang="sr-rs">Beleška</label>
+        <label xml:lang="sv-se">Alarm</label>
+        <label xml:lang="tr-tr">Alarm</label>
+        <label xml:lang="uk-ua">Будильник</label>
+        <label xml:lang="uz-uz">Uyg‘otgich</label>
+        <label xml:lang="zh-cn">闹钟</label>
+        <label xml:lang="zh-hk">鬧鐘</label>
+        <label xml:lang="zh-tw">鬧鐘</label>
+        <icon>org.tizen.alarm.png</icon>
+        <app-control>
+            <operation name="http://tizen.org/appcontrol/operation/add"/>
+            <mime name="application/vnd.tizen.alarm"/>
+        </app-control>
+        <app-control>
+            <operation name="http://tizen.org/appcontrol/operation/pick"/>
+            <mime name="application/vnd.tizen.alarm"/>
+        </app-control>
+        <app-control>
+            <operation name="http://tizen.org/appcontrol/operation/edit"/>
+            <mime name="application/vnd.tizen.alarm"/>
+        </app-control>
+    </ui-application>
+    <ui-application appid="org.tizen.alarm.alert" exec="/usr/apps/org.tizen.alarm/bin/alarm-app" hw-acceleration="on" multiple="false" nodisplay="true" taskmanage="false" type="capp">
+        <label>Alarm</label>
+        <label xml:lang="ar-ae">تنبيه</label>
+        <label xml:lang="az-az">Siqnal</label>
+        <label xml:lang="bg-bg">Аларма</label>
+        <label xml:lang="ca-es">Alarma</label>
+        <label xml:lang="cs-cz">Upozornění</label>
+        <label xml:lang="da-dk">Alarm</label>
+        <label xml:lang="de-de">Alarm</label>
+        <label xml:lang="el-gr">Ξυπνητήρι</label>
+        <label xml:lang="en-gb">Alarm</label>
+        <label xml:lang="en-ph">Alarm</label>
+        <label xml:lang="en-us">Alarm</label>
+        <label xml:lang="es-es">Alarma</label>
+        <label xml:lang="es-mx">Alarma</label>
+        <label xml:lang="et-ee">Märguanne</label>
+        <label xml:lang="eu-es">Alarma</label>
+        <label xml:lang="fi-fi">Hälytys</label>
+        <label xml:lang="fr-ca">Alarme</label>
+        <label xml:lang="fr-fr">Alarme</label>
+        <label xml:lang="ga-ie">Aláram</label>
+        <label xml:lang="gl-es">Alarma</label>
+        <label xml:lang="hr-hr">Alarm</label>
+        <label xml:lang="hu-hu">Jelzés</label>
+        <label xml:lang="hy-am">Տագնապ</label>
+        <label xml:lang="is-is">Vekjari</label>
+        <label xml:lang="it-it">Sveglia</label>
+        <label xml:lang="ja-jp">アラーム</label>
+        <label xml:lang="ka-ge">სიგნალი</label>
+        <label xml:lang="kk-kz">Оятар</label>
+        <label xml:lang="ko-kr">알람</label>
+        <label xml:lang="lt-lt">Signalas</label>
+        <label xml:lang="lv-lv">Signāls</label>
+        <label xml:lang="mk-mk">Аларм</label>
+        <label xml:lang="nb-no">Alarm</label>
+        <label xml:lang="nl-nl">Alarm</label>
+        <label xml:lang="pl-pl">Alarm</label>
+        <label xml:lang="pt-br">Alarme</label>
+        <label xml:lang="pt-pt">Alarme</label>
+        <label xml:lang="ro-ro">Alarmă</label>
+        <label xml:lang="ru-ru">Будильник</label>
+        <label xml:lang="sk-sk">Budík</label>
+        <label xml:lang="sl-si">Alarm</label>
+        <label xml:lang="sr-rs">Beleška</label>
+        <label xml:lang="sv-se">Alarm</label>
+        <label xml:lang="tr-tr">Alarm</label>
+        <label xml:lang="uk-ua">Будильник</label>
+        <label xml:lang="uz-uz">Uyg‘otgich</label>
+        <label xml:lang="zh-cn">闹钟</label>
+        <label xml:lang="zh-hk">鬧鐘</label>
+        <label xml:lang="zh-tw">鬧鐘</label>
+        <icon>org.tizen.alarm.png</icon>
+    </ui-application>
+    <privileges>
+        <privilege>http://tizen.org/privilege/haptic</privilege>
+        <privilege>http://tizen.org/privilege/datasharing</privilege>
+        <privilege>http://tizen.org/privilege/display</privilege>
+        <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
+        <privilege>http://tizen.org/privilege/alarm.get</privilege>
+        <privilege>http://tizen.org/privilege/alarm.set</privilege>
+    </privileges>
+    <service-application appid="org.tizen.alarm.svc" exec="/usr/apps/org.tizen.alarm/bin/alarm-svc" multiple="false" nodisplay="true" taskmanage="false" type="capp">
+        <label>Alarm Service</label>
+        <icon>org.tizen.alarm.png</icon>
+        <datacontrol access="ReadWrite" providerid="http://alarm.tizen.org/datacontrol/provider/alarm" type="Sql"/>
+    </service-application>
+    <widget-application appid="org.tizen.alarm.widget" exec="/usr/apps/org.tizen.alarm/bin/alarm-widget" main="true" update-period="0">
+        <label>Alarm</label>
+        <icon>org.tizen.alarm.png</icon>
+        <support-size preview="alarm_widget_preview.png">2x2</support-size>
+    </widget-application>
+</manifest>
diff --git a/tests/unit_tests/data/packages/org.tizen.app-selector.xml b/tests/unit_tests/data/packages/org.tizen.app-selector.xml
new file mode 100644 (file)
index 0000000..314cff5
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" package="org.tizen.app-selector" version="0.1.9" api-version="3.0" install-location="internal-only" type="tpk" readonly="true" preload="true" removable="false">
+       <label>Application Selection Popup</label>
+       <description>Application Selection Popup</description>
+       <ui-application appid="org.tizen.app-selector" exec="/usr/apps/org.tizen.app-selector/bin/app-selector" nodisplay="true" multiple="false" type="capp" taskmanage="false" hw-acceleration="on" launch_mode="group">
+               <label>Application Selection Popup</label>
+       </ui-application>
+    <privileges>
+        <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
+       <privilege>http://tizen.org/privilege/mediastorage</privilege>
+       <privilege>http://tizen.org/privilege/externalstorage</privilege>
+    </privileges>
+</manifest>
diff --git a/tests/unit_tests/data/packages/org.tizen.bluetooth.xml b/tests/unit_tests/data/packages/org.tizen.bluetooth.xml
new file mode 100644 (file)
index 0000000..b3f618e
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" package="org.tizen.bluetooth" api-version="3.0" version="2.0.25" install-location="internal-only" type="rpm" preload="true" readonly="true" removable="false">
+       <label>iW bluetooth</label>
+       <author email="insung.cho@samsung.com" href="www.samsung.com">Insung Cho</author>
+       <description>W bluetooth</description>
+       <ui-application appid="org.tizen.bluetooth" exec="/usr/apps/org.tizen.bluetooth/bin/bluetooth" nodisplay="true" multiple="false" type="capp" taskmanage="false" launch_mode="group">
+               <icon/>
+               <label>Bluetooth application</label>
+               <label xml:lang="en-us">Bluetooth application</label>
+               <app-control>
+                       <operation name="http://tizen.org/appcontrol/operation/edit"/>
+                       <mime name="application/x-bluetooth-on-off"/>
+                       <mime name="application/x-bluetooth-visibility"/>
+               </app-control>
+       </ui-application>
+       <privileges>
+               <privilege>http://tizen.org/privilege/bluetooth</privilege>
+               <privilege>http://tizen.org/privilege/bluetooth.admin</privilege>
+       </privileges>
+</manifest>
diff --git a/tests/unit_tests/data/rw/list.txt b/tests/unit_tests/data/rw/list.txt
new file mode 100644 (file)
index 0000000..eaba1da
--- /dev/null
@@ -0,0 +1,2 @@
+"package=org.tizen.new_rw":"version=1.2.0":"type=tpk":"removable=false"
+"package=org.test.pkg2":"version=1.2.0":"type=wgt":"removable=true"
diff --git a/tests/unit_tests/src/test_main.cc b/tests/unit_tests/src/test_main.cc
new file mode 100644 (file)
index 0000000..c2eb730
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+int main(int argc, char** argv) {
+  int ret = -1;
+
+  try {
+    testing::InitGoogleTest(&argc, argv);
+  } catch(...) {
+    std::cout << "Exception occurred" << std::endl;
+  }
+
+  try {
+    ret = RUN_ALL_TESTS();
+  } catch (const ::testing::internal::GoogleTestFailureException& e) {
+    ret = -1;
+    std::cout << "GoogleTestFailureException was thrown:" << e.what() << std::endl;
+  }
+
+  return ret;
+}
diff --git a/tests/unit_tests/src/test_pkg_upgrader.cc b/tests/unit_tests/src/test_pkg_upgrader.cc
new file mode 100644 (file)
index 0000000..1a13125
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+
+#include <memory>
+
+#include "pkgmgr_info_mock.h"
+#include "os_mock.h"
+#include "test_fixture.h"
+#include "pkg_finder.hh"
+#include "pkg_upgrader_factory.hh"
+#include "upgrader.hh"
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::InvokeArgument;
+using ::testing::SaveArg;
+
+using namespace common_fota;
+
+class Mocks : public ::testing::NiceMock<PkgMgrInfoMock>,
+    public ::testing::NiceMock<OsMock> {};
+
+class PkgFinderTest : public TestFixture {
+ public:
+  PkgFinderTest() : TestFixture(std::make_unique<Mocks>()) {}
+  virtual ~PkgFinderTest() {}
+
+  virtual void SetUp() {
+    static int k;
+    pkgmgrinfo_pkginfo_filter_h dummy_filter = (pkgmgrinfo_pkginfo_filter_h)&k;
+
+    EXPECT_CALL(GetMock<PkgMgrInfoMock>(), pkgmgrinfo_pkginfo_filter_create(_))
+        .WillRepeatedly(DoAll(SetArgPointee<0>(dummy_filter), Return(0)));
+    EXPECT_CALL(GetMock<PkgMgrInfoMock>(),
+        pkgmgrinfo_pkginfo_filter_add_bool(_, _, _))
+        .WillRepeatedly(Return(0));
+
+    EXPECT_CALL(GetMock<PkgMgrInfoMock>(),
+        pkgmgrinfo_pkginfo_filter_foreach_pkginfo(_, _, _))
+        .WillOnce(
+            Invoke([](pkgmgrinfo_pkginfo_filter_h handle,
+                pkgmgrinfo_pkg_list_cb pkg_cb, void *user_data) -> int {
+              pkg_cb(nullptr, user_data);
+              pkg_cb(nullptr, user_data);
+              pkg_cb(nullptr, user_data);
+              return 0;
+            })
+        )
+        .WillOnce(Invoke([](pkgmgrinfo_pkginfo_filter_h handle,
+                pkgmgrinfo_pkg_list_cb pkg_cb, void *user_data) -> int {
+              pkg_cb(nullptr, user_data);
+              return 0;
+            }));
+
+    const char* old_ro_pkgid[] = {
+      "org.test.pkg1",
+      "org.test.pkg2",
+      "org.tizen.app-selector"
+    };
+
+    const char* old_ro_pkg_type[] = {
+      "tpk",
+      "wgt",
+      "tpk"
+    };
+
+    const char* old_ro_pkg_version[] = {
+      "1.0.0",
+      "1.2.0",
+      "0.1.0"
+    };
+
+    const char* old_rw_pkgid[] = {
+      "org.tizen.alarm"
+    };
+
+    const char* old_rw_pkg_type[] = {
+      "tpk"
+    };
+
+    const char* old_rw_pkg_version[] = {
+      "1.5.0",
+    };
+
+    EXPECT_CALL(GetMock<PkgMgrInfoMock>(),
+        pkgmgrinfo_pkginfo_get_pkgid(_,_))
+        .WillOnce(DoAll(SetArgPointee<1>(const_cast<char*>(old_ro_pkgid[0])), Return(0)))
+        .WillOnce(DoAll(SetArgPointee<1>(const_cast<char*>(old_ro_pkgid[1])), Return(0)))
+        .WillOnce(DoAll(SetArgPointee<1>(const_cast<char*>(old_ro_pkgid[2])), Return(0)))
+        .WillOnce(DoAll(SetArgPointee<1>(const_cast<char*>(old_rw_pkgid[0])), Return(0)));
+    EXPECT_CALL(GetMock<PkgMgrInfoMock>(),
+        pkgmgrinfo_pkginfo_get_type(_,_))
+        .WillOnce(DoAll(SetArgPointee<1>(const_cast<char*>(old_ro_pkg_type[0])), Return(0)))
+        .WillOnce(DoAll(SetArgPointee<1>(const_cast<char*>(old_ro_pkg_type[1])), Return(0)))
+        .WillOnce(DoAll(SetArgPointee<1>(const_cast<char*>(old_ro_pkg_type[2])), Return(0)))
+        .WillOnce(DoAll(SetArgPointee<1>(const_cast<char*>(old_rw_pkg_type[0])), Return(0)));
+    EXPECT_CALL(GetMock<PkgMgrInfoMock>(),
+        pkgmgrinfo_pkginfo_get_version(_,_))
+        .WillOnce(DoAll(SetArgPointee<1>(const_cast<char*>(old_ro_pkg_version[0])), Return(0)))
+        .WillOnce(DoAll(SetArgPointee<1>(const_cast<char*>(old_ro_pkg_version[1])), Return(0)))
+        .WillOnce(DoAll(SetArgPointee<1>(const_cast<char*>(old_ro_pkg_version[2])), Return(0)))
+        .WillOnce(DoAll(SetArgPointee<1>(const_cast<char*>(old_rw_pkg_version[0])), Return(0)));
+
+    EXPECT_CALL(GetMock<PkgMgrInfoMock>(), pkgmgrinfo_pkginfo_filter_destroy(_))
+        .WillRepeatedly(Return(0));
+
+    finder_.SetManifestDir("./tests/unit_tests/data/packages/");
+    finder_.SetPreloadRwListPath("./tests/unit_tests/data/rw/list.txt");
+  }
+
+  virtual void TearDown() {
+  }
+
+  PkgFinder finder_;
+};
+
+TEST_F(PkgFinderTest, PkgFinder) {
+  finder_.Find();
+
+  EXPECT_EQ(finder_.GetOldPkgs().size(), 4);
+  EXPECT_EQ(finder_.GetNewPkgs().size(), 5);
+}
+
+TEST_F(PkgFinderTest, PkgUpgraderFactory) {
+  PkgUpgraderFactory factory;
+  auto list = factory.MakeList(&finder_);
+
+  EXPECT_EQ(list.size(), 6);
+}
+
+class PkgUpgraderTest : public PkgFinderTest {
+ public:
+  PkgUpgraderTest() {}
+  virtual ~PkgUpgraderTest() {}
+
+  void SetUp() override {
+    PkgFinderTest::SetUp();
+    EXPECT_CALL(GetMock<OsMock>(), fork())
+        .WillRepeatedly(Return(1));
+    EXPECT_CALL(GetMock<OsMock>(), waitpid(_, _, _))
+          .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(1)));
+    EXPECT_CALL(GetMock<OsMock>(), fchown(_, _, _))
+          .WillRepeatedly(Return(0));
+    EXPECT_CALL(GetMock<OsMock>(), fchmod(_, _))
+          .WillRepeatedly(Return(0));
+    EXPECT_CALL(GetMock<OsMock>(), smack_setlabel(_, _, _))
+          .WillRepeatedly(Return(0));
+  }
+
+  void TearDown() override {
+    PkgFinderTest::TearDown();
+  }
+};
+
+TEST_F(PkgUpgraderTest, Upgrader) {
+  Upgrader upgrader;
+
+  upgrader.SetDbPath("./tests/unit_tests/data/db");
+  ASSERT_TRUE(upgrader.Process(&finder_));
+
+  const auto& success = upgrader.GetSuccessList();
+  const auto& failure = upgrader.GetFailureList();
+
+  EXPECT_EQ(success.size(), 6);
+  EXPECT_EQ(failure.size(), 0);
+}
+
+TEST_F(PkgUpgraderTest, Upgrader_db_bck) {
+  Upgrader upgrader;
+
+  upgrader.SetDbPath("./tests/unit_tests/data/db_bck");
+  EXPECT_TRUE(upgrader.Process(&finder_));
+}
+
+class PkgUpgraderTestForInvalidDbPath : public TestFixture {
+ public:
+  PkgUpgraderTestForInvalidDbPath() : TestFixture(std::make_unique<Mocks>()) {}
+  virtual ~PkgUpgraderTestForInvalidDbPath() {}
+
+  virtual void SetUp() {
+    finder_.SetManifestDir("./tests/unit_tests/data/packages/");
+    finder_.SetPreloadRwListPath("./tests/unit_tests/data/rw/list.txt");
+  }
+
+  virtual void TearDown() {
+  }
+
+  PkgFinder finder_;
+};
+
+TEST_F(PkgUpgraderTestForInvalidDbPath, Upgrader_invalid_db) {
+  Upgrader upgrader;
+
+  upgrader.SetDbPath("./tests/unit_tests/data/invalid_path");
+  EXPECT_FALSE(upgrader.Process(&finder_));
+}