Move tpk-backend implementation from app-installers 87/54887/3 accepted/tizen/mobile/20151219.044134 accepted/tizen/tv/20151219.044545 accepted/tizen/wearable/20151219.044842 submit/tizen/20151218.151823
authorTomasz Iwanek <t.iwanek@samsung.com>
Mon, 14 Dec 2015 13:23:59 +0000 (14:23 +0100)
committerTomasz Iwanek <t.iwanek@samsung.com>
Fri, 18 Dec 2015 12:40:12 +0000 (13:40 +0100)
Requires to be submitted with:
 - https://review.tizen.org/gerrit/#/c/54291/

Aligned with app-installer's commit: 532a4707928d6d137c2cb93ae3523f25f0ac06ee

Change-Id: I9aa00bf8e150e9d2b01fbcb3753d0927d98cebeb

34 files changed:
CMakeLists.txt [new file with mode: 0644]
cmake/Modules/ApplyPkgConfig.cmake [new file with mode: 0644]
packaging/tpk-backend-tests.manifest [new file with mode: 0644]
packaging/tpk-backend.manifest [new file with mode: 0644]
packaging/tpk-backend.spec
src/CMakeLists.txt [new file with mode: 0644]
src/tpk/CMakeLists.txt [new file with mode: 0644]
src/tpk/step/step_check_tpk_background_category.cc [new file with mode: 0644]
src/tpk/step/step_check_tpk_background_category.h [new file with mode: 0644]
src/tpk/step/step_convert_xml.cc [new file with mode: 0644]
src/tpk/step/step_convert_xml.h [new file with mode: 0644]
src/tpk/step/step_create_symbolic_link.cc [new file with mode: 0644]
src/tpk/step/step_create_symbolic_link.h [new file with mode: 0644]
src/tpk/step/step_parse.cc [new file with mode: 0644]
src/tpk/step/step_parse.h [new file with mode: 0644]
src/tpk/step/step_parse_recovery.cc [new file with mode: 0644]
src/tpk/step/step_parse_recovery.h [new file with mode: 0644]
src/tpk/tpk_app_query_interface.cc [new file with mode: 0644]
src/tpk/tpk_app_query_interface.h [new file with mode: 0644]
src/tpk/tpk_backend.cc [new file with mode: 0644]
src/tpk/tpk_installer.cc [new file with mode: 0644]
src/tpk/tpk_installer.h [new file with mode: 0644]
src/unit_tests/CMakeLists.txt [new file with mode: 0644]
src/unit_tests/smoke_test.cc [new file with mode: 0644]
src/unit_tests/test_samples/smoke/DeinstallationMode_Tpk.tpk [new file with mode: 0644]
src/unit_tests/test_samples/smoke/DeltaMode_Tpk.delta [new file with mode: 0644]
src/unit_tests/test_samples/smoke/DeltaMode_Tpk.tpk [new file with mode: 0644]
src/unit_tests/test_samples/smoke/InstallationMode_Tpk.tpk [new file with mode: 0644]
src/unit_tests/test_samples/smoke/RecoveryMode_Tpk_Installation.tpk [new file with mode: 0644]
src/unit_tests/test_samples/smoke/RecoveryMode_Tpk_Update.tpk [new file with mode: 0644]
src/unit_tests/test_samples/smoke/RecoveryMode_Tpk_Update_2.tpk [new file with mode: 0644]
src/unit_tests/test_samples/smoke/UpdateMode_Tpk.tpk [new file with mode: 0644]
src/unit_tests/test_samples/smoke/UpdateMode_Tpk_2.tpk [new file with mode: 0644]
src/unit_tests/test_samples/tpk-sample-manifest.xml [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..13f7498
--- /dev/null
@@ -0,0 +1,46 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12)
+PROJECT(TpkBackend)
+SET(PREFIX "${CMAKE_INSTALL_PREFIX}")
+SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin")
+SET(LIBDIR "${CMAKE_INSTALL_LIBDIR}")
+SET(SHAREDIR "${CMAKE_INSTALL_PREFIX}/share")
+SET(INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include")
+SET(VERSION_MAJOR 0)
+SET(VERSION "${VERSION_MAJOR}.1.0")
+
+IF(NOT CMAKE_BUILD_TYPE)
+  SET(CMAKE_BUILD_TYPE "Release")
+ENDIF(NOT CMAKE_BUILD_TYPE)
+
+# Compiler flags
+SET(CMAKE_C_FLAGS_PROFILING    "-O2")
+SET(CMAKE_CXX_FLAGS_PROFILING  "-O2 -std=c++11")
+SET(CMAKE_C_FLAGS_DEBUG        "-O0 -g")
+SET(CMAKE_CXX_FLAGS_DEBUG      "-O0 -std=c++11 -g")
+SET(CMAKE_C_FLAGS_RELEASE      "-O2 -g")
+SET(CMAKE_CXX_FLAGS_RELEASE    "-O2 -std=c++11 -g")
+SET(CMAKE_CXX_FLAGS_CCOV       "-O0 -std=c++11 -g --coverage")
+
+# Targets
+SET(TARGET_LIBNAME_TPK "tpk-installer")
+SET(TARGET_TPK_BACKEND "tpk-backend")
+
+ADD_DEFINITIONS("-Wall")
+ADD_DEFINITIONS("-Wextra")
+ADD_DEFINITIONS("-fPIE")
+ADD_DEFINITIONS("-fPIC")
+
+SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
+INCLUDE(FindPkgConfig)
+INCLUDE(ApplyPkgConfig)
+
+# Find all needed packages once
+PKG_CHECK_MODULES(APP_INSTALLERS_DEPS REQUIRED app-installers)
+PKG_CHECK_MODULES(PKGMGR_DEPS REQUIRED pkgmgr)
+PKG_CHECK_MODULES(TPK_MANIFEST_HANDLERS_DEPS REQUIRED tpk-manifest-handlers)
+PKG_CHECK_MODULES(MANIFEST_PARSER_DEPS REQUIRED manifest-parser)
+
+FIND_PACKAGE(Boost REQUIRED COMPONENTS system filesystem regex program_options)
+FIND_PACKAGE(GTest REQUIRED)
+
+ADD_SUBDIRECTORY(src)
diff --git a/cmake/Modules/ApplyPkgConfig.cmake b/cmake/Modules/ApplyPkgConfig.cmake
new file mode 100644 (file)
index 0000000..97679d7
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+#
+# This function applies external (out of source tree) dependencies
+# to given target. Arguments are:
+#   TARGET - valid cmake target
+#   PRIVACY - dependency can be inherited by dependent targets or not:
+#     PUBLIC - this should be used by default, cause compile/link flags passing
+#     PRIVATE - do not passes any settings to dependent targets,
+#               may be usefull for static libraries from the inside of the project
+# Argument ARGV2 and following are supposed to be names of checked pkg config
+# packages. This function will use variables created by check_pkg_modules().
+#  - ${DEP_NAME}_LIBRARIES
+#  - ${DEP_NAME}_INCLUDE_DIRS
+#  - ${DEP_NAME}_CFLAGS
+#
+FUNCTION(APPLY_PKG_CONFIG TARGET PRIVACY)
+  MATH(EXPR DEST_INDEX "${ARGC}-1")
+  FOREACH(I RANGE 2 ${DEST_INDEX})
+    IF(NOT ${ARGV${I}}_FOUND)
+      MESSAGE(FATAL_ERROR "Not found dependency - ${ARGV${I}}_FOUND")
+    ENDIF(NOT ${ARGV${I}}_FOUND)
+    TARGET_LINK_LIBRARIES(${TARGET} ${PRIVACY} "${${ARGV${I}}_LIBRARIES}")
+    TARGET_INCLUDE_DIRECTORIES(${TARGET} ${PRIVACY} SYSTEM "${${ARGV${I}}_INCLUDE_DIRS}")
+    STRING(REPLACE ";" " " CFLAGS_STR "${${ARGV${I}}_CFLAGS}")
+    SET(CFLAGS_LIST ${CFLAGS_STR})
+    SEPARATE_ARGUMENTS(CFLAGS_LIST)
+    FOREACH(OPTION ${CFLAGS_LIST})
+      TARGET_COMPILE_OPTIONS(${TARGET} ${PRIVACY} ${OPTION})
+    ENDFOREACH(OPTION)
+    SET_TARGET_PROPERTIES(${TARGET} PROPERTIES SKIP_BUILD_RPATH true)
+  ENDFOREACH(I RANGE 2 ${DEST_INDEX})
+ENDFUNCTION(APPLY_PKG_CONFIG TARGET PRIVACY)
diff --git a/packaging/tpk-backend-tests.manifest b/packaging/tpk-backend-tests.manifest
new file mode 100644 (file)
index 0000000..ddd4d34
--- /dev/null
@@ -0,0 +1,8 @@
+<manifest>
+        <request>
+                <domain name="_" />
+        </request>
+        <assign>
+                <filesystem path="/usr/bin/tpk-backend-ut/smoke_test" exec_label="User" />
+        </assign>
+</manifest>
diff --git a/packaging/tpk-backend.manifest b/packaging/tpk-backend.manifest
new file mode 100644 (file)
index 0000000..925f49b
--- /dev/null
@@ -0,0 +1,8 @@
+<manifest>
+        <request>
+                <domain name="_" />
+        </request>
+        <assign>
+                <filesystem path="/usr/bin/tpk-backend" exec_label="User" />
+        </assign>
+</manifest>
index aa13db5..16b4f7b 100644 (file)
@@ -8,10 +8,54 @@ Release:        1
 Group:          Application Framework/Package Management
 License:        Apache-2.0
 Source0:        %{name}-%{version}.tar.gz
+Source1000:     tpk-backend.manifest
+Source1001:     tpk-backend-tests.manifest
 
+BuildRequires:  boost-devel
+BuildRequires:  cmake
+BuildRequires:  gtest-devel
+BuildRequires:  pkgconfig(app-installers)
+BuildRequires:  pkgconfig(manifest-parser)
+BuildRequires:  pkgconfig(pkgmgr)
+BuildRequires:  pkgconfig(tpk-manifest-handlers)
+
+%description
+Backend for tizen package files
+
+%package tests
+Summary: Unit tests for tpk-backend
+Requires: %{name} = %{version}
+
+%description tests
+Unit tests for al modules of app-installers
+
+%prep
+%setup -q
+
+cp %{SOURCE1000} .
+cp %{SOURCE1001} .
+
+%build
+%cmake . -DCMAKE_BUILD_TYPE=%{?build_type:%build_type}
+make %{?_smp_mflags}
+
+%install
+%make_install
+
+mkdir -p %{buildroot}/etc/package-manager/backend
+ln -s %{_bindir}/tpk-backend %{buildroot}%{_sysconfdir}/package-manager/backend/tpk
+
+%files
+%{_sysconfdir}/package-manager/backend/tpk
+%license LICENSE
+%manifest tpk-backend.manifest
+%{_bindir}/tpk-backend
+
+%files tests
+%manifest tpk-backend-tests.manifest
+%{_bindir}/tpk-backend-ut/*
+%{_datadir}/tpk-backend-ut/*
 
 %changelog
 * Thu Dec 18 2015 Pawel Sikorski <p.sikorski@samsung.com> 0.1-1
 - initial files creation
-
-
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6e53623
--- /dev/null
@@ -0,0 +1,2 @@
+ADD_SUBDIRECTORY(tpk)
+ADD_SUBDIRECTORY(unit_tests)
diff --git a/src/tpk/CMakeLists.txt b/src/tpk/CMakeLists.txt
new file mode 100644 (file)
index 0000000..cc121b6
--- /dev/null
@@ -0,0 +1,26 @@
+SET(SRCS
+    step/step_check_tpk_background_category.cc
+    step/step_create_symbolic_link.cc
+    step/step_parse.cc
+    step/step_parse_recovery.cc
+    step/step_convert_xml.cc
+    tpk_app_query_interface.cc
+    tpk_installer.cc
+)
+ADD_LIBRARY(${TARGET_LIBNAME_TPK} STATIC ${SRCS})
+ADD_EXECUTABLE(${TARGET_TPK_BACKEND} "tpk_backend.cc")
+
+TARGET_INCLUDE_DIRECTORIES(${TARGET_LIBNAME_TPK} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../")
+TARGET_INCLUDE_DIRECTORIES(${TARGET_TPK_BACKEND} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../")
+
+APPLY_PKG_CONFIG(${TARGET_LIBNAME_TPK} PUBLIC
+  APP_INSTALLERS_DEPS
+  PKGMGR_DEPS
+  TPK_MANIFEST_HANDLERS_DEPS
+  MANIFEST_PARSER_DEPS
+  Boost
+)
+
+TARGET_LINK_LIBRARIES(${TARGET_TPK_BACKEND} PRIVATE ${TARGET_LIBNAME_TPK})
+
+INSTALL(TARGETS ${TARGET_TPK_BACKEND} DESTINATION ${BINDIR})
diff --git a/src/tpk/step/step_check_tpk_background_category.cc b/src/tpk/step/step_check_tpk_background_category.cc
new file mode 100644 (file)
index 0000000..47c7729
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#include "tpk/step/step_check_tpk_background_category.h"
+
+#include <common/installer_context.h>
+
+namespace {
+namespace ci_sec = common_installer::security;
+}  // namespace
+
+namespace tpk {
+namespace security {
+
+StepCheckTpkBackgroundCategory::StepCheckTpkBackgroundCategory(
+    common_installer::InstallerContext* context) :
+        ci_sec::StepCheckBackgroundCategory(context) {}
+
+bool StepCheckTpkBackgroundCategory::GetBackgroundSupport() {
+  return true;
+}
+
+}  // namespace security
+}  // namespace tpk
diff --git a/src/tpk/step/step_check_tpk_background_category.h b/src/tpk/step/step_check_tpk_background_category.h
new file mode 100644 (file)
index 0000000..e4bf312
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef TPK_STEP_STEP_CHECK_TPK_BACKGROUND_CATEGORY_H_
+#define TPK_STEP_STEP_CHECK_TPK_BACKGROUND_CATEGORY_H_
+
+#include <manifest_parser/utils/version_number.h>
+
+#include <common/step/step_check_background_category.h>
+
+namespace tpk {
+namespace security {
+
+/**
+ * \brief This step check background category value and modify it depending on
+ *        required version, cert level, background support, and value itself
+ */
+class StepCheckTpkBackgroundCategory :
+    public common_installer::security::StepCheckBackgroundCategory {
+ public:
+  explicit StepCheckTpkBackgroundCategory(
+      common_installer::InstallerContext* context);
+
+ protected:
+  bool GetBackgroundSupport() override;
+};
+
+}  // namespace security
+}  // namespace tpk
+
+#endif  // TPK_STEP_STEP_CHECK_TPK_BACKGROUND_CATEGORY_H_
diff --git a/src/tpk/step/step_convert_xml.cc b/src/tpk/step/step_convert_xml.cc
new file mode 100644 (file)
index 0000000..11b670f
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#include "tpk/step/step_convert_xml.h"
+
+#include <pkgmgr_parser.h>
+#include <pkgmgr-info.h>
+
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/system/error_code.hpp>
+#include <common/utils/glist_range.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+
+#include <string>
+
+
+namespace bs = boost::system;
+namespace bf = boost::filesystem;
+
+namespace {
+
+const xmlChar kExecAttributeKey[] = "exec";
+const xmlChar kXmlNamespaceUri[] = "http://tizen.org/ns/packages";
+const char kXmlXPathAppExpr[] =
+    "//*[local-name()='ui-application' or local-name()='service-application' "
+    "or local-name()='widget-application']";
+
+}  // namespace
+
+namespace common_installer {
+namespace tpk {
+
+Step::Status StepConvertXml::precheck() {
+  bf::path xml_path = context_->pkg_path.get();
+  xml_path /= "tizen-manifest.xml";
+
+  if (!bf::exists(xml_path)) {
+    LOG(ERROR) << "Cannot find manifest file";
+    return Step::Status::INVALID_VALUE;
+  }
+
+  xml_path_ = xml_path;
+
+  return Step::Status::OK;
+}
+
+bool StepConvertXml::ConvertXml(xmlDocPtr doc) {
+  xmlXPathContextPtr xpath_ctx;
+
+  xpath_ctx = xmlXPathNewContext(doc);
+  if (!xpath_ctx) {
+    LOG(ERROR) << "Failed to create XPath context";
+    return false;
+  }
+
+  for (application_x* app :
+       GListRange<application_x*>(context_->manifest_data.get()->application)) {
+    std::string expr;
+    xmlXPathObjectPtr xpath_obj;
+    xmlNodePtr node;
+
+    expr = std::string(kXmlXPathAppExpr) + "[@appid='" + app->appid + "']";
+    xpath_obj = xmlXPathEvalExpression((const xmlChar*)expr.c_str(), xpath_ctx);
+    if (!xpath_obj || !xpath_obj->nodesetval || !xpath_obj->nodesetval->nodeNr)
+      continue;
+
+    node = xpath_obj->nodesetval->nodeTab[0];
+    xmlSetProp(node, kExecAttributeKey, (const xmlChar*)app->exec);
+    xmlXPathFreeObject(xpath_obj);
+  }
+
+  xmlXPathFreeContext(xpath_ctx);
+
+  return true;
+}
+
+Step::Status StepConvertXml::process() {
+  xmlDocPtr doc = xmlParseFile(xml_path_.string().c_str());
+  if (!doc) {
+    LOG(ERROR) << "Failed to parse xml file";
+    return Step::Status::ERROR;
+  }
+
+  if (!ConvertXml(doc))
+    return Step::Status::ERROR;
+
+  bf::path new_path = bf::path(getUserManifestPath(context_->uid.get()))
+      / bf::path(context_->pkgid.get());
+  new_path += ".xml";
+  if (xmlSaveFile(new_path.string().c_str(), doc) == -1) {
+    LOG(ERROR) << "Failed to write xml file";
+    return Step::Status::ERROR;
+  }
+
+  context_->xml_path.set(new_path.string());
+
+  if (pkgmgr_parser_check_manifest_validation(
+      context_->xml_path.get().c_str()) != 0) {
+    LOG(ERROR) << "Manifest is not valid";
+    return Step::Status::ERROR;
+  }
+
+  LOG(DEBUG) << "Successfully create manifest xml "
+      << context_->xml_path.get();
+
+  return Step::Status::OK;
+}
+
+Step::Status StepConvertXml::clean() {
+  return Step::Status::OK;
+}
+
+Step::Status StepConvertXml::undo() {
+  bs::error_code error;
+
+  if (bf::exists(context_->xml_path.get()))
+    bf::remove_all(context_->xml_path.get(), error);
+
+  return Step::Status::OK;
+}
+
+}  // namespace tpk
+}  // namespace common_installer
diff --git a/src/tpk/step/step_convert_xml.h b/src/tpk/step/step_convert_xml.h
new file mode 100644 (file)
index 0000000..273b1c7
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef TPK_STEP_STEP_CONVERT_XML_H_
+#define TPK_STEP_STEP_CONVERT_XML_H_
+
+#include <manifest_parser/utils/logging.h>
+
+#include <boost/filesystem/path.hpp>
+#include <libxml/tree.h>
+
+#include <common/step/step.h>
+
+namespace common_installer {
+namespace tpk {
+
+class StepConvertXml : public common_installer::Step {
+ public:
+  using Step::Step;
+
+  Status process() override;
+  Status clean() override;
+  Status undo() override;
+  Status precheck() override;
+
+ private:
+  boost::filesystem::path xml_path_;
+  bool ConvertXml(xmlDocPtr doc);
+
+  SCOPE_LOG_TAG(ConvertXml)
+};
+
+}  // namespace tpk
+}  // namespace common_installer
+
+#endif  // TPK_STEP_STEP_CONVERT_XML_H_
diff --git a/src/tpk/step/step_create_symbolic_link.cc b/src/tpk/step/step_create_symbolic_link.cc
new file mode 100644 (file)
index 0000000..ca8143a
--- /dev/null
@@ -0,0 +1,96 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#include "tpk/step/step_create_symbolic_link.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/system/error_code.hpp>
+
+#include <common/app_installer.h>
+#include <common/step/step.h>
+#include <common/installer_context.h>
+#include <common/utils/file_util.h>
+#include <common/utils/glist_range.h>
+
+#include <pkgmgr-info.h>
+
+#include <iostream>
+
+namespace tpk {
+namespace filesystem {
+
+namespace bf = boost::filesystem;
+using common_installer::InstallerContext;
+typedef common_installer::Step::Status Status;
+
+namespace {
+
+bool CreateSymLink(application_x* app, InstallerContext* context) {
+  boost::system::error_code boost_error;
+  bf::path bindir = context->pkg_path.get() /
+      bf::path("bin");
+  LOG(DEBUG) << "Creating dir: " << bindir;
+  if (!common_installer::CreateDir(bindir)) {
+    LOG(ERROR) << "Directory creation failure: " << bindir;
+    return false;
+  }
+
+  // Exec path
+  // Make a symlink with the name of appid, pointing exec file
+  bf::path symlink_path = bindir / bf::path(app->appid);
+  LOG(DEBUG) << "Creating symlink " << symlink_path << " pointing " <<
+      app->exec;
+  bf::create_symlink(bf::path(app->exec), symlink_path, boost_error);
+  if (boost_error) {
+    LOG(ERROR) << "Symlink creation failure: " << symlink_path;
+    return false;
+  }
+
+  // Give an execution permission to the original executable
+  LOG(DEBUG) << "Giving exec permission to " << app->exec;
+  bf::permissions(bf::path(app->exec), bf::owner_all |
+      bf::group_read | bf::group_exe |
+      bf::others_read | bf::others_exe, boost_error);
+  if (boost_error) {
+    LOG(ERROR) << "Permission change failure";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+Status StepCreateSymbolicLink::precheck() {
+  manifest_x *m = context_->manifest_data.get();
+  if (!m) {
+    LOG(ERROR) << "manifest_data attribute is empty";
+    return Step::Status::INVALID_VALUE;
+  }
+  if (!m->application) {
+    LOG(ERROR) << "No application exists";
+    return Step::Status::ERROR;
+  }
+
+  return Step::Status::OK;
+}
+
+Status StepCreateSymbolicLink::process() {
+  manifest_x* m = context_->manifest_data.get();
+  for (application_x* app : GListRange<application_x*>(m->application)) {
+    if (!CreateSymLink(app, context_))
+      return Status::ERROR;
+  }
+  return Status::OK;
+}
+
+
+Status StepCreateSymbolicLink::undo() {
+  manifest_x* m = context_->manifest_data.get();
+  Step::Status ret = Status::OK;
+  for (application_x* app : GListRange<application_x*>(m->application)) {
+    if (!CreateSymLink(app, context_))
+      ret = Status::ERROR;
+  }
+  return ret;
+}
+
+}  // namespace filesystem
+}  // namespace tpk
diff --git a/src/tpk/step/step_create_symbolic_link.h b/src/tpk/step/step_create_symbolic_link.h
new file mode 100644 (file)
index 0000000..fc1cad9
--- /dev/null
@@ -0,0 +1,26 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#ifndef TPK_STEP_STEP_CREATE_SYMBOLIC_LINK_H_
+#define TPK_STEP_STEP_CREATE_SYMBOLIC_LINK_H_
+
+#include <manifest_parser/utils/logging.h>
+
+#include <common/app_installer.h>
+
+namespace tpk {
+namespace filesystem {
+
+class StepCreateSymbolicLink : public common_installer::Step {
+ public:
+  using Step::Step;
+  Status process() override;
+  Status clean() override { return Status::OK; }
+  Status undo() override;
+  Status precheck() override;
+
+  SCOPE_LOG_TAG(SymbolicLink)
+};
+
+}  // namespace filesystem
+}  // namespace tpk
+
+#endif  // TPK_STEP_STEP_CREATE_SYMBOLIC_LINK_H_
diff --git a/src/tpk/step/step_parse.cc b/src/tpk/step/step_parse.cc
new file mode 100644 (file)
index 0000000..24109b7
--- /dev/null
@@ -0,0 +1,672 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache 2.0 license that can be
+// found in the LICENSE file.
+
+#include "tpk/step/step_parse.h"
+
+#include <common/app_installer.h>
+#include <common/installer_context.h>
+#include <common/step/step.h>
+#include <common/utils/glist_range.h>
+
+#include <tpk_manifest_handlers/account_handler.h>
+#include <tpk_manifest_handlers/application_manifest_constants.h>
+#include <tpk_manifest_handlers/author_handler.h>
+#include <tpk_manifest_handlers/description_handler.h>
+#include <tpk_manifest_handlers/package_handler.h>
+#include <tpk_manifest_handlers/privileges_handler.h>
+#include <tpk_manifest_handlers/profile_handler.h>
+#include <tpk_manifest_handlers/service_application_handler.h>
+#include <tpk_manifest_handlers/shortcut_handler.h>
+#include <tpk_manifest_handlers/ui_application_handler.h>
+#include <tpk_manifest_handlers/widget_application_handler.h>
+#include <manifest_parser/manifest_constants.h>
+
+#include <pkgmgr/pkgmgr_parser.h>
+
+#include <chrono>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <memory>
+#include <set>
+#include <type_traits>
+#include <string>
+#include <vector>
+
+
+namespace tpk {
+namespace parse {
+
+namespace {
+
+namespace app_keys = tpk::application_keys;
+namespace bf = boost::filesystem;
+
+const char kManifestFileName[] = "tizen-manifest.xml";
+
+}  // namepsace
+
+common_installer::Step::Status StepParse::precheck() {
+  if (context_->unpacked_dir_path.get().empty()) {
+    LOG(ERROR) << "unpacked_dir_path attribute is empty";
+    return common_installer::Step::Status::INVALID_VALUE;
+  }
+  if (!boost::filesystem::exists(context_->unpacked_dir_path.get())) {
+    LOG(ERROR) << "unpacked_dir_path ("
+               << context_->unpacked_dir_path.get()
+               << ") path does not exist";
+    return common_installer::Step::Status::INVALID_VALUE;
+  }
+
+  boost::filesystem::path tmp;
+  if (!context_->xml_path.get().empty()) {
+    tmp = context_->xml_path.get();
+  } else {
+    tmp = context_->unpacked_dir_path.get();
+    tmp /= kManifestFileName;
+  }
+
+  if (!boost::filesystem::exists(tmp)) {
+    LOG(ERROR) << "manifest not found from the package";
+    return common_installer::Step::Status::INVALID_VALUE;
+  }
+
+  return common_installer::Step::Status::OK;
+}
+
+bool StepParse::LocateConfigFile() {
+  boost::filesystem::path manifest;
+  if (!context_->xml_path.get().empty()) {
+    manifest = context_->xml_path.get();
+  } else {
+    manifest = context_->unpacked_dir_path.get();
+    manifest /= kManifestFileName;
+  }
+
+  LOG(DEBUG) << "manifest path: " << manifest;
+
+  if (!boost::filesystem::exists(manifest))
+    return false;
+
+  path_ = manifest;
+  return true;
+}
+
+bf::path StepParse::LocateConfigFile() const {
+  boost::filesystem::path path;
+  if (!context_->xml_path.get().empty()) {
+    path = context_->xml_path.get();
+  } else {
+    path = context_->unpacked_dir_path.get();
+    path /= kManifestFileName;
+  }
+  return path;
+}
+
+bool StepParse::FillInstallationInfo(manifest_x* manifest) {
+  manifest->root_path = strdup(
+      (context_->root_application_path.get() / manifest->package).c_str());
+  manifest->installed_time =
+      strdup(std::to_string(std::chrono::system_clock::to_time_t(
+          std::chrono::system_clock::now())).c_str());
+  return true;
+}
+
+bool StepParse::FillPackageInfo(manifest_x* manifest) {
+  std::shared_ptr<const PackageInfo> pkg_info =
+      std::static_pointer_cast<const PackageInfo>(
+          parser_->GetManifestData(app_keys::kManifestKey));
+  if (!pkg_info) {
+    LOG(ERROR) << "Package info manifest data has not been found.";
+    return false;
+  }
+
+  std::shared_ptr<const UIApplicationInfoList> ui_application_list =
+      std::static_pointer_cast<const UIApplicationInfoList>(
+          parser_->GetManifestData(app_keys::kUIApplicationKey));
+  std::shared_ptr<const ServiceApplicationInfoList> service_application_list =
+      std::static_pointer_cast<const ServiceApplicationInfoList>(
+          parser_->GetManifestData(app_keys::kServiceApplicationKey));
+  std::shared_ptr<const WidgetApplicationInfoList> widget_application_list =
+      std::static_pointer_cast<const WidgetApplicationInfoList>(
+          parser_->GetManifestData(app_keys::kWidgetApplicationKey));
+
+  // mandatory check
+  if (!ui_application_list && !service_application_list &&
+      !widget_application_list) {
+    LOG(ERROR) << "UI Application or Service Application or Widget Application "
+                  "are mandatory and has not been found.";
+    return false;
+  }
+
+  manifest->ns = strdup(pkg_info->xmlns().c_str());
+  manifest->package = strdup(pkg_info->package().c_str());
+  manifest->nodisplay_setting = strdup(pkg_info->nodisplay_setting().c_str());
+  manifest->type = strdup("tpk");
+  manifest->appsetting = strdup("false");
+  manifest->support_disable = strdup("false");
+  manifest->version = strdup(pkg_info->version().c_str());
+  manifest->installlocation = strdup(pkg_info->install_location().c_str());
+  manifest->api_version = strdup(pkg_info->api_version().c_str());
+
+  for (auto& pair : pkg_info->labels()) {
+    label_x* label = reinterpret_cast<label_x*>(calloc(1, sizeof(label_x)));
+    if (!pair.first.empty())
+      label->lang = strdup(pair.first.c_str());
+    else
+      label->lang = strdup(DEFAULT_LOCALE);
+    label->name = strdup(pair.second.c_str());
+    manifest->label = g_list_append(manifest->label, label);
+  }
+
+  std::shared_ptr<const ProfileInfo> profile_info =
+      std::static_pointer_cast<const ProfileInfo>(
+          parser_->GetManifestData(ProfileInfo::Key()));
+  if (profile_info) {
+    for (auto& profile : profile_info->profiles()) {
+      manifest->deviceprofile = g_list_append(manifest->deviceprofile,
+                                              strdup(profile.c_str()));
+    }
+  }
+
+  if (ui_application_list) {
+    manifest->mainapp_id =
+        strdup(ui_application_list->items[0].ui_info.appid().c_str());
+  } else if (service_application_list) {
+    manifest->mainapp_id =
+        strdup(service_application_list->items[0].sa_info.appid().c_str());
+  } else if (widget_application_list) {
+    manifest->mainapp_id =
+        strdup(widget_application_list->items[0].widget_info.appid().c_str());
+  }
+  return true;
+}
+
+bool StepParse::FillAuthorInfo(manifest_x* manifest) {
+  std::shared_ptr<const AuthorInfo> author_info =
+      std::static_pointer_cast<const AuthorInfo>(
+          parser_->GetManifestData(app_keys::kAuthorKey));
+
+  if (!author_info) {
+    LOG(ERROR) << "Author data has not been found.";
+    return false;
+  }
+
+  author_x* author = reinterpret_cast<author_x*>(calloc(1, sizeof(author_x)));
+  author->text = strdup(author_info->name().c_str());
+  author->email = strdup(author_info->email().c_str());
+  author->href = strdup(author_info->href().c_str());
+  author->lang = strdup(DEFAULT_LOCALE);
+  manifest->author = g_list_append(manifest->author, author);
+  return true;
+}
+
+bool StepParse::FillDescription(manifest_x* manifest) {
+  std::shared_ptr<const DescriptionInfo> description_info =
+      std::static_pointer_cast<const DescriptionInfo>(
+          parser_->GetManifestData(app_keys::kDescriptionKey));
+
+  if (!description_info) {
+    LOG(ERROR) << "Description data has not been found.";
+    return false;
+  }
+
+  description_x* description = reinterpret_cast<description_x*>
+      (calloc(1, sizeof(description_x)));
+  description->text = strdup(description_info->description().c_str());
+  description->lang = !description_info->xml_lang().empty() ?
+      strdup(description_info->xml_lang().c_str()) : strdup(DEFAULT_LOCALE);
+  manifest->description = g_list_append(manifest->description, description);
+  return true;
+}
+
+bool StepParse::FillPrivileges(manifest_x* manifest) {
+  std::shared_ptr<const PrivilegesInfo> perm_info =
+      std::static_pointer_cast<const PrivilegesInfo>(parser_->GetManifestData(
+          app_keys::kPrivilegesKey));
+  if (!perm_info)
+    return true;
+
+  std::set<std::string> privileges = perm_info->GetPrivileges();
+  for (auto& priv : privileges) {
+    manifest->privileges = g_list_append(manifest->privileges,
+                                         strdup(priv.c_str()));
+  }
+  return true;
+}
+
+bool StepParse::FillWidgetApplication(manifest_x* manifest) {
+  std::shared_ptr<const WidgetApplicationInfoList> widget_application_list =
+      std::static_pointer_cast<const WidgetApplicationInfoList>(
+          parser_->GetManifestData(app_keys::kWidgetApplicationKey));
+  if (!widget_application_list)
+    return true;
+
+  for (const auto& application : widget_application_list->items) {
+    // if there is no app yet, set this app as mainapp
+    bool main_app = manifest->application == nullptr;
+
+    application_x* widget_app =
+        static_cast<application_x*>(calloc(1, sizeof(application_x)));
+    widget_app->appid = strdup(application.widget_info.appid().c_str());
+    widget_app->exec = strdup((context_->root_application_path.get()
+                           / manifest->package / "bin"
+                           / application.widget_info.exec()).c_str());
+    widget_app->launch_mode =
+        strdup(application.widget_info.launch_mode().c_str());
+    widget_app->multiple = strdup(application.widget_info.multiple().c_str());
+    widget_app->nodisplay =
+        strdup(application.widget_info.nodisplay().c_str());
+    widget_app->type = strdup("capp");
+    widget_app->component_type = strdup("widgetapp");
+    widget_app->hwacceleration =
+        strdup(application.widget_info.hwacceleration().c_str());
+    widget_app->onboot = strdup("false");
+    widget_app->autorestart = strdup("false");
+    widget_app->mainapp = main_app ? strdup("true") : strdup("false");
+    widget_app->enabled = strdup("true");
+    widget_app->screenreader = strdup("use-system-setting");
+    widget_app->recentimage = strdup("false");
+    widget_app->launchcondition = strdup("false");
+    widget_app->guestmode_visibility = strdup("true");
+    widget_app->permission_type = strdup("normal");
+    widget_app->ambient_support = strdup("false");
+    widget_app->package = strdup(manifest->package);
+    widget_app->support_disable = strdup(manifest->support_disable);
+    manifest->application = g_list_append(manifest->application, widget_app);
+
+    if (!FillApplicationIconPaths(widget_app, application.app_icons))
+      return false;
+    if (!FillLabel(widget_app, application.label))
+      return false;
+    if (!FillImage(widget_app, application.app_images))
+      return false;
+    if (!FillMetadata(widget_app, application.meta_data))
+      return false;
+  }
+  return true;
+}
+
+bool StepParse::FillServiceApplication(manifest_x* manifest) {
+  std::shared_ptr<const ServiceApplicationInfoList> service_application_list =
+      std::static_pointer_cast<const ServiceApplicationInfoList>(
+          parser_->GetManifestData(app_keys::kServiceApplicationKey));
+  if (!service_application_list)
+    return true;
+
+  for (const auto& application : service_application_list->items) {
+    // if there is no app yet, set this app as mainapp
+    bool main_app = manifest->application == nullptr;
+
+    application_x* service_app =
+        static_cast<application_x*>(calloc(1, sizeof(application_x)));
+    service_app->appid = strdup(application.sa_info.appid().c_str());
+    service_app->autorestart =
+        strdup(application.sa_info.auto_restart().c_str());
+    service_app->exec = strdup((context_->root_application_path.get()
+                           / manifest->package / "bin"
+                           / application.sa_info.exec()).c_str());
+    service_app->onboot = strdup(application.sa_info.on_boot().c_str());
+    service_app->type = strdup(application.sa_info.type().c_str());
+    service_app->process_pool =
+        strdup(application.sa_info.process_pool().c_str());
+    service_app->component_type = strdup("svcapp");
+    service_app->mainapp = main_app ? strdup("true") : strdup("false");
+    service_app->enabled = strdup("true");
+    service_app->hwacceleration = strdup("default");
+    service_app->screenreader = strdup("use-system-setting");
+    service_app->recentimage = strdup("false");
+    service_app->launchcondition = strdup("false");
+    service_app->indicatordisplay = strdup("true");
+    service_app->effectimage_type = strdup("image");
+    service_app->guestmode_visibility = strdup("true");
+    service_app->permission_type = strdup("normal");
+    service_app->submode = strdup("false");
+    service_app->process_pool = strdup("false");
+    service_app->ambient_support = strdup("false");
+    service_app->package = strdup(manifest->package);
+    service_app->support_disable = strdup(manifest->support_disable);
+    manifest->application = g_list_append(manifest->application, service_app);
+
+    if (!FillAppControl(service_app,  application.app_control))
+      return false;
+    if (!FillDataControl(service_app, application.data_control))
+      return false;
+    if (!FillApplicationIconPaths(service_app, application.app_icons))
+      return false;
+    if (!FillLabel(service_app, application.label))
+      return false;
+    if (!FillMetadata(service_app, application.meta_data))
+      return false;
+    if (!FillBackgroundCategoryInfo(service_app,
+        application.background_category))
+      return false;
+  }
+  return true;
+}
+
+bool StepParse::FillUIApplication(manifest_x* manifest) {
+  std::shared_ptr<const UIApplicationInfoList> ui_application_list =
+      std::static_pointer_cast<const UIApplicationInfoList>(
+          parser_->GetManifestData(app_keys::kUIApplicationKey));
+  if (!ui_application_list)
+    return true;
+
+  for (const auto& application : ui_application_list->items) {
+    // if there is no app yet, set this app as mainapp
+    bool main_app = manifest->application == nullptr;
+
+    application_x* ui_app =
+        static_cast<application_x*>(calloc(1, sizeof(application_x)));
+    ui_app->appid = strdup(application.ui_info.appid().c_str());
+    ui_app->exec = strdup((context_->root_application_path.get()
+                           / manifest->package / "bin"
+                           / application.ui_info.exec()).c_str());
+    ui_app->launch_mode = strdup(application.ui_info.launch_mode().c_str());
+    ui_app->multiple = strdup(application.ui_info.multiple().c_str());
+    ui_app->nodisplay = strdup(application.ui_info.nodisplay().c_str());
+    ui_app->taskmanage = strdup(application.ui_info.taskmanage().c_str());
+    ui_app->type = strdup(application.ui_info.type().c_str());
+    ui_app->component_type = strdup("uiapp");
+    ui_app->ui_gadget = strdup(application.ui_info.uigadget().c_str());
+    ui_app->process_pool = strdup(application.ui_info.process_pool().c_str());
+    ui_app->submode = strdup(application.ui_info.submode().c_str());
+    ui_app->indicatordisplay =
+        strdup(application.ui_info.indicator_display().c_str());
+    ui_app->effectimage_type =
+        strdup(application.ui_info.effectimage_type().c_str());
+    ui_app->portraitimg =
+        strdup(application.ui_info.portrait_image().c_str());
+    ui_app->landscapeimg =
+        strdup(application.ui_info.landscape_image().c_str());
+    ui_app->submode_mainid =
+        strdup(application.ui_info.submode_mainid().c_str());
+    ui_app->hwacceleration =
+        strdup(application.ui_info.hwacceleration().c_str());
+    ui_app->onboot = strdup("false");
+    ui_app->autorestart = strdup("false");
+    ui_app->component_type = strdup("uiapp");
+    ui_app->mainapp = main_app ? strdup("true") : strdup("false");
+    ui_app->enabled = strdup("true");
+    ui_app->screenreader = strdup("use-system-setting");
+    ui_app->recentimage = strdup("false");
+    ui_app->launchcondition = strdup("false");
+    ui_app->guestmode_visibility = strdup("true");
+    ui_app->permission_type = strdup("normal");
+    ui_app->ambient_support = strdup("false");
+    ui_app->package = strdup(manifest->package);
+    ui_app->support_disable = strdup(manifest->support_disable);
+    manifest->application = g_list_append(manifest->application, ui_app);
+
+    if (!FillAppControl(ui_app, application.app_control))
+      return false;
+    if (!FillDataControl(ui_app, application.data_control))
+      return false;
+    if (!FillApplicationIconPaths(ui_app, application.app_icons))
+      return false;
+    if (!FillLabel(ui_app, application.label))
+      return false;
+    if (!FillImage(ui_app, application.app_images))
+      return false;
+    if (!FillMetadata(ui_app, application.meta_data))
+      return false;
+    if (!FillBackgroundCategoryInfo(ui_app, application.background_category))
+      return false;
+  }
+  return true;
+}
+
+template <typename T>
+bool StepParse::FillAppControl(application_x* app, const T& app_control_list) {
+  if (app_control_list.empty())
+    return true;
+
+  for (const auto& control : app_control_list) {
+    appcontrol_x* app_control =
+          static_cast<appcontrol_x*>(calloc(1, sizeof(appcontrol_x)));
+    app_control->operation = strdup(control.operation().c_str());
+    if (!control.mime().empty())
+      app_control->mime = strdup(control.mime().c_str());
+    if (!control.uri().empty())
+      app_control->uri = strdup(control.uri().c_str());
+    app->appcontrol = g_list_append(app->appcontrol, app_control);
+  }
+  return true;
+}
+
+template <typename T>
+bool StepParse::FillDataControl(application_x* app,
+                                const T& data_control_list) {
+  if (data_control_list.empty())
+    return true;
+
+  for (const auto& control : data_control_list) {
+    datacontrol_x* data_control =
+          static_cast<datacontrol_x*>(calloc(1, sizeof(datacontrol_x)));
+    data_control->access = strdup(control.access().c_str());
+    data_control->providerid = strdup(control.providerid().c_str());
+    data_control->type = strdup(control.type().c_str());
+    app->datacontrol = g_list_append(app->datacontrol, data_control);
+  }
+  return true;
+}
+
+template <typename T>
+bool StepParse::FillApplicationIconPaths(application_x* app,
+                                         const T& icons_info) {
+  for (auto& application_icon : icons_info.icons()) {
+    icon_x* icon = reinterpret_cast<icon_x*> (calloc(1, sizeof(icon_x)));
+    // NOTE: name is an attribute, but the xml writer uses it as text.
+    // This must be fixed in whole app-installer modules, including wgt.
+    // Current implementation is just for compatibility.
+    icon->text = strdup(application_icon.path().c_str());
+    icon->name = strdup(application_icon.path().c_str());
+    icon->lang = strdup(DEFAULT_LOCALE);
+    app->icon = g_list_append(app->icon, icon);
+  }
+  return true;
+}
+
+template <typename T>
+bool StepParse::FillLabel(application_x* app, const T& label_list) {
+  if (label_list.empty())
+    return true;
+
+  for (const auto& control : label_list) {
+    label_x* label =
+          static_cast<label_x*>(calloc(1, sizeof(label_x)));
+    // NOTE: name is an attribute, but the xml writer uses it as text.
+    // This must be fixed in whole app-installer modules, including wgt.
+    // Current implementation is just for compatibility.
+    label->text = strdup(control.text().c_str());
+    label->name = strdup(control.name().c_str());
+    label->lang = !control.xml_lang().empty() ?
+        strdup(control.xml_lang().c_str()) : strdup(DEFAULT_LOCALE);
+    app->label = g_list_append(app->label, label);
+  }
+  return true;
+}
+
+template <typename T>
+bool StepParse::FillMetadata(application_x* app, const T& meta_data_list) {
+  if (meta_data_list.empty())
+    return true;
+
+  for (auto& meta : meta_data_list) {
+    metadata_x* metadata =
+        static_cast<metadata_x*>(calloc(1, sizeof(metadata_x)));
+    metadata->key = strdup(meta.key().c_str());
+    metadata->value = strdup(meta.val().c_str());
+    app->metadata = g_list_append(app->metadata, metadata);
+  }
+  return true;
+}
+
+bool StepParse::FillImage(application_x* app,
+                          const tpk::parse::ApplicationImagesInfo& image_list) {
+  for (auto& app_image : image_list.images) {
+    image_x* image =
+        static_cast<image_x*>(calloc(1, sizeof(image_x)));
+    image->name = strdup(app_image.name().c_str());
+    const std::string& lang = app_image.lang();
+    if (!lang.empty())
+      image->lang = strdup(lang.c_str());
+    else
+      image->lang = strdup(DEFAULT_LOCALE);
+    if (!app_image.section().empty())
+      image->section = strdup(app_image.section().c_str());
+    app->image = g_list_append(app->image, image);
+  }
+  return true;
+}
+
+bool StepParse::FillAccounts() {
+  std::shared_ptr<const AccountInfo> account_info =
+      std::static_pointer_cast<const AccountInfo>(parser_->GetManifestData(
+          app_keys::kAccountKey));
+  if (!account_info)
+    return true;
+
+  common_installer::AccountInfo info;
+  for (auto& account : account_info->accounts()) {
+    common_installer::SingleAccountInfo single_info;
+    single_info.capabilities = account.capabilities;
+    single_info.icon_paths = account.icon_paths;
+    single_info.multiple_account_support = account.multiple_account_support;
+    single_info.names = account.labels;
+    // appid has the same value as package
+    single_info.appid =  account.app_id;
+    single_info.providerid = account.provider_id;
+    info.set_account(single_info);
+  }
+  context_->manifest_plugins_data.get().account_info.set(info);
+  return true;
+}
+
+bool StepParse::FillShortcuts() {
+  std::shared_ptr<const ShortcutListInfo> shortcut_info =
+      std::static_pointer_cast<const ShortcutListInfo>(parser_->GetManifestData(
+          app_keys::kShortcutListKey));
+  if (!shortcut_info)
+    return true;
+
+  common_installer::ShortcutListInfo list;
+  for (auto& shortcut : shortcut_info->shortcuts) {
+    common_installer::ShortcutInfo single_info;
+    single_info.app_id = shortcut.app_id;
+    single_info.extra_data = shortcut.extra_data;
+    single_info.extra_key = shortcut.extra_key;
+    single_info.icon = shortcut.icon;
+    single_info.labels =  shortcut.labels;
+    list.push_back(single_info);
+  }
+  context_->manifest_plugins_data.get().shortcut_info.set(list);
+  return true;
+}
+
+template <typename T>
+bool StepParse::FillBackgroundCategoryInfo(application_x* app,
+    const T& background_category_data_list) {
+  for (const auto& background_category : background_category_data_list) {
+    app->background_category = g_list_append(
+        app->background_category, strdup(background_category.value().c_str()));
+  }
+
+  return true;
+}
+
+bool StepParse::FillManifestX(manifest_x* manifest) {
+  if (!FillPackageInfo(manifest))
+    return false;
+  if (!FillInstallationInfo(manifest))
+    return false;
+  if (!FillUIApplication(manifest))
+    return false;
+  if (!FillServiceApplication(manifest))
+    return false;
+  if (!FillWidgetApplication(manifest))
+    return false;
+  if (!FillPrivileges(manifest))
+    return false;
+  if (!FillAccounts())
+    return false;
+  if (!FillShortcuts())
+    return false;
+  return true;
+}
+
+common_installer::Step::Status StepParse::process() {
+  if (!LocateConfigFile()) {
+    LOG(ERROR) << "No manifest file exists";
+    return common_installer::Step::Status::ERROR;
+  }
+  parser_.reset(new tpk::parse::TPKConfigParser());
+  if (!parser_->ParseManifest(path_)) {
+    LOG(ERROR) << "[Parse] Parse failed. " <<  parser_->GetErrorMessage();
+    return common_installer::Step::Status::ERROR;
+  }
+
+  manifest_x* manifest =
+      static_cast<manifest_x*>(calloc(1, sizeof(manifest_x)));
+
+  if (!FillManifestX(const_cast<manifest_x*>(manifest))) {
+    LOG(ERROR) << "[Parse] Storing manifest_x failed. "
+               <<  parser_->GetErrorMessage();
+    return common_installer::Step::Status::ERROR;
+  }
+
+  if (!context_->tep_path.get().empty())
+    manifest->tep_name = context_->tep_path.get().c_str();
+
+  // Copy data from ManifestData to InstallerContext
+  std::shared_ptr<const PackageInfo> info =
+      std::static_pointer_cast<const PackageInfo>(
+          parser_->GetManifestData(
+              app_keys::kManifestKey));
+
+  context_->pkgid.set(manifest->package);
+
+  // write pkgid for recovery file
+  if (context_->recovery_info.get().recovery_file) {
+    context_->recovery_info.get().recovery_file->set_pkgid(manifest->package);
+    context_->recovery_info.get().recovery_file->WriteAndCommitFileContent();
+  }
+
+  std::shared_ptr<const PrivilegesInfo> perm_info =
+      std::static_pointer_cast<const PrivilegesInfo>(
+          parser_->GetManifestData(
+              application_keys::kPrivilegesKey));
+  parser::PrivilegesSet privileges;
+  if (perm_info)
+    privileges = perm_info->GetPrivileges();
+
+  std::shared_ptr<const UIApplicationInfoList> ui_application_list =
+      std::static_pointer_cast<const UIApplicationInfoList>(
+          parser_->GetManifestData(app_keys::kUIApplicationKey));
+
+  LOG(DEBUG) << " Read data -[ ";
+  LOG(DEBUG) << "App package: " << info->package();
+  LOG(DEBUG) << "  aplication version     = " <<  info->version();
+  LOG(DEBUG) << "  api_version = " <<  info->api_version();
+  if (ui_application_list) {
+    LOG(DEBUG) << "  launch_modes -[";
+    for (const auto& application : ui_application_list->items) {
+      LOG(DEBUG) << "    launch_mode[" << application.ui_info.appid() << "] = "
+        <<  application.ui_info.launch_mode();
+    }
+  }
+  LOG(DEBUG) << "  ]-";
+  LOG(DEBUG) << "  privileges -[";
+  for (const auto& p : privileges) {
+    LOG(DEBUG) << "    " << p;
+  }
+  LOG(DEBUG) << "  ]-";
+  LOG(DEBUG) << "]-";
+
+  context_->manifest_data.set(manifest);
+  return common_installer::Step::Status::OK;
+}
+
+}  // namespace parse
+}  // namespace tpk
diff --git a/src/tpk/step/step_parse.h b/src/tpk/step/step_parse.h
new file mode 100644 (file)
index 0000000..e60b6ca
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache 2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef TPK_STEP_STEP_PARSE_H_
+#define TPK_STEP_STEP_PARSE_H_
+
+#include <boost/filesystem.hpp>
+
+#include <common/app_installer.h>
+#include <common/installer_context.h>
+#include <common/step/step.h>
+
+#include <manifest_parser/utils/logging.h>
+#include <tpk_manifest_handlers/privileges_handler.h>
+#include <tpk_manifest_handlers/tpk_config_parser.h>
+#include <tpk_manifest_handlers/ui_and_service_application_infos.h>
+
+#include <memory>
+#include <set>
+#include <string>
+
+namespace tpk {
+namespace parse {
+
+class StepParse : public common_installer::Step {
+ public:
+  using Step::Step;
+  explicit StepParse(common_installer::InstallerContext* context,
+      bool check_start_file);
+
+  Status process() override;
+  Status clean() override { return Status::OK; }
+  Status undo() override { return Status::OK; }
+  Status precheck() override;
+
+ protected:
+  virtual bool LocateConfigFile();
+  // This function is needed by recovery mode to override searching
+  // of configuration file of the package
+  virtual boost::filesystem::path LocateConfigFile() const;
+  boost::filesystem::path path_;
+
+ private:
+  bool FillInstallationInfo(manifest_x* manifest);
+  bool FillPackageInfo(manifest_x* manifest);
+  bool FillAuthorInfo(manifest_x* manifest);
+  bool FillDescription(manifest_x* manifest);
+  bool FillPrivileges(manifest_x* manifest);
+  bool FillWidgetApplication(manifest_x* manifest);
+  bool FillServiceApplication(manifest_x* manifest);
+  bool FillUIApplication(manifest_x* manifest);
+  template <typename T>
+      bool FillAppControl(application_x* manifest, const T& app_control_list);
+  template <typename T>
+      bool FillDataControl(application_x* manifest, const T& data_control_list);
+  template <typename T>
+      bool FillApplicationIconPaths(application_x* manifest,
+                                    const T& icons_info);
+  template <typename T>
+      bool FillLabel(application_x* manifest, const T& label_list);
+  template <typename T>
+      bool FillMetadata(application_x* manifest, const T& meta_data_list);
+  bool FillImage(application_x* app,
+                 const tpk::parse::ApplicationImagesInfo& label_list);
+  bool FillAccounts();
+  bool FillShortcuts();
+  template <typename T>
+  bool FillBackgroundCategoryInfo(application_x* app,
+      const T& background_category_data_list);
+  bool FillManifestX(manifest_x* manifest);
+
+  std::unique_ptr<tpk::parse::TPKConfigParser> parser_;
+
+  SCOPE_LOG_TAG(Parse)
+};
+
+}  // namespace parse
+}  // namespace tpk
+
+#endif  // TPK_STEP_STEP_PARSE_H_
diff --git a/src/tpk/step/step_parse_recovery.cc b/src/tpk/step/step_parse_recovery.cc
new file mode 100644 (file)
index 0000000..839c054
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#include "tpk/step/step_parse_recovery.h"
+
+#include <boost/filesystem/operations.hpp>
+
+#include <common/backup_paths.h>
+
+namespace bf = boost::filesystem;
+
+namespace {
+
+const char kManifestFileName[] = "tizen-manifest.xml";
+
+}  // namespace
+
+namespace tpk {
+namespace parse {
+
+common_installer::Step::Status StepParseRecovery::process() {
+  (void) StepParse::process();
+  return Status::OK;
+}
+
+
+common_installer::Step::Status StepParseRecovery::precheck() {
+  if (context_->root_application_path.get().empty()) {
+    LOG(ERROR) << "Root path of packages in not set";
+    return Status::ERROR;
+  }
+  if (context_->pkgid.get().empty()) {
+    LOG(WARNING) << "Pkgid is not set. Parsing skipped";
+    return Status::OK;
+  }
+  return Status::OK;
+}
+
+boost::filesystem::path StepParseRecovery::LocateConfigFile() const {
+  context_->pkg_path.set(
+      context_->root_application_path.get() / context_->pkgid.get());
+  bf::path path1 = common_installer::GetBackupPathForPackagePath(
+      context_->pkg_path.get()) / kManifestFileName;
+  bf::path path2 = context_->pkg_path.get() / kManifestFileName;
+  if (bf::exists(path1))
+    return path1;
+  if (bf::exists(path2))
+    return path2;
+  return {};
+}
+
+}  // namespace parse
+}  // namespace tpk
+
diff --git a/src/tpk/step/step_parse_recovery.h b/src/tpk/step/step_parse_recovery.h
new file mode 100644 (file)
index 0000000..5522ed0
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef TPK_STEP_STEP_PARSE_RECOVERY_H_
+#define TPK_STEP_STEP_PARSE_RECOVERY_H_
+
+#include <boost/filesystem/path.hpp>
+
+#include <manifest_parser/utils/logging.h>
+
+#include "tpk/step/step_parse.h"
+
+namespace tpk {
+namespace parse {
+
+class StepParseRecovery : public StepParse {
+ public:
+  using StepParse::StepParse;
+
+  Status process() override;
+  Status precheck() override;
+
+ protected:
+  boost::filesystem::path LocateConfigFile() const override;
+
+  SCOPE_LOG_TAG(ParseRecovery)
+};
+}  // namespace parse
+}  // namespace tpk
+
+#endif  // TPK_STEP_STEP_PARSE_RECOVERY_H_
diff --git a/src/tpk/tpk_app_query_interface.cc b/src/tpk/tpk_app_query_interface.cc
new file mode 100644 (file)
index 0000000..5e816b4
--- /dev/null
@@ -0,0 +1,119 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#include "tpk/tpk_app_query_interface.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/system/error_code.hpp>
+
+#include <common/pkgmgr_registration.h>
+#include <common/request.h>
+#include <common/utils/file_util.h>
+
+#include <manifest_parser/utils/logging.h>
+#include <tpk_manifest_handlers/application_manifest_constants.h>
+#include <tpk_manifest_handlers/package_handler.h>
+#include <tpk_manifest_handlers/tpk_config_parser.h>
+
+#include <memory>
+#include <string>
+
+namespace bf = boost::filesystem;
+namespace bs = boost::system;
+namespace ci = common_installer;
+
+namespace {
+
+const char kManifestFileName[] = "tizen-manifest.xml";
+
+std::string GetInstallationPackagePath(int argc, char** argv) {
+  std::string path;
+  for (int i = 0; i < argc; ++i) {
+    if (!strcmp(argv[i], "-i")) {
+      if (i + 1 < argc) {
+        path = argv[i + 1];
+        break;
+      }
+    }
+  }
+  return path;
+}
+
+std::string GetXmlPath(int argc, char** argv) {
+  std::string path;
+  for (int i = 0; i < argc; ++i) {
+    if (!strcmp(argv[i], "-x")) {
+      if (i + 1 < argc) {
+        path = argv[i + 1];
+        break;
+      }
+    }
+  }
+  return path;
+}
+
+std::string GetPkgIdFromXml(const std::string&path) {
+  bf::path xml_path(path);
+
+  return xml_path.stem().string();
+}
+
+std::string GetPkgIdFromPath(const std::string& path) {
+  bf::path tmp_path = common_installer::GenerateTmpDir("/tmp");
+  bs::error_code code;
+  bf::create_directories(tmp_path, code);
+  if (code)
+    return {};
+  if (!common_installer::ExtractToTmpDir(path.c_str(), tmp_path,
+      kManifestFileName)) {
+    bf::remove_all(tmp_path, code);
+    return {};
+  }
+  bf::path manifest_path = tmp_path / kManifestFileName;
+  if (!bf::exists(manifest_path)) {
+    bf::remove_all(tmp_path, code);
+    return {};
+  }
+
+  tpk::parse::TPKConfigParser parser;
+  if (!parser.ParseManifest(manifest_path))
+    return {};
+  auto package_info = std::static_pointer_cast<const tpk::parse::PackageInfo>(
+      parser.GetManifestData(tpk::application_keys::kManifestKey));
+  if (!package_info)
+    return {};
+  std::string pkg_id = package_info->package();
+  bf::remove_all(tmp_path, code);
+  return pkg_id;
+}
+
+}  // namespace
+
+namespace tpk {
+
+bool TpkAppQueryInterface::IsAppInstalledByArgv(int argc, char** argv) {
+  std::string path = GetInstallationPackagePath(argc, argv);
+  std::string pkg_id;
+  if (path.empty()) {
+    // check if it is manifest direct install
+    path = GetXmlPath(argc, argv);
+    if (path.empty())
+      return false;
+
+    pkg_id = GetPkgIdFromXml(path);
+  } else {
+    pkg_id = GetPkgIdFromPath(path);
+  }
+
+  if (pkg_id.empty())
+    return false;
+  return ci::IsPackageInstalled(pkg_id, ci::GetRequestMode());
+}
+
+}  // namespace tpk
+
diff --git a/src/tpk/tpk_app_query_interface.h b/src/tpk/tpk_app_query_interface.h
new file mode 100644 (file)
index 0000000..0dbf471
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef TPK_TPK_APP_QUERY_INTERFACE_H_
+#define TPK_TPK_APP_QUERY_INTERFACE_H_
+
+#include <common/app_query_interface.h>
+
+namespace tpk {
+
+class TpkAppQueryInterface : public common_installer::AppQueryInterface {
+ public:
+  bool IsAppInstalledByArgv(int argc, char** argv) override;
+};
+
+}  // namespace tpk
+
+#endif  // TPK_TPK_APP_QUERY_INTERFACE_H_
diff --git a/src/tpk/tpk_backend.cc b/src/tpk/tpk_backend.cc
new file mode 100644 (file)
index 0000000..657c89b
--- /dev/null
@@ -0,0 +1,26 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+
+#include <common/pkgmgr_interface.h>
+#include <manifest_parser/utils/logging.h>
+
+#include <iostream>
+
+#include "tpk/tpk_app_query_interface.h"
+#include "tpk/tpk_installer.h"
+
+namespace ci = common_installer;
+
+int main(const int argc, char* argv[]) {
+  tpk::TpkAppQueryInterface interface;
+  ci::PkgMgrPtr pkgmgr = ci::PkgMgrInterface::Create(argc, argv, &interface);
+  if (!pkgmgr) {
+    LOG(ERROR) << "Failed to create pkgmgr interface";
+    return -1;
+  }
+  tpk::TpkInstaller t(pkgmgr);
+  if (t.Run() != ci::AppInstaller::Result::OK) {
+    LOG(ERROR) << "TpkInstaller run failure";
+    return -1;
+  }
+  return 0;
+}
diff --git a/src/tpk/tpk_installer.cc b/src/tpk/tpk_installer.cc
new file mode 100644 (file)
index 0000000..7fe8e28
--- /dev/null
@@ -0,0 +1,218 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#include "tpk/tpk_installer.h"
+#include <common/app_installer.h>
+#include <common/step/step_configure.h>
+#include <common/step/step_backup_icons.h>
+#include <common/step/step_backup_manifest.h>
+#include <common/step/step_create_icons.h>
+#include <common/step/step_create_storage_directories.h>
+#include <common/step/step_copy.h>
+#include <common/step/step_copy_tep.h>
+#include <common/step/step_copy_backup.h>
+#include <common/step/step_check_old_certificate.h>
+#include <common/step/step_delta_patch.h>
+#include <common/step/step_fail.h>
+#include <common/step/step_kill_apps.h>
+#include <common/step/step_old_manifest.h>
+#include <common/step/step_open_recovery_file.h>
+#include <common/step/step_parse.h>
+#include <common/step/step_privilege_compatibility.h>
+#include <common/step/step_recover_application.h>
+#include <common/step/step_recover_files.h>
+#include <common/step/step_recover_icons.h>
+#include <common/step/step_recover_manifest.h>
+#include <common/step/step_recover_security.h>
+#include <common/step/step_recover_storage_directories.h>
+#include <common/step/step_register_app.h>
+#include <common/step/step_remove_icons.h>
+#include <common/step/step_remove_files.h>
+#include <common/step/step_revoke_security.h>
+#include <common/step/step_remove_temporary_directory.h>
+#include <common/step/step_register_security.h>
+#include <common/step/step_rollback_deinstallation_security.h>
+#include <common/step/step_rollback_installation_security.h>
+#include <common/step/step_check_signature.h>
+#include <common/step/step_unregister_app.h>
+#include <common/step/step_unzip.h>
+#include <common/step/step_update_app.h>
+#include <common/step/step_update_security.h>
+#include <common/step/step_update_tep.h>
+#include "tpk/step/step_check_tpk_background_category.h"
+#include "tpk/step/step_create_symbolic_link.h"
+#include "tpk/step/step_parse.h"
+#include "tpk/step/step_parse_recovery.h"
+#include "tpk/step/step_convert_xml.h"
+
+namespace ci = common_installer;
+
+namespace {
+
+const char kPkgType[] = "tpk";
+
+}  // namespace
+
+namespace tpk {
+
+TpkInstaller::TpkInstaller(common_installer::PkgMgrPtr pkgmgr)
+    : AppInstaller(kPkgType, pkgmgr) {
+  Prepare();
+}
+
+TpkInstaller::~TpkInstaller() {
+}
+
+void TpkInstaller::Prepare() {
+  switch (pkgmgr_->GetRequestType()) {
+    case ci::RequestType::Install:
+      InstallSteps();
+      break;
+    case ci::RequestType::Update:
+      UpdateSteps();
+      break;
+    case ci::RequestType::Uninstall:
+      UninstallSteps();
+      break;
+    case ci::RequestType::Reinstall:
+      ReinstallSteps();
+      break;
+    case ci::RequestType::Delta:
+      DeltaSteps();
+      break;
+    case ci::RequestType::Recovery:
+      RecoverySteps();
+      break;
+    case ci::RequestType::ManifestDirectInstall:
+      ManifestDirectInstallSteps();
+      break;
+    case ci::RequestType::ManifestDirectUpdate:
+      ManifestDirectUpdateSteps();
+      break;
+    default:
+      AddStep<ci::configuration::StepFail>();
+      break;
+  }
+}
+
+void TpkInstaller::InstallSteps() {
+  AddStep<ci::configuration::StepConfigure>(pkgmgr_);
+  AddStep<ci::filesystem::StepUnzip>();
+  AddStep<tpk::parse::StepParse>();
+  AddStep<ci::security::StepCheckSignature>();
+  AddStep<ci::security::StepPrivilegeCompatibility>();
+  AddStep<tpk::security::StepCheckTpkBackgroundCategory>();
+  AddStep<ci::security::StepRollbackInstallationSecurity>();
+  AddStep<ci::filesystem::StepCopy>();
+  AddStep<ci::filesystem::StepCopyTep>();
+  AddStep<ci::filesystem::StepCreateStorageDirectories>();
+  AddStep<tpk::filesystem::StepCreateSymbolicLink>();
+  AddStep<ci::filesystem::StepCreateIcons>();
+  AddStep<ci::security::StepRegisterSecurity>();
+  AddStep<ci::tpk::StepConvertXml>();
+  AddStep<ci::pkgmgr::StepRegisterApplication>();
+}
+
+void TpkInstaller::UpdateSteps() {
+  AddStep<ci::configuration::StepConfigure>(pkgmgr_);
+  AddStep<ci::filesystem::StepUnzip>();
+  AddStep<tpk::parse::StepParse>();
+  AddStep<ci::security::StepCheckSignature>();
+  AddStep<ci::security::StepPrivilegeCompatibility>();
+  AddStep<tpk::security::StepCheckTpkBackgroundCategory>();
+  AddStep<ci::security::StepCheckOldCertificate>();
+  AddStep<ci::backup::StepOldManifest>();
+  AddStep<ci::pkgmgr::StepKillApps>();
+  AddStep<ci::backup::StepBackupManifest>();
+  AddStep<ci::backup::StepBackupIcons>();
+  AddStep<ci::backup::StepCopyBackup>();
+  AddStep<ci::filesystem::StepCopyTep>();
+  AddStep<ci::filesystem::StepCreateStorageDirectories>();
+  // TODO(t.iwanek): handle coping storage directories
+  AddStep<tpk::filesystem::StepCreateSymbolicLink>();
+  AddStep<ci::filesystem::StepCreateIcons>();
+  AddStep<ci::security::StepUpdateSecurity>();
+  AddStep<ci::tpk::StepConvertXml>();
+  AddStep<ci::pkgmgr::StepUpdateApplication>();
+  /* TODO(jungh.yeon): this temporary step will be removed
+  * when secondary parsing procedure has removed*/
+  AddStep<ci::pkgmgr::StepUpdateTep>();
+}
+
+void TpkInstaller::UninstallSteps() {
+  AddStep<ci::configuration::StepConfigure>(pkgmgr_);
+  AddStep<ci::parse::StepParse>();
+  AddStep<ci::pkgmgr::StepKillApps>();
+  AddStep<ci::backup::StepBackupManifest>();
+  AddStep<ci::pkgmgr::StepUnregisterApplication>();
+  AddStep<ci::security::StepRollbackDeinstallationSecurity>();
+  AddStep<ci::filesystem::StepRemoveFiles>();
+  AddStep<ci::filesystem::StepRemoveIcons>();
+  AddStep<ci::security::StepRevokeSecurity>();
+}
+
+void TpkInstaller::ReinstallSteps() {
+  AddStep<ci::configuration::StepFail>();
+}
+
+void TpkInstaller::DeltaSteps() {
+  AddStep<ci::configuration::StepConfigure>(pkgmgr_);
+  AddStep<ci::filesystem::StepUnzip>();
+  AddStep<tpk::parse::StepParse>();
+  AddStep<ci::filesystem::StepDeltaPatch>();
+  AddStep<ci::security::StepCheckSignature>();
+  AddStep<ci::security::StepPrivilegeCompatibility>();
+  AddStep<tpk::security::StepCheckTpkBackgroundCategory>();
+  AddStep<ci::security::StepCheckOldCertificate>();
+  AddStep<ci::backup::StepOldManifest>();
+  AddStep<ci::pkgmgr::StepKillApps>();
+  AddStep<ci::backup::StepBackupManifest>();
+  AddStep<ci::backup::StepBackupIcons>();
+  AddStep<ci::backup::StepCopyBackup>();
+  AddStep<ci::filesystem::StepCreateStorageDirectories>();
+  // TODO(t.iwanek): handle coping storage directories
+  AddStep<tpk::filesystem::StepCreateSymbolicLink>();
+  AddStep<ci::filesystem::StepCreateIcons>();
+  AddStep<ci::security::StepUpdateSecurity>();
+  AddStep<ci::tpk::StepConvertXml>();
+  AddStep<ci::pkgmgr::StepUpdateApplication>();
+}
+
+void TpkInstaller::RecoverySteps() {
+  AddStep<ci::configuration::StepConfigure>(pkgmgr_);
+  AddStep<ci::recovery::StepOpenRecoveryFile>();
+  AddStep<tpk::parse::StepParseRecovery>();
+  AddStep<ci::pkgmgr::StepRecoverApplication>();
+  AddStep<ci::filesystem::StepRemoveTemporaryDirectory>();
+  AddStep<ci::filesystem::StepRecoverIcons>();
+  AddStep<ci::filesystem::StepRecoverManifest>();
+  AddStep<ci::filesystem::StepRecoverStorageDirectories>();
+  AddStep<ci::filesystem::StepRecoverFiles>();
+  AddStep<ci::security::StepRecoverSecurity>();
+}
+
+void TpkInstaller::ManifestDirectInstallSteps() {
+  AddStep<ci::configuration::StepConfigure>(pkgmgr_);
+  AddStep<tpk::parse::StepParse>();
+  AddStep<ci::security::StepCheckSignature>();
+  AddStep<ci::security::StepPrivilegeCompatibility>();
+  AddStep<tpk::security::StepCheckTpkBackgroundCategory>();
+  AddStep<ci::security::StepRollbackInstallationSecurity>();
+  AddStep<ci::security::StepRegisterSecurity>();
+  AddStep<ci::pkgmgr::StepRegisterApplication>();
+}
+
+void TpkInstaller::ManifestDirectUpdateSteps() {
+  AddStep<ci::configuration::StepConfigure>(pkgmgr_);
+  AddStep<tpk::parse::StepParse>();
+  AddStep<ci::security::StepCheckSignature>();
+  AddStep<ci::security::StepPrivilegeCompatibility>();
+  AddStep<tpk::security::StepCheckTpkBackgroundCategory>();
+  AddStep<ci::security::StepCheckOldCertificate>();
+  AddStep<ci::pkgmgr::StepKillApps>();
+  AddStep<ci::security::StepRollbackInstallationSecurity>();
+  AddStep<ci::security::StepRegisterSecurity>();
+  AddStep<ci::pkgmgr::StepUpdateApplication>();
+}
+
+
+}  // namespace tpk
+
diff --git a/src/tpk/tpk_installer.h b/src/tpk/tpk_installer.h
new file mode 100644 (file)
index 0000000..1b5d8fe
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+
+#ifndef TPK_TPK_INSTALLER_H_
+#define TPK_TPK_INSTALLER_H_
+
+#include <common/app_installer.h>
+#include <common/pkgmgr_interface.h>
+#include <manifest_parser/utils/logging.h>
+
+namespace tpk {
+
+/**
+ * @brief The TpkInstaller class
+ *        Handles request of tpk packages.
+ *
+ * This class is main class for installation/update/deinstallation of tpk
+ * packages. Pkgmgr request is parsed within and sequence of steps is built to
+ * be run.
+ */
+class TpkInstaller : public common_installer::AppInstaller {
+ public:
+  explicit TpkInstaller(common_installer::PkgMgrPtr pkgmgr);
+  ~TpkInstaller();
+  void Prepare();
+
+ private:
+  void InstallSteps();
+  void UpdateSteps();
+  void UninstallSteps();
+  void ReinstallSteps();
+  void DeltaSteps();
+  void RecoverySteps();
+  void ManifestDirectInstallSteps();
+  void ManifestDirectUpdateSteps();
+
+  SCOPE_LOG_TAG(TpkInstaller)
+};
+
+}  // namespace tpk
+
+#endif  // TPK_TPK_INSTALLER_H_
diff --git a/src/unit_tests/CMakeLists.txt b/src/unit_tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a815554
--- /dev/null
@@ -0,0 +1,22 @@
+SET(DESTINATION_DIR tpk-backend-ut)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../)
+
+# Executables
+ADD_EXECUTABLE(smoke_test
+  smoke_test.cc
+)
+
+INSTALL(DIRECTORY test_samples/ DESTINATION ${SHAREDIR}/${DESTINATION_DIR}/test_samples)
+
+APPLY_PKG_CONFIG(smoke_test PUBLIC
+  Boost
+  GTEST
+)
+
+# FindGTest module do not sets all needed libraries in GTEST_LIBRARIES and
+# GTest main libraries is still missing, so additional linking of
+# GTEST_MAIN_LIBRARIES is needed.
+target_link_libraries(smoke_test PRIVATE ${TARGET_LIBNAME_TPK} ${GTEST_MAIN_LIBRARIES})
+
+INSTALL(TARGETS smoke_test DESTINATION ${BINDIR}/${DESTINATION_DIR})
diff --git a/src/unit_tests/smoke_test.cc b/src/unit_tests/smoke_test.cc
new file mode 100644 (file)
index 0000000..67ca95a
--- /dev/null
@@ -0,0 +1,406 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <boost/system/error_code.hpp>
+
+#include <common/backup_paths.h>
+#include <common/pkgmgr_interface.h>
+#include <common/pkgmgr_registration.h>
+#include <common/request.h>
+#include <common/step/step_fail.h>
+
+#include <gtest/gtest.h>
+#include <gtest/gtest-death-test.h>
+#include <pkgmgr-info.h>
+#include <signal.h>
+#include <unistd.h>
+#include <tzplatform_config.h>
+
+#include <array>
+#include <cstdio>
+#include <cstdlib>
+
+#include "tpk/tpk_app_query_interface.h"
+#include "tpk/tpk_installer.h"
+
+#define SIZEOFARRAY(ARR)                                                       \
+  sizeof(ARR) / sizeof(ARR[0])                                                 \
+
+namespace bf = boost::filesystem;
+namespace bs = boost::system;
+namespace ci = common_installer;
+
+namespace {
+
+const char kApplicationDir[] = ".applications";
+const char kApplicationDirBackup[] = ".applications.bck";
+const char KUserAppsDir[] = "apps_rw";
+const char KUserAppsDirBackup[] = "apps_rw.bck";
+
+enum class RequestResult {
+  NORMAL,
+  FAIL,
+  CRASH
+};
+
+class StepCrash : public ci::Step {
+ public:
+  using Step::Step;
+
+  ci::Step::Status process() override {
+    raise(SIGSEGV);
+    return Status::OK;
+  }
+  ci::Step::Status clean() override { return ci::Step::Status::OK; }
+  ci::Step::Status undo() override { return ci::Step::Status::OK; }
+  ci::Step::Status precheck() override { return ci::Step::Status::OK; }
+};
+
+void RemoveAllRecoveryFiles() {
+  bf::path root_path = ci::GetRootAppPath();
+  for (auto& dir_entry : boost::make_iterator_range(
+         bf::directory_iterator(root_path), bf::directory_iterator())) {
+    if (bf::is_regular_file(dir_entry)) {
+      if (dir_entry.path().string().find("/recovery") != std::string::npos) {
+        bs::error_code error;
+        bf::remove(dir_entry.path(), error);
+      }
+    }
+  }
+}
+
+bf::path FindRecoveryFile() {
+  bf::path root_path = ci::GetRootAppPath();
+  for (auto& dir_entry : boost::make_iterator_range(
+         bf::directory_iterator(root_path), bf::directory_iterator())) {
+    if (bf::is_regular_file(dir_entry)) {
+      if (dir_entry.path().string().find("/recovery") != std::string::npos) {
+        return dir_entry.path();
+      }
+    }
+  }
+  return {};
+}
+
+bool ValidateFileContentInPackage(const std::string& pkgid,
+                                  const std::string& relative,
+                                  const std::string& expected) {
+  bf::path root_path = ci::GetRootAppPath();
+  bf::path file_path = root_path / pkgid / relative;
+  if (!bf::exists(file_path)) {
+    LOG(ERROR) << file_path << " doesn't exist";
+    return false;
+  }
+  FILE* handle = fopen(file_path.c_str(), "r");
+  if (!handle) {
+    LOG(ERROR) << file_path << " cannot  be open";
+    return false;
+  }
+  std::string content;
+  std::array<char, 200> buffer;
+  while (fgets(buffer.data(), buffer.size(), handle)) {
+    content += buffer.data();
+  }
+  fclose(handle);
+  return content == expected;
+}
+
+void ValidatePackageFS(const std::string& pkgid, const std::string& appid) {
+  bf::path root_path = ci::GetRootAppPath();
+  bf::path package_path = root_path / pkgid;
+  bf::path binary_path = package_path / "bin" / appid;
+  bf::path data_path = package_path / "data";
+  bf::path shared_path = package_path / "shared";
+  bf::path cache_path = package_path / "cache";
+  ASSERT_TRUE(bf::exists(root_path));
+  ASSERT_TRUE(bf::exists(package_path));
+  ASSERT_TRUE(bf::exists(binary_path));
+  ASSERT_TRUE(bf::exists(data_path));
+  ASSERT_TRUE(bf::exists(shared_path));
+  ASSERT_TRUE(bf::exists(cache_path));
+
+  bf::path manifest_path =
+      bf::path(getUserManifestPath(getuid())) / (pkgid + ".xml");
+  bf::path icon_path = bf::path(getIconPath(getuid())) / (appid + ".png");
+  ASSERT_TRUE(bf::exists(manifest_path));
+  ASSERT_TRUE(bf::exists(icon_path));
+
+  // backups should not exist
+  bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
+  bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
+  bf::path icon_backup = ci::GetBackupPathForIconFile(icon_path);
+  ASSERT_FALSE(bf::exists(package_backup));
+  ASSERT_FALSE(bf::exists(manifest_backup));
+  ASSERT_FALSE(bf::exists(icon_backup));
+}
+
+void PackageCheckCleanup(const std::string& pkgid, const std::string& appid) {
+  bf::path root_path = ci::GetRootAppPath();
+  bf::path package_path = root_path / pkgid;
+  ASSERT_FALSE(bf::exists(package_path));
+
+  bf::path manifest_path =
+      bf::path(getUserManifestPath(getuid())) / (pkgid + ".xml");
+  bf::path icon_path = bf::path(getIconPath(getuid())) / (appid + ".png");
+  ASSERT_FALSE(bf::exists(manifest_path));
+  ASSERT_FALSE(bf::exists(icon_path));
+
+  // backups should not exist
+  bf::path package_backup = ci::GetBackupPathForPackagePath(package_path);
+  bf::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
+  bf::path icon_backup = ci::GetBackupPathForIconFile(icon_path);
+  ASSERT_FALSE(bf::exists(package_backup));
+  ASSERT_FALSE(bf::exists(manifest_backup));
+  ASSERT_FALSE(bf::exists(icon_backup));
+}
+
+void ValidatePackage(const std::string& pkgid, const std::string& appid) {
+  ASSERT_TRUE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
+  ValidatePackageFS(pkgid, appid);
+}
+
+void CheckPackageNonExistance(const std::string& pkgid,
+                              const std::string& appid) {
+  ASSERT_FALSE(ci::IsPackageInstalled(pkgid, ci::GetRequestMode()));
+  PackageCheckCleanup(pkgid, appid);
+}
+
+std::unique_ptr<ci::AppQueryInterface> CreateQueryInterface() {
+  std::unique_ptr<ci::AppQueryInterface> query_interface(
+      new tpk::TpkAppQueryInterface());
+  return query_interface;
+}
+
+std::unique_ptr<ci::AppInstaller> CreateInstaller(ci::PkgMgrPtr pkgmgr) {
+  std::unique_ptr<ci::AppInstaller> installer(new tpk::TpkInstaller(pkgmgr));
+  return installer;
+}
+
+ci::AppInstaller::Result RunInstallerWithPkgrmgr(ci::PkgMgrPtr pkgmgr,
+                                                 RequestResult mode) {
+  std::unique_ptr<ci::AppInstaller> installer = CreateInstaller(pkgmgr);
+  switch (mode) {
+  case RequestResult::FAIL:
+    installer->AddStep<ci::configuration::StepFail>();
+    break;
+  case RequestResult::CRASH:
+    installer->AddStep<StepCrash>();
+  default:
+    break;
+  }
+  return installer->Run();
+}
+
+ci::AppInstaller::Result Install(const bf::path& path,
+                                 RequestResult mode = RequestResult::NORMAL) {
+  const char* argv[] = {"", "-i", path.c_str()};
+  std::unique_ptr<ci::AppQueryInterface> query_interface =
+      CreateQueryInterface();
+  auto pkgmgr =
+      ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
+                                  query_interface.get());
+  if (!pkgmgr) {
+    LOG(ERROR) << "Failed to initialize pkgmgr interface";
+    return ci::AppInstaller::Result::UNKNOWN;
+  }
+  return RunInstallerWithPkgrmgr(pkgmgr, mode);
+}
+
+ci::AppInstaller::Result Update(const bf::path& path_old,
+                                const bf::path& path_new,
+                                RequestResult mode = RequestResult::NORMAL) {
+  if (Install(path_old) != ci::AppInstaller::Result::OK) {
+    LOG(ERROR) << "Failed to install application. Cannot update";
+    return ci::AppInstaller::Result::UNKNOWN;
+  }
+  return Install(path_new, mode);
+}
+
+ci::AppInstaller::Result Uninstall(const std::string& pkgid,
+                                   RequestResult mode = RequestResult::NORMAL) {
+  const char* argv[] = {"", "-d", pkgid.c_str()};
+  std::unique_ptr<ci::AppQueryInterface> query_interface =
+      CreateQueryInterface();
+  auto pkgmgr =
+      ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
+                                  query_interface.get());
+  if (!pkgmgr) {
+    LOG(ERROR) << "Failed to initialize pkgmgr interface";
+    return ci::AppInstaller::Result::UNKNOWN;
+  }
+  return RunInstallerWithPkgrmgr(pkgmgr, mode);
+}
+
+ci::AppInstaller::Result Reinstall(const bf::path& path,
+                                   const bf::path& delta_dir,
+                                   RequestResult mode = RequestResult::NORMAL) {
+  if (Install(path) != ci::AppInstaller::Result::OK) {
+    LOG(ERROR) << "Failed to install application. Cannot perform RDS";
+    return ci::AppInstaller::Result::UNKNOWN;
+  }
+  const char* argv[] = {"", "-r", delta_dir.c_str()};
+  std::unique_ptr<ci::AppQueryInterface> query_interface =
+      CreateQueryInterface();
+  auto pkgmgr =
+      ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
+                                  query_interface.get());
+  if (!pkgmgr) {
+    LOG(ERROR) << "Failed to initialize pkgmgr interface";
+    return ci::AppInstaller::Result::UNKNOWN;
+  }
+  return RunInstallerWithPkgrmgr(pkgmgr, mode);
+}
+
+ci::AppInstaller::Result DeltaInstall(const bf::path& path,
+    const bf::path& delta_package) {
+  if (Install(path) != ci::AppInstaller::Result::OK) {
+    LOG(ERROR) << "Failed to install application. Cannot perform RDS";
+    return ci::AppInstaller::Result::UNKNOWN;
+  }
+  return Install(delta_package);
+}
+
+ci::AppInstaller::Result Recover(const bf::path& recovery_file,
+                                 RequestResult mode = RequestResult::NORMAL) {
+  const char* argv[] = {"", "-e", recovery_file.c_str()};
+  std::unique_ptr<ci::AppQueryInterface> query_interface =
+      CreateQueryInterface();
+  auto pkgmgr =
+      ci::PkgMgrInterface::Create(SIZEOFARRAY(argv), const_cast<char**>(argv),
+                                  query_interface.get());
+  if (!pkgmgr) {
+    LOG(ERROR) << "Failed to initialize pkgmgr interface";
+    return ci::AppInstaller::Result::UNKNOWN;
+  }
+  return RunInstallerWithPkgrmgr(pkgmgr, mode);
+}
+
+}  // namespace
+
+namespace common_installer {
+
+class SmokeEnvironment : public testing::Environment {
+ public:
+  explicit SmokeEnvironment(const bf::path& home) : home_(home) {
+  }
+  void SetUp() override {
+    bs::error_code error;
+    bf::remove_all(home_ / kApplicationDirBackup, error);
+    bf::remove_all(home_ / KUserAppsDirBackup, error);
+    if (bf::exists(home_ / KUserAppsDir)) {
+      bf::rename(home_ / KUserAppsDir, home_ / KUserAppsDirBackup, error);
+      assert(!error);
+    }
+    if (bf::exists(home_ / kApplicationDir)) {
+      bf::rename(home_ / kApplicationDir, home_ / kApplicationDirBackup, error);
+      assert(!error);
+    }
+  }
+  void TearDown() override {
+    bs::error_code error;
+    bf::remove_all(home_ / kApplicationDir, error);
+    bf::remove_all(home_ / KUserAppsDir, error);
+    if (bf::exists(home_ / KUserAppsDirBackup))
+      bf::rename(home_ / KUserAppsDirBackup, home_ / KUserAppsDir, error);
+    if (bf::exists(home_ / kApplicationDirBackup))
+      bf::rename(home_ / kApplicationDirBackup, home_ / kApplicationDir, error);
+  }
+
+ private:
+  bf::path home_;
+};
+
+class SmokeTest : public testing::Test {
+};
+
+TEST_F(SmokeTest, DeltaMode_Tpk) {
+  bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/DeltaMode_Tpk.tpk";  // NOLINT
+  std::string delta_package = "/usr/share/app-installers-ut/test_samples/smoke/DeltaMode_Tpk.delta"; // NOLINT
+  std::string pkgid = "smokeapp18";
+  std::string appid = "smokeapp18.DeltaModeTpk";
+  ASSERT_EQ(DeltaInstall(path, delta_package),
+            ci::AppInstaller::Result::OK);
+  ValidatePackage(pkgid, appid);
+
+  // Check delta modifications
+  bf::path root_path = ci::GetRootAppPath();
+  ASSERT_FALSE(bf::exists(root_path / pkgid / "DELETED"));
+  ASSERT_TRUE(bf::exists(root_path / pkgid / "ADDED"));
+  ASSERT_TRUE(bf::exists(root_path / pkgid / "bin" / "native"));
+  ASSERT_TRUE(bf::exists(root_path / pkgid / "shared" / "res" / "native.png"));
+  ValidateFileContentInPackage(pkgid, "MODIFIED", "version 2\n");
+}
+
+TEST_F(SmokeTest, InstallationMode_Tpk) {
+  bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/InstallationMode_Tpk.tpk";  // NOLINT
+  std::string pkgid = "smokeapp12";
+  std::string appid = "smokeapp12.InstallationModeTpk";
+  ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
+  ValidatePackage(pkgid, appid);
+}
+
+TEST_F(SmokeTest, UpdateMode_Tpk) {
+  bf::path path_old = "/usr/share/app-installers-ut/test_samples/smoke/UpdateMode_Tpk.tpk";  // NOLINT
+  bf::path path_new = "/usr/share/app-installers-ut/test_samples/smoke/UpdateMode_Tpk_2.tpk";  // NOLINT
+  std::string pkgid = "smokeapp13";
+  std::string appid = "smokeapp13.UpdateModeTpk";
+  ASSERT_EQ(Update(path_old, path_new), ci::AppInstaller::Result::OK);
+  ValidatePackage(pkgid, appid);
+
+  ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "VERSION", "2\n"));
+}
+
+TEST_F(SmokeTest, DeinstallationMode_Tpk) {
+  bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/DeinstallationMode_Tpk.tpk";  // NOLINT
+  std::string pkgid = "smokeapp14";
+  std::string appid = "smokeapp14.DeinstallationModeTpk";
+  ASSERT_EQ(Install(path), ci::AppInstaller::Result::OK);
+  ASSERT_EQ(Uninstall(pkgid), ci::AppInstaller::Result::OK);
+  CheckPackageNonExistance(pkgid, appid);
+}
+
+TEST_F(SmokeTest, RecoveryMode_Tpk_Installation) {
+  bf::path path = "/usr/share/app-installers-ut/test_samples/smoke/RecoveryMode_Tpk_Installation.tpk";  // NOLINT
+  ASSERT_DEATH(Install(path, RequestResult::CRASH), ".*");
+
+  std::string pkgid = "smokeapp15";
+  std::string appid = "smokeapp15.RecoveryModeTpkInstallation";
+  bf::path recovery_file = FindRecoveryFile();
+  ASSERT_FALSE(recovery_file.empty());
+  ASSERT_EQ(Recover(recovery_file), ci::AppInstaller::Result::OK);
+  CheckPackageNonExistance(pkgid, appid);
+}
+
+TEST_F(SmokeTest, RecoveryMode_Tpk_Update) {
+  bf::path path_old = "/usr/share/app-installers-ut/test_samples/smoke/RecoveryMode_Tpk_Update.tpk";  // NOLINT
+  bf::path path_new = "/usr/share/app-installers-ut/test_samples/smoke/RecoveryMode_Tpk_Update_2.tpk";  // NOLINT
+  RemoveAllRecoveryFiles();
+  ASSERT_DEATH(Update(path_old, path_new, RequestResult::CRASH), ".*");
+
+  std::string pkgid = "smokeapp16";
+  std::string appid = "smokeapp16.RecoveryModeTpkUpdate";
+  bf::path recovery_file = FindRecoveryFile();
+  ASSERT_FALSE(recovery_file.empty());
+  ASSERT_EQ(Recover(recovery_file), ci::AppInstaller::Result::OK);
+  ValidatePackage(pkgid, appid);
+
+  ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "VERSION", "1\n"));
+}
+
+}  // namespace common_installer
+
+int main(int argc,  char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  const char* directory = getenv("HOME");
+  if (!directory) {
+    LOG(ERROR) << "Cannot get $HOME value";
+    return 1;
+  }
+  testing::AddGlobalTestEnvironment(
+      new common_installer::SmokeEnvironment(directory));
+  return RUN_ALL_TESTS();
+}
diff --git a/src/unit_tests/test_samples/smoke/DeinstallationMode_Tpk.tpk b/src/unit_tests/test_samples/smoke/DeinstallationMode_Tpk.tpk
new file mode 100644 (file)
index 0000000..955b8b5
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/DeinstallationMode_Tpk.tpk differ
diff --git a/src/unit_tests/test_samples/smoke/DeltaMode_Tpk.delta b/src/unit_tests/test_samples/smoke/DeltaMode_Tpk.delta
new file mode 100644 (file)
index 0000000..bae36e2
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/DeltaMode_Tpk.delta differ
diff --git a/src/unit_tests/test_samples/smoke/DeltaMode_Tpk.tpk b/src/unit_tests/test_samples/smoke/DeltaMode_Tpk.tpk
new file mode 100644 (file)
index 0000000..b0a04ec
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/DeltaMode_Tpk.tpk differ
diff --git a/src/unit_tests/test_samples/smoke/InstallationMode_Tpk.tpk b/src/unit_tests/test_samples/smoke/InstallationMode_Tpk.tpk
new file mode 100644 (file)
index 0000000..42dcc5d
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/InstallationMode_Tpk.tpk differ
diff --git a/src/unit_tests/test_samples/smoke/RecoveryMode_Tpk_Installation.tpk b/src/unit_tests/test_samples/smoke/RecoveryMode_Tpk_Installation.tpk
new file mode 100644 (file)
index 0000000..9ef0e27
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/RecoveryMode_Tpk_Installation.tpk differ
diff --git a/src/unit_tests/test_samples/smoke/RecoveryMode_Tpk_Update.tpk b/src/unit_tests/test_samples/smoke/RecoveryMode_Tpk_Update.tpk
new file mode 100644 (file)
index 0000000..5a111e5
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/RecoveryMode_Tpk_Update.tpk differ
diff --git a/src/unit_tests/test_samples/smoke/RecoveryMode_Tpk_Update_2.tpk b/src/unit_tests/test_samples/smoke/RecoveryMode_Tpk_Update_2.tpk
new file mode 100644 (file)
index 0000000..22db6cb
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/RecoveryMode_Tpk_Update_2.tpk differ
diff --git a/src/unit_tests/test_samples/smoke/UpdateMode_Tpk.tpk b/src/unit_tests/test_samples/smoke/UpdateMode_Tpk.tpk
new file mode 100644 (file)
index 0000000..490b632
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/UpdateMode_Tpk.tpk differ
diff --git a/src/unit_tests/test_samples/smoke/UpdateMode_Tpk_2.tpk b/src/unit_tests/test_samples/smoke/UpdateMode_Tpk_2.tpk
new file mode 100644 (file)
index 0000000..5bb17b6
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/UpdateMode_Tpk_2.tpk differ
diff --git a/src/unit_tests/test_samples/tpk-sample-manifest.xml b/src/unit_tests/test_samples/tpk-sample-manifest.xml
new file mode 100644 (file)
index 0000000..c661101
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="2.3" package="org.tizen.testapp" version="1.0.0">
+    <author email="tester@samsung.com" href="www.tizen.org">tester</author>
+    <description>This is default description</description>
+    <description xml:lang="en-us">This is test description</description>
+    <ui-application appid="org.tizen.testapp" exec="testapp" multiple="false" nodisplay="false" taskmanage="true" type="capp">
+        <label>testapp</label>
+        <label xml:lang="en-us">Test</label>
+        <icon>testapp.png</icon>
+        <app-control>
+            <mime name="EditMime"/>
+            <operation name="http://tizen.org/appcontrol/operation/edit"/>
+            <uri name="EditUri"/>
+        </app-control>
+        <app-control>
+            <operation name="http://tizen.org/appcontrol/operation/view"/>
+            <uri name="ViewUri"/>
+            <mime name="ViewMime"/>
+        </app-control>
+        <metadata key="metakey1" value="metaval1"/>
+        <metadata key="metakey2" value="metaval2"/>
+        <datacontrol access="ReadOnly" providerid="http://testapp.com/datacontrol/provider/testapp" type="Sql"/>
+        <datacontrol access="ReadOnly" providerid="http://testapp.com/datacontrol/provider/testapp" type="Map"/>
+    </ui-application>
+    <account>
+        <account-provider appid="org.tizen.testapp" multiple-accounts-support="false" providerid="com.samsung">
+            <icon section="account">testapp.png</icon>
+            <icon section="account-small">testapp.png</icon>
+            <label xml:lang="en-gb">account icon</label>
+            <label>Samsung</label>
+            <capability>http://tizen.org/account/capability/calendar</capability>
+            <capability>http://tizen.org/account/capability/photo</capability>
+        </account-provider>
+    </account>
+    <privileges>
+        <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
+        <privilege>http://tizen.org/privilege/packagemanager.info</privilege>
+    </privileges>
+    <feature name="http://tizen.org/feature/camera.front.flash">true</feature>
+    <feature name="http://tizen.org/feature/camera">true</feature>
+    <feature name="http://tizen.org/feature/camera.back.flash">true</feature>
+    <feature name="http://tizen.org/feature/camera.front">true</feature>
+</manifest>