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