b6d3abbf22545c914b0627de3881a5668d22ca57
[platform/core/appfw/pkgmgr-info.git] / src / client / pkginfo_client.cc
1 // Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by an apache-2.0 license that can be
3 // found in the LICENSE file.
4
5 #include "pkginfo_client.hh"
6
7 #include <cpu-boosting.h>
8 #include <dlfcn.h>
9
10 #include <parcel.hh>
11 #include <vconf.h>
12
13 #include <mutex>
14 #include <string>
15
16 #include "parcelable_factory.hh"
17 #include "system_locale.hh"
18 #include "ready_checker.hh"
19 #include "utils/logging.hh"
20
21 #include "pkgmgrinfo_debug.h"
22 #include "pkgmgrinfo_private.h"
23
24 #define LIBPKGMGR_INFO LIB_PATH "/libpkgmgr-info-server.so.0"
25 #define DIRECT_ACCESS_FUNC "_request_handler_direct_access"
26
27 namespace pkgmgr_client {
28
29 constexpr const char SOCK_PATH[] = "/run/pkgmgr-info-server";
30 constexpr const char SERVER_READY[] = "/run/.pkginfo_server_ready";
31 constexpr const char DEST_PROCESS_NAME[] = "pkgmgr-info";
32
33 PkgInfoClient::CPUInheritanceInvoker::CPUInheritanceInvoker()
34     : set_complete_(false) {}
35
36 PkgInfoClient::CPUInheritanceInvoker::~CPUInheritanceInvoker() {
37   ClearCPUInheritance();
38 }
39
40 void PkgInfoClient::CPUInheritanceInvoker::SetCPUInheritance() {
41   int ret = resource_set_cpu_inheritance(gettid(), DEST_PROCESS_NAME, -1);
42   if (ret != 0) {
43     LOG(ERROR) << "set cpu inheritance fail ret : " << ret;
44     return;
45   }
46
47   set_complete_ = true;
48 }
49
50 void PkgInfoClient::CPUInheritanceInvoker::ClearCPUInheritance() {
51   if (!set_complete_)
52     return;
53
54   int ret = resource_clear_cpu_inheritance(gettid(), DEST_PROCESS_NAME);
55   if (ret != 0) {
56     LOG(ERROR) << "clear cpu inheritance fail ret : " << ret;
57     return;
58   }
59
60   set_complete_ = false;
61 }
62
63 PkgInfoClient::PkgInfoClient(
64     std::shared_ptr<pkgmgr_common::parcel::AbstractParcelable> parcel,
65     uid_t uid, pkgmgr_common::ReqType req_type)
66     : parcel_(parcel),
67       result_parcel_(nullptr),
68       uid_(uid),
69       req_type_(req_type),
70       is_offline_(false) {
71   socket_ = std::make_unique<pkgmgr_common::socket::ClientSocket>(SOCK_PATH);
72 }
73
74 bool PkgInfoClient::SendRequest() {
75   static pkgmgr_common::ReadyChecker check_server(SERVER_READY);
76   if (socket_ == nullptr) {
77     LOG(ERROR) << "Socket is not ready";
78     return false;
79   }
80
81   tizen_base::Parcel p;
82   p.WriteParcelable(*parcel_.get());
83   const auto& raw = p.GetRaw();
84   int len = raw.size();
85
86   // CREATE_DB request type need to be executed directly by the caller
87   if (req_type_ == pkgmgr_common::ReqType::CREATE_DB) {
88     is_offline_ = true;
89     return RequestHandlerDirectAccess(p.GetRaw());
90   }
91
92   if (!check_server.IsReady()) {
93     LOG(WARNING) << "Server is not ready, try to direct access";
94     is_offline_ = true;
95     return RequestHandlerDirectAccess(p.GetRaw());
96   }
97
98   LOG(WARNING) << "Try to send request, Request type: "
99       << pkgmgr_common::ReqTypeToString(req_type_);
100
101   cpu_inheritance_invoker_.SetCPUInheritance();
102   if (!socket_->Connect(req_type_)) {
103     LOG(ERROR) << "Failed to connect client socket, try to direct access";
104     is_offline_ = true;
105     return RequestHandlerDirectAccess(p.GetRaw());
106   }
107
108   if (socket_->SendData(&req_type_, sizeof(req_type_)) != 0) {
109     LOG(ERROR) << "fail to send data";
110     return false;
111   }
112
113   if (socket_->SendData(&len, sizeof(len)) != 0) {
114     LOG(ERROR) << "fail to send data";
115     return false;
116   }
117
118   if (socket_->SendData(&raw[0], len) != 0) {
119     LOG(ERROR) << "Fail to send data";
120     return false;
121   }
122
123   return true;
124 }
125
126 std::shared_ptr<pkgmgr_common::parcel::AbstractParcelable>
127 PkgInfoClient::GetResultParcel() {
128   if (is_offline_)
129     return result_parcel_;
130
131   if (socket_ == nullptr) {
132     LOG(ERROR) << "Socket is not ready";
133     return nullptr;
134   }
135
136   int len = 0;
137   if (socket_->ReceiveData(&len, sizeof(len)) != 0 || len <= 0) {
138     LOG(ERROR) << "Fail to receive data";
139     return nullptr;
140   }
141
142   unsigned char* raw = new (std::nothrow) unsigned char[len];
143   if (raw == nullptr) {
144     LOG(ERROR) << "Out of memory";
145     return nullptr;
146   }
147
148   if (socket_->ReceiveData(raw, len) != 0) {
149     LOG(ERROR) << "Fail to receive data";
150     delete[] raw;
151     return nullptr;
152   }
153
154   LOG(WARNING) << "Success to receive result from server"
155
156   cpu_inheritance_invoker_.ClearCPUInheritance();
157
158   auto res = pkgmgr_common::parcel::ParcelableFactory::GetInst().CreateParcel(
159       raw, len);
160   delete[] raw;
161
162   return res;
163 }
164
165 bool PkgInfoClient::RequestHandlerDirectAccess(
166     const std::vector<uint8_t>& raw) {
167   static std::mutex lock;
168   static void* handle = nullptr;
169   static void* (*dl_func)(int, const unsigned char*, int, const char*);
170
171   std::unique_lock<std::mutex> u(lock);
172   if (handle == nullptr) {
173     handle = dlopen(LIBPKGMGR_INFO, RTLD_GLOBAL | RTLD_LAZY);
174     if (!handle) {
175       LOG(ERROR) << "Failed to open library: " << LIBPKGMGR_INFO
176           << ", : " << dlerror();
177       return false;
178     }
179     dl_func = reinterpret_cast<void* (*)(
180         int, const unsigned char*, int, const char*)>(
181             dlsym(handle, DIRECT_ACCESS_FUNC));
182     if (dl_func == nullptr) {
183       LOG(ERROR) << "cannot find " << DIRECT_ACCESS_FUNC << " symbol in "
184           << LIBPKGMGR_INFO;
185       dlclose(handle);
186       handle = nullptr;
187       return false;
188     }
189   }
190   u.unlock();
191
192   result_parcel_.reset(
193       reinterpret_cast<pkgmgr_common::parcel::AbstractParcelable*>(
194           dl_func(req_type_, &raw[0], raw.size(),
195               pkgmgr_common::SystemLocale::GetInst(false).Get().c_str())));
196
197   return true;
198 }
199
200 }  // namespace pkgmgr_client