Remove log print related to fds
[platform/core/appfw/launchpad.git] / src / lib / launchpad-glib / util.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-glib/util.hh"
18
19 #include <bundle_internal.h>
20 #include <dbus/dbus.h>
21 #include <stdlib.h>
22 #include <sys/mount.h>
23 #include <sys/personality.h>
24 #include <sys/resource.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <tzplatform_config.h>
28 #include <unistd.h>
29
30 #include <algorithm>
31 #include <filesystem>
32 #include <fstream>
33 #include <memory>
34 #include <string>
35 #include <utility>
36 #include <vector>
37
38 #include <aul_keys.hh>
39 #include <exception.hh>
40 #include <parcel.hh>
41 #include <parcelable.hh>
42 #include <server_socket.hh>
43 #include <socket.hh>
44
45 #include "launchpad-glib/log_private.hh"
46
47 #define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)
48
49 namespace fs = std::filesystem;
50
51 namespace launchpad {
52 namespace {
53
54 constexpr const char kDefaultLocale[] = "en_US.UTF-8";
55 constexpr const char kTepBusName[] = "org.tizen.system.deviced";
56 constexpr const char kTepObjectPath[] = "/Org/Tizen/System/DeviceD/Tzip";
57 constexpr const char kTepInterfaceName[] = "org.tizen.system.deviced.Tzip";
58 constexpr const char kTepIsMountedMethod[] = "IsMounted";
59 const int kMaxTepIsMountRetryCount = 100;
60 constexpr const char kApp2sdBusName[] = "org.tizen.app2sd";
61 constexpr const char kApp2sdObjectPath[] = "/org/tizen/app2sd";
62 constexpr const char kApp2sdInterfaceName[] = "org.tizen.app2sd";
63 constexpr const char kApp2sdOndemandSetupInitMethod[] = "OndemandSetupInit";
64 const int kApp2sdRetryMax = 5;
65 const int kApp2sdWaitUsec = 1000000 / 2;  // 0.5 sec
66
67 void SetLanguageEnvironments() {
68   const char* lang = getenv("LANG");
69   if (lang == nullptr) {
70     lang = kDefaultLocale;
71     setenv("LANG", lang, 1);
72   }
73
74   setenv("LANGUAGE", lang, 1);
75   setenv("LC_MESSAGES", lang, 1);
76   setenv("LC_ALL", lang, 1);
77 }
78
79 void SetRegionFormatEnvironments() {
80   const char* region = getenv("LC_CTYPE");
81   if (region == nullptr) {
82     region = kDefaultLocale;
83     setenv("LC_CTYPE", region, 1);
84   }
85
86   setenv("LC_NUMERIC", region, 1);
87   setenv("LC_TIME", region, 1);
88   setenv("LC_COLLATE", region, 1);
89   setenv("LC_MONETARY", region, 1);
90   setenv("LC_PAPER", region, 1);
91   setenv("LC_NAME", region, 1);
92   setenv("LC_ADDRESS", region, 1);
93   setenv("LC_TELEPHONE", region, 1);
94   setenv("LC_MEASUREMENT", region, 1);
95   setenv("LC_IDENTIFICATION", region, 1);
96 }
97
98 void SetGadgetPkgIdsEnvironments(const tizen_base::Bundle& b) {
99   auto gadget_pkgids = b.GetStringArray(kAulMountGadgetPkgIds);
100   if (gadget_pkgids.empty()) return;
101
102   std::string pkgids;
103   for (auto& pkgid : gadget_pkgids) {
104     if (!pkgids.empty()) pkgids += ":";
105
106     pkgids += pkgid;
107   }
108
109   setenv("GADGET_PKGIDS", pkgids.c_str(), 1);
110 }
111
112 #ifdef TIZEN_FEATURE_SET_PERSONALITY_32
113 static void SetExecutionDomain() {
114   int ret = personality(PER_LINUX32);
115   if (ret < 0) {
116     char err_buf[1024];
117     _E("persionality() is failed. errno: %d(%s)",
118         errno, strerror_r(errno, err_buf, sizeof(err_buf)));
119   }
120 }
121 #endif  // TIZEN_FEATURE_SET_PERSONALITY_32
122
123 class DBus {
124  public:
125   DBus() {
126     DBusError error;
127     dbus_error_init(&error);
128     conn_ = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
129     if (conn_ == nullptr) {
130       _E("Failed to connect to D-Bus Daemon");
131       if (dbus_error_is_set(&error)) {
132         _E("D-Bus error: %s", error.message);
133         dbus_error_free(&error);
134       }
135       THROW(-ENOTCONN);
136     }
137   }
138
139   virtual ~DBus() {
140     if (conn_ != nullptr)
141       dbus_connection_close(conn_);
142   }
143
144   void SendMessage(DBusMessage* message, int timeout, int* result) {
145     if (message == nullptr) {
146       _E("Invalid parameter");
147       THROW(-EINVAL);
148     }
149
150     DBusPendingCall* pending = nullptr;
151     dbus_bool_t ret = dbus_connection_send_with_reply(conn_, message, &pending,
152         timeout);
153     if (!ret || pending == nullptr) {
154       _E("Failed to send message");
155       THROW(-EIO);
156     }
157
158     dbus_connection_flush(conn_);
159     dbus_pending_call_block(pending);
160     auto* reply = dbus_pending_call_steal_reply(pending);
161     dbus_pending_call_unref(pending);
162     if (reply == nullptr) {
163       _E("Failed to get reply message");
164       THROW(-EIO);
165     }
166
167     auto reply_auto =
168         std::unique_ptr<DBusMessage, decltype(dbus_message_unref)*>(
169             reply, dbus_message_unref);
170     DBusMessageIter iter;
171     if (!dbus_message_iter_init(reply, &iter)) {
172       _E("Message ha no argument");
173       THROW(-EIO);
174     }
175
176     if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
177       _E("Argument is not interger. type(%d)",
178           dbus_message_iter_get_arg_type(&iter));
179       THROW(-EIO);
180     }
181
182     dbus_int32_t res;
183     dbus_message_iter_get_basic(&iter, &res);
184     *result = static_cast<int>(res);
185     _D("Result: %d", *result);
186   }
187
188  private:
189   DBusConnection* conn_ = nullptr;
190 };
191
192 class TepMountChecker : public DBus {
193  public:
194   explicit TepMountChecker(std::vector<std::string> paths)
195       : paths_(std::move(paths)) {}
196
197   bool IsMounted() {
198     for (auto& path : paths_) {
199       if (CheckTepMount(path) != 0)
200         return false;
201     }
202
203     return true;
204   }
205
206  private:
207   DBusMessage* CreateTepMountMessage(const std::string& path) {
208     DBusMessage* message = dbus_message_new_method_call(kTepBusName,
209         kTepObjectPath, kTepInterfaceName, kTepIsMountedMethod);
210     if (message == nullptr) {
211       _E("dbus_message_new_method_call() is failed");
212       return nullptr;
213     }
214
215     DBusMessageIter iter;
216     dbus_message_iter_init_append(message, &iter);
217     auto* tep_path = path.c_str();
218     auto ret = dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
219         &tep_path);
220     if (!ret) {
221       _E("dbus_message_iter_append_basic() is failed");
222       dbus_message_unref(message);
223       return nullptr;
224     }
225
226     return message;
227   }
228
229   int IsTepMountDone(const std::string& path) {
230     int result = -1;
231     auto message = std::unique_ptr<DBusMessage, decltype(dbus_message_unref)*>(
232         CreateTepMountMessage(path), dbus_message_unref);
233     SendMessage(message.get(), 500, &result);
234     return result;
235   }
236
237   int CheckTepMount(const std::string& path) {
238     if (path.empty())
239       return 0;
240
241     int count = 0;
242     while (count < kMaxTepIsMountRetryCount) {
243       if (IsTepMountDone(path) == 1)
244         return 0;
245
246       usleep(50 * 1000);
247       count++;
248     }
249
250     _E("Not able to mount within 5 seconds. path(%s", path.c_str());
251     return -1;
252   }
253
254  private:
255   std::vector<std::string> paths_;
256 };
257
258 int MountDirectories(const std::vector<std::string>& srcs,
259     const std::string& dest) {
260   std::string opt = "lowerdir=";
261   for (auto& src : srcs)
262     opt += src + ":";
263   opt += dest;
264
265   _D("mount opt: %s", opt.c_str());
266   int ret = mount(nullptr, dest.c_str(), "overlay", MS_RDONLY, opt.c_str());
267   if (ret != 0)
268     _E("mount() is failed. dest(%s), errno(%d)", dest.c_str(), errno);
269
270   return ret;
271 }
272
273 class ExternalPackage : public DBus {
274  public:
275   ExternalPackage(std::string package, uid_t uid)
276       : package_(std::move(package)), uid_(uid) {
277     _D("package(%s), uid(%u)", package_.c_str(), uid_);
278   }
279
280   void Enable() {
281     int result = -1;
282     int retry_count = 0;
283     auto message = std::unique_ptr<DBusMessage, decltype(dbus_message_unref)*>(
284         CreateApp2sdMessage(), dbus_message_unref);
285     while (retry_count <= kApp2sdRetryMax) {
286       try {
287         SendMessage(message.get(), 500, &result);
288       } catch (const Exception& e) {
289         _E("Exception occurs. error(%s)", e.what());
290         retry_count++;
291         continue;
292       }
293
294       break;
295     }
296
297     _D("Result: %d", result);
298     if (result < 0)
299       THROW(-EIO);
300   }
301
302  private:
303   DBusMessage* CreateApp2sdMessage() {
304     DBusMessage* message = dbus_message_new_method_call(kApp2sdBusName,
305         kApp2sdObjectPath, kApp2sdInterfaceName,
306         kApp2sdOndemandSetupInitMethod);
307     if (message == nullptr) {
308       _E("dbus_message_new_method_call() is failed");
309       return nullptr;
310     }
311
312     DBusMessageIter iter;
313     dbus_message_iter_init_append(message, &iter);
314     const char* package = package_.c_str();
315     if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &package)) {
316       _E("dbus_message_iter_append_basic() is failed");
317       dbus_message_unref(message);
318       return nullptr;
319     }
320
321     if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &uid_)) {
322       _E("dbus_message_iter_append_basic() is failed");
323       dbus_message_unref(message);
324       return nullptr;
325     }
326
327     return message;
328   }
329
330  private:
331   std::string package_;
332   uid_t uid_;
333 };
334
335 class AmdPacket : public tizen_base::Parcelable {
336  public:
337   explicit AmdPacket(int cmd, bundle* request, int opt)
338       : cmd_(cmd), request_(request), opt_(opt) {}
339
340   void WriteToParcel(tizen_base::Parcel* parcel) const {
341     parcel->WriteInt32(cmd_);
342     if (request_ == nullptr) {
343       parcel->WriteInt32(0);
344       parcel->WriteInt32(opt_);
345     } else {
346       bundle_raw* raw = nullptr;
347       int len = 0;
348       bundle_encode(request_, &raw, &len);
349       parcel->WriteInt32(len);
350       parcel->WriteInt32(opt_);
351       parcel->Write(reinterpret_cast<unsigned char*>(raw), len);
352       bundle_free_encoded_rawdata(&raw);
353     }
354   }
355
356   void ReadFromParcel(tizen_base::Parcel* parcel) {
357     parcel->ReadInt32(&cmd_);
358   }
359
360  private:
361   int cmd_ = -1;
362   bundle* request_ = nullptr;
363   int opt_ = 0;
364 };
365
366 std::vector<std::string> ValidateAndModifyGadgetPaths(
367     const std::vector<std::string> gadget_paths) {
368   std::vector<std::string> paths;
369   for (const auto& path : gadget_paths) {
370     if (access(path.c_str(), F_OK) == 0)
371       paths.push_back(path);
372     else
373       paths.push_back(fs::path(path).parent_path().string());
374   }
375
376   return paths;
377 }
378
379 }  // namespace
380
381 void Util::SetEnvironments(const AppInfo* app_info) {
382   auto& b = app_info->GetBundle();
383   auto value = b.GetString(kAulStarttime);
384   if (!value.empty())
385     setenv("APP_START_TIME", value.c_str(), 1);
386
387   if (!app_info->GetHwacc().empty())
388     setenv("HWACC", app_info->GetHwacc().c_str(), 1);
389
390   if (!app_info->GetTaskmanage().empty())
391     setenv("TASKMANAGE", app_info->GetTaskmanage().c_str(), 1);
392
393   if (!app_info->GetRootPath().empty())
394     setenv("AUL_ROOT_PATH", app_info->GetRootPath().c_str(), 1);
395
396   if (!app_info->GetAppId().empty()) {
397     auto multiple_instance_app_id = b.GetString(kAulMultipleInstanceAppId);
398     if (!multiple_instance_app_id.empty())
399       setenv("AUL_APPID", multiple_instance_app_id.c_str(), 1);
400     else
401       setenv("AUL_APPID", app_info->GetAppId().c_str(), 1);
402   }
403
404   if (!app_info->GetPkgId().empty())
405     setenv("AUL_PKGID", app_info->GetPkgId().c_str(), 1);
406
407   if (!app_info->GetAppType().empty())
408     setenv("RUNTIME_TYPE", app_info->GetAppType().c_str(), 1);
409
410   value = b.GetString(kAulWaylandDisplay);
411   if (!value.empty())
412     setenv("WAYLAND_DISPLAY", value.c_str(), 1);
413
414   value = b.GetString(kAulWaylandWorkingDir);
415   if (!value.empty())
416     setenv("XDG_RUNTIME_DIR", value.c_str(), 1);
417
418   value = b.GetString(kAulApiVersion);
419   if (!value.empty())
420     setenv("TIZEN_API_VERSION", value.c_str(), 1);
421
422   setenv("AUL_PID", std::to_string(getpid()).c_str(), 1);
423
424   if (getenv("TIZEN_GLIB_CONTEXT") == nullptr)
425     setenv("TIZEN_GLIB_CONTEXT", "0", 1);
426
427   value = b.GetString(kAulFastLaunch);
428   if (!value.empty())
429     setenv("AUL_FAST_LAUNCH", value.c_str(), 1);
430
431   SetLanguageEnvironments();
432   SetRegionFormatEnvironments();
433
434 #ifdef TIZEN_FEATURE_SET_PERSONALITY_32
435   SetExecutionDomain();
436 #endif  // TIZEN_FEATURE_SET_PERSONALITY_32
437
438   setenv("GCOV_PREFIX", "/tmp", 1);
439   setenv("DALI_DISABLE_PARTIAL_UPDATE", "0", 1);
440   SetGadgetPkgIdsEnvironments(b);
441 }
442
443 void Util::DeleteSocketPath(pid_t pid, uid_t uid) {
444   std::string path ="/run/aul/apps/" + std::to_string(uid) + "/" +
445       std::to_string(pid);
446   if (!fs::exists(path))
447     return;
448
449   try {
450     fs::remove_all(path);
451   } catch (const std::exception& e) {
452     _E("Exception occurs. error: %s", e.what());
453   }
454 }
455
456 int Util::EnableExternalPackage(const AppInfo* app_info) {
457   auto installed_storage = app_info->GetBundle().GetString(
458       kAulInstalledStorage);
459   if (installed_storage != "external")
460     return 0;
461
462   try {
463     ExternalPackage external_package(app_info->GetPkgId(),
464         app_info->IsGlobal() ? GLOBAL_USER : getuid());
465     external_package.Enable();
466   } catch (const Exception& e) {
467     _E("Exception occurs. error(%s)", e.what());
468     return -1;
469   }
470
471   return 0;
472 }
473
474 int Util::MountResourceDirectories(const AppInfo* app_info) {
475   auto& root_path = app_info->GetRootPath();
476   auto& b = app_info->GetBundle();
477   auto global_res_dir = b.GetStringArray(kAulMountGlobalResDir);
478   if (!global_res_dir.empty())
479     MountDirectories(global_res_dir, root_path + "/res/mount/global");
480
481   auto allowed_res_dir = b.GetStringArray(kAulMountAllowedResDir);
482   if (!allowed_res_dir.empty())
483     MountDirectories(allowed_res_dir, root_path + "/res/mount/allowed");
484
485   return 0;
486 }
487
488 int Util::MountLibraryDirectories(const tizen_base::Bundle& b) {
489   auto lib_dir = b.GetStringArray(kAulMountLibDir);
490   if (!lib_dir.empty()) {
491     auto root_path = b.GetString(kAulRootPath);
492     MountDirectories(lib_dir, root_path + "/lib/");
493   }
494
495   return 0;
496 }
497
498 int Util::MountGadgetDirectories(const tizen_base::Bundle& b) {
499   auto gadget_paths = b.GetStringArray(kAulMountGadgetPaths);
500   if (!gadget_paths.empty()) {
501     gadget_paths = ValidateAndModifyGadgetPaths(gadget_paths);
502     auto root_path = b.GetString(kAulRootPath);
503     return MountDirectories(gadget_paths, root_path + "/bin");
504   }
505
506   return 0;
507 }
508
509 int Util::WaitTepMount(const AppInfo* app_info) {
510   if (app_info->GetBundle().GetType(kAulTepPath) == BUNDLE_TYPE_NONE)
511     return 0;
512
513   try {
514     auto paths = app_info->GetBundle().GetStringArray(kAulTepPath);
515     TepMountChecker checker(std::move(paths));
516     if (!checker.IsMounted())
517       return -1;
518   } catch (const Exception& e) {
519     _E("Exception occurs. error(%s)", e.what());
520     return e.GetErrorCode();
521   }
522
523   _I("TEP Mount has been done");
524   return 0;
525 }
526
527 std::string Util::GetLibDirectory(const std::string& app_path) {
528   std::filesystem::path path(app_path);
529   auto lib_dir = path.parent_path().string() + "/../lib/";
530   if (std::filesystem::exists(lib_dir))
531     return lib_dir;
532
533   return "";
534 }
535
536 void Util::CloseAllFds(const std::vector<int>& except_fds) {
537   int aul_fd = -1;
538   const char* aul_listen_fd = getenv("AUL_LISTEN_FD");
539   if (aul_listen_fd != nullptr)
540     aul_fd = atoi(aul_listen_fd);
541
542   std::vector<int> fds;
543   try {
544     fs::path proc_path("/proc/self/fd");
545     for (const auto& entry : fs::directory_iterator(proc_path)) {
546       if (!isdigit(entry.path().filename().string()[0]))
547         continue;
548
549       int fd = std::stoi(entry.path().filename().string());
550       if (fd < 3 || fd == aul_fd)
551         continue;
552
553       auto found = std::find_if(except_fds.begin(), except_fds.end(),
554           [&](int except_fd) {
555             return except_fd == fd;
556           });
557       if (found != except_fds.end())
558         continue;
559
560       fds.push_back(fd);
561     }
562   } catch (const fs::filesystem_error& e) {
563     _E("Execption occurs. error(%s)", e.what());
564   }
565
566   for (auto fd : fds)
567     close(fd);
568 }
569
570 int Util::PrepareAppSocket() {
571   try {
572     std::string path = "/run/aul/apps/" + std::to_string(getuid()) + "/" +
573         std::to_string(getpid());
574     if (access(path.c_str(), F_OK) != 0)
575       fs::create_directory(path);
576
577     path += "/.app-sock";
578     ServerSocket socket;
579     socket.Bind(path);
580     socket.Listen(128);
581     socket.SetReceiveBufferSize(Socket::kSocketMaxBufferSize);
582     socket.SetSendBufferSize(Socket::kSocketMaxBufferSize);
583     socket.SetCloseOnExec(false);
584     int fd = socket.RemoveFd();
585     setenv("AUL_LISTEN_FD", std::to_string(fd).c_str(), 1);
586   } catch (const Exception& e) {
587     _E("Exception occurs. error(%s)", e.what());
588     return e.GetErrorCode();
589   }
590
591   return 0;
592 }
593
594 int Util::PrepareAppIdFile(const AppInfo* app_info) {
595   std::string path = "/run/aul/apps/" + std::to_string(getuid()) + "/" +
596       std::to_string(getpid()) + "/" + app_info->GetAppId();
597   std::ofstream stream(path);
598   stream.close();
599   return 0;
600 }
601
602 int Util::SendCmdToAmd(enum AmdCmd cmd) {
603   return SendCmdToAmd(cmd, nullptr, static_cast<int>(AmdSocketOption::None));
604 }
605
606 int Util::SendCmdToAmd(enum AmdCmd cmd, bundle* request, int opt) {
607   try {
608     std::string endpoint = "/run/aul/daemons/.amd-sock";
609     ClientSocket socket;
610     socket.Connect(endpoint);
611     socket.SetReceiveBufferSize(Socket::kSocketMaxBufferSize);
612     socket.SetReceiveTimeout(5000);
613
614     AmdPacket packet(static_cast<int>(cmd), request, opt);
615     tizen_base::Parcel parcel;
616     parcel.WriteParcelable(packet);
617
618     int ret = socket.Send(parcel.GetData(), parcel.GetDataSize());
619     if (ret != 0) {
620       _E("Failed to send cmd(%d), error(%d)", static_cast<int>(cmd), ret);
621       return -ECOMM;
622     }
623   } catch (const Exception& e) {
624     _E("Exception occrus. error(%s)", e.what());
625     return e.GetErrorCode();
626   }
627
628   return 0;
629 }
630
631 }  // namespace launchpad