Handle abnormally terminated installer process
[platform/core/appfw/pkgmgr-info.git] / src / server / worker_thread.cc
index c377a8f..129ff1d 100644 (file)
 #include "worker_thread.hh"
 
 #include <sqlite3.h>
+#include <sys/types.h>
 #include <malloc.h>
 
+#include <tzplatform_config.h>
+
 #include "abstract_parcelable.hh"
-#include "command_request_handler.hh"
-#include "create_cache_request_handler.hh"
-#include "create_db_request_handler.hh"
-#include "db_handle_provider.hh"
-#include "get_appinfo_request_handler.hh"
-#include "get_cert_request_handler.hh"
-#include "get_depinfo_request_handler.hh"
-#include "get_pkginfo_request_handler.hh"
-#include "query_request_handler.hh"
-#include "set_cert_request_handler.hh"
-#include "set_pkginfo_request_handler.hh"
+#include "cynara_checker.hh"
+#include "request_handler_factory.hh"
+#include "server/database/db_handle_provider.hh"
+#include "server/database/remove_cache_db_handler.hh"
 #include "utils/logging.hh"
 
 #include "pkgmgrinfo_debug.h"
 #define SQLITE_ENABLE_MEMORY_MANAGEMENT
 #endif
 
-namespace pkgmgr_server {
+namespace {
 
-WorkerThread::Scheduler::Scheduler(pid_t tid) : tid_(tid) {
-  Get(&policy_, &param_);
-}
+uid_t globaluser_uid = -1;
 
-void WorkerThread::Scheduler::ChangePolicy() {
-  struct sched_param param = { 0, };
-  param.sched_priority = 1;
-  if (Set(SCHED_RR, &param) != 0)
-    return;
+uid_t GetGlobalUID() {
+  if (globaluser_uid == (uid_t)-1)
+    globaluser_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
 
-  int policy = -1;
-  Get(&policy, &param);
-  LOG(WARNING) << "Current policy: " << policy << ", priority: "
-               << param.sched_priority;
+  return globaluser_uid;
 }
 
-void WorkerThread::Scheduler::ResetPolicy() {
-  if (Set(policy_, &param_) != 0)
-    return;
-
-  struct sched_param param = { 0, };
-  int policy = -1;
-  Get(&policy, &param);
-  LOG(WARNING) << "Current policy: " << policy << ", priority: "
-               << param.sched_priority;
+uid_t ConvertUID(uid_t uid) {
+  if (uid < REGULAR_USER)
+    return GetGlobalUID();
+  else
+    return uid;
 }
 
-void WorkerThread::Scheduler::Get(int* policy, struct sched_param* param) {
-  if (sched_getparam(tid_, param) != 0)
-    LOG(ERROR) << "sched_getparam() is failed. errno: " << errno;
+const char PRIVILEGE_PACKAGE_MANAGER_ADMIN[] =
+    "http://tizen.org/privilege/packagemanager.admin";
+
+std::vector<std::string> GetPrivileges(pkgmgr_common::ReqType type) {
+  std::vector<std::string> ret;
+  if (type == pkgmgr_common::SET_CERT_INFO)
+    ret.emplace_back(PRIVILEGE_PACKAGE_MANAGER_ADMIN);
+  else if (type == pkgmgr_common::SET_PKG_INFO)
+    ret.emplace_back(PRIVILEGE_PACKAGE_MANAGER_ADMIN);
 
-  *policy = sched_getscheduler(tid_);
-  if (*policy < 0)
-    LOG(ERROR) << "sched_getscheduler() is failed. errno: " << errno;
+  return ret;
 }
 
-int WorkerThread::Scheduler::Set(int policy, struct sched_param* param) {
-  if (sched_setscheduler(tid_, policy, param) != 0) {
-    LOG(ERROR) << "sched_setscheduler() is failed. policy: " << policy
-               << ", errno: " << errno;
-    return -1;
-  }
+}  // namespace
 
-  LOG(WARNING) << "policy: " << policy << ", sched_priority: "
-               << param->sched_priority;
-  return 0;
-}
+namespace pkgmgr_server {
 
 WorkerThread::WorkerThread(unsigned int num) : stop_all_(false) {
   threads_.reserve(num);
@@ -119,91 +100,68 @@ bool WorkerThread::PushQueue(std::shared_ptr<PkgRequest> req) {
   return true;
 }
 
-void WorkerThread::Run() {
-  std::unique_ptr<request_handler::AbstractRequestHandler>
-      handler[pkgmgr_common::ReqType::MAX];
-  handler[pkgmgr_common::ReqType::GET_PKG_INFO].reset(
-      new request_handler::GetPkginfoRequestHandler());
-  handler[pkgmgr_common::ReqType::GET_APP_INFO].reset(
-      new request_handler::GetAppinfoRequestHandler());
-  handler[pkgmgr_common::ReqType::SET_PKG_INFO].reset(
-      new request_handler::SetPkginfoRequestHandler());
-  handler[pkgmgr_common::ReqType::SET_CERT_INFO].reset(
-      new request_handler::SetCertRequestHandler());
-  handler[pkgmgr_common::ReqType::GET_CERT_INFO].reset(
-      new request_handler::GetCertRequestHandler());
-  handler[pkgmgr_common::ReqType::GET_PKG_DEP_INFO].reset(
-      new request_handler::GetDepinfoRequestHandler());
-  handler[pkgmgr_common::ReqType::QUERY].reset(
-      new request_handler::QueryRequestHandler());
-  handler[pkgmgr_common::ReqType::COMMAND].reset(
-      new request_handler::CommandRequestHandler());
-  handler[pkgmgr_common::ReqType::CREATE_DB].reset(
-      new request_handler::CreateDBRequestHandler());
-  handler[pkgmgr_common::ReqType::CREATE_CACHE].reset(
-      new request_handler::CreateCacheRequestHandler());
-
-  std::unique_ptr<WorkerThread::Scheduler> scheduler(
-      new WorkerThread::Scheduler(gettid()));
+std::shared_ptr<PkgRequest> WorkerThread::PopQueue() {
+  SetMemoryTrimTimer();
+  std::unique_lock<std::mutex> u(lock_);
+  cv_.wait(u, [this] { return !this->queue_.empty() || stop_all_; });
+  if (stop_all_ && queue_.empty())
+    return nullptr;
 
+  auto req = queue_.front();
+  queue_.pop();
+  return req;
+}
+
+void WorkerThread::Run() {
+  RequestHandlerFactory factory;
   LOG(DEBUG) << "Initialize request handlers";
   while (true) {
-    std::shared_ptr<PkgRequest> req;
-    {
-      std::unique_lock<std::mutex> u(lock_);
-      cv_.wait(u, [this] { return !this->queue_.empty() || stop_all_; });
-      if (stop_all_ && queue_.empty())
-        return;
-      req = PopQueue();
+    std::shared_ptr<PkgRequest> req = PopQueue();
+    if (req == nullptr)
+      return;
+
+    if (!req->GetPrivilegeChecked()) {
+      if (!req->ReceiveData()) {
+        LOG(ERROR) << "Fail to receive data";
+        continue;
+      }
+
+      pkgmgr_common::ReqType type = req->GetRequestType();
+      std::vector<std::string> privileges = GetPrivileges(type);
+      if (!CynaraChecker::GetInst().CheckPrivilege(this, req, privileges))
+        continue;
     }
 
-    pkgmgr_common::ReqType type = req->GetRequestType();
+    auto type = req->GetRequestType();
     LOG(WARNING) << "Request type: " << pkgmgr_common::ReqTypeToString(type)
-        << " pid: " << req->GetSenderPID();
-    if (type <= pkgmgr_common::ReqType::REQ_TYPE_NONE
-            || type >= pkgmgr_common::ReqType::MAX) {
-      LOG(ERROR) << "Request type is invalid: " << static_cast<int>(type)
-          << ",  pid:" << req->GetSenderPID();
-      SendError(req);
-
+        << " pid: " << req->GetSenderPID() << " tid: " << req->GetSenderTID();
+    auto handler = factory.GetRequestHandler(type);
+    if (handler == nullptr)
       continue;
-    }
 
     try {
-      if (type == pkgmgr_common::ReqType::CREATE_CACHE)
-        scheduler->ChangePolicy();
-
-      handler[type]->SetPID(req->GetSenderPID());
-      if (!handler[type]->HandleRequest(req->GetData(), req->GetSize(),
-                                        locale_.GetObject()))
+      handler->PreExec();
+      handler->SetUID(ConvertUID(req->GetSenderUID()));
+      handler->SetPID(req->GetSenderPID());
+      if (!handler->HandleRequest(req->DetachData(), req->GetSize(),
+          locale_.GetObject()))
         LOG(ERROR) << "Failed to handle request";
+
+      if (req->SendData(handler->ExtractResult()) == false)
+        LOG(ERROR) << "Failed to send response pid: " << req->GetSenderPID();
+      else
+        LOG(WARNING) << "Success response pid: " << req->GetSenderPID()
+            << " tid: " << req->GetSenderTID();
     } catch (const std::exception& err) {
       LOG(ERROR) << "Exception occurred: " << err.what()
-          << ", pid: " << req->GetSenderPID();
+                 << ", pid: " << req->GetSenderPID();
       SendError(req);
-      if (type == pkgmgr_common::ReqType::CREATE_CACHE)
-        scheduler->ResetPolicy();
-
-      continue;
     } catch (...) {
       LOG(ERROR) << "Exception occurred pid: " << req->GetSenderPID();
       SendError(req);
-      if (type == pkgmgr_common::ReqType::CREATE_CACHE)
-        scheduler->ResetPolicy();
-
-      continue;
-    }
-
-    std::vector<uint8_t> result_data = handler[type]->ExtractResult();
-    if (req->SendData(result_data.data(), result_data.size()) == false) {
-      LOG(ERROR) << "Failed to send response pid: " << req->GetSenderPID();
-      continue;
     }
 
-    if (type == pkgmgr_common::ReqType::CREATE_CACHE)
-      scheduler->ResetPolicy();
-
-    LOG(WARNING) << "Success response pid: " <<  req->GetSenderPID();
+    handler->PostExec();
   }
 }
 
@@ -224,34 +182,31 @@ gboolean WorkerThread::TrimMemory(void* data) {
     h->timer_ = 0;
   }
 
-  if (database::DBHandleProvider::IsCrashedWriteRequest())
-    database::DBHandleProvider::GetInst(getuid()).UnsetMemoryMode(getpid());
+  auto crashed_writer_pids =
+      database::DBHandleProvider::CrashedWriteRequestPIDs();
+  if (!crashed_writer_pids.empty()) {
+    database::RemoveCacheDBHandler db(getuid(), std::move(crashed_writer_pids));
+    db.SetLocale(h->locale_.GetObject());
+    db.Execute();
+  }
 
   sqlite3_release_memory(-1);
   malloc_trim(0);
   return G_SOURCE_REMOVE;
 }
 
-std::shared_ptr<PkgRequest> WorkerThread::PopQueue() {
-  SetMemoryTrimTimer();
-  auto req = queue_.front();
-  queue_.pop();
-  return req;
-}
-
 void WorkerThread::SetLocale(std::string locale) {
   LOG(DEBUG) << "Change locale : " << locale_.GetObject()
       << " -> "  << locale;
   locale_.SetObject(std::move(locale));
 }
 
-void WorkerThread::SendError(std::shared_ptr<PkgRequest> req) {
+void WorkerThread::SendError(const std::shared_ptr<PkgRequest>& req) {
   pkgmgr_common::parcel::AbstractParcelable parcelable(
       0, pkgmgr_common::parcel::ParcelableType::Unknown, PMINFO_R_ERROR);
   tizen_base::Parcel p;
   p.WriteParcelable(parcelable);
-  std::vector<uint8_t> raw = p.GetRaw();
-  req->SendData(&raw[0], raw.size());
+  req->SendData(p);
 }
 
 }  // namespace pkgmgr_server