--- /dev/null
+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)
--- /dev/null
+# 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)
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+ <assign>
+ <filesystem path="/usr/bin/tpk-backend-ut/smoke_test" exec_label="User" />
+ </assign>
+</manifest>
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+ <assign>
+ <filesystem path="/usr/bin/tpk-backend" exec_label="User" />
+ </assign>
+</manifest>
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
-
-
--- /dev/null
+ADD_SUBDIRECTORY(tpk)
+ADD_SUBDIRECTORY(unit_tests)
--- /dev/null
+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})
--- /dev/null
+// 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
--- /dev/null
+// 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_
--- /dev/null
+// 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
--- /dev/null
+// 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_
--- /dev/null
+/* 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
--- /dev/null
+/* 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_
--- /dev/null
+// 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
--- /dev/null
+// 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_
--- /dev/null
+// 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
+
--- /dev/null
+// 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_
--- /dev/null
+// 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
+
--- /dev/null
+// 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_
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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
+
--- /dev/null
+/* 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_
--- /dev/null
+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})
--- /dev/null
+// 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();
+}
--- /dev/null
+<?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>