Fix for readonly update mode 79/97079/17
authorSangyoon Jang <s89.jang@samsung.com>
Fri, 11 Nov 2016 06:14:37 +0000 (15:14 +0900)
committerSangyoon Jang <s89.jang@samsung.com>
Wed, 30 Nov 2016 11:11:17 +0000 (20:11 +0900)
When try to update preload package RO to RW, installer should keep files
for rollback. This patch introduce new request type(ReadonlyUpdateInstall,
ReadonlyUpdateUninstall) for handling above request.

RO -> RW: keep RO package files, install new RW package at TZ_SYS_RW_APPS.
          signal type to send: Update
  changed package attributes: preload(true->false), update(false->true)

RW -> RO: remove RW package files at TZ_SYS_RW_APPS, pkgmgr/security
          context register using existing RO manifest and files.
  signal type to send: Update
  changed package attributes: preload(false->true), update(true->false)

Change-Id: Ibeceeffddb00d70f4a75abf8a1376a93e47f02f7
Signed-off-by: Sangyoon Jang <s89.jang@samsung.com>
14 files changed:
src/common/app_query_interface.h
src/common/pkgmgr_interface.cc
src/common/pkgmgr_query.cc
src/common/pkgmgr_query.h
src/common/pkgmgr_registration.cc
src/common/pkgmgr_signal.cc
src/common/request.h
src/common/step/configuration/step_configure.cc
src/common/step/configuration/step_parse_manifest.cc
src/common/step/configuration/step_switch_readonly_mode.cc [new file with mode: 0644]
src/common/step/configuration/step_switch_readonly_mode.h [new file with mode: 0644]
src/common/step/filesystem/step_remove_globalapp_symlinks.cc
src/common/step/pkgmgr/step_remove_manifest.cc
src/common/step/security/step_check_signature.cc

index ec1c2cb4495219757c8a3eb4e8cbf435224268c3..e6f275e49cc339cb2223447a9ffb0312f68a1629 100644 (file)
@@ -27,6 +27,13 @@ class AppQueryInterface {
    * \return true if package is installed
    */
   virtual bool IsPkgInstalled(const std::string& arg, uid_t uid) = 0;
+
+  /**
+   * \brief abstract method for getting package id from package file
+   *
+   * \return package id
+   */
+  virtual std::string GetPkgId(const std::string& arg) = 0;
 };
 
 }  // namespace common_installer
index 46db0349ba8f47b80497ce0ebc40b7fabcb7d988..cfdf11bfe5fdcaa07fceca1478339681b11cb4de 100644 (file)
@@ -15,6 +15,7 @@
 #include <fstream>
 
 #include "common/app_query_interface.h"
+#include "common/pkgmgr_query.h"
 #include "common/pkgmgr_signal.h"
 
 namespace bf = boost::filesystem;
@@ -105,17 +106,29 @@ RequestType PkgMgrInterface::GetRequestType() const {
           return RequestType::Install;
         }
       } else {
-        if (extension == kDeltaFileExtension)
+        if (extension == kDeltaFileExtension) {
           return RequestType::Delta;
-        else
-          return RequestType::Update;
+        } else {
+          std::string pkgid = query_interface_->GetPkgId(GetRequestInfo());
+          if (!GetIsPreloadRequest() &&
+              QueryIsReadonlyPackage(pkgid, GetUid()) &&
+              !QueryIsUpdatedReadonlyPackage(pkgid, GetUid()))
+            return RequestType::ReadonlyUpdateInstall;
+          else
+            return RequestType::Update;
+        }
       }
     }
-    case PKGMGR_REQ_UNINSTALL:
-      if (GetIsPreloadRequest() && GetIsPartialRW())
+    case PKGMGR_REQ_UNINSTALL: {
+      std::string pkgid = GetRequestInfo();
+      if (!GetIsPreloadRequest() &&
+          QueryIsUpdatedReadonlyPackage(pkgid, GetUid()))
+        return RequestType::ReadonlyUpdateUninstall;
+      else if (GetIsPreloadRequest() && GetIsPartialRW())
         return RequestType::PartialUninstall;
       else
         return RequestType::Uninstall;
+    }
     case PKGMGR_REQ_REINSTALL:
       return RequestType::Reinstall;
     case PKGMGR_REQ_CLEAR:
index a65ad7f5dd4f8a1e4cffef5616a037350ded3a4d..b92cf3e2a7c87451475049c5f01d3d4ddedd2507 100644 (file)
@@ -273,4 +273,24 @@ bool QueryIsDisabledPackage(const std::string& pkg_id, uid_t uid) {
   return true;
 }
 
