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