Mount gadget resource paths for NUIGadget
[platform/core/appfw/launchpad.git] / src / launchpad-process-pool / hydra_loader_context.cc
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "launchpad-process-pool/hydra_loader_context.hh"
18
19 #include <filesystem>
20 #include <string>
21 #include <utility>
22
23 #include <cpu_boost_controller.hh>
24 #include <exception.hh>
25 #include <hydra_request.hh>
26 #include <types.hh>
27
28 #include "launchpad-process-pool/log_private.hh"
29
30 namespace fs = std::filesystem;
31
32 namespace launchpad {
33 namespace {
34
35 constexpr const char kHydraLoaderSocketName[] = ".hydra-loader";
36 const int kSocketMaxBufferSize = 131071;
37
38 }  // namespace
39
40 HydraLoaderContext::Builder::operator LoaderContext*() {
41   return new HydraLoaderContext(std::move(loader_info_), loader_id_,
42       caller_pid_, activated_, std::move(loader_mount_));
43 }
44
45 HydraLoaderContext::HydraLoaderContext(
46     std::shared_ptr<LoaderInfo> loader_info, int loader_id, pid_t caller_pid,
47     bool activated, std::shared_ptr<LoaderMount> loader_mount)
48     : LoaderContext(std::move(loader_info), loader_id, caller_pid, activated,
49                     std::move(loader_mount)) {
50   Listen();
51 }
52
53 void HydraLoaderContext::Listen() {
54   try {
55     std::string socket_path = "/run/aul/daemons/" + std::to_string(getuid()) +
56         "/" + std::string(kHydraLoaderSocketName) + std::to_string(GetType()) +
57         "-" + std::to_string(GetLoaderId());
58     if (fs::exists(socket_path))
59       fs::remove(socket_path);
60
61     hydra_socket_.reset(new ServerSocket());
62     hydra_socket_->Bind(socket_path);
63     hydra_socket_->Listen(128);
64
65     hydra_channel_.reset(
66         new IOChannel(
67             hydra_socket_->GetFd(), IOChannel::IOCondition::IO_IN, this));
68     hydra_channel_->SetCloseOnDestroy(false);
69   } catch (const Exception& e) {
70     _E("Exception occurs. error: %s", e.what());
71     THROW(e.GetErrorCode());
72   }
73 }
74
75 void HydraLoaderContext::Dispose() {
76   _D("Dispose hydra process. type(%d), loader_name(%s)",
77       GetType(), GetLoaderName().c_str());
78
79   LoaderContext::Dispose();
80   if (hydra_pid_ > 0) {
81     _D("Kill process(%d)", hydra_pid_);
82     if (kill(hydra_pid_, SIGKILL) != 0)
83       _E("kill() is failed. pid(%d), errno(%d)", hydra_pid_, errno);
84
85     hydra_pid_ = 0;
86   }
87
88   client_channel_.reset();
89   client_socket_.reset();
90   hydra_prepared_ = false;
91 }
92
93 pid_t HydraLoaderContext::Prepare() {
94   _W("Prepare");
95   if (hydra_pid_ > 0 && client_socket_.get() != nullptr) {
96     PrepareCandidateProcess();
97     return hydra_pid_;
98   }
99
100   hydra_pid_ = LoaderContext::Prepare();
101   SetPid(0);
102   return hydra_pid_;
103 }
104
105 pid_t HydraLoaderContext::GetHydraPid() const {
106   return hydra_pid_;
107 }
108
109 void HydraLoaderContext::SetHydraPid(pid_t hydra_pid) {
110   hydra_pid_ = hydra_pid;
111 }
112
113 void HydraLoaderContext::PrepareCandidateProcess() {
114   _W("Send launch request to hydra loader. fd(%d)", client_socket_->GetFd());
115   HydraRequest request(HydraCmd::LaunchCandidate, GetSchedPriority());
116   tizen_base::Parcel parcel;
117   parcel.WriteParcelable(request);
118
119   size_t data_size = parcel.GetDataSize();
120   int ret = client_socket_->Send(static_cast<void*>(&data_size),
121       sizeof(data_size));
122   if (ret != 0) {
123     _E("Send() is failed. error: %d", ret);
124     return;
125   }
126
127   ret = client_socket_->Send(parcel.GetData(), data_size);
128   if (ret != 0)
129     _E("Send() is failed. error: %d", ret);
130 }
131
132 void HydraLoaderContext::HandleHydraLoaderEvent() {
133   if (!hydra_prepared_) {
134     try {
135       client_socket_ = hydra_socket_->Accept();
136       client_socket_->SetReceiveBufferSize(kSocketMaxBufferSize);
137       client_socket_->SetReceiveTimeout(5200);
138       client_socket_->SetSendBufferSize(kSocketMaxBufferSize);
139
140       int pid = -1;
141       int ret = client_socket_->Receive(static_cast<void*>(&pid), sizeof(pid));
142       if (ret != 0) {
143         _E("Receive() is failed. error: %d", ret);
144         client_socket_.reset();
145         return;
146       }
147
148       client_channel_.reset(
149           new IOChannel(client_socket_->GetFd(),
150             IOChannel::IOCondition::IO_IN | IOChannel::IOCondition::IO_HUP,
151             this));
152       client_channel_->SetCloseOnDestroy(false);
153       hydra_prepared_ = true;
154       SECURE_LOGI("Type %d hydra loader was connected. pid: %d",
155           GetType(), GetHydraPid());
156     } catch (const Exception& e) {
157       _E("Exception occurs. error: %s", e.what());
158       return;
159     }
160   } else {
161     auto client_socket = hydra_socket_->Accept();
162     _E("Refuse hydra process connection");
163   }
164 }
165
166 void HydraLoaderContext::HandleHydraLoaderClientEvent(int condition) {
167   if (condition &
168       (IOChannel::IOCondition::IO_HUP | IOChannel::IOCondition::IO_NVAL)) {
169     SECURE_LOGE("Type %d loader was disconnected. pid: %d",
170         GetType(), GetHydraPid());
171     Dispose();
172     Prepare();
173     return;
174   }
175
176   if (condition & IOChannel::IOCondition::IO_IN) {
177     pid_t pid = -1;
178     int ret = client_socket_->Receive(static_cast<void*>(&pid), sizeof(pid));
179     if (ret != 0) {
180       _E("Receive() is failed. error(%d)", ret);
181     } else {
182       _W("Candidate process: %d", pid);
183       if (pid > 0) {
184         SetPid(pid);
185         if (RefCount() > 0) {
186           CPUBoostController::DoBoost(pid, CPUBoostController::Level::Strong,
187               10000);
188         }
189       }
190     }
191   }
192 }
193
194 void HydraLoaderContext::OnIOEventReceived(int fd, int condition) {
195   _W("[DEBUG] fd(%d), condition(%d)", fd, condition);
196   if (hydra_socket_.get() != nullptr && hydra_socket_->GetFd() == fd)
197     HandleHydraLoaderEvent();
198   else if (client_socket_.get() != nullptr && client_socket_->GetFd() == fd)
199     HandleHydraLoaderClientEvent(condition);
200   else
201     LoaderContext::OnIOEventReceived(fd, condition);
202 }
203
204 }  // namespace launchpad