The launchpad library is impemented using C++ language.
Change-Id: I191aca9713f8771806a2516374d0710185ab9993
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
#include "launchpad-process-pool/config.hh"
#include "launchpad-process-pool/dbus.hh"
#include "launchpad-process-pool/debug.hh"
-#include "launchpad-process-pool/language_config.hh"
#include "launchpad-process-pool/launcher_info.hh"
#include "launchpad-process-pool/launchpad_args.hh"
#include "launchpad-process-pool/loader_manager.hh"
#include "launchpad-process-pool/loader_executor.hh"
#include "launchpad-process-pool/log.hh"
#include "launchpad-process-pool/memory_monitor.hh"
-#include "launchpad-process-pool/region_format_config.hh"
#include "launchpad-process-pool/signal_manager.hh"
#include "launchpad-process-pool/tracer.hh"
#include "launchpad-process-pool/user_tracer.hh"
#include <unordered_map>
#include <vector>
+#include <language_config.hh>
#include <io_channel.hh>
+#include <region_format_config.hh>
#include <server_socket.hh>
#include "launchpad-process-pool/app_executor.hh"
-#include "launchpad-process-pool/language_config.hh"
-#include "launchpad-process-pool/region_format_config.hh"
#include "launchpad-process-pool/request.hh"
#include "launchpad-process-pool/signal_manager.hh"
#include "launchpad-process-pool/loader_manager.hh"
return 0;
}
-int SendAppPacket(ClientSocket* client_socket, app_pkt_t *app_packet) {
- if (client_socket == nullptr || app_packet == nullptr) {
- _E("Invalid parameter");
- return -EINVAL;
- }
-
- const size_t size = sizeof(app_packet->cmd) + sizeof(app_packet->opt) +
- sizeof(app_packet->len) + app_packet->len;
- return client_socket->Send(static_cast<void*>(app_packet), size);
-}
-
} // namespace
LoaderContext::Builder& LoaderContext::Builder::SetLoaderInfo(
pid_t LoaderContext::Deploy(const AppInfo* app_info, app_pkt_t* app_packet) {
Util::DeleteSocketPath(pid_, getuid());
- int ret = SendAppPacket(client_socket_.get(), app_packet);
+ tizen_base::Parcel parcel;
+ parcel.WriteParcelable(*app_info);
+ size_t data_size = parcel.GetDataSize();
+ int ret = client_socket_->Send(static_cast<void*>(&data_size),
+ sizeof(data_size));
+ if (ret != 0) {
+ _E("Failed to send request. pid(%d)", pid_);
+ return ret;
+ }
+
+ ret = client_socket_->Send(parcel.GetData(), data_size);
if (ret != 0) {
- _E("Failed to send request to the loader. pid(%d)", pid_);
+ _E("Failed to send request. pid(%d)", pid_);
return ret;
}
namespace launchpad {
-void SchedPriority::Set(int priority) {
+int SchedPriority::Set(int priority) {
int ret = setpriority(PRIO_PGRP, 0, priority);
if (ret != 0) {
_E("Failed to set process priority. priority(%d), errno(%d)",
} else {
_D("Setting priority(%d) is sucessful", priority);
}
+
+ return ret;
}
int SchedPriority::Get() {
class EXPORT_API SchedPriority {
public:
- static void Set(int priority);
+ static int Set(int priority);
static int Get();
};
* limitations under the License.
*/
-#include "launchpad-process-pool/language_config.hh"
+#include "launchpad-glib/language_config.hh"
#include <stdlib.h>
-#include "launchpad-process-pool/log_private.hh"
+#include "launchpad-glib/log_private.hh"
namespace launchpad {
* limitations under the License.
*/
-#ifndef LAUNCHPAD_PROCESS_POOL_LANGUAGE_CONFIG_HH_
-#define LAUNCHPAD_PROCESS_POOL_LANGUAGE_CONFIG_HH_
+#ifndef LIB_LAUNCHPAD_GLIB_LANGUAGE_CONFIG_HH_
+#define LIB_LAUNCHPAD_GLIB_LANGUAGE_CONFIG_HH_
#include <string>
} // namespace launchpad
-#endif // LAUNCHPAD_PROCESS_POOL_LANGUAGE_CONFIG_HH_
+#endif // LIB_LAUNCHPAD_GLIB_LANGUAGE_CONFIG_HH_
* limitations under the License.
*/
-#include "launchpad-process-pool/region_format_config.hh"
+#include "launchpad-glib/region_format_config.hh"
#include <stdlib.h>
-#include "launchpad-process-pool/log_private.hh"
+#include "launchpad-glib/log_private.hh"
namespace launchpad {
* limitations under the License.
*/
-#ifndef LAUNCHPAD_PROCESS_POOL_REGION_FORMAT_CONFIG_HH_
-#define LAUNCHPAD_PROCESS_POOL_REGION_FORMAT_CONFIG_HH_
+#ifndef LIB_LAUNCHPAD_GLIB_REGION_FORMAT_CONFIG_HH_
+#define LIB_LAUNCHPAD_GLIB_REGION_FORMAT_CONFIG_HH_
#include <string>
#include <vconf.hh>
+#undef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+
namespace launchpad {
-class RegionFormatConfig : public Vconf::IEvent {
+class EXPORT_API RegionFormatConfig : public Vconf::IEvent {
public:
RegionFormatConfig();
} // namespace launchpad
-#endif // LAUNCHPAD_PROCESS_POOL_REGION_FORMAT_CONFIG_HH_
+#endif // LIB_LAUNCHPAD_GLIB_REGION_FORMAT_CONFIG_HH_
-AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src LAUNCHPAD_SRCS)
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} LAUNCHPAD_SRCS)
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../common/src LIB_COMMON_SRCS)
ADD_LIBRARY(${TARGET_LAUNCHPAD} SHARED
${LAUNCHPAD_SRCS}
${LIB_COMMON_SRCS})
+
SET_TARGET_PROPERTIES(${TARGET_LAUNCHPAD} PROPERTIES SOVERSION ${MAJORVER})
SET_TARGET_PROPERTIES(${TARGET_LAUNCHPAD} PROPERTIES VERSION ${VERSION})
TANCHOR_DEPS
)
-TARGET_LINK_LIBRARIES(${TARGET_LAUNCHPAD} PUBLIC "-ldl")
+TARGET_LINK_LIBRARIES(${TARGET_LAUNCHPAD} PUBLIC
+ ${TARGET_LAUNCHPAD_COMMON} ${TARGET_LAUNCHPAD_GLIB} "-ldl")
INSTALL(TARGETS ${TARGET_LAUNCHPAD} DESTINATION ${LIB_INSTALL_DIR}
COMPONENT RuntimeLibraries)
--- /dev/null
+/*
+ * Copyright (c) 2023 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 "launchpad/launchpad_loader.hh"
+
+#include <aul.h>
+#include <bundle_cpp.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <app_info.hh>
+#include <client_socket.hh>
+#include <exception.hh>
+#include <parcel.hh>
+#include <sched_priority.hh>
+#include <socket.hh>
+#include <util.hh>
+
+#include "common/inc/launchpad_common.h"
+#include "common/inc/launchpad_types.h"
+#include "launchpad/log_private.hh"
+#include "launchpad/step_prepare_execution.hh"
+#include "launchpad/thread_control.hh"
+
+namespace launchpad {
+namespace {
+
+const uint32_t kMaxRetryingCount = 600;
+constexpr const char kLaunchpadLoaderSocketName[] = ".launchpad-type";
+
+tizen_base::Bundle loader_bundle;
+std::unique_ptr<LaunchpadLoader> context;
+
+} // namespace
+
+LaunchpadLoader::LaunchpadLoader(int argc, char** argv)
+ : argc_(argc), argv_(argv) {
+ if (argc_ < 4) {
+ _E("Too few argument");
+ THROW(-EINVAL);
+ }
+
+ int is_hydra = argv_[LOADER_ARG_HYDRA][0] - '0';
+ if (is_hydra) {
+ _E("Cannot run in hydra mode");
+ THROW(-EINVAL);
+ }
+
+ loader_type_ = atoi(argv_[LOADER_ARG_TYPE]);
+ if (loader_type_ < 0 || loader_type_ >= LAUNCHPAD_TYPE_MAX) {
+ _E("Invalid argument. type: %d", loader_type_);
+ THROW(-EINVAL);
+ }
+
+ loader_id_ = atoi(argv_[LOADER_ARG_ID]);
+ _W("loader type: %d, loader id: %d", loader_type_, loader_id_);
+ context.reset(this);
+}
+
+LaunchpadLoader::~LaunchpadLoader() {
+ if (app_argv_ != nullptr) {
+ for (int i = 0; i < app_argc_; ++i)
+ free(app_argv_[i]);
+
+ free(app_argv_);
+ }
+}
+
+void LaunchpadLoader::Run(loader_lifecycle_callback_s* callback,
+ loader_adapter_s* adapter, void* user_data) {
+ if (callback == nullptr || adapter == nullptr) {
+ _E("Invalid argument");
+ THROW(-EINVAL);
+ }
+
+ if (adapter->loop_begin == nullptr || adapter->loop_quit == nullptr ||
+ adapter->add_fd == nullptr || adapter->remove_fd == nullptr) {
+ _E("Invalid argument. adapter callback is nullptr");
+ THROW(-EINVAL);
+ }
+
+ callback_ = *callback;
+ adapter_callback_ = *adapter;
+ user_data_ = user_data;
+
+ if (!OnCreate()) {
+ _E("OnCreate() returns false");
+ THROW(-1);
+ }
+
+ SchedPriority::Set(0);
+ OnAdapterLoopBegin();
+ OnTerminate();
+}
+
+void LaunchpadLoader::Quit() {
+ OnAdapterLoopQuit();
+}
+
+const tizen_base::Bundle& LaunchpadLoader::GetBundle() const {
+ return app_info_.GetBundle();
+}
+
+void LaunchpadLoader::ResetArgs() {
+ memset(argv_[LOADER_ARG_TYPE], 0, strlen(argv_[LOADER_ARG_TYPE]));
+ memset(argv_[LOADER_ARG_ID], 0, strlen(argv_[LOADER_ARG_ID]));
+ memset(argv_[LOADER_ARG_EXTRA], 0, strlen(argv_[LOADER_ARG_EXTRA]));
+}
+
+void LaunchpadLoader::WaitForThreads(int threads) {
+ uint32_t retrying_count = 0;
+
+ if (threads <= 1)
+ return;
+
+ _W("Thread count = %u", threads);
+ do {
+ int thread_count = ThreadControl::GetInst().GetCount();
+ if (thread_count >= threads) {
+ _E("Threads(%u) are ready", thread_count);
+ return;
+ }
+
+ _D("Current thread count = %u", thread_count);
+ usleep(50 * 1000);
+ retrying_count++;
+ } while (retrying_count < kMaxRetryingCount);
+ _E("Maximum retyring count exceeded");
+}
+
+int LaunchpadLoader::ConnectToLaunchpad() {
+ std::string endpoint = "/run/aul/daemons/" + std::to_string(getuid()) +
+ "/" + std::string(kLaunchpadLoaderSocketName) +
+ std::to_string(loader_type_) + "-" + std::to_string(loader_id_);
+ ClientSocket client_socket;
+ client_socket.Connect(endpoint);
+ client_socket.SetReceiveBufferSize(Socket::kSocketMaxBufferSize);
+ client_socket.SetReceiveTimeout(5000);
+
+ pid_t pid = getpid();
+ int ret = client_socket.Send(static_cast<void*>(&pid), sizeof(pid));
+ if (ret != 0) {
+ _E("Send() is failed. error: %d", ret);
+ return ret;
+ }
+
+ return client_socket.RemoveFd();
+}
+
+bool LaunchpadLoader::OnCreate() {
+ setsid();
+ tizen_base::Bundle extra(argv_[LOADER_ARG_EXTRA]);
+ ResetArgs();
+
+ if (callback_.create == nullptr) {
+ _E("create callback is nullptr");
+ return false;
+ }
+
+ int threads = 0;
+ std::string threads_str = extra.GetString("threads");
+ if (!threads_str.empty() && std::isdigit(threads_str[0])) {
+ _W("threads: %s", threads_str.c_str());
+ threads = std::stoi(threads_str);
+ }
+
+ callback_.create(extra.GetHandle(), loader_type_, user_data_);
+ aul_launch_worker_init();
+ WaitForThreads(threads);
+ malloc_trim(0);
+
+ try {
+ int fd = ConnectToLaunchpad();
+ if (fd < 0) {
+ _E("Connection to launchpad was failed. error: %d", fd);
+ return false;
+ }
+
+ OnAdapterAddFd(fd);
+ } catch (const Exception& e) {
+ _E("Exception occurs. error: %s", e.what());
+ return false;
+ }
+
+ language_config_.reset(new LanguageConfig());
+ region_format_config_.reset(new RegionFormatConfig());
+ return true;
+}
+
+void LaunchpadLoader::OnPrelaunch(int argc, char** argv, AppInfo* app_info) {
+ if (callback_.prelaunch) {
+ int ret = callback_.prelaunch(argc, argv, app_info->GetAppPath().c_str(),
+ app_info->GetAppId().c_str(), app_info->GetPkgId().c_str(),
+ app_info->GetPkgType().c_str(), user_data_);
+ if (ret < 0) {
+ _E("prelaunch returns an error: %d", ret);
+ exit(-1);
+ }
+ }
+}
+
+void LaunchpadLoader::DefaultLaunch(AppInfo* app_info) {
+ StepPrepareExecution step_prepare_execution;
+ if (step_prepare_execution.Prepare(app_info) != 0) {
+ _E("Failed to prepare execution");
+ exit(-1);
+ }
+}
+
+void LaunchpadLoader::ChangeArgs(int argc, char** argv) {
+ auto* env = getenv("TIZEN_LOADER_ARGS");
+ if (env != nullptr) {
+ auto* loader_args = reinterpret_cast<char*>(strtoul(env, nullptr, 10));
+ if (loader_args != nullptr)
+ argv_[0] = loader_args;
+ }
+
+ memset(argv_[0], '\0', strlen(argv_[0]));
+ snprintf(argv_[0], LOADER_ARG_LEN, "%s", argv[0]);
+}
+
+int LaunchpadLoader::OnLaunch(int argc, char** argv, AppInfo* app_info) {
+ if (callback_.launch == nullptr)
+ return -1;
+
+ return callback_.launch(argc, argv, app_info->GetAppPath().c_str(),
+ app_info->GetAppId().c_str(), app_info->GetPkgId().c_str(),
+ app_info->GetPkgType().c_str(), user_data_);
+}
+
+void LaunchpadLoader::OnTerminate() {
+ _W("Terminating...");
+ region_format_config_.reset();
+ language_config_.reset();
+
+ if (callback_.terminate != nullptr) {
+ int ret = callback_.terminate(app_argc_, app_argv_, user_data_);
+ if (ret != 0)
+ exit(ret);
+ }
+}
+
+void LaunchpadLoader::OnAdapterLoopBegin() {
+ _W("Loop begin");
+ adapter_callback_.loop_begin(user_data_);
+}
+
+void LaunchpadLoader::OnAdapterLoopQuit() {
+ _W("Loop quit");
+ adapter_callback_.loop_quit(user_data_);
+}
+
+void LaunchpadLoader::OnAdapterAddFd(int fd) {
+ _W("Add fd: %d", fd);
+ adapter_callback_.add_fd(user_data_, fd, ReceiverCb);
+}
+
+void LaunchpadLoader::OnAdapterRemovefd(int fd) {
+ _W("Remove fd: %d", fd);
+ adapter_callback_.remove_fd(user_data_, fd);
+}
+
+void LaunchpadLoader::HandleReceiverEvent(int fd) {
+ _D("fd: %d", fd);
+ ClientSocket socket(fd);
+ size_t data_size = 0;
+ int ret = socket.Receive(static_cast<void*>(&data_size), sizeof(data_size));
+ if (ret != 0) {
+ _E("Failed to receive the data from socket. error(%d)", ret);
+ return;
+ }
+
+ std::vector<uint8_t> data(data_size);
+ ret = socket.Receive(data.data(), data.size());
+ if (ret != 0) {
+ _E("Failed to receive the data from socket. error(%d)", ret);
+ return;
+ }
+
+ tizen_base::Parcel parcel(data.data(), data.size());
+ OnAdapterRemovefd(fd);
+
+ ProcessLaunchRequest(&parcel);
+ if (ret >= 0)
+ Quit();
+}
+
+void LaunchpadLoader::ReceiverCb(int fd) {
+ context->HandleReceiverEvent(fd);
+}
+
+void LaunchpadLoader::ProcessLaunchRequest(tizen_base::Parcel* parcel) {
+ parcel->ReadParcelable(&app_info_);
+ SECURE_LOGD("App Id: %s, Package Id: %s, Loader Type: %d",
+ app_info_.GetAppId().c_str(), app_info_.GetPkgId().c_str(), loader_type_);
+ if (app_info_.GetAppPath().empty() || app_info_.GetAppPath()[0] != '/') {
+ _E("AppPath is not absolute path");
+ exit(-1);
+ }
+
+ Util::SetEnvironments(&app_info_);
+ auto exported_args = app_info_.GetBundle().Export();
+ exported_args[0] = app_info_.GetAppPath();
+ app_argc_ = exported_args.size();
+ app_argv_ = static_cast<char**>(calloc(app_argc_, sizeof(char*)));
+ if (app_argv_ == nullptr) {
+ _E("calloc() is failed");
+ exit(-ENOMEM);
+ }
+
+ for (int i = 0; i < app_argc_; ++i) {
+ app_argv_[i] = strdup(exported_args[i].c_str());
+ if (app_argv_[i] == nullptr) {
+ _E("strdup() is failed. [%d] %s", i, exported_args[i].c_str());
+ exit(-ENOMEM);
+ }
+
+ SECURE_LOGD("Input argument %d : %s##", i, app_argv_[i]);
+ }
+
+ OnPrelaunch(app_argc_, app_argv_, &app_info_);
+ DefaultLaunch(&app_info_);
+ OnLaunch(app_argc_, app_argv_, &app_info_);
+ ChangeArgs(app_argc_, app_argv_);
+}
+
+} // namespace launchpad
+
+using namespace launchpad;
+
+extern "C" EXPORT_API bundle* launchpad_loader_get_bundle(void) {
+ if (!::context)
+ return nullptr;
+
+ return ::context->GetBundle().GetHandle();
+}
+
+extern "C" EXPORT_API int launchpad_loader_main(int argc, char** argv,
+ loader_lifecycle_callback_s* callback, loader_adapter_s* adapter,
+ void* user_data) {
+ try {
+ LaunchpadLoader loader(argc, argv);
+ loader.Run(callback, adapter, user_data);
+ } catch (const Exception& e) {
+ _E("Exception occurs. error: %s", e.what());
+ return e.GetErrorCode();
+ }
+
+ return 0;
+}
+
+extern "C" EXPORT_API int launchpad_loader_set_priority(int prio) {
+ return SchedPriority::Set(prio);
+}
+
+extern "C" EXPORT_API int launchpad_loader_block_threads(void) {
+ return ThreadControl::GetInst().BlockThreads();
+}
+
+extern "C" EXPORT_API int launchpad_loader_unblock_threads(void) {
+ return ThreadControl::GetInst().UnblockThreads();
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 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_LOADER_HH_
+#define LIB_LAUNCHPAD_LAUNCHPAD_LOADER_HH_
+
+#include <bundle_cpp.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <app_info.hh>
+#include <language_config.hh>
+#include <parcel.hh>
+#include <region_format_config.hh>
+
+#include "inc/launchpad.h"
+
+namespace launchpad {
+
+class LaunchpadLoader {
+ public:
+ LaunchpadLoader(int argc, char** argv);
+ virtual ~LaunchpadLoader();
+
+ void Run(loader_lifecycle_callback_s* callback, loader_adapter_s* adapter,
+ void* user_data);
+ void Quit();
+ const tizen_base::Bundle& GetBundle() const;
+
+ private:
+ void WaitForThreads(int threads);
+ int ConnectToLaunchpad();
+ void DefaultLaunch(AppInfo* app_info);
+ void ResetArgs();
+ void ChangeArgs(int argc, char** argv);
+
+ bool OnCreate();
+ void OnPrelaunch(int argc, char** argv, AppInfo* app_info);
+ int OnLaunch(int argc, char** argv, AppInfo* app_info);
+ void OnTerminate();
+
+ void OnAdapterLoopBegin();
+ void OnAdapterLoopQuit();
+ void OnAdapterAddFd(int fd);
+ void OnAdapterRemovefd(int fd);
+
+ void HandleReceiverEvent(int fd);
+ void ProcessLaunchRequest(tizen_base::Parcel* parcel);
+ static void ReceiverCb(int fd);
+
+ private:
+ int argc_;
+ char** argv_;
+ int loader_type_;
+ int loader_id_;
+ loader_lifecycle_callback_s callback_ = { nullptr, };
+ loader_adapter_s adapter_callback_ = { nullptr, };
+ void* user_data_ = nullptr;
+ AppInfo app_info_;
+ std::unique_ptr<LanguageConfig> language_config_;
+ std::unique_ptr<RegionFormatConfig> region_format_config_;
+ int app_argc_ = 0;
+ char** app_argv_ = nullptr;
+};
+
+} // namespace launchpad
+
+#endif // LIB_LAUNCHPAD_LAUNCHPAD_LOADER_HH_
--- /dev/null
+/*
+ * Copyright (c) 2023 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_LOG_PRIVATE_HH_
+#define LIB_LAUNCHPAD_LOG_PRIVATE_HH_
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "LIB_LAUNCHPAD"
+
+#undef _E
+#define _E LOGE
+
+#undef _W
+#define _W LOGW
+
+#undef _I
+#define _I LOGI
+
+#undef _D
+#define _D LOGD
+
+#endif // LIB_LAUNCHPAD_LOG_PRIVATE_HH_
+++ /dev/null
-/*
- * Copyright (c) 2015 - 2019 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.
- */
-
-#define _GNU_SOURCE
-#include <dirent.h>
-#include <malloc.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <bundle_internal.h>
-#include <aul.h>
-#include <security-manager.h>
-#include <trust-anchor.h>
-#include <buxton2.h>
-#include <vconf.h>
-
-#include "launchpad.h"
-#include "launchpad_common.h"
-#include "launchpad_types.h"
-#include "preexec.h"
-
-#ifndef API
-#define API __attribute__ ((visibility("default")))
-#endif
-
-#define AUL_PR_NAME 16
-#define SIGRTINT (SIGRTMIN + 2)
-
-typedef struct thread_handler_s {
- struct sigaction old;
- GMutex mutex;
- GCond cond;
- gint count;
- gint num;
- bool blocked;
- bool done;
-} thread_handler_t;
-
-static loader_lifecycle_callback_s *__loader_callbacks;
-static loader_adapter_s *__loader_adapter;
-static void *__loader_user_data;
-static int __argc;
-static char **__argv;
-static bundle *__bundle;
-static int __loader_type = LAUNCHPAD_TYPE_UNSUPPORTED;
-static int __loader_id;
-static bool __loop_quit;
-static thread_handler_t __thread_handler;
-
-static void __at_exit_to_release_bundle(void)
-{
- if (__bundle)
- bundle_free(__bundle);
-}
-
-static int __prepare_exec(const char *appid, const char *app_path,
- const char *pkg_type, int type, const char* pkgid,
- const char *root_path, bool global, bundle *kb)
-{
- const char *file_name = NULL;
- const char *enabled_light_user;
- char process_name[AUL_PR_NAME] = { 0, };
- int ret;
- struct buxton_client *bxt_cli;
-
- __preexec_run(pkg_type, appid, app_path);
-
- ret = _enable_external_pkg(kb, pkgid, global ? GLOBAL_USER : getuid());
- if (ret < 0)
- return -1;
-
- /* SET PRIVILEGES*/
- SECURE_LOGD("[candidate] appid : %s / pkg_type : %s / app_path : %s",
- appid, pkg_type, app_path);
-
- if (global)
- ret = trust_anchor_launch(pkgid, GLOBAL_USER);
- else
- ret = trust_anchor_launch(pkgid, getuid());
-
- if (ret != TRUST_ANCHOR_ERROR_NONE &&
- ret != TRUST_ANCHOR_ERROR_NOT_INSTALLED) {
- _E("trust_anchor_launch() returns %d", ret);
- return -1;
- }
-
- ret = _mount_res_dir(root_path, kb);
- if (ret < 0)
- return -1;
-
- enabled_light_user = bundle_get_val(kb, AUL_K_ENABLED_LIGHT_USER);
- _W("security_manager_prepare_app2 ++ %s", appid);
- ret = security_manager_prepare_app2(appid, enabled_light_user);
- _W("security_manager_prepare_app2 -- %s", appid);
- if (ret != SECURITY_MANAGER_SUCCESS) {
- _E("Failed to set privileges %s:%d", appid, ret);
- return -1;
- }
-
- _setup_stdio(basename(app_path));
-
- ret = buxton_open(&bxt_cli, NULL, NULL);
- if (ret != 0) {
- _E("buxton_open() failed, errno(%d)", errno);
- return -1;
- }
- ret = buxton_update_client_label_sync(bxt_cli);
- if (ret != 0) {
- _E("buxton_update_client_label() failed, errno(%d)", errno);
- buxton_close(bxt_cli);
- return -1;
- }
- buxton_close(bxt_cli);
-
- /*
- * SET DUMPABLE - for coredump
- * This dumpable flag should be set after
- * calling perm_app_set_privilege().
- */
- prctl(PR_SET_DUMPABLE, 1);
-
- /* SET PROCESS NAME*/
- if (app_path == NULL) {
- _D("app_path should not be NULL - check menu db");
- return -1;
- }
-
- file_name = strrchr(app_path, '/');
- if (file_name == NULL) {
- _D("file_name is NULL");
- return -1;
- }
-
- file_name++;
- if (*file_name == '\0') {
- _D("can't locate file name to execute");
- return -1;
- }
-
- memset(process_name, '\0', AUL_PR_NAME);
- snprintf(process_name, AUL_PR_NAME, "%s", file_name);
- prctl(PR_SET_NAME, process_name);
-
- ret = _wait_tep_mount(kb);
- if (ret < 0)
- return -1;
-
- ret = _prepare_app_socket();
- if (ret < 0)
- return -1;
-
- ret = _prepare_id_file();
- if (ret < 0)
- return -1;
-
- _send_cmd_to_amd(APP_STARTUP_SIGNAL);
- return 0;
-}
-
-static int __default_launch_cb(bundle *kb, const char *appid,
- const char *app_path, const char *root_path,
- const char *pkgid, const char *pkg_type, int loader_type, bool global)
-{
- char err_str[MAX_LOCAL_BUFSZ] = { 0, };
- int r;
-
- r = __prepare_exec(appid, app_path, pkg_type, loader_type, pkgid,
- root_path, global, kb);
- if (r < 0) {
- _E("__candidate_process_prepare_exec() failed");
- if (access(app_path, F_OK | R_OK)) {
- SECURE_LOGE("access() failed for file: \"%s\", " \
- "error: %d (%s)", app_path, errno,
- strerror_r(errno, err_str, sizeof(err_str)));
- }
- exit(-1);
- }
-
- return 0;
-}
-
-static int __candidate_process_launchpad_main_loop(app_pkt_t *pkt,
- char *out_app_path, int *out_argc, char ***out_argv, int type)
-{
- bundle *kb;
- appinfo_t *menu_info = NULL;
- const char *app_path = NULL;
- int tmp_argc = 0;
- char **tmp_argv = NULL;
- const char *env;
- char *loader_args = NULL;
- int ret = -1;
- int i;
-
- kb = bundle_decode(pkt->data, pkt->len);
- if (!kb) {
- _E("bundle decode error");
- exit(-1);
- }
-
- if (__bundle != NULL)
- bundle_free(__bundle);
-
- __bundle = kb;
- atexit(__at_exit_to_release_bundle);
-
- menu_info = _appinfo_create(kb);
- if (menu_info == NULL) {
- _D("such pkg no found");
- exit(-1);
- }
-
- if (menu_info->appid == NULL) {
- _E("Unable to get app_id");
- exit(-1);
- }
-
- if (type < 0) {
- _E("Invalid launchpad type: %d", type);
- exit(-1);
- }
-
- SECURE_LOGD("app id: %s, launchpad type: %d", menu_info->appid, type);
-
- app_path = _appinfo_get_app_path(menu_info);
- if (app_path == NULL) {
- _E("app_path is NULL");
- exit(-1);
- }
-
- if (app_path[0] != '/') {
- _E("app_path is not absolute path");
- exit(-1);
- }
-
- _modify_bundle(kb, /*cr.pid - unused parameter*/ 0, menu_info,
- pkt->cmd);
-
- if (menu_info->pkgid == NULL) {
- _E("unable to get pkg_id from menu_info");
- exit(-1);
- }
-
- SECURE_LOGD("pkg id: %s", menu_info->pkgid);
-
- /* Set environments */
- _set_env(menu_info, kb);
-
- tmp_argv = _create_argc_argv(kb, &tmp_argc);
-
- if (__loader_callbacks->prelaunch) {
- ret = __loader_callbacks->prelaunch(tmp_argc, tmp_argv,
- app_path, menu_info->appid, menu_info->pkgid,
- menu_info->pkg_type, __loader_user_data);
-
- if (ret < 0) {
- _E("prelaunch callback fail (%d)", ret);
- exit(-1);
- }
- }
-
- __default_launch_cb(kb, menu_info->appid, app_path,
- menu_info->root_path, menu_info->pkgid,
- menu_info->pkg_type, type, menu_info->global);
-
- if (__loader_callbacks->launch) {
- ret = __loader_callbacks->launch(tmp_argc, tmp_argv, app_path,
- menu_info->appid, menu_info->pkgid,
- menu_info->pkg_type, __loader_user_data);
- }
-
- if (out_app_path != NULL && out_argc != NULL && out_argv != NULL) {
- env = getenv("TIZEN_LOADER_ARGS");
- if (env != NULL) {
- loader_args = (char *)strtoul(env, NULL, 10);
- if (loader_args != NULL)
- out_app_path = loader_args;
- }
-
- memset(out_app_path, '\0', strlen(out_app_path));
- snprintf(out_app_path, LOADER_ARG_LEN, "%s", app_path);
-
- *out_argv = tmp_argv;
- *out_argc = tmp_argc;
- (*out_argv)[LOADER_ARG_PATH] = out_app_path;
-
- for (i = 0; i < *out_argc; i++) {
- SECURE_LOGD("input argument %d : %s##", i,
- (*out_argv)[i]);
- }
- } else {
- exit(-1);
- }
-
- if (menu_info != NULL)
- _appinfo_free(menu_info);
-
- if (__bundle) {
- bundle_free(__bundle);
- __bundle = NULL;
- }
-
- return ret;
-}
-
-static void __receiver_cb(int fd)
-{
- int ret = -1;
- app_pkt_t *pkt;
-
- _D("[candidate] ECORE_FD_READ");
- pkt = _recv_pkt_raw(fd);
- if (!pkt) {
- _D("[candidate] _recv_pkt_raw error!");
- exit(-1);
- }
-
- __loader_adapter->remove_fd(__loader_user_data, fd);
- close(fd);
- ret = __candidate_process_launchpad_main_loop(pkt,
- __argv[LOADER_ARG_PATH], &__argc, &__argv,
- __loader_type);
- SECURE_LOGD("[candidate] real app argv[0]: %s, real app argc: %d",
- __argv[LOADER_ARG_PATH], __argc);
- free(pkt);
-
- if (ret >= 0) {
- __loader_adapter->loop_quit(__loader_user_data);
- _D("[candidate] ecore main loop quit");
- __loop_quit = true;
- }
-}
-
-static void __update_lang(keynode_t *node, void *user_data)
-{
- char *lang;
-
- lang = vconf_keynode_get_str(node);
- if (!lang) {
- _E("Failed to get language");
- return;
- }
-
- setenv("LANG", lang, 1);
-}
-
-static void __region_format_changed_cb(keynode_t *node, void *user_data)
-{
- char *region;
-
- region = vconf_keynode_get_str(node);
- if (!region) {
- _E("Failed to get regionformat");
- return;
- }
-
- setenv("LC_CTYPE", region, 1);
-}
-
-#ifndef USE_STATUS
-static unsigned int __get_thread_count(void)
-{
- DIR *dp;
- struct dirent *dentry;
- unsigned int count = 0;
-
- dp = opendir("/proc/self/task");
- if (dp == NULL) {
- _E("opendir() is failed. errno(%d)", errno);
- return 0;
- }
-
- while ((dentry = readdir(dp)) != NULL) {
- if (!isdigit(dentry->d_name[0]))
- continue;
-
- count++;
- }
-
- closedir(dp);
- return count;
-}
-#else
-static unsigned int __get_thread_count(void)
-{
- unsigned int count = 0;
- char line[LINE_MAX];
- FILE *fp;
-
- fp = fopen("/proc/self/status", "r");
- if (fp == NULL) {
- _E("fopen() is failed");
- return 0;
- }
-
- while (fgets(line, sizeof(line), fp)) {
- if (sscanf(line, "Threads: %u", &count) == 1)
- break;
- }
-
- fclose(fp);
- return count;
-}
-#endif
-
-static void __wait_for_threads(unsigned int threads)
-{
-#define MAX_RETRYING_COUNT 600
- unsigned int thread_count;
- unsigned int retrying_count = 0;
-
- if (threads <= 1)
- return;
-
- _W("Thread count = %u", threads);
- do {
- thread_count = __get_thread_count();
- if (thread_count >= threads) {
- _E("Threads(%u) are ready", thread_count);
- return;
- }
-
- _D("Current thread count = %u", thread_count);
- usleep(50 * 1000);
- retrying_count++;
- } while (retrying_count < MAX_RETRYING_COUNT);
- _E("Maximum retrying count exceeded");
-}
-
-static int __before_loop(int argc, char **argv)
-{
- int client_fd;
- int ret = -1;
- bundle *extra = NULL;
- const char *val;
- unsigned int threads = 0;
- int r;
-
- if (_verify_proc_caps() < 0)
- return -1;
-
- __preexec_init(argc, argv);
-
- /* Set new session ID & new process group ID*/
- /* In linux, child can set new session ID without check permission */
- /* TODO : should be add to check permission in the kernel*/
- setsid();
-
- memset(argv[LOADER_ARG_TYPE], 0, strlen(argv[LOADER_ARG_TYPE]));
- memset(argv[LOADER_ARG_ID], 0, strlen(argv[LOADER_ARG_ID]));
- if (argc > 3) {
- extra = bundle_decode((bundle_raw *)argv[LOADER_ARG_EXTRA],
- strlen(argv[LOADER_ARG_EXTRA]));
- memset(argv[LOADER_ARG_EXTRA], 0,
- strlen(argv[LOADER_ARG_EXTRA]));
- }
-
- if (__loader_callbacks->create) {
- val = bundle_get_val(extra, "threads");
- if (val && isdigit(val[0])) {
- _D("threads: %s", val);
- threads = atoi(val);
- }
-
- __loader_callbacks->create(extra, __loader_type,
- __loader_user_data);
- ret = 0;
- aul_launch_worker_init();
- __wait_for_threads(threads);
- }
-
- if (extra)
- bundle_free(extra);
-
- malloc_trim(0);
-
- client_fd = _connect_to_launchpad(__loader_type, __loader_id);
- if (client_fd == -1) {
- _D("Connecting to candidate process was failed.");
- return -1;
- }
-
- __loader_adapter->add_fd(__loader_user_data, client_fd, __receiver_cb);
-
- r = vconf_notify_key_changed(VCONFKEY_LANGSET, __update_lang, NULL);
- if (r != VCONF_OK)
- _E("Failed to register callback for langset. error(%d)", r);
-
- r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT,
- __region_format_changed_cb, NULL);
- if (r != VCONF_OK)
- _E("Failed to register callback for regionformat. error(%d)", r);
-
- return ret;
-}
-
-static int __after_loop(void)
-{
- vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT,
- __region_format_changed_cb);
- vconf_ignore_key_changed(VCONFKEY_LANGSET, __update_lang);
-
- if (__loader_callbacks->terminate) {
- return __loader_callbacks->terminate(__argc, __argv,
- __loader_user_data);
- }
-
- return -1;
-}
-
-API bundle *launchpad_loader_get_bundle(void)
-{
- return __bundle;
-}
-
-API int launchpad_loader_main(int argc, char **argv,
- loader_lifecycle_callback_s *callbacks,
- loader_adapter_s *adapter, void *user_data)
-{
- int is_hydra;
-
- if (argc < 4) {
- _E("too few argument.");
- return -1;
- }
-
- is_hydra = argv[LOADER_ARG_HYDRA][0] - '0';
-
- if (is_hydra) {
- _D("Cannot run in hydra mode");
- return -1;
- }
-
- __loader_type = atoi(argv[LOADER_ARG_TYPE]);
- if (__loader_type < 0 || __loader_type >= LAUNCHPAD_TYPE_MAX) {
- _E("invalid argument. (type: %d)", __loader_type);
- return -1;
- }
-
- __loader_id = atoi(argv[LOADER_ARG_ID]);
-
- if (callbacks == NULL) {
- _E("invalid argument. callback is null");
- return -1;
- }
-
- if (adapter == NULL) {
- _E("invalid argument. adapter is null");
- return -1;
- }
-
- if (adapter->loop_begin == NULL || adapter->loop_quit == NULL
- || adapter->add_fd == NULL || adapter->remove_fd == NULL) {
- _E("invalid argument. adapter callback is null");
- return -1;
- }
-
- __loader_callbacks = callbacks;
- __loader_adapter = adapter;
- __loader_user_data = user_data;
- __argc = argc;
- __argv = argv;
-
- if (__before_loop(argc, argv) != 0) {
- _E("Failed to prepare running loader. type(%d)", __loader_type);
- return -1;
- }
-
- _set_priority(0);
- _D("[candidate] ecore main loop begin");
- __loader_adapter->loop_begin(__loader_user_data);
-
- if (!__loop_quit) {
- _E("[candidate] loop was stopped forcedly");
- return -1;
- }
-
- return __after_loop();
-}
-
-API int launchpad_loader_set_priority(int prio)
-{
- return _set_priority(prio);
-}
-
-static void __signal_handler(int signo)
-{
- _D("Block thread");
- g_mutex_lock(&__thread_handler.mutex);
- g_atomic_int_set(&__thread_handler.count,
- g_atomic_int_get(&__thread_handler.count) - 1);
- while (!__thread_handler.done)
- g_cond_wait(&__thread_handler.cond, &__thread_handler.mutex);
- g_mutex_unlock(&__thread_handler.mutex);
- g_atomic_int_inc(&__thread_handler.count);
- _D("Unblock thread");
-}
-
-API int launchpad_loader_block_threads(void)
-{
- struct sigaction act;
- struct dirent *dentry;
- DIR *dp;
- pid_t pid = getpid();
- pid_t tid;
- gint i;
-
- if (__thread_handler.blocked) {
- _D("Already blocked");
- return 0;
- }
-
- g_mutex_init(&__thread_handler.mutex);
- g_cond_init(&__thread_handler.cond);
-
- memset(&act, '\0', sizeof(act));
- sigemptyset(&act.sa_mask);
- act.sa_flags = SA_RESTART;
- act.sa_handler = __signal_handler;
-
- if (sigaction(SIGRTINT, &act, &__thread_handler.old) != 0) {
- _E("sigaction() is failed. errno(%d)", errno);
- return -1;
- }
-
- __thread_handler.done = false;
- __thread_handler.count = 0;
- __thread_handler.num = 0;
-
- dp = opendir("/proc/self/task");
- if (dp == NULL) {
- _E("opendir() is failed. errno(%d)", errno);
- sigaction(SIGRTINT, &__thread_handler.old, NULL);
- return -1;
- }
-
- while ((dentry = readdir(dp)) != NULL) {
- if (!isdigit(dentry->d_name[0]))
- continue;
-
- tid = atoi(dentry->d_name);
- if (tid != pid) {
- _D("Send signal to thread(%d)", tid);
- if (tgkill(pid, tid, SIGRTINT) != 0) {
- _E("tgkill() is failed. errno(%d)", errno);
- } else {
- g_atomic_int_inc(&__thread_handler.count);
- __thread_handler.num++;
- }
- }
- }
- closedir(dp);
-
- for (i = 1000; g_atomic_int_get(&__thread_handler.count) && i; --i)
- usleep(2000);
-
- __thread_handler.blocked = true;
-
- return 0;
-}
-
-API int launchpad_loader_unblock_threads(void)
-{
- gint i;
-
- if (!__thread_handler.blocked)
- return 0;
-
- g_mutex_lock(&__thread_handler.mutex);
- __thread_handler.done = true;
- g_cond_broadcast(&__thread_handler.cond);
- g_mutex_unlock(&__thread_handler.mutex);
-
- for (i = 1000; g_atomic_int_get(&__thread_handler.count) != __thread_handler.num && i; --i)
- usleep(2000);
-
- sigaction(SIGRTINT, &__thread_handler.old, NULL);
- g_mutex_clear(&__thread_handler.mutex);
- g_cond_clear(&__thread_handler.cond);
- __thread_handler.blocked = false;
-
- return 0;
-}
--- /dev/null
+/*
+ * Copyright (c) 2023 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 "launchpad/step_prepare_execution.hh"
+
+#include <aul.h>
+#include <bundle_cpp.h>
+#include <bundle_internal.h>
+#include <buxton2.h>
+#include <security-manager.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <trust-anchor.h>
+#include <unistd.h>
+#include <vconf.h>
+
+#include <app_info.hh>
+#include <aul_keys.hh>
+
+#include "common/inc/launchpad_common.h"
+#include "common/inc/launchpad_types.h"
+#include "launchpad/log_private.hh"
+
+namespace launchpad {
+
+StepPrepareExecution::StepPrepareExecution() {
+ steps_ = {
+ std::bind(&StepPrepareExecution::EnableExternalPackage, this,
+ std::placeholders::_1),
+ std::bind(&StepPrepareExecution::TrustAnchorLaunch, this,
+ std::placeholders::_1),
+ std::bind(&StepPrepareExecution::MountResourceDirectories, this,
+ std::placeholders::_1),
+ std::bind(&StepPrepareExecution::SecurityManagerPrepareApp, this,
+ std::placeholders::_1),
+ std::bind(&StepPrepareExecution::SetupStdio, this,
+ std::placeholders::_1),
+ std::bind(&StepPrepareExecution::BuxtonUpdateClientLabel, this,
+ std::placeholders::_1),
+ std::bind(&StepPrepareExecution::SetDumpable, this,
+ std::placeholders::_1),
+ std::bind(&StepPrepareExecution::SetProcessName, this,
+ std::placeholders::_1),
+ std::bind(&StepPrepareExecution::WaitTepMount, this,
+ std::placeholders::_1),
+ std::bind(&StepPrepareExecution::PrepareAppSocket, this,
+ std::placeholders::_1),
+ std::bind(&StepPrepareExecution::PrepareIdFile, this,
+ std::placeholders::_1),
+ std::bind(&StepPrepareExecution::SendStartupSignal, this,
+ std::placeholders::_1),
+ };
+}
+
+int StepPrepareExecution::Prepare(AppInfo* app_info) {
+ for (auto& step : steps_) {
+ if (step(app_info) != 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+int StepPrepareExecution::EnableExternalPackage(AppInfo* app_info) {
+ int ret = _enable_external_pkg(app_info->GetBundle().GetHandle(),
+ app_info->GetPkgId().c_str(),
+ app_info->IsGlobal() ? GLOBAL_USER : getuid());
+ if (ret < 0) {
+ _E("Failed to enable external package. error: %d", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+int StepPrepareExecution::TrustAnchorLaunch(AppInfo* app_info) {
+ int ret = trust_anchor_launch(app_info->GetPkgId().c_str(),
+ app_info->IsGlobal() ? GLOBAL_USER : getuid());
+ if (ret != TRUST_ANCHOR_ERROR_NONE &&
+ ret != TRUST_ANCHOR_ERROR_NOT_INSTALLED) {
+ _E("trust_anchor_launch() is failed. error: %d", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+int StepPrepareExecution::MountResourceDirectories(AppInfo* app_info) {
+ int ret = _mount_res_dir(app_info->GetRootPath().c_str(),
+ app_info->GetBundle().GetHandle());
+ if (ret < 0) {
+ _E("Failed to mount resource direstories. error: %d", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+int StepPrepareExecution::SecurityManagerPrepareApp(AppInfo* app_info) {
+ auto* enabled_light_user = bundle_get_val(app_info->GetBundle().GetHandle(),
+ kAulEnabledLightUser);
+ _W("security_manager_prepare_app2() ++ %s", app_info->GetAppId().c_str());
+ int ret = security_manager_prepare_app2(app_info->GetAppId().c_str(),
+ enabled_light_user);
+ _W("security_manager_prepare_app2() -- %s", app_info->GetAppId().c_str());
+ if (ret != SECURITY_MANAGER_SUCCESS) {
+ _E("security_manager_prepare_app2() is failed. appid: %s, error: %d",
+ app_info->GetAppId().c_str(), ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+int StepPrepareExecution::SetupStdio(AppInfo* app_info) {
+ _setup_stdio(basename(app_info->GetAppPath().c_str()));
+ return 0;
+}
+
+int StepPrepareExecution::BuxtonUpdateClientLabel(AppInfo* app_info) {
+ struct buxton_client* client = nullptr;
+ int ret = buxton_open(&client, nullptr, nullptr);
+ if (ret != 0) {
+ _E("buxton_open() is failed. errno: %d", errno);
+ return -1;
+ }
+
+ ret = buxton_update_client_label_sync(client);
+ buxton_close(client);
+ if (ret != 0) {
+ _E("buxton_update_client_label_sync() is failed. errno: %d", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+int StepPrepareExecution::SetDumpable(AppInfo* app_info) {
+ prctl(PR_SET_DUMPABLE, 1);
+ return 0;
+}
+
+int StepPrepareExecution::SetProcessName(AppInfo* app_info) {
+ char process_name[16] = { 0, };
+ snprintf(process_name, sizeof(process_name), "%s",
+ basename(app_info->GetAppPath().c_str()));
+ prctl(PR_SET_NAME, process_name);
+ return 0;
+}
+
+int StepPrepareExecution::WaitTepMount(AppInfo* app_info) {
+ int ret = _wait_tep_mount(app_info->GetBundle().GetHandle());
+ if (ret < 0) {
+ _E("Failed to wait tep mount. error: %d", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+int StepPrepareExecution::PrepareAppSocket(AppInfo* app_info) {
+ int ret = _prepare_app_socket();
+ if (ret < 0) {
+ _E("Failed to prepare app socket. error: %d", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+int StepPrepareExecution::PrepareIdFile(AppInfo* app_info) {
+ int ret = _prepare_id_file();
+ if (ret < 0) {
+ _E("Failed to prepare id file. error: %d", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+int StepPrepareExecution::SendStartupSignal(AppInfo* app_info) {
+ if (_send_cmd_to_amd(APP_STARTUP_SIGNAL) != 0)
+ _W("Failed to send startup signal");
+
+ return 0;
+}
+
+} // namespace launchpad
--- /dev/null
+/*
+ * Copyright (c) 2023 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_STEP_PREPARE_EXECUTION_HH_
+#define LIB_LAUNCHPAD_STEP_PREPARE_EXECUTION_HH_
+
+#include <functional>
+#include <vector>
+
+#include <app_info.hh>
+
+namespace launchpad {
+
+class StepPrepareExecution {
+ public:
+ StepPrepareExecution();
+ virtual ~StepPrepareExecution() = default;
+
+ int Prepare(AppInfo* app_info);
+
+ private:
+ int EnableExternalPackage(AppInfo* app_info);
+ int TrustAnchorLaunch(AppInfo* app_info);
+ int MountResourceDirectories(AppInfo* app_info);
+ int SecurityManagerPrepareApp(AppInfo* app_info);
+ int SetupStdio(AppInfo* app_info);
+ int BuxtonUpdateClientLabel(AppInfo* app_info);
+ int SetDumpable(AppInfo* app_info);
+ int SetProcessName(AppInfo* app_info);
+ int WaitTepMount(AppInfo* app_info);
+ int PrepareAppSocket(AppInfo* app_info);
+ int PrepareIdFile(AppInfo* app_info);
+ int SendStartupSignal(AppInfo* app_info);
+
+ private:
+ std::vector<std::function<int(AppInfo*)>> steps_;
+};
+
+} // namespace launchpad
+
+#endif // LIB_LAUNCHPAD_STEP_PREPARE_EXECUTION_HH_
--- /dev/null
+/*
+ * Copyright (c) 2023 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 "launchpad/thread_control.hh"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <filesystem>
+#include <string>
+#include <vector>
+
+#include "launchpad/log_private.hh"
+
+namespace launchpad {
+namespace {
+
+const int SIGRTINT = SIGRTMIN + 2;
+
+std::vector<pid_t> GetTasks() {
+ std::vector<pid_t> tasks;
+ std::filesystem::path task_path("/proc/self/task");
+ try {
+ for (auto& entry : std::filesystem::directory_iterator(task_path)) {
+ if (!std::isdigit(entry.path().filename().c_str()[0]))
+ continue;
+
+ tasks.push_back(std::stoi(entry.path().filename().string()));
+ }
+ } catch (const std::filesystem::filesystem_error& e) {
+ _E("Exception occurs. error: %s", e.what());
+ }
+
+ return tasks;
+}
+
+} // namespace
+
+ThreadControl& ThreadControl::GetInst() {
+ static ThreadControl inst;
+ return inst;
+}
+
+ThreadControl::~ThreadControl() {
+ UnblockThreads();
+}
+
+int ThreadControl::BlockThreads() {
+ if (blocked_)
+ return 0;
+
+ if (!ChangeSigaction())
+ return -1;
+
+ InterruptThreads();
+ WaitThreads();
+ blocked_ = true;
+ return 0;
+}
+
+int ThreadControl::UnblockThreads() {
+ if (!blocked_)
+ return 0;
+
+ ContinueThreads();
+ WaitThreads();
+ RestoreSigaction();
+ blocked_ = false;
+ return 0;
+}
+
+bool ThreadControl::IsBlocked() const {
+ return blocked_;
+}
+
+int ThreadControl::GetCount() {
+ return GetTasks().size();
+}
+
+bool ThreadControl::ChangeSigaction() {
+ struct sigaction act;
+ memset(&act, '\0', sizeof(struct sigaction));
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
+ act.sa_handler = SignalHandler;
+
+ if (sigaction(SIGRTINT, &act, &old_action_) != 0) {
+ _E("sigaction() is failed. errno(%d)", errno);
+ return false;
+ }
+
+ return true;
+}
+
+void ThreadControl::InterruptThreads() {
+ pid_t pid = getpid();
+ auto tasks = GetTasks();
+ count_ = tasks.size() - 1;
+ _D("tasks count: %d", count_);
+ for (auto& tid : tasks) {
+ if (tid != pid) {
+ _D("Send signal to thread(%d)", tid);
+ if (tgkill(pid, tid, SIGRTINT) != 0) {
+ _E("tgkill() is failed. tid(%d), errno(%d)", tid, errno);
+ count_--;
+ }
+ }
+ }
+}
+
+void ThreadControl::ContinueThreads() {
+ std::unique_lock<std::mutex> lock(mutex_);
+ count_ = GetTasks().size() - 1;
+ _D("tasks count: %d", count_);
+ done_ = true;
+ cond_.notify_all();
+}
+
+void ThreadControl::WaitThreads() {
+ for (int i = 1000; count_ && i; --i)
+ usleep(2000);
+}
+
+void ThreadControl::RestoreSigaction() {
+ if (sigaction(SIGRTINT, &old_action_, nullptr) != 0)
+ _E("sigaction() is failed. errno(%d)", errno);
+}
+
+void ThreadControl::SignalHandler(int signo) {
+ _W("Block");
+ auto& inst = ThreadControl::GetInst();
+ std::unique_lock<std::mutex> lock(inst.mutex_);
+ inst.count_--;
+ inst.cond_.wait(lock, [&] { return inst.done_; });
+ inst.count_--;
+ _W("Unblock");
+}
+
+} // namespace launchpad
--- /dev/null
+/*
+ * Copyright (c) 2023 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_THREAD_CONTROL_HH_
+#define LIB_LAUNCHPAD_THREAD_CONTROL_HH_
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <mutex>
+#include <condition_variable>
+
+namespace launchpad {
+
+class ThreadControl {
+ public:
+ static ThreadControl& GetInst();
+
+ int BlockThreads();
+ int UnblockThreads();
+ bool IsBlocked() const;
+ int GetCount();
+
+ private:
+ ThreadControl() = default;
+ ~ThreadControl();
+
+ bool ChangeSigaction();
+ void InterruptThreads();
+ void ContinueThreads();
+ void WaitThreads();
+ void RestoreSigaction();
+ static void SignalHandler(int signo);
+
+ private:
+ struct sigaction old_action_ = { 0, };
+ std::mutex mutex_;
+ std::condition_variable cond_;
+ uint32_t count_ = 0;
+ uint32_t num_ = 0;
+ bool blocked_ = false;
+ bool done_ = false;
+};
+
+} // namespace launchpad
+
+#endif // LIB_LAUNCHPAD_THREAD_CONTROL_HH_