The management policy for the loader process will be changed.
Loader processes will be created without checking the CPU threshold.
When an execution request is received, if a loader process is in
the ready state, the execution request will be held until the loader process is
ready and then forwarded to the loader process.
This patch was created with reference to the patch below:
- https://review.tizen.org/gerrit/#/c/platform/core/appfw/launchpad/+/288190/
Change-Id: I1b9dbed0824e7b72d6a743d8c8a2b4b266fa741c
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
PKG_CHECK_MODULES(AUL_DEPS REQUIRED aul)
PKG_CHECK_MODULES(BUNDLE_DEPS REQUIRED bundle)
PKG_CHECK_MODULES(BUXTON2_DEPS REQUIRED buxton2)
+PKG_CHECK_MODULES(CAPI_SYSTEM_RESOURCE_DEPS REQUIRED capi-system-resource)
PKG_CHECK_MODULES(DBUS_DEPS REQUIRED dbus-1)
PKG_CHECK_MODULES(DLOG_DEPS REQUIRED dlog)
PKG_CHECK_MODULES(DLOG_REDIRECT_STDOUT_DEPS REQUIRED dlog-redirect-stdout)
PKG_CHECK_MODULES(LIBSYSTEMD_DEPS REQUIRED libsystemd)
PKG_CHECK_MODULES(LIBTZPLATFORM_CONFIG_DEPS REQUIRED libtzplatform-config)
PKG_CHECK_MODULES(LIBXML_DEPS REQUIRED libxml-2.0)
+PKG_CHECK_MODULES(PARCEL_DEPS REQUIRED parcel)
PKG_CHECK_MODULES(PKGMGR_INSTALLER_DEPS REQUIRED pkgmgr-installer)
PKG_CHECK_MODULES(SECURITY_MANAGER_DEPS REQUIRED security-manager)
PKG_CHECK_MODULES(TANCHOR_DEPS REQUIRED tanchor)
PKG_CHECK_MODULES(TIZEN_SHARED_QUEUE_DEPS REQUIRED tizen-shared-queue)
PKG_CHECK_MODULES(TTRACE_DEPS REQUIRED ttrace)
PKG_CHECK_MODULES(VCONF_DEPS REQUIRED vconf)
-PKG_CHECK_MODULES(PARCEL_DEPS REQUIRED parcel)
ENABLE_TESTING()
ADD_TEST(NAME ${TARGET_LAUNCHPAD_PROCESS_POOL_UNITTEST}
BuildRequires: pkgconfig(aul)
BuildRequires: pkgconfig(bundle)
BuildRequires: pkgconfig(buxton2)
+BuildRequires: pkgconfig(capi-system-resource)
BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(dlog)
BuildRequires: pkgconfig(dlog-redirect-stdout)
BuildRequires: pkgconfig(libsystemd)
BuildRequires: pkgconfig(libtzplatform-config)
BuildRequires: pkgconfig(libxml-2.0)
+BuildRequires: pkgconfig(parcel)
BuildRequires: pkgconfig(pkgmgr-installer)
BuildRequires: pkgconfig(security-manager)
BuildRequires: pkgconfig(tanchor)
BuildRequires: pkgconfig(tizen-shared-queue)
BuildRequires: pkgconfig(ttrace)
BuildRequires: pkgconfig(vconf)
-BuildRequires: pkgconfig(parcel)
Requires(post): /sbin/ldconfig
Requires(post): /usr/bin/systemctl
constexpr const char kTagCpuChecker[] = "CpuChecker";
constexpr const char kKeyCpuCheckerMaxCount[] = "MaxCount";
+constexpr const char kKeyCpuCheckerEnable[] = "Enable";
constexpr const char kTagLogger[] = "Logger";
constexpr const char kKeyLoggerPath[] = "Path";
if (!max_count.empty() && std::isdigit(max_count[0]))
max_count_ = std::stoi(max_count);
- _W("[CPUChecker] max_count: %d", max_count_);
+ auto enable = parser.Get(kTagCpuChecker, kKeyCpuCheckerEnable);
+ if (enable == "0" || enable == "false")
+ enable_ = false;
+
+ _W("[CPUChecker] max_count: %d, enable: %s",
+ max_count_, enable_ ? "true" : "false");
+}
+
+const bool Config::CPUChecker::IsEnabled() const {
+ return enable_;
}
const std::string& Config::Logger::GetPath() const {
explicit CPUChecker(const IniParser& parser);
const int GetMaxCount() const;
+ const bool IsEnabled() const;
private:
int max_count_ = 10;
+ bool enable_ = false;
};
class Logger {
#include <string>
#include <utility>
+#include <cpu_boost_controller.hh>
#include <exception.hh>
#include "launchpad-process-pool/log_private.hh"
_E("Receive() is failed. error(%d)", ret);
} else {
_W("Candidate process: %d", pid);
- if (pid > 0)
+ if (pid > 0) {
SetPid(pid);
+ if (IsPending()) {
+ CPUBoostController::DoBoost(pid, CPUBoostController::Level::Strong,
+ 10000);
+ }
+ }
}
}
}
#include <app_info.hh>
#include <aul_keys.hh>
+#include <cpu_boost_controller.hh>
#include <exception.hh>
#include <executor.hh>
#include <procfs.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/loader_executor.hh"
#include "launchpad-process-pool/log.hh"
#include "launchpad-process-pool/memory_monitor.hh"
#include "launchpad-process-pool/region_format_config.hh"
return std::stoi(loader_id);
}
+inline bool CanUseLoaderContext(const std::shared_ptr<LoaderContext>& context) {
+ return ((LoaderExecutor::GetInst().HasCandidateProcess() ||
+ context->GetPid() > 0) && !context->IsPending());
+}
+
+inline void CheckAndPrepareLoaderContext(LoaderContext* context) {
+ if (!context->IsLaunchable())
+ return;
+
+ auto* hydra_loader_context = dynamic_cast<HydraLoaderContext*>(context);
+ if (hydra_loader_context != nullptr)
+ hydra_loader_context->Prepare();
+ else
+ context->Prepare();
+}
+
} // namespace
Launchpad::Launchpad(int argc, char** argv)
}
LoaderManager::GetInst().AddDefaultLoaderContexts();
+ LoaderManager::GetInst().SetEventListener(this);
launchpad::Debug::GetInst().Init();
_send_cmd_to_amd(LAUNCHPAD_LAUNCH_SIGNAL);
if (request->GetLoaderId() > PAD_LOADER_ID_DYNAMIC_BASE) {
auto context = loader_manager.FindLoaderContext(LoaderType::Dynamic,
request->GetLoaderId());
- if (context != nullptr && context->IsPrepared())
+ if (context != nullptr && CanUseLoaderContext(context))
request->SetAvailableLoaderContext(std::move(context));
} else {
request->SetLoaderId(PAD_LOADER_ID_DIRECT);
app_info->GetLoaderName());
if (context != nullptr) {
request->SetLoaderContext(context);
- if (context->IsPrepared()) {
+ if (CanUseLoaderContext(context)) {
request->SetAvailableLoaderContext(std::move(context));
} else {
- request->SetAvailableLoaderContext(
- loader_manager.FindAlternativeLoaderContext(
- static_cast<LoaderType>(context->GetType())));
+ auto alt_context = loader_manager.FindAlternativeLoaderContext(
+ static_cast<LoaderType>(context->GetType()));
+ if (alt_context != nullptr && CanUseLoaderContext(alt_context))
+ request->SetAvailableLoaderContext(std::move(alt_context));
}
}
} else {
auto context = loader_manager.FindLoaderContext(LoaderType::Dynamic,
request->GetLoaderId());
- if (context != nullptr && context->IsPrepared())
+ if (context != nullptr && CanUseLoaderContext(context))
request->SetAvailableLoaderContext(std::move(context));
}
}
return 0;
}
+ if (!loader_context->IsPrepared()) {
+ _W("Loader context is not prepared");
+ loader_context->SetPending(true);
+ CheckAndPrepareLoaderContext(loader_context.get());
+ CPUBoostController::DoBoost(loader_context->GetPid(),
+ CPUBoostController::Level::Strong, 10000);
+ pending_requests_.push_back(std::move(request));
+ return 1;
+ }
+
auto* app_info = request->GetAppInfo();
_W("Launch %d type process. appid: %s",
static_cast<int>(loader_context->GetType()),
}
ret = LaunchRequestDo(request);
- if (ret < 0)
- request->SetPid(ret);
+ if (ret == 1)
+ return;
LaunchRequestComplete(request);
_D("PAD_CMD_LAUNCH] appid: %s, result: %d",
LoaderManager::GetInst().HandleSigchld(pid);
}
+void Launchpad::OnLoaderPrepared(LoaderContext* loader_context) {
+ _W("Loader is prepared. name(%s), pid(%d)",
+ loader_context->GetLoaderName().c_str(), loader_context->GetPid());
+ loader_context->SetPending(false);
+
+ auto iter = pending_requests_.begin();
+ while (iter != pending_requests_.end()) {
+ auto request = *iter;
+ auto context = request->GetAvailableLoaderContext();
+ if (context != nullptr && context.get() == loader_context) {
+ pending_requests_.erase(iter);
+ LaunchRequestDo(request);
+ LaunchRequestComplete(request);
+ return;
+ }
+
+ iter++;
+ }
+}
+
} // namespace launchpad
int main(int argc, char** argv) {
#include <memory>
#include <string>
#include <unordered_map>
+#include <vector>
#include <io_channel.hh>
#include <server_socket.hh>
#include "launchpad-process-pool/region_format_config.hh"
#include "launchpad-process-pool/request.hh"
#include "launchpad-process-pool/signal_manager.hh"
+#include "launchpad-process-pool/loader_manager.hh"
namespace launchpad {
class Launchpad : public IOChannel::IEvent,
- public SignalManager::IEvent {
+ public SignalManager::IEvent,
+ public LoaderManager::IEvent {
public:
Launchpad(int argc, char** argv);
~Launchpad();
void OnIOEventReceived(int fd, int condition) override;
void OnSigchldReceived(pid_t pid) override;
+ void OnLoaderPrepared(LoaderContext* loader_context);
private:
int argc_;
std::unique_ptr<LanguageConfig> lang_config_;
std::unique_ptr<RegionFormatConfig> region_format_config_;
std::unique_ptr<Worker> cleaner_;
+ std::vector<std::shared_ptr<Request>> pending_requests_;
};
} // namespace launchpad
}
}
+bool LoaderContext::IsLaunchable() {
+ if (ShouldCheckAppInstallation() && !IsAppInstalled()) {
+ _W("The application is not installed. type(%d)", GetType());
+ return false;
+ }
+
+ if (ShouldWaitForFileCreation()) {
+ _W("The load should wait for file creation. type(%d)", GetType());
+ return false;
+ }
+
+ if (!IsActivated()) {
+ _W("The loader is deactivated. type(%d)", GetType());
+ return false;
+ }
+
+ if (GetPid() > 0) {
+ _W("The loader is already running. type(%d), pid(%d)", GetType(), GetPid());
+ return false;
+ }
+
+ return true;
+}
+
+void LoaderContext::SetPending(bool pending) {
+ pending_ = pending;
+}
+
+bool LoaderContext::IsPending() const {
+ return pending_;
+}
+
void LoaderContext::SetLiveTimer() {
_W("type(%d), loader_name(%s), deactivation_method(%d)",
GetType(), GetLoaderName().c_str(),
pid_ = peer_cred->GetPid();
prepared_ = true;
+ if (listener_!= nullptr)
+ listener_->OnLoaderPrepared(this);
+
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_));
public:
virtual ~IEvent() = default;
virtual void OnTimeoutEvent(LoaderContext* context) = 0;
+ virtual void OnLoaderPrepared(LoaderContext* context) = 0;
};
LoaderContext(std::shared_ptr<LoaderInfo> loader_info, int loader_id,
unsigned int GetScore() const;
bool CanActivate(LoaderMethod method) const;
void UpdateState(LoaderMethod method, bool force);
+ bool IsLaunchable();
+ void SetPending(bool pending);
+ bool IsPending() const;
protected:
void SetPrepared(bool prepared);
private:
bool prepared_ = false;
+ bool pending_ = false;
std::shared_ptr<LoaderInfo> loader_info_;
int loader_id_;
pid_t caller_pid_;
return Executor::Execute(priority);
}
+bool LoaderExecutor::HasCandidateProcess() const {
+ return process_pool_->IsPrepared();
+}
+
void LoaderExecutor::OnExecution() {
std::vector<char*> loader_argv(loader_argv_.size() + 1);
int loader_argc = loader_argv_.size();
static LoaderExecutor& GetInst();
pid_t Execute(const LoaderContext* loader_context, int priority);
+ bool HasCandidateProcess() const;
private:
LoaderExecutor();
disposed_ = false;
}
+void LoaderManager::SetEventListener(LoaderManager::IEvent* event_listener) {
+ event_listener_ = event_listener;
+}
+
void LoaderManager::HandleSigchld(pid_t pid) {
auto context = FindLoaderContextFromPid(pid);
if (context != nullptr) {
std::shared_ptr<HydraLoaderContext>
LoaderManager::FindHydraLoaderContextFromPid(pid_t pid) {
for (auto& context : loader_contexts_) {
- if (context->IsHydraMode()) {
- auto* hydra_context = dynamic_cast<HydraLoaderContext*>(context.get());
- if (hydra_context != nullptr && hydra_context->GetHydraPid() == pid)
+ auto* hydra_context = dynamic_cast<HydraLoaderContext*>(context.get());
+ if (hydra_context != nullptr && hydra_context->GetHydraPid() == pid) {
return std::dynamic_pointer_cast<HydraLoaderContext>(
hydra_context->shared_from_this());
}
if (context == nullptr)
continue;
- if (context->IsPrepared())
- return context;
+ return context;
}
return nullptr;
_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");
+ if (!context->IsLaunchable())
return false;
- }
if (context->GetCPUChecker()->IsIdle()) {
context->Prepare();
return true;
}
+void LoaderManager::OnLoaderLaunch(LoaderContext* context) {
+ _W("Loader(%s), type(%d), pid(%d)",
+ context->GetLoaderName().c_str(), context->GetType(), context->GetPid());
+
+ if (!context->IsLaunchable())
+ return;
+
+ context->Prepare();
+}
+
+void LoaderManager::OnLoaderPrepared(LoaderContext* context) {
+ if (event_listener_ != nullptr)
+ event_listener_->OnLoaderPrepared(context);
+}
+
} // namespace launchpad
public Sequencer::IEvent,
public LoaderContext::IEvent {
public:
+ class IEvent {
+ public:
+ virtual ~IEvent() = default;
+ virtual void OnLoaderPrepared(LoaderContext* context) = 0;
+ };
+
LoaderManager(const LoaderManager&) = delete;
LoaderManager& operator=(const LoaderManager&) = delete;
LoaderManager(LoaderManager&&) = delete;
static LoaderManager& GetInst();
void Dispose();
+ void SetEventListener(IEvent* event_listener);
void HandleSigchld(pid_t pid);
void AddDefaultLoaderContexts();
void ActivateLoaderContexts(LoaderMethod method);
void OnLoaderInfoRemoved(const std::string_view name) override;
void OnTimeoutEvent(LoaderContext* context) override;
bool OnIdleCheck(LoaderContext* context) override;
+ void OnLoaderLaunch(LoaderContext* context) override;
+ void OnLoaderPrepared(LoaderContext* context) override;
private:
bool disposed_ = true;
+ IEvent* event_listener_ = nullptr;
std::unique_ptr<Sequencer> sequencer_;
std::unique_ptr<LoaderInfoManager> loader_info_manager_;
std::unique_ptr<AppDefinedLoaderInfoManager> app_defined_loader_info_manager_;
Sequencer::Sequencer(Sequencer::IEvent* listener) : listener_(listener) {}
Sequencer::~Sequencer() {
- if (idle_checker_ > 0)
- g_source_remove(idle_checker_);
+ if (source_ > 0)
+ g_source_remove(source_);
if (timer_ > 0)
g_source_remove(timer_);
if (timer_)
return;
- timer_ = g_timeout_add(500, RunCb, this);
+ guint interval = Config::GetInst().GetCPUChecker().IsEnabled() ? 500 : 100;
+ timer_ = g_timeout_add(interval, RunCb, this);
if (timer_ == 0)
_E("Failed to add sequencer timer");
}
gboolean Sequencer::RunCb(gpointer user_data) {
auto* sequencer = static_cast<Sequencer*>(user_data);
- if (sequencer->idle_checker_ > 0)
+ if (sequencer->source_ > 0)
return G_SOURCE_CONTINUE;
if (sequencer->queue_.empty()) {
_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);
+ if (Config::GetInst().GetCPUChecker().IsEnabled())
+ sequencer->source_ = g_timeout_add(1000, IdleCheckCb, user_data);
+ else
+ sequencer->source_ = g_idle_add(LaunchCb, user_data);
+
return G_SOURCE_CONTINUE;
}
if (listener == nullptr ||
!listener->OnIdleCheck(sequencer->running_context_.get())) {
sequencer->running_context_ = nullptr;
- sequencer->idle_checker_ = 0;
+ sequencer->source_ = 0;
return G_SOURCE_REMOVE;
}
return G_SOURCE_CONTINUE;
}
+gboolean Sequencer::LaunchCb(gpointer user_data) {
+ auto* sequencer = static_cast<Sequencer*>(user_data);
+ sequencer->source_ = 0;
+
+ auto* listener = sequencer->listener_;
+ if (listener == nullptr) {
+ sequencer->running_context_ = nullptr;
+ return G_SOURCE_REMOVE;
+ }
+
+ listener->OnLoaderLaunch(sequencer->running_context_.get());
+ sequencer->running_context_ = nullptr;
+ return G_SOURCE_REMOVE;
+}
+
} // namespace launchpad
public:
virtual ~IEvent() = default;
virtual bool OnIdleCheck(LoaderContext* context) = 0;
+ virtual void OnLoaderLaunch(LoaderContext* context) = 0;
};
explicit Sequencer(IEvent* listener);
private:
static gboolean RunCb(gpointer user_data);
static gboolean IdleCheckCb(gpointer user_data);
+ static gboolean LaunchCb(gpointer user_data);
private:
IEvent* listener_;
guint timer_ = 0;
- guint idle_checker_ = 0;
+ guint source_ = 0;
std::shared_ptr<LoaderContext> running_context_;
std::list<std::shared_ptr<LoaderContext>> queue_;
};
APPLY_PKG_CONFIG(${TARGET_LAUNCHPAD_COMMON} PUBLIC
BUNDLE_DEPS
+ CAPI_SYSTEM_RESOURCE_DEPS
DLOG_DEPS
GIO_DEPS
INIPARSER_DEPS
--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "launchpad-common/cpu_boost_controller.hh"
+
+#include <cpu-boosting.h>
+
+#include "launchpad-common/log_private.hh"
+
+namespace launchpad {
+
+void CPUBoostController::DoBoost(pid_t pid, Level level, int timeout_msec) {
+ if (pid < 1)
+ return;
+
+ resource_pid_t res_pid = {
+ .pid = 0,
+ .tid = &pid,
+ .tid_count = 1,
+ };
+
+ int ret = resource_set_cpu_boosting(res_pid,
+ static_cast<cpu_boosting_level_e>(level), CPU_BOOSTING_RESET_ON_FORK,
+ timeout_msec);
+ if (ret != 0)
+ _E("resource_set_cpu_boosting() is failed. error: %d", ret);
+ else
+ _D("resource_set_cpu_boosting() is successful");
+}
+
+} // namespace launchpad
--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIB_LAUNCHPAD_COMMON_CPU_BOOST_CONTROLLER_HH_
+#define LIB_LAUNCHPAD_COMMON_CPU_BOOST_CONTROLLER_HH_
+
+#include <sys/types.h>
+
+#undef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+
+namespace launchpad {
+
+class EXPORT_API CPUBoostController {
+ public:
+ enum class Level {
+ None,
+ Strong,
+ Medium,
+ Weak,
+ };
+
+ static void DoBoost(pid_t pid, Level level, int timeout_msec);
+};
+
+} // namespace launchpad
+
+#endif // LIB_LAUNCHPAD_COMMON_CPU_BOOST_CONTROLLER_HH_