From 23227ad03db5d25428a5019f9f8e2d67c76eb7e6 Mon Sep 17 00:00:00 2001 From: Changgyu Choi Date: Fri, 31 Mar 2023 15:17:19 +0900 Subject: [PATCH] Refactor launchpad The launchpad is implemented using C++ language. Change-Id: I43ee313ed4c5f73067f0f79df226dee09c77226a Signed-off-by: Changgyu Choi --- .../app_defined_loader_info_manager.cc | 18 + .../app_defined_loader_info_manager.hh | 1 + src/launchpad-process-pool/app_executor.cc | 286 +++ src/launchpad-process-pool/app_executor.hh | 74 + .../candidate_process_context.hh | 81 - src/launchpad-process-pool/debugger_info.cc | 249 +- src/launchpad-process-pool/debugger_info.hh | 64 +- src/launchpad-process-pool/executor.cc | 54 + src/launchpad-process-pool/executor.hh | 44 + src/launchpad-process-pool/hydra_loader_context.cc | 184 ++ src/launchpad-process-pool/hydra_loader_context.hh | 62 + src/launchpad-process-pool/launcher_info.cc | 191 +- src/launchpad-process-pool/launcher_info.hh | 48 +- src/launchpad-process-pool/launchpad.cc | 2454 ++------------------ src/launchpad-process-pool/launchpad.hh | 23 +- src/launchpad-process-pool/launchpad_inotify.cc | 188 -- src/launchpad-process-pool/launchpad_inotify.h | 42 - src/launchpad-process-pool/launchpad_io_channel.cc | 153 -- src/launchpad-process-pool/launchpad_io_channel.h | 48 - src/launchpad-process-pool/loader_context.cc | 616 +++++ src/launchpad-process-pool/loader_context.hh | 153 ++ src/launchpad-process-pool/loader_executor.cc | 86 + src/launchpad-process-pool/loader_executor.hh | 53 + src/launchpad-process-pool/loader_factory.cc | 147 ++ src/launchpad-process-pool/loader_factory.hh | 55 + src/launchpad-process-pool/loader_info.cc | 744 ++++-- src/launchpad-process-pool/loader_info.hh | 210 +- src/launchpad-process-pool/loader_manager.cc | 526 +++++ src/launchpad-process-pool/loader_manager.hh | 111 + src/launchpad-process-pool/request.cc | 15 +- src/launchpad-process-pool/request.hh | 14 +- src/launchpad-process-pool/sequencer.cc | 125 + src/launchpad-process-pool/sequencer.hh | 60 + src/launchpad-process-pool/slot_info.h | 48 - src/launchpad-process-pool/util.hh | 5 + src/lib/common/inc/launchpad_common.h | 15 +- src/lib/common/src/launchpad_common.c | 12 +- src/lib/launchpad-common/plugin.cc | 62 + src/lib/launchpad-common/plugin.hh | 36 + src/lib/launchpad-common/procfs.cc | 2 +- src/lib/launchpad-common/util.cc | 30 + src/lib/launchpad-common/util.hh | 2 + .../src/test_launchpad.cc | 4 +- 43 files changed, 4070 insertions(+), 3325 deletions(-) create mode 100644 src/launchpad-process-pool/app_executor.cc create mode 100644 src/launchpad-process-pool/app_executor.hh delete mode 100644 src/launchpad-process-pool/candidate_process_context.hh create mode 100644 src/launchpad-process-pool/executor.cc create mode 100644 src/launchpad-process-pool/executor.hh create mode 100644 src/launchpad-process-pool/hydra_loader_context.cc create mode 100644 src/launchpad-process-pool/hydra_loader_context.hh delete mode 100644 src/launchpad-process-pool/launchpad_inotify.cc delete mode 100644 src/launchpad-process-pool/launchpad_inotify.h delete mode 100644 src/launchpad-process-pool/launchpad_io_channel.cc delete mode 100644 src/launchpad-process-pool/launchpad_io_channel.h create mode 100644 src/launchpad-process-pool/loader_context.cc create mode 100644 src/launchpad-process-pool/loader_context.hh create mode 100644 src/launchpad-process-pool/loader_executor.cc create mode 100644 src/launchpad-process-pool/loader_executor.hh create mode 100644 src/launchpad-process-pool/loader_factory.cc create mode 100644 src/launchpad-process-pool/loader_factory.hh create mode 100644 src/launchpad-process-pool/loader_manager.cc create mode 100644 src/launchpad-process-pool/loader_manager.hh create mode 100644 src/launchpad-process-pool/sequencer.cc create mode 100644 src/launchpad-process-pool/sequencer.hh delete mode 100644 src/launchpad-process-pool/slot_info.h create mode 100644 src/lib/launchpad-common/plugin.cc create mode 100644 src/lib/launchpad-common/plugin.hh diff --git a/src/launchpad-process-pool/app_defined_loader_info_manager.cc b/src/launchpad-process-pool/app_defined_loader_info_manager.cc index a677655..8905303 100644 --- a/src/launchpad-process-pool/app_defined_loader_info_manager.cc +++ b/src/launchpad-process-pool/app_defined_loader_info_manager.cc @@ -22,6 +22,7 @@ namespace launchpad { namespace { constexpr const char kAppDefinedLoaderInfoPath[] = "/opt/share/loaders"; +constexpr const char kAppDefinedLoaderPath[] = "/usr/bin/app-defined-loader"; } // namespace @@ -55,6 +56,7 @@ void AppDefinedLoaderInfoManager::OnFileChanged(const std::string_view name, _W("name: %s, event: %d", name.data(), static_cast(event)); if (event == FileMonitor::Event::Created) { info_manager_->LoadFile(name); + UpdateLoaderInfo(); if (listener_ != nullptr) listener_->OnLoaderInfoAdded(filename); } else if (event == FileMonitor::Event::Deleted) { @@ -64,4 +66,20 @@ void AppDefinedLoaderInfoManager::OnFileChanged(const std::string_view name, } } +void AppDefinedLoaderInfoManager::UpdateLoaderInfo() { + for (auto& loader : info_manager_->GetLoaderInfoList()) { + auto& loader_info = const_cast&>(loader); + loader_info->SetType(LoaderType::Dynamic); + loader_info->SetExe(kAppDefinedLoaderPath); + loader_info->SetDetectionMethod( + LoaderMethod::Timeout | LoaderMethod::Visibility); + loader_info->SetActivationMethod( + LoaderMethod::Request | LoaderMethod::AvailableMemory); + loader_info->SetDeactivationMethod( + LoaderMethod::TimeToLive | LoaderMethod::OutOfMemory); + loader_info->SetTimeout(2000); + loader_info->SetAppInstalled(true); + } +} + } // namespace launchpad diff --git a/src/launchpad-process-pool/app_defined_loader_info_manager.hh b/src/launchpad-process-pool/app_defined_loader_info_manager.hh index e6f1550..9df5ffd 100644 --- a/src/launchpad-process-pool/app_defined_loader_info_manager.hh +++ b/src/launchpad-process-pool/app_defined_loader_info_manager.hh @@ -42,6 +42,7 @@ class AppDefinedLoaderInfoManager : public FileMonitor::IEvent { private: void OnFileChanged(const std::string_view name, FileMonitor::Event event) override; + void UpdateLoaderInfo(); private: std::unique_ptr file_monitor_; diff --git a/src/launchpad-process-pool/app_executor.cc b/src/launchpad-process-pool/app_executor.cc new file mode 100644 index 0000000..a5d6f95 --- /dev/null +++ b/src/launchpad-process-pool/app_executor.cc @@ -0,0 +1,286 @@ +/* + * 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-process-pool/app_executor.hh" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "launchpad-process-pool/debug.hh" +#include "launchpad-process-pool/log_private.hh" +#include "launchpad-process-pool/signal_manager.hh" +#include "launchpad-process-pool/user_tracer.hh" +#include "lib/common/inc/launchpad_common.h" +#include "lib/common/inc/launchpad_types.h" + +namespace launchpad { +namespace fs = std::filesystem; + +AppExecutor::AppExecutor() : Executor(this) { + LauncherInfoInflator inflator; + launcher_infos_ = inflator.Inflate("/usr/share/aul"); + + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepCreateNewSession, this)); + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepPluginPrepareApp, this)); + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepEnableExternalPackage, this)); + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepEnableTrustAnchor, this)); + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepMountResDir, this)); + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepChangeMountNamespace, this)); + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepSecurityPrepareApp, this)); + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepSetupStdio, this)); + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepSetDumpable, this)); + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepSetProcessName, this)); + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepSetEnvironments, this)); + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepWaitTepMount, this)); + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepPrepareAppSocketAndIdFile, this)); + prepare_funcs_.push_back( + std::bind(&AppExecutor::StepSendStartupSignal, this)); +} + +pid_t AppExecutor::Execute(const AppInfo* app_info) { + app_info_ = app_info; + return Executor::Execute(); +} + +void AppExecutor::OnExecution() { + UserTracer::Print(std::to_string(getpid()) + "|after calling fork(). " + + app_info_->GetAppId()); + CheckAndPrepareDebugging(); + SignalManager::GetInst().UnblockSigchld(); + Util::DeleteSocketPath(getpid(), getuid()); + + int ret = Prepare(); + if (ret < 0) { + _E("Failed to prepare executing application(%s)", + app_info_->GetAppId().c_str()); + exit(ret); + } + + std::vector argv = CreateAppArgv(app_info_->GetAppPath(), + app_info_->GetBundle(), app_info_->GetAppType()); + char** app_argv = static_cast(calloc(argv.size() + 1, sizeof(char*))); + if (app_argv == nullptr) { + _E("Out of memory"); + exit(-1); + } + + int app_argc = argv.size(); + for (int i = 0; i < app_argc; ++i) { + app_argv[i] = const_cast(argv[i].c_str()); + SECURE_LOGD("input argument %d : %s##", i, app_argv[i]); + } + + auto* lib_dir = _get_libdir(app_info_->GetAppPath().c_str()); + if (lib_dir != nullptr) { + setenv("LD_LIBRARY_PATH", lib_dir, 1); + free(lib_dir); + } + + _close_all_fds(); + if (execv(app_argv[LOADER_ARG_PATH], app_argv) < 0) { + char err_buf[1024]; + fprintf(stderr, "Failed to exeucte a file. errno: %d(%s)\n", + errno, strerror_r(errno, err_buf, sizeof(err_buf))); + exit(EXIT_FAILURE); + } +} + +int AppExecutor::Prepare() { + for (auto& func : prepare_funcs_) { + if (func() != 0) + return -1; + } + + return 0; +} + +int AppExecutor::StepCreateNewSession() { + setsid(); + return 0; +} + +int AppExecutor::StepPluginPrepareApp() { + return Plugin::PrepareApp(app_info_->GetAppId(), app_info_->GetBundle()); +} + +int AppExecutor::StepEnableExternalPackage() { + return _enable_external_pkg(app_info_->GetBundle().GetHandle(), + app_info_->GetPkgId().c_str(), + app_info_->IsGlobal() ? GLOBAL_USER : getuid()); +} + +int AppExecutor::StepEnableTrustAnchor() { + 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() returns %d", ret); + return -2; + } + + return 0; +} + +int AppExecutor::StepMountResDir() { + return _mount_res_dir(app_info_->GetRootPath().c_str(), + app_info_->GetBundle().GetHandle()); +} + +int AppExecutor::StepChangeMountNamespace() { + if (app_info_->GetBundle().GetType(kAulSdk) != BUNDLE_TYPE_NONE) + Debug::ChangeMountNamespace(); + + return 0; +} + +int AppExecutor::StepSecurityPrepareApp() { + auto enabled_light_user = app_info_->GetBundle().GetString( + 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.empty() ? nullptr : enabled_light_user.c_str()); + _W("security_manager_prepare_app2 -- %s", app_info_->GetAppId().c_str()); + if (ret != SECURITY_MANAGER_SUCCESS) { + _E("security_manager_prepare_app2() returns %d", ret); + return -2; + } + + return 0; +} + +int AppExecutor::StepSetupStdio() { + if (app_info_->GetBundle().GetType(kAulSdk) == BUNDLE_TYPE_NONE) + _setup_stdio(basename(const_cast(app_info_->GetAppPath().c_str()))); + + return 0; +} + +int AppExecutor::StepSetDumpable() { + prctl(PR_SET_DUMPABLE, 1); + return 0; +} + +int AppExecutor::StepSetProcessName() { + fs::path file_path(app_info_->GetAppPath()); + fs::path file_name = file_path.filename(); + prctl(PR_SET_NAME, file_name.c_str()); + return 0; +} + +int AppExecutor::StepSetEnvironments() { + Util::SetEnvironments(app_info_); + return 0; +} + +int AppExecutor::StepWaitTepMount() { + return _wait_tep_mount(app_info_->GetBundle().GetHandle()); +} + +int AppExecutor::StepPrepareAppSocketAndIdFile() { + if (app_info_->GetBundle().GetType(kAulSdk) != BUNDLE_TYPE_NONE) + return 0; + + if (_prepare_app_socket() < 0) + return -1; + + return _prepare_id_file(); +} + +int AppExecutor::StepSendStartupSignal() { + _send_cmd_to_amd(APP_STARTUP_SIGNAL); + return 0; +} + +void AppExecutor::CheckAndPrepareDebugging() { + auto& debug = Debug::GetInst(); + auto& b = app_info_->GetBundle(); + if (b.GetType(kAulSdk) != BUNDLE_TYPE_NONE) + debug.PrepareDebugger(b); + + debug.CheckAndSetAsanActivation(app_info_->GetAppId()); + debug.CheckWebAppDebugging(b); +} + +std::vector AppExecutor::GetLauncherArgv( + const std::string& app_type) { + std::vector argv; + auto found = std::find_if( + launcher_infos_.begin(), launcher_infos_.end(), + [app_type](const launchpad::LauncherInfoPtr& info) -> bool { + return std::find_if(info->GetAppTypes().begin(), + info->GetAppTypes().end(), + [app_type](const std::string& type) -> bool { + return type == app_type; + }) != info->GetAppTypes().end(); + }); + if (found == launcher_infos_.end()) + return argv; + + auto launcher_info = *found; + argv.insert(argv.end(), launcher_info->GetExe()); + argv.insert(argv.end(), launcher_info->GetExtraArgs().begin(), + launcher_info->GetExtraArgs().end()); + return argv; +} + +std::vector AppExecutor::CreateAppArgv(const std::string& app_path, + const tizen_base::Bundle& b, const std::string& app_type) { + auto& inst = launchpad::Debug::GetInst(); + std::vector argv = inst.GetArgv(); + if (inst.ShouldAttach()) + return argv; + + auto launcher_argv = GetLauncherArgv(app_type); + if (!launcher_argv.empty()) + argv.insert(argv.end(), launcher_argv.begin(), launcher_argv.end()); + + auto exported_argv = b.Export(); + exported_argv[LOADER_ARG_PATH] = app_path; + if (!exported_argv.empty()) + argv.insert(argv.end(), exported_argv.begin(), exported_argv.end()); + + auto extra_argv = inst.GetExtraArgv(); + if (!extra_argv.empty()) + argv.insert(argv.end(), extra_argv.begin(), extra_argv.end()); + + return argv; +} + +} // namespace launchpad diff --git a/src/launchpad-process-pool/app_executor.hh b/src/launchpad-process-pool/app_executor.hh new file mode 100644 index 0000000..78bebc9 --- /dev/null +++ b/src/launchpad-process-pool/app_executor.hh @@ -0,0 +1,74 @@ +/* + * 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 LAUNCHPAD_PROCESS_POOL_APP_EXECUTOR_HH_ +#define LAUNCHPAD_PROCESS_POOL_APP_EXECUTOR_HH_ + +#include + +#include +#include +#include + +#include + +#include "launchpad-process-pool/executor.hh" +#include "launchpad-process-pool/launcher_info.hh" + +namespace launchpad { + +class AppExecutor : public Executor::Delegator, + public Executor { + public: + AppExecutor(); + + pid_t Execute(const AppInfo* app_info); + + private: + void OnExecution() override; + + int Prepare(); + int StepCreateNewSession(); + int StepPluginPrepareApp(); + int StepEnableExternalPackage(); + int StepEnableTrustAnchor(); + int StepMountResDir(); + int StepChangeMountNamespace(); + int StepSecurityPrepareApp(); + int StepSetupStdio(); + int StepSetDumpable(); + int StepSetProcessName(); + int StepSetEnvironments(); + int StepWaitTepMount(); + int StepPrepareAppSocketAndIdFile(); + int StepSendStartupSignal(); + + void CheckAndPrepareDebugging(); + std::vector GetLauncherArgv(const std::string& app_type); + std::vector CreateAppArgv(const std::string& app_path, + const tizen_base::Bundle& b, const std::string& app_type); + + private: + using PrepareFunc = std::function; + + std::vector launcher_infos_; + std::vector prepare_funcs_; + const AppInfo* app_info_ = nullptr; +}; + +} // namespace launchpad + +#endif // LAUNCHPAD_PROCESS_POOL_APP_EXECUTOR_HH_ diff --git a/src/launchpad-process-pool/candidate_process_context.hh b/src/launchpad-process-pool/candidate_process_context.hh deleted file mode 100644 index b5073bf..0000000 --- a/src/launchpad-process-pool/candidate_process_context.hh +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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 LAUNCHPAD_PROCESS_POOL_CANDIDATE_PROCESS_CONTEXT_HH_ -#define LAUNCHPAD_PROCESS_POOL_CANDIDATE_PROCESS_CONTEXT_HH_ - -#include - -#include -#include - -#include "launchpad-process-pool/launchpad_io_channel.h" -#include "lib/common/inc/launchpad_common.h" - -#define CANDIDATE_NONE 0 - -enum candidate_process_state_e { - CANDIDATE_PROCESS_STATE_RUNNING, - CANDIDATE_PROCESS_STATE_PAUSED, -}; - -typedef struct { - int type = -1; - bool prepared = false; - int pid = - CANDIDATE_NONE; /* for hydra this pid is not the pid of hydra itself */ - /* but pid of non-hydra candidate, which was forked from hydra */ - int hydra_pid = CANDIDATE_NONE; - int loader_id = -1; - int caller_pid = CANDIDATE_NONE; - int send_fd = -1; - int hydra_fd = -1; - int last_exec_time = 0; - guint timer = 0; - char* loader_name = nullptr; - char* loader_path = nullptr; - char* loader_extra = nullptr; - int detection_method = 0; - int timeout_val = 0; - unsigned long long cpu_total_time = 0; - unsigned long long cpu_idle_time = 0; - int threshold = 0; - int threshold_max = 0; - int threshold_min = 0; - int cur_event = 0; - bool on_boot = false; - bool app_exists = false; - bool touched = false; - int activation_method = 0; - int deactivation_method = 0; - unsigned int ttl = 0; - guint live_timer = 0; - int state = 0; - bool is_hydra = false; - bool app_check = false; - io_channel_h client_channel = nullptr; - io_channel_h channel = nullptr; - io_channel_h hydra_channel = nullptr; - unsigned int score = 0; - uint64_t pss = 0; - int cpu_check_count = 0; - int on_boot_timeout = 0; - guint on_boot_timer = 0; - int sched_priority = 0; - std::vector condition_path_exists; -} candidate_process_context_t; - -#endif // LAUNCHPAD_PROCESS_POOL_CANDIDATE_PROCESS_CONTEXT_HH_ diff --git a/src/launchpad-process-pool/debugger_info.cc b/src/launchpad-process-pool/debugger_info.cc index b82890f..42cb0bd 100644 --- a/src/launchpad-process-pool/debugger_info.cc +++ b/src/launchpad-process-pool/debugger_info.cc @@ -50,6 +50,93 @@ constexpr const char kTagDefaultOpt[] = "DEFAULT_OPT"; namespace fs = std::filesystem; +DebuggerInfo::Builder& DebuggerInfo::Builder::SetName(std::string name) { + name_ = std::move(name); + return *this; +} + +DebuggerInfo::Builder& DebuggerInfo::Builder::SetExe(std::string exe) { + exe_ = std::move(exe); + return *this; +} + +DebuggerInfo::Builder& DebuggerInfo::Builder::AddAppType(std::string app_type) { + app_types_.push_back(std::move(app_type)); + return *this; +} + +DebuggerInfo::Builder& DebuggerInfo::Builder::AddExtraKey( + std::string extra_key) { + extra_keys_.push_back(std::move(extra_key)); + return *this; +} +DebuggerInfo::Builder& DebuggerInfo::Builder::AddExtraEnv( + std::string extra_env) { + extra_envs_.push_back(std::move(extra_env)); + return *this; +} + +DebuggerInfo::Builder& DebuggerInfo::Builder::AddFileToDelete( + std::string file) { + delete_files_.push_back(std::move(file)); + return *this; +} + +DebuggerInfo::Builder& DebuggerInfo::Builder::SetAttach(std::string attach) { + attach_ = std::move(attach); + return *this; +} + +DebuggerInfo::Builder& DebuggerInfo::Builder::AddLastExtraKey( + std::string last_extra_key) { + last_extra_keys_.push_back(std::move(last_extra_key)); + return *this; +} + +DebuggerInfo::Builder& DebuggerInfo::Builder::AddDefaultOpt( + std::string default_opt) { + default_opts_.push_back(std::move(default_opt)); + return *this; +} + +DebuggerInfo::Builder& DebuggerInfo::Builder::Reset() { + name_.clear(); + exe_.clear(); + app_types_.clear(); + extra_keys_.clear(); + extra_envs_.clear(); + delete_files_.clear(); + attach_.clear(); + last_extra_keys_.clear(); + default_opts_.clear(); + return *this; +} + +DebuggerInfo* DebuggerInfo::Builder::Build() { + return new DebuggerInfo(std::move(name_), std::move(exe_), + std::move(app_types_), std::move(extra_keys_), std::move(extra_envs_), + std::move(delete_files_), std::move(attach_), + std::move(last_extra_keys_), std::move(default_opts_)); +} + +DebuggerInfo::DebuggerInfo(std::string name, std::string exe, + std::vector app_types, + std::vector extra_keys, + std::vector extra_envs, + std::vector delete_files, + std::string attach, + std::vector last_extra_keys, + std::vector default_opts) + : name_(std::move(name)), + exe_(std::move(exe)), + app_types_(std::move(app_types)), + extra_keys_(std::move(extra_keys)), + extra_envs_(std::move(extra_envs)), + delete_files_(std::move(delete_files)), + attach_(std::move(attach)), + last_extra_keys_(std::move(last_extra_keys)), + default_opts_(std::move(default_opts)) {} + const std::string& DebuggerInfo::GetName() const { return name_; } @@ -63,15 +150,15 @@ const std::vector& DebuggerInfo::GetAppTypes() const { } const std::vector& DebuggerInfo::GetExtraKeyList() const { - return extra_key_list_; + return extra_keys_; } const std::vector& DebuggerInfo::GetExtraEnvList() const { - return extra_env_list_; + return extra_envs_; } const std::vector& DebuggerInfo::GetUnlinkList() const { - return unlink_list_; + return delete_files_; } const std::string& DebuggerInfo::GetAttachInfo() const { @@ -79,93 +166,151 @@ const std::string& DebuggerInfo::GetAttachInfo() const { } const std::vector& DebuggerInfo::GetLastExtraKeyList() const { - return last_extra_key_list_; + return last_extra_keys_; } const std::vector& DebuggerInfo::GetDefaultOptList() const { - return default_opt_list_; + return default_opts_; +} + +DebuggerInfoInflator::DebuggerInfoInflator() { + parsers_ = { + { kTagName, + std::bind(&DebuggerInfoInflator::ParseName, + this, std::placeholders::_1) }, + { kTagExe, + std::bind(&DebuggerInfoInflator::ParseExe, + this, std::placeholders::_1) }, + { kTagAppType, + std::bind(&DebuggerInfoInflator::ParseAppType, + this, std::placeholders::_1) }, + { kTagExtraKey, + std::bind(&DebuggerInfoInflator::ParseExtraKey, + this, std::placeholders::_1) }, + { kTagExtraEnv, + std::bind(&DebuggerInfoInflator::ParseExtraEnv, + this, std::placeholders::_1) }, + { kTagUnlink, + std::bind(&DebuggerInfoInflator::ParseUnlink, + this, std::placeholders::_1) }, + { kTagAttach, + std::bind(&DebuggerInfoInflator::ParseAttach, + this, std::placeholders::_1) }, + { kTagLastExtraKey, + std::bind(&DebuggerInfoInflator::ParseLastExtraKey, + this, std::placeholders::_1) }, + { kTagDefaultOpt, + std::bind(&DebuggerInfoInflator::ParseDefaultOpt, + this, std::placeholders::_1) }, + }; } -std::unordered_map DebuggerInfoInflator::Inflate( - const std::string_view path) { +std::unordered_map +DebuggerInfoInflator::Inflate(const std::string_view path) { fs::path input_path(path); if (fs::is_directory(input_path) == false) return debugger_infos_; - for (auto& entry : fs::directory_iterator(input_path)) { - fs::path file(entry.path()); - if (file.extension() == ".debugger") - Parse(file); + try { + for (auto& entry : fs::directory_iterator(input_path)) { + fs::path file(entry.path()); + if (file.extension() == ".debugger") + Parse(file); + } + } catch (const fs::filesystem_error& e) { + _E("Exception occurs. error(%s:%d)", e.what(), e.code().value()); } return debugger_infos_; } +void DebuggerInfoInflator::ParseName(std::string token) { + builder_.SetName(std::move(token)); +} + +void DebuggerInfoInflator::ParseExe(std::string token) { + builder_.SetExe(std::move(token)); +} + +void DebuggerInfoInflator::ParseAppType(std::string token) { + std::string line = std::move(token); + do { + auto tokens = Split(line, " |\t\r\n"); + for (auto& app_type : tokens) { + _D("app-type: %s", app_type.c_str()); + builder_.AddAppType(app_type); + } + } while (std::getline(string_stream_, line)); +} + +void DebuggerInfoInflator::ParseExtraKey(std::string token) { + builder_.AddExtraKey(std::move(token)); +} + +void DebuggerInfoInflator::ParseExtraEnv(std::string token) { + builder_.AddExtraEnv(std::move(token)); +} + +void DebuggerInfoInflator::ParseUnlink(std::string token) { + builder_.AddFileToDelete(std::move(token)); +} + +void DebuggerInfoInflator::ParseAttach(std::string token) { + builder_.SetAttach(std::move(token)); +} + +void DebuggerInfoInflator::ParseLastExtraKey(std::string token) { + builder_.AddLastExtraKey(std::move(token)); +} + +void DebuggerInfoInflator::ParseDefaultOpt(std::string token) { + builder_.AddDefaultOpt(std::move(token)); +} + void DebuggerInfoInflator::Parse(const fs::path& path) { std::ifstream input_file(path); if (!input_file.is_open()) return; - DebuggerInfoPtr current_info; + bool parsing = false; std::string input; while (std::getline(input_file, input)) { - std::istringstream ss(input); + string_stream_ = std::istringstream(input); std::string token1; - if (!(ss >> token1)) + if (!(string_stream_ >> token1)) continue; - std::string key = ToUpper(token1); + std::string key = ToUpper(std::move(token1)); if (key == kTagDebugger) { - if (current_info != nullptr) - InsertDebuggerInfo(std::move(current_info)); + if (parsing) + InsertDebuggerInfo(std::shared_ptr(builder_.Build())); - current_info = std::make_unique(); + builder_.Reset(); + parsing = true; continue; } - if (key.front() == '#' || current_info == nullptr) + if (parsing == false) continue; std::string token2; - if (!(ss >> token2)) + if (!(string_stream_ >> token2)) continue; - if (key == kTagName) { - current_info->name_ = std::move(token2); - } else if (key == kTagExe) { - current_info->exe_ = std::move(token2); - } else if (key == kTagAppType) { - ParseAndSetAppTypes(current_info.get(), ss, std::move(token2)); - } else if (key == kTagExtraKey) { - current_info->extra_key_list_.push_back(std::move(token2)); - } else if (key == kTagExtraEnv) { - current_info->extra_env_list_.push_back(std::move(token2)); - } else if (key == kTagUnlink) { - current_info->unlink_list_.push_back(std::move(token2)); - } else if (key == kTagAttach) { - current_info->attach_ = std::move(token2); - } else if (key == kTagLastExtraKey) { - current_info->last_extra_key_list_.push_back(std::move(token2)); - } else if (key == kTagDefaultOpt) { - current_info->default_opt_list_.push_back(std::move(token2)); - } - } + auto found = parsers_.find(key); + if (found == parsers_.end()) + continue; - if (current_info != nullptr) - InsertDebuggerInfo(std::move(current_info)); + auto& parser = found->second; + parser(std::move(token2)); + } input_file.close(); -} -void DebuggerInfoInflator::ParseAndSetAppTypes(DebuggerInfo* info, - std::istringstream& ss, std::string line) { - do { - auto tokens = Split(line, " |\t\r\n"); - for (auto& token : tokens) { - _D("app-type: %s", token.c_str()); - info->app_types_.push_back(std::move(token)); - } - } while (std::getline(ss, line)); + if (parsing) + InsertDebuggerInfo(std::shared_ptr(builder_.Build())); + + input_file.close(); } void DebuggerInfoInflator::InsertDebuggerInfo(DebuggerInfoPtr info) { diff --git a/src/launchpad-process-pool/debugger_info.hh b/src/launchpad-process-pool/debugger_info.hh index b02bdb1..c08fce5 100644 --- a/src/launchpad-process-pool/debugger_info.hh +++ b/src/launchpad-process-pool/debugger_info.hh @@ -18,6 +18,7 @@ #define LAUNCHPAD_PROCESS_POOL_DEBUGGER_INFO_HH_ #include +#include #include #include #include @@ -28,6 +29,42 @@ namespace launchpad { class DebuggerInfo { public: + class Builder { + public: + Builder& SetName(std::string name); + Builder& SetExe(std::string exe); + Builder& AddAppType(std::string app_type); + Builder& AddExtraKey(std::string extra_key); + Builder& AddExtraEnv(std::string extra_env); + Builder& AddFileToDelete(std::string file); + Builder& SetAttach(std::string attach); + Builder& AddLastExtraKey(std::string last_extra_key); + Builder& AddDefaultOpt(std::string default_opt); + Builder& Reset(); + + DebuggerInfo* Build(); + + private: + std::string name_; + std::string exe_; + std::vector app_types_; + std::vector extra_keys_; + std::vector extra_envs_; + std::vector delete_files_; + std::string attach_; + std::vector last_extra_keys_; + std::vector default_opts_; + }; + + DebuggerInfo(std::string name, std::string exe, + std::vector app_types, + std::vector extra_keys, + std::vector extra_envs, + std::vector delete_files, + std::string attach, + std::vector last_extra_keys, + std::vector default_opts); + const std::string& GetName() const; const std::string& GetExe() const; const std::vector& GetAppTypes() const; @@ -42,12 +79,12 @@ class DebuggerInfo { std::string name_; std::string exe_; std::vector app_types_; - std::vector extra_key_list_; - std::vector extra_env_list_; - std::vector unlink_list_; + std::vector extra_keys_; + std::vector extra_envs_; + std::vector delete_files_; std::string attach_; - std::vector last_extra_key_list_; - std::vector default_opt_list_; + std::vector last_extra_keys_; + std::vector default_opts_; friend class DebuggerInfoInflator; }; @@ -56,17 +93,30 @@ using DebuggerInfoPtr = std::shared_ptr; class DebuggerInfoInflator { public: + DebuggerInfoInflator(); + std::unordered_map Inflate( const std::string_view path); private: + void ParseName(std::string token); + void ParseExe(std::string token); + void ParseAppType(std::string token); + void ParseExtraKey(std::string token); + void ParseExtraEnv(std::string token); + void ParseUnlink(std::string token); + void ParseAttach(std::string token); + void ParseLastExtraKey(std::string token); + void ParseDefaultOpt(std::string token); void Parse(const std::filesystem::path& path); - void ParseAndSetAppTypes(DebuggerInfo* info, std::istringstream& ss, - std::string line); + void InsertDebuggerInfo(DebuggerInfoPtr info); private: + std::unordered_map> parsers_; std::unordered_map debugger_infos_; + std::istringstream string_stream_; + DebuggerInfo::Builder builder_; }; } // namespace launchpad diff --git a/src/launchpad-process-pool/executor.cc b/src/launchpad-process-pool/executor.cc new file mode 100644 index 0000000..74541d6 --- /dev/null +++ b/src/launchpad-process-pool/executor.cc @@ -0,0 +1,54 @@ +/* + * 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-process-pool/executor.hh" + +#include + +#include + +#include "launchpad-process-pool/log_private.hh" + +namespace launchpad { + +Executor::Executor(Executor::Delegator* delegator) : delegator_(delegator) {} + +pid_t Executor::Execute(int priority) { + pid_t pid = fork(); + if (pid == -1) { + _E("Failed to create child process. errno(%d)", errno); + return -1; + } + + if (pid == 0) { + if (priority != 0) + Util::SetPriority(priority); + + _W("security_manager_prepare_app_candidate ++"); + int ret = security_manager_prepare_app_candidate(); + _W("security_manager_prepare_app_candidate --"); + if (ret != SECURITY_MANAGER_SUCCESS) { + _E("Failed to prepare app candidate process. error(%d)", ret); + exit(1); + } + + delegator_->OnExecution(); + } + + return pid; +} + +} // namespace launchpad diff --git a/src/launchpad-process-pool/executor.hh b/src/launchpad-process-pool/executor.hh new file mode 100644 index 0000000..29078ff --- /dev/null +++ b/src/launchpad-process-pool/executor.hh @@ -0,0 +1,44 @@ +/* + * 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 LAUNCHPAD_PROCESS_POOL_EXECUTOR_HH_ +#define LAUNCHPAD_PROCESS_POOL_EXECUTOR_HH_ + +#include +#include + +namespace launchpad { + +class Executor { + public: + class Delegator { + public: + virtual ~Delegator() = default; + virtual void OnExecution() = 0; + }; + + explicit Executor(Delegator* delegator); + virtual ~Executor() = default; + + pid_t Execute(int priority = 0); + + private: + Delegator* delegator_; +}; + +} // namespace launchpad + +#endif // LAUNCHPAD_PROCESS_POOL_EXECUTOR_HH_ diff --git a/src/launchpad-process-pool/hydra_loader_context.cc b/src/launchpad-process-pool/hydra_loader_context.cc new file mode 100644 index 0000000..8718e9a --- /dev/null +++ b/src/launchpad-process-pool/hydra_loader_context.cc @@ -0,0 +1,184 @@ +/* + * 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-process-pool/hydra_loader_context.hh" + +#include +#include +#include + +#include + +#include "launchpad-process-pool/log_private.hh" +#include "lib/common/inc/launchpad_types.h" + +namespace fs = std::filesystem; + +namespace launchpad { +namespace { + +constexpr const char kHydraLoaderSocketName[] = ".hydra-loader"; +const int kSocketMaxBufferSize = 131071; + +} // namespace + +HydraLoaderContext::Builder::operator LoaderContext*() { + return new HydraLoaderContext(std::move(loader_info_), loader_id_, + caller_pid_, activated_); +} + +HydraLoaderContext::HydraLoaderContext(std::shared_ptr loader_info, + int loader_id, pid_t caller_pid, bool activated) + : LoaderContext(std::move(loader_info), loader_id, caller_pid, activated) { + Listen(); +} + +void HydraLoaderContext::Listen() { + try { + std::string socket_path = "/run/aul/daemons/" + std::to_string(getuid()) + + "/" + std::string(kHydraLoaderSocketName) + std::to_string(GetType()) + + "-" + std::to_string(GetLoaderId()); + if (fs::exists(socket_path)) + fs::remove(socket_path); + + hydra_socket_.reset(new ServerSocket()); + hydra_socket_->Bind(socket_path); + hydra_socket_->Listen(128); + + hydra_channel_.reset( + new IOChannel( + hydra_socket_->GetFd(), IOChannel::IOCondition::IO_IN, this)); + hydra_channel_->SetCloseOnDestroy(false); + } catch (const Exception& e) { + _E("Exception occurs. error: %s", e.what()); + THROW(e.GetErrorCode()); + } +} + +void HydraLoaderContext::Dispose() { + _D("Dispose hydra process. type(%d), loader_name(%s)", + GetType(), GetLoaderName().c_str()); + + LoaderContext::Dispose(); + if (hydra_pid_ > 0) { + _D("Kill process(%d)", hydra_pid_); + if (kill(hydra_pid_, SIGKILL) != 0) + _E("kill() is failed. pid(%d), errno(%d)", hydra_pid_, errno); + + hydra_pid_ = 0; + } + + client_channel_.reset(); + client_socket_.reset(); + hydra_prepared_ = false; +} + +pid_t HydraLoaderContext::Prepare() { + _W("Prepare"); + if (hydra_pid_ > 0 && client_socket_.get() != nullptr) { + PrepareCandidateProcess(); + return hydra_pid_; + } + + hydra_pid_ = LoaderContext::Prepare(); + SetPid(0); + return hydra_pid_; +} + +pid_t HydraLoaderContext::GetHydraPid() const { + return hydra_pid_; +} + +void HydraLoaderContext::SetHydraPid(pid_t hydra_pid) { + hydra_pid_ = hydra_pid; +} + +void HydraLoaderContext::PrepareCandidateProcess() { + _W("Send launch request to hydra loader. fd(%d)", client_socket_->GetFd()); + int cmd = static_cast(LAUNCH_CANDIDATE); + int ret = client_socket_->Send(static_cast(&cmd), sizeof(cmd)); + if (ret != 0) + _E("Failed to send candidate launch request. error(%d)", ret); +} + +void HydraLoaderContext::HandleHydraLoaderEvent() { + if (!hydra_prepared_) { + try { + client_socket_ = hydra_socket_->Accept(); + client_socket_->SetReceiveBufferSize(kSocketMaxBufferSize); + client_socket_->SetReceiveTimeout(5200); + client_socket_->SetSendBufferSize(kSocketMaxBufferSize); + + int pid = -1; + int ret = client_socket_->Receive(static_cast(&pid), sizeof(pid)); + if (ret != 0) { + _E("Receive() is failed. error: %d", ret); + client_socket_.reset(); + return; + } + + client_channel_.reset( + new IOChannel(client_socket_->GetFd(), + IOChannel::IOCondition::IO_IN | IOChannel::IOCondition::IO_HUP, + this)); + client_channel_->SetCloseOnDestroy(false); + hydra_prepared_ = true; + SECURE_LOGI("Type %d hydra loader was connected. pid: %d", + GetType(), GetHydraPid()); + } catch (const Exception& e) { + _E("Exception occurs. error: %s", e.what()); + return; + } + } else { + auto client_socket = hydra_socket_->Accept(); + _E("Refuse hydra process connection"); + } +} + +void HydraLoaderContext::HandleHydraLoaderClientEvent(int condition) { + if (condition & + (IOChannel::IOCondition::IO_HUP | IOChannel::IOCondition::IO_NVAL)) { + SECURE_LOGE("Type %d loader was disconnected. pid: %d", + GetType(), GetHydraPid()); + Dispose(); + Prepare(); + return; + } + + if (condition & IOChannel::IOCondition::IO_IN) { + pid_t pid = -1; + int ret = client_socket_->Receive(static_cast(&pid), sizeof(pid)); + if (ret != 0) { + _E("Receive() is failed. error(%d)", ret); + } else { + _W("Candidate process: %d", pid); + if (pid > 0) + SetPid(pid); + } + } +} + +void HydraLoaderContext::OnIOEventReceived(int fd, int condition) { + _W("[DEBUG] fd(%d), condition(%d)", fd, condition); + if (hydra_socket_.get() != nullptr && hydra_socket_->GetFd() == fd) + HandleHydraLoaderEvent(); + else if (client_socket_.get() != nullptr && client_socket_->GetFd() == fd) + HandleHydraLoaderClientEvent(condition); + else + LoaderContext::OnIOEventReceived(fd, condition); +} + +} // namespace launchpad diff --git a/src/launchpad-process-pool/hydra_loader_context.hh b/src/launchpad-process-pool/hydra_loader_context.hh new file mode 100644 index 0000000..88f2fbd --- /dev/null +++ b/src/launchpad-process-pool/hydra_loader_context.hh @@ -0,0 +1,62 @@ +/* + * 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 LAUNCHPAD_PROCESS_POOL_HYDRA_LOADER_CONTEXT_HH_ +#define LAUNCHPAD_PROCESS_POOL_HYDRA_LOADER_CONTEXT_HH_ + +#include + +#include + +#include "launchpad-process-pool/loader_context.hh" + +namespace launchpad { + +class HydraLoaderContext : public LoaderContext { + public: + class Builder : public LoaderContext::Builder { + public: + operator LoaderContext*() override; + }; + + HydraLoaderContext(std::shared_ptr loader_info, int loader_id, + pid_t caller_pid, bool activated); + + void Listen() override; + void Dispose() override; + pid_t Prepare() override; + + pid_t GetHydraPid() const; + void SetHydraPid(pid_t hydra_pid); + + private: + void PrepareCandidateProcess(); + void HandleHydraLoaderClientEvent(int condition); + void HandleHydraLoaderEvent(); + void OnIOEventReceived(int fd, int condition) override; + + private: + bool hydra_prepared_ = false; + pid_t hydra_pid_ = 0; + std::unique_ptr hydra_socket_; + std::unique_ptr hydra_channel_; + std::unique_ptr client_socket_; + std::unique_ptr client_channel_; +}; + +} // namespace launchpad + +#endif // LAUNCHPAD_PROCESS_POOL_HYDRA_LOADER_CONTEXT_HH_ diff --git a/src/launchpad-process-pool/launcher_info.cc b/src/launchpad-process-pool/launcher_info.cc index a8baacd..95646ad 100644 --- a/src/launchpad-process-pool/launcher_info.cc +++ b/src/launchpad-process-pool/launcher_info.cc @@ -16,19 +16,13 @@ #include "launchpad-process-pool/launcher_info.hh" -#include -#include -#include -#include -#include -#include -#include - #include #include #include #include +#include + #include "launchpad-process-pool/util.hh" #include "lib/common/inc/launchpad_common.h" @@ -45,6 +39,48 @@ constexpr const char kTagExtraArg[] = "EXTRA_ARG"; namespace fs = std::filesystem; +LauncherInfo::Builder& LauncherInfo::Builder::SetName(std::string name) { + name_ = std::move(name); + return *this; +} + +LauncherInfo::Builder& LauncherInfo::Builder::SetExe(std::string exe) { + exe_ = std::move(exe); + return *this; +} + +LauncherInfo::Builder& LauncherInfo::Builder::AddAppType(std::string app_type) { + app_types_.push_back(std::move(app_type)); + return *this; +} + +LauncherInfo::Builder& LauncherInfo::Builder::AddExtraArg( + std::string extra_arg) { + extra_args_.push_back(std::move(extra_arg)); + return *this; +} + +LauncherInfo::Builder& LauncherInfo::Builder::Reset() { + name_.clear(); + exe_.clear(); + app_types_.clear(); + extra_args_.clear(); + return *this; +} + +LauncherInfo* LauncherInfo::Builder::Build() { + return new LauncherInfo(std::move(name_), std::move(exe_), + std::move(app_types_), std::move(extra_args_)); +} + +LauncherInfo::LauncherInfo(std::string name, std::string exe, + std::vector app_types, std::vector extra_args) + : name_(std::move(name)), + exe_(std::move(exe)), + app_types_(std::move(app_types)), + extra_args_(std::move(extra_args)) { +} + const std::string& LauncherInfo::GetName() const { return name_; } @@ -61,86 +97,111 @@ const std::vector& LauncherInfo::GetExtraArgs() const { return extra_args_; } -void LauncherInfoInflator::Parse( - std::vector& launcher_info_list, - const fs::path& path) { - std::ifstream fp; - fp.open(path); - if (fp.fail()) +LauncherInfoInflator::LauncherInfoInflator() { + parsers_ = { + { kTagName, + std::bind(&LauncherInfoInflator::ParseName, + this, std::placeholders::_1) }, + { kTagExe, + std::bind(&LauncherInfoInflator::ParseExe, + this, std::placeholders::_1) }, + { kTagAppType, + std::bind(&LauncherInfoInflator::ParseAppType, + this, std::placeholders::_1) }, + { kTagExtraArg, + std::bind(&LauncherInfoInflator::ParseExtraArg, + this, std::placeholders::_1) }, + }; +} + +void LauncherInfoInflator::ParseName(std::string token) { + builder_.SetName(std::move(token)); +} + +void LauncherInfoInflator::ParseExe(std::string token) { + builder_.SetExe(std::move(token)); +} + +void LauncherInfoInflator::ParseAppType(std::string token) { + std::string line = std::move(token); + do { + auto tokens = Split(line, " |\t\r\n"); + for (auto& app_type : tokens) + builder_.AddAppType(app_type); + } while (std::getline(string_stream_, line)); +} + +void LauncherInfoInflator::ParseExtraArg(std::string token) { + builder_.AddExtraArg(std::move(token)); +} + +void LauncherInfoInflator::Parse(const fs::path& path) { + std::ifstream launcher_file; + launcher_file.open(path); + if (launcher_file.fail()) return; - LauncherInfoPtr info; - std::string input; - while (std::getline(fp, input)) { - std::istringstream ss(input); - std::string tok1, tok2; - if (!(ss >> tok1)) + bool parsing = false; + std::string line; + while (std::getline(launcher_file, line)) { + string_stream_ = std::istringstream(line); + std::string token1; + if (!(string_stream_ >> token1)) continue; - if (strcasecmp(kTagLauncher, tok1.c_str()) == 0) { - if (info != nullptr) { - _D("name: %s, exe: %s", info->name_.c_str(), info->exe_.c_str()); - launcher_info_list.push_back(std::move(info)); - } + std::string key = ToUpper(std::move(token1)); + if (key == kTagLauncher) { + if (parsing) + Insert(); - info = std::make_shared(); + builder_.Reset(); + parsing = true; continue; } - if (!(ss >> tok2)) + if (parsing == false) continue; - if (tok1.front() == '#' || info == nullptr) + + std::string token2; + if (!(string_stream_ >> token2)) continue; - std::string key; - std::transform(tok1.begin(), tok1.end(), std::back_inserter(key), - [](char ch) { return toupper(ch); }); - if (kTagName == key) { - info->name_ = std::move(tok2); - } else if (kTagExe == key) { - fs::path file(tok2); - if (fs::exists(file) == false) { - _E("Failed to access %s", tok2.c_str()); - info.reset(); - continue; - } + auto found = parsers_.find(key); + if (found == parsers_.end()) + continue; - info->exe_ = std::move(tok2); - } else if (kTagAppType == key) { - std::string line = std::move(tok2); - do { - auto tokens = Split(line, " |\t\r\n"); - for (auto& token : tokens) { - info->app_types_.push_back(std::move(token)); - } - } while (std::getline(ss, line)); - } else if (kTagExtraArg == key) { - info->extra_args_.push_back(std::move(tok2)); - } + auto& parser = found->second; + parser(std::move(token2)); } - fp.close(); - if (info) { - _D("name: %s, exe: %s", info->name_.c_str(), info->exe_.c_str()); - launcher_info_list.push_back(std::move(info)); - } + if (parsing) + Insert(); + + launcher_file.close(); +} + +void LauncherInfoInflator::Insert() { + launcher_infos_.emplace_back(builder_.Build()); } std::vector LauncherInfoInflator::Inflate( const std::string_view path) { - fs::path p(path); - if (fs::is_directory(p) == false) + fs::path dir_path(path); + if (fs::is_directory(dir_path) == false) return {}; - std::vector result; - for (auto& entry : fs::directory_iterator(p)) { - fs::path file(entry.path()); - if (file.extension() == ".launcher") { - Parse(result, file); + try { + for (auto& entry : fs::directory_iterator(dir_path)) { + fs::path file(entry.path()); + if (file.extension() == ".launcher") { + Parse(file); + } } + } catch (const fs::filesystem_error& e) { + _E("Exception occurs. error(%s:%d)", e.what(), e.code().value()); } - return result; + return launcher_infos_; } } // namespace launchpad diff --git a/src/launchpad-process-pool/launcher_info.hh b/src/launchpad-process-pool/launcher_info.hh index 0a7c178..975991c 100644 --- a/src/launchpad-process-pool/launcher_info.hh +++ b/src/launchpad-process-pool/launcher_info.hh @@ -14,43 +14,79 @@ * limitations under the License. */ -#ifndef LAUNCHER_INFO_HH_ -#define LAUNCHER_INFO_HH_ +#ifndef LAUNCHPAD_PROCESS_POOL_LAUNCHER_INFO_HH_ +#define LAUNCHPAD_PROCESS_POOL_LAUNCHER_INFO_HH_ #include +#include #include #include #include +#include #include namespace launchpad { class LauncherInfo { public: + class Builder { + public: + Builder& SetName(std::string name); + Builder& SetExe(std::string exe); + Builder& AddAppType(std::string app_type); + Builder& AddExtraArg(std::string extra_arg); + Builder& Reset(); + + LauncherInfo* Build(); + + private: + std::string name_; + std::string exe_; + std::vector app_types_; + std::vector extra_args_; + }; + + LauncherInfo(std::string name, std::string exe, + std::vector app_types, std::vector extra_args); + const std::string& GetName() const; const std::string& GetExe() const; const std::vector& GetAppTypes() const; const std::vector& GetExtraArgs() const; private: + friend class LauncherInfoInflator; + std::string name_; std::string exe_; std::vector app_types_; std::vector extra_args_; - friend class LauncherInfoInflator; }; using LauncherInfoPtr = std::shared_ptr; class LauncherInfoInflator { public: + LauncherInfoInflator(); + std::vector Inflate(const std::string_view path); private: - void Parse(std::vector& launcher_info_list, - const std::filesystem::path& path); + void Parse(const std::filesystem::path& path); + + void ParseName(std::string token); + void ParseExe(std::string token); + void ParseAppType(std::string token); + void ParseExtraArg(std::string token); + void Insert(); + + private: + std::unordered_map> parsers_; + std::istringstream string_stream_; + LauncherInfo::Builder builder_; + std::vector> launcher_infos_; }; } // namespace launchpad -#endif /* LAUNCHER_INFO_HH_ */ +#endif // LAUNCHPAD_PROCESS_POOL_LAUNCHER_INFO_HH_ diff --git a/src/launchpad-process-pool/launchpad.cc b/src/launchpad-process-pool/launchpad.cc index fcc11df..ac8aa35 100644 --- a/src/launchpad-process-pool/launchpad.cc +++ b/src/launchpad-process-pool/launchpad.cc @@ -19,2107 +19,39 @@ #include #include #include -#include -#include -#include -#include #include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include #include #include +#include #include #include #include +#include #include #include -#include "launchpad-process-pool/launchpad_io_channel.h" -#include "launchpad-process-pool/slot_info.h" -#include "lib/common/inc/key.h" #include "lib/common/inc/launchpad_common.h" #include "lib/common/inc/launchpad_plugin.h" #include "lib/common/inc/launchpad_types.h" -#include "lib/common/inc/perf.h" -#include "launchpad-process-pool/app_defined_loader_info_manager.hh" -#include "launchpad-process-pool/app_labels_monitor.hh" -#include "launchpad-process-pool/candidate_process_context.hh" #include "launchpad-process-pool/config.hh" -#include "launchpad-process-pool/debug.hh" -#include "launchpad-process-pool/dbus.hh" -#include "launchpad-process-pool/hw_acceleration_config.hh" -#include "launchpad-process-pool/language_config.hh" -#include "launchpad-process-pool/launcher_info.hh" -#include "launchpad-process-pool/loader_info.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 "launchpad-process-pool/util.hh" -#include "launchpad-process-pool/worker.hh" - -#define AUL_PR_NAME 16 -#define EXEC_CANDIDATE_EXPIRED 5 -#define EXEC_CANDIDATE_WAIT 1 -#define DIFF(a, b) (((a) > (b)) ? (a) - (b) : (b) - (a)) -#define HYDRA_NONE 0 -#define PROCESS_POOL_LAUNCHPAD_SOCK ".launchpad-process-pool-sock" -#define LOADER_PATH_DEFAULT "/usr/bin/launchpad-loader" -#define LOADER_INFO_PATH "/usr/share/aul" -#define OPT_SHARE_PATH "/opt/share" -#define LOADERS_PATH "loaders" -#define APP_DEFINED_LOADER_INFO_PATH OPT_SHARE_PATH "/" LOADERS_PATH -#define COMMON_LOADER_NAME "common-loader1" - -#define LAUNCHER_INFO_PATH LOADER_INFO_PATH -#define REGULAR_UID_MIN 5000 -#define PAD_ERR_FAILED -1 -#define PAD_ERR_REJECTED -2 -#define PAD_ERR_INVALID_ARGUMENT -3 -#define PAD_ERR_INVALID_PATH -4 -#define CPU_CHECKER_TIMEOUT 1000 -#define PI 3.14159265 -#define WIN_SCORE 100 -#define LOSE_SCORE_RATE 0.7f - -typedef struct { - GPollFD* gpollfd; - int type; - int loader_id; -} loader_context_t; - -typedef struct { - GQueue* queue; - guint timer; - guint idle_checker; - candidate_process_context_t* running_cpc; -} sequencer; - -struct app_launch_arg { - const char* appid; - const char* app_path; - const launchpad::AppInfo* app_info; - bundle* kb; -}; - -struct app_arg { - int argc; - char** argv; -}; - -struct app_info { - const char* type; - bool exists; -}; - -struct cleanup_info_s { - char* appid; - int pid; -}; - -typedef struct candidate_info_s { - char** argv; - int argc; - int loader_id; - int type; - pid_t pid; -} candidate_info_t; - -static void UpdateSlotStates(bool low_memory); -static void HandleMemoryStatusChangedEvent(bool low_memory); -static void HandleSigchld(pid_t pid); -static candidate_process_context_t* __find_slot_from_loader_name( - const char* loader_name); -static int __remove_slot(int type, int loader_id); -static void HandleAppLabelsChanged(); - -namespace { - -class CleanupInfo : public launchpad::Worker::Job { - public: - CleanupInfo(std::string appid, pid_t pid) - : appid_(std::move(appid)), pid_(pid) {} - - void Do() override { - _W("security_manager_cleanup_app() ++"); - security_manager_cleanup_app(appid_.c_str(), getuid(), pid_); - _W("security_manager_cleanup_app() --"); - } - - private: - std::string appid_; - pid_t pid_; -}; - -std::unique_ptr loader_info_manager; -int user_slot_offset; -GList* candidate_slot_list; -std::vector launcher_info_list; -GHashTable* __pid_table; -sequencer __sequencer; -std::unique_ptr cleaner; -std::unique_ptr hwacc_config; -std::unique_ptr lang_config; -std::unique_ptr region_format_config; - -} // namespace - -static candidate_process_context_t* __add_slot(slot_info_t* info); -static int __add_default_slots(void); -static gboolean __handle_idle_checker(gpointer data); -static int __add_idle_checker(int detection_method, GList* cur); -static void __dispose_candidate_process(candidate_process_context_t* cpc); -static void __update_slot_state(candidate_process_context_t* cpc, - launchpad::LoaderMethod method, - bool force); - -static gboolean __handle_queuing_slots(gpointer data) { - candidate_process_context_t* cpc; - unsigned long long total = 0; - unsigned long long idle = 0; - - if (__sequencer.idle_checker > 0) - return G_SOURCE_CONTINUE; - - if (g_queue_is_empty(__sequencer.queue)) { - __sequencer.timer = 0; - return G_SOURCE_REMOVE; - } - - cpc = reinterpret_cast( - g_queue_pop_head(__sequencer.queue)); - if (!cpc) { - _E("Critical error!"); - __sequencer.timer = 0; - return G_SOURCE_REMOVE; - } - - if (cpc->app_check && !cpc->app_exists) { - _W("The application is not installed. Type(%d)", cpc->type); - return G_SOURCE_CONTINUE; - } - - if (cpc->timer) { - g_source_remove(cpc->timer); - cpc->timer = 0; - } - - if (cpc->pid != CANDIDATE_NONE) { - _W("The slot(%d) is already running. pid(%d)", cpc->type, cpc->pid); - return G_SOURCE_CONTINUE; - } - - _get_cpu_idle(&total, &idle); - cpc->cpu_idle_time = idle; - cpc->cpu_total_time = total; - cpc->cpu_check_count = 0; - - __sequencer.idle_checker = - g_timeout_add(CPU_CHECKER_TIMEOUT, __handle_idle_checker, cpc); - __sequencer.running_cpc = cpc; - - _W("[__SEQUENCER__] Add idle checker. Type(%d)", cpc->type); - - return G_SOURCE_CONTINUE; -} - -static bool __sequencer_slot_is_running(candidate_process_context_t* cpc) { - if (__sequencer.running_cpc == cpc) - return true; - - return false; -} - -static bool __sequencer_slot_exist(candidate_process_context_t* cpc) { - GList* found; - - found = g_queue_find(__sequencer.queue, cpc); - if (found) - return true; - - return false; -} - -static int __sequencer_add_slot(candidate_process_context_t* cpc) { - if (__sequencer_slot_exist(cpc)) { - _W("Already exists"); - return -1; - } - - if (__sequencer_slot_is_running(cpc)) { - _W("slot(%d) is running", cpc->type); - return -1; - } - - g_queue_push_tail(__sequencer.queue, cpc); - - return 0; -} - -static void __sequencer_remove_slot(candidate_process_context_t* cpc) { - g_queue_remove(__sequencer.queue, cpc); -} - -static void __sequencer_run(void) { - if (__sequencer.timer) - return; - - __sequencer.timer = g_timeout_add(500, __handle_queuing_slots, nullptr); - if (!__sequencer.timer) - _E("Failed to add sequencer timer"); -} - -static void __sequencer_stop(void) { - if (!__sequencer.timer) - return; - - g_source_remove(__sequencer.timer); - __sequencer.timer = 0; -} - -static bool __sequencer_queue_is_empty(void) { - if (g_queue_is_empty(__sequencer.queue)) - return true; - - return false; -} - -static int __sequencer_init(void) { - _D("[__SEQUENCER__] Init"); - - __sequencer.queue = g_queue_new(); - if (!__sequencer.queue) { - _E("Out of memory"); - return -1; - } - - return 0; -} - -static void __sequencer_fini(void) { - _D("[__SEQUENCER__] Finish"); - - if (__sequencer.idle_checker > 0) - g_source_remove(__sequencer.idle_checker); - - if (__sequencer.timer > 0) - g_source_remove(__sequencer.timer); - - g_queue_free(__sequencer.queue); -} - -static int __make_loader_id(void) { - static int id = PAD_LOADER_ID_DYNAMIC_BASE; - - return ++id; -} - -static candidate_process_context_t* __find_slot_from_static_type(int type) { - candidate_process_context_t* cpc; - GList* iter = candidate_slot_list; - - if (type == static_cast(launchpad::LoaderType::Dynamic) || - type == static_cast(launchpad::LoaderType::Unsupported)) - return nullptr; - - while (iter) { - cpc = reinterpret_cast(iter->data); - if (type == cpc->type) - return cpc; - - iter = g_list_next(iter); - } - - return nullptr; -} - -static candidate_process_context_t* __find_slot_from_pid(int pid) { - candidate_process_context_t* cpc; - GList* iter = candidate_slot_list; - - while (iter) { - cpc = reinterpret_cast(iter->data); - if (pid == cpc->pid) - return cpc; - - iter = g_list_next(iter); - } - - return nullptr; -} - -static candidate_process_context_t* __find_hydra_slot_from_pid(int pid) { - candidate_process_context_t* cpc; - GList* iter = candidate_slot_list; - - while (iter) { - cpc = reinterpret_cast(iter->data); - if (cpc->is_hydra && pid == cpc->hydra_pid) - return cpc; - - iter = g_list_next(iter); - } - - return nullptr; -} - -static candidate_process_context_t* __find_slot_from_caller_pid( - int caller_pid) { - candidate_process_context_t* cpc; - GList* iter = candidate_slot_list; - - while (iter) { - cpc = reinterpret_cast(iter->data); - if (caller_pid == cpc->caller_pid) - return cpc; - - iter = g_list_next(iter); - } - - return nullptr; -} - -static candidate_process_context_t* __find_slot_from_loader_id(int id) { - candidate_process_context_t* cpc; - GList* iter = candidate_slot_list; - - while (iter) { - cpc = reinterpret_cast(iter->data); - if (id == cpc->loader_id) - return cpc; - - iter = g_list_next(iter); - } - - return nullptr; -} - -static candidate_process_context_t* __find_slot_from_loader_name( - const char* loader_name) { - candidate_process_context_t* cpc; - GList* iter = candidate_slot_list; - - while (iter) { - cpc = reinterpret_cast(iter->data); - if (strcmp(cpc->loader_name, loader_name) == 0) - return cpc; - - iter = g_list_next(iter); - } - - return nullptr; -} - -static candidate_process_context_t* __find_slot(int type, int loader_id) { - if (type == static_cast(launchpad::LoaderType::Dynamic)) - return __find_slot_from_loader_id(loader_id); - - return __find_slot_from_static_type(type); -} - -static void __update_slot_score(candidate_process_context_t* slot) { - if (!slot) - return; - - slot->score *= LOSE_SCORE_RATE; - slot->score += WIN_SCORE; -} - -static void __update_slots_pss(void) { - candidate_process_context_t* cpc; - GList* iter; - - iter = candidate_slot_list; - while (iter) { - cpc = reinterpret_cast(iter->data); - iter = g_list_next(iter); - - if (cpc->pid == CANDIDATE_NONE) - continue; - - launchpad::Procfs::GetPssMemory(cpc->pid, &cpc->pss); - } -} - -static gint __compare_slot(gconstpointer a, gconstpointer b) { - auto* slot_a = reinterpret_cast(a); - auto* slot_b = reinterpret_cast(b); - - if (slot_a->is_hydra && !slot_b->is_hydra) - return -1; - if (!slot_a->is_hydra && slot_b->is_hydra) - return 1; - - if (slot_a->score < slot_b->score) - return 1; - if (slot_a->score > slot_b->score) - return -1; - - if (slot_a->pss < slot_b->pss) - return -1; - if (slot_a->pss > slot_b->pss) - return 1; - - return 0; -} - -static candidate_process_context_t* __get_running_slot(bool is_hydra) { - candidate_process_context_t* cpc; - GList* iter; - - iter = candidate_slot_list; - while (iter) { - cpc = reinterpret_cast(iter->data); - if (cpc->is_hydra == is_hydra && cpc->pid != CANDIDATE_NONE) - return cpc; - - iter = g_list_next(iter); - } - - return nullptr; -} - -static void __pause_all_running_slots(bool is_hydra) { - candidate_process_context_t* cpc = nullptr; - GList* iter; - - iter = g_list_last(candidate_slot_list); - while (iter) { - cpc = reinterpret_cast(iter->data); - if (cpc->is_hydra == is_hydra && cpc->pid != CANDIDATE_NONE) { - __update_slot_state(cpc, launchpad::LoaderMethod::OutOfMemory, true); - if (!launchpad::MemoryMonitor::GetInst().IsLowMemory()) - return; - } - - iter = g_list_previous(iter); - } -} - -static void __resume_all_slots(void) { - candidate_process_context_t* cpc; - GList* iter; - - iter = candidate_slot_list; - while (iter) { - cpc = reinterpret_cast(iter->data); - __update_slot_state(cpc, launchpad::LoaderMethod::AvailableMemory, true); - - iter = g_list_next(iter); - } -} - -static void __kill_process(int pid) { - char err_str[MAX_LOCAL_BUFSZ] = { - 0, - }; - - if (kill(pid, SIGKILL) == -1) { - _E("send SIGKILL: %s", strerror_r(errno, err_str, sizeof(err_str))); - } -} - -static void __refuse_candidate_process(int server_fd) { - int client_fd = -1; - - if (server_fd == -1) { - _E("arguments error!"); - goto error; - } - - client_fd = accept(server_fd, nullptr, nullptr); - if (client_fd == -1) { - _E("accept error!"); - goto error; - } - - close(client_fd); - _D("refuse connection!"); - -error: - return; -} - -static int __accept_candidate_process(int server_fd, - int* out_client_fd, - int* out_client_pid, - int cpc_pid) { - int client_fd = -1; - int recv_pid = 0; - int ret; - socklen_t len; - struct ucred cred = {}; - - if (server_fd == -1 || out_client_fd == nullptr || - out_client_pid == nullptr) { - _E("arguments error!"); - goto error; - } - - client_fd = accept(server_fd, nullptr, nullptr); - if (client_fd == -1) { - _E("accept error!"); - goto error; - } - - if (_set_sock_option(client_fd, 1) < 0) { - _E("Failed to set sock option"); - goto error; - } - - ret = recv(client_fd, &recv_pid, sizeof(recv_pid), MSG_WAITALL); - if (ret == -1) { - _E("recv error!"); - goto error; - } - - len = (socklen_t)sizeof(cred); - ret = getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &cred, &len); - if (ret < 0) { - _E("getsockopt error"); - goto error; - } - - if (cpc_pid != -1 && cred.pid != cpc_pid) { - _E("Invalid accept. pid(%d)", cred.pid); - goto error; - } - - if (cred.pid != recv_pid) - _W("Not equal recv and real pid"); - - *out_client_fd = client_fd; - *out_client_pid = cred.pid; - - return *out_client_fd; - -error: - if (client_fd != -1) - close(client_fd); - - return -1; -} - -static int __listen_addr(struct sockaddr_un* addr) { - int fd = -1; - fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (fd < 0) { - _E("Socket error"); - goto error; - } - - unlink(addr->sun_path); - - _D("bind to %s", addr->sun_path); - if (bind(fd, (struct sockaddr*)addr, sizeof(struct sockaddr_un)) < 0) { - _E("bind error"); - goto error; - } - - _D("listen to %s", addr->sun_path); - if (listen(fd, MAX_PENDING_CONNECTIONS) == -1) { - _E("listen error"); - goto error; - } - - SECURE_LOGD("[launchpad] done, listen fd: %d", fd); - return fd; - -error: - if (fd != -1) - close(fd); - - return -1; -} - -static int __listen_candidate_process(int type, int loader_id) { - struct sockaddr_un addr; - - _D("[launchpad] enter, type: %d", type); - - memset(&addr, 0x00, sizeof(struct sockaddr_un)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/daemons/%u/%s%d-%d", - SOCKET_PATH, getuid(), LAUNCHPAD_LOADER_SOCKET_NAME, type, loader_id); - return __listen_addr(&addr); -} - -static int __listen_hydra_process(int type, int loader_id) { - struct sockaddr_un addr; - - _D("[launchpad] enter, type: %d", type); - - memset(&addr, 0x00, sizeof(struct sockaddr_un)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/daemons/%d/%s%d-%d", - SOCKET_PATH, getuid(), HYDRA_LOADER_SOCKET_NAME, type, loader_id); - return __listen_addr(&addr); -} - -static int __get_loader_id(bundle* kb) { - const char* val; - - val = bundle_get_val(kb, AUL_K_LOADER_ID); - if (val == nullptr) - return -1; - _W("Requested loader id: %s", val); - - return atoi(val); -} - -static int __candidate_process_real_launch(int candidate_fd, app_pkt_t* pkt) { - return _send_pkt_raw(candidate_fd, pkt); -} - -static int __fork_app_process(int (*child_fn)(void*), void* arg, - int sched_priority) { - int pid; - int ret; - - pid = fork(); - if (pid == -1) { - _E("failed to fork child process"); - return -1; - } - - if (pid == 0) { - if (sched_priority != 0) - _set_priority(sched_priority); - - _W("security_manager_prepare_app_candidate ++"); - ret = security_manager_prepare_app_candidate(); - _W("security_manager_prepare_app_candidate --"); - if (ret != SECURITY_MANAGER_SUCCESS) { - _E("failed to prepare app candidate process (%d)", ret); - exit(1); - } - - ret = child_fn(arg); - _E("failed to exec app process (%d)", errno); - exit(ret); - } - - return pid; -} - -static int __exec_loader_process(void* arg) { - char** argv = static_cast(arg); - char err_buf[1024]; - - launchpad::SignalManager::GetInst().UnblockSigchld(); - _close_all_fds(); - _setup_stdio(basename(argv[LOADER_ARG_PATH])); - - if (execv(argv[LOADER_ARG_PATH], argv) < 0) { - fprintf(stderr, "Failed to execute a file. path: %s, errno: %d(%s)\n", - argv[LOADER_ARG_PATH], errno, - strerror_r(errno, err_buf, sizeof(err_buf))); - exit(EXIT_FAILURE); - } - - return 0; -} - -static gboolean __handle_deactivate_event(gpointer user_data) { - auto* cpc = reinterpret_cast(user_data); - __update_slot_state(cpc, launchpad::LoaderMethod::Ttl, false); - _D("Deactivate event: type(%d), loader_name(%s)", - cpc->type, cpc->loader_name); - - return G_SOURCE_REMOVE; -} - -static void __set_live_timer(candidate_process_context_t* cpc) { - if (!cpc) - return; - - if (cpc->deactivation_method & - static_cast(launchpad::LoaderMethod::Ttl)) { - if (cpc->live_timer == 0) { - cpc->live_timer = - g_timeout_add_seconds(cpc->ttl, __handle_deactivate_event, cpc); - } - } -} - -static int __hydra_send_request(int fd, enum hydra_cmd cmd) { - size_t sent = 0; - size_t size = sizeof(cmd); - ssize_t send_ret = 0; - - while (sent != size) { - send_ret = send(fd, reinterpret_cast(&cmd) + sent, size - sent, - MSG_NOSIGNAL); - if (send_ret == -1) { - _E("send error! (%d)", errno); - return -1; - } - - sent += send_ret; - _D("send(%d: ret: %zd) : %zd / %zd", fd, send_ret, sent, size); - } - - return 0; -} - -static int __hydra_send_launch_candidate_request(int fd) { - SECURE_LOGD("Send launch cmd to hydra, fd: %d", fd); - return __hydra_send_request(fd, LAUNCH_CANDIDATE); -} - -static void __candidate_info_free(candidate_info_t* info) { - int i; - - if (info == nullptr) - return; - - if (info->argv) { - for (i = 0; i < info->argc; i++) - free(info->argv[i]); - - free(info->argv); - } - - free(info); -} - -static int __candidate_info_create(candidate_process_context_t* cpt, - candidate_info_t** candidate_info) { - char type_str[12] = { 0, }; - char loader_id_str[12] = { 0, }; - char argbuf[LOADER_ARG_LEN]; - candidate_info_t* info; - - if (cpt == nullptr) - return -EINVAL; - - info = static_cast(calloc(1, sizeof(candidate_info_t))); - if (info == nullptr) { - _E("calloc() is failed"); - return -ENOMEM; - } - - info->argv = static_cast(calloc(LOADER_ARG_DUMMY + 1, sizeof(char*))); - if (info->argv == nullptr) { - _E("calloc() is failed"); - __candidate_info_free(info); - return -ENOMEM; - } - - memset(argbuf, ' ', LOADER_ARG_LEN); - argbuf[LOADER_ARG_LEN - 1] = '\0'; - info->argv[LOADER_ARG_DUMMY] = strdup(argbuf); - - snprintf(loader_id_str, sizeof(loader_id_str), "%d", cpt->loader_id); - snprintf(type_str, sizeof(type_str), "%d", cpt->type); - info->argv[LOADER_ARG_PATH] = strdup(cpt->loader_path); - info->argv[LOADER_ARG_TYPE] = strdup(type_str); - info->argv[LOADER_ARG_ID] = strdup(loader_id_str); - info->argv[LOADER_ARG_HYDRA] = strdup(cpt->is_hydra ? "1" : "0"); - info->argv[LOADER_ARG_EXTRA] = strdup(cpt->loader_extra); - - info->argc = LOADER_ARG_DUMMY + 1; - info->type = cpt->type; - info->loader_id = cpt->loader_id; - - *candidate_info = info; - return 0; -} - -static int __prepare_candidate_process(int type, int loader_id) { - candidate_process_context_t* cpt = __find_slot(type, loader_id); - candidate_info_t* info; - int ret; - - if (cpt == nullptr) - return -1; - - if (cpt->is_hydra && cpt->hydra_pid != HYDRA_NONE) - return __hydra_send_launch_candidate_request(cpt->hydra_fd); - - _D("prepare candidate process / type:%d", type); - ret = __candidate_info_create(cpt, &info); - if (ret < 0) - return ret; - - info->pid = __fork_app_process(__exec_loader_process, info->argv, - cpt->sched_priority); - if (info->pid == -1) { - _E("Failed to create a child process. type: %d", type); - __candidate_info_free(info); - return -1; - } - - _W("Candidate process. type: %d, loader_id: %d, pid: %d", - info->type, info->loader_id, info->pid); - cpt = __find_slot(info->type, info->loader_id); - if (cpt == nullptr) { - _E("Not found slot."); - __candidate_info_free(info); - return -1; - } - - cpt->last_exec_time = time(nullptr); - if (cpt->is_hydra) { - cpt->hydra_pid = info->pid; - } else { - cpt->pid = info->pid; - __set_live_timer(cpt); - } - - launchpad::Log::Print("[CANDIDATE]", "pid(%7d) | type(%d) | loader(%s)", - info->pid, cpt->loader_id, cpt->loader_name); - launchpad::MemoryMonitor::GetInst().Reset(); - __candidate_info_free(info); - return 0; -} - -static gboolean __handle_timeout_event(gpointer user_data) { - auto* cpc = reinterpret_cast(user_data); - cpc->timer = 0; - - _W("type(%d), loader_name(%s), state(%d)", - cpc->type, cpc->loader_name, cpc->state); - if (cpc->pid != CANDIDATE_NONE) { - _W("Candidate(%d) process(%d) is running", cpc->type, cpc->pid); - return G_SOURCE_REMOVE; - } - - __sequencer_add_slot(cpc); - __sequencer_run(); - return G_SOURCE_REMOVE; -} - -static void __set_timer(candidate_process_context_t* cpc) { - if (cpc == nullptr || cpc->timer > 0) { - _E("Invalid parameter"); - return; - } - - _W("type(%d), loader_name(%s), state(%d)", - cpc->type, cpc->loader_name, cpc->state); - if ((cpc->detection_method & - static_cast(launchpad::LoaderMethod::Timeout)) && - cpc->state == CANDIDATE_PROCESS_STATE_RUNNING) { - cpc->timer = g_timeout_add(cpc->timeout_val, __handle_timeout_event, cpc); - if (cpc->timer == 0) - _E("g_timeout_add() is failed. %d:%s", cpc->type, cpc->loader_name); - } else { - _E("Skip adding timer. detection_method(%d), state(%d)", - cpc->detection_method, cpc->state); - } -} - -static void __reset_slot(candidate_process_context_t* cpc) { - if (cpc == nullptr) - return; - - cpc->send_fd = -1; - cpc->prepared = false; - cpc->pid = CANDIDATE_NONE; - cpc->client_channel = nullptr; - cpc->timer = 0; - cpc->live_timer = 0; - cpc->on_boot_timer = 0; -} - -static void __dispose_candidate_process(candidate_process_context_t* cpc) { - if (!cpc) - return; - - _D("Dispose candidate process %d:%s", cpc->type, cpc->loader_name); - if (cpc->pid > 0) { - _D("kill process %d", cpc->pid); - __kill_process(cpc->pid); - } - if (cpc->live_timer > 0) - g_source_remove(cpc->live_timer); - if (cpc->client_channel) - _io_channel_destroy(cpc->client_channel); - if (cpc->timer > 0) - g_source_remove(cpc->timer); - if (cpc->send_fd > 0) - close(cpc->send_fd); - if (cpc->on_boot_timer > 0) - g_source_remove(cpc->on_boot_timer); - __reset_slot(cpc); -} - -static void __dispose_hydra_process(candidate_process_context_t* cpc) { - if (!cpc) - return; - - __dispose_candidate_process(cpc); - - _D("Dispose hydra process %d:%s", cpc->type, cpc->loader_name); - if (cpc->hydra_pid > 0) { - _D("kill process %d", cpc->hydra_pid); - __kill_process(cpc->hydra_pid); - cpc->hydra_pid = HYDRA_NONE; - } - - if (cpc->hydra_fd > 0) { - close(cpc->hydra_fd); - cpc->hydra_fd = -1; - } -} - -static int __send_launchpad_loader(candidate_process_context_t* cpc, - app_pkt_t* pkt, const char* app_path, int clifd) { - int pid = -1; - int ret; - - ret = _delete_sock_path(cpc->pid, getuid()); - if (ret != 0) - return -1; - - __candidate_process_real_launch(cpc->send_fd, pkt); - _W("Request to candidate process, pid: %d, bin path: %s", cpc->pid, app_path); - - pid = cpc->pid; - cpc->pid = CANDIDATE_NONE; - __dispose_candidate_process(cpc); - __set_timer(cpc); - __update_slot_score(cpc); - - return pid; -} - -static int __normal_fork_exec(int argc, char** argv, const char* app_path) { - char* libdir; - char err_buf[1024]; - - _D("start real fork and exec"); - - libdir = _get_libdir(app_path); - if (libdir) { - setenv("LD_LIBRARY_PATH", libdir, 1); - free(libdir); - } - - _close_all_fds(); - - if (execv(argv[LOADER_ARG_PATH], argv) < 0) { - fprintf(stderr, "Failed to execute a file. path: %s, errno: %d(%s)\n", - argv[LOADER_ARG_PATH], errno, - strerror_r(errno, err_buf, sizeof(err_buf))); - exit(EXIT_FAILURE); - } - - return 0; -} - -static std::vector GetLauncherArgv( - const std::string& app_type) { - std::vector argv; - auto found = std::find_if(launcher_info_list.begin(), - launcher_info_list.end(), - [app_type](const launchpad::LauncherInfoPtr& info) -> bool { - return std::find_if(info->GetAppTypes().begin(), - info->GetAppTypes().end(), - [app_type](const std::string& type) -> bool { - return type == app_type; - }) != info->GetAppTypes().end(); - }); - if (found == launcher_info_list.end()) - return argv; - - auto launcher_info = *found; - argv.insert(argv.end(), launcher_info->GetExe()); - argv.insert(argv.end(), launcher_info->GetExtraArgs().begin(), - launcher_info->GetExtraArgs().end()); - return argv; -} - -static std::vector CreateAppArgv(const std::string& app_path, - const tizen_base::Bundle& b, const std::string& app_type) { - auto& inst = launchpad::Debug::GetInst(); - std::vector argv = inst.GetArgv(); - if (inst.ShouldAttach()) - return argv; - - auto launcher_argv = GetLauncherArgv(app_type); - if (!launcher_argv.empty()) - argv.insert(argv.end(), launcher_argv.begin(), launcher_argv.end()); - - auto exported_argv = b.Export(); - exported_argv[LOADER_ARG_PATH] = app_path; - if (!exported_argv.empty()) - argv.insert(argv.end(), exported_argv.begin(), exported_argv.end()); - - auto extra_argv = inst.GetExtraArgv(); - if (!extra_argv.empty()) - argv.insert(argv.end(), extra_argv.begin(), extra_argv.end()); - - return argv; -} - -static void __real_launch(const char* app_path, bundle* kb, - const launchpad::AppInfo* app_info) { - tizen_base::Bundle b(kb, false, false); - launchpad::Debug::CheckWebAppDebugging(b); - - std::vector argv = CreateAppArgv(app_path, b, - app_info->GetAppType().c_str()); - char** app_argv = static_cast(calloc(argv.size() + 1, sizeof(char*))); - if (app_argv == nullptr) { - _E("Out of memory"); - exit(-1); - } - - int app_argc = argv.size(); - for (int i = 0; i < app_argc; i++) { - app_argv[i] = const_cast(argv[i].c_str()); - SECURE_LOGD("input argument %d : %s##", i, app_argv[i]); - } - - PERF("setup argument done"); - __normal_fork_exec(app_argc, app_argv, app_path); - free(app_argv); -} - -static int __prepare_exec(const char* appid, const char* app_path, - const launchpad::AppInfo* app_info, bundle* kb) { - char* file_name; - const char* enabled_light_user; - char process_name[AUL_PR_NAME]; - int ret; - - /* 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(); - - ret = _launchpad_plugin_prepare_app(appid, kb); - if (ret < 0) { - _E("_launchpad_plugin_prepare_app() is failed. error(%d)", ret); - return PAD_ERR_FAILED; - } - - ret = _enable_external_pkg(kb, app_info->GetPkgId().c_str(), - app_info->IsGlobal() ? GLOBAL_USER : getuid()); - if (ret < 0) - return PAD_ERR_FAILED; - - 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() returns %d", ret); - return PAD_ERR_REJECTED; - } - - ret = _mount_res_dir(app_info->GetRootPath().c_str(), kb); - if (ret < 0) - return PAD_ERR_FAILED; - - if (bundle_get_type(kb, AUL_K_SDK) != BUNDLE_TYPE_NONE) - launchpad::Debug::ChangeMountNamespace(); - - /* SET PRIVILEGES*/ - 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) - return PAD_ERR_REJECTED; - - if (bundle_get_type(kb, AUL_K_SDK) == BUNDLE_TYPE_NONE) - _setup_stdio(basename(app_path)); - - /* SET DUMPABLE - for coredump*/ - prctl(PR_SET_DUMPABLE, 1); - - /* SET PROCESS NAME*/ - if (app_path == nullptr) - return PAD_ERR_INVALID_ARGUMENT; - - file_name = const_cast(strrchr(app_path, '/')); - if (file_name == nullptr) - return PAD_ERR_INVALID_PATH; - - file_name++; - if (*file_name == '\0') - return PAD_ERR_INVALID_PATH; - - memset(process_name, '\0', AUL_PR_NAME); - snprintf(process_name, AUL_PR_NAME, "%s", file_name); - prctl(PR_SET_NAME, process_name); - - /* SET ENVIROMENT*/ - launchpad::Util::SetEnvironments(app_info); - - ret = _wait_tep_mount(kb); - if (ret < 0) - return PAD_ERR_FAILED; - - if (bundle_get_type(kb, AUL_K_SDK) == BUNDLE_TYPE_NONE) { - ret = _prepare_app_socket(); - if (ret < 0) - return PAD_ERR_FAILED; - - ret = _prepare_id_file(); - if (ret < 0) - return PAD_ERR_FAILED; - } - - _send_cmd_to_amd(APP_STARTUP_SIGNAL); - return 0; -} - -static int __exec_app_process(void* arg) { - auto* launch_arg = static_cast(arg); - int ret; - - launchpad::UserTracer::Print( - std::to_string(getpid()) + "|after calling fork(). " + - std::string(launch_arg->appid)); - _D("lock up test log(no error) : fork done"); - - tizen_base::Bundle b(launch_arg->kb, false, false); - if (b.GetType(AUL_K_SDK) != BUNDLE_TYPE_NONE) - launchpad::Debug::GetInst().PrepareDebugger(b); - - launchpad::Debug::GetInst().CheckAndSetAsanActivation(launch_arg->appid); - - launchpad::SignalManager::GetInst().UnblockSigchld(); - _delete_sock_path(getpid(), getuid()); - - PERF("prepare exec - first done"); - ret = __prepare_exec(launch_arg->appid, launch_arg->app_path, - launch_arg->app_info, launch_arg->kb); - if (ret < 0) - return ret; - - PERF("prepare exec - second done"); - __real_launch(launch_arg->app_path, launch_arg->kb, launch_arg->app_info); - - return PAD_ERR_FAILED; -} - -static int LaunchDirectly(const launchpad::AppInfo* app_info) { - struct app_launch_arg arg = { - .appid = app_info->GetAppId().c_str(), - .app_path = app_info->GetAppPath().c_str(), - .app_info = app_info, - .kb = app_info->GetBundle().GetHandle(), - }; - - launchpad::UserTracer::Print( - "before calling fork(). " + std::string(arg.appid)); - int pid = __fork_app_process(__exec_app_process, &arg, 0); - if (pid <= 0) - _E("Failed to fork app process"); - - SECURE_LOGD("==> real launch pid: %d, app_path: %s", pid, arg.app_path); - return pid; -} - -static bool __handle_loader_client_event(int fd, io_condition_e cond, - void* data) { - auto* cpc = static_cast(data); - if (cpc == nullptr) - return false; - - if (cond & (IO_HUP | IO_NVAL)) { - SECURE_LOGE( - "Type %d candidate process was " - "(POLLHUP|POLLNVAL), pid: %d", - cpc->type, cpc->pid); - cpc->pid = CANDIDATE_NONE; - __dispose_candidate_process(cpc); - __prepare_candidate_process(cpc->type, cpc->loader_id); - return false; - } - - return true; -} - -static bool __handle_hydra_client_event(int fd, io_condition_e cond, - void* data) { - auto* cpc = static_cast(data); - int recv_pid = -1; - int ret; - - if (cpc == nullptr) - return false; - - if (cond & (IO_HUP | IO_NVAL)) { - SECURE_LOGE( - "Type %d hydra process was " - "(POLLHUP|POLLNVAL), pid: %d", - cpc->type, cpc->hydra_pid); - __dispose_hydra_process(cpc); - __prepare_candidate_process(cpc->type, cpc->loader_id); - return false; - } - - if (cond & IO_IN) { - ret = recv(cpc->hydra_fd, &recv_pid, sizeof(recv_pid), MSG_WAITALL); - if (ret == -1) { - _E("recv() is failed. errno(%d)", errno); - } else { - _W("candidate process: %d", recv_pid); - if (recv_pid > 1) - cpc->pid = recv_pid; - } - } - - return true; -} - -static bool __handle_loader_event(int fd, io_condition_e cond, void* data) { - auto* cpc = static_cast(data); - int client_fd; - int client_pid; - int ret; - - if (cpc == nullptr) - return false; - - if (!cpc->prepared) { - ret = __accept_candidate_process(fd, &client_fd, &client_pid, - cpc->is_hydra ? -1 : cpc->pid); - if (ret >= 0) { - /* for hydra need to set pid to pid of non-hydra candidate, */ - /* which is connecting now */ - if (cpc->is_hydra) - cpc->pid = client_pid; - - cpc->prepared = true; - cpc->send_fd = client_fd; - - SECURE_LOGI( - "Type %d candidate process was connected, " - "pid: %d", - cpc->type, cpc->pid); - - _print_hwc_log( - "Type %d candidate process was connected, " - "pid: %d", - cpc->type, cpc->pid); - cpc->client_channel = _io_channel_create( - client_fd, static_cast(IO_IN | IO_HUP), - __handle_loader_client_event, cpc); - if (!cpc->client_channel) - close(client_fd); - } - } else { - __refuse_candidate_process(fd); - _E("Refused candidate process connection"); - } - - return true; -} - -static bool __handle_hydra_event(int fd, io_condition_e cond, void* data) { - auto* cpc = static_cast(data); - int client_fd; - int client_pid; - int ret; - - if (cpc == nullptr) - return false; - - if (!cpc->prepared) { - ret = - __accept_candidate_process(fd, &client_fd, &client_pid, cpc->hydra_pid); - if (ret >= 0) { - cpc->hydra_fd = client_fd; - - SECURE_LOGD( - "Type %d hydra process was connected," - " pid: %d", - cpc->type, cpc->hydra_pid); - - cpc->client_channel = _io_channel_create( - client_fd, static_cast(IO_IN | IO_HUP), - __handle_hydra_client_event, cpc); - if (!cpc->client_channel) - close(client_fd); - } - } else { - __refuse_candidate_process(fd); - _E("Refused hydra process connection"); - } - - return true; -} - -static void HandleSigchld(pid_t pid) { - char* appid = static_cast( - g_hash_table_lookup(__pid_table, GINT_TO_POINTER(pid))); - if (appid) { - cleaner->Add(std::make_shared(appid, pid)); - g_hash_table_remove(__pid_table, GINT_TO_POINTER(pid)); - } - - launchpad::Log::Print("[SIGCHLD]", "pid(%7d)", pid); - candidate_process_context_t* cpc = __find_slot_from_pid(pid); - if (cpc != nullptr) { - cpc->pid = CANDIDATE_NONE; - __dispose_candidate_process(cpc); - __prepare_candidate_process(cpc->type, cpc->loader_id); - } else { - cpc = __find_hydra_slot_from_pid(pid); - if (cpc != nullptr) { - cpc->hydra_pid = HYDRA_NONE; - __dispose_hydra_process(cpc); - __prepare_candidate_process(cpc->type, cpc->loader_id); - } - } - - cpc = __find_slot_from_caller_pid(pid); - while (cpc) { - __remove_slot(static_cast(launchpad::LoaderType::Dynamic), - cpc->loader_id); - cpc = __find_slot_from_caller_pid(pid); - } -} - -static void HandleAppLabelsChanged() { - GList* iter = candidate_slot_list; - while (iter) { - auto* cpc = reinterpret_cast(iter->data); - if (cpc->is_hydra) { - if (cpc->hydra_pid > 0) { - __dispose_hydra_process(cpc); - __prepare_candidate_process(cpc->type, cpc->loader_id); - } - } else if (cpc->pid > 0) { - __dispose_candidate_process(cpc); - __prepare_candidate_process(cpc->type, cpc->loader_id); - } - - iter = g_list_next(iter); - } -} - -static float __interpolator(float input, int cpu_max, int cpu_min) { - float ret; - float min = cpu_min / 100.0f; - float max = cpu_max / 100.0f; - - if (input > 1.0f) - input = 1.0f; - if (input < 0.0f) - input = 0.0f; - - ret = cos(input * PI) / 2.0f + 0.5f; - ret *= max - min; - ret += min; - - return ret; -} - -static void __update_threshold(candidate_process_context_t* cpc, float delta) { - static float pos = 0.0f; - - pos += delta; - if (pos < 0.0f) - pos = 0.0f; - - if (pos > 1.0f) - pos = 1.0f; - - cpc->threshold = static_cast( - __interpolator(pos, cpc->threshold_max, cpc->threshold_min) * 100); - _D("[CPU] type:%d / delta:%f / input cursor : %f / threshold : %d", - cpc->type, delta, pos, cpc->threshold); -} - -static gboolean __handle_idle_checker(gpointer data) { - unsigned long long total = 0; - unsigned long long idle = 0; - int per; - candidate_process_context_t* cpc; - - if (!data) { - _E("Critical error!"); - __sequencer.idle_checker = 0; - __sequencer.running_cpc = nullptr; - return G_SOURCE_REMOVE; - } - - cpc = reinterpret_cast(data); - if (cpc->app_check && !cpc->app_exists) { - _W("The application is not installed. loader(%s:%d)", - cpc->loader_name, cpc->type); - __sequencer.idle_checker = 0; - __sequencer.running_cpc = nullptr; - return G_SOURCE_REMOVE; - } - - if (cpc->state != CANDIDATE_PROCESS_STATE_RUNNING) { - _W("Slot state is not running. loader(%s:%d)", cpc->loader_name, cpc->type); - __sequencer.idle_checker = 0; - __sequencer.running_cpc = nullptr; - return G_SOURCE_REMOVE; - } - - if (cpc->pid != CANDIDATE_NONE) { - _W("Slot is already running. %d:%s:%d", - cpc->type, cpc->loader_name, cpc->pid); - __sequencer.idle_checker = 0; - __sequencer.running_cpc = nullptr; - return G_SOURCE_REMOVE; - } - - _get_cpu_idle(&total, &idle); - if (total == cpc->cpu_total_time) - total++; - - per = (idle - cpc->cpu_idle_time) * 100 / (total - cpc->cpu_total_time); - _D("[CPU] Idle : %d / loader(%s:%d)", per, cpc->loader_name, cpc->type); - - if (per >= cpc->threshold) { - __update_threshold(cpc, -0.02f * (per - cpc->threshold)); - __prepare_candidate_process(cpc->type, cpc->loader_id); - cpc->touched = true; - __sequencer.idle_checker = 0; - __sequencer.running_cpc = nullptr; - return G_SOURCE_REMOVE; - } - - cpc->cpu_idle_time = idle; - cpc->cpu_total_time = total; - __update_threshold(cpc, 0.05f); - - cpc->cpu_check_count++; - if (cpc->cpu_check_count == - launchpad::Config::GetInst().GetCPUChecker().GetMaxCount()) { - _W("CPU check count has exceeded %d times. loader(%s:%d)", - cpc->cpu_check_count, cpc->loader_name, cpc->type); - __sequencer.idle_checker = 0; - __sequencer.running_cpc = nullptr; - __sequencer_add_slot(cpc); - return G_SOURCE_REMOVE; - } - - return G_SOURCE_CONTINUE; -} - -static gboolean __on_boot_timeout_cb(gpointer user_data) { - auto* context = static_cast(user_data); - - _W("type(%d), loader_name(%s)", context->type, context->loader_name); - context->on_boot_timer = 0; - if (context->pid != CANDIDATE_NONE) { - _E("Candidate process is already running. %d:%s:%d", - context->type, context->loader_name, context->pid); - } else { - auto iter = context->condition_path_exists.begin(); - while (iter != context->condition_path_exists.end()) { - auto& path = *iter; - if (access(path.c_str(), F_OK) != 0) { - _D("%s does not exist", path.c_str()); - context->on_boot_timer = g_timeout_add(100, __on_boot_timeout_cb, - context); - return G_SOURCE_REMOVE; - } - - iter = context->condition_path_exists.erase(iter); - } - - __prepare_candidate_process(context->type, context->loader_id); - context->touched = true; - } - - return G_SOURCE_REMOVE; -} - -static void __add_on_boot_timer(candidate_process_context_t* context) { - if (context->on_boot_timer != 0) - return; - - context->on_boot_timer = - g_timeout_add(context->on_boot_timeout, __on_boot_timeout_cb, context); -} - -static int __add_idle_checker(int detection_method, GList* cur) { - candidate_process_context_t* cpc; - GList* iter = cur; - - while (iter) { - cpc = reinterpret_cast(iter->data); - if (!cpc->touched && cpc->on_boot && cpc->on_boot_timeout > 0) - __add_on_boot_timer(cpc); - - if (cpc->state != CANDIDATE_PROCESS_STATE_RUNNING) { - iter = g_list_next(iter); - continue; - } - - if (strcmp("null", cpc->loader_path) == 0) { - iter = g_list_next(iter); - continue; - } - - if (!cpc->touched && !cpc->on_boot) { - iter = g_list_next(iter); - continue; - } - - if (cpc->app_check && !cpc->app_exists) { - iter = g_list_next(iter); - continue; - } - - if (cpc->pid == CANDIDATE_NONE && - (!cpc->touched || (cpc->detection_method & detection_method))) { - if (cpc->timer > 0) { - g_source_remove(cpc->timer); - cpc->timer = 0; - } - - cpc->cur_event = detection_method; - __sequencer_add_slot(cpc); - __sequencer_run(); - } - - iter = g_list_next(iter); - } - - return -1; -} - -static int __check_caller_by_pid(int pid) { - std::string attr = launchpad::Procfs::GetAttrCurrent(pid); - if (attr.empty()) - return -1; - - if (attr.compare("User") == 0 || - attr.compare("System") == 0 || - attr.compare("System::Privileged") == 0) - return 0; - - return -1; -} - -static bool __is_hw_acc(const char* hwacc) { - if (strcmp(hwacc, "USE") == 0 || - (strcmp(hwacc, "SYS") == 0 && - hwacc_config->Get() == SETTING_HW_ACCELERATION_ON)) - return true; - - return false; -} - -static candidate_process_context_t* __find_available_slot( - const char* hwacc, - const char* app_type, - const char* loader_name, - candidate_process_context_t** org_cpc) { - launchpad::LoaderType type = launchpad::LoaderType::Unsupported; - candidate_process_context_t* cpc; - - if (loader_name && loader_name[0] != '\0') { - for (auto& info : loader_info_manager->GetLoaderInfoList()) { - if (info->GetName() == loader_name) { - type = info->GetType(); - break; - } - } - } else { - if (__is_hw_acc(hwacc)) - type = loader_info_manager->FindHwType(app_type); - else - type = loader_info_manager->FindSwType(app_type); - } - - cpc = __find_slot(static_cast(type), PAD_LOADER_ID_STATIC); - if (!cpc) - return nullptr; - - *org_cpc = cpc; - - if (cpc->prepared) - return cpc; - - auto a_types = loader_info_manager->GetAlternativeTypes(type); - if (a_types.empty()) - return nullptr; - - for (auto& a_type : a_types) { - cpc = __find_slot(static_cast(a_type), PAD_LOADER_ID_STATIC); - if (!cpc) - continue; - if (cpc->prepared) { - return cpc; - } - } - - return nullptr; -} - -static void __update_slot(int type, bool app_exists) { - candidate_process_context_t* cpc; - - cpc = __find_slot(type, PAD_LOADER_ID_STATIC); - if (!cpc) - return; - - cpc->app_exists = app_exists; - _W("type(%d), loader_name(%s), app_check(%d), app_exists(%d)", - cpc->type, cpc->loader_name, cpc->app_check, cpc->app_exists); - if (cpc->app_check && !cpc->app_exists) { - if (cpc->pid > 0) - __dispose_candidate_process(cpc); - __sequencer_remove_slot(cpc); - if (__sequencer_queue_is_empty()) - __sequencer_stop(); - } else { - if (cpc->state != CANDIDATE_PROCESS_STATE_RUNNING) - return; - - if (!cpc->touched && !cpc->on_boot) - return; - - if (cpc->timer > 0) { - g_source_remove(cpc->timer); - cpc->timer = 0; - } - - if (cpc->pid == CANDIDATE_NONE) { - __sequencer_add_slot(cpc); - __sequencer_run(); - } - } -} - -static void __deactivate_slot(candidate_process_context_t* cpc) { - _W("type(%d), loader_name(%s), state(%d)", - cpc->type, cpc->loader_name, cpc->state); - if (cpc->state == CANDIDATE_PROCESS_STATE_PAUSED) - return; - - cpc->state = CANDIDATE_PROCESS_STATE_PAUSED; - if (cpc->is_hydra) - __dispose_hydra_process(cpc); - else - __dispose_candidate_process(cpc); -} - -static void __activate_slot(candidate_process_context_t* cpc) { - _W("type(%d), loader_name(%s), state(%d)", - cpc->type, cpc->loader_name, cpc->state); - if (cpc->state == CANDIDATE_PROCESS_STATE_RUNNING) - return; - - cpc->state = CANDIDATE_PROCESS_STATE_RUNNING; - if (!cpc->touched && !cpc->on_boot) - return; - - if ((cpc->app_check && !cpc->app_exists) || cpc->pid > CANDIDATE_NONE) - return; - - if (cpc->detection_method & - static_cast(launchpad::LoaderMethod::Timeout)) - __set_timer(cpc); -} - -static void __update_slot_state(candidate_process_context_t* cpc, - launchpad::LoaderMethod method, bool force) { - _W("type(%d), loader_name(%s), state(%d), method(%d), force(%d)", - cpc->type, cpc->loader_name, cpc->state, static_cast(method), force); - switch (method) { - case launchpad::LoaderMethod::OutOfMemory: - if ((force || cpc->deactivation_method & static_cast(method)) && - launchpad::MemoryMonitor::GetInst().IsLowMemory()) { - _W("Low memory, deactivate slot %d", cpc->type); - __deactivate_slot(cpc); - } else { - __activate_slot(cpc); - } - break; - case launchpad::LoaderMethod::Ttl: - if (force || cpc->deactivation_method & static_cast(method)) - __deactivate_slot(cpc); - break; - case launchpad::LoaderMethod::AvailableMemory: - if (force || cpc->activation_method & static_cast(method)) - __activate_slot(cpc); - break; - case launchpad::LoaderMethod::Request: - if (force || cpc->activation_method & static_cast(method)) - __update_slot_state(cpc, launchpad::LoaderMethod::OutOfMemory, force); - break; - default: - __activate_slot(cpc); - break; - } -} - -static void __destroy_slot(candidate_process_context_t* cpc) { - if (!cpc) - return; - - if (cpc->hydra_channel) - _io_channel_destroy(cpc->hydra_channel); - - if (cpc->channel) - _io_channel_destroy(cpc->channel); - - if (cpc->loader_extra) - free(cpc->loader_extra); - - if (cpc->loader_path) - free(cpc->loader_path); - - if (cpc->loader_name) - free(cpc->loader_name); - - delete cpc; -} - -static candidate_process_context_t* __create_slot(slot_info_t* info) { - candidate_process_context_t* cpc; - - cpc = new candidate_process_context_t(); - if (cpc == nullptr) { - _E("Out of memory"); - return nullptr; - } - - cpc->loader_name = strdup(info->loader_name); - if (cpc->loader_name == nullptr) { - _E("Failed to duplicate loader name(%s)", info->loader_name); - __destroy_slot(cpc); - return nullptr; - } - - cpc->loader_path = strdup(info->loader_path); - if (cpc->loader_path == nullptr) { - _E("Failed to duplicate loader path(%s)", info->loader_path); - __destroy_slot(cpc); - return nullptr; - } - - cpc->loader_extra = - info->loader_extra ? strdup(info->loader_extra) : strdup(""); - if (cpc->loader_extra == nullptr) { - _E("Failed to duplicate loader extra(%s)", info->loader_extra); - __destroy_slot(cpc); - return nullptr; - } - - cpc->type = info->type; - cpc->prepared = false; - cpc->pid = CANDIDATE_NONE; - cpc->hydra_pid = HYDRA_NONE; - cpc->caller_pid = info->caller_pid; - cpc->loader_id = info->loader_id; - cpc->send_fd = -1; - cpc->hydra_fd = -1; - cpc->last_exec_time = 0; - cpc->timer = 0; - cpc->detection_method = info->detection_method; - cpc->timeout_val = info->timeout_val; - cpc->cpu_total_time = 0; - cpc->cpu_idle_time = 0; - cpc->threshold = info->threshold_max; - cpc->threshold_max = info->threshold_max; - cpc->threshold_min = info->threshold_min; - cpc->on_boot = info->on_boot; - cpc->app_exists = info->app_exists; - cpc->touched = false; - cpc->cur_event = 0; - cpc->activation_method = info->activation_method; - cpc->deactivation_method = info->deactivation_method; - cpc->ttl = info->ttl; - cpc->live_timer = 0; - cpc->is_hydra = info->is_hydra; - cpc->app_check = info->app_check; - cpc->client_channel = nullptr; - cpc->channel = nullptr; - cpc->hydra_channel = nullptr; - cpc->score = WIN_SCORE; - cpc->pss = 0; - cpc->cpu_check_count = 0; - cpc->on_boot_timeout = info->on_boot_timeout; - cpc->on_boot_timer = 0; - cpc->sched_priority = info->sched_priority; - cpc->condition_path_exists = info->condition_path_exists; - - if ((cpc->deactivation_method & - static_cast(launchpad::LoaderMethod::OutOfMemory)) && - launchpad::MemoryMonitor::GetInst().IsLowMemory()) - cpc->state = CANDIDATE_PROCESS_STATE_PAUSED; - else - cpc->state = CANDIDATE_PROCESS_STATE_RUNNING; - - _W("loader(%s), type(%d), state(%d)", - cpc->loader_name, cpc->type, cpc->state); - return cpc; -} - -static candidate_process_context_t* __add_slot(slot_info_t* info) { - candidate_process_context_t* cpc; - int fd; - io_channel_h channel; - int hydra_fd; - io_channel_h hydra_channel; - - if (info == nullptr) - return nullptr; - - if (__find_slot(info->type, info->loader_id) != nullptr) - return nullptr; - - cpc = __create_slot(info); - if (cpc == nullptr) - return nullptr; - - fd = __listen_candidate_process(cpc->type, cpc->loader_id); - if (fd == -1) { - _E("Listening the socket to the type %d candidate process failed.", - cpc->type); - __destroy_slot(cpc); - return nullptr; - } - - channel = _io_channel_create(fd, IO_IN, __handle_loader_event, cpc); - if (!channel) { - close(fd); - __destroy_slot(cpc); - return nullptr; - } - - cpc->channel = channel; - - if (info->is_hydra) { - hydra_fd = __listen_hydra_process(cpc->type, cpc->loader_id); - if (hydra_fd == -1) { - _E("Listening the socket to the type %d hydra process failed.", - cpc->type); - __destroy_slot(cpc); - return nullptr; - } - - hydra_channel = - _io_channel_create(hydra_fd, IO_IN, __handle_hydra_event, cpc); - if (!hydra_channel) { - close(hydra_fd); - __destroy_slot(cpc); - return nullptr; - } - - cpc->hydra_channel = hydra_channel; - } - - candidate_slot_list = g_list_append(candidate_slot_list, cpc); - - return cpc; -} - -static int __remove_slot(int type, int loader_id) { - candidate_process_context_t* cpc; - GList* iter; - - iter = candidate_slot_list; - while (iter) { - cpc = reinterpret_cast(iter->data); - if (type == cpc->type && loader_id == cpc->loader_id) { - __dispose_candidate_process(cpc); - candidate_slot_list = g_list_delete_link(candidate_slot_list, iter); - __destroy_slot(cpc); - return 0; - } - - iter = g_list_next(iter); - } - - return -1; -} - -static int __verify_loader_caps(const char* loader) { - cap_t cap_d; - cap_flag_value_t eff_state; - cap_flag_value_t inh_state; - cap_value_t values[] = {CAP_SETGID, CAP_MAC_ADMIN}; - int r; - int i; - int size = ARRAY_SIZE(values); - - /* If Dytransition feature is enabled, CAP_MAC_ADMIN is unnecessary */ - if (!launchpad::AppLabelsMonitor::GetInst().IsDisposed()) - size--; - - cap_d = cap_get_file(loader); - if (!cap_d) { - _E("Failed to get cap from file(%s)", loader); - return -1; - } - - for (i = 0; i < size; i++) { - r = cap_get_flag(cap_d, values[i], CAP_INHERITABLE, &inh_state); - if (r != 0) { - _E("Failed to get cap inh - errno(%d)", errno); - cap_free(cap_d); - return -1; - } - - r = cap_get_flag(cap_d, values[i], CAP_EFFECTIVE, &eff_state); - if (r != 0) { - _E("Failed to get cap eff - errno(%d)", errno); - cap_free(cap_d); - return -1; - } - - if ((inh_state != CAP_SET) || (eff_state != CAP_SET)) { - _E("The %s doesn't have %d cap", loader, values[i]); - cap_free(cap_d); - return -1; - } - } - cap_free(cap_d); - - return 0; -} - -static void __get_app_type_string(const launchpad::LoaderInfoPtr& info, - char buf[], size_t size) { - char* ptr = buf; - - for (auto& app_type : info->GetAppTypes()) { - if (size < app_type.size() + 1) - return; - - strncpy(ptr, app_type.c_str(), size); - ptr += app_type.size(); - size -= app_type.size(); - (*ptr++) = ' '; - size--; - } -} - -static void __add_slot_from_info(const launchpad::LoaderInfoPtr& info) { - candidate_process_context_t* cpc; - bundle_raw* extra = nullptr; - int len; - char buf[2048] = { - 0, - }; - - slot_info_t slot_info = { - .type = LAUNCHPAD_LOADER_TYPE_USER + user_slot_offset, - .loader_name = info->GetName().c_str(), - .loader_path = info->GetExe().c_str(), - .threshold_max = info->GetCpuThresholdMax(), - .threshold_min = info->GetCpuThresholdMin(), - .app_exists = info->IsAppExists(), - .is_hydra = info->IsHydraEnabled(), - .app_check = info->IsNeededAppCheck(), - .on_boot_timeout = info->GetOnbootTimeout(), - .sched_priority = info->GetSchedPriority(), - .condition_path_exists = info->GetConditionPathExists() - }; - - if (info->GetExe() == "null") { - slot_info.loader_id = PAD_LOADER_ID_DIRECT; - - cpc = __add_slot(&slot_info); - if (cpc == nullptr) - return; - - info->SetType(static_cast( - static_cast(launchpad::LoaderType::User) + user_slot_offset)); - user_slot_offset++; - return; - } else if (access(info->GetExe().c_str(), F_OK | X_OK) == 0) { - if (__verify_loader_caps(info->GetExe().c_str()) < 0) - return; - - bundle_encode(info->GetExtra().GetHandle(), &extra, &len); - - slot_info.loader_id = PAD_LOADER_ID_STATIC; - slot_info.loader_extra = (const char*)extra; - slot_info.detection_method = static_cast(info->GetDetectionMethod()); - slot_info.activation_method = static_cast(info->GetActivationMethod()); - slot_info.deactivation_method = static_cast( - info->GetDeactivationMethod()); - slot_info.ttl = info->GetTtl(); - slot_info.timeout_val = info->GetTimeoutVal(); - slot_info.on_boot = info->IsOnBoot(); - - cpc = __add_slot(&slot_info); - bundle_free_encoded_rawdata(&extra); - if (cpc == nullptr) - return; - - info->SetType(static_cast( - static_cast(launchpad::LoaderType::User) + user_slot_offset)); - user_slot_offset++; - __get_app_type_string(info, buf, sizeof(buf)); - _I("candidate slot. app-type(%s) loader-type(%d)", - buf, static_cast(info->GetType())); - _print_hwc_log("candidate slot. app-type(%s) loader-type(%d)", - buf, static_cast(info->GetType())); - } -} - -static int __add_default_slots(void) { - loader_info_manager = - std::make_unique(LOADER_INFO_PATH); - - loader_info_manager->Load(); - user_slot_offset = 0; - for (auto& info : loader_info_manager->GetLoaderInfoList()) { - __add_slot_from_info(info); - } - __add_idle_checker(0, candidate_slot_list); - - return 0; -} - -static void UpdateSlotStates(bool low_memory) { - GList* iter = candidate_slot_list; - while (iter) { - auto* context = reinterpret_cast(iter->data); - iter = g_list_next(iter); - - if (low_memory) { - __update_slot_state(context, launchpad::LoaderMethod::OutOfMemory, true); - } else { - __update_slot_state(context, launchpad::LoaderMethod::AvailableMemory, - true); - } - } -} - -static void HandleMemoryStatusChangedEvent(bool low_memory) { - if (low_memory) { - candidate_process_context_t* cpc = __get_running_slot(false); - if (cpc == nullptr) - return; - - _W("Low memory"); - __update_slots_pss(); - - candidate_slot_list = g_list_sort(candidate_slot_list, __compare_slot); - __pause_all_running_slots(false); - } else { - __resume_all_slots(); - } -} +#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/loader_manager.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 "launchpad-process-pool/util.hh" +#include "launchpad-process-pool/worker.hh" namespace launchpad { namespace { @@ -2127,8 +59,26 @@ namespace { constexpr const char kRunAulDaemonsPath[] = "/run/aul/daemons/"; constexpr const char kLaunchpadProcessPoolSock[] = ".launchpad-process-pool-sock"; +constexpr const char kInfoDirectoryPath[] = "/usr/share/aul"; const int kReceivedBufferSize = 131071; const int kMaxPendingConnection = 128; +const uid_t kRegularUidMin = 5000; + +class CleanupInfo : public launchpad::Worker::Job { + public: + CleanupInfo(std::string appid, pid_t pid) + : appid_(std::move(appid)), pid_(pid) {} + + void Do() override { + _W("security_manager_cleanup_app() ++"); + security_manager_cleanup_app(appid_.c_str(), getuid(), pid_); + _W("security_manager_cleanup_app() --"); + } + + private: + std::string appid_; + pid_t pid_; +}; int GetLaunchpadFdFromSystemd() { const std::string path = kRunAulDaemonsPath + std::to_string(getuid()) + @@ -2181,12 +131,35 @@ void PrintAppInfo(const AppInfo* app_info) { SECURE_LOGD("pkg_type: %s", app_info->GetPkgType().c_str()); } +int CheckCallerPermission(pid_t caller_pid) { + std::string attr_current = Procfs::GetAttrCurrent(caller_pid); + if (attr_current.empty()) + return -1; + + if (attr_current.compare("User") == 0 || + attr_current.compare("System") == 0 || + attr_current.compare("System::Privileged") == 0) + return 0; + + return -1; +} + +int GetLoaderIdFromBundle(const tizen_base::Bundle& b) { + auto loader_id = b.GetString(kAulLoaderId); + if (loader_id.empty()) + return -1; + + _W("Requested loader id: %s", loader_id.c_str()); + return std::stoi(loader_id); +} + } // namespace Launchpad::Launchpad(int argc, char** argv) : argc_(argc), argv_(argv), - loop_(g_main_loop_new(nullptr, FALSE)) { + loop_(g_main_loop_new(nullptr, FALSE)), + app_executor_(new AppExecutor()) { handlers_ = { { PAD_CMD_VISIBILITY, std::bind(&Launchpad::HandleVisibilityRequest, this, @@ -2250,9 +223,6 @@ void Launchpad::Quit() { bool Launchpad::OnCreate() { UserTracer user_tracer( std::string(__FUNCTION__) + "(" + std::to_string(__LINE__) + ")"); - if (__sequencer_init() < 0) - return false; - launchpad::SignalManager::GetInst().SetEventListener(this); try { @@ -2265,125 +235,51 @@ bool Launchpad::OnCreate() { return false; } - auto& label_monitor = AppLabelsMonitor::GetInst(); - label_monitor.Init(); - label_monitor.SetEventListener(this); - MemoryMonitor::GetInst().SetEventListener(this); - __add_default_slots(); - - launchpad::LauncherInfoInflator inflator; - launcher_info_list = inflator.Inflate(LAUNCHER_INFO_PATH); + LoaderManager::GetInst().AddDefaultLoaderContexts(); launchpad::Debug::GetInst().Init(); - try { - app_defined_loader_info_manager_.reset(new AppDefinedLoaderInfoManager()); - app_defined_loader_info_manager_->SetEventListener(this); - } catch (const Exception& e) { - _E("Exception occurs. error: %s", e.what()); - } - _send_cmd_to_amd(LAUNCHPAD_LAUNCH_SIGNAL); - __pid_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, - nullptr, free); - if (__pid_table == nullptr) { - _E("Failed to create pid table"); - return false; - } + lang_config_.reset(new LanguageConfig()); + region_format_config_.reset(new RegionFormatConfig()); - hwacc_config.reset(new HWAccelerationConfig()); - lang_config.reset(new LanguageConfig()); - region_format_config.reset(new RegionFormatConfig()); - - cleaner.reset(new Worker("cleaner+")); + cleaner_.reset(new Worker("cleaner+")); Log::Init(); return true; } void Launchpad::OnTerminate() { Log::Finish(); - cleaner.reset(); - region_format_config.reset(); - lang_config.reset(); - hwacc_config.reset(); - - if (__pid_table != nullptr) - g_hash_table_destroy(__pid_table); + cleaner_.reset(); + region_format_config_.reset(); + lang_config_.reset(); + pid_map_.clear(); _send_cmd_to_amd(LAUNCHPAD_DEAD_SIGNAL); Debug::GetInst().Dispose(); - launcher_info_list.clear(); - app_defined_loader_info_manager_.reset(); - MemoryMonitor::GetInst().Dispose(); - AppLabelsMonitor::GetInst().Dispose(); + LoaderManager::GetInst().Dispose(); channel_.reset(); socket_.reset(); SignalManager::GetInst().Dispose(); - __sequencer_fini(); } void Launchpad::HandleVisibilityRequest(std::shared_ptr request) { - __add_idle_checker(static_cast(LoaderMethod::Visibility), - candidate_slot_list); + LoaderManager::GetInst().ActivateLoaderContexts(LoaderMethod::Visibility); request->SendResult(0); _D("[PAD_CMD_VISIBILITY]"); } void Launchpad::HandleAddLoaderRequest(std::shared_ptr request) { - _W("[PAD_CMD_ADD_LOADER] BEGIN"); - auto& b = request->GetBundle(); - auto loader_path = b.GetString(kAulLoaderPath); - if (loader_path.empty()) { - _E("Failed to get loader path"); - request->SendResult(-1); - return; - } - - auto caller_pid_str = b.GetString(kAulCallerPid); - if (caller_pid_str.empty()) { - _E("Failed to get caller pid"); - request->SendResult(-1); - return; - } - - auto extra = b.GetString(kAulLoaderExtra); - int loader_id = __make_loader_id(); - std::string loader_name = loader_path + caller_pid_str + - std::to_string(loader_id); - slot_info_t slot_info; - slot_info.type = static_cast(LoaderType::Dynamic); - slot_info.loader_id = loader_id; - slot_info.caller_pid = std::stoi(caller_pid_str); - slot_info.loader_name = loader_name.c_str(); - slot_info.loader_path = loader_path.c_str(); - slot_info.loader_extra = extra.c_str(); - slot_info.detection_method = static_cast( - LoaderMethod::Timeout | LoaderMethod::Visibility); - slot_info.activation_method = static_cast( - LoaderMethod::Request | LoaderMethod::AvailableMemory); - slot_info.deactivation_method = static_cast( - LoaderMethod::Ttl | LoaderMethod::OutOfMemory); - slot_info.ttl = 600; - slot_info.timeout_val = 2000; - slot_info.threshold_max = DefaultCpuThresholdMax; - slot_info.threshold_min = DefaultCpuThresholdMin; - slot_info.on_boot = false; - slot_info.app_exists = true; - slot_info.is_hydra = false; - slot_info.app_check = true; - slot_info.on_boot_timeout = 0; - slot_info.sched_priority = 0; - - auto* context = __add_slot(&slot_info); + auto context = LoaderManager::GetInst().AddLoaderContext( + request->GetBundle()); if (context == nullptr) { - _E("Failed to add slot"); request->SendResult(-1); + _W("[PAD_CMD_ADD_LOADER] Can not add loader context"); return; } - __set_timer(context); - request->SendResult(loader_id); - _D("[PAD_CMD_ADD_LOADER] END"); + request->SendResult(context->GetLoaderId()); + _D("[PAD_CMD_ADD_LOADER]"); } void Launchpad::HandleRemoveLoaderRequest(std::shared_ptr request) { @@ -2395,17 +291,16 @@ void Launchpad::HandleRemoveLoaderRequest(std::shared_ptr request) { return; } - int loader_id = std::stoi(loader_id_str); - int ret = __remove_slot(static_cast(LoaderType::Dynamic), loader_id); - request->SendResult(ret); - _D("[PAD_CMD_REMOVE_LOADER] result: %d", ret); + LoaderManager::GetInst().RemoveLoaderContext(LoaderType::Dynamic, + std::stoi(loader_id_str)); + request->SendResult(0); + _D("[PAD_CMD_REMOVE_LOADER]"); } void Launchpad::HandleMakeDefaultSlotsRequest( std::shared_ptr request) { - int ret = __add_default_slots(); - request->SendResult(ret); - _D("[PAD_CMD_MAKE_DEFAULT_SLOTS] result: %d", ret); + LoaderManager::GetInst().AddDefaultLoaderContexts(); + _D("[PAD_CMD_MAKE_DEFAULT_SLOTS]"); } void Launchpad::HandlePrepareAppDefinedLoaderRequest( @@ -2418,70 +313,19 @@ void Launchpad::HandlePrepareAppDefinedLoaderRequest( return; } - auto info = app_defined_loader_info_manager_->Find(loader_name.c_str()); - if (info == nullptr) { - _E("There is no loaders. loader_name: %s", loader_name.c_str()); + auto context = LoaderManager::GetInst().PrepareAppDefinedLoaderContext( + loader_name, request->GetCallerPid()); + if (context == nullptr) { request->SendResult(-EINVAL); return; } - int loader_id; - auto* context = __find_slot_from_loader_name(loader_name.c_str()); - if (context == nullptr) { - loader_id = __make_loader_id(); - bundle_raw* extra; - int len; - bundle_encode(info->GetExtra().GetHandle(), &extra, &len); - slot_info_t slot_info; - slot_info.type = static_cast(launchpad::LoaderType::Dynamic); - slot_info.loader_id = loader_id; - slot_info.caller_pid = 0; - slot_info.loader_name = loader_name.c_str(); - slot_info.loader_path = "/usr/bin/app-defined-loader"; - slot_info.loader_extra = (const char*)extra; - slot_info.detection_method = - static_cast(launchpad::LoaderMethod::Timeout) | - static_cast(launchpad::LoaderMethod::Visibility); - slot_info.activation_method = - static_cast(launchpad::LoaderMethod::Request) | - static_cast(launchpad::LoaderMethod::AvailableMemory); - slot_info.deactivation_method = - static_cast(launchpad::LoaderMethod::Ttl) | - static_cast(launchpad::LoaderMethod::OutOfMemory); - slot_info.ttl = info->GetTtl(); - slot_info.timeout_val = 2000; - slot_info.threshold_max = launchpad::DefaultCpuThresholdMax; - slot_info.threshold_min = launchpad::DefaultCpuThresholdMin; - slot_info.on_boot = false; - slot_info.app_exists = true; - slot_info.is_hydra = false; - slot_info.app_check = true; - slot_info.on_boot_timeout = 0; - slot_info.sched_priority = 0; - - context = __add_slot(&slot_info); - bundle_free_encoded_rawdata(&extra); - if (context == nullptr) { - _E("Out of memory"); - request->SendResult(-ENOMEM); - return; - } - } else { - loader_id = context->loader_id; - } - - if (context->pid == CANDIDATE_NONE) { - __prepare_candidate_process( - static_cast(launchpad::LoaderType::Dynamic), loader_id); - } - - request->SendResult(loader_id); - _D("[PAD_CMD_PREPARE_APP_DEFINED_LOADER] result: %d", loader_id); + request->SendResult(context->GetLoaderId()); + _D("[PAD_CMD_PREPARE_APP_DEFINED_LOADER] result: %d", context->GetLoaderId()); } void Launchpad::HandleDemandRequest(std::shared_ptr request) { - __add_idle_checker(static_cast(LoaderMethod::Demand), - candidate_slot_list); + LoaderManager::GetInst().ActivateLoaderContexts(LoaderMethod::Demand); request->SendResult(0); _D("[PAD_CMD_DEMAND]"); } @@ -2501,19 +345,8 @@ void Launchpad::HandleUpdateAppTypeRequest(std::shared_ptr request) { auto installed = b.GetString(kAulIsInstalled); _I("type: %s, installed: %s", app_type.c_str(), installed.c_str()); - bool exists = (installed == "true") ? true : false; - - for (auto& info : loader_info_manager->GetLoaderInfoList()) { - auto found = std::find_if(info->GetAppTypes().begin(), - info->GetAppTypes().end(), - [&](const std::string& type) -> bool { return type == app_type; }); - if (found == info->GetAppTypes().end()) - continue; - - info->SetAppExists(exists); - __update_slot(static_cast(info->GetType()), info->IsAppExists()); - } - + bool app_installed = (installed == "true") ? true : false; + LoaderManager::GetInst().UpdateAppInstallationStatus(app_type, app_installed); _D("[PAD_CMD_UPDATE_APP_TYPE]"); } @@ -2538,63 +371,53 @@ int Launchpad::LaunchRequestPrepare(std::shared_ptr request) { PrintAppInfo(app_info); + auto& loader_manager = LoaderManager::GetInst(); auto& comp_type = app_info->GetCompType(); if (comp_type == "svcapp") { - request->SetLoaderId(__get_loader_id(request->GetBundle().GetHandle())); + request->SetLoaderId(GetLoaderIdFromBundle(request->GetBundle())); if (request->GetLoaderId() > PAD_LOADER_ID_DYNAMIC_BASE) { - int type = static_cast(launchpad::LoaderType::Dynamic); - request->SetLoaderContext(__find_slot(type, request->GetLoaderId())); - if (request->GetLoaderContext() && !request->GetLoaderContext()->prepared) - request->SetLoaderContext(nullptr); + auto context = loader_manager.FindLoaderContext(LoaderType::Dynamic, + request->GetLoaderId()); + if (context != nullptr && context->IsPrepared()) + request->SetAvailableLoaderContext(std::move(context)); } else { request->SetLoaderId(PAD_LOADER_ID_DIRECT); } } else if (comp_type == "widget" && app_info->GetAppType() == "webapp") { request->SetLoaderId(PAD_LOADER_ID_DIRECT); } else { - request->SetLoaderId(__get_loader_id(request->GetBundle().GetHandle())); + request->SetLoaderId(GetLoaderIdFromBundle(request->GetBundle())); if (request->GetLoaderId() <= PAD_LOADER_ID_STATIC) { - candidate_process_context_t* original_loader_context = nullptr; - request->SetLoaderContext( - __find_available_slot( - app_info->GetHwacc().c_str(), app_info->GetAppType().c_str(), - app_info->GetLoaderName().c_str(), &original_loader_context)); - request->SetOriginalLoaderContext(original_loader_context); + auto context = loader_manager.FindAvailableLoaderContext( + app_info->GetHwacc(), app_info->GetAppType(), + app_info->GetLoaderName()); + if (context != nullptr) { + request->SetLoaderContext(context); + if (context->IsPrepared()) { + request->SetAvailableLoaderContext(std::move(context)); + } else { + request->SetAvailableLoaderContext( + loader_manager.FindAlternativeLoaderContext( + static_cast(context->GetType()))); + } + } } else { - int type = static_cast(launchpad::LoaderType::Dynamic); - request->SetLoaderContext(__find_slot(type, request->GetLoaderId())); - if (request->GetLoaderContext() && !request->GetLoaderContext()->prepared) - request->SetLoaderContext(nullptr); + auto context = loader_manager.FindLoaderContext(LoaderType::Dynamic, + request->GetLoaderId()); + if (context != nullptr && context->IsPrepared()) + request->SetAvailableLoaderContext(std::move(context)); } } return 0; } -void Launchpad::HandleDirectLaunch(std::shared_ptr request) { - auto* original_loader_context = request->GetOriginalLoaderContext(); - if (original_loader_context != nullptr && - (!original_loader_context->app_check || - original_loader_context->app_exists) && - original_loader_context->pid == CANDIDATE_NONE && - !__sequencer_slot_exist(original_loader_context)) { - if (original_loader_context->timer > 0) { - g_source_remove(original_loader_context->timer); - original_loader_context->timer = 0; - } - - __update_slot_state(original_loader_context, - launchpad::LoaderMethod::Request, true); - __set_timer(original_loader_context); - } -} - void Launchpad::ForkProcessing(std::shared_ptr request) { - if (request->GetBundle().GetType(AUL_K_SDK) != BUNDLE_TYPE_NONE) + if (request->GetBundle().GetType(kAulSdk) != BUNDLE_TYPE_NONE) Debug::GetInst().Load(); _W("appid: %s", request->GetAppInfo()->GetAppId().c_str()); - request->SetPid(LaunchDirectly(request->GetAppInfo())); + request->SetPid(app_executor_->Execute(request->GetAppInfo())); if (request->GetPid() == -1) { _E("Failed to create a child process. appid: %s", request->GetAppInfo()->GetAppId().c_str()); @@ -2603,26 +426,25 @@ void Launchpad::ForkProcessing(std::shared_ptr request) { request->SendResult(request->GetPid()); _W("appid: %s, pid: %d", request->GetAppInfo()->GetAppId().c_str(), request->GetPid()); - HandleDirectLaunch(request); + LoaderManager::GetInst().HandleDirectLaunch( + std::move(request->GetLoaderContext())); } int Launchpad::LaunchRequestDo(std::shared_ptr request) { + auto loader_context = request->GetAvailableLoaderContext(); if (request->GetLoaderId() == PAD_LOADER_ID_DIRECT || - request->GetLoaderContext() == nullptr || + loader_context == nullptr || launchpad::Debug::GetInst().CheckAsanApp( request->GetAppInfo()->GetAppId())) { ForkProcessing(request); return 0; } + auto* app_info = request->GetAppInfo(); _W("Launch %d type process. appid: %s", - request->GetLoaderContext()->type, - request->GetAppInfo()->GetAppId().c_str()); - request->SetPid( - __send_launchpad_loader( - request->GetLoaderContext(), request->GetAppPacket(), - request->GetAppInfo()->GetAppPath().c_str(), - request->GetClientSocket()->GetFd())); + static_cast(loader_context->GetType()), + app_info->GetAppId().c_str()); + request->SetPid(loader_context->Deploy(app_info, request->GetAppPacket())); return 0; } @@ -2634,8 +456,7 @@ void Launchpad::LaunchRequestComplete(std::shared_ptr request) { auto* app_info = request->GetAppInfo(); launchpad::DBus::SendAppLaunchSignal(request->GetPid(), app_info->GetAppId().c_str()); - g_hash_table_insert(__pid_table, GINT_TO_POINTER(request->GetPid()), - strdup(app_info->GetAppId().c_str())); + pid_map_[request->GetPid()] = app_info->GetAppId(); launchpad::Log::Print("[LAUNCH]", "pid(%7d) | appid(%s)", request->GetPid(), app_info->GetAppId().c_str()); } @@ -2678,8 +499,8 @@ void Launchpad::OnIOEventReceived(int fd, int condition) { std::make_unique(client_fd), pkt_auto.release(), std::move(b)); _W("cmd(%d), caller(%d)", request->GetCmd(), request->GetCallerPid()); - if (request->GetCallerUid() >= REGULAR_UID_MIN) { - if (__check_caller_by_pid(request->GetCallerPid()) < 0) { + if (request->GetCallerUid() >= kRegularUidMin) { + if (CheckCallerPermission(request->GetCallerPid()) < 0) { _E("Permission denied. pid(%d)", request->GetCallerPid()); request->SendResult(-EPERM); return; @@ -2698,28 +519,15 @@ void Launchpad::OnIOEventReceived(int fd, int condition) { } void Launchpad::OnSigchldReceived(pid_t pid) { - HandleSigchld(pid); -} - -void Launchpad::OnAppLabelsChanged() { - HandleAppLabelsChanged(); -} - -void Launchpad::OnMemoryStatusChanged(bool low_memory, bool should_check_pss) { - if (should_check_pss) - HandleMemoryStatusChangedEvent(low_memory); - else - UpdateSlotStates(low_memory); -} - -void Launchpad::OnLoaderInfoAdded(const std::string_view name) { - _W("%s is added", name.data()); -} + auto found = pid_map_.find(pid); + if (found != pid_map_.end()) { + auto appid = found->second; + cleaner_->Add(std::make_shared(std::move(appid), pid)); + pid_map_.erase(found); + } -void Launchpad::OnLoaderInfoRemoved(const std::string_view name) { - _W("%s is removed", name.data()); - auto* context = __find_slot_from_loader_name(name.data()); - if (context != nullptr) __remove_slot(context->type, context->loader_id); + launchpad::Log::Print("[SIGCHLD]", "pid(%7d)", pid); + LoaderManager::GetInst().HandleSigchld(pid); } } // namespace launchpad diff --git a/src/launchpad-process-pool/launchpad.hh b/src/launchpad-process-pool/launchpad.hh index 83ade4d..877ee9d 100644 --- a/src/launchpad-process-pool/launchpad.hh +++ b/src/launchpad-process-pool/launchpad.hh @@ -21,24 +21,22 @@ #include #include +#include #include #include #include -#include "launchpad-process-pool/app_defined_loader_info_manager.hh" -#include "launchpad-process-pool/app_labels_monitor.hh" -#include "launchpad-process-pool/memory_monitor.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" namespace launchpad { class Launchpad : public IOChannel::IEvent, - public SignalManager::IEvent, - public AppLabelsMonitor::IEvent, - public MemoryMonitor::IEvent, - public AppDefinedLoaderInfoManager::IEvent { + public SignalManager::IEvent { public: Launchpad(int argc, char** argv); ~Launchpad(); @@ -68,7 +66,6 @@ class Launchpad : public IOChannel::IEvent, void HandleConnectRequest(std::shared_ptr request); void HandleLaunchRequest(std::shared_ptr request); - void HandleDirectLaunch(std::shared_ptr request); void ForkProcessing(std::shared_ptr request); int LaunchRequestPrepare(std::shared_ptr request); int LaunchRequestDo(std::shared_ptr request); @@ -76,20 +73,20 @@ class Launchpad : public IOChannel::IEvent, void OnIOEventReceived(int fd, int condition) override; void OnSigchldReceived(pid_t pid) override; - void OnAppLabelsChanged() override; - void OnMemoryStatusChanged(bool low_memory, bool should_check_pss) override; - void OnLoaderInfoAdded(const std::string_view name) override; - void OnLoaderInfoRemoved(const std::string_view name) override; private: int argc_; char** argv_; GMainLoop* loop_ = nullptr; + std::unique_ptr app_executor_; std::unordered_map handlers_; std::unique_ptr socket_; std::unique_ptr channel_; - std::unique_ptr app_defined_loader_info_manager_; std::unique_ptr client_socket_; + std::unordered_map pid_map_; + std::unique_ptr lang_config_; + std::unique_ptr region_format_config_; + std::unique_ptr cleaner_; }; } // namespace launchpad diff --git a/src/launchpad-process-pool/launchpad_inotify.cc b/src/launchpad-process-pool/launchpad_inotify.cc deleted file mode 100644 index 82ffcdc..0000000 --- a/src/launchpad-process-pool/launchpad_inotify.cc +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2020 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-process-pool/launchpad_inotify.h" - -#include -#include -#include -#include -#include -#include - -#include "lib/common/inc/log_private.h" - -struct inotify_watch_info_s { - int fd; - int wd; - GIOChannel* io; - guint tag; - uint32_t mask; - inotify_watch_cb cb; - void* data; -}; - -static GList* __watch_list; - -static gboolean __inotify_cb(GIOChannel* source, - GIOCondition condition, - gpointer data) { -#define ALIGN_INOTIFY_EVENT \ - __attribute__((aligned(__alignof__(struct inotify_event)))) -#define SIZE_INOTIFY_EVENT (sizeof(struct inotify_event)) - int fd = g_io_channel_unix_get_fd(source); - char buf[4096] ALIGN_INOTIFY_EVENT; - const struct inotify_event* event; - auto* info = static_cast(data); - ssize_t len; - char* ptr; - char* nptr; - - while ((len = read(fd, buf, sizeof(buf))) > 0) { - for (ptr = buf; ptr < buf + len; - ptr += sizeof(struct inotify_event) + event->len) { - if ((ptr + SIZE_INOTIFY_EVENT) > (buf + len)) - break; - - event = (const struct inotify_event*)ptr; - nptr = ptr + sizeof(struct inotify_event) + event->len; - if (nptr > buf + len) - break; - - if (event->mask & info->mask) { - if (!info->cb(event->name, event->mask, info->data)) { - _inotify_rm_watch(info); - return G_SOURCE_CONTINUE; - } - } - } - } - - return G_SOURCE_CONTINUE; -} - -static void __destroy_inotify_watch_info(gpointer data) { - struct inotify_watch_info_s* info = (struct inotify_watch_info_s*)data; - - if (info == nullptr) - return; - - if (info->tag > 0) - g_source_remove(info->tag); - - if (info->io) - g_io_channel_unref(info->io); - - if (info->wd > 0) - inotify_rm_watch(info->fd, info->wd); - - if (info->fd > 0) - close(info->fd); - - free(info); -} - -static struct inotify_watch_info_s* __create_inotify_watch_info( - const char* path, - uint32_t mask, - inotify_watch_cb cb, - void* data) { - auto cond = G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP; - struct inotify_watch_info_s* info; - - info = static_cast( - calloc(1, sizeof(inotify_watch_info_s))); - if (info == nullptr) { - _E("Out of memory"); - return nullptr; - } - - info->fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); - if (info->fd < 0) { - _E("inotify_init1() is failed. errno(%d)", errno); - __destroy_inotify_watch_info(info); - return nullptr; - } - - info->wd = inotify_add_watch(info->fd, path, mask); - if (info->wd < 0) { - _E("inotify_add_watch() is failed. path(%s), errno(%d)", path, errno); - __destroy_inotify_watch_info(info); - return nullptr; - } - - info->io = g_io_channel_unix_new(info->fd); - if (!info->io) { - _E("g_io_channel_unix_new() is failed"); - __destroy_inotify_watch_info(info); - return nullptr; - } - - info->tag = g_io_add_watch(info->io, static_cast(cond), - __inotify_cb, info); - if (!info->tag) { - _E("g_io_add_watch() is failed"); - __destroy_inotify_watch_info(info); - return nullptr; - } - - info->mask = mask; - info->cb = cb; - info->data = data; - - return info; -} - -int _inotify_add_watch(const char* path, - uint32_t mask, - inotify_watch_cb callback, - void* data) { - struct inotify_watch_info_s* info; - - if (path == nullptr || callback == nullptr) { - _E("Invalid parameter"); - return -1; - } - - info = __create_inotify_watch_info(path, mask, callback, data); - if (info == nullptr) - return -1; - - __watch_list = g_list_append(__watch_list, info); - - return 0; -} - -void _inotify_rm_watch(inotify_watch_info_h handle) { - if (handle == nullptr) - return; - - __watch_list = g_list_remove(__watch_list, handle); - __destroy_inotify_watch_info(handle); -} - -int _inotify_init(void) { - _D("inotify init"); - - return 0; -} - -void _inotify_fini(void) { - _D("inotify fini"); - - if (__watch_list) - g_list_free_full(__watch_list, __destroy_inotify_watch_info); -} diff --git a/src/launchpad-process-pool/launchpad_inotify.h b/src/launchpad-process-pool/launchpad_inotify.h deleted file mode 100644 index 77d1122..0000000 --- a/src/launchpad-process-pool/launchpad_inotify.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2020 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. - */ - -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct inotify_watch_info_s *inotify_watch_info_h; - -typedef bool (*inotify_watch_cb)(const char *event_name, uint32_t mask, - void *data); - -int _inotify_add_watch(const char *path, uint32_t mask, - inotify_watch_cb callback, void *data); - -void _inotify_rm_watch(inotify_watch_info_h handle); - -int _inotify_init(void); - -void _inotify_fini(void); - -#ifdef __cplusplus -} -#endif diff --git a/src/launchpad-process-pool/launchpad_io_channel.cc b/src/launchpad-process-pool/launchpad_io_channel.cc deleted file mode 100644 index e74bc0c..0000000 --- a/src/launchpad-process-pool/launchpad_io_channel.cc +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2020 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-process-pool/launchpad_io_channel.h" - -#include -#include -#include -#include - -#include "lib/common/inc/log_private.h" - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) - -struct io_channel_s { - GIOChannel* io; - guint tag; - bool do_close; - int fd; - io_channel_event_cb callback; - void* user_data; -}; - -struct io_condition_s { - io_condition_e io_cond; - GIOCondition g_io_cond; -}; - -static struct io_condition_s __cond_map[] = { - {.io_cond = IO_IN, .g_io_cond = G_IO_IN}, - {.io_cond = IO_OUT, .g_io_cond = G_IO_OUT}, - {.io_cond = IO_PRI, .g_io_cond = G_IO_PRI}, - {.io_cond = IO_ERR, .g_io_cond = G_IO_ERR}, - {.io_cond = IO_HUP, .g_io_cond = G_IO_HUP}, - { - .io_cond = IO_NVAL, - .g_io_cond = G_IO_NVAL, - }}; - -static io_condition_e __convert_g_io_condition(GIOCondition cond) { - int condition = 0; - - for (unsigned int i = 0; i < ARRAY_SIZE(__cond_map); i++) { - if (__cond_map[i].g_io_cond & cond) - condition |= __cond_map[i].io_cond; - } - - return static_cast(condition); -} - -static GIOCondition __convert_io_condition(io_condition_e cond) { - int condition = 0; - - for (unsigned int i = 0; i < ARRAY_SIZE(__cond_map); i++) { - if (__cond_map[i].io_cond & cond) - condition |= __cond_map[i].g_io_cond; - } - - return static_cast(condition); -} - -static gboolean __io_event_cb(GIOChannel* source, - GIOCondition condition, - gpointer data) { - io_channel_h channel = (io_channel_h)data; - io_condition_e cond = __convert_g_io_condition(condition); - int fd = g_io_channel_unix_get_fd(source); - - if (!channel->callback(fd, cond, channel->user_data)) - return G_SOURCE_REMOVE; - - return G_SOURCE_CONTINUE; -} - -io_channel_h _io_channel_create(int fd, - io_condition_e cond, - io_channel_event_cb callback, - void* user_data) { - struct io_channel_s* channel; - - if (fd < 3 || !callback) { - _E("Invalid parameter"); - return nullptr; - } - - channel = static_cast(calloc(1, sizeof(io_channel_s))); - if (!channel) { - _E("Out of memory"); - return nullptr; - } - - channel->io = g_io_channel_unix_new(fd); - if (!channel->io) { - _E("Failed to create GIOChannel"); - _io_channel_destroy(channel); - return nullptr; - } - - channel->tag = g_io_add_watch(channel->io, __convert_io_condition(cond), - __io_event_cb, channel); - if (!channel->tag) { - _E("Failed to add GIO watch"); - _io_channel_destroy(channel); - return nullptr; - } - - channel->do_close = true; - channel->fd = fd; - channel->callback = callback; - channel->user_data = user_data; - - return channel; -} - -void _io_channel_destroy(io_channel_h channel) { - if (!channel) - return; - - if (channel->tag) - g_source_remove(channel->tag); - - if (channel->io) - g_io_channel_unref(channel->io); - - if (channel->do_close && channel->fd > 0) - close(channel->fd); - - free(channel); -} - -int _io_channel_set_close_on_destroy(io_channel_h channel, bool do_close) { - if (!channel) { - _E("Invalid parameter"); - return -EINVAL; - } - - channel->do_close = do_close; - - return 0; -} diff --git a/src/launchpad-process-pool/launchpad_io_channel.h b/src/launchpad-process-pool/launchpad_io_channel.h deleted file mode 100644 index 25fab13..0000000 --- a/src/launchpad-process-pool/launchpad_io_channel.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020 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. - */ - -#pragma once - -#include - -typedef enum { - IO_IN = 0x01, - IO_OUT = 0x02, - IO_PRI = 0x04, - IO_ERR = 0x08, - IO_HUP = 0x10, - IO_NVAL = 0x20, -} io_condition_e; - -#ifdef __cplusplus -extern "C" { -#endif - -typedef bool (*io_channel_event_cb)(int fd, io_condition_e condition, - void *user_data); - -typedef struct io_channel_s *io_channel_h; - -io_channel_h _io_channel_create(int fd, io_condition_e condition, - io_channel_event_cb, void *user_data); - -void _io_channel_destroy(io_channel_h channel); - -int _io_channel_set_close_on_destroy(io_channel_h channel, bool do_close); - -#ifdef __cplusplus -} -#endif diff --git a/src/launchpad-process-pool/loader_context.cc b/src/launchpad-process-pool/loader_context.cc new file mode 100644 index 0000000..c69b853 --- /dev/null +++ b/src/launchpad-process-pool/loader_context.cc @@ -0,0 +1,616 @@ +/* + * 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-process-pool/loader_context.hh" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "launchpad-process-pool/app_labels_monitor.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/user_tracer.hh" +#include "launchpad-process-pool/util.hh" +#include "lib/common/inc/key.h" +#include "lib/common/inc/launchpad_common.h" +#include "lib/common/inc/launchpad_types.h" + +namespace fs = std::filesystem; + +namespace launchpad { +namespace { + +constexpr const char kLaunchpadType[] = ".launchpad-type"; +const int kSocketMaxBufferSize = 131071; +const unsigned int kWinScore = 100; +const float kLoseScoreRate = 0.7f; + +int VerifyLoaderCaps(const std::string& executable_file) { + std::vector values { CAP_SETGID, CAP_MAC_ADMIN }; + + // If Dytransition feature is enabled, CAP_MAC_ADMIN is unnecessary. + if (!AppLabelsMonitor::GetInst().IsDisposed()) + values.pop_back(); + + _W("Executable file: %s", executable_file.c_str()); + cap_t cap = cap_get_file(executable_file.c_str()); + if (cap == nullptr) { + _E("Failed to get cap from file(%s)", executable_file.c_str()); + return -1; + } + + auto cap_auto = std::unique_ptr::type, + decltype(cap_free)*>(cap, cap_free); + + for (size_t i = 0; i < values.size(); i++) { + cap_flag_value_t inh_state; + int ret = cap_get_flag(cap, values[i], CAP_INHERITABLE, &inh_state); + if (ret != 0) { + _E("Failed to get cap inhertiable. errno(%d)", errno); + return -1; + } + + cap_flag_value_t eff_state; + ret = cap_get_flag(cap, values[i], CAP_EFFECTIVE, &eff_state); + if (ret != 0) { + _E("Failed to get cap effective. errno(%d)", errno); + return -1; + } + + if ((inh_state != CAP_SET) || (eff_state != CAP_SET)) { + _E("%d capability is needed", values[i]); + return -1; + } + } + + 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(app_packet), size); +} + +} // namespace + +LoaderContext::Builder& LoaderContext::Builder::SetLoaderInfo( + std::shared_ptr loader_info) { + loader_info_ = std::move(loader_info); + return *this; +} + +LoaderContext::Builder& LoaderContext::Builder::SetLoaderId(int loader_id) { + loader_id_ = loader_id; + return *this; +} + +LoaderContext::Builder& LoaderContext::Builder::SetCallerPid(pid_t caller_pid) { + caller_pid_ = caller_pid; + return *this; +} + +LoaderContext::Builder& LoaderContext::Builder::SetActive() { + if ((static_cast(loader_info_->GetDeactivationMethod()) & + static_cast(LoaderMethod::OutOfMemory)) && + MemoryMonitor::GetInst().IsLowMemory()) + activated_ = false; + + return *this; +} + +LoaderContext::Builder::operator LoaderContext*() { + return new LoaderContext(std::move(loader_info_), loader_id_, caller_pid_, + activated_); +} + +LoaderContext::LoaderContext(std::shared_ptr loader_info, + int loader_id, pid_t caller_pid, bool activated) + : loader_info_(std::move(loader_info)), + loader_id_(loader_id), + caller_pid_(caller_pid), + activated_(activated), + cpu_checker_( + new CPUChecker(loader_info_->GetCpuThresholdMax(), + loader_info_->GetCpuThresholdMin())), + score_(kWinScore) { + auto& executable_file = loader_info_->GetExe(); + if (executable_file != "null") { + if (access(executable_file.c_str(), F_OK | X_OK) != 0) { + int error = -errno; + _E("access() is failed. path: %s, errno: %d", + executable_file.c_str(), errno); + THROW(error); + } + + if (VerifyLoaderCaps(executable_file) < 0) + THROW(-EINVAL); + } + + loader_extra_ = reinterpret_cast( + loader_info_->GetExtra().ToRaw().first.get()); + Listen(); + condition_path_exists_ = loader_info_->GetConditionPathExists(); +} + +LoaderContext::~LoaderContext() { + Dispose(); +} + +void LoaderContext::Listen() { + try { + std::string socket_path = "/run/aul/daemons/" + std::to_string(getuid()) + + "/" + std::string(kLaunchpadType) + std::to_string(GetType()) + "-" + + std::to_string(loader_id_); + if (fs::exists(socket_path)) + fs::remove(socket_path); + + server_socket_.reset(new ServerSocket()); + server_socket_->Bind(socket_path); + server_socket_->Listen(128); + + server_channel_.reset(new IOChannel(server_socket_->GetFd(), + IOChannel::IOCondition::IO_IN, this)); + server_channel_->SetCloseOnDestroy(false); + } catch (const Exception& e) { + _E("Exception occurs. error: %s", e.what()); + THROW(e.GetErrorCode()); + } +} + +void LoaderContext::Dispose() { + _E("Dispose. type(%d), name(%s), pid(%d)", + GetType(), GetLoaderName().c_str(), GetPid()); + + if (pid_ > 0) { + _D("Kill process(%d)", pid_); + if (kill(pid_, SIGKILL) != 0) + _E("kill() is failed. pid(%d), errno(%d)", pid_, errno); + + pid_ = 0; + } + + if (live_timer_ > 0) { + g_source_remove(live_timer_); + live_timer_ = 0; + } + + if (timer_ > 0) { + g_source_remove(timer_); + timer_ = 0; + } + + if (on_boot_timer_ > 0) { + g_source_remove(on_boot_timer_); + on_boot_timer_ = 0; + } + + client_channel_.reset(); + client_socket_.reset(); + prepared_ = false; +} + +pid_t LoaderContext::Prepare() { + pid_ = LoaderExecutor::GetInst().Execute(this, + loader_info_->GetSchedPriority()); + _W("Prepare. type(%d), name(%s), pid(%d)", + GetType(), GetLoaderName().c_str(), pid_); + if (pid_ == -1) { + _E("Failed to create a child process"); + return -1; + } + + Log::Print("[CANDIDATE]", "pid(%7d) | type(%d) | loader(%s)", + GetPid(), GetLoaderId(), GetLoaderName().c_str()); + + if (!IsHydraMode()) + SetLiveTimer(); + + MemoryMonitor::GetInst().Reset(); + return pid_; +} + +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); + if (ret != 0) { + _E("Failed to send request to the loader. pid(%d)", pid_); + return ret; + } + + _W("Request to the loader process. pid(%d), path(%s)", + pid_, app_info->GetAppPath().c_str()); + + pid_t pid = pid_; + pid_ = 0; + LoaderContext::Dispose(); + SetTimer(); + UpdateScore(); + return pid; +} + +const std::string& LoaderContext::GetLoaderName() const { + return loader_info_->GetName(); +} + +const std::string& LoaderContext::GetLoaderPath() const { + return loader_info_->GetExe(); +} + +const std::string& LoaderContext::GetLoaderExtra() const { + return loader_extra_; +} + +int LoaderContext::GetType() const { + return static_cast(loader_info_->GetType()); +} + +bool LoaderContext::IsPrepared() const { + return prepared_; +} + +void LoaderContext::SetPrepared(bool prepared) { + prepared_ = prepared; +} + +pid_t LoaderContext::GetPid() const { + return pid_; +} + +void LoaderContext::SetPid(pid_t pid) { + pid_ = pid; +} + +pid_t LoaderContext::GetCallerPid() const { + return caller_pid_; +} + +int LoaderContext::GetLoaderId() const { + return loader_id_; +} + +bool LoaderContext::IsHydraMode() const { + return loader_info_->IsHydraMode(); +} + +bool LoaderContext::IsActivated() const { + return activated_; +} + +bool LoaderContext::IsTouched() const { + return touched_; +} + +bool LoaderContext::IsOnBoot() const { + return loader_info_->IsOnBoot(); +} + +int LoaderContext::GetOnBootTimeout() const { + return loader_info_->GetOnBootTimeout(); +} + +LoaderMethod LoaderContext::GetDetectionMethod() const { + return loader_info_->GetDetectionMethod(); +} + +void LoaderContext::SetLoaderMethod(LoaderMethod method) { + method_ = method; +} + +bool LoaderContext::ShouldCheckAppInstallation() const { + return loader_info_->ShouldCheckAppInstallation(); +} + +void LoaderContext::SetAppInstalled(bool installed) { + loader_info_->SetAppInstalled(installed); +} + +bool LoaderContext::IsAppInstalled() const { + return loader_info_->IsAppInstalled(); +} + +CPUChecker* LoaderContext::GetCPUChecker() const { + return cpu_checker_.get(); +} + +void LoaderContext::UnsetTimer() { + if (timer_ > 0) { + g_source_remove(timer_); + timer_ = 0; + } +} + +void LoaderContext::SetTimer(LoaderContext::IEvent* listener) { + listener_ = listener; + SetTimer(); +} + +void LoaderContext::SetTimer() { + if (timer_ > 0) { + _W("Already registered"); + return; + } + + if (!IsActivated()) { + _W("The loader is deacitvated. type(%d)", GetType()); + return; + } + + if (static_cast(loader_info_->GetDetectionMethod()) & + static_cast(LoaderMethod::Timeout)) { + timer_ = g_timeout_add(loader_info_->GetTimeout(), TimeoutCb, this); + if (timer_ == 0) + _E("g_timeout_add() is failed"); + } +} + +void LoaderContext::SetOnBootTimer(int timeout) { + if (on_boot_timer_ != 0) + return; + + on_boot_timer_ = g_timeout_add(timeout, OnBootTimeoutCb, this); + if (on_boot_timer_ == 0) + _E("g_timeout_add() is failed"); +} + +bool LoaderContext::ShouldWaitForFileCreation() { + auto iter = condition_path_exists_.begin(); + while (iter != condition_path_exists_.end()) { + auto& path = *iter; + if (!fs::exists(path)) { + _D("%s does not exist", path.c_str()); + return true; + } + + iter = condition_path_exists_.erase(iter); + } + + return false; +} + +int LoaderContext::IncreaseCPUCheckCount() { + return ++cpu_check_count_; +} + +void LoaderContext::ResetCPUCheckCount() { + cpu_check_count_ = 0; +} + +void LoaderContext::UpdatePssMemory() { + Procfs::GetPssMemory(pid_, &pss_); +} + +uint64_t LoaderContext::GetPssMemory() const { + return pss_; +} + +unsigned int LoaderContext::GetScore() const { + return score_; +} + +gboolean LoaderContext::TimeoutCb(gpointer user_data) { + auto* context = static_cast(user_data); + auto* listener = context->listener_; + if (listener != nullptr) + listener->OnTimeoutEvent(context); + + return G_SOURCE_REMOVE; +} + +gboolean LoaderContext::TimeToLiveCb(gpointer user_data) { + auto* context = static_cast(user_data); + context->UpdateState(LoaderMethod::TimeToLive, false); + return G_SOURCE_REMOVE; +} + +gboolean LoaderContext::OnBootTimeoutCb(gpointer user_data) { + auto* context = static_cast(user_data); + _W("type(%d), loader_name(%s)", + context->GetType(), context->GetLoaderName().c_str()); + context->on_boot_timer_ = 0; + if (context->GetPid() > 0) { + _E("Loader is already running. pid(%d)", context->GetPid()); + return G_SOURCE_REMOVE; + } + + if (context->ShouldWaitForFileCreation()) { + context->SetOnBootTimer(100); + return G_SOURCE_REMOVE; + } + + _W("Loader(%d:%s) is starting by the on-boot timer option", + context->GetType(), context->GetLoaderName().c_str()); + context->Prepare(); + context->touched_ = true; + return G_SOURCE_REMOVE; +} + +void LoaderContext::UpdateScore() { + score_ = score_ * kLoseScoreRate + kWinScore; +} + +void LoaderContext::Activate() { + _W("type(%d), loader_name(%s), activated(%d)", + GetType(), GetLoaderName().c_str(), IsActivated()); + if (IsActivated()) + return; + + activated_ = true; + if (!touched_ && !loader_info_->IsOnBoot()) + return; + + if (pid_ > 0) + return; + + if (loader_info_->ShouldCheckAppInstallation() && + !loader_info_->IsAppInstalled()) + return; + + if (CanActivate(LoaderMethod::Timeout)) + SetTimer(); +} + +void LoaderContext::Deactivate() { + _W("type(%d), loader_name(%s), activated(%d)", + GetType(), GetLoaderName().c_str(), IsActivated()); + if (!IsActivated()) + return; + + activated_ = false; + Dispose(); +} + +bool LoaderContext::CanActivate(LoaderMethod method) const { + return (static_cast(loader_info_->GetActivationMethod()) & + static_cast(method)); +} + +bool LoaderContext::CanDeactivate(LoaderMethod method) const { + return (static_cast(loader_info_->GetDeactivationMethod()) & + static_cast(method)); +} + +void LoaderContext::UpdateState(LoaderMethod method, bool force) { + _W("type(%d), loader_name(%s), activated(%d), method(%d), force(%d)", + GetType(), GetLoaderName().c_str(), activated_, static_cast(method), + force); + SetLoaderMethod(method); + switch (method) { + case LoaderMethod::OutOfMemory: + if ((force || CanDeactivate(method)) && + MemoryMonitor::GetInst().IsLowMemory()) { + _W("Low memory"); + Deactivate(); + } else { + Activate(); + } + break; + case LoaderMethod::TimeToLive: + if (force || CanDeactivate(method)) + Deactivate(); + break; + case LoaderMethod::AvailableMemory: + if (force || CanActivate(method)) + Activate(); + break; + case LoaderMethod::Request: + if (force || CanActivate(method)) + UpdateState(LoaderMethod::OutOfMemory, force); + break; + default: + Activate(); + break; + } +} + +void LoaderContext::SetLiveTimer() { + _W("type(%d), loader_name(%s), deactivation_method(%d)", + GetType(), GetLoaderName().c_str(), + static_cast(loader_info_->GetDeactivationMethod())); + if (static_cast(loader_info_->GetDeactivationMethod()) & + static_cast(LoaderMethod::TimeToLive)) { + if (live_timer_ == 0) { + live_timer_ = g_timeout_add_seconds(loader_info_->GetTimeToLive(), + TimeToLiveCb, this); + } + } +} + +void LoaderContext::HandleLoaderEvent() { + if (!prepared_) { + try { + client_socket_ = server_socket_->Accept(); + client_socket_->SetReceiveBufferSize(kSocketMaxBufferSize); + client_socket_->SetReceiveTimeout(5200); + client_socket_->SetSendBufferSize(kSocketMaxBufferSize); + + int pid = -1; + int ret = client_socket_->Receive(static_cast(&pid), sizeof(pid)); + if (ret != 0) { + _E("Receive() is failed. error: %d", ret); + client_socket_.reset(); + return; + } + + auto peer_cred = PeerCredentials::Get(client_socket_->GetFd()); + if (peer_cred->GetPid() != pid) { + _E("The peer information does not match. %d : %d", + peer_cred->GetPid(), pid); + client_socket_.reset(); + return; + } + + client_channel_.reset( + new IOChannel( + client_socket_->GetFd(), + IOChannel::IOCondition::IO_IN | IOChannel::IOCondition::IO_HUP, + this)); + client_channel_->SetCloseOnDestroy(false); + + if (IsHydraMode()) + pid_ = peer_cred->GetPid(); + + prepared_ = true; + SECURE_LOGI("Type %d loader was connected. pid: %d", GetType(), pid_); + UserTracer::Print("Type " + std::to_string(GetType()) + + " loader was connected. pid: " + std::to_string(pid_)); + } catch (const Exception& e) { + _E("Exception occurs. error: %s", e.what()); + return; + } + } else { + auto client_socket = server_socket_->Accept(); + _E("Refuse loader process connection"); + } +} + +void LoaderContext::HandleLoaderClientEvent(int condition) { + if (condition & + (IOChannel::IOCondition::IO_HUP | IOChannel::IOCondition::IO_NVAL)) { + SECURE_LOGE("Type %d loader was disconnected. pid: %d", GetType(), pid_); + pid_ = 0; + Dispose(); + Prepare(); + } +} + +void LoaderContext::OnIOEventReceived(int fd, int condition) { + _W("[DEBUG] fd(%d), condition(%d)", fd, condition); + if (server_socket_.get() != nullptr && server_socket_->GetFd() == fd) + HandleLoaderEvent(); + else if (client_socket_.get() != nullptr && client_socket_->GetFd() == fd) + HandleLoaderClientEvent(condition); +} + +} // namespace launchpad diff --git a/src/launchpad-process-pool/loader_context.hh b/src/launchpad-process-pool/loader_context.hh new file mode 100644 index 0000000..e5ee1cf --- /dev/null +++ b/src/launchpad-process-pool/loader_context.hh @@ -0,0 +1,153 @@ +/* + * 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 LAUNCHPAD_PROCESS_POOL_LOADER_CONTEXT_HH_ +#define LAUNCHPAD_PROCESS_POOL_LOADER_CONTEXT_HH_ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "lib/common/inc/launchpad_common.h" + +#include "launchpad-process-pool/cpu_checker.hh" +#include "launchpad-process-pool/loader_info.hh" +#include "launchpad-process-pool/launcher_info.hh" + +namespace launchpad { + +class LoaderContext : public std::enable_shared_from_this, + public IOChannel::IEvent { + public: + class Builder { + public: + virtual ~Builder() = default; + + Builder& SetLoaderInfo(std::shared_ptr loader_info); + Builder& SetLoaderId(int loader_id); + Builder& SetCallerPid(pid_t caller_pid); + Builder& SetActive(); + + virtual operator LoaderContext*(); + + protected: + std::shared_ptr loader_info_; + int loader_id_ = 0; + pid_t caller_pid_ = getpid(); + bool activated_ = true; + }; + + class IEvent { + public: + virtual ~IEvent() = default; + virtual void OnTimeoutEvent(LoaderContext* context) = 0; + }; + + LoaderContext(std::shared_ptr loader_info, int loader_id, + pid_t caller_pid, bool activated); + virtual ~LoaderContext(); + + virtual void Listen(); + virtual void Dispose(); + virtual pid_t Prepare(); + virtual pid_t Deploy(const AppInfo* app_info, app_pkt_t* request); + + const std::string& GetLoaderName() const; + const std::string& GetLoaderPath() const; + const std::string& GetLoaderExtra() const; + int GetType() const; + bool IsPrepared() const; + pid_t GetPid() const; + void SetPid(pid_t pid); + pid_t GetCallerPid() const; + int GetLoaderId() const; + bool IsHydraMode() const; + bool IsActivated() const; + bool IsTouched() const; + bool IsOnBoot() const; + int GetOnBootTimeout() const; + LoaderMethod GetDetectionMethod() const; + void SetLoaderMethod(LoaderMethod method); + bool ShouldCheckAppInstallation() const; + void SetAppInstalled(bool installed); + bool IsAppInstalled() const; + CPUChecker* GetCPUChecker() const; + void UnsetTimer(); + void SetTimer(IEvent* listener); + void SetOnBootTimer(int timeout); + bool ShouldWaitForFileCreation(); + int IncreaseCPUCheckCount(); + void ResetCPUCheckCount(); + void UpdatePssMemory(); + uint64_t GetPssMemory() const; + unsigned int GetScore() const; + bool CanActivate(LoaderMethod method) const; + void UpdateState(LoaderMethod method, bool force); + + protected: + void SetPrepared(bool prepared); + void OnIOEventReceived(int fd, int condition) override; + + private: + void UpdateScore(); + void Activate(); + void Deactivate(); + bool CanDeactivate(LoaderMethod method) const; + void SetTimer(); + void SetLiveTimer(); + void HandleLoaderEvent(); + void HandleLoaderClientEvent(int condition); + + static gboolean TimeoutCb(gpointer user_data); + static gboolean TimeToLiveCb(gpointer user_data); + static gboolean OnBootTimeoutCb(gpointer user_data); + + private: + bool prepared_ = false; + std::shared_ptr loader_info_; + int loader_id_; + pid_t caller_pid_; + bool activated_; + std::unique_ptr cpu_checker_; + unsigned int score_; + std::string loader_extra_; + std::unique_ptr server_socket_; + std::unique_ptr server_channel_; + std::unique_ptr client_socket_; + std::unique_ptr client_channel_; + pid_t pid_ = 0; + launchpad::LoaderMethod method_ = launchpad::LoaderMethod::None; + bool touched_ = false; + uint64_t pss_ = 0; + int cpu_check_count_ = 0; + guint timer_ = 0; + guint live_timer_ = 0; + guint on_boot_timer_ = 0; + std::vector condition_path_exists_; + IEvent* listener_ = nullptr; +}; + +} // namespace launchpad + +#endif // LAUNCHPAD_PROCESS_POOL_LOADER_CONTEXT_HH_ diff --git a/src/launchpad-process-pool/loader_executor.cc b/src/launchpad-process-pool/loader_executor.cc new file mode 100644 index 0000000..7f66558 --- /dev/null +++ b/src/launchpad-process-pool/loader_executor.cc @@ -0,0 +1,86 @@ +/* + * 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-process-pool/loader_executor.hh" + +#include +#include +#include + +#include + +#include "launchpad-process-pool/log_private.hh" +#include "launchpad-process-pool/signal_manager.hh" +#include "lib/common/inc/launchpad_common.h" +#include "lib/common/inc/launchpad_types.h" + +namespace launchpad { + +LoaderExecutor::LoaderExecutor() : Executor(this) {} + +LoaderExecutor& LoaderExecutor::GetInst() { + static LoaderExecutor inst; + return inst; +} + +pid_t LoaderExecutor::Execute(const LoaderContext* loader_context, + int priority) { + loader_context_ = loader_context; + return Executor::Execute(priority); +} + +void LoaderExecutor::OnExecution() { + std::vector argv = CreateLoaderArgv(); + char** loader_argv = static_cast( + calloc(argv.size() + 1, sizeof(char*))); + if (loader_argv == nullptr) { + _E("Out of memory"); + exit(EXIT_FAILURE); + } + + int loader_argc = argv.size(); + for (int i = 0; i < loader_argc; ++i) { + loader_argv[i] = const_cast(argv[i].c_str()); + if ((i + 1) != loader_argc) + SECURE_LOGD("loader argument %d : %s##", i, loader_argv[i]); + } + + SignalManager::GetInst().UnblockSigchld(); + _close_all_fds(); + _setup_stdio(basename(loader_argv[LOADER_ARG_PATH])); + + if (execv(loader_argv[LOADER_ARG_PATH], loader_argv) < 0) { + char err_buf[1024]; + fprintf(stderr, "Failed to execute a file. path: %s, errno: %d:%s\n", + loader_argv[LOADER_ARG_PATH], errno, + strerror_r(errno, err_buf, sizeof(err_buf))); + exit(EXIT_FAILURE); + } +} + +std::vector LoaderExecutor::CreateLoaderArgv() { + std::string dummy(LOADER_ARG_LEN - 1, ' '); + std::vector argv(LOADER_ARG_DUMMY + 1); + argv[LOADER_ARG_DUMMY] = std::move(dummy); + argv[LOADER_ARG_PATH] = loader_context_->GetLoaderPath(); + argv[LOADER_ARG_TYPE] = std::to_string(loader_context_->GetType()); + argv[LOADER_ARG_ID] = std::to_string(loader_context_->GetLoaderId()); + argv[LOADER_ARG_HYDRA] = loader_context_->IsHydraMode() ? "1" : "0"; + argv[LOADER_ARG_EXTRA] = loader_context_->GetLoaderExtra(); + return argv; +} + +} // namespace launchpad diff --git a/src/launchpad-process-pool/loader_executor.hh b/src/launchpad-process-pool/loader_executor.hh new file mode 100644 index 0000000..b2cafaa --- /dev/null +++ b/src/launchpad-process-pool/loader_executor.hh @@ -0,0 +1,53 @@ +/* + * 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 LAUNCHPAD_PROCESS_POOL_LOADER_EXECUTOR_HH_ +#define LAUNCHPAD_PROCESS_POOL_LOADER_EXECUTOR_HH_ + +#include +#include + +#include "launchpad-process-pool/executor.hh" +#include "launchpad-process-pool/loader_context.hh" + +namespace launchpad { + +class LoaderExecutor : public Executor::Delegator, + public Executor { + public: + LoaderExecutor(const LoaderExecutor&) = delete; + LoaderExecutor& operator=(const LoaderExecutor&) = delete; + LoaderExecutor(LoaderExecutor&&) = delete; + LoaderExecutor& operator=(LoaderExecutor&&) = delete; + + static LoaderExecutor& GetInst(); + + pid_t Execute(const LoaderContext* loader_context, int priority); + + private: + LoaderExecutor(); + ~LoaderExecutor() = default; + + void OnExecution() override; + std::vector CreateLoaderArgv(); + + private: + const LoaderContext* loader_context_ = nullptr; +}; + +} // namespace launchpad + +#endif // LAUNCHPAD_PROCESS_POOL_LOADER_EXECUTOR_HH_ diff --git a/src/launchpad-process-pool/loader_factory.cc b/src/launchpad-process-pool/loader_factory.cc new file mode 100644 index 0000000..8ac97d5 --- /dev/null +++ b/src/launchpad-process-pool/loader_factory.cc @@ -0,0 +1,147 @@ +/* + * 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-process-pool/loader_factory.hh" + +#include +#include + +#include + +#include "lib/common/inc/launchpad_common.h" + +#include "launchpad-process-pool/loader_context.hh" +#include "launchpad-process-pool/hydra_loader_context.hh" +#include "launchpad-process-pool/user_tracer.hh" + +namespace launchpad { +namespace { + +std::string GetAppTypeString(const std::shared_ptr& info) { + std::string app_types; + for (auto& app_type : info->GetAppTypes()) { + if (!app_types.empty()) + app_types += "|"; + + app_types += app_type; + } + + return app_types; +} + +constexpr char kInfoDirectoryPath[] = "/usr/share/aul"; + +std::shared_ptr CreateDynamicLoaderInfo(tizen_base::Bundle b, + int loader_id, const std::string& caller_pid) { + auto loader_path = b.GetString(kAulLoaderPath); + if (loader_path.empty()) + return nullptr; + + auto loader_name = loader_path + caller_pid + std::to_string(loader_id); + LoaderInfo::Builder builder; + builder.SetType(LoaderType::Dynamic); + builder.SetName(std::move(loader_name)); + builder.SetExe(std::move(loader_path)); + builder.SetDetectionMethod(LoaderMethod::Timeout | LoaderMethod::Visibility); + builder.SetActivationMethod(LoaderMethod::Request | + LoaderMethod::AvailableMemory); + builder.SetDeactivationMethod(LoaderMethod::TimeToLive | + LoaderMethod::OutOfMemory); + builder.SetTimeToLive(600); + builder.SetTimeout(2000); + builder.SetOnBoot(false); + builder.SetHydraMode(false); + return std::shared_ptr(builder.Build()); +} + +} // namespace + +LoaderFactory& LoaderFactory::GetInst() { + static LoaderFactory inst; + return inst; +} + +std::shared_ptr LoaderFactory::CreateLoaderContext( + LoaderInfoPtr info) { + auto app_types = GetAppTypeString(info); + int loader_id = (info->GetExe() == "null") ? PAD_LOADER_ID_DIRECT : + PAD_LOADER_ID_STATIC; + LoaderContext* context; + if (info->IsHydraMode()) { + context = HydraLoaderContext::Builder() + .SetLoaderInfo(std::move(info)) + .SetLoaderId(loader_id) + .SetActive(); + } else { + context = LoaderContext::Builder() + .SetLoaderInfo(std::move(info)) + .SetLoaderId(loader_id) + .SetActive(); + } + + if (context == nullptr) + return nullptr; + + _I("loader_type(%d), loader_id(%d), loader_name(%s), app_type(%s)", + context->GetType(), loader_id, context->GetLoaderName().c_str(), + app_types.c_str()); + UserTracer::Print("candidate slot. app-type(" + app_types + ") loader-type(" + + std::to_string(context->GetType())); + return std::shared_ptr(context); +} + +std::shared_ptr LoaderFactory::CreateLoaderContext( + tizen_base::Bundle b) { + auto caller_pid = b.GetString(kAulCallerPid); + if (caller_pid.empty()) + return nullptr; + + int loader_id = MakeDynamicLoaderId(); + auto loader_info = CreateDynamicLoaderInfo(std::move(b), loader_id, + caller_pid); + if (loader_info == nullptr) + return nullptr; + + LoaderContext* context = LoaderContext::Builder() + .SetLoaderInfo(std::move(loader_info)) + .SetLoaderId(loader_id) + .SetCallerPid(std::stoi(caller_pid)) + .SetActive(); + if (context == nullptr) + return nullptr; + + return std::shared_ptr(context); +} + +std::shared_ptr LoaderFactory::CreateLoaderContext( + LoaderInfoPtr info, pid_t caller_pid) { + int loader_id = MakeDynamicLoaderId(); + LoaderContext* context = LoaderContext::Builder() + .SetLoaderInfo(std::move(info)) + .SetLoaderId(loader_id) + .SetCallerPid(caller_pid) + .SetActive(); + if (context == nullptr) + return nullptr; + + return std::shared_ptr(context); +} + +int LoaderFactory::MakeDynamicLoaderId() { + return ++dynamic_loader_id_; +} + +} // namespace launchpad diff --git a/src/launchpad-process-pool/loader_factory.hh b/src/launchpad-process-pool/loader_factory.hh new file mode 100644 index 0000000..bfd8856 --- /dev/null +++ b/src/launchpad-process-pool/loader_factory.hh @@ -0,0 +1,55 @@ +/* + * 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 LAUNCHPAD_PROCESS_POOL_LOADER_FACTORY_HH_ +#define LAUNCHPAD_PROCESS_POOL_LOADER_FACTORY_HH_ + +#include + +#include +#include + +#include "lib/common/inc/launchpad_types.h" + +#include "launchpad-process-pool/loader_context.hh" +#include "launchpad-process-pool/loader_info.hh" + +namespace launchpad { + +class LoaderFactory { + public: + LoaderFactory(LoaderFactory&) = delete; + LoaderFactory& operator=(LoaderFactory&) = delete; + + static LoaderFactory& GetInst(); + + std::shared_ptr CreateLoaderContext(LoaderInfoPtr info); + std::shared_ptr CreateLoaderContext(tizen_base::Bundle b); + std::shared_ptr CreateLoaderContext(LoaderInfoPtr info, + pid_t caller_pid); + + private: + LoaderFactory() = default; + + int MakeDynamicLoaderId(); + + private: + int dynamic_loader_id_ = PAD_LOADER_ID_DYNAMIC_BASE; +}; + +} // namespace launchpad + +#endif // LAUNCHPAD_PROCESS_POOL_LOADER_FACTORY_HH_ diff --git a/src/launchpad-process-pool/loader_info.cc b/src/launchpad-process-pool/loader_info.cc index 465c8a1..b7e32f2 100644 --- a/src/launchpad-process-pool/loader_info.cc +++ b/src/launchpad-process-pool/loader_info.cc @@ -30,6 +30,8 @@ #include "launchpad-process-pool/util.hh" #include "lib/common/inc/launchpad_common.h" +namespace fs = std::filesystem; + namespace launchpad { namespace { @@ -66,203 +68,226 @@ constexpr const char kValMethodAvailableMemory[] = "AVAILABLE_MEMORY"; constexpr const char kValMethodTtl[] = "TTL"; constexpr const char kValMethodOutOfMemory[] = "OUT_OF_MEMORY"; +LoaderType MakeLoaderType() { + static uint32_t user_slot_offset; + return static_cast( + static_cast(LoaderType::User) + user_slot_offset++); +} + } // namespace -namespace fs = std::filesystem; +LoaderInfo::Builder& LoaderInfo::Builder::SetType(LoaderType type) { + type_ = type; + return *this; +} -void LoaderInfoInflator::ParseDetectionMethod(const LoaderInfoPtr& info, - std::string& tok_start, - std::istringstream& ss) { - std::string line = tok_start; - do { - auto tokens = Split(line, " |\t\r\n"); - for (auto& token : tokens) { - if (token == kValMethodTimeout) - info->detection_method_ = - info->detection_method_ | LoaderMethod::Timeout; - else if (token == kValMethodVisibility) - info->detection_method_ = - info->detection_method_ | LoaderMethod::Visibility; - else if (token == kValMethodDemand) - info->detection_method_ = - info->detection_method_ | LoaderMethod::Demand; - } - } while (std::getline(ss, line)); +LoaderInfo::Builder& LoaderInfo::Builder::SetName(std::string name) { + name_ = std::move(name); + return *this; +} - info->detection_method_ = info->detection_method_ | LoaderMethod::Install; - _D("detection_method:%d", static_cast(info->detection_method_)); +LoaderInfo::Builder& LoaderInfo::Builder::SetExe(std::string exe) { + exe_ = std::move(exe); + return *this; } -void LoaderInfoInflator::ParseActivationMethod(const LoaderInfoPtr& info, - std::string& tok_start, - std::istringstream& ss) { - info->activation_method_ = LoaderMethod::Empty; - std::string line = tok_start; - do { - auto tokens = Split(line, " |\t\r\n"); - for (auto& token : tokens) { - if (token == kValMethodRequest) - info->activation_method_ = - info->activation_method_ | LoaderMethod::Request; - else if (token == kValMethodAvailableMemory) - info->activation_method_ = - info->activation_method_ | LoaderMethod::AvailableMemory; - } - } while (std::getline(ss, line)); +LoaderInfo::Builder& LoaderInfo::Builder::AddAppType(std::string app_type) { + app_types_.push_back(std::move(app_type)); + return *this; +} - _D("activation_method:%d", static_cast(info->activation_method_)); +LoaderInfo::Builder& LoaderInfo::Builder::SetAppTypes( + std::vector app_types) { + app_types_ = std::move(app_types); + return *this; } -void LoaderInfoInflator::ParseDeactivationMethod(const LoaderInfoPtr& info, - std::string& tok_start, - std::istringstream& ss) { - info->deactivation_method_ = LoaderMethod::Empty; - std::string line = tok_start; - do { - auto tokens = Split(line, " |\t\r\n"); - for (auto& token : tokens) { - if (token == kValMethodTtl) - info->deactivation_method_ = - info->deactivation_method_ | LoaderMethod::Ttl; - else if (token == kValMethodOutOfMemory) - info->deactivation_method_ = - info->deactivation_method_ | LoaderMethod::OutOfMemory; - } - } while (std::getline(ss, line)); +LoaderInfo::Builder& LoaderInfo::Builder::SetDetectionMethod( + LoaderMethod method) { + detection_method_ = method; + return *this; +} - _D("deactivation_method:%d", static_cast(info->deactivation_method_)); +LoaderInfo::Builder& LoaderInfo::Builder::SetActivationMethod( + LoaderMethod method) { + activation_method_ = method; + return *this; } -void LoaderInfoInflator::ParseAppTypes(const LoaderInfoPtr& info, - std::string& tok_start, - std::istringstream& ss) { - std::string line = tok_start; - do { - auto tokens = Split(line, " |\t\r\n"); - for (auto& token : tokens) { - info->app_types_.push_back(std::move(token)); - } - } while (std::getline(ss, line)); +LoaderInfo::Builder& LoaderInfo::Builder::SetDeactivationMethod( + LoaderMethod method) { + deactivation_method_ = method; + return *this; } -void LoaderInfoInflator::ParseConditionPathExists(const LoaderInfoPtr& info, - const std::string& tok_start, std::istringstream& stream) { - std::string line = tok_start; - do { - auto tokens = Split(line, " |\t\r\n"); - for (auto& token : tokens) - info->condition_path_exists_.push_back(std::move(token)); - } while (std::getline(stream, line)); +LoaderInfo::Builder& LoaderInfo::Builder::SetTimeout(int timeout) { + timeout_ = timeout; + return *this; } -void LoaderInfoInflator::Parse(std::vector& loader_info_list, - const fs::path& path) { - std::ifstream fp; - fp.open(path); - if (fp.fail()) - return; +LoaderInfo::Builder& LoaderInfo::Builder::SetHwAcc(std::string hw_acc) { + hw_acc_ = std::move(hw_acc); + return *this; +} - LoaderInfoPtr info; - std::string input; - std::string extra_array_key; - std::vector extra_array; - while (std::getline(fp, input)) { - std::istringstream ss(input); - std::string tok1, tok2; - if (!(ss >> tok1)) - continue; +LoaderInfo::Builder& LoaderInfo::Builder::AddAlternativeLoader( + std::string alternative_loader) { + alternative_loaders_.push_back(std::move(alternative_loader)); + return *this; +} - if (strcasecmp(kTagLoader, tok1.c_str()) == 0) { - if (info != nullptr) { - if (!extra_array.empty()) { - info->extra_.Add(std::move(extra_array_key), std::move(extra_array)); - extra_array.clear(); - } +LoaderInfo::Builder& LoaderInfo::Builder::SetAlternativeLoaders( + std::vector alternative_loaders) { + alternative_loaders_ = std::move(alternative_loaders); + return *this; +} - loader_info_list.push_back(std::move(info)); - } +LoaderInfo::Builder& LoaderInfo::Builder::AddExtraData(std::string key, + std::string value) { + extra_.Add(std::move(key), std::move(value)); + return *this; +} - info = std::make_shared(); - continue; - } +LoaderInfo::Builder& LoaderInfo::Builder::AddExtraArrayData(std::string key, + std::vector value) { + extra_.Add(std::move(key), std::move(value)); + return *this; +} - if (!(ss >> tok2)) - continue; - if (tok1.front() == '#' || info == nullptr) - continue; +LoaderInfo::Builder& LoaderInfo::Builder::SetExtra(tizen_base::Bundle extra) { + extra_ = std::move(extra); + return *this; +} - std::string key; - std::transform(tok1.begin(), tok1.end(), std::back_inserter(key), - [](char ch) { return toupper(ch); }); - if (kTagName == key) { - info->name_ = std::move(tok2); - } else if (kTagExe == key) { - info->exe_ = std::move(tok2); - } else if (kTagAppType == key) { - ParseAppTypes(info, tok2, ss); - } else if (kTagDetectionMethod == key) { - ParseDetectionMethod(info, tok2, ss); - } else if (kTagActivationMethod == key) { - ParseActivationMethod(info, tok2, ss); - } else if (kTagDeactivationMethod == key) { - ParseDeactivationMethod(info, tok2, ss); - } else if (kTagTtl == key) { - info->ttl_ = std::stoul(tok2); - } else if (kTagTimeout == key) { - info->timeout_val_ = std::stoi(tok2); - } else if (kTagExtra == key) { - std::string val; - if (ss >> val) - info->extra_.Add(std::move(tok2), std::move(val)); - } else if (kTagExtraArray == key) { - if (!extra_array.empty()) { - info->extra_.Add(std::move(extra_array_key), std::move(extra_array)); - extra_array.clear(); - } - extra_array_key = std::move(tok2); - } else if (kTagExtraArrayVal == key) { - extra_array.push_back(std::move(tok2)); - } else if (kTagHwAcc == key) { - info->hw_acc_ = std::move(tok2); - } else if (kTagAlternativeLoader == key) { - info->alternative_loaders_.push_back(std::move(tok2)); - } else if (kTagCpuThresholdMax == key) { - info->cpu_threshold_max_ = std::stoi(tok2); - } else if (kTagCpuThresholdMin == key) { - info->cpu_threshold_min_ = std::stoi(tok2); - } else if (kTagOnBoot == key) { - if (kValOff == tok2) - info->on_boot_ = false; - } else if (kTagHydra == key) { - if (kValOn == tok2) - info->is_hydra_ = true; - else - info->is_hydra_ = false; - } else if (kTagAppCheck == key) { - if (kValOff == tok2) - info->app_check_ = false; - } else if (kTagOnBootTimeout == key) { - info->on_boot_timeout_ = std::stoi(tok2); - } else if (kTagSchedPriority == key) { - info->sched_priority_ = std::min(std::max(std::stoi(tok2), -20), 19); - } else if (key == kTagConditionPathExists) { - ParseConditionPathExists(info, tok2, ss); - } - } +LoaderInfo::Builder& LoaderInfo::Builder::SetCPUThresholdMax( + int cpu_threshold_max) { + cpu_threshold_max_ = cpu_threshold_max; + return *this; +} - fp.close(); - if (info != nullptr) { - if (!extra_array.empty()) - info->extra_.Add(std::move(extra_array_key), std::move(extra_array)); +LoaderInfo::Builder& LoaderInfo::Builder::SetCPUThresholdMin( + int cpu_threshold_min) { + cpu_threshold_min_ = cpu_threshold_min; + return *this; +} - loader_info_list.push_back(std::move(info)); - } +LoaderInfo::Builder& LoaderInfo::Builder::SetOnBoot(bool on_boot) { + on_boot_ = on_boot; + return *this; +} + +LoaderInfo::Builder& LoaderInfo::Builder::SetTimeToLive(int time_to_live) { + time_to_live_ = time_to_live; + return *this; +} + +LoaderInfo::Builder& LoaderInfo::Builder::SetHydraMode(bool hydra_mode) { + hydra_mode_ = hydra_mode; + return *this; +} + +LoaderInfo::Builder& LoaderInfo::Builder::SetAppCheck(bool app_check) { + app_check_ = app_check; + return *this; +} + +LoaderInfo::Builder& LoaderInfo::Builder::SetOnBootTimeout( + int on_boot_timeout) { + on_boot_timeout_ = on_boot_timeout; + return *this; +} + +LoaderInfo::Builder& LoaderInfo::Builder::SetSchedPriority(int sched_priority) { + sched_priority_ = sched_priority; + return *this; +} + +LoaderInfo::Builder& LoaderInfo::Builder::AddConditionPathExists( + std::string path) { + condition_path_exists_.push_back(std::move(path)); + return *this; +} + +LoaderInfo::Builder& LoaderInfo::Builder::SetConditionPathExists( + std::vector condition_path_exists) { + condition_path_exists_ = std::move(condition_path_exists); + return *this; +} + +LoaderInfo::Builder& LoaderInfo::Builder::Reset() { + type_ = LoaderType::None; + name_.clear(); + exe_.clear(); + app_types_.clear(); + detection_method_ = LoaderMethod::Timeout | LoaderMethod::Visibility | + LoaderMethod::Install; + activation_method_ = LoaderMethod::None; + deactivation_method_ = LoaderMethod::None; + timeout_ = 5000; + hw_acc_.clear(); + alternative_loaders_.clear(); + extra_ = tizen_base::Bundle(); + cpu_threshold_max_ = 90; + cpu_threshold_min_ = 40; + on_boot_ = true; + time_to_live_ = 600; + hydra_mode_ = false; + app_check_ = true; + on_boot_timeout_ = 0; + sched_priority_ = 0; + condition_path_exists_.clear(); + return *this; +} + +LoaderInfo* LoaderInfo::Builder::Build() { + return new LoaderInfo(type_, std::move(name_), std::move(exe_), + std::move(app_types_), detection_method_, activation_method_, + deactivation_method_, timeout_, std::move(hw_acc_), + std::move(alternative_loaders_), std::move(extra_), + cpu_threshold_max_, cpu_threshold_min_, on_boot_, time_to_live_, + hydra_mode_, app_check_, on_boot_timeout_, sched_priority_, + std::move(condition_path_exists_)); +} + +LoaderInfo::LoaderInfo(LoaderType type, std::string name, std::string exe, + std::vector app_types, LoaderMethod detection_method, + LoaderMethod activation_method, LoaderMethod deactivation_method, + int timeout, std::string hw_acc, + std::vector alternative_loaders, + tizen_base::Bundle extra, int cpu_threshold_max, + int cpu_threshold_min, bool on_boot, int time_to_live, + bool hydra_mode, bool app_check, int on_boot_timeout, + int sched_priority, std::vector condition_path_exists) + : type_(type), + name_(std::move(name)), + exe_(std::move(exe)), + app_types_(std::move(app_types)), + detection_method_(detection_method), + activation_method_(activation_method), + deactivation_method_(deactivation_method), + timeout_(timeout), + hw_acc_(std::move(hw_acc)), + alternative_loaders_(std::move(alternative_loaders)), + extra_(std::move(extra)), + cpu_threshold_max_(cpu_threshold_max), + cpu_threshold_min_(cpu_threshold_min), + on_boot_(on_boot), + time_to_live_(time_to_live), + hydra_mode_(hydra_mode), + app_check_(app_check), + on_boot_timeout_(on_boot_timeout), + sched_priority_(sched_priority), + condition_path_exists_(std::move(condition_path_exists)) { } LoaderType LoaderInfo::GetType() const { return type_; } +void LoaderInfo::SetType(LoaderType type) { + type_ = type; +} + const std::string& LoaderInfo::GetName() const { return name_; } @@ -271,6 +296,10 @@ const std::string& LoaderInfo::GetExe() const { return exe_; } +void LoaderInfo::SetExe(std::string exe) { + exe_ = std::move(exe); +} + int LoaderInfo::GetCpuThresholdMax() const { return cpu_threshold_max_; } @@ -279,8 +308,8 @@ int LoaderInfo::GetCpuThresholdMin() const { return cpu_threshold_min_; } -unsigned int LoaderInfo::GetTtl() const { - return ttl_; +int LoaderInfo::GetTimeToLive() const { + return time_to_live_; } const std::vector& LoaderInfo::GetAppTypes() const { @@ -291,80 +320,369 @@ LoaderMethod LoaderInfo::GetDetectionMethod() const { return detection_method_; } +void LoaderInfo::SetDetectionMethod(LoaderMethod detection_method) { + detection_method_ = detection_method; +} + LoaderMethod LoaderInfo::GetActivationMethod() const { return activation_method_; } +void LoaderInfo::SetActivationMethod(LoaderMethod activation_method) { + activation_method_ = activation_method; +} + LoaderMethod LoaderInfo::GetDeactivationMethod() const { return deactivation_method_; } +void LoaderInfo::SetDeactivationMethod(LoaderMethod deactivation_method) { + deactivation_method_ = deactivation_method; +} + const std::string& LoaderInfo::GetHwAcc() const { return hw_acc_; } -int LoaderInfo::GetOnbootTimeout() const { +int LoaderInfo::GetOnBootTimeout() const { return on_boot_timeout_; } -int LoaderInfo::GetTimeoutVal() const { - return timeout_val_; +int LoaderInfo::GetTimeout() const { + return timeout_; +} + +void LoaderInfo::SetTimeout(int timeout) { + timeout_ = timeout; } int LoaderInfo::GetSchedPriority() const { return sched_priority_; } -bool LoaderInfo::IsAppExists() const { - return app_exists_; +bool LoaderInfo::ShouldCheckAppInstallation() const { + return app_check_; } bool LoaderInfo::IsOnBoot() const { return on_boot_; } -bool LoaderInfo::IsHydraEnabled() const { - return is_hydra_; -} - -bool LoaderInfo::IsNeededAppCheck() const { - return app_check_; +bool LoaderInfo::IsHydraMode() const { + return hydra_mode_; } tizen_base::Bundle& LoaderInfo::GetExtra() { return extra_; } -void LoaderInfo::SetType(LoaderType type) { - type_ = type; +void LoaderInfo::SetAppInstalled(bool app_installed) { + app_installed_ = app_installed; } -void LoaderInfo::SetAppExists(bool exists) { - app_exists_ = exists; +bool LoaderInfo::IsAppInstalled() const { + return app_installed_; } const std::vector& LoaderInfo::GetConditionPathExists() const { return condition_path_exists_; } +LoaderInfoInflator::LoaderInfoInflator() { + parsers_ = { + { kTagName, + std::bind(&LoaderInfoInflator::ParseName, + this, std::placeholders::_1) }, + { kTagExe, + std::bind(&LoaderInfoInflator::ParseExe, + this, std::placeholders::_1) }, + { kTagAppType, + std::bind(&LoaderInfoInflator::ParseAppType, + this, std::placeholders::_1) }, + { kTagDetectionMethod, + std::bind(&LoaderInfoInflator::ParseDetectionMethod, + this, std::placeholders::_1) }, + { kTagActivationMethod, + std::bind(&LoaderInfoInflator::ParseActivationMethod, + this, std::placeholders::_1) }, + { kTagDeactivationMethod, + std::bind(&LoaderInfoInflator::ParseDeativationMethod, + this, std::placeholders::_1) }, + { kTagTtl, + std::bind(&LoaderInfoInflator::ParseTimeToLive, + this, std::placeholders::_1) }, + { kTagTimeout, + std::bind(&LoaderInfoInflator::ParseTimeout, + this, std::placeholders::_1) }, + { kTagExtra, + std::bind(&LoaderInfoInflator::ParseExtra, + this, std::placeholders::_1) }, + { kTagExtraArray, + std::bind(&LoaderInfoInflator::ParseExtraArray, + this, std::placeholders::_1) }, + { kTagExtraArrayVal, + std::bind(&LoaderInfoInflator::ParseExtraArrayValue, + this, std::placeholders::_1) }, + { kTagHwAcc, + std::bind(&LoaderInfoInflator::ParseHwAcc, + this, std::placeholders::_1) }, + { kTagAlternativeLoader, + std::bind(&LoaderInfoInflator::ParseAlternativeLoader, + this, std::placeholders::_1) }, + { kTagCpuThresholdMax, + std::bind(&LoaderInfoInflator::ParseCPUThresholdMax, + this, std::placeholders::_1) }, + { kTagCpuThresholdMin, + std::bind(&LoaderInfoInflator::ParseCPUThresholdMin, + this, std::placeholders::_1) }, + { kTagOnBoot, + std::bind(&LoaderInfoInflator::ParseOnBoot, + this, std::placeholders::_1) }, + { kTagHydra, + std::bind(&LoaderInfoInflator::ParseHydra, + this, std::placeholders::_1) }, + { kTagAppCheck, + std::bind(&LoaderInfoInflator::ParseAppCheck, + this, std::placeholders::_1) }, + { kTagOnBootTimeout, + std::bind(&LoaderInfoInflator::ParseOnBootTimeout, + this, std::placeholders::_1) }, + { kTagSchedPriority, + std::bind(&LoaderInfoInflator::ParseSchedPriority, + this, std::placeholders::_1) }, + { kTagConditionPathExists, + std::bind(&LoaderInfoInflator::ParseConditionPathExists, + this, std::placeholders::_1) }, + }; +} + +void LoaderInfoInflator::ParseName(std::string token) { + builder_.SetName(std::move(token)); +} + +void LoaderInfoInflator::ParseExe(std::string token) { + builder_.SetExe(std::move(token)); +} + +void LoaderInfoInflator::ParseAppType(std::string token) { + std::string line = std::move(token); + do { + auto tokens = Split(line, " |\t\r\n"); + for (auto& app_type : tokens) + builder_.AddAppType(app_type); + } while (std::getline(string_stream_, line)); +} + +void LoaderInfoInflator::ParseDetectionMethod(std::string token) { + LoaderMethod method = LoaderMethod::None; + std::string line = std::move(token); + do { + auto tokens = Split(line, " |\t\r\n"); + for (auto& token : tokens) { + if (token == kValMethodTimeout) + method = method | LoaderMethod::Timeout; + else if (token == kValMethodVisibility) + method = method | LoaderMethod::Visibility; + else if (token == kValMethodDemand) + method = method | LoaderMethod::Demand; + } + } while (std::getline(string_stream_, line)); + + method = method | LoaderMethod::Install; + builder_.SetDetectionMethod(method); + _D("Detection method: %d", static_cast(method)); +} + +void LoaderInfoInflator::ParseActivationMethod(std::string token) { + LoaderMethod method = LoaderMethod::None; + std::string line = std::move(token); + do { + auto tokens = Split(line, " |\t\r\n"); + for (auto& token : tokens) { + if (token == kValMethodRequest) + method = method | LoaderMethod::Request; + else if (token == kValMethodAvailableMemory) + method = method | LoaderMethod::AvailableMemory; + } + } while (std::getline(string_stream_, line)); + + builder_.SetActivationMethod(method); + _D("Activation method: %d", static_cast(method)); +} + +void LoaderInfoInflator::ParseDeativationMethod(std::string token) { + LoaderMethod method = LoaderMethod::None; + std::string line = std::move(token); + do { + auto tokens = Split(line, " |\t\r\n"); + for (auto& token : tokens) { + if (token == kValMethodTtl) + method = method | LoaderMethod::TimeToLive; + else if (token == kValMethodOutOfMemory) + method = method | LoaderMethod::OutOfMemory; + } + } while (std::getline(string_stream_, line)); + + builder_.SetDeactivationMethod(method); + _D("Deactivation method: %d", static_cast(method)); +} + +void LoaderInfoInflator::ParseTimeToLive(std::string token) { + builder_.SetTimeToLive(std::stoi(token)); +} + +void LoaderInfoInflator::ParseTimeout(std::string token) { + builder_.SetTimeout(std::stoi(token)); +} + +void LoaderInfoInflator::ParseExtra(std::string token) { + std::string value; + if (string_stream_ >> value) + builder_.AddExtraData(std::move(token), std::move(value)); +} + +void LoaderInfoInflator::ParseExtraArray(std::string token) { + if (!extra_array_key_.empty() && !extra_array_value_.empty()) { + builder_.AddExtraArrayData(std::move(extra_array_key_), + std::move(extra_array_value_)); + extra_array_value_.clear(); + } + + extra_array_key_ = std::move(token); +} + +void LoaderInfoInflator::ParseExtraArrayValue(std::string token) { + extra_array_value_.push_back(std::move(token)); +} + +void LoaderInfoInflator::ParseHwAcc(std::string token) { + builder_.SetHwAcc(std::move(token)); +} + +void LoaderInfoInflator::ParseAlternativeLoader(std::string token) { + builder_.AddAlternativeLoader(std::move(token)); +} + +void LoaderInfoInflator::ParseCPUThresholdMax(std::string token) { + builder_.SetCPUThresholdMax(std::stoi(token)); +} + +void LoaderInfoInflator::ParseCPUThresholdMin(std::string token) { + builder_.SetCPUThresholdMin(std::stoi(token)); +} + +void LoaderInfoInflator::ParseOnBoot(std::string token) { + if (token == kValOff) + builder_.SetOnBoot(false); +} + +void LoaderInfoInflator::ParseHydra(std::string token) { + if (token == kValOn) + builder_.SetHydraMode(true); +} + +void LoaderInfoInflator::ParseAppCheck(std::string token) { + if (token == kValOff) + builder_.SetAppCheck(false); +} + +void LoaderInfoInflator::ParseOnBootTimeout(std::string token) { + builder_.SetOnBootTimeout(std::stoi(token)); +} + +void LoaderInfoInflator::ParseSchedPriority(std::string token) { + builder_.SetSchedPriority(std::min(std::max(std::stoi(token), -20), 19)); +} + +void LoaderInfoInflator::ParseConditionPathExists(std::string token) { + std::string line = std::move(token); + do { + auto tokens = Split(line, " |\t\r\n"); + for (auto& token : tokens) + builder_.AddConditionPathExists(token); + } while (std::getline(string_stream_, line)); +} + +void LoaderInfoInflator::Parse(const std::filesystem::path& path, + LoaderType type) { + std::ifstream loader_file; + loader_file.open(path); + if (loader_file.fail()) + return; + + bool parsing = false; + std::string line; + while (std::getline(loader_file, line)) { + string_stream_ = std::istringstream(line); + std::string token1; + if (!(string_stream_ >> token1)) + continue; + + std::string key = ToUpper(std::move(token1)); + if (key == kTagLoader) { + if (parsing) + Insert(type); + + builder_.Reset(); + parsing = true; + continue; + } + + if (parsing == false) + continue; + + std::string token2; + if (!(string_stream_ >> token2)) + continue; + + auto found = parsers_.find(key); + if (found == parsers_.end()) + continue; + + auto& parser = found->second; + parser(std::move(token2)); + } + + if (parsing) + Insert(type); + + loader_file.close(); +} + +void LoaderInfoInflator::Insert(LoaderType type) { + if (!extra_array_key_.empty() && !extra_array_value_.empty()) { + builder_.AddExtraArrayData(std::move(extra_array_key_), + std::move(extra_array_value_)); + extra_array_value_.clear(); + } + + if (type != LoaderType::Dynamic) + type = MakeLoaderType(); + + builder_.SetType(type); + loader_infos_.emplace_back(builder_.Build()); +} + std::vector LoaderInfoInflator::Inflate( const std::string_view path) { - fs::path p(path); - if (fs::is_directory(p) == false) + fs::path input_path(path); + if (fs::is_directory(input_path) == false) return {}; - std::vector result; - for (auto& entry : fs::directory_iterator(p)) { - fs::path file(entry.path()); - if (file.extension() == ".loader") - Parse(result, file); + try { + for (auto& entry : fs::directory_iterator(input_path)) { + fs::path file(entry.path()); + if (file.extension() == ".loader") + Parse(file, LoaderType::User); + } + } catch (const fs::filesystem_error& e) { + _E("Exception occurs. error(%s:%d)", e.what(), e.code().value()); } - return result; + return loader_infos_; } LoaderInfoManager::LoaderInfoManager(std::string path): path_(std::move(path)) { - } void LoaderInfoManager::Load() { @@ -377,15 +695,15 @@ void LoaderInfoManager::Load() { void LoaderInfoManager::LoadFile(const std::string_view file) { LoaderInfoInflator inflator; - fs::path p(path_); - inflator.Parse(loader_list_, p / file); + fs::path path(path_); + inflator.Parse(path / file, LoaderType::Dynamic); } void LoaderInfoManager::Unload(const std::string_view loader_name) { loader_list_.erase(std::remove_if(loader_list_.begin(), loader_list_.end(), - [&](const LoaderInfoPtr& info) -> bool { - return info->GetName() == loader_name; - }), loader_list_.end()); + [&](const LoaderInfoPtr& info) -> bool { + return info->GetName() == loader_name; + }), loader_list_.end()); } void LoaderInfoManager::Dispose() { @@ -415,31 +733,29 @@ LoaderInfoPtr LoaderInfoManager::FindLoaderInfo( LoaderType LoaderInfoManager::FindHwType(const std::string_view app_type) { for (auto& info : loader_list_) { if (info->GetHwAcc().empty() || info->GetHwAcc() == kValOn) { - auto it = std::find_if( + auto found = std::find_if( info->GetAppTypes().begin(), info->GetAppTypes().end(), [&](const std::string& type) -> bool { return type == app_type; }); - - if (it != info->GetAppTypes().end()) + if (found != info->GetAppTypes().end()) return info->GetType(); } } - return LoaderType::Unsupported; + return LoaderType::None; } LoaderType LoaderInfoManager::FindSwType(const std::string_view app_type) { for (auto& info : loader_list_) { if (info->GetHwAcc().empty() || info->GetHwAcc() == kValOff) { - auto it = std::find_if( + auto found = std::find_if( info->GetAppTypes().begin(), info->GetAppTypes().end(), [&](const std::string& type) -> bool { return type == app_type; }); - - if (it != info->GetAppTypes().end()) + if (found != info->GetAppTypes().end()) return info->GetType(); } } - return LoaderType::Unsupported; + return LoaderType::None; } std::vector LoaderInfoManager::GetAlternativeTypes( @@ -448,14 +764,14 @@ std::vector LoaderInfoManager::GetAlternativeTypes( for (auto& info : loader_list_) { if (info->GetType() == type) { for (auto& alt_loader : info->alternative_loaders_) { - auto it = std::find_if(loader_list_.begin(), loader_list_.end(), - [&](const auto& li) -> bool { - return li->GetName() == alt_loader; - }); - - if (it != loader_list_.end()) { - result.push_back((*it)->GetType()); - } + auto found = std::find_if(loader_list_.begin(), loader_list_.end(), + [&](const auto& li) -> bool { + return li->GetName() == alt_loader; + }); + if (found == loader_list_.end()) + continue; + + result.push_back((*found)->GetType()); } } } diff --git a/src/launchpad-process-pool/loader_info.hh b/src/launchpad-process-pool/loader_info.hh index af12572..4f4e982 100644 --- a/src/launchpad-process-pool/loader_info.hh +++ b/src/launchpad-process-pool/loader_info.hh @@ -14,120 +14,208 @@ * limitations under the License. */ -#ifndef LOADER_INFO_HH_ -#define LOADER_INFO_HH_ +#ifndef LAUNCHPAD_PROCESS_POOL_LOADER_INFO_HH_ +#define LAUNCHPAD_PROCESS_POOL_LOADER_INFO_HH_ #include #include +#include #include #include #include +#include #include #include "launchpad-process-pool/util.hh" namespace launchpad { -constexpr int DefaultCpuThresholdMax = 90; -constexpr int DefaultCpuThresholdMin = 40; - enum class LoaderType : int { - Unsupported = -1, - User = 1, - Dynamic = 100, - Max + None = 0, + User = 1, + Dynamic = 100, }; enum class LoaderMethod : int { - Empty = 0x0000, - Timeout = 0x0001, - Visibility = 0x0002, - Demand = 0x0004, - Request = 0x0010, + None = 0x0000, + Timeout = 0x0001, + Visibility = 0x0002, + Demand = 0x0004, + Request = 0x0010, AvailableMemory = 0x0020, - Ttl = 0x0040, - OutOfMemory = 0x0100, - Install = 0x0200, + TimeToLive = 0x0040, + OutOfMemory = 0x0100, + Install = 0x0200, }; class LoaderInfo { public: + class Builder { + public: + Builder& SetType(LoaderType type); + Builder& SetName(std::string name); + Builder& SetExe(std::string exe); + Builder& AddAppType(std::string app_type); + Builder& SetAppTypes(std::vector app_types); + Builder& SetDetectionMethod(launchpad::LoaderMethod method); + Builder& SetActivationMethod(launchpad::LoaderMethod method); + Builder& SetDeactivationMethod(launchpad::LoaderMethod method); + Builder& SetTimeout(int timeout); + Builder& SetHwAcc(std::string hw_acc); + Builder& AddAlternativeLoader(std::string alternative_loader); + Builder& SetAlternativeLoaders( + std::vector alternative_loaders); + Builder& AddExtraData(std::string key, std::string value); + Builder& AddExtraArrayData(std::string key, std::vector value); + Builder& SetExtra(tizen_base::Bundle extra); + Builder& SetCPUThresholdMax(int cpu_threshold_max); + Builder& SetCPUThresholdMin(int cpu_threshold_min); + Builder& SetOnBoot(bool on_boot); + Builder& SetTimeToLive(int time_to_live); + Builder& SetHydraMode(bool hydra_mode); + Builder& SetAppCheck(bool app_check); + Builder& SetOnBootTimeout(int on_boot_timeout); + Builder& SetSchedPriority(int sched_priority); + Builder& AddConditionPathExists(std::string path); + Builder& SetConditionPathExists( + std::vector condition_path_exists); + Builder& Reset(); + + LoaderInfo* Build(); + + private: + LoaderType type_ = LoaderType::None; + std::string name_; + std::string exe_; + std::vector app_types_; + LoaderMethod detection_method_ = + LoaderMethod::Timeout | LoaderMethod::Visibility | LoaderMethod::Install; + LoaderMethod activation_method_ = LoaderMethod::None; + LoaderMethod deactivation_method_ = LoaderMethod::None; + int timeout_ = 5000; + std::string hw_acc_; + std::vector alternative_loaders_; + tizen_base::Bundle extra_; + int cpu_threshold_max_ = 90; + int cpu_threshold_min_ = 40; + bool on_boot_ = true; + int time_to_live_ = 600; + bool hydra_mode_ = false; + bool app_check_ = true; + int on_boot_timeout_ = 0; + int sched_priority_ = 0; + std::vector condition_path_exists_; + }; + + LoaderInfo(LoaderType type, std::string name, std::string exe, + std::vector app_types, LoaderMethod detection_method, + LoaderMethod activation_method, LoaderMethod deactivation_method, + int timeout, std::string hw_acc, + std::vector alternative_loaders, + tizen_base::Bundle extra, int cpu_threshold_max, + int cpu_threshold_min, bool on_boot, int time_to_live, + bool hydra_mode, bool app_check, int on_boot_timeout, + int sched_priority, + std::vector condition_path_exists); + LoaderType GetType() const; + void SetType(LoaderType type); const std::string& GetName() const; const std::string& GetExe() const; + void SetExe(std::string exe); int GetCpuThresholdMax() const; int GetCpuThresholdMin() const; - unsigned int GetTtl() const; + int GetTimeToLive() const; const std::vector& GetAppTypes() const; LoaderMethod GetDetectionMethod() const; + void SetDetectionMethod(LoaderMethod detection_method); LoaderMethod GetActivationMethod() const; + void SetActivationMethod(LoaderMethod activation_method); LoaderMethod GetDeactivationMethod() const; + void SetDeactivationMethod(LoaderMethod deactivation_method); const std::string& GetHwAcc() const; - int GetOnbootTimeout() const; - int GetTimeoutVal() const; + int GetOnBootTimeout() const; + int GetTimeout() const; + void SetTimeout(int timeout); int GetSchedPriority() const; - bool IsAppExists() const; + bool ShouldCheckAppInstallation() const; bool IsOnBoot() const; - bool IsHydraEnabled() const; - bool IsNeededAppCheck() const; + bool IsHydraMode() const; tizen_base::Bundle& GetExtra(); - void SetType(LoaderType type); - void SetAppExists(bool exsits); const std::vector& GetConditionPathExists() const; + void SetAppInstalled(bool app_installed); + bool IsAppInstalled() const; + + private: + friend class LoaderInfoManager; + friend class LoaderInfoInflator; private: - LoaderType type_ = LoaderType::Unsupported; + LoaderType type_; std::string name_; std::string exe_; std::vector app_types_; - LoaderMethod detection_method_ = - LoaderMethod::Timeout | LoaderMethod::Visibility | LoaderMethod::Install; - LoaderMethod activation_method_ = LoaderMethod::Empty; - LoaderMethod deactivation_method_ = LoaderMethod::Empty; - int timeout_val_ = 5000; + LoaderMethod detection_method_; + LoaderMethod activation_method_; + LoaderMethod deactivation_method_; + int timeout_; std::string hw_acc_; std::vector alternative_loaders_; tizen_base::Bundle extra_; - int cpu_threshold_max_ = DefaultCpuThresholdMax; - int cpu_threshold_min_ = DefaultCpuThresholdMin; - bool on_boot_ = true; - bool global_ = false; - bool app_exists_ = false; - unsigned int ttl_ = 600U; /* 10 minute */ - bool is_hydra_ = false; - bool app_check_ = true; - int on_boot_timeout_ = 0; - int sched_priority_ = 0; + int cpu_threshold_max_; + int cpu_threshold_min_; + bool on_boot_; + int time_to_live_; + bool hydra_mode_; + bool app_check_; + int on_boot_timeout_; + int sched_priority_; std::vector condition_path_exists_; - - friend class LoaderInfoManager; - friend class LoaderInfoInflator; + bool app_installed_ = false; }; using LoaderInfoPtr = std::shared_ptr; class LoaderInfoInflator { public: + LoaderInfoInflator(); + std::vector Inflate(const std::string_view path); - void Parse(std::vector& launcher_info_list, - const std::filesystem::path& path); + + void Parse(const std::filesystem::path& path, LoaderType type); + + private: + void ParseName(std::string token); + void ParseExe(std::string token); + void ParseAppType(std::string token); + void ParseDetectionMethod(std::string token); + void ParseActivationMethod(std::string token); + void ParseDeativationMethod(std::string token); + void ParseTimeToLive(std::string token); + void ParseTimeout(std::string token); + void ParseExtra(std::string token); + void ParseExtraArray(std::string token); + void ParseExtraArrayValue(std::string token); + void ParseHwAcc(std::string token); + void ParseAlternativeLoader(std::string token); + void ParseCPUThresholdMax(std::string token); + void ParseCPUThresholdMin(std::string token); + void ParseOnBoot(std::string token); + void ParseHydra(std::string token); + void ParseAppCheck(std::string token); + void ParseOnBootTimeout(std::string token); + void ParseSchedPriority(std::string token); + void ParseConditionPathExists(std::string token); + void Insert(LoaderType type); private: - void ParseDetectionMethod(const LoaderInfoPtr& info, - std::string& tok_start, - std::istringstream& ss); - void ParseActivationMethod(const LoaderInfoPtr& info, - std::string& tok_start, - std::istringstream& ss); - void ParseDeactivationMethod(const LoaderInfoPtr& info, - std::string& tok_start, - std::istringstream& ss); - void ParseAppTypes(const LoaderInfoPtr& info, - std::string& tok_start, - std::istringstream& ss); - void ParseConditionPathExists(const LoaderInfoPtr& info, - const std::string& tok_start, std::istringstream& stream); + std::unordered_map> parsers_; + std::istringstream string_stream_; + std::string extra_array_key_; + std::vector extra_array_value_; + LoaderInfo::Builder builder_; + std::vector> loader_infos_; }; class LoaderInfoManager { @@ -154,4 +242,4 @@ class LoaderInfoManager { } // namespace launchpad -#endif // LOADER_INFO_HH_ +#endif // LAUNCHPAD_PROCESS_POOL_LOADER_INFO_HH_ diff --git a/src/launchpad-process-pool/loader_manager.cc b/src/launchpad-process-pool/loader_manager.cc new file mode 100644 index 0000000..37c6c33 --- /dev/null +++ b/src/launchpad-process-pool/loader_manager.cc @@ -0,0 +1,526 @@ +/* + * 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-process-pool/loader_manager.hh" + +#include +#include + +#include "launchpad-process-pool/config.hh" +#include "launchpad-process-pool/loader_factory.hh" +#include "launchpad-process-pool/log_private.hh" + +namespace launchpad { +namespace { + +constexpr const char kInfoDirectoryPath[] = "/usr/share/aul"; + +} // namespace + +LoaderManager& LoaderManager::GetInst() { + static LoaderManager inst; + inst.Init(); + return inst; +} + +void LoaderManager::Dispose() { + if (disposed_) + return; + + hwacc_config_.reset(); + app_defined_loader_info_manager_.reset(); + loader_info_manager_.reset(); + MemoryMonitor::GetInst().Dispose(); + AppLabelsMonitor::GetInst().Dispose(); + disposed_ = true; +} + +void LoaderManager::Init() { + if (!disposed_) + return; + + try { + sequencer_.reset(new Sequencer(this)); + auto& label_monitor = AppLabelsMonitor::GetInst(); + label_monitor.Init(); + label_monitor.SetEventListener(this); + MemoryMonitor::GetInst().SetEventListener(this); + + app_defined_loader_info_manager_.reset(new AppDefinedLoaderInfoManager()); + app_defined_loader_info_manager_->SetEventListener(this); + hwacc_config_.reset(new HWAccelerationConfig()); + } catch (const Exception& e) { + _E("Exception occurs. error: %s", e.what()); + return; + } + + disposed_ = false; +} + +void LoaderManager::HandleSigchld(pid_t pid) { + auto context = FindLoaderContextFromPid(pid); + if (context != nullptr) { + context->SetPid(0); + context->Dispose(); + context->Prepare(); + } else { + auto hydra_context = FindHydraLoaderContextFromPid(pid); + if (hydra_context != nullptr) { + hydra_context->SetHydraPid(0); + hydra_context->Dispose(); + hydra_context->Prepare(); + } + } + + RemoveLoaderContextsByCallerPid(pid); +} + +void LoaderManager::AddDefaultLoaderContexts() { + loader_info_manager_.reset(new LoaderInfoManager(kInfoDirectoryPath)); + loader_info_manager_->Load(); + + for (auto& info : loader_info_manager_->GetLoaderInfoList()) { + auto context = LoaderFactory::GetInst().CreateLoaderContext(info); + if (context != nullptr) + loader_contexts_.push_back(std::move(context)); + } + + ActivateLoaderContexts(LoaderMethod::None); +} + +void LoaderManager::ActivateLoaderContexts(LoaderMethod method) { + for (auto& context : loader_contexts_) { + if (!context->IsTouched() && context->IsOnBoot() && + context->GetOnBootTimeout() > 0) + context->SetOnBootTimer(context->GetOnBootTimeout()); + + if (!context->IsActivated()) + continue; + + if (context->GetLoaderPath() == "null") + continue; + + if (!context->IsTouched() && !context->IsOnBoot()) + continue; + + if (context->GetPid() > 0) + continue; + + if (!context->IsTouched() || context->CanActivate(method)) { + context->UnsetTimer(); + context->SetLoaderMethod(method); + sequencer_->Add(context); + sequencer_->Run(); + } + } +} + +std::shared_ptr LoaderManager::PrepareAppDefinedLoaderContext( + const std::string& name, pid_t caller_pid) { + auto info = app_defined_loader_info_manager_->Find(name.c_str()); + if (info == nullptr) { + _E("There is no loaders. loader_name: %s", name.c_str()); + return nullptr; + } + + auto context = FindLoaderContextFromName(name); + if (context == nullptr) { + context = LoaderFactory::GetInst().CreateLoaderContext(info, caller_pid); + if (context == nullptr) { + _E("Failed to create loader context. loader_name: %s", + name.c_str()); + return nullptr; + } + + loader_contexts_.push_back(context); + } + + if (context->GetPid() < 1) + context->Prepare(); + + return context; +} + +std::shared_ptr LoaderManager::AddLoaderContext( + tizen_base::Bundle b) { + auto context = LoaderFactory::GetInst().CreateLoaderContext(std::move(b)); + if (context == nullptr) + return nullptr; + + context->SetTimer(this); + loader_contexts_.push_back(context); + return context; +} + +void LoaderManager::HandleDirectLaunch(std::shared_ptr context) { + if (context == nullptr) + return; + + if (context->ShouldCheckAppInstallation() && !context->IsAppInstalled()) + return; + + if (context->GetPid() > 0) + return; + + if (sequencer_->Exist(context)) + return; + + context->UnsetTimer(); + context->UpdateState(LoaderMethod::Request, true); + context->SetTimer(this); +} + +void LoaderManager::UpdateAppInstallationStatus(const std::string& app_type, + bool app_installed) { + for (auto& info : loader_info_manager_->GetLoaderInfoList()) { + auto found = std::find_if(info->GetAppTypes().begin(), + info->GetAppTypes().end(), + [&](const std::string& type) -> bool { return type == app_type; }); + if (found == info->GetAppTypes().end()) + continue; + + info->SetAppInstalled(app_installed); + UpdateLoaderContext(info->GetType()); + } +} + +std::shared_ptr LoaderManager::FindLoaderContextFromPid( + pid_t pid) { + for (auto& context : loader_contexts_) { + if (context->GetPid() == pid) + return context; + } + + return nullptr; +} + +std::shared_ptr +LoaderManager::FindHydraLoaderContextFromPid(pid_t pid) { + for (auto& context : loader_contexts_) { + if (context->IsHydraMode()) { + auto* hydra_context = dynamic_cast(context.get()); + if (hydra_context != nullptr && hydra_context->GetHydraPid() == pid) + return std::dynamic_pointer_cast( + hydra_context->shared_from_this()); + } + } + + return nullptr; +} + +void LoaderManager::RemoveLoaderContextsByCallerPid(pid_t caller_pid) { + auto iter = loader_contexts_.begin(); + while (iter != loader_contexts_.end()) { + auto& context = (*iter); + if (context->GetCallerPid() == caller_pid) { + context->Dispose(); + iter = loader_contexts_.erase(iter); + } else { + iter++; + } + } +} + +std::shared_ptr LoaderManager::FindLoaderContextFromName( + const std::string& loader_name) { + for (auto& context : loader_contexts_) { + if (context->GetLoaderName() == loader_name) + return context; + } + + return nullptr; +} + +std::shared_ptr LoaderManager::FindLoaderContext(LoaderType type, + int loader_id) { + if (type == LoaderType::Dynamic) + return FindLoaderContextFromLoaderId(loader_id); + + return FindLoaderContextFromType(type); +} + +std::shared_ptr LoaderManager::FindLoaderContextFromLoaderId( + int loader_id) { + for (auto& context : loader_contexts_) { + if (context->GetLoaderId() == loader_id) + return context; + } + + return nullptr; +} + +std::shared_ptr LoaderManager::FindLoaderContextFromType( + LoaderType type) { + if (type == LoaderType::Dynamic || type == LoaderType::None) + return nullptr; + + for (auto& context : loader_contexts_) { + if (context->GetType() == static_cast(type)) + return context; + } + + return nullptr; +} + +std::shared_ptr LoaderManager::FindAvailableLoaderContext( + const std::string& hwacc, const std::string& app_type, + const std::string& loader_name) { + LoaderType type = LoaderType::None; + if (!loader_name.empty()) { + for (auto& info : loader_info_manager_->GetLoaderInfoList()) { + if (info->GetName() == loader_name) { + type = info->GetType(); + break; + } + } + } else { + if (IsHwAcceleration(hwacc)) + type = loader_info_manager_->FindHwType(app_type); + else + type = loader_info_manager_->FindSwType(app_type); + } + + return FindLoaderContext(type, PAD_LOADER_ID_STATIC); +} + +std::shared_ptr LoaderManager::FindAlternativeLoaderContext( + LoaderType type) { + auto alternative_types = loader_info_manager_->GetAlternativeTypes(type); + for (auto& alternative_type : alternative_types) { + auto context = FindLoaderContext(alternative_type, PAD_LOADER_ID_STATIC); + if (context == nullptr) + continue; + + if (context->IsPrepared()) + return context; + } + + return nullptr; +} + +bool LoaderManager::IsHwAcceleration(const std::string& hwacc) { + if (hwacc == "USE" || + (hwacc == "SYS" && hwacc_config_->Get() == SETTING_HW_ACCELERATION_ON)) + return true; + + return false; +} + +void LoaderManager::UpdateLoaderContext(LoaderType type) { + auto loader_context = FindLoaderContextFromType(type); + if (loader_context == nullptr) + return; + + _W("type(%d), loader_name(%s), app_installed(%s:%s)", + static_cast(type), loader_context->GetLoaderName().c_str(), + loader_context->ShouldCheckAppInstallation() ? "yes" : "no", + loader_context->IsAppInstalled() ? "yes" : "no"); + if (loader_context->ShouldCheckAppInstallation() && + !loader_context->IsAppInstalled()) { + loader_context->Dispose(); + sequencer_->Remove(loader_context); + } else { + if (!loader_context->IsActivated()) + return; + + if (!loader_context->IsTouched() && !loader_context->IsOnBoot()) + return; + + loader_context->UnsetTimer(); + if (loader_context->GetPid() < 1) { + sequencer_->Add(loader_context); + sequencer_->Run(); + } + } +} + +void LoaderManager::RemoveLoaderContext(LoaderType type, int loader_id) { + auto iter = loader_contexts_.begin(); + while (iter != loader_contexts_.end()) { + auto& loader_context = *iter; + if (loader_context->GetType() == static_cast(type) && + loader_context->GetLoaderId() == loader_id) + iter = loader_contexts_.erase(iter); + else + iter++; + } +} + +void LoaderManager::RemoveLoaderContext(const std::string_view loader_name) { + auto iter = loader_contexts_.begin(); + while (iter != loader_contexts_.end()) { + auto& loader_context = *iter; + if (loader_context->GetLoaderName() == loader_name) + iter = loader_contexts_.erase(iter); + else + iter++; + } +} + +void LoaderManager::UpdateLoaderContexts(bool low_memory) { + for (auto& loader_context : loader_contexts_) { + if (low_memory) + loader_context->UpdateState(LoaderMethod::OutOfMemory, true); + else + loader_context->UpdateState(LoaderMethod::AvailableMemory, true); + } +} + +void LoaderManager::HandleMemoryStatusChangedEvent(bool low_memory) { + if (low_memory) { + _W("Low memory"); + UpdatePssMemoryOfLoaderContexts(); + SortLoaderContexts(); + DeactivateLoaderContexts(); + } else { + ActivateLoaderContexts(); + } +} + +void LoaderManager::UpdatePssMemoryOfLoaderContexts() { + for (auto& loader_context : loader_contexts_) { + if (loader_context->GetPid() > 0) + loader_context->UpdatePssMemory(); + } +} + +void LoaderManager::SortLoaderContexts() { + std::sort(loader_contexts_.begin(), loader_contexts_.end(), + [&](const std::shared_ptr context_a, + const std::shared_ptr context_b) -> bool { + if (context_a->IsHydraMode() && !context_b->IsHydraMode()) + return false; + + if (!context_a->IsHydraMode() && context_b->IsHydraMode()) + return true; + + if (context_a->GetScore() > context_b->GetScore()) + return false; + + if (context_a->GetScore() < context_b->GetScore()) + return true; + + return context_a->GetPssMemory() < context_b->GetPssMemory(); + }); +} + +void LoaderManager::DeactivateLoaderContexts() { + for (auto& loader_context : loader_contexts_) { + if (loader_context->IsHydraMode()) + continue; + + loader_context->UpdateState(LoaderMethod::OutOfMemory, true); + if (!MemoryMonitor::GetInst().IsLowMemory()) + return; + } +} + +void LoaderManager::ActivateLoaderContexts() { + for (auto& loader_context : loader_contexts_) + loader_context->UpdateState(LoaderMethod::AvailableMemory, true); +} + +LoaderManager::LoaderManager() : sequencer_(new Sequencer(this)) {} + +LoaderManager::~LoaderManager() { + Dispose(); +} + +void LoaderManager::OnAppLabelsChanged() { + for (auto& context : loader_contexts_) { + if (context->IsHydraMode()) { + auto* hydra_context = dynamic_cast(context.get()); + if (hydra_context != nullptr && hydra_context->GetPid() > 0) { + hydra_context->Dispose(); + hydra_context->Prepare(); + } + } else if (context->GetPid() > 0) { + context->Dispose(); + context->Prepare(); + } + } +} + +void LoaderManager::OnMemoryStatusChanged(bool low_memory, + bool should_check_pss) { + if (should_check_pss) + HandleMemoryStatusChangedEvent(low_memory); + else + UpdateLoaderContexts(low_memory); +} + +void LoaderManager::OnLoaderInfoAdded(const std::string_view name) { + _W("%s is added", name.data()); +} + +void LoaderManager::OnLoaderInfoRemoved(const std::string_view name) { + _W("%s is removed", name.data()); + RemoveLoaderContext(name); +} + +void LoaderManager::OnTimeoutEvent(LoaderContext* context) { + _W("type(%d), loader_name(%s), state(%d)", + context->GetType(), context->GetLoaderName().c_str(), + context->IsActivated()); + + if (context->GetPid() > 0) { + _W("The loader is already running"); + return; + } + + sequencer_->Add(context->shared_from_this()); + sequencer_->Run(); +} + +bool LoaderManager::OnIdleCheck(LoaderContext* context) { + _W("Loader(%s), type(%d), pid(%d)", + context->GetLoaderName().c_str(), context->GetType(), context->GetPid()); + + if (context->ShouldCheckAppInstallation() && !context->IsAppInstalled()) { + _W("The application is not installed"); + return false; + } + + if (context->ShouldWaitForFileCreation()) { + _W("The loader should wait for file creation"); + return false; + } + + if (!context->IsActivated()) { + _W("The loader is deactivated"); + return false; + } + + if (context->GetPid() > 0) { + _W("The loader is already running"); + return false; + } + + if (context->GetCPUChecker()->IsIdle()) { + context->Prepare(); + return false; + } + + int count = context->IncreaseCPUCheckCount(); + if (count == Config::GetInst().GetCPUChecker().GetMaxCount()) { + _W("CPU check count has exceeded %d times", count); + sequencer_->Add(context->shared_from_this()); + } + + return true; +} + +} // namespace launchpad diff --git a/src/launchpad-process-pool/loader_manager.hh b/src/launchpad-process-pool/loader_manager.hh new file mode 100644 index 0000000..e715f5a --- /dev/null +++ b/src/launchpad-process-pool/loader_manager.hh @@ -0,0 +1,111 @@ +/* + * 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 LAUNCHPAD_PROCESS_POOL_LOADER_MANAGER_HH_ +#define LAUNCHPAD_PROCESS_POOL_LOADER_MANAGER_HH_ + +#include +#include +#include + +#include +#include +#include +#include + +#include "launchpad-process-pool/app_defined_loader_info_manager.hh" +#include "launchpad-process-pool/app_labels_monitor.hh" +#include "launchpad-process-pool/hw_acceleration_config.hh" +#include "launchpad-process-pool/hydra_loader_context.hh" +#include "launchpad-process-pool/loader_context.hh" +#include "launchpad-process-pool/loader_info.hh" +#include "launchpad-process-pool/memory_monitor.hh" +#include "launchpad-process-pool/sequencer.hh" + +namespace launchpad { + +class LoaderManager : public AppDefinedLoaderInfoManager::IEvent, + public AppLabelsMonitor::IEvent, + public MemoryMonitor::IEvent, + public Sequencer::IEvent, + public LoaderContext::IEvent { + public: + LoaderManager(const LoaderManager&) = delete; + LoaderManager& operator=(const LoaderManager&) = delete; + LoaderManager(LoaderManager&&) = delete; + LoaderManager& operator=(LoaderManager&&) = delete; + + static LoaderManager& GetInst(); + void Dispose(); + + void HandleSigchld(pid_t pid); + void AddDefaultLoaderContexts(); + void ActivateLoaderContexts(LoaderMethod method); + std::shared_ptr PrepareAppDefinedLoaderContext( + const std::string& name, pid_t caller_pid); + std::shared_ptr AddLoaderContext(tizen_base::Bundle b); + void UpdateAppInstallationStatus(const std::string& app_type, + bool app_installed); + void HandleDirectLaunch(std::shared_ptr context); + std::shared_ptr FindLoaderContext(LoaderType type, + int loader_id); + std::shared_ptr FindAvailableLoaderContext( + const std::string& hwacc, const std::string& app_type, + const std::string& loader_name); + std::shared_ptr FindAlternativeLoaderContext(LoaderType type); + void RemoveLoaderContext(LoaderType type, int loader_id); + + private: + LoaderManager(); + ~LoaderManager(); + + void Init(); + std::shared_ptr FindLoaderContextFromPid(pid_t pid); + std::shared_ptr FindHydraLoaderContextFromPid(pid_t pid); + std::shared_ptr FindLoaderContextFromName( + const std::string& loader_name); + std::shared_ptr FindLoaderContextFromLoaderId(int loader_id); + std::shared_ptr FindLoaderContextFromType(LoaderType type); + void RemoveLoaderContextsByCallerPid(pid_t caller_pid); + bool IsHwAcceleration(const std::string& hwacc); + void UpdateLoaderContext(LoaderType type); + void RemoveLoaderContext(const std::string_view loader_name); + void UpdateLoaderContexts(bool low_memory); + void HandleMemoryStatusChangedEvent(bool low_memory); + void UpdatePssMemoryOfLoaderContexts(); + void SortLoaderContexts(); + void DeactivateLoaderContexts(); + void ActivateLoaderContexts(); + + void OnAppLabelsChanged() override; + void OnMemoryStatusChanged(bool low_memory, bool should_check_pss) override; + void OnLoaderInfoAdded(const std::string_view name) override; + void OnLoaderInfoRemoved(const std::string_view name) override; + void OnTimeoutEvent(LoaderContext* context) override; + bool OnIdleCheck(LoaderContext* context) override; + + private: + bool disposed_ = true; + std::unique_ptr sequencer_; + std::unique_ptr loader_info_manager_; + std::unique_ptr app_defined_loader_info_manager_; + std::vector> loader_contexts_; + std::unique_ptr hwacc_config_; +}; + +} // namespace launchpad + +#endif // LAUNCHPAD_PROCESS_POOL_LOADER_MANAGER_HH_ diff --git a/src/launchpad-process-pool/request.cc b/src/launchpad-process-pool/request.cc index 33db7fd..98a87b5 100644 --- a/src/launchpad-process-pool/request.cc +++ b/src/launchpad-process-pool/request.cc @@ -80,20 +80,21 @@ void Request::SendResult(int result) { client_socket_->Send(static_cast(&result), sizeof(result)); } -void Request::SetLoaderContext(candidate_process_context_t* context) { - context_ = context; +void Request::SetLoaderContext(std::shared_ptr context) { + context_ = std::move(context); } -candidate_process_context_t* Request::GetLoaderContext() const { +std::shared_ptr Request::GetLoaderContext() const { return context_; } -void Request::SetOriginalLoaderContext(candidate_process_context_t* context) { - org_context_ = context; +void Request::SetAvailableLoaderContext( + std::shared_ptr context) { + available_context_ = std::move(context); } -candidate_process_context_t* Request::GetOriginalLoaderContext() const { - return org_context_; +std::shared_ptr Request::GetAvailableLoaderContext() const { + return available_context_; } } // namespace launchpad diff --git a/src/launchpad-process-pool/request.hh b/src/launchpad-process-pool/request.hh index f0abc06..3079a9f 100644 --- a/src/launchpad-process-pool/request.hh +++ b/src/launchpad-process-pool/request.hh @@ -28,7 +28,7 @@ #include "lib/common/inc/launchpad_common.h" -#include "launchpad-process-pool/candidate_process_context.hh" +#include "launchpad-process-pool/loader_context.hh" namespace launchpad { @@ -50,10 +50,10 @@ class Request { void SetPid(pid_t pid); pid_t GetPid() const; void SendResult(int result); - void SetLoaderContext(candidate_process_context_t* context); - candidate_process_context_t* GetLoaderContext() const; - void SetOriginalLoaderContext(candidate_process_context_t* context); - candidate_process_context_t* GetOriginalLoaderContext() const; + void SetLoaderContext(std::shared_ptr context); + std::shared_ptr GetLoaderContext() const; + void SetAvailableLoaderContext(std::shared_ptr context); + std::shared_ptr GetAvailableLoaderContext() const; private: std::unique_ptr client_socket_; @@ -61,8 +61,8 @@ class Request { tizen_base::Bundle b_; std::unique_ptr peer_cred_; std::unique_ptr app_info_; - candidate_process_context_t* context_ = nullptr; - candidate_process_context_t* org_context_ = nullptr; + std::shared_ptr context_; + std::shared_ptr available_context_; int loader_id_ = -1; pid_t pid_ = -1; }; diff --git a/src/launchpad-process-pool/sequencer.cc b/src/launchpad-process-pool/sequencer.cc new file mode 100644 index 0000000..7ea3ed6 --- /dev/null +++ b/src/launchpad-process-pool/sequencer.cc @@ -0,0 +1,125 @@ +/* + * 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-process-pool/sequencer.hh" + +#include +#include + +#include "launchpad-process-pool/config.hh" +#include "lib/common/inc/launchpad_common.h" + +namespace launchpad { + +Sequencer::Sequencer(Sequencer::IEvent* listener) : listener_(listener) {} + +Sequencer::~Sequencer() { + if (idle_checker_ > 0) + g_source_remove(idle_checker_); + + if (timer_ > 0) + g_source_remove(timer_); +} + +void Sequencer::Add(std::shared_ptr context) { + auto found = std::find_if(queue_.begin(), queue_.end(), + [&](const std::shared_ptr& loader_context) -> bool { + return loader_context == context; + }); + if (found != queue_.end()) { + _W("Already exists"); + return; + } + + if (running_context_ == context) { + _W("slot(%d) is running", context->GetType()); + return; + } + + queue_.push_back(std::move(context)); +} + +void Sequencer::Remove(const std::shared_ptr& context) { + queue_.remove(context); +} + +void Sequencer::Run() { + if (timer_) + return; + + timer_ = g_timeout_add(500, RunCb, this); + if (timer_ == 0) + _E("Failed to add sequencer timer"); +} + +void Sequencer::Stop() { + if (timer_ > 0) { + g_source_remove(timer_); + timer_ = 0; + } +} + +bool Sequencer::Exist(const std::shared_ptr& context) { + auto found = std::find_if(queue_.begin(), queue_.end(), + [&](const std::shared_ptr& loader_context) -> bool { + return loader_context == context; + }); + if (found != queue_.end()) + return true; + + return false; +} + +gboolean Sequencer::RunCb(gpointer user_data) { + auto* sequencer = static_cast(user_data); + if (sequencer->idle_checker_ > 0) + return G_SOURCE_CONTINUE; + + if (sequencer->queue_.empty()) { + sequencer->timer_ = 0; + return G_SOURCE_REMOVE; + } + + auto context = std::move(sequencer->queue_.front()); + sequencer->queue_.pop_front(); + + context->UnsetTimer(); + if (context->GetPid() > 0) { + _W("The slot(%d) is already running. pid(%d)", + context->GetType(), context->GetPid()); + return G_SOURCE_CONTINUE; + } + + _W("[SEQUENCER] Add idle checker. Type(%d)", context->GetType()); + sequencer->running_context_ = std::move(context); + sequencer->idle_checker_ = g_timeout_add(1000, IdleCheckCb, user_data); + return G_SOURCE_CONTINUE; +} + +gboolean Sequencer::IdleCheckCb(gpointer user_data) { + auto* sequencer = static_cast(user_data); + auto* listener = sequencer->listener_; + if (listener == nullptr || + !listener->OnIdleCheck(sequencer->running_context_.get())) { + sequencer->running_context_ = nullptr; + sequencer->idle_checker_ = 0; + return G_SOURCE_REMOVE; + } + + return G_SOURCE_CONTINUE; +} + +} // namespace launchpad diff --git a/src/launchpad-process-pool/sequencer.hh b/src/launchpad-process-pool/sequencer.hh new file mode 100644 index 0000000..d5d0230 --- /dev/null +++ b/src/launchpad-process-pool/sequencer.hh @@ -0,0 +1,60 @@ +/* + * 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 LAUNCHPAD_PROCESS_POOL_SEQUENCER_HH_ +#define LAUNCHPAD_PROCESS_POOL_SEQUENCER_HH_ + +#include + +#include +#include + +#include "launchpad-process-pool/loader_context.hh" + +namespace launchpad { + +class Sequencer { + public: + class IEvent { + public: + virtual ~IEvent() = default; + virtual bool OnIdleCheck(LoaderContext* context) = 0; + }; + + explicit Sequencer(IEvent* listener); + ~Sequencer(); + + void Add(std::shared_ptr context); + void Remove(const std::shared_ptr& context); + void Run(); + void Stop(); + bool Exist(const std::shared_ptr& context); + + private: + static gboolean RunCb(gpointer user_data); + static gboolean IdleCheckCb(gpointer user_data); + + private: + IEvent* listener_; + guint timer_ = 0; + guint idle_checker_ = 0; + std::shared_ptr running_context_; + std::list> queue_; +}; + +} // namespace launchpad + +#endif // LAUNCHPAD_PROCESS_POOL_SEQUENCER_HH_ diff --git a/src/launchpad-process-pool/slot_info.h b/src/launchpad-process-pool/slot_info.h deleted file mode 100644 index 9597fa1..0000000 --- a/src/launchpad-process-pool/slot_info.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2022 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 __SLOT_INFO_H__ -#define __SLOT_INFO_H__ - -#include - -#include -#include - -typedef struct slot_info_s { - int type; - int loader_id; - int caller_pid; - const char *loader_name; - const char *loader_path; - const char *loader_extra; - int detection_method; - int activation_method; - int deactivation_method; - unsigned int ttl; - int timeout_val; - int threshold_max; - int threshold_min; - bool on_boot; - bool app_exists; - bool is_hydra; - bool app_check; - int on_boot_timeout; - int sched_priority; - std::vector condition_path_exists; -} slot_info_t; - -#endif /* __SLOT_INFO_H__ */ diff --git a/src/launchpad-process-pool/util.hh b/src/launchpad-process-pool/util.hh index b0f50e9..b61ce76 100644 --- a/src/launchpad-process-pool/util.hh +++ b/src/launchpad-process-pool/util.hh @@ -32,6 +32,11 @@ bool operator==(E a, int x) { return static_cast(a) == x; } +template +int operator&(int a, E b) { + return a & static_cast(b); +} + std::vector Split(const std::string& str, const std::string& delim); diff --git a/src/lib/common/inc/launchpad_common.h b/src/lib/common/inc/launchpad_common.h index 2506fb8..4a16938 100644 --- a/src/lib/common/inc/launchpad_common.h +++ b/src/lib/common/inc/launchpad_common.h @@ -53,9 +53,16 @@ #define LOADER_TYPE_HW "hw-loader" #define LOADER_TYPE_SW "sw-loader" +#undef _E #define _E(fmt, arg...) LOGE(fmt, ##arg) + +#undef _D #define _D(fmt, arg...) LOGD(fmt, ##arg) + +#undef _W #define _W(fmt, arg...) LOGW(fmt, ##arg) + +#undef _I #define _I(fmt, arg...) LOGI(fmt, ##arg) #define FREE_AND_NULL(x) do { \ @@ -137,8 +144,14 @@ int _prepare_id_file(void); void _print_hwc_log(const char *format, ...); int _mount_res_dir(const char *menu_info, bundle *kb); +#ifdef TIZEN_FEATURE_SET_PERSONALITY_32 +void _set_execution_domain(void); +#endif /* TIZEN_FEATURE_SET_PERSONALITY_32 */ + +void _set_lang_env(void); +void _set_region_env(void); + #ifdef __cplusplus } #endif #endif /* __LAUNCHPAD_COMMON_H__ */ - diff --git a/src/lib/common/src/launchpad_common.c b/src/lib/common/src/launchpad_common.c index 9fab91e..b12f10d 100644 --- a/src/lib/common/src/launchpad_common.c +++ b/src/lib/common/src/launchpad_common.c @@ -698,7 +698,7 @@ int _connect_to_launchpad(int type, int id) } #ifdef TIZEN_FEATURE_SET_PERSONALITY_32 -static void __set_execution_domain(void) +void _set_execution_domain(void) { char err_buf[1024]; int res; @@ -712,7 +712,7 @@ static void __set_execution_domain(void) } #endif /* TIZEN_FEATURE_SET_PERSONALITY_32 */ -static void __set_lang_env(void) +void _set_lang_env(void) { const char *lang; @@ -727,7 +727,7 @@ static void __set_lang_env(void) setenv("LC_ALL", lang, 1); } -static void __set_region_env(void) +void _set_region_env(void) { const char *region; @@ -787,10 +787,10 @@ void _set_env(appinfo_t *menu_info, bundle *kb) setenv("AUL_PID", buf, 1); setenv("TIZEN_GLIB_CONTEXT", "0", 1); - __set_lang_env(); - __set_region_env(); + _set_lang_env(); + _set_region_env(); #ifdef TIZEN_FEATURE_SET_PERSONALITY_32 - __set_execution_domain(); + _set_execution_domain(); #endif /* TIZEN_FEATURE_SET_PERSONALITY_32 */ setenv("GCOV_PREFIX", "/tmp", 1); diff --git a/src/lib/launchpad-common/plugin.cc b/src/lib/launchpad-common/plugin.cc new file mode 100644 index 0000000..d8f3778 --- /dev/null +++ b/src/lib/launchpad-common/plugin.cc @@ -0,0 +1,62 @@ +/* + * 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-common/plugin.hh" + +#include + +#include + +#include "launchpad-common/log_private.hh" + +namespace fs = std::filesystem; + +namespace launchpad { +namespace { + +constexpr const char kPathLaunchpadPlugin[] = + "/usr/share/aul/plugin/liblaunchpad-plugin.so"; +constexpr const char kTagLaunchpadPluginPrepareApp[] = + "LAUNCHPAD_PLUGIN_PREPARE_APP"; + +} // namespace + +int Plugin::PrepareApp(const std::string& appid, const tizen_base::Bundle& b) { + if (!fs::exists(kPathLaunchpadPlugin)) + return 0; + + void* handle = dlopen(kPathLaunchpadPlugin, RTLD_LAZY | RTLD_LOCAL); + if (handle == nullptr) { + _W("dlopen() is failed. path(%s), error(%s)", + kPathLaunchpadPlugin, dlerror()); + return 0; + } + + auto* prepare_app_func = reinterpret_cast( + dlsym(handle, kTagLaunchpadPluginPrepareApp)); + if (prepare_app_func == nullptr) { + _W("dlsym() is failed. %s", kTagLaunchpadPluginPrepareApp); + dlclose(handle); + return 0; + } + + _W("%s ++", kTagLaunchpadPluginPrepareApp); + int ret = prepare_app_func(appid.c_str(), b.GetHandle()); + _W("%s --", kTagLaunchpadPluginPrepareApp); + return ret; +} + +} // namespace launchpad diff --git a/src/lib/launchpad-common/plugin.hh b/src/lib/launchpad-common/plugin.hh new file mode 100644 index 0000000..57b1a8b --- /dev/null +++ b/src/lib/launchpad-common/plugin.hh @@ -0,0 +1,36 @@ +/* + * 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_COMMON_PLUGIN_HH_ +#define LIB_LAUNCHPAD_COMMON_PLUGIN_HH_ + +#include + +#include + +#undef EXPORT_API +#define EXPORT_API __attribute__((visibility("default"))) + +namespace launchpad { + +class EXPORT_API Plugin { + public: + static int PrepareApp(const std::string& appid, const tizen_base::Bundle& b); +}; + +} // namespace launchpad + +#endif // LIB_LAUNCHPAD_COMMON_PLUGIN_HH_ diff --git a/src/lib/launchpad-common/procfs.cc b/src/lib/launchpad-common/procfs.cc index 6fa2137..54009e2 100644 --- a/src/lib/launchpad-common/procfs.cc +++ b/src/lib/launchpad-common/procfs.cc @@ -69,7 +69,7 @@ void Procfs::GetMemoryUsage(uint32_t* usage) { mem_available = mem_free + mem_cached; *usage = (mem_total - mem_available) * 100 / mem_total; - _W("usage: %u %%", *usage); + _D("usage: %u%%", *usage); } void Procfs::GetPssMemory(pid_t pid, uint64_t* mem_pss) { diff --git a/src/lib/launchpad-common/util.cc b/src/lib/launchpad-common/util.cc index 885cde1..b7ee819 100644 --- a/src/lib/launchpad-common/util.cc +++ b/src/lib/launchpad-common/util.cc @@ -18,12 +18,19 @@ #include #include +#include +#include #include #include +#include +#include + #include "launchpad-common/aul_keys.hh" #include "launchpad-common/log_private.hh" +namespace fs = std::filesystem; + namespace launchpad { namespace { @@ -122,4 +129,27 @@ void Util::SetEnvironments(const AppInfo* app_info) { setenv("GCOV_PREFIX", "/tmp", 1); } +void Util::SetPriority(int priority) { + int ret = setpriority(PRIO_PROCESS, 0, priority); + if (ret != 0) { + _E("Failed to set process priority. priority(%d), errno(%d)", + priority, errno); + } else { + _D("Setting priority(%d) is sucessful", priority); + } +} + +void Util::DeleteSocketPath(pid_t pid, uid_t uid) { + std::string path ="/run/aul/apps/" + std::to_string(uid) + "/" + + std::to_string(pid); + if (!fs::exists(path)) + return; + + try { + fs::remove_all(path); + } catch (const std::exception& e) { + _E("Exception occurs. error: %s", e.what()); + } +} + } // namespace launchpad diff --git a/src/lib/launchpad-common/util.hh b/src/lib/launchpad-common/util.hh index 980bc11..dec2885 100644 --- a/src/lib/launchpad-common/util.hh +++ b/src/lib/launchpad-common/util.hh @@ -27,6 +27,8 @@ namespace launchpad { class EXPORT_API Util { public: static void SetEnvironments(const AppInfo* app_info); + static void SetPriority(int priority); + static void DeleteSocketPath(pid_t pid, uid_t uid); }; } // namespace launchpad diff --git a/tests/launchpad-process-pool-unittest/src/test_launchpad.cc b/tests/launchpad-process-pool-unittest/src/test_launchpad.cc index 61279ef..36f9233 100644 --- a/tests/launchpad-process-pool-unittest/src/test_launchpad.cc +++ b/tests/launchpad-process-pool-unittest/src/test_launchpad.cc @@ -182,7 +182,7 @@ TEST_F(LaunchpadTest, LoaderInfoTest) { EXPECT_EQ(info->GetDetectionMethod(), (LoaderMethod::Timeout | LoaderMethod::Visibility | LoaderMethod::Install)); - EXPECT_EQ(info->GetTimeoutVal(), 5000); + EXPECT_EQ(info->GetTimeout(), 5000); auto& b = info->GetExtra(); EXPECT_EQ(b.GetString("loader_type"), "hw-loader"); EXPECT_EQ(b.GetString("threads"), "7"); @@ -198,6 +198,6 @@ TEST_F(LaunchpadTest, LoaderInfoTest) { EXPECT_EQ(arr[7], "/test/libcapi-media-camera.so.0"); EXPECT_EQ(arr[8], "/test/ecore_evas/engines/extn/v-1.25/module.so"); - EXPECT_EQ(info->GetOnbootTimeout(), 10000); + EXPECT_EQ(info->GetOnBootTimeout(), 10000); EXPECT_EQ(info->GetConditionPathExists()[0], "/run/.wm_ready"); } -- 2.7.4