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