Release version 0.26.11
[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
84   // CREATE_DB request type need to be executed directly by the caller
85   if (req_type_ == pkgmgr_common::ReqType::CREATE_DB) {
86     is_offline_ = true;
87     return RequestHandlerDirectAccess(&p);
88   }
89
90   cpu_inheritance_invoker_.SetCPUInheritance();
91
92   if (!check_server.IsReady() && !check_server.Check()) {
93     LOG(WARNING) << "Server is not ready, try to direct access"
94         ", Request type: " << pkgmgr_common::ReqTypeToString(req_type_);
95     is_offline_ = true;
96     return RequestHandlerDirectAccess(&p);
97   }
98
99   LOG(WARNING) << "Try to send request, Request type: "
100       << pkgmgr_common::ReqTypeToString(req_type_);
101
102   if (!socket_->Connect(req_type_)) {
103     LOG(ERROR) << "Failed to connect client socket, try to direct access"
104         ", Request type: " << pkgmgr_common::ReqTypeToString(req_type_);
105     is_offline_ = true;
106     return RequestHandlerDirectAccess(&p);
107   }
108
109   if (socket_->SendData(&req_type_, sizeof(req_type_)) != 0) {
110     LOG(ERROR) << "fail to send data";
111     return false;
112   }
113
114   pid_t tid = gettid();
115   if (socket_->SendData(&tid, sizeof(tid)) != 0) {
116     LOG(ERROR) << "fail to send data";
117     return false;
118   }
119
120   size_t len = p.GetDataSize();
121   if (socket_->SendData(&len, sizeof(len)) != 0) {
122     LOG(ERROR) << "fail to send data";
123     return false;
124   }
125
126   if (socket_->SendData(p.GetData(), len) != 0) {
127     LOG(ERROR) << "Fail to send data";
128     return false;
129   }
130
131   return true;
132 }
133
134 std::shared_ptr<pkgmgr_common::parcel::AbstractParcelable>
135 PkgInfoClient::GetResultParcel() {
136   if (is_offline_)
137     return result_parcel_;
138
139   if (socket_ == nullptr) {
140     LOG(ERROR) << "Socket is not ready";
141     return nullptr;
142   }
143
144   size_t len = 0;
145   if (socket_->ReceiveData(&len, sizeof(len)) != 0 || len <= 0) {
146     LOG(ERROR) << "Fail to receive data";
147     return nullptr;
148   }
149
150   unsigned char* raw = static_cast<unsigned char*>(malloc(len));
151   if (raw == nullptr) {
152     LOG(ERROR) << "Out of memory";
153     return nullptr;
154   }
155
156   if (socket_->ReceiveData(raw, len) != 0) {
157     LOG(ERROR) << "Fail to receive data";
158     free(raw);
159     return nullptr;
160   }
161
162   LOG(WARNING) << "Success to receive result from server";
163
164   cpu_inheritance_invoker_.ClearCPUInheritance();
165
166   return pkgmgr_common::parcel::ParcelableFactory::GetInst().CreateParcel(
167       raw, len);
168 }
169
170 bool PkgInfoClient::RequestHandlerDirectAccess(tizen_base::Parcel* parcel) {
171   static std::mutex lock;
172   static void* handle = nullptr;
173   static void* (*dl_func)(int, unsigned char*, int, const char*);
174
175   std::unique_lock<std::mutex> u(lock);
176   if (handle == nullptr) {
177     handle = dlopen(LIBPKGMGR_INFO, RTLD_GLOBAL | RTLD_LAZY);
178     if (!handle) {
179       LOG(ERROR) << "Failed to open library: " << LIBPKGMGR_INFO
180           << ", : " << dlerror();
181       return false;
182     }
183     dl_func = reinterpret_cast<void* (*)(
184         int, unsigned char*, int, const char*)>(
185             dlsym(handle, DIRECT_ACCESS_FUNC));
186     if (dl_func == nullptr) {
187       LOG(ERROR) << "cannot find " << DIRECT_ACCESS_FUNC << " symbol in "
188           << LIBPKGMGR_INFO;
189       dlclose(handle);
190       handle = nullptr;
191       return false;
192     }
193   }
194   u.unlock();
195
196   size_t len = 0;
197   uint8_t* raw = parcel->Detach(&len);
198   result_parcel_.reset(
199       reinterpret_cast<pkgmgr_common::parcel::AbstractParcelable*>(
200           dl_func(req_type_, raw, len,
201               pkgmgr_common::SystemLocale::GetInst(false).Get().c_str())));
202
203   LOG(WARNING) << "Success to receive result";
204
205   return true;
206 }
207
208 }  // namespace pkgmgr_client