2 * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "launchpad-glib/util.hh"
19 #include <bundle_internal.h>
20 #include <dbus/dbus.h>
22 #include <sys/mount.h>
23 #include <sys/personality.h>
24 #include <sys/resource.h>
26 #include <sys/types.h>
27 #include <tzplatform_config.h>
38 #include <aul_keys.hh>
39 #include <exception.hh>
41 #include <parcelable.hh>
42 #include <server_socket.hh>
45 #include "launchpad-glib/log_private.hh"
47 #define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)
49 namespace fs = std::filesystem;
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
67 void SetLanguageEnvironments() {
68 const char* lang = getenv("LANG");
69 if (lang == nullptr) {
70 lang = kDefaultLocale;
71 setenv("LANG", lang, 1);
74 setenv("LANGUAGE", lang, 1);
75 setenv("LC_MESSAGES", lang, 1);
76 setenv("LC_ALL", lang, 1);
79 void SetRegionFormatEnvironments() {
80 const char* region = getenv("LC_CTYPE");
81 if (region == nullptr) {
82 region = kDefaultLocale;
83 setenv("LC_CTYPE", region, 1);
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);
98 void SetGadgetPkgIdsEnvironments(const tizen_base::Bundle& b) {
99 auto gadget_pkgids = b.GetStringArray(kAulMountGadgetPkgIds);
100 if (gadget_pkgids.empty()) return;
103 for (auto& pkgid : gadget_pkgids) {
104 if (!pkgids.empty()) pkgids += ":";
109 setenv("GADGET_PKGIDS", pkgids.c_str(), 1);
112 #ifdef TIZEN_FEATURE_SET_PERSONALITY_32
113 static void SetExecutionDomain() {
114 int ret = personality(PER_LINUX32);
117 _E("persionality() is failed. errno: %d(%s)",
118 errno, strerror_r(errno, err_buf, sizeof(err_buf)));
121 #endif // TIZEN_FEATURE_SET_PERSONALITY_32
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);
140 if (conn_ != nullptr)
141 dbus_connection_close(conn_);
144 void SendMessage(DBusMessage* message, int timeout, int* result) {
145 if (message == nullptr) {
146 _E("Invalid parameter");
150 DBusPendingCall* pending = nullptr;
151 dbus_bool_t ret = dbus_connection_send_with_reply(conn_, message, &pending,
153 if (!ret || pending == nullptr) {
154 _E("Failed to send message");
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");
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");
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));
183 dbus_message_iter_get_basic(&iter, &res);
184 *result = static_cast<int>(res);
185 _D("Result: %d", *result);
189 DBusConnection* conn_ = nullptr;
192 class TepMountChecker : public DBus {
194 explicit TepMountChecker(std::vector<std::string> paths)
195 : paths_(std::move(paths)) {}
198 for (auto& path : paths_) {
199 if (CheckTepMount(path) != 0)
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");
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,
221 _E("dbus_message_iter_append_basic() is failed");
222 dbus_message_unref(message);
229 int IsTepMountDone(const std::string& path) {
231 auto message = std::unique_ptr<DBusMessage, decltype(dbus_message_unref)*>(
232 CreateTepMountMessage(path), dbus_message_unref);
233 SendMessage(message.get(), 500, &result);
237 int CheckTepMount(const std::string& path) {
242 while (count < kMaxTepIsMountRetryCount) {
243 if (IsTepMountDone(path) == 1)
250 _E("Not able to mount within 5 seconds. path(%s", path.c_str());
255 std::vector<std::string> paths_;
258 int MountDirectories(const std::vector<std::string>& srcs,
259 const std::string& dest) {
260 std::string opt = "lowerdir=" + dest;
261 for (auto& src : srcs)
264 _D("mount opt: %s", opt.c_str());
265 int ret = mount(nullptr, dest.c_str(), "overlay", MS_RDONLY, opt.c_str());
267 _E("mount() is failed. dest(%s), errno(%d)", dest.c_str(), errno);
272 class ExternalPackage : public DBus {
274 ExternalPackage(std::string package, uid_t uid)
275 : package_(std::move(package)), uid_(uid) {
276 _D("package(%s), uid(%u)", package_.c_str(), uid_);
282 auto message = std::unique_ptr<DBusMessage, decltype(dbus_message_unref)*>(
283 CreateApp2sdMessage(), dbus_message_unref);
284 while (retry_count <= kApp2sdRetryMax) {
286 SendMessage(message.get(), 500, &result);
287 } catch (const Exception& e) {
288 _E("Exception occurs. error(%s)", e.what());
296 _D("Result: %d", result);
302 DBusMessage* CreateApp2sdMessage() {
303 DBusMessage* message = dbus_message_new_method_call(kApp2sdBusName,
304 kApp2sdObjectPath, kApp2sdInterfaceName,
305 kApp2sdOndemandSetupInitMethod);
306 if (message == nullptr) {
307 _E("dbus_message_new_method_call() is failed");
311 DBusMessageIter iter;
312 dbus_message_iter_init_append(message, &iter);
313 const char* package = package_.c_str();
314 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &package)) {
315 _E("dbus_message_iter_append_basic() is failed");
316 dbus_message_unref(message);
320 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &uid_)) {
321 _E("dbus_message_iter_append_basic() is failed");
322 dbus_message_unref(message);
330 std::string package_;
334 class AmdPacket : public tizen_base::Parcelable {
336 explicit AmdPacket(int cmd, bundle* request, int opt)
337 : cmd_(cmd), request_(request), opt_(opt) {}
339 void WriteToParcel(tizen_base::Parcel* parcel) const {
340 parcel->WriteInt32(cmd_);
341 if (request_ == nullptr) {
342 parcel->WriteInt32(0);
343 parcel->WriteInt32(opt_);
345 bundle_raw* raw = nullptr;
347 bundle_encode(request_, &raw, &len);
348 parcel->WriteInt32(len);
349 parcel->WriteInt32(opt_);
350 parcel->Write(reinterpret_cast<unsigned char*>(raw), len);
351 bundle_free_encoded_rawdata(&raw);
355 void ReadFromParcel(tizen_base::Parcel* parcel) {
356 parcel->ReadInt32(&cmd_);
361 bundle* request_ = nullptr;
367 void Util::SetEnvironments(const AppInfo* app_info) {
368 auto& b = app_info->GetBundle();
369 auto value = b.GetString(kAulStarttime);
371 setenv("APP_START_TIME", value.c_str(), 1);
373 if (!app_info->GetHwacc().empty())
374 setenv("HWACC", app_info->GetHwacc().c_str(), 1);
376 if (!app_info->GetTaskmanage().empty())
377 setenv("TASKMANAGE", app_info->GetTaskmanage().c_str(), 1);
379 if (!app_info->GetRootPath().empty())
380 setenv("AUL_ROOT_PATH", app_info->GetRootPath().c_str(), 1);
382 if (!app_info->GetAppId().empty()) {
383 auto multiple_instance_app_id = b.GetString(kAulMultipleInstanceAppId);
384 if (!multiple_instance_app_id.empty())
385 setenv("AUL_APPID", multiple_instance_app_id.c_str(), 1);
387 setenv("AUL_APPID", app_info->GetAppId().c_str(), 1);
390 if (!app_info->GetPkgId().empty())
391 setenv("AUL_PKGID", app_info->GetPkgId().c_str(), 1);
393 if (!app_info->GetAppType().empty())
394 setenv("RUNTIME_TYPE", app_info->GetAppType().c_str(), 1);
396 value = b.GetString(kAulWaylandDisplay);
398 setenv("WAYLAND_DISPLAY", value.c_str(), 1);
400 value = b.GetString(kAulWaylandWorkingDir);
402 setenv("XDG_RUNTIME_DIR", value.c_str(), 1);
404 value = b.GetString(kAulApiVersion);
406 setenv("TIZEN_API_VERSION", value.c_str(), 1);
408 setenv("AUL_PID", std::to_string(getpid()).c_str(), 1);
410 if (getenv("TIZEN_GLIB_CONTEXT") == nullptr)
411 setenv("TIZEN_GLIB_CONTEXT", "0", 1);
413 value = b.GetString(kAulFastLaunch);
415 setenv("AUL_FAST_LAUNCH", value.c_str(), 1);
417 SetLanguageEnvironments();
418 SetRegionFormatEnvironments();
420 #ifdef TIZEN_FEATURE_SET_PERSONALITY_32
421 SetExecutionDomain();
422 #endif // TIZEN_FEATURE_SET_PERSONALITY_32
424 setenv("GCOV_PREFIX", "/tmp", 1);
425 setenv("DALI_DISABLE_PARTIAL_UPDATE", "0", 1);
426 SetGadgetPkgIdsEnvironments(b);
429 void Util::DeleteSocketPath(pid_t pid, uid_t uid) {
430 std::string path ="/run/aul/apps/" + std::to_string(uid) + "/" +
432 if (!fs::exists(path))
436 fs::remove_all(path);
437 } catch (const std::exception& e) {
438 _E("Exception occurs. error: %s", e.what());
442 int Util::EnableExternalPackage(const AppInfo* app_info) {
443 auto installed_storage = app_info->GetBundle().GetString(
444 kAulInstalledStorage);
445 if (installed_storage != "external")
449 ExternalPackage external_package(app_info->GetPkgId(),
450 app_info->IsGlobal() ? GLOBAL_USER : getuid());
451 external_package.Enable();
452 } catch (const Exception& e) {
453 _E("Exception occurs. error(%s)", e.what());
460 int Util::MountResourceDirectories(const AppInfo* app_info) {
461 auto& root_path = app_info->GetRootPath();
462 auto& b = app_info->GetBundle();
463 auto global_res_dir = b.GetStringArray(kAulMountGlobalResDir);
464 if (!global_res_dir.empty())
465 MountDirectories(global_res_dir, root_path + "/res/mount/global");
467 auto allowed_res_dir = b.GetStringArray(kAulMountAllowedResDir);
468 if (!allowed_res_dir.empty())
469 MountDirectories(allowed_res_dir, root_path + "/res/mount/allowed");
471 auto res_pkgids = b.GetStringArray(kAulMountResPkgIds);
472 if (!res_pkgids.empty()) {
474 for (auto& pkgid : res_pkgids) {
481 setenv("RES_PKGIDS", pkgids.c_str(), 1);
487 int Util::MountGadgetDirectories(const tizen_base::Bundle& b) {
488 auto gadget_paths = b.GetStringArray(kAulMountGadgetPaths);
489 if (!gadget_paths.empty()) {
490 auto root_path = b.GetString(kAulRootPath);
491 return MountDirectories(gadget_paths, root_path + "/bin");
497 int Util::WaitTepMount(const AppInfo* app_info) {
498 if (app_info->GetBundle().GetType(kAulTepPath) == BUNDLE_TYPE_NONE)
502 auto paths = app_info->GetBundle().GetStringArray(kAulTepPath);
503 TepMountChecker checker(std::move(paths));
504 if (!checker.IsMounted())
506 } catch (const Exception& e) {
507 _E("Exception occurs. error(%s)", e.what());
508 return e.GetErrorCode();
511 _I("TEP Mount has been done");
515 std::string Util::GetLibDirectory(const std::string& app_path) {
516 std::filesystem::path path(app_path);
517 auto lib_dir = path.parent_path().string() + "/../lib/";
518 if (std::filesystem::exists(lib_dir))
524 void Util::CloseAllFds(const std::vector<int>& except_fds) {
526 const char* aul_listen_fd = getenv("AUL_LISTEN_FD");
527 if (aul_listen_fd != nullptr)
528 aul_fd = atoi(aul_listen_fd);
530 std::vector<int> fds;
532 fs::path proc_path("/proc/self/fd");
533 for (const auto& entry : fs::directory_iterator(proc_path)) {
534 if (!isdigit(entry.path().filename().string()[0]))
537 int fd = std::stoi(entry.path().filename().string());
538 if (fd < 3 || fd == aul_fd)
541 auto found = std::find_if(except_fds.begin(), except_fds.end(),
543 return except_fd == fd;
545 if (found != except_fds.end())
550 } catch (const fs::filesystem_error& e) {
551 _E("Execption occurs. error(%s)", e.what());
554 _W("size: %zd", fds.size());
559 int Util::PrepareAppSocket() {
561 std::string path = "/run/aul/apps/" + std::to_string(getuid()) + "/" +
562 std::to_string(getpid());
563 if (access(path.c_str(), F_OK) != 0)
564 fs::create_directory(path);
566 path += "/.app-sock";
570 socket.SetReceiveBufferSize(Socket::kSocketMaxBufferSize);
571 socket.SetSendBufferSize(Socket::kSocketMaxBufferSize);
572 socket.SetCloseOnExec(false);
573 int fd = socket.RemoveFd();
574 setenv("AUL_LISTEN_FD", std::to_string(fd).c_str(), 1);
575 } catch (const Exception& e) {
576 _E("Exception occurs. error(%s)", e.what());
577 return e.GetErrorCode();
583 int Util::PrepareAppIdFile(const AppInfo* app_info) {
584 std::string path = "/run/aul/apps/" + std::to_string(getuid()) + "/" +
585 std::to_string(getpid()) + "/" + app_info->GetAppId();
586 std::ofstream stream(path);
591 int Util::SendCmdToAmd(enum AmdCmd cmd) {
592 return SendCmdToAmd(cmd, nullptr, static_cast<int>(AmdSocketOption::None));
595 int Util::SendCmdToAmd(enum AmdCmd cmd, bundle* request, int opt) {
597 std::string endpoint = "/run/aul/daemons/.amd-sock";
599 socket.Connect(endpoint);
600 socket.SetReceiveBufferSize(Socket::kSocketMaxBufferSize);
601 socket.SetReceiveTimeout(5000);
603 AmdPacket packet(static_cast<int>(cmd), request, opt);
604 tizen_base::Parcel parcel;
605 parcel.WriteParcelable(packet);
607 int ret = socket.Send(parcel.GetData(), parcel.GetDataSize());
609 _E("Failed to send cmd(%d), error(%d)", static_cast<int>(cmd), ret);
612 } catch (const Exception& e) {
613 _E("Exception occrus. error(%s)", e.what());
614 return e.GetErrorCode();
620 } // namespace launchpad