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 hwacc_config_.reset();
47 app_defined_loader_info_manager_.reset();
48 loader_info_manager_.reset();
49 MemoryMonitor::GetInst().Dispose();
50 AppLabelsMonitor::GetInst().Dispose();
54 void LoaderManager::Init() {
59 sequencer_.reset(new Sequencer(this));
60 auto& label_monitor = AppLabelsMonitor::GetInst();
62 label_monitor.SetEventListener(this);
63 MemoryMonitor::GetInst().SetEventListener(this);
65 app_defined_loader_info_manager_.reset(new AppDefinedLoaderInfoManager());
66 app_defined_loader_info_manager_->SetEventListener(this);
67 hwacc_config_.reset(new HWAccelerationConfig());
68 } catch (const Exception& e) {
69 _E("Exception occurs. error: %s", e.what());
76 void LoaderManager::SetEventListener(LoaderManager::IEvent* event_listener) {
77 event_listener_ = event_listener;
80 void LoaderManager::HandleSigchld(pid_t pid) {
81 auto context = FindLoaderContextFromPid(pid);
82 if (context != nullptr) {
87 auto hydra_context = FindHydraLoaderContextFromPid(pid);
88 if (hydra_context != nullptr) {
89 hydra_context->SetHydraPid(0);
90 hydra_context->Dispose();
91 hydra_context->Prepare();
95 RemoveLoaderContextsByCallerPid(pid);
96 LoaderExecutor::GetInst().HandleSigchld(pid);
99 void LoaderManager::AddDefaultLoaderContexts() {
100 loader_info_manager_.reset(new LoaderInfoManager(kInfoDirectoryPath));
101 loader_info_manager_->Load();
103 for (auto& info : loader_info_manager_->GetLoaderInfoList()) {
104 auto context = LoaderFactory::GetInst().CreateLoaderContext(info);
105 if (context != nullptr) {
106 context->SetEventListener(this);
107 loader_contexts_.push_back(std::move(context));
111 ActivateLoaderContexts(LoaderMethod::None);
114 void LoaderManager::ActivateLoaderContexts(LoaderMethod method) {
115 for (auto& context : loader_contexts_) {
116 if (!context->IsTouched() && context->IsOnBoot() &&
117 context->GetOnBootTimeout() > 0)
118 context->SetOnBootTimer(context->GetOnBootTimeout());
120 if (!context->IsActivated())
123 if (context->GetLoaderPath() == "null")
126 if (!context->IsTouched() && !context->IsOnBoot())
129 if (context->GetPid() > 0)
132 if (!context->IsTouched() || context->CanBeDetected(method)) {
133 context->UnsetTimer();
134 context->SetLoaderMethod(method);
135 sequencer_->Add(context);
141 std::shared_ptr<LoaderContext> LoaderManager::PrepareAppDefinedLoaderContext(
142 const std::string& name, pid_t caller_pid) {
143 auto info = app_defined_loader_info_manager_->Find(name.c_str());
144 if (info == nullptr) {
145 _E("There is no loaders. loader_name: %s", name.c_str());
149 auto context = FindLoaderContextFromName(name);
150 if (context == nullptr) {
151 context = LoaderFactory::GetInst().CreateLoaderContext(info, caller_pid);
152 if (context == nullptr) {
153 _E("Failed to create loader context. loader_name: %s",
158 loader_contexts_.push_back(context);
161 if (context->GetPid() < 1)
167 std::shared_ptr<LoaderContext> LoaderManager::AddLoaderContext(
168 tizen_base::Bundle b) {
169 auto context = LoaderFactory::GetInst().CreateLoaderContext(std::move(b));
170 if (context == nullptr)
173 context->SetEventListener(this);
175 loader_contexts_.push_back(context);
179 void LoaderManager::HandleDirectLaunch(std::shared_ptr<LoaderContext> context) {
180 if (context == nullptr)
183 if (context->ShouldCheckAppInstallation() && !context->IsAppInstalled())
186 if (context->GetPid() > 0)
189 if (sequencer_->Exist(context))
192 context->UnsetTimer();
193 context->UpdateState(LoaderMethod::Request, true);
197 void LoaderManager::UpdateAppInstallationStatus(const std::string& app_type,
198 bool app_installed) {
199 for (auto& info : loader_info_manager_->GetLoaderInfoList()) {
200 auto found = std::find_if(info->GetAppTypes().begin(),
201 info->GetAppTypes().end(),
202 [&](const std::string& type) -> bool { return type == app_type; });
203 if (found == info->GetAppTypes().end())
206 info->SetAppInstalled(app_installed);
207 UpdateLoaderContext(info->GetType());
211 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromPid(
213 for (auto& context : loader_contexts_) {
214 if (context->GetPid() == pid)
221 std::shared_ptr<HydraLoaderContext>
222 LoaderManager::FindHydraLoaderContextFromPid(pid_t pid) {
223 for (auto& context : loader_contexts_) {
224 auto* hydra_context = dynamic_cast<HydraLoaderContext*>(context.get());
225 if (hydra_context != nullptr && hydra_context->GetHydraPid() == pid) {
226 return std::dynamic_pointer_cast<HydraLoaderContext>(
227 hydra_context->shared_from_this());
234 void LoaderManager::RemoveLoaderContextsByCallerPid(pid_t caller_pid) {
235 auto iter = loader_contexts_.begin();
236 while (iter != loader_contexts_.end()) {
237 auto& context = (*iter);
238 if (context->GetCallerPid() == caller_pid) {
240 iter = loader_contexts_.erase(iter);
247 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromName(
248 const std::string& loader_name) {
249 for (auto& context : loader_contexts_) {
250 if (context->GetLoaderName() == loader_name)
257 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContext(LoaderType type,
259 if (type == LoaderType::Dynamic)
260 return FindLoaderContextFromLoaderId(loader_id);
262 return FindLoaderContextFromType(type);
265 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromLoaderId(
267 for (auto& context : loader_contexts_) {
268 if (context->GetLoaderId() == loader_id)
275 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromType(
277 if (type == LoaderType::Dynamic || type == LoaderType::None)
280 for (auto& context : loader_contexts_) {
281 if (context->GetType() == static_cast<int>(type))
288 std::shared_ptr<LoaderContext> LoaderManager::FindAvailableLoaderContext(
289 const std::string& hwacc, const std::string& app_type,
290 const std::string& loader_name) {
291 LoaderType type = LoaderType::None;
292 if (!loader_name.empty()) {
293 for (auto& info : loader_info_manager_->GetLoaderInfoList()) {
294 if (info->GetName() == loader_name) {
295 type = info->GetType();
300 if (IsHwAcceleration(hwacc))
301 type = loader_info_manager_->FindHwType(app_type);
303 type = loader_info_manager_->FindSwType(app_type);
306 return FindLoaderContext(type, PadLoaderId::Static);
309 std::shared_ptr<LoaderContext> LoaderManager::FindAlternativeLoaderContext(
311 auto alternative_types = loader_info_manager_->GetAlternativeTypes(type);
312 for (auto& alternative_type : alternative_types) {
313 auto context = FindLoaderContext(alternative_type, PadLoaderId::Static);
314 if (context == nullptr)
323 bool LoaderManager::IsHwAcceleration(const std::string& hwacc) {
324 if (hwacc == "USE" ||
325 (hwacc == "SYS" && hwacc_config_->Get() == SETTING_HW_ACCELERATION_ON))
331 void LoaderManager::UpdateLoaderContext(LoaderType type) {
332 auto loader_context = FindLoaderContextFromType(type);
333 if (loader_context == nullptr)
336 _W("type(%d), loader_name(%s), app_installed(%s:%s)",
337 static_cast<int>(type), loader_context->GetLoaderName().c_str(),
338 loader_context->ShouldCheckAppInstallation() ? "yes" : "no",
339 loader_context->IsAppInstalled() ? "yes" : "no");
340 if (loader_context->ShouldCheckAppInstallation() &&
341 !loader_context->IsAppInstalled()) {
342 loader_context->Dispose();
343 sequencer_->Remove(loader_context);
345 if (!loader_context->IsActivated())
348 if (!loader_context->IsTouched() && !loader_context->IsOnBoot())
351 loader_context->UnsetTimer();
352 if (loader_context->GetPid() < 1) {
353 sequencer_->Add(loader_context);
359 void LoaderManager::RemoveLoaderContext(LoaderType type, int loader_id) {
360 auto iter = loader_contexts_.begin();
361 while (iter != loader_contexts_.end()) {
362 auto& loader_context = *iter;
363 if (loader_context->GetType() == static_cast<int>(type) &&
364 loader_context->GetLoaderId() == loader_id)
365 iter = loader_contexts_.erase(iter);
371 void LoaderManager::RemoveLoaderContext(const std::string_view loader_name) {
372 auto iter = loader_contexts_.begin();
373 while (iter != loader_contexts_.end()) {
374 auto& loader_context = *iter;
375 if (loader_context->GetLoaderName() == loader_name)
376 iter = loader_contexts_.erase(iter);
382 void LoaderManager::UpdateLoaderContexts(bool low_memory) {
383 for (auto& loader_context : loader_contexts_) {
385 loader_context->UpdateState(LoaderMethod::OutOfMemory, true);
387 loader_context->UpdateState(LoaderMethod::AvailableMemory, true);
391 void LoaderManager::HandleMemoryStatusChangedEvent(bool low_memory) {
394 UpdatePssMemoryOfLoaderContexts();
395 SortLoaderContexts();
396 DeactivateLoaderContexts();
398 ActivateLoaderContexts();
402 void LoaderManager::UpdatePssMemoryOfLoaderContexts() {
403 for (auto& loader_context : loader_contexts_) {
404 if (loader_context->GetPid() > 0)
405 loader_context->UpdatePssMemory();
409 void LoaderManager::SortLoaderContexts() {
410 std::sort(loader_contexts_.begin(), loader_contexts_.end(),
411 [&](const std::shared_ptr<LoaderContext> context_a,
412 const std::shared_ptr<LoaderContext> context_b) -> bool {
413 if (context_a->IsHydraMode() && !context_b->IsHydraMode())
416 if (!context_a->IsHydraMode() && context_b->IsHydraMode())
419 if (context_a->GetScore() > context_b->GetScore())
422 if (context_a->GetScore() < context_b->GetScore())
425 return context_a->GetPssMemory() < context_b->GetPssMemory();
429 void LoaderManager::DeactivateLoaderContexts() {
430 for (auto& loader_context : loader_contexts_) {
431 if (loader_context->IsHydraMode())
434 loader_context->UpdateState(LoaderMethod::OutOfMemory, true);
435 if (!MemoryMonitor::GetInst().IsLowMemory())
440 void LoaderManager::ActivateLoaderContexts() {
441 for (auto& loader_context : loader_contexts_)
442 loader_context->UpdateState(LoaderMethod::AvailableMemory, true);
445 LoaderManager::LoaderManager() : sequencer_(new Sequencer(this)) {}
447 LoaderManager::~LoaderManager() {
451 void LoaderManager::OnAppLabelsChanged() {
453 LoaderExecutor::GetInst().DisposeCandidateProcess();
454 for (auto& context : loader_contexts_) {
455 if (context->IsHydraMode()) {
456 auto* hydra_context = dynamic_cast<HydraLoaderContext*>(context.get());
457 if (hydra_context != nullptr && hydra_context->GetPid() > 0) {
458 hydra_context->Dispose();
459 hydra_context->Prepare();
461 } else if (context->GetPid() > 0) {
462 if (context->RefCount() != 0) {
463 _W("Except. type(%d), loader_name(%s), pid(%d)",
464 context->GetType(), context->GetLoaderName().c_str(),
476 void LoaderManager::OnMemoryStatusChanged(bool low_memory,
477 bool should_check_pss) {
478 if (should_check_pss)
479 HandleMemoryStatusChangedEvent(low_memory);
481 UpdateLoaderContexts(low_memory);
484 void LoaderManager::OnLoaderInfoAdded(const std::string_view name) {
485 _W("%s is added", name.data());
488 void LoaderManager::OnLoaderInfoRemoved(const std::string_view name) {
489 _W("%s is removed", name.data());
490 RemoveLoaderContext(name);
493 void LoaderManager::OnTimeoutEvent(LoaderContext* context) {
494 _W("type(%d), loader_name(%s), state(%d)",
495 context->GetType(), context->GetLoaderName().c_str(),
496 context->IsActivated());
498 if (context->GetPid() > 0) {
499 _W("The loader is already running");
503 sequencer_->Add(context->shared_from_this());
507 bool LoaderManager::OnIdleCheck(LoaderContext* context) {
508 _W("Loader(%s), type(%d), pid(%d)",
509 context->GetLoaderName().c_str(), context->GetType(), context->GetPid());
511 if (!context->IsLaunchable())
514 if (context->GetCPUChecker()->IsIdle()) {
519 int count = context->IncreaseCPUCheckCount();
520 if (count == Config::GetInst().GetCPUChecker().GetMaxCount()) {
521 _W("CPU check count has exceeded %d times", count);
522 sequencer_->Add(context->shared_from_this());
528 void LoaderManager::OnLoaderLaunch(LoaderContext* context) {
529 _D("Loader(%s), type(%d), pid(%d)",
530 context->GetLoaderName().c_str(), context->GetType(), context->GetPid());
532 if (!context->IsLaunchable())
538 void LoaderManager::OnLoaderPrepared(LoaderContext* context) {
539 if (event_listener_ != nullptr)
540 event_listener_->OnLoaderPrepared(context);
543 void LoaderManager::OnLoaderLaunched(LoaderContext* context) {
544 if (event_listener_ != nullptr)
545 event_listener_->OnLoaderLaunched(context);
548 } // namespace launchpad