+bool QueryIsUpdatedReadonlyPackage(const std::string& pkg_id, uid_t uid) {
+  pkgmgrinfo_pkginfo_h handle;
+  int ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkg_id.c_str(), uid, &handle);
+  if (ret != PMINFO_R_OK) {
+    if (ret != PMINFO_R_ENOENT)
+      LOG(ERROR) << "Failed to call pkgmgrinfo_pkginfo_get_usr_pkginfo";
+    return false;
+  }
+
+  bool is_update = false;
+  if (pkgmgrinfo_pkginfo_is_update(handle, &is_update) != PMINFO_R_OK) {
+    LOG(ERROR) << "pkgmgrinfo_pkginfo_is_preload failed";
+    pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+    return false;
+  }
+
+  pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+  return is_update;
+}
+
 }  // namespace common_installer
index 27f2770844387739cd9f68a8a918431122408448..939178010ccdd4a7639521cda9838658a7b880d3 100644 (file)
@@ -140,6 +140,17 @@ bool QueryIsReadonlyPackage(const std::string& pkg_id, uid_t uid);
  */
 bool QueryIsDisabledPackage(const std::string& pkg_id, uid_t uid);
 
+/**
+ * \brief Adapter interface for external PkgMgr module used for checking
+ *        if given package is updated readonly package
+ *
+ * \param pkg_id package id
+ * \param uid user id
+ *
+ * \return true if package is updated
+ */
+bool QueryIsUpdatedReadonlyPackage(const std::string& pkg_id, uid_t uid);
+
 }  // namespace common_installer
 
 #endif  // COMMON_PKGMGR_QUERY_H_
