2 * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "launchpad-process-pool/loader_manager.hh"
24 #include "launchpad-process-pool/config.hh"
25 #include "launchpad-process-pool/loader_executor.hh"
26 #include "launchpad-process-pool/loader_factory.hh"
27 #include "launchpad-process-pool/log_private.hh"
32 constexpr const char kInfoDirectoryPath[] = "/usr/share/aul";
36 LoaderManager& LoaderManager::GetInst() {
37 static LoaderManager inst;
42 void LoaderManager::Dispose() {
46 loader_mount_.reset();
47 hwacc_config_.reset();
48 app_defined_loader_info_manager_.reset();
49 loader_info_manager_.reset();
50 MemoryMonitor::GetInst().Dispose();
51 AppLabelsMonitor::GetInst().Dispose();
55 void LoaderManager::Init() {
60 sequencer_.reset(new Sequencer(this));
61 auto& label_monitor = AppLabelsMonitor::GetInst();
63 label_monitor.SetEventListener(this);
64 MemoryMonitor::GetInst().SetEventListener(this);
66 app_defined_loader_info_manager_.reset(new AppDefinedLoaderInfoManager());
67 app_defined_loader_info_manager_->SetEventListener(this);
68 hwacc_config_.reset(new HWAccelerationConfig());
70 if (!label_monitor.IsDisposed()) {
71 setenv("LOADER_MOUNT", "1", 1);
72 loader_mount_.reset(new LoaderMount());
74 } catch (const Exception& e) {
75 _E("Exception occurs. error: %s", e.what());
82 void LoaderManager::PrepareApp(const std::shared_ptr<LoaderContext>& context,
83 const AppInfo* app_info) {
84 pid_t pid = context->GetPid();
85 loader_mount_->Mount(pid, app_info);
88 void LoaderManager::SetEventListener(LoaderManager::IEvent* event_listener) {
89 event_listener_ = event_listener;
92 void LoaderManager::HandleSigchld(pid_t pid) {
93 auto context = FindLoaderContextFromPid(pid);
94 if (context != nullptr) {
99 auto hydra_context = FindHydraLoaderContextFromPid(pid);
100 if (hydra_context != nullptr) {
101 hydra_context->SetHydraPid(0);
102 hydra_context->Dispose();
103 hydra_context->Prepare();
107 RemoveLoaderContextsByCallerPid(pid);
108 LoaderExecutor::GetInst().HandleSigchld(pid);
109 if (loader_mount_) loader_mount_->HandleSigchld(pid);
112 void LoaderManager::AddDefaultLoaderContexts() {
113 loader_info_manager_.reset(new LoaderInfoManager(kInfoDirectoryPath));
114 loader_info_manager_->Load();
116 for (auto& info : loader_info_manager_->GetLoaderInfoList()) {
118 LoaderFactory::GetInst().CreateLoaderContext(info, loader_mount_);
119 if (context != nullptr) {
120 context->SetEventListener(this);
121 loader_contexts_.push_back(std::move(context));
125 ActivateLoaderContexts(LoaderMethod::None);
128 void LoaderManager::ActivateLoaderContexts(LoaderMethod method) {
129 for (auto& context : loader_contexts_) {
130 if (!context->IsTouched() && context->IsOnBoot() &&
131 context->GetOnBootTimeout() > 0)
132 context->SetOnBootTimer(context->GetOnBootTimeout());
134 if (!context->IsActivated())
137 if (context->GetLoaderPath() == "null")
140 if (!context->IsTouched() && !context->IsOnBoot())
143 if (context->GetPid() > 0)
146 if (!context->IsTouched() || context->CanBeDetected(method)) {
147 context->UnsetTimer();
148 context->SetLoaderMethod(method);
149 sequencer_->Add(context);
155 std::shared_ptr<LoaderContext> LoaderManager::PrepareAppDefinedLoaderContext(
156 const std::string& name, pid_t caller_pid) {
157 auto info = app_defined_loader_info_manager_->Find(name.c_str());
158 if (info == nullptr) {
159 _E("There is no loaders. loader_name: %s", name.c_str());
163 auto context = FindLoaderContextFromName(name);
164 if (context == nullptr) {
165 context = LoaderFactory::GetInst().CreateLoaderContext(info, caller_pid,
167 if (context == nullptr) {
168 _E("Failed to create loader context. loader_name: %s",
173 loader_contexts_.push_back(context);
176 if (context->GetPid() < 1)
182 std::shared_ptr<LoaderContext> LoaderManager::AddLoaderContext(
183 tizen_base::Bundle b) {
185 LoaderFactory::GetInst().CreateLoaderContext(std::move(b), loader_mount_);
186 if (context == nullptr)
189 context->SetEventListener(this);
191 loader_contexts_.push_back(context);
195 void LoaderManager::HandleDirectLaunch(std::shared_ptr<LoaderContext> context) {
196 if (context == nullptr)
199 if (context->ShouldCheckAppInstallation() && !context->IsAppInstalled())
202 if (context->GetPid() > 0)
205 if (sequencer_->Exist(context))
208 context->UnsetTimer();
209 context->UpdateState(LoaderMethod::Request, true);
213 void LoaderManager::UpdateAppInstallationStatus(const std::string& app_type,
214 bool app_installed) {
215 for (auto& info : loader_info_manager_->GetLoaderInfoList()) {
216 auto found = std::find_if(info->GetAppTypes().begin(),
217 info->GetAppTypes().end(),
218 [&](const std::string& type) -> bool { return type == app_type; });
219 if (found == info->GetAppTypes().end())
222 info->SetAppInstalled(app_installed);
223 UpdateLoaderContext(info->GetType());
227 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromPid(
229 for (auto& context : loader_contexts_) {
230 if (context->GetPid() == pid)
237 std::shared_ptr<HydraLoaderContext>
238 LoaderManager::FindHydraLoaderContextFromPid(pid_t pid) {
239 for (auto& context : loader_contexts_) {
240 auto* hydra_context = dynamic_cast<HydraLoaderContext*>(context.get());
241 if (hydra_context != nullptr && hydra_context->GetHydraPid() == pid) {
242 return std::dynamic_pointer_cast<HydraLoaderContext>(
243 hydra_context->shared_from_this());
250 void LoaderManager::RemoveLoaderContextsByCallerPid(pid_t caller_pid) {
251 auto iter = loader_contexts_.begin();
252 while (iter != loader_contexts_.end()) {
253 auto& context = (*iter);
254 if (context->GetCallerPid() == caller_pid) {
256 iter = loader_contexts_.erase(iter);
263 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromName(
264 const std::string& loader_name) {
265 for (auto& context : loader_contexts_) {
266 if (context->GetLoaderName() == loader_name)
273 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContext(LoaderType type,
275 if (type == LoaderType::Dynamic)
276 return FindLoaderContextFromLoaderId(loader_id);
278 return FindLoaderContextFromType(type);
281 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromLoaderId(
283 for (auto& context : loader_contexts_) {
284 if (context->GetLoaderId() == loader_id)
291 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromType(
293 if (type == LoaderType::Dynamic || type == LoaderType::None)
296 for (auto& context : loader_contexts_) {
297 if (context->GetType() == static_cast<int>(type))
304 std::shared_ptr<LoaderContext> LoaderManager::FindAvailableLoaderContext(
305 const std::string& hwacc, const std::string& app_type,
306 const std::string& loader_name) {
307 LoaderType type = LoaderType::None;
308 if (!loader_name.empty()) {
309 for (auto& info : loader_info_manager_->GetLoaderInfoList()) {
310 if (info->GetName() == loader_name) {
311 type = info->GetType();
316 if (IsHwAcceleration(hwacc))
317 type = loader_info_manager_->FindHwType(app_type);
319 type = loader_info_manager_->FindSwType(app_type);
322 return FindLoaderContext(type, PadLoaderId::Static);
325 std::shared_ptr<LoaderContext> LoaderManager::FindAlternativeLoaderContext(
327 auto alternative_types = loader_info_manager_->GetAlternativeTypes(type);
328 for (auto& alternative_type : alternative_types) {
329 auto context = FindLoaderContext(alternative_type, PadLoaderId::Static);
330 if (context == nullptr)
339 bool LoaderManager::IsHwAcceleration(const std::string& hwacc) {
340 if (hwacc == "USE" ||
341 (hwacc == "SYS" && hwacc_config_->Get() == SETTING_HW_ACCELERATION_ON))
347 void LoaderManager::UpdateLoaderContext(LoaderType type) {
348 auto loader_context = FindLoaderContextFromType(type);
349 if (loader_context == nullptr)
352 _W("type(%d), loader_name(%s), app_installed(%s:%s)",
353 static_cast<int>(type), loader_context->GetLoaderName().c_str(),
354 loader_context->ShouldCheckAppInstallation() ? "yes" : "no",
355 loader_context->IsAppInstalled() ? "yes" : "no");
356 if (loader_context->ShouldCheckAppInstallation() &&
357 !loader_context->IsAppInstalled()) {
358 loader_context->Dispose();
359 sequencer_->Remove(loader_context);
361 if (!loader_context->IsActivated())
364 if (!loader_context->IsTouched() && !loader_context->IsOnBoot())
367 loader_context->UnsetTimer();
368 if (loader_context->GetPid() < 1) {
369 sequencer_->Add(loader_context);
375 void LoaderManager::RemoveLoaderContext(LoaderType type, int loader_id) {
376 auto iter = loader_contexts_.begin();
377 while (iter != loader_contexts_.end()) {
378 auto& loader_context = *iter;
379 if (loader_context->GetType() == static_cast<int>(type) &&
380 loader_context->GetLoaderId() == loader_id)
381 iter = loader_contexts_.erase(iter);
387 void LoaderManager::RemoveLoaderContext(const std::string_view loader_name) {
388 auto iter = loader_contexts_.begin();
389 while (iter != loader_contexts_.end()) {
390 auto& loader_context = *iter;
391 if (loader_context->GetLoaderName() == loader_name)
392 iter = loader_contexts_.erase(iter);
398 void LoaderManager::UpdateLoaderContexts(bool low_memory) {
399 for (auto& loader_context : loader_contexts_) {
401 loader_context->UpdateState(LoaderMethod::OutOfMemory, true);
403 loader_context->UpdateState(LoaderMethod::AvailableMemory, true);
407 void LoaderManager::HandleMemoryStatusChangedEvent(bool low_memory) {
410 UpdatePssMemoryOfLoaderContexts();
411 SortLoaderContexts();
412 DeactivateLoaderContexts();
414 ActivateLoaderContexts();
418 void LoaderManager::UpdatePssMemoryOfLoaderContexts() {
419 for (auto& loader_context : loader_contexts_) {
420 if (loader_context->GetPid() > 0)
421 loader_context->UpdatePssMemory();
425 void LoaderManager::SortLoaderContexts() {
426 std::sort(loader_contexts_.begin(), loader_contexts_.end(),
427 [&](const std::shared_ptr<LoaderContext> context_a,
428 const std::shared_ptr<LoaderContext> context_b) -> bool {
429 if (context_a->IsHydraMode() && !context_b->IsHydraMode())
432 if (!context_a->IsHydraMode() && context_b->IsHydraMode())
435 if (context_a->GetScore() > context_b->GetScore())
438 if (context_a->GetScore() < context_b->GetScore())
441 return context_a->GetPssMemory() < context_b->GetPssMemory();
445 void LoaderManager::DeactivateLoaderContexts() {
446 for (auto& loader_context : loader_contexts_) {
447 if (loader_context->IsHydraMode())
450 loader_context->UpdateState(LoaderMethod::OutOfMemory, true);
451 if (!MemoryMonitor::GetInst().IsLowMemory())
456 void LoaderManager::ActivateLoaderContexts() {
457 for (auto& loader_context : loader_contexts_)
458 loader_context->UpdateState(LoaderMethod::AvailableMemory, true);
461 LoaderManager::LoaderManager() : sequencer_(new Sequencer(this)) {}
463 LoaderManager::~LoaderManager() {
467 void LoaderManager::OnAppLabelsChanged() {
469 LoaderExecutor::GetInst().DisposeCandidateProcess();
470 for (auto& context : loader_contexts_) {
471 if (context->IsHydraMode()) {
472 auto* hydra_context = dynamic_cast<HydraLoaderContext*>(context.get());
473 if (hydra_context != nullptr && hydra_context->GetPid() > 0) {
474 hydra_context->Dispose();
475 hydra_context->Prepare();
477 } else if (context->GetPid() > 0) {
478 if (context->RefCount() != 0) {
479 _W("Except. type(%d), loader_name(%s), pid(%d)",
480 context->GetType(), context->GetLoaderName().c_str(),
492 void LoaderManager::OnMemoryStatusChanged(bool low_memory,
493 bool should_check_pss) {
494 if (should_check_pss)
495 HandleMemoryStatusChangedEvent(low_memory);
497 UpdateLoaderContexts(low_memory);
500 void LoaderManager::OnLoaderInfoAdded(const std::string_view name) {
501 _W("%s is added", name.data());
504 void LoaderManager::OnLoaderInfoRemoved(const std::string_view name) {
505 _W("%s is removed", name.data());
506 RemoveLoaderContext(name);
509 void LoaderManager::OnTimeoutEvent(LoaderContext* context) {
510 _W("type(%d), loader_name(%s), state(%d)",
511 context->GetType(), context->GetLoaderName().c_str(),
512 context->IsActivated());
514 if (context->GetPid() > 0) {
515 _W("The loader is already running");
519 sequencer_->Add(context->shared_from_this());
523 bool LoaderManager::OnIdleCheck(LoaderContext* context) {
524 _W("Loader(%s), type(%d), pid(%d)",
525 context->GetLoaderName().c_str(), context->GetType(), context->GetPid());
527 if (!context->IsLaunchable())
530 if (context->GetCPUChecker()->IsIdle()) {
535 int count = context->IncreaseCPUCheckCount();
536 if (count == Config::GetInst().GetCPUChecker().GetMaxCount()) {
537 _W("CPU check count has exceeded %d times", count);
538 sequencer_->Add(context->shared_from_this());
544 void LoaderManager::OnLoaderLaunch(LoaderContext* context) {
545 _D("Loader(%s), type(%d), pid(%d)",
546 context->GetLoaderName().c_str(), context->GetType(), context->GetPid());
548 if (!context->IsLaunchable())
554 void LoaderManager::OnLoaderPrepared(LoaderContext* context) {
555 if (event_listener_ != nullptr)
556 event_listener_->OnLoaderPrepared(context);
559 void LoaderManager::OnLoaderLaunched(LoaderContext* context) {
560 if (event_listener_ != nullptr)
561 event_listener_->OnLoaderLaunched(context);
564 } // namespace launchpad