From f73b2d0413f87e587ed18717712e1d66135b7677 Mon Sep 17 00:00:00 2001 From: Sangyoon Jang Date: Tue, 7 Jun 2016 20:12:53 +0900 Subject: [PATCH] Implement tpk backend library This backend library is for getting package information from file. The functions are called by dlsym from pkgmgr_client api. (Refer to: https://review.tizen.org/gerrit/73286) Change-Id: I81d302854c73d1975bc3ce3e3bc5d13b2089812b Signed-off-by: Sangyoon Jang --- CMakeLists.txt | 3 + packaging/tpk-backend.spec | 3 + src/CMakeLists.txt | 1 + src/lib/CMakeLists.txt | 16 +++ src/lib/tpk_archive_info.cc | 319 ++++++++++++++++++++++++++++++++++++++++++++ src/lib/tpk_archive_info.h | 23 ++++ src/lib/tpk_pkgmgr.cc | 32 +++++ 7 files changed, 397 insertions(+) create mode 100644 src/lib/CMakeLists.txt create mode 100644 src/lib/tpk_archive_info.cc create mode 100644 src/lib/tpk_archive_info.h create mode 100644 src/lib/tpk_pkgmgr.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a8d8ce..79d54e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EXTRA_LINKER_FLAGS}") # Targets SET(TARGET_LIBNAME_TPK "tpk-installer") +SET(TARGET_LIBNAME_TPK_ARCHIVE_INFO "tpk") SET(TARGET_TPK_BACKEND "tpk-backend") SET(TARGET_SMOKE_TEST "smoke-test") @@ -44,8 +45,10 @@ 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(PKGMGR_TYPES_DEPS REQUIRED pkgmgr-types) PKG_CHECK_MODULES(TPK_MANIFEST_HANDLERS_DEPS REQUIRED tpk-manifest-handlers) PKG_CHECK_MODULES(MANIFEST_PARSER_DEPS REQUIRED manifest-parser) +PKG_CHECK_MODULES(VCONF_DEPS REQUIRED vconf) FIND_PACKAGE(Boost REQUIRED COMPONENTS system filesystem regex program_options) FIND_PACKAGE(GTest REQUIRED) diff --git a/packaging/tpk-backend.spec b/packaging/tpk-backend.spec index fe23e7f..c00c9ac 100644 --- a/packaging/tpk-backend.spec +++ b/packaging/tpk-backend.spec @@ -14,7 +14,9 @@ BuildRequires: gtest-devel BuildRequires: pkgconfig(app-installers) BuildRequires: pkgconfig(manifest-parser) BuildRequires: pkgconfig(pkgmgr) +BuildRequires: pkgconfig(pkgmgr-types) BuildRequires: pkgconfig(tpk-manifest-handlers) +BuildRequires: pkgconfig(vconf) %description Backend for tizen package files @@ -58,6 +60,7 @@ ln -s %{_bindir}/tpk-backend %{buildroot}%{_sysconfdir}/package-manager/backend/ %files %{_sysconfdir}/package-manager/backend/tpk %{_sysconfdir}/package-manager/backend/rpm +%{_sysconfdir}/package-manager/backendlib/libtpk.so %license LICENSE %manifest tpk-backend.manifest %{_bindir}/tpk-backend diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6e53623..0189747 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,2 +1,3 @@ +ADD_SUBDIRECTORY(lib) ADD_SUBDIRECTORY(tpk) ADD_SUBDIRECTORY(unit_tests) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt new file mode 100644 index 0000000..f8b0604 --- /dev/null +++ b/src/lib/CMakeLists.txt @@ -0,0 +1,16 @@ +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} LIB_SRCS) +ADD_LIBRARY(${TARGET_LIBNAME_TPK_ARCHIVE_INFO} SHARED ${LIB_SRCS}) + +TARGET_INCLUDE_DIRECTORIES(${TARGET_LIBNAME_TPK_ARCHIVE_INFO} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../") + +APPLY_PKG_CONFIG(${TARGET_LIBNAME_TPK_ARCHIVE_INFO} PUBLIC + APP_INSTALLERS_DEPS + PKGMGR_DEPS + PKGMGR_TYPES_DEPS + MANIFEST_PARSER_DEPS + TPK_MANIFEST_HANDLERS_DEPS + VCONF_DEPS + Boost +) + +INSTALL(TARGETS ${TARGET_LIBNAME_TPK_ARCHIVE_INFO} DESTINATION ${SYSCONF_INSTALL_DIR}/package-manager/backendlib) diff --git a/src/lib/tpk_archive_info.cc b/src/lib/tpk_archive_info.cc new file mode 100644 index 0000000..2d2433f --- /dev/null +++ b/src/lib/tpk_archive_info.cc @@ -0,0 +1,319 @@ +// Copyright (c) 2016 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 "lib/tpk_archive_info.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace bf = boost::filesystem; +namespace ci = common_installer; + +namespace { + +const char kVconfLanguageKey[] = "db/menu_widget/language"; +const std::vector kEntries = { + "shared/res", + "tizen-manifest.xml" +}; + +bool ExtractPackageArchive(const char* file_path, const bf::path& tmp_dir) { + for (auto& entry : kEntries) { + if (!ci::ExtractToTmpDir(file_path, tmp_dir, entry)) { + LOG(ERROR) << "Failed to extract"; + return false; + } + } + return true; +} + +bool GetPackageInfo(const tpk::parse::TPKConfigParser& parser, + package_manager_pkg_detail_info_t* info) { + auto pkg_info = + std::static_pointer_cast( + parser.GetManifestData(tpk::parse::PackageInfo::key())); + if (!pkg_info) + return false; + + snprintf(info->pkg_type, sizeof(info->pkg_type), "tpk"); + snprintf(info->pkg_name, sizeof(info->pkg_name), "%s", + pkg_info->package().c_str()); + snprintf(info->pkgid, sizeof(info->pkgid), "%s", pkg_info->package().c_str()); + snprintf(info->version, sizeof(info->version), "%s", + pkg_info->version().c_str()); + snprintf(info->api_version, sizeof(info->api_version), "%s", + pkg_info->api_version().c_str()); + + return true; +} + +bool GetAuthorInfo(const tpk::parse::TPKConfigParser& parser, + package_manager_pkg_detail_info_t* info) { + auto author_info = + std::static_pointer_cast( + parser.GetManifestData(tpk::parse::AuthorInfo::Key())); + if (!author_info) + return false; + + snprintf(info->author, sizeof(info->author), "%s", + author_info->name().c_str()); + + return true; +} + +bool GetPrivilegesInfo(const tpk::parse::TPKConfigParser& parser, + package_manager_pkg_detail_info_t* info) { + auto privileges_info = + std::static_pointer_cast( + parser.GetManifestData(tpk::parse::PrivilegesInfo::key())); + if (!privileges_info) + return false; + + const auto& privileges = privileges_info->GetPrivileges(); + for (auto& priv : privileges) { + // TODO: remove duplicates + info->privilege_list = g_list_append(info->privilege_list, + strdup(priv.first.c_str())); + } + + return true; +} + +template +bool GetAppLabel(const tpk::parse::TPKConfigParser& parser, + const std::string& key, const char* locale, + package_manager_pkg_detail_info_t* info) { + auto apps = std::static_pointer_cast(parser.GetManifestData(key)); + if (!apps) + return false; + for (auto& label : apps->items[0].label) { + if (label.xml_lang().empty()) + continue; + if (!strcmp(label.xml_lang().c_str(), locale)) { + snprintf(info->label, sizeof(info->label), "%s", label.text().c_str()); + return true; + } + } + for (auto& label : apps->items[0].label) { + if (label.xml_lang().empty()) { + snprintf(info->label, sizeof(info->label), "%s", label.text().c_str()); + return true; + } + } + return false; +} + +bool GetLabelInfo(const tpk::parse::TPKConfigParser& parser, const char* locale, + package_manager_pkg_detail_info_t* info) { + auto pkg_info = + std::static_pointer_cast( + parser.GetManifestData(tpk::parse::PackageInfo::key())); + // label for pkg is in PakageInfo + if (!pkg_info) { + LOG(ERROR) << "PackageInfo not found"; + return false; + } + + // search current locale first + for (auto& label : pkg_info->labels()) { + if (label.first.empty()) + continue; + // There is label info in PackageInfo using below format: + // using LangTextPair = pair; + // Maybe this can be refactored. + if (!strcmp(label.first.c_str(), locale)) { + snprintf(info->label, sizeof(info->label), "%s", label.second.c_str()); + return true; + } + } + // search again if cannot find label with current locale + for (auto& label : pkg_info->labels()) { + if (label.first.empty()) { + snprintf(info->label, sizeof(info->label), "%s", label.second.c_str()); + return true; + } + } + + // get label from app + if (GetAppLabel(parser, + tpk::application_keys::kUIApplicationKey, locale, info)) + return true; + if (GetAppLabel(parser, + tpk::application_keys::kServiceApplicationKey, locale, info)) + return true; + if (GetAppLabel(parser, + tpk::application_keys::kWidgetApplicationKey, locale, info)) + return true; + if (GetAppLabel(parser, + tpk::application_keys::kWatchApplicationKey, locale, info)) + return true; + + return false; +} + +bool GetDescriptionInfo(const tpk::parse::TPKConfigParser& parser, + const char* locale, package_manager_pkg_detail_info_t* info) { + auto desc_info = + std::static_pointer_cast( + parser.GetManifestData(tpk::parse::DescriptionInfoList::Key())); + if (!desc_info) + return false; + + // search current locale first + if (locale) { + for (auto& desc : desc_info->descriptions) { + if (desc.xml_lang().empty()) + continue; + if (!strcmp(desc.xml_lang().c_str(), locale)) { + snprintf(info->pkg_description, sizeof(info->pkg_description), "%s", + desc.description().c_str()); + return true; + } + } + } + // search again if cannot find desc with current locale + for (auto& desc : desc_info->descriptions) { + if (desc.xml_lang().empty()) { + snprintf(info->pkg_description, sizeof(info->pkg_description), "%s", + desc.description().c_str()); + return true; + } + } + + return false; +} + +bool ReadIcon(const bf::path& icon, const bf::path& tmp_dir, + package_manager_pkg_detail_info_t* info) { + bf::path icon_path; + if (icon.is_absolute()) + icon_path = icon; + else + icon_path = tmp_dir / "shared/res" / icon; + + LOG(INFO) << "Icon file path: " << icon_path; + + std::ifstream ifs(icon_path.c_str(), + std::ifstream::in | std::ifstream::binary); + ifs.seekg(0, ifs.end); + int len = ifs.tellg(); + ifs.seekg(0, ifs.beg); + + if (len <= 0) + return false; + + char* buf = static_cast(malloc(sizeof(char) * len)); + + LOG(INFO) << "Reading icon file, " << len << " bytes"; + ifs.read(buf, len); + + info->icon_buf = buf; + info->icon_size = len; + + return true; +} + +template +bool GetAppIcon(const tpk::parse::TPKConfigParser& parser, + const std::string& key, const char* locale, const bf::path tmp_dir, + package_manager_pkg_detail_info_t* info) { + auto apps = std::static_pointer_cast(parser.GetManifestData(key)); + if (!apps) + return false; + for (auto& icon : apps->items[0].app_icons.icons()) { + if (icon.lang().empty()) + continue; + if (!strcmp(icon.lang().c_str(), locale)) + return ReadIcon(bf::path(icon.path()), tmp_dir, info); + } + for (auto& icon : apps->items[0].app_icons.icons()) { + if (icon.lang().empty()) + return ReadIcon(bf::path(icon.path()), tmp_dir, info); + } + return false; +} + +bool GetIconInfo(const tpk::parse::TPKConfigParser& parser, const char* locale, + const bf::path tmp_dir, package_manager_pkg_detail_info_t* info) { + // get icon from ui application + if (GetAppIcon(parser, + tpk::application_keys::kUIApplicationKey, locale, tmp_dir, info)) + return true; + if (GetAppIcon(parser, + tpk::application_keys::kServiceApplicationKey, locale, tmp_dir, info)) + return true; + if (GetAppIcon(parser, + tpk::application_keys::kWidgetApplicationKey, locale, tmp_dir, info)) + return true; + if (GetAppIcon(parser, + tpk::application_keys::kWatchApplicationKey, locale, tmp_dir, info)) + return true; + return false; +} + +} // namespace + +bool TpkArchiveInfo::GetArchiveInfo(const char* file_path, + package_manager_pkg_detail_info_t* info) { + bf::path tmp_dir = ci::GenerateTmpDir("/tmp"); + if (!ci::CreateDir(tmp_dir)) + return false; + LOG(DEBUG) << "Unpack at temporary dir: " << tmp_dir; + if (!ExtractPackageArchive(file_path, tmp_dir)) + return false; + + tpk::parse::TPKConfigParser parser; + bf::path manifest_path = tmp_dir / "tizen-manifest.xml"; + if (!parser.ParseManifest(manifest_path)) { + LOG(ERROR) << "Failed to parse"; + return false; + } + + if (!GetPackageInfo(parser, info)) { + LOG(ERROR) << "Failed to get package info"; + bf::remove_all(tmp_dir); + return false; + } + if (!GetAuthorInfo(parser, info)) + LOG(WARNING) << "Failed to get author info"; + if (!GetPrivilegesInfo(parser, info)) + LOG(WARNING) << "Failed to get privilege info"; + + char* locale = vconf_get_str(kVconfLanguageKey); + LOG(INFO) << "Current locale: " << locale; + if (!GetLabelInfo(parser, locale, info)) + LOG(WARNING) << "Failed to get label info"; + if (!GetDescriptionInfo(parser, locale, info)) + LOG(WARNING) << "Failed to get description info"; + if (!GetIconInfo(parser, locale, tmp_dir, info)) + LOG(WARNING) << "Failed to get icon info"; + + free(locale); + bf::remove_all(tmp_dir); + + return true; +} diff --git a/src/lib/tpk_archive_info.h b/src/lib/tpk_archive_info.h new file mode 100644 index 0000000..160d331 --- /dev/null +++ b/src/lib/tpk_archive_info.h @@ -0,0 +1,23 @@ +// Copyright (c) 2016 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 LIB_TPK_ARCHIVE_INFO_H_ +#define LIB_TPK_ARCHIVE_INFO_H_ + +#include + +#include + +#include + +class TpkArchiveInfo : public common_installer::Singleton { + CRTP_DECLARE_DEFAULT_CONSTRUCTOR_CLASS(TpkArchiveInfo) + public: + bool GetArchiveInfo(const char* path, + package_manager_pkg_detail_info_t* info); + + SCOPE_LOG_TAG(TpkArchiveInfo) +}; + +#endif // LIB_TPK_ARCHIVE_INFO_H_ diff --git a/src/lib/tpk_pkgmgr.cc b/src/lib/tpk_pkgmgr.cc new file mode 100644 index 0000000..798123b --- /dev/null +++ b/src/lib/tpk_pkgmgr.cc @@ -0,0 +1,32 @@ +// Copyright (c) 2016 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 + +#include "lib/tpk_archive_info.h" + +namespace { + +int GetPackageArchiveInfo(const char* path, + package_manager_pkg_detail_info_t* info) { + if (!TpkArchiveInfo::Instance().GetArchiveInfo(path, info)) + return -1; + return 0; +} + +void PluginOnUnload() { +} + +} // namespace + +extern "C" TPK_BACKEND_EXPORT_API int pkg_plugin_on_load(pkg_plugin_set* set) { + if (set == nullptr) + return -1; + set->plugin_on_unload = PluginOnUnload; + set->pkg_is_installed = nullptr; + set->get_installed_pkg_list = nullptr; + set->get_pkg_detail_info = nullptr; + set->get_pkg_detail_info_from_package = GetPackageArchiveInfo; + return 0; +} -- 2.7.4