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 <dbus/dbus.h>
21 #include <sys/mount.h>
22 #include <sys/personality.h>
23 #include <sys/resource.h>
25 #include <sys/types.h>
26 #include <tzplatform_config.h>
36 #include <aul_keys.hh>
37 #include <exception.hh>
39 #include <parcelable.hh>
40 #include <server_socket.hh>
43 #include "launchpad-glib/log_private.hh"
45 #define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)
47 namespace fs = std::filesystem;
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
65 void SetLanguageEnvironments() {
66 const char* lang = getenv("LANG");
67 if (lang == nullptr) {
68 lang = kDefaultLocale;
69 setenv("LANG", lang, 1);
72 setenv("LANGUAGE", lang, 1);
73 setenv("LC_MESSAGES", lang, 1);
74 setenv("LC_ALL", lang, 1);
77 void SetRegionFormatEnvironments() {
78 const char* region = getenv("LC_CTYPE");
79 if (region == nullptr) {
80 region = kDefaultLocale;
81 setenv("LC_CTYPE", region, 1);
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);
96 #ifdef TIZEN_FEATURE_SET_PERSONALITY_32
97 static void SetExecutionDomain() {
98 int ret = personality(PER_LINUX32);
101 _E("persionality() is failed. errno: %d(%s)",
102 errno, strerror_r(errno, err_buf, sizeof(err_buf)));
105 #endif // TIZEN_FEATURE_SET_PERSONALITY_32
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);
124 if (conn_ != nullptr)
125 dbus_connection_close(conn_);
128 void SendMessage(DBusMessage* message, int timeout, int* result) {
129 if (message == nullptr) {
130 _E("Invalid parameter");
134 DBusPendingCall* pending = nullptr;
135 dbus_bool_t ret = dbus_connection_send_with_reply(conn_, message, &pending,
137 if (!ret || pending == nullptr) {
138 _E("Failed to send message");
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");
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");
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));
167 dbus_message_iter_get_basic(&iter, &res);
168 *result = static_cast<int>(res);
169 _D("Result: %d", *result);
173 DBusConnection* conn_ = nullptr;
176 class TepMountChecker : public DBus {
178 explicit TepMountChecker(std::vector<std::string> paths)
179 : paths_(std::move(paths)) {}
182 for (auto& path : paths_) {
183 if (CheckTepMount(path) != 0)
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");
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,
205 _E("dbus_message_iter_append_basic() is failed");
206 dbus_message_unref(message);
213 int IsTepMountDone(const std::string& path) {
215 auto message = std::unique_ptr<DBusMessage, decltype(dbus_message_unref)*>(
216 CreateTepMountMessage(path), dbus_message_unref);
217 SendMessage(message.get(), 500, &result);
221 int CheckTepMount(const std::string& path) {
226 while (count < kMaxTepIsMountRetryCount) {
227 if (IsTepMountDone(path) == 1)
234 _E("Not able to mount within 5 seconds. path(%s", path.c_str());
239 std::vector<std::string> paths_;
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)
248 _D("mount opt: %s", opt.c_str());
249 int ret = mount(nullptr, dest.c_str(), "overlay", MS_RDONLY, opt.c_str());
251 _E("mount() is failed. dest(%s), errno(%d)", dest.c_str(), errno);
254 class ExternalPackage : public DBus {
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_);
264 auto message = std::unique_ptr<DBusMessage, decltype(dbus_message_unref)*>(
265 CreateApp2sdMessage(), dbus_message_unref);
266 while (retry_count <= kApp2sdRetryMax) {
268 SendMessage(message.get(), 500, &result);
269 } catch (const Exception& e) {
270 _E("Exception occurs. error(%s)", e.what());
278 _D("Result: %d", result);
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");
293 DBusMessageIter iter;
294 dbus_message_iter_init_append(message, &iter);
295 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
297 _E("dbus_message_iter_append_basic() is failed");
298 dbus_message_unref(message);
306 std::string package_;
310 class AmdPacket : public tizen_base::Parcelable {
312 explicit AmdPacket(int cmd) : cmd_(cmd) {}
314 void WriteToParcel(tizen_base::Parcel* parcel) const {
315 parcel->WriteInt32(cmd_);
316 parcel->WriteInt32(0);
317 parcel->WriteInt32(0);
320 void ReadFromParcel(tizen_base::Parcel* parcel) {
321 parcel->ReadInt32(&cmd_);
330 void Util::SetEnvironments(const AppInfo* app_info) {
331 auto& b = app_info->GetBundle();
332 auto value = b.GetString(kAulStarttime);
334 setenv("APP_START_TIME", value.c_str(), 1);
336 if (!app_info->GetHwacc().empty())
337 setenv("HWACC", app_info->GetHwacc().c_str(), 1);
339 if (!app_info->GetTaskmanage().empty())
340 setenv("TASKMANAGE", app_info->GetTaskmanage().c_str(), 1);
342 if (!app_info->GetRootPath().empty())
343 setenv("AUL_ROOT_PATH", app_info->GetRootPath().c_str(), 1);
345 if (!app_info->GetAppId().empty())
346 setenv("AUL_APPID", app_info->GetAppId().c_str(), 1);
348 if (!app_info->GetPkgId().empty())
349 setenv("AUL_PKGID", app_info->GetPkgId().c_str(), 1);
351 if (!app_info->GetAppType().empty())
352 setenv("RUNTIME_TYPE", app_info->GetAppType().c_str(), 1);
354 value = b.GetString(kAulWaylandDisplay);
356 setenv("WAYLAND_DISPLAY", value.c_str(), 1);
358 value = b.GetString(kAulWaylandWorkingDir);
360 setenv("XDG_RUNTIME_DIR", value.c_str(), 1);
362 value = b.GetString(kAulApiVersion);
364 setenv("TIZEN_API_VERSION", value.c_str(), 1);
366 setenv("AUL_PID", std::to_string(getpid()).c_str(), 1);
367 setenv("TIZEN_GLIB_CONTEXT", "0", 1);
369 SetLanguageEnvironments();
370 SetRegionFormatEnvironments();
372 #ifdef TIZEN_FEATURE_SET_PERSONALITY_32
373 SetExecutionDomain();
374 #endif // TIZEN_FEATURE_SET_PERSONALITY_32
376 setenv("GCOV_PREFIX", "/tmp", 1);
377 setenv("DALI_DISABLE_PARTIAL_UPDATE", "0", 1);
380 void Util::DeleteSocketPath(pid_t pid, uid_t uid) {
381 std::string path ="/run/aul/apps/" + std::to_string(uid) + "/" +
383 if (!fs::exists(path))
387 fs::remove_all(path);
388 } catch (const std::exception& e) {
389 _E("Exception occurs. error: %s", e.what());
393 int Util::EnableExternalPackage(const AppInfo* app_info) {
394 auto installed_storage = app_info->GetBundle().GetString(
395 kAulInstalledStorage);
396 if (installed_storage != "external")
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());
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");
418 auto allowed_res_dir = b.GetStringArray(kAulMountAllowedResDir);
419 if (!allowed_res_dir.empty())
420 MountDirectories(allowed_res_dir, root_path + "/res/mount/allowed");
422 auto res_pkgids = b.GetStringArray(kAulMountResPkgIds);
423 if (!res_pkgids.empty()) {
425 for (auto& pkgid : res_pkgids) {
432 setenv("RES_PKGIDS", pkgids.c_str(), 1);
438 int Util::WaitTepMount(const AppInfo* app_info) {
439 if (app_info->GetBundle().GetType(kAulTepPath) == BUNDLE_TYPE_NONE)
443 auto paths = app_info->GetBundle().GetStringArray(kAulTepPath);
444 TepMountChecker checker(std::move(paths));
445 if (!checker.IsMounted())
447 } catch (const Exception& e) {
448 _E("Exception occurs. error(%s)", e.what());
449 return e.GetErrorCode();
452 _I("TEP Mount has been done");
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))
465 void Util::CloseAllFds() {
467 const char* aul_listen_fd = getenv("AUL_LISTEN_FD");
468 if (aul_listen_fd != nullptr)
469 aul_fd = atoi(aul_listen_fd);
471 std::vector<int> fds;
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]))
478 int fd = std::stoi(entry.path().filename().string());
479 if (fd < 3 || fd == aul_fd)
484 } catch (const fs::filesystem_error& e) {
485 _E("Execption occurs. error(%s)", e.what());
488 _W("size: %zd", fds.size());
493 int Util::PrepareAppSocket() {
495 std::string path = "/run/aul/apps/" + std::to_string(getuid()) + "/" +
496 std::to_string(getpid());
498 if (!fs::exists(path))
499 fs::create_directory(path);
501 path += "/.app-sock";
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();
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);
525 int Util::SendCmdToAmd(enum AmdCmd cmd) {
527 std::string endpoint = "/run/aul/daemons/.amd-sock";
529 socket.Connect(endpoint);
530 socket.SetReceiveBufferSize(Socket::kSocketMaxBufferSize);
531 socket.SetReceiveTimeout(5000);
533 AmdPacket packet(static_cast<int>(cmd));
534 tizen_base::Parcel parcel;
535 parcel.WriteParcelable(packet);
537 int ret = socket.Send(parcel.GetData(), parcel.GetDataSize());
539 _E("Failed to send cmd(%d), error(%d)", static_cast<int>(cmd), ret);
542 } catch (const Exception& e) {
543 _E("Exception occrus. error(%s)", e.what());
544 return e.GetErrorCode();
550 } // namespace launchpad