Change how to check pkginfo server ready flag
[platform/core/appfw/pkgmgr-info.git] / src / client / pkginfo_client.cc
index 0fc582e..d2ca8d5 100644 (file)
 
 #include "pkginfo_client.hh"
 
-#include "../common/parcel/abstract_parcel.hh"
+#include <cpu-boosting.h>
+#include <dlfcn.h>
 
+#include <parcel.hh>
+#include <vconf.h>
+
+#include <mutex>
 #include <string>
 
+#include "parcelable_factory.hh"
+#include "system_locale.hh"
+#include "ready_checker.hh"
+#include "utils/logging.hh"
+
+#include "pkgmgrinfo_debug.h"
+#include "pkgmgrinfo_private.h"
+
+#define LIBPKGMGR_INFO LIB_PATH "/libpkgmgr-info-server.so.0"
+#define DIRECT_ACCESS_FUNC "_request_handler_direct_access"
+
 namespace pkgmgr_client {
+
+constexpr const char SOCK_PATH[] = "/run/pkgmgr-info-server";
+constexpr const char SERVER_READY[] = "/run/.pkginfo_server_ready";
+constexpr const char DEST_PROCESS_NAME[] = "pkgmgr-info";
+
+PkgInfoClient::CPUInheritanceInvoker::CPUInheritanceInvoker()
+    : set_complete_(false) {}
+
+PkgInfoClient::CPUInheritanceInvoker::~CPUInheritanceInvoker() {
+  ClearCPUInheritance();
+}
+
+void PkgInfoClient::CPUInheritanceInvoker::SetCPUInheritance() {
+  int ret = resource_set_cpu_inheritance(gettid(), DEST_PROCESS_NAME, -1);
+  if (ret != 0) {
+    LOG(ERROR) << "set cpu inheritance fail ret : " << ret;
+    return;
+  }
+
+  set_complete_ = true;
+}
+
+void PkgInfoClient::CPUInheritanceInvoker::ClearCPUInheritance() {
+  if (!set_complete_)
+    return;
+
+  int ret = resource_clear_cpu_inheritance(gettid(), DEST_PROCESS_NAME);
+  if (ret != 0) {
+    LOG(ERROR) << "clear cpu inheritance fail ret : " << ret;
+    return;
+  }
+
+  set_complete_ = false;
+}
+
 PkgInfoClient::PkgInfoClient(
-    std::shared_ptr<pkgmgr_common::parcel::AbstractParcel> parcel,
-    uid_t uid,
-    std::shared_ptr<pkgmgr_common::parcel::AbstractParcel::IFactory> factory)
-    : parcel_(parcel), uid_(uid), factory_(factory) {
+    std::shared_ptr<pkgmgr_common::parcel::AbstractParcelable> parcel,
+    uid_t uid, pkgmgr_common::ReqType req_type)
+    : parcel_(parcel),
+      result_parcel_(nullptr),
+      uid_(uid),
+      req_type_(req_type),
+      is_offline_(false) {
+  socket_ = std::make_unique<pkgmgr_common::socket::ClientSocket>(SOCK_PATH);
 }
 
 bool PkgInfoClient::SendRequest() {
+  static pkgmgr_common::ReadyChecker check_server(SERVER_READY);
+  if (socket_ == nullptr) {
+    LOG(ERROR) << "Socket is not ready";
+    return false;
+  }
+
+  tizen_base::Parcel p;
+  p.WriteParcelable(*parcel_.get());
+
+  // CREATE_DB request type need to be executed directly by the caller
+  if (req_type_ == pkgmgr_common::ReqType::CREATE_DB) {
+    is_offline_ = true;
+    return RequestHandlerDirectAccess(&p);
+  }
+
+  if (!check_server.IsReady() && !check_server.Check()) {
+    LOG(WARNING) << "Server is not ready, try to direct access"
+        ", Request type: " << pkgmgr_common::ReqTypeToString(req_type_);
+    is_offline_ = true;
+    return RequestHandlerDirectAccess(&p);
+  }
+
+  LOG(WARNING) << "Try to send request, Request type: "
+      << pkgmgr_common::ReqTypeToString(req_type_);
+
+  cpu_inheritance_invoker_.SetCPUInheritance();
+  if (!socket_->Connect(req_type_)) {
+    LOG(ERROR) << "Failed to connect client socket, try to direct access"
+        ", Request type: " << pkgmgr_common::ReqTypeToString(req_type_);
+    is_offline_ = true;
+    return RequestHandlerDirectAccess(&p);
+  }
+
+  if (socket_->SendData(&req_type_, sizeof(req_type_)) != 0) {
+    LOG(ERROR) << "fail to send data";
+    return false;
+  }
+
+  pid_t tid = gettid();
+  if (socket_->SendData(&tid, sizeof(tid)) != 0) {
+    LOG(ERROR) << "fail to send data";
+    return false;
+  }
+
+  size_t len = p.GetDataSize();
+  if (socket_->SendData(&len, sizeof(len)) != 0) {
+    LOG(ERROR) << "fail to send data";
+    return false;
+  }
+
+  if (socket_->SendData(p.GetData(), len) != 0) {
+    LOG(ERROR) << "Fail to send data";
+    return false;
+  }
+
   return true;
 }
 
-std::shared_ptr<pkgmgr_common::parcel::AbstractParcel> PkgInfoClient::GetResultParcel() {
-  return nullptr;
+std::shared_ptr<pkgmgr_common::parcel::AbstractParcelable>
+PkgInfoClient::GetResultParcel() {
+  if (is_offline_)
+    return result_parcel_;
+
+  if (socket_ == nullptr) {
+    LOG(ERROR) << "Socket is not ready";
+    return nullptr;
+  }
+
+  size_t len = 0;
+  if (socket_->ReceiveData(&len, sizeof(len)) != 0 || len <= 0) {
+    LOG(ERROR) << "Fail to receive data";
+    return nullptr;
+  }
+
+  unsigned char* raw = static_cast<unsigned char*>(malloc(len));
+  if (raw == nullptr) {
+    LOG(ERROR) << "Out of memory";
+    return nullptr;
+  }
+
+  if (socket_->ReceiveData(raw, len) != 0) {
+    LOG(ERROR) << "Fail to receive data";
+    free(raw);
+    return nullptr;
+  }
+
+  LOG(WARNING) << "Success to receive result from server";
+
+  cpu_inheritance_invoker_.ClearCPUInheritance();
+
+  return pkgmgr_common::parcel::ParcelableFactory::GetInst().CreateParcel(
+      raw, len);
+}
+
+bool PkgInfoClient::RequestHandlerDirectAccess(tizen_base::Parcel* parcel) {
+  static std::mutex lock;
+  static void* handle = nullptr;
+  static void* (*dl_func)(int, unsigned char*, int, const char*);
+
+  std::unique_lock<std::mutex> u(lock);
+  if (handle == nullptr) {
+    handle = dlopen(LIBPKGMGR_INFO, RTLD_GLOBAL | RTLD_LAZY);
+    if (!handle) {
+      LOG(ERROR) << "Failed to open library: " << LIBPKGMGR_INFO
+          << ", : " << dlerror();
+      return false;
+    }
+    dl_func = reinterpret_cast<void* (*)(
+        int, unsigned char*, int, const char*)>(
+            dlsym(handle, DIRECT_ACCESS_FUNC));
+    if (dl_func == nullptr) {
+      LOG(ERROR) << "cannot find " << DIRECT_ACCESS_FUNC << " symbol in "
+          << LIBPKGMGR_INFO;
+      dlclose(handle);
+      handle = nullptr;
+      return false;
+    }
+  }
+  u.unlock();
+
+  size_t len = 0;
+  uint8_t* raw = parcel->Detach(&len);
+  result_parcel_.reset(
+      reinterpret_cast<pkgmgr_common::parcel::AbstractParcelable*>(
+          dl_func(req_type_, raw, len,
+              pkgmgr_common::SystemLocale::GetInst(false).Get().c_str())));
+
+  LOG(WARNING) << "Success to receive result";
+
+  return true;
 }
 
 }  // namespace pkgmgr_client