LIB_COMMON_SRCS)
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/launch
LIB_LAUNCH_SRCS)
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/launchpad
+ LIB_LAUNCHPAD_SRCS)
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/lifecycle
LIB_LIFECYCLE_SRCS)
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/pkgmgr_event
${LIB_BOOT_SEQUENCER_SRCS}
${LIB_COMMON_SRCS}
${LIB_LAUNCH_SRCS}
+ ${LIB_LAUNCHPAD_SRCS}
${LIB_LIFECYCLE_SRCS}
${LIB_PKGMGR_EVENT_SRCS}
${LIB_RESTART_MANAGER_SRCS}
INIPARSER_DEPS
LIBSYSTEMD_DEPS
LIBTZPLATFORM_CONFIG_DEPS
+ SECURITY_MANAGER_DEPS
PARCEL_DEPS
PKGMGR_DEPS
PKGMGR_INFO_DEPS
#include "lib/amd_launchpad.h"
-#include <signal.h>
-#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
-#include <gio/gio.h>
-#include <glib.h>
-#include <aul.h>
-#include <aul_sock.h>
#include <bundle_cpp.h>
#include <bundle_internal.h>
-#include <memory>
#include <string>
-#include <unordered_map>
-#include <utility>
-#include <parcel.hh>
-
-#include "lib/amd_config.h"
-#include "lib/amd_login_monitor.h"
#include "lib/amd_socket.h"
-#include "lib/amd_util.h"
-
-#include "lib/common/exception.hh"
-#include "lib/common/log_private.hh"
-#include "lib/socket/client_socket.hh"
-
-namespace {
-
-tizen_base::Parcel CreateParcel(int cmd, int opt, bundle* request) {
- tizen_base::Bundle b(request, false, false);
- auto raw = b.ToRaw();
- int len = raw.second;
- auto* data = reinterpret_cast<const void*>(raw.first.get());
- tizen_base::Parcel parcel;
- parcel.WriteInt32(cmd);
- parcel.WriteInt32(len);
- parcel.WriteInt32(opt | AUL_SOCK_BUNDLE);
- parcel.Write(data, len);
- return parcel;
-}
-
-class ClientChannel : public amd::ClientSocket {
- public:
- class IEvent {
- public:
- virtual ~IEvent() = default;
- virtual void OnResultReceived(unsigned int id, int result) = 0;
- };
-
- ClientChannel(uid_t uid, unsigned int id, launchpad_result_cb cb,
- void* user_data, IEvent* listener)
- : uid_(uid), id_(id), cb_(cb), user_data_(user_data),
- listener_(listener) {
- auto* channel = g_io_channel_unix_new(GetFd());
- if (channel == nullptr) {
- _E("g_io_channel_unix_new() is failed");
- THROW(-ENOMEM);
- }
-
- auto source = g_io_add_watch_full(channel, AMD_PRIORITY_MAX, G_IO_IN,
- OnGIOEvent, this, nullptr);
- if (source == 0) {
- _E("g_io_add_watch() is failed");
- g_io_channel_unref(channel);
- THROW(-EIO);
- }
-
- channel_ = channel;
- source_ = source;
- }
-
- ~ClientChannel() {
- if (channel_)
- g_io_channel_unref(channel_);
-
- if (source_)
- g_source_remove(source_);
- }
-
- uid_t GetUid() const {
- return uid_;
- }
-
- unsigned int GetId() const {
- return id_;
- }
-
- private:
- void Invoke(int result) {
- _D("[LAUNCHPAD] id: %u, result: %d", id_, result);
- cb_(id_, result, user_data_);
- }
-
- static gboolean OnGIOEvent(GIOChannel* channel,
- GIOCondition condition, gpointer user_data) {
- auto* client_channel = static_cast<ClientChannel*>(user_data);
- client_channel->source_ = 0;
- int result = -1;
- int ret = client_channel->Receive(reinterpret_cast<void*>(&result),
- sizeof(result));
- if (ret != 0) {
- _E("Receive() is failed. error(%d), result(%d)", ret, result);
- result = -ECOMM;
- }
-
- client_channel->Invoke(result);
-
- auto* listener = client_channel->listener_;
- listener->OnResultReceived(client_channel->GetId(), result);
- return G_SOURCE_REMOVE;
- }
-
- private:
- uid_t uid_;
- unsigned int id_;
- launchpad_result_cb cb_;
- void* user_data_;
- IEvent* listener_;
- GIOChannel* channel_ = nullptr;
- guint source_ = 0;
-};
-
-class Launchpad : public ClientChannel::IEvent {
- public:
- static Launchpad& GetInst() {
- static Launchpad inst;
- return inst;
- }
-
- int SendRequest(unsigned int id, int cmd, bundle* request, uid_t uid,
- launchpad_result_cb cb, void* data) {
- try {
- auto client_channel =
- std::make_shared<ClientChannel>(uid, id, cb, data, this);
- std::string endpoint = GetEndpoint(uid, LAUNCHPAD_PROCESS_POOL_SOCK);
- client_channel->Connect(endpoint);
- client_channel->SetSendBufferSize(AUL_SOCK_MAXBUFF);
- client_channel->SetReceiveBufferSize(AUL_SOCK_MAXBUFF);
- client_channel->SetReceiveTimeout(5000);
-
- tizen_base::Parcel parcel = CreateParcel(cmd, AUL_SOCK_ASYNC, request);
- int ret = client_channel->Send(parcel.GetData(), parcel.GetDataSize());
- if (ret != 0) {
- _E("Send() is failed. error(%d)", ret);
- return -ECOMM;
- }
-
- channels_[id] = std::move(client_channel);
- } catch (const amd::Exception& e) {
- _E("Exception occurs. error(%s)", e.what());
- return e.GetErrorCode();
- }
-
- return 0;
- }
-
- int Launch(unsigned int id, bundle* request, uid_t uid,
- launchpad_result_cb cb, void* data) {
- return SendRequest(id, PAD_CMD_LAUNCH, request, uid, cb, data);
- }
-
- static std::string GetEndpoint(uid_t uid, const std::string& name) {
- return "/run/aul/daemons/" + std::to_string(uid) + "/" + name;
- }
-
- private:
- Launchpad() = default;
- ~Launchpad() = default;
-
- void OnResultReceived(unsigned int id, int result) override {
- channels_.erase(id);
- }
-
- private:
- std::unordered_map<unsigned int, std::shared_ptr<ClientChannel>> channels_;
-};
-
-int SendAndReceive(bundle* request, uid_t uid, int cmd) {
- int result = -1;
- try {
- auto client = std::make_shared<amd::ClientSocket>();
- std::string endpoint = Launchpad::GetEndpoint(uid,
- LAUNCHPAD_PROCESS_POOL_SOCK);
- client->Connect(endpoint);
- client->SetSendBufferSize(AUL_SOCK_MAXBUFF);
- client->SetReceiveBufferSize(AUL_SOCK_MAXBUFF);
- client->SetReceiveTimeout(5000);
-
- tizen_base::Parcel parcel = CreateParcel(cmd, AUL_SOCK_ASYNC, request);
- int ret = client->Send(parcel.GetData(), parcel.GetDataSize());
- if (ret != 0) {
- _E("Send() is failed. error(%d)", ret);
- return -ECOMM;
- }
-
- ret = client->Receive(reinterpret_cast<void*>(&result), sizeof(result));
- if (ret != 0) {
- _E("Receive() is failed. error(%d)", ret);
- return -ECOMM;
- }
- } catch (const amd::Exception& e) {
- _E("Exception occurs. error(%s)", e.what());
- return -ECOMM;
- }
-
- return result;
-}
-
-} // namespace
+#include "lib/launchpad/launchpad.hh"
int _launchpad_launch_with_result_cb(unsigned int id, bundle* request,
- uid_t uid, launchpad_result_cb callback, void* user_data) {
- return Launchpad::GetInst().Launch(id, request, uid, callback, user_data);
+ uid_t uid, launchpad_result_cb callback,
+ void* user_data) {
+ return amd::Launchpad::GetInst().SendRequest(id, PAD_CMD_LAUNCH, request, uid,
+ callback, user_data);
}
int _launchpad_send_hint(uid_t uid, int hint) {
tizen_base::Bundle b;
- return SendAndReceive(b.GetHandle(), uid, hint);
+ return amd::Launchpad::GetInst().SendAndReceive(hint, b.GetHandle(), uid);
}
int _launchpad_send_request_with_result_cb(unsigned int id, int cmd,
bundle* request, uid_t uid,
launchpad_result_cb callback,
void* user_data) {
- return Launchpad::GetInst().SendRequest(id, cmd, request, uid, callback,
- user_data);
+ return amd::Launchpad::GetInst().SendRequest(id, cmd, request, uid, callback,
+ user_data);
}
#include "lib/common/cpu_boost_controller.hh"
#include "lib/common/exception.hh"
+#include "lib/launchpad/launchpad.hh"
#include "lib/res_info/res_info_manager.hh"
typedef int (*amd_mod_init_func)(void);
_comp_status_init();
_app_com_broker_init();
_boot_manager_init();
+ amd::Launchpad::GetInst().Init();
_launch_init();
_suspend_init();
_app_property_init();
_login_monitor_fini();
_app_property_fini();
_suspend_fini();
+ amd::Launchpad::GetInst().Dispose();
_boot_manager_fini();
_app_com_broker_fini();
_comp_status_fini();
#include <sys/un.h>
#include <bundle.h>
+#include "lib/api/amd_api_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
#define LAUNCHPAD_PROCESS_POOL_SOCK ".launchpad-process-pool-sock"
-#define PAD_CMD_LAUNCH 0
-
-#define PAD_CMD_VISIBILITY 10
-
-#define PAD_CMD_ADD_LOADER 11
-
-#define PAD_CMD_REMOVE_LOADER 12
-
-#define PAD_CMD_MAKE_DEFAULT_SLOTS 13
-
-#define PAD_CMD_DEMAND 14
-
-#define PAD_CMD_PING 15
-
-#define PAD_CMD_UPDATE_APP_TYPE 16
-
-#define PAD_CMD_CONNECT 18
-
int _create_sock_activation(void);
int _create_server_sock(void);
#include <bundle.h>
#include <stdbool.h>
#include <sys/types.h>
+#include <amd_api_types.h>
#ifdef __cplusplus
extern "C" {
#endif
-typedef enum {
- PAD_CMD_PREPARE_APP_DEFINED_LOADER = 17,
-} pad_cmd_e;
-
void amd_socket_send_result(int fd, int res, bool close);
int amd_socket_send_cmd_to_launchpad(uid_t uid, pad_cmd_e cmd, bundle *b);
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AMD_API_TYPES_H__
+#define __AMD_API_TYPES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ PAD_CMD_LAUNCH = 0,
+ PAD_CMD_VISIBILITY = 10,
+ PAD_CMD_ADD_LOADER = 11,
+ PAD_CMD_REMOVE_LOADER = 12,
+ PAD_CMD_MAKE_DEFAULT_SLOTS = 13,
+ PAD_CMD_DEMAND = 14,
+ PAD_CMD_PING = 15,
+ PAD_CMD_UPDATE_APP_TYPE = 16,
+ PAD_CMD_PREPARE_APP_DEFINED_LOADER = 17,
+ PAD_CMD_CONNECT = 18,
+ PAD_CMD_KILL_LOADER = 19,
+ PAD_CMD_RESTART_LOADER = 20,
+ PAD_CMD_DISPOSE_LOADER = 21,
+ PAD_CMD_LISTEN_SIGCHLD = 22,
+} pad_cmd_e;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AMD_API_TYPES_H__ */
if (!is.is_open())
return -1;
- std::string key;
- pid_t ppid;
- while (is >> key >> ppid) {
- if (key == "PPid:") {
- is.close();
- return ppid;
+ std::string line;
+ while (std::getline(is, line)) {
+ if (line.find("PPid:") == 0) {
+ std::string ppid_str = line.substr(6);
+ return std::stoi(ppid_str);
}
}
handle, amd_inotify_rm_watch);
}
+ Launchpad::GetInst().ListenSigchld(uid, this);
return 0;
}
else
_D("Watch fd doesn't exist - uid(%d)", uid);
+ Launchpad::GetInst().IgnoreSigchld();
auto iter = app_status_list_.begin();
while (iter != app_status_list_.end()) {
auto app_status = *iter;
}
void AppStatusManager::AppDeadHandler(int pid, int status, void* data) {
- if (pid <= 0)
- return;
-
- auto app_status = GetInst().Find(pid);
- if (app_status == nullptr)
- return;
-
- _E("APP_DEAD_SIGNAL appid(%s), pid(%d), status(%d)",
- app_status->GetAppID().c_str(), pid, status);
-
- uid_t uid = app_status->GetUID();
- std::string appid = app_status->GetAppID();
- _noti_send(AMD_NOTI_MSG_MAIN_APP_DEAD, pid, uid, app_status.get(), nullptr);
- _request_flush_pending_request(pid);
- GetInst().CleanUp(std::move(app_status));
- int crash_count = 0;
- if (IsCrashStatus(status)) {
- _E("pid(%d) is crashed by signal(%d)", pid, WTERMSIG(status));
- crash_count = ++GetInst().crash_count_map_[uid][appid];
- } else {
- GetInst().crash_count_map_[uid].erase(appid);
- }
-
- if (crash_count < kMaxCrashCount) {
- _restart_manager_restart_app(uid, appid.c_str());
- } else {
- _E("%s has been crashed %d times in a row", appid.c_str(), crash_count);
- GetInst().crash_count_map_[uid].erase(appid);
- }
-
- _util_save_log("TERMINATED", std::to_string(pid).c_str());
+ _E("pid(%d), status(%d)", pid, status);
}
void AppStatusManager::LoadAppStatusFromDB(uid_t uid) {
return 0;
}
+void AppStatusManager::OnSigchldEvent(pid_t pid, int status) {
+ if (pid <= 0)
+ return;
+
+ auto app_status = Find(pid);
+ if (app_status == nullptr) return;
+
+ _E("appid(%s), pid(%d), status(%d)",
+ app_status->GetAppID().c_str(), pid, status);
+
+ uid_t uid = app_status->GetUID();
+ std::string appid = app_status->GetAppID();
+ _noti_send(AMD_NOTI_MSG_MAIN_APP_DEAD, pid, uid, app_status.get(), nullptr);
+ _request_flush_pending_request(pid);
+ GetInst().CleanUp(std::move(app_status));
+ int crash_count = 0;
+ if (IsCrashStatus(status)) {
+ _E("pid(%d) is crashed by signal(%d)", pid, WTERMSIG(status));
+ crash_count = ++GetInst().crash_count_map_[uid][appid];
+ } else {
+ GetInst().crash_count_map_[uid].erase(appid);
+ }
+
+ if (crash_count < kMaxCrashCount) {
+ _restart_manager_restart_app(uid, appid.c_str());
+ } else {
+ _E("%s has been crashed %d times in a row", appid.c_str(), crash_count);
+ GetInst().crash_count_map_[uid].erase(appid);
+ }
+
+ _util_save_log("TERMINATED", std::to_string(pid).c_str());
+}
+
void AppStatusManager::AddSignalReadyCb() {
_signal_add_ready_cb(
[](void* data) -> int {
#include "lib/app_status/app_status.hh"
#include "lib/app_status/app_status_dao.hh"
#include "lib/app_status/pkg_status.hh"
+#include "lib/launchpad/launchpad.hh"
#include "lib/launch/launch_context.hh"
namespace amd {
using AppStatusPtr = std::shared_ptr<AppStatus>;
-class AppStatusManager : public AppStatus::IEvent {
+class AppStatusManager : public AppStatus::IEvent, public Launchpad::IEvent {
using ForeachCb = std::function<void(AppStatus*, void*)>;
public:
static int OnLaunchPrepareEnd(const char *msg, pid_t pid, int uid,
void* arg3, bundle* data);
+ void OnSigchldEvent(pid_t pid, int status) override;
+
private:
static constexpr int kMaxCrashCount = 3;
bool disposed_ = true;
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "lib/launchpad/client_channel.hh"
+
+#include <glib.h>
+#include <glib-unix.h>
+
+#include <memory>
+#include <string>
+
+#include "lib/amd_util.h"
+#include "lib/common/log_private.hh"
+
+namespace amd {
+
+ClientChannel::ClientChannel(IEvent* listener) : listener_(listener) {
+ source_ = g_unix_fd_add_full(AMD_PRIORITY_MAX, GetFd(), G_IO_IN, OnGIOEvent,
+ this, nullptr);
+ if (source_ == 0) {
+ _E("g_unix_fd_add_full() is failed");
+ THROW(-ENOMEM);
+ }
+}
+
+ClientChannel::~ClientChannel() {
+ if (source_) g_source_remove(source_);
+}
+
+void ClientChannel::SetExtraData(void* extra_data) { extra_data_ = extra_data; }
+
+void* ClientChannel::GetExtraData() const { return extra_data_; }
+
+gboolean ClientChannel::OnGIOEvent(gint fd, GIOCondition condition,
+ gpointer user_data) {
+ auto* client_channel = static_cast<ClientChannel*>(user_data);
+ client_channel->source_ = 0;
+ int result = -1;
+ int ret =
+ client_channel->Receive(reinterpret_cast<void*>(&result), sizeof(result));
+ if (ret != 0) {
+ _E("Receive() is failed. error(%d), result(%d)", ret, result);
+ result = -ECOMM;
+ }
+
+ auto* listener = client_channel->listener_;
+ listener->OnResultReceived(fd, result);
+ return G_SOURCE_REMOVE;
+}
+
+} // namespace amd
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIB_LAUNCHPAD_CLIENT_CHANNEL_HH_
+#define LIB_LAUNCHPAD_CLIENT_CHANNEL_HH_
+
+#include <glib.h>
+#include <glib-unix.h>
+
+#include <memory>
+#include <string>
+
+#include "lib/socket/client_socket.hh"
+
+namespace amd {
+
+class ClientChannel : public ClientSocket {
+ public:
+ class IEvent {
+ public:
+ virtual ~IEvent() = default;
+ virtual void OnResultReceived(int fd, int result) = 0;
+ };
+
+ explicit ClientChannel(IEvent* listener);
+ ~ClientChannel();
+
+ void SetExtraData(void* extra_data);
+ void* GetExtraData() const;
+
+ private:
+ static gboolean OnGIOEvent(gint fd, GIOCondition condition,
+ gpointer user_data);
+
+ private:
+ IEvent* listener_;
+ guint source_ = 0;
+ void* extra_data_ = nullptr;
+};
+
+} // namespace amd
+
+#endif // LIB_LAUNCHPAD_CLIENT_CHANNEL_HH_
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "lib/launchpad/launchpad.hh"
+
+#include <aul.h>
+#include <aul_sock.h>
+#include <bundle_cpp.h>
+#include <security-manager.h>
+
+#include <filesystem>
+#include <fstream>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <parcel.hh>
+
+#include "lib/amd_socket.h"
+#include "lib/app_status/app_status_manager.hh"
+#include "lib/common/exception.hh"
+#include "lib/common/log_private.hh"
+#include "lib/signal/dbus_broker.hh"
+
+namespace amd {
+namespace {
+namespace fs = std::filesystem;
+
+constexpr const char AUL_DBUS_PATH[] = "/aul/dbus_handler";
+constexpr const char AUL_DBUS_SIGNAL_INTERFACE[] = "org.tizen.aul.signal";
+constexpr const char AUL_DBUS_APPDEAD_SIGNAL[] = "app_dead";
+constexpr const char AUL_DBUS_APPLAUNCH_SIGNAL[] = "app_launch";
+
+class GarbageCollector : public Worker::Job {
+ public:
+ GarbageCollector(pid_t pid, uid_t uid, std::string appid)
+ : pid_(pid), uid_(uid), appid_(std::move(appid)) {}
+
+ void Do() override {
+ _D("pid=%d, appid=%s", pid_, appid_.c_str());
+ try {
+ std::string path =
+ "/run/aul/apps/" + std::to_string(uid_) + "/" + std::to_string(pid_);
+ DeleteSocketPath(fs::path(path));
+
+ DeleteUnusedFiles();
+ SocketGarbadgeCollector();
+ } catch (const std::filesystem::filesystem_error& e) {
+ _E("Exception occurs. error(%s:%d)", e.what(), e.code().value());
+ }
+
+ _W("security_manager_cleanup_app() ++ %s(%d)", appid_.c_str(), pid_);
+ security_manager_cleanup_app(appid_.c_str(), uid_, pid_);
+ _W("security_manager_cleanup_app() -- %s(%d)", appid_.c_str(), pid_);
+ }
+
+ private:
+ void DeleteSocketPath(const fs::path& path) {
+ try {
+ fs::remove_all(path);
+ } catch (const fs::filesystem_error& e) {
+ _E("Exception occurs. error(%s)", e.what());
+ }
+ }
+
+ void SocketGarbadgeCollector() {
+ std::string path = "/run/aul/apps/" + std::to_string(uid_);
+ for (const auto& entry : fs::directory_iterator(path)) {
+ if (!isdigit(entry.path().filename().string()[0])) continue;
+
+ std::string proc_path = "/proc/" + entry.path().filename().string();
+ if (!fs::exists(proc_path)) DeleteSocketPath(entry.path());
+ }
+ }
+
+ void DeleteUnusedFiles() {
+ DeleteMCJFile();
+ DeleteTmpFiles();
+ }
+
+ void DeleteMCJFile() {
+ std::string path = "/tmp/.dotnet/mcj/MCJ.TMP." + std::to_string(pid_);
+ if (access(path.c_str(), F_OK) == 0) {
+ _W("Remove file: %s", path.c_str());
+ fs::remove(path);
+ }
+ }
+
+ void DeleteTmpFiles() {
+ std::vector<std::string> files = {
+ "clr-debug-pipe-" + std::to_string(pid_) + "-",
+ "dotnet-diagnostic-" + std::to_string(pid_) + "-"};
+
+ fs::path tmp_path = "/tmp";
+ for (const auto& entry : fs::directory_iterator(tmp_path)) {
+ if (entry.is_directory() || entry.path().filename().string()[0] == '.')
+ continue;
+
+ bool found = false;
+ for (const auto& file : files) {
+ if (entry.path().filename().string().find(file) == 0) {
+ fs::remove(entry.path());
+ _W("Removed file: %s", entry.path().c_str());
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) continue;
+ }
+ }
+
+ private:
+ pid_t pid_;
+ uid_t uid_;
+ std::string appid_;
+};
+
+class ResultCb {
+ public:
+ ResultCb(unsigned int id, int cmd, std::string appid, launchpad_result_cb cb,
+ void* user_data)
+ : id_(id),
+ cmd_(cmd),
+ appid_(std::move(appid)),
+ cb_(cb),
+ user_data_(user_data) {}
+
+ void Invoke(int result) {
+ if (cb_) cb_(id_, result, user_data_);
+ }
+
+ int GetCmd() const { return cmd_; }
+
+ const std::string& GetAppId() const { return appid_; }
+
+ private:
+ unsigned int id_;
+ int cmd_;
+ std::string appid_;
+ launchpad_result_cb cb_;
+ void* user_data_;
+};
+
+std::string GetEndpoint(uid_t uid, const std::string& name) {
+ return "/run/aul/daemons/" + std::to_string(uid) + "/" + name;
+}
+
+tizen_base::Parcel CreateParcel(int cmd, int opt, bundle* request) {
+ tizen_base::Bundle b(request, false, false);
+ auto raw = b.ToRaw();
+ int len = raw.second;
+ auto* data = reinterpret_cast<const void*>(raw.first.get());
+ tizen_base::Parcel parcel;
+ parcel.WriteInt32(cmd);
+ parcel.WriteInt32(len);
+ parcel.WriteInt32(opt | AUL_SOCK_BUNDLE);
+ parcel.Write(data, len);
+ return parcel;
+}
+
+} // namespace
+
+Launchpad::Launchpad() = default;
+
+Launchpad::~Launchpad() { Dispose(); }
+
+Launchpad& Launchpad::GetInst() {
+ static Launchpad inst;
+ return inst;
+}
+
+void Launchpad::Init() {
+ if (!disposed_) return;
+
+ try {
+ garbage_collector_.reset(new Worker("LaunchpadGC+"));
+ } catch (const Exception& e) {
+ _E("Exception occurs. error=%s", e.what());
+ return;
+ }
+
+ disposed_ = false;
+}
+
+void Launchpad::Dispose() {
+ if (disposed_) return;
+
+ IgnoreSigchld();
+ garbage_collector_.reset();
+ disposed_ = true;
+}
+
+int Launchpad::SendRequest(unsigned int id, int cmd, bundle* request, uid_t uid,
+ launchpad_result_cb cb, void* user_data) {
+ try {
+ auto client_channel = std::make_shared<ClientChannel>(this);
+ std::string endpoint = GetEndpoint(uid, LAUNCHPAD_PROCESS_POOL_SOCK);
+ client_channel->Connect(endpoint);
+ client_channel->SetSendBufferSize(AUL_SOCK_MAXBUFF);
+ client_channel->SetReceiveBufferSize(AUL_SOCK_MAXBUFF);
+ client_channel->SetReceiveTimeout(5000);
+
+ tizen_base::Parcel parcel = CreateParcel(cmd, AUL_SOCK_ASYNC, request);
+ int ret = client_channel->Send(parcel.GetData(), parcel.GetDataSize());
+ if (ret != 0) {
+ _E("Send() is failed. error(%d)", ret);
+ return -ECOMM;
+ }
+
+ auto* appid = bundle_get_val(request, AUL_K_APPID);
+ if (appid == nullptr) appid = "";
+
+ client_channel->SetExtraData(new ResultCb(id, cmd, appid, cb, user_data));
+ int fd = client_channel->GetFd();
+ channels_[fd] = std::move(client_channel);
+ } catch (const Exception& e) {
+ _E("Exception occurs. error(%s)", e.what());
+ return e.GetErrorCode();
+ }
+
+ return 0;
+}
+
+int Launchpad::SendAndReceive(int cmd, bundle* request, uid_t uid) {
+ int result = -1;
+ try {
+ auto client = std::make_shared<ClientSocket>();
+ std::string endpoint = GetEndpoint(uid, LAUNCHPAD_PROCESS_POOL_SOCK);
+ client->Connect(endpoint);
+ client->SetSendBufferSize(AUL_SOCK_MAXBUFF);
+ client->SetReceiveBufferSize(AUL_SOCK_MAXBUFF);
+ client->SetReceiveTimeout(5000);
+
+ tizen_base::Parcel parcel = CreateParcel(cmd, AUL_SOCK_ASYNC, request);
+ int ret = client->Send(parcel.GetData(), parcel.GetDataSize());
+ if (ret != 0) {
+ _E("Send() is failed. error(%d)", ret);
+ return -ECOMM;
+ }
+
+ ret = client->Receive(reinterpret_cast<void*>(&result), sizeof(result));
+ if (ret != 0) {
+ _E("Receive() is failed. error(%d)", ret);
+ return -ECOMM;
+ }
+ } catch (const Exception& e) {
+ _E("Exception occurs. error(%s)", e.what());
+ return -ECOMM;
+ }
+
+ return result;
+}
+
+bool Launchpad::ListenSigchld() {
+ try {
+ sigchld_socket_.reset(new ClientSocket());
+ std::string endpoint = GetEndpoint(uid_, LAUNCHPAD_PROCESS_POOL_SOCK);
+ sigchld_socket_->Connect(endpoint);
+ sigchld_socket_->SetSendBufferSize(AUL_SOCK_MAXBUFF);
+ sigchld_socket_->SetReceiveBufferSize(AUL_SOCK_MAXBUFF);
+ sigchld_socket_->SetReceiveTimeout(5000);
+
+ tizen_base::Bundle envelope;
+ tizen_base::Parcel parcel = CreateParcel(
+ PAD_CMD_LISTEN_SIGCHLD, AUL_SOCK_ASYNC, envelope.GetHandle());
+ int ret = sigchld_socket_->Send(parcel.GetData(), parcel.GetDataSize());
+ if (ret != 0) {
+ _E("Send() is failed. error=%d", ret);
+ return false;
+ }
+
+ sigchld_source_ =
+ g_unix_fd_add(sigchld_socket_->GetFd(), G_IO_IN, UnixFdFunc, this);
+ if (sigchld_source_ == 0) _E("g_unix_fd_add() is failed");
+ } catch (const Exception& e) {
+ _E("Exception occurs. error=%s", e.what());
+ return false;
+ }
+ return true;
+}
+
+gboolean Launchpad::RetryFunc(gpointer user_data) {
+ auto* self = static_cast<Launchpad*>(user_data);
+ if (!self->ListenSigchld()) return G_SOURCE_CONTINUE;
+
+ self->retry_source_ = 0;
+ return G_SOURCE_REMOVE;
+}
+
+void Launchpad::ListenSigchld(uid_t uid, IEvent* listener) {
+ uid_ = uid;
+ listener_ = listener;
+ if (sigchld_source_ != 0) return;
+
+ if (!ListenSigchld()) {
+ if (retry_source_) g_source_remove(retry_source_);
+
+ retry_source_ = g_timeout_add(100, RetryFunc, this);
+ }
+}
+
+void Launchpad::IgnoreSigchld() {
+ if (retry_source_) {
+ g_source_remove(retry_source_);
+ retry_source_ = 0;
+ }
+
+ if (sigchld_source_) {
+ g_source_remove(sigchld_source_);
+ sigchld_source_ = 0;
+ }
+
+ sigchld_socket_.reset();
+ listener_ = nullptr;
+}
+
+void Launchpad::SendAppLaunchSignal(pid_t pid, const std::string& appid) {
+ std::string log_message = "[AppLaunch] " + std::to_string(pid) + ":" + appid;
+ DBusBroker::GetInst().SendSignal(std::make_shared<DBusRequest>(
+ AUL_DBUS_PATH, AUL_DBUS_SIGNAL_INTERFACE, AUL_DBUS_APPLAUNCH_SIGNAL,
+ std::move(log_message), g_variant_new("(us)", pid, appid.c_str())));
+}
+
+void Launchpad::SendAppDeadSignal(pid_t pid, int status) {
+ std::string log_message =
+ "[AppDead] " + std::to_string(pid) + ":" + std::to_string(status);
+ DBusBroker::GetInst().SendSignal(std::make_shared<DBusRequest>(
+ AUL_DBUS_PATH, AUL_DBUS_SIGNAL_INTERFACE, AUL_DBUS_APPDEAD_SIGNAL,
+ std::move(log_message), g_variant_new("(ii)", pid, status)));
+}
+
+void Launchpad::OnResultReceived(int fd, int result) {
+ auto found = channels_.find(fd);
+ if (found == channels_.end()) return;
+
+ auto client_channel = found->second;
+ auto* result_cb = static_cast<ResultCb*>(client_channel->GetExtraData());
+ if (result_cb) {
+ if (result_cb->GetCmd() == PAD_CMD_LAUNCH)
+ SendAppLaunchSignal(result, result_cb->GetAppId());
+ result_cb->Invoke(result);
+ delete result_cb;
+ }
+ channels_.erase(found);
+}
+
+void Launchpad::HandleSigchldEvent() {
+ size_t data_size = 0;
+ int ret = sigchld_socket_->Receive(static_cast<void*>(&data_size),
+ sizeof(data_size));
+ if (ret != 0) {
+ _E("Receive() is failed. error=%d", ret);
+ return;
+ }
+
+ std::vector<uint8_t> data(data_size);
+ ret = sigchld_socket_->Receive(data.data(), data_size);
+ if (ret != 0) {
+ _E("Receive() is failed. error=%d", ret);
+ return;
+ }
+
+ tizen_base::Parcel parcel(data.data(), data.size());
+ pid_t pid = -1;
+ parcel.ReadInt32(&pid);
+ int status = 0;
+ parcel.ReadInt32(&status);
+ _W("[SIGCHLD] pid=%d, status=%d", pid, status);
+
+ auto app_status = AppStatusManager::GetInst().Find(pid);
+ if (app_status) {
+ SendAppDeadSignal(pid, status);
+ garbage_collector_->Post(std::make_shared<GarbageCollector>(
+ pid, app_status->GetUID(), app_status->GetAppID()));
+ }
+
+ if (listener_) listener_->OnSigchldEvent(pid, status);
+}
+
+gboolean Launchpad::UnixFdFunc(gint fd, GIOCondition cond, gpointer user_data) {
+ _D("fd=%d, cond=%d", fd, static_cast<int>(cond));
+ auto* self = static_cast<Launchpad*>(user_data);
+ self->HandleSigchldEvent();
+ return G_SOURCE_CONTINUE;
+}
+
+} // namespace amd
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIB_LAUNCHPAD_LAUNCHPAD_HH_
+#define LIB_LAUNCHPAD_LAUNCHPAD_HH_
+
+#include <glib.h>
+#include <glib-unix.h>
+#include <bundle.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "lib/amd_launchpad.h"
+#include "lib/launchpad/client_channel.hh"
+#include "lib/launchpad/worker.hh"
+
+namespace amd {
+
+class Launchpad : public ClientChannel::IEvent {
+ public:
+ class IEvent {
+ public:
+ virtual ~IEvent() = default;
+ virtual void OnSigchldEvent(pid_t pid, int status) = 0;
+ };
+
+ Launchpad(const Launchpad&) = delete;
+ Launchpad& operator=(const Launchpad&) = delete;
+ Launchpad(Launchpad&&) = delete;
+ Launchpad& operator=(Launchpad&&) = delete;
+
+ static Launchpad& GetInst();
+
+ void Init();
+ void Dispose();
+ int SendRequest(unsigned int id, int cmd, bundle* request, uid_t uid,
+ launchpad_result_cb cb, void* user_data);
+ int SendAndReceive(int cmd, bundle* request, uid_t uid);
+ void ListenSigchld(uid_t uid, IEvent* listener);
+ void IgnoreSigchld();
+
+ private:
+ Launchpad();
+ ~Launchpad();
+
+ void SendAppLaunchSignal(pid_t pid, const std::string& appid);
+ void SendAppDeadSignal(pid_t pid, int status);
+ void OnResultReceived(int fd, int result) override;
+ void HandleSigchldEvent();
+ bool ListenSigchld();
+ static gboolean UnixFdFunc(gint fd, GIOCondition cond, gpointer user_data);
+ static gboolean RetryFunc(gpointer user_data);
+
+ private:
+ bool disposed_ = true;
+ std::unique_ptr<Worker> garbage_collector_;
+ std::unordered_map<int, std::shared_ptr<ClientChannel>> channels_;
+ std::unique_ptr<ClientSocket> sigchld_socket_{nullptr};
+ guint sigchld_source_ = 0;
+ uid_t uid_ = 0;
+ IEvent* listener_ = nullptr;
+ guint retry_source_ = 0;
+};
+
+} // namespace amd
+
+#endif // LIB_LAUNCHPAD_LAUNCHPAD_HH_
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "lib/launchpad/worker.hh"
+
+#include <utility>
+
+#include "lib/common/exception.hh"
+#include "lib/common/log_private.hh"
+
+namespace amd {
+
+Worker::Worker(std::string name) : name_(std::move(name)) {
+ int ret = tizen_core_task_create(name_.c_str(), true, &task_);
+ if (ret != TIZEN_CORE_ERROR_NONE) {
+ _E("tizen_core_task_create() is failed. error=%d", ret);
+ THROW(ret);
+ }
+
+ tizen_core_task_get_tizen_core(task_, &core_);
+ tizen_core_task_run(task_);
+}
+
+Worker::~Worker() {
+ bool running = false;
+ tizen_core_task_is_running(task_, &running);
+ if (running) tizen_core_task_quit(task_);
+
+ tizen_core_task_destroy(task_);
+}
+
+
+void Worker::Post(std::shared_ptr<Job> job) {
+ queue_.Push(std::move(job));
+ tizen_core_source_h source = nullptr;
+ tizen_core_add_idle_job(core_, JobCb, this, &source);
+ if (source == nullptr) _E("Failed to add idle job");
+}
+
+bool Worker::JobCb(void* user_data) {
+ auto* worker = static_cast<Worker*>(user_data);
+ while (!worker->queue_.IsEmpty()) {
+ auto job = worker->queue_.WaitAndPop();
+ if (job) job->Do();
+ }
+
+ return false;
+}
+
+} // namespace amd
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIB_LAUNCHPAD_WORKER_HH_
+#define LIB_LAUNCHPAD_WORKER_HH_
+
+#include <tizen_core.h>
+
+#include <memory>
+#include <string>
+
+#include <shared-queue.hpp>
+
+namespace amd {
+
+class Worker {
+ public:
+ class Job {
+ public:
+ virtual ~Job() = default;
+ virtual void Do() {}
+ };
+
+ explicit Worker(std::string name);
+ virtual ~Worker();
+
+ void Post(std::shared_ptr<Job> job);
+ private:
+ static bool JobCb(void* user_data);
+
+ private:
+ std::string name_;
+ tizen_core_task_h task_ = nullptr;
+ tizen_core_h core_ = nullptr;
+ tizen_base::SharedQueue<std::shared_ptr<Job>> queue_;
+};
+
+} // namespace amd
+
+#endif // LIB_LAUNCHPAD_WORKER_HH_
\ No newline at end of file