Add to mount lib directory for rpk
[platform/core/appfw/launchpad.git] / src / launchpad-process-pool / app_executor.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/app_executor.hh"
18
19 #include <errno.h>
20 #include <libgen.h>
21 #include <malloc.h>
22 #include <stdio.h>
23 #include <sys/prctl.h>
24 #include <trust-anchor.h>
25 #include <tzplatform_config.h>
26 #include <unistd.h>
27
28 #include <filesystem>
29 #include <utility>
30
31 #include <aul_keys.hh>
32 #include <plugin.hh>
33 #include <stdio.hh>
34 #include <types.hh>
35 #include <user_tracer.hh>
36 #include <util.hh>
37
38 #include "launchpad-process-pool/config.hh"
39 #include "launchpad-process-pool/debug.hh"
40 #include "launchpad-process-pool/log_private.hh"
41 #include "launchpad-process-pool/signal_manager.hh"
42
43 namespace launchpad {
44 namespace fs = std::filesystem;
45 namespace {
46
47 void ExecuteEcho(const std::string& app_path, const std::string& error) {
48   char *argv[] = {
49       const_cast<char*>("/usr/bin/echo"),
50       const_cast<char*>("Failed to execute a file. path:"),
51       const_cast<char*>(app_path.c_str()),
52       const_cast<char*>("error:"),
53       const_cast<char*>(error.c_str()),
54       nullptr,
55   };
56
57   execv(argv[0], argv);
58 }
59
60 }  // namespace
61
62 AppExecutor::AppExecutor() : Executor(this) {
63   LauncherInfoInflator inflator;
64   launcher_infos_ = inflator.Inflate("/usr/share/aul");
65
66   prepare_funcs_.push_back(
67       std::bind(&AppExecutor::StepPluginPrepareApp, this));
68   prepare_funcs_.push_back(
69       std::bind(&AppExecutor::StepEnableExternalPackage, this));
70   prepare_funcs_.push_back(
71       std::bind(&AppExecutor::StepEnableTrustAnchor, this));
72   prepare_funcs_.push_back(
73       std::bind(&AppExecutor::StepMountResDir, this));
74   prepare_funcs_.push_back(
75       std::bind(&AppExecutor::StepChangeMountNamespace, this));
76   prepare_funcs_.push_back(
77       std::bind(&AppExecutor::StepSecurityPrepareApp, this));
78   prepare_funcs_.push_back(
79       std::bind(&AppExecutor::StepSetupStdio, this));
80   prepare_funcs_.push_back(
81       std::bind(&AppExecutor::StepSetDumpable, this));
82   prepare_funcs_.push_back(
83       std::bind(&AppExecutor::StepSetProcessName, this));
84   prepare_funcs_.push_back(
85       std::bind(&AppExecutor::StepSetEnvironments, this));
86   prepare_funcs_.push_back(
87       std::bind(&AppExecutor::StepWaitTepMount, this));
88   prepare_funcs_.push_back(
89       std::bind(&AppExecutor::StepPrepareAppSocketAndIdFile, this));
90   prepare_funcs_.push_back(
91       std::bind(&AppExecutor::StepSendStartupSignal, this));
92
93   auto& process_pool_config = Config::GetInst().GetProcessPool();
94   process_pool_ = std::unique_ptr<ProcessPool>(
95       new ProcessPool("app", process_pool_config.GetNumberOfProcesses(), this));
96 }
97
98 pid_t AppExecutor::Execute(const AppInfo* app_info) {
99   if (process_pool_->IsPrepared()) {
100     tizen_base::Parcel parcel;
101     parcel.WriteParcelable(*app_info);
102     pid_t pid = process_pool_->Execute(parcel);
103     if (pid > 0)
104       return pid;
105   }
106
107   app_info_ = app_info;
108   return Executor::Execute();
109 }
110
111 void AppExecutor::DisposeCandidateProcess() {
112   process_pool_->Dispose();
113   process_pool_->SetTimer();
114 }
115
116 void AppExecutor::HandleSigchld(pid_t pid) {
117   process_pool_->HandleSigchld(pid);
118 }
119
120 void AppExecutor::OnExecution() {
121   UserTracer::Print(std::to_string(getpid()) + "|after calling fork(). " +
122       app_info_->GetAppId());
123   CheckAndPrepareDebugging();
124   SignalManager::GetInst().UnblockSigchld();
125   Util::DeleteSocketPath(getpid(), getuid());
126
127   int ret = Prepare();
128   if (ret < 0) {
129     _E("Failed to prepare executing application(%s)",
130         app_info_->GetAppId().c_str());
131     ExecuteEcho(app_info_->GetAppPath(), std::to_string(ret));
132     exit(ret);
133   }
134
135   std::vector<std::string> argv = CreateAppArgv(app_info_->GetAppPath(),
136       app_info_->GetBundle(), app_info_->GetAppType());
137   char** app_argv = static_cast<char**>(calloc(argv.size() + 1, sizeof(char*)));
138   if (app_argv == nullptr) {
139     _E("Out of memory");
140     ExecuteEcho(app_info_->GetAppPath(), std::to_string(-ENOMEM));
141     exit(-1);
142   }
143
144   int app_argc = argv.size();
145   for (int i = 0; i < app_argc; ++i) {
146     app_argv[i] = const_cast<char*>(argv[i].c_str());
147     SECURE_LOGD("input argument %d : %s##", i, app_argv[i]);
148   }
149
150   auto lib_dir = Util::GetLibDirectory(app_info_->GetAppPath());
151   if (!lib_dir.empty())
152     setenv("LD_LIBRARY_PATH", lib_dir.c_str(), 1);
153
154   Util::CloseAllFds();
155   if (execv(app_argv[LoaderArg::Path], app_argv) < 0) {
156     char err_buf[1024];
157     fprintf(stderr, "Failed to execute a file. path: %s, errno: %d(%s)\n",
158         app_info_->GetAppPath().c_str(), errno,
159         strerror_r(errno, err_buf, sizeof(err_buf)));
160     ExecuteEcho(app_info_->GetAppPath(), err_buf);
161     exit(EXIT_FAILURE);
162   }
163 }
164
165 void AppExecutor::OnRequestReceived(tizen_base::Parcel* parcel) {
166   _W("Request received");
167   AppInfo app_info;
168   parcel->ReadParcelable(&app_info);
169   app_info_ = &app_info;
170   OnExecution();
171 }
172
173 int AppExecutor::Prepare() {
174   for (auto& func : prepare_funcs_) {
175     if (func() != 0)
176       return -1;
177   }
178
179   return 0;
180 }
181
182 int AppExecutor::StepPluginPrepareApp() {
183   return Plugin::PrepareApp(app_info_->GetAppId(), app_info_->GetBundle());
184 }
185
186 int AppExecutor::StepEnableExternalPackage() {
187   return Util::EnableExternalPackage(app_info_);
188 }
189
190 int AppExecutor::StepEnableTrustAnchor() {
191   int ret = trust_anchor_launch(app_info_->GetPkgId().c_str(),
192       app_info_->IsGlobal() ? GLOBAL_USER : getuid());
193   if (ret != TRUST_ANCHOR_ERROR_NONE &&
194       ret != TRUST_ANCHOR_ERROR_NOT_INSTALLED) {
195     _E("trust_anchor_launch() returns %d", ret);
196     return -2;
197   }
198
199   return 0;
200 }
201
202 int AppExecutor::StepMountResDir() {
203   int ret = Util::MountGadgetDirectories(app_info_->GetBundle());
204   if (ret != 0) {
205     _E("Failed to mount gadget resources");
206     return ret;
207   }
208
209   ret = Util::MountLibraryDirectories(app_info_->GetBundle());
210   if (ret != 0) {
211     _E("Failed to mount lib directories");
212     return ret;
213   }
214
215   return Util::MountResourceDirectories(app_info_);
216 }
217
218 int AppExecutor::StepChangeMountNamespace() {
219   if (app_info_->GetBundle().GetType(kAulSdk) != BUNDLE_TYPE_NONE)
220     Debug::ChangeMountNamespace();
221
222   return 0;
223 }
224
225 int AppExecutor::StepSecurityPrepareApp() {
226   auto enabled_light_user = app_info_->GetBundle().GetString(
227       kAulEnabledLightUser);
228   _W("security_manager_prepare_app2 ++ %s", app_info_->GetAppId().c_str());
229   int ret = security_manager_prepare_app2(app_info_->GetAppId().c_str(),
230       enabled_light_user.empty() ? nullptr : enabled_light_user.c_str());
231   _W("security_manager_prepare_app2 -- %s", app_info_->GetAppId().c_str());
232   if (ret != SECURITY_MANAGER_SUCCESS) {
233     _E("security_manager_prepare_app2() returns %d", ret);
234     return -2;
235   }
236
237   return 0;
238 }
239
240 int AppExecutor::StepSetupStdio() {
241   if (app_info_->GetBundle().GetType(kAulSdk) == BUNDLE_TYPE_NONE)
242     Stdio::Setup();
243
244   return 0;
245 }
246
247 int AppExecutor::StepSetDumpable() {
248   prctl(PR_SET_DUMPABLE, 1);
249   return 0;
250 }
251
252 int AppExecutor::StepSetProcessName() {
253   fs::path file_path(app_info_->GetAppPath());
254   fs::path file_name = file_path.filename();
255   prctl(PR_SET_NAME, file_name.c_str());
256   return 0;
257 }
258
259 int AppExecutor::StepSetEnvironments() {
260   Util::SetEnvironments(app_info_);
261   return 0;
262 }
263
264 int AppExecutor::StepWaitTepMount() {
265   return Util::WaitTepMount(app_info_);
266 }
267
268 int AppExecutor::StepPrepareAppSocketAndIdFile() {
269   if (app_info_->GetBundle().GetType(kAulSdk) != BUNDLE_TYPE_NONE)
270     return 0;
271
272   if (Util::PrepareAppSocket() < 0)
273     return -1;
274
275   return Util::PrepareAppIdFile(app_info_);
276 }
277
278 int AppExecutor::StepSendStartupSignal() {
279   Util::SendCmdToAmd(AmdCmd::AppStartupSignal);
280   return 0;
281 }
282
283 void AppExecutor::CheckAndPrepareDebugging() {
284   auto& debug = Debug::GetInst();
285   auto& b = app_info_->GetBundle();
286   if (b.GetType(kAulSdk) != BUNDLE_TYPE_NONE)
287     debug.PrepareDebugger(b);
288
289   debug.CheckAndSetAsanActivation(app_info_->GetAppId());
290   debug.CheckWebAppDebugging(b);
291 }
292
293 std::vector<std::string> AppExecutor::GetLauncherArgv(
294   const std::string& app_type) {
295   std::vector<std::string> argv;
296   auto found = std::find_if(
297       launcher_infos_.begin(), launcher_infos_.end(),
298       [app_type](const launchpad::LauncherInfoPtr& info) -> bool {
299         return std::find_if(info->GetAppTypes().begin(),
300             info->GetAppTypes().end(),
301             [app_type](const std::string& type) -> bool {
302               return type == app_type;
303             }) != info->GetAppTypes().end();
304       });
305   if (found == launcher_infos_.end())
306     return argv;
307
308   auto launcher_info = *found;
309   argv.insert(argv.end(), launcher_info->GetExe());
310   argv.insert(argv.end(), launcher_info->GetExtraArgs().begin(),
311       launcher_info->GetExtraArgs().end());
312   return argv;
313 }
314
315 std::vector<std::string> AppExecutor::CreateAppArgv(const std::string& app_path,
316     const tizen_base::Bundle& b, const std::string& app_type) {
317   auto& inst = launchpad::Debug::GetInst();
318   std::vector<std::string> argv = inst.GetArgv();
319   if (inst.ShouldAttach())
320     return argv;
321
322   auto launcher_argv = GetLauncherArgv(app_type);
323   if (!launcher_argv.empty())
324     argv.insert(argv.end(), launcher_argv.begin(), launcher_argv.end());
325
326   auto exported_argv = b.Export();
327   exported_argv[LoaderArg::Path] = app_path;
328   if (!exported_argv.empty())
329     argv.insert(argv.end(), exported_argv.begin(), exported_argv.end());
330
331   auto extra_argv = inst.GetExtraArgv();
332   if (!extra_argv.empty())
333     argv.insert(argv.end(), extra_argv.begin(), extra_argv.end());
334
335   return argv;
336 }
337
338 }  // namespace launchpad