index 6f7b706aaafb004ea647b5dfb25650875df9ebc8..31b11ab22651bf770ae2d538ee0c68b184795e78 100644 (file)
@@ -80,17 +80,13 @@ bool RegisterCertificates(
 // "update" : this package is "preload" and is updated by downloadable update.
 // "removable" : this package can be removed.
 // "readonly" : this package exists in readonly location.
-bool AssignPackageTags(manifest_x* manifest,
-                       bool is_update) {
+bool AssignPackageTags(manifest_x* manifest) {
   // preload, removalbe and readonly : in parse_preload step.
-  if (!strcmp(manifest->preload, "true")) {
-    manifest->update = is_update ? strdup("true") : strdup("false");
+  if (!strcmp(manifest->preload, "true"))
     manifest->system = !strcmp(manifest->removable, "false") ?
         strdup("true") : strdup("false");
-  } else {
-    manifest->update = strdup("false");
+  else
     manifest->system = strdup("false");
-  }
 
   return true;
 }
@@ -109,7 +105,7 @@ bool RegisterAppInPkgmgr(manifest_x* manifest,
   if (!tep_path.empty())
     manifest->tep_name = strdup(tep_path.c_str());
 
-  if (!AssignPackageTags(manifest, false))
+  if (!AssignPackageTags(manifest))
     return false;
 
   int ret = request_mode != RequestMode::GLOBAL ?
@@ -133,7 +129,7 @@ bool UpgradeAppInPkgmgr(manifest_x* manifest,
                         const CertificateInfo& cert_info,
                         uid_t uid,
                         RequestMode request_mode) {
-  if (!AssignPackageTags(manifest, true))
+  if (!AssignPackageTags(manifest))
     return false;
 
   int ret = request_mode != RequestMode::GLOBAL ?
index 8e5408c572e43b2f79627ec78e3ef947ef993506..a3834db2f79477a003ff2a6f3cbad79d920d02cf 100644 (file)
@@ -30,6 +30,9 @@ const std::map<ci::RequestType, const char*> kEventStr = {
   {ci::RequestType::Uninstall, PKGMGR_INSTALLER_UNINSTALL_EVENT_STR},
   {ci::RequestType::PartialUninstall, PKGMGR_INSTALLER_UNINSTALL_EVENT_STR},
   {ci::RequestType::Update, PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
+  {ci::RequestType::ReadonlyUpdateInstall, PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
+  {ci::RequestType::ReadonlyUpdateUninstall,
+      PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
   {ci::RequestType::Delta, PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
   {ci::RequestType::Move, PKGMGR_INSTALLER_MOVE_EVENT_STR},
   {ci::RequestType::MountInstall, PKGMGR_INSTALLER_INSTALL_EVENT_STR},
index 0d53f964e45516c8ac0fdff59f35823661b24ce4..6b2abc17371cdb8fa1fdc7ff6ea3327d911f4bc9 100644 (file)
@@ -29,6 +29,8 @@ enum class RequestType : int {
   ManifestPartialInstall,
   ManifestPartialUpdate,
   PartialUninstall,
+  ReadonlyUpdateInstall,
+  ReadonlyUpdateUninstall,
   DisablePkg,
   EnablePkg
 };
index eeb65fa2baa5277f70be7351972b048eed24f9d2..56277c66d1f2477a141e0abeb0abae7b98a96191 100644 (file)
@@ -117,6 +117,22 @@ Step::Status StepConfigure::process() {
       context_->xml_path.set(xml_path);
       break;
     }
+    case RequestType::ReadonlyUpdateInstall:
+      context_->file_path.set(pkgmgr_->GetRequestInfo());
+      context_->pkgid.set(kStrEmpty);
+      if (!pkgmgr_->GetTepPath().empty()) {
+        context_->tep_path.set(pkgmgr_->GetTepPath());
+        context_->is_tep_move.set(pkgmgr_->GetIsTepMove());
+      }
+      break;
+    case RequestType::ReadonlyUpdateUninstall: {
+      context_->pkgid.set(pkgmgr_->GetRequestInfo());
+      bf::path original_path =
+          bf::path(tzplatform_getenv(TZ_SYS_RO_APP)) / context_->pkgid.get();
+      context_->unpacked_dir_path.set(original_path);
+      context_->file_path.set(kStrEmpty);
+      break;
+    }
     case RequestType::DisablePkg:
     case RequestType::EnablePkg:
       context_->pkgid.set(pkgmgr_->GetRequestInfo());
index a8df469055e31579ecba922e3d5f1deae2af1227..15ebe20d5dc7543872813e14326e851ab0abf3dd 100644 (file)
@@ -107,15 +107,11 @@ bool StepParseManifest::LocateConfigFile() {
     }
     case ManifestLocation::INSTALLED: {
       uid_t uid;
-      bool is_readonly;
-      if (QueryIsGlobalPackage(context_->pkgid.get(), context_->uid.get())) {
+      bool is_readonly = context_->is_readonly_package.get();
+      if (QueryIsGlobalPackage(context_->pkgid.get(), context_->uid.get()))
         uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
-        is_readonly = QueryIsReadonlyPackage(context_->pkgid.get(),
-            context_->uid.get());
-      } else {
+      else
         uid = context_->uid.get();
-        is_readonly = context_->is_readonly_package.get();
-      }
       bf::path xml_path =
           bf::path(getUserManifestPath(uid, is_readonly))
           / bf::path(context_->pkgid.get());
@@ -222,8 +218,19 @@ bool StepParseManifest::FillPackageInfo(manifest_x* manifest) {
   manifest->preload = strdup(pkg_info->preload().c_str());
   manifest->removable = strdup(pkg_info->removable().c_str());
 
+  // set update true if package is updated preload package
+  common_installer::RequestType req_type = context_->request_type.get();
+  if (req_type == RequestType::ReadonlyUpdateInstall)
+    manifest->update = strdup("true");
+  else if (req_type == RequestType::ReadonlyUpdateUninstall)
+    manifest->update = strdup("false");
+  else if (QueryIsUpdatedReadonlyPackage(pkg_info->package(),
+        context_->uid.get()))
+    manifest->update = strdup("true");
+  else
+    manifest->update = strdup("false");
+
   if (pkg_info->type().empty()) {
-    common_installer::RequestType req_type = context_->request_type.get();
     if ((req_type == RequestType::ManifestDirectInstall ||
         req_type == RequestType::ManifestDirectUpdate) &&
         context_->is_readonly_package.get())
diff --git a/src/common/step/configuration/step_switch_readonly_mode.cc b/src/common/step/configuration/step_switch_readonly_mode.cc
new file mode 100644 (file)
index 0000000..3a73741
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright (c) 2016 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 "common/step/configuration/step_switch_readonly_mode.h"
+
+namespace common_installer {
+namespace configuration {
+
+Step::Status StepSwitchReadonlyMode::process() {
+  bool is_readonly_package = context_->is_readonly_package.get();
+  context_->is_readonly_package.set(!is_readonly_package);
+  return Status::OK;
+}
+
+}  // namespace configuration
+}  // namespace common_installer
diff --git a/src/common/step/configuration/step_switch_readonly_mode.h b/src/common/step/configuration/step_switch_readonly_mode.h
new file mode 100644 (file)
index 0000000..32128fc
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright (c) 2016 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 COMMON_STEP_CONFIGURATION_STEP_SWITCH_READONLY_MODE_H_
+#define COMMON_STEP_CONFIGURATION_STEP_SWITCH_READONLY_MODE_H_
+
+#include <manifest_parser/utils/logging.h>
+
+#include "common/step/step.h"
+
+namespace common_installer {
+namespace configuration {
+
+class StepSwitchReadonlyMode : public common_installer::Step {
+ public:
+  using Step::Step;
+
+  Status process() override;
+  Status clean() override { return Status::OK; }
+  Status undo() override { return Status::OK; }
+  Status precheck() override { return Status::OK; }
+
+  STEP_NAME(SwitchReadonlyMode)
+};
+
+}  // namespace configuration
+}  // namespace common_installer
+
+#endif  // COMMON_STEP_CONFIGURATION_STEP_SWITCH_READONLY_MODE_H_
index 2cb761811139d556f90a9ba6b1ac31fb2ab3238f..dae5712b50e793903b3a318053a07cb042d93cce 100644 (file)
@@ -26,19 +26,22 @@ Step::Status StepRemoveGlobalAppSymlinks::process() {
   if (context_->is_readonly_package.get())
     return Step::Status::OK;
 
+  if (context_->request_mode.get() != RequestMode::GLOBAL)
+    return Step::Status::OK;
+
   if (!QueryIsPackageInstalled(context_->pkgid.get(), kGlobalUserUid))
     return Step::Status::OK;
 
   std::string package_id = context_->pkgid.get();
 
-  if (context_->request_type.get() == RequestType::Uninstall) {
-    if (context_->request_mode.get() == RequestMode::GLOBAL) {
-      LOG(INFO) << "Deleting globalapp symlinks for all user, package: "
-                << package_id;
-      if (!DeleteGlobalAppSymlinksForAllUsers(package_id)) {
-        LOG(ERROR) << "Failed to delete globalapp symlinks";
-        return Status::GLOBALSYMLINK_ERROR;
-      }
+  RequestType req_type = context_->request_type.get();
+  if (req_type == RequestType::Uninstall ||
+      req_type == RequestType::ReadonlyUpdateUninstall) {
+    LOG(INFO) << "Deleting globalapp symlinks for all user, package: "
+              << package_id;
+    if (!DeleteGlobalAppSymlinksForAllUsers(package_id)) {
+      LOG(ERROR) << "Failed to delete globalapp symlinks";
+      return Status::GLOBALSYMLINK_ERROR;
     }
   } else {
     LOG(INFO) << "Deleting globalapp symlinks for current user, package: "
index cd7e85f598a0f0d18347fabd2d6f88163961265d..45c4e4a4cf666678402baeb8cfe2596d9f4378ba 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <pkgmgr-info.h>
 #include <pkgmgr_installer.h>
+#include <tzplatform_config.h>
 
 #include <algorithm>
 #include <string>
@@ -24,8 +25,16 @@ namespace pkgmgr {
 
 
 common_installer::Step::Status StepRemoveManifest::process() {
+  bf::path manifest_path;
+  if (context_->request_type.get() == RequestType::ReadonlyUpdateUninstall) {
+    manifest_path = bf::path(tzplatform_getenv(TZ_SYS_RW_PACKAGES)) /
+        context_->pkgid.get();
+    manifest_path += ".xml";
+  } else {
+    manifest_path = context_->xml_path.get();
+  }
   bs::error_code error;
-  bf::remove(context_->xml_path.get(), error);
+  bf::remove(manifest_path, error);
 
   if (error) {
     LOG(ERROR) << "Failed to remove xml manifest file";
index fa8ea040661815d36925e07157f9370bce3d6f5c..8e184b80e0af70eee095825531d97a9ee6e2ca69 100644 (file)
@@ -104,6 +104,8 @@ Step::Status StepCheckSignature::process() {
   PrivilegeLevel level = PrivilegeLevel::UNTRUSTED;
   bool check_reference = true;
   if (context_->request_type.get() == ci::RequestType::Reinstall ||
+      context_->request_type.get() ==
+          ci::RequestType::ReadonlyUpdateUninstall ||
       (getuid() == 0 &&
       (context_->request_type.get() == ci::RequestType::ManifestDirectInstall ||
       context_->request_type.get() == ci::RequestType::ManifestDirectUpdate)))