Implement tpk backend library 43/97443/12 accepted/tizen/3.0/common/20161124.181943 accepted/tizen/3.0/ivi/20161124.030511 accepted/tizen/3.0/mobile/20161124.030352 accepted/tizen/3.0/tv/20161124.030425 accepted/tizen/3.0/wearable/20161124.030449 accepted/tizen/common/20161125.095050 accepted/tizen/ivi/20161125.004128 accepted/tizen/mobile/20161125.003522 accepted/tizen/tv/20161125.003855 accepted/tizen/wearable/20161125.004007 submit/tizen/20161124.000829 submit/tizen_3.0/20161123.114701
authorSangyoon Jang <s89.jang@samsung.com>
Tue, 7 Jun 2016 11:12:53 +0000 (20:12 +0900)
committerSangyoon Jang <s89.jang@samsung.com>
Tue, 22 Nov 2016 05:58:17 +0000 (14:58 +0900)
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 <s89.jang@samsung.com>
CMakeLists.txt
packaging/tpk-backend.spec
src/CMakeLists.txt
src/lib/CMakeLists.txt [new file with mode: 0644]
src/lib/tpk_archive_info.cc [new file with mode: 0644]
src/lib/tpk_archive_info.h [new file with mode: 0644]
src/lib/tpk_pkgmgr.cc [new file with mode: 0644]

index 7a8d8ce..79d54e4 100644 (file)
@@ -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)
index fe23e7f..c00c9ac 100644 (file)
@@ -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
index 6e53623..0189747 100644 (file)
@@ -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 (file)
index 0000000..f8b0604
--- /dev/null
@@ -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 (file)
index 0000000..2d2433f
--- /dev/null
@@ -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 <package-manager-plugin.h>
+#include <pkgmgr-info.h>
+#include <vconf.h>
+
+#include <boost/filesystem/path.hpp>
+
+#include <tpk_manifest_handlers/tpk_config_parser.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/service_application_handler.h>
+#include <tpk_manifest_handlers/ui_application_handler.h>
+#include <tpk_manifest_handlers/watch_application_handler.h>
+#include <tpk_manifest_handlers/widget_application_handler.h>
+
+#include <common/utils/file_util.h>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fstream>
+#include <string>
+#include <vector>
+
+namespace bf = boost::filesystem;
+namespace ci = common_installer;
+
+namespace {
+
+const char kVconfLanguageKey[] = "db/menu_widget/language";
+const std::vector<std::string> 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<const tpk::parse::PackageInfo>(
+          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<const tpk::parse::AuthorInfo>(
+          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<const tpk::parse::PrivilegesInfo>(
+          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 <typename T>
+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<const T>(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<const tpk::parse::PackageInfo>(
+          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<lang, text>;
+    // 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<tpk::parse::UIApplicationInfoList>(parser,
+      tpk::application_keys::kUIApplicationKey, locale, info))
+    return true;
+  if (GetAppLabel<tpk::parse::ServiceApplicationInfoList>(parser,
+      tpk::application_keys::kServiceApplicationKey, locale, info))
+    return true;
+  if (GetAppLabel<tpk::parse::WidgetApplicationInfoList>(parser,
+      tpk::application_keys::kWidgetApplicationKey, locale, info))
+    return true;
+  if (GetAppLabel<tpk::parse::WatchApplicationInfoList>(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<const tpk::parse::DescriptionInfoList>(
+          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<char*>(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 <typename T>
+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<const T>(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<tpk::parse::UIApplicationInfoList>(parser,
+      tpk::application_keys::kUIApplicationKey, locale, tmp_dir, info))
+    return true;
+  if (GetAppIcon<tpk::parse::ServiceApplicationInfoList>(parser,
+      tpk::application_keys::kServiceApplicationKey, locale, tmp_dir, info))
+    return true;
+  if (GetAppIcon<tpk::parse::WidgetApplicationInfoList>(parser,
+      tpk::application_keys::kWidgetApplicationKey, locale, tmp_dir, info))
+    return true;
+  if (GetAppIcon<tpk::parse::WatchApplicationInfoList>(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 (file)
index 0000000..160d331
--- /dev/null
@@ -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 <package-manager-plugin.h>
+
+#include <manifest_parser/utils/logging.h>
+
+#include <common/utils/singleton.h>
+
+class TpkArchiveInfo : public common_installer::Singleton<TpkArchiveInfo> {
+  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 (file)
index 0000000..798123b
--- /dev/null
@@ -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 <package-manager-plugin.h>
+
+#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;
+}