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"
22 #include "launchpad-process-pool/config.hh"
23 #include "launchpad-process-pool/loader_executor.hh"
24 #include "launchpad-process-pool/loader_factory.hh"
25 #include "launchpad-process-pool/log_private.hh"
30 constexpr const char kInfoDirectoryPath[] = "/usr/share/aul";
34 LoaderManager& LoaderManager::GetInst() {
35 static LoaderManager inst;
40 void LoaderManager::Dispose() {
44 hwacc_config_.reset();
45 app_defined_loader_info_manager_.reset();
46 loader_info_manager_.reset();
47 MemoryMonitor::GetInst().Dispose();
48 AppLabelsMonitor::GetInst().Dispose();
52 void LoaderManager::Init() {
57 sequencer_.reset(new Sequencer(this));
58 auto& label_monitor = AppLabelsMonitor::GetInst();
60 label_monitor.SetEventListener(this);
61 MemoryMonitor::GetInst().SetEventListener(this);
63 app_defined_loader_info_manager_.reset(new AppDefinedLoaderInfoManager());
64 app_defined_loader_info_manager_->SetEventListener(this);
65 hwacc_config_.reset(new HWAccelerationConfig());
66 } catch (const Exception& e) {
67 _E("Exception occurs. error: %s", e.what());
74 void LoaderManager::SetEventListener(LoaderManager::IEvent* event_listener) {
75 event_listener_ = event_listener;
78 void LoaderManager::HandleSigchld(pid_t pid) {
79 auto context = FindLoaderContextFromPid(pid);
80 if (context != nullptr) {
85 auto hydra_context = FindHydraLoaderContextFromPid(pid);
86 if (hydra_context != nullptr) {
87 hydra_context->SetHydraPid(0);
88 hydra_context->Dispose();
89 hydra_context->Prepare();
93 RemoveLoaderContextsByCallerPid(pid);
96 void LoaderManager::AddDefaultLoaderContexts() {
97 loader_info_manager_.reset(new LoaderInfoManager(kInfoDirectoryPath));
98 loader_info_manager_->Load();
100 for (auto& info : loader_info_manager_->GetLoaderInfoList()) {
101 auto context = LoaderFactory::GetInst().CreateLoaderContext(info);
102 if (context != nullptr) {
103 context->SetEventListener(this);
104 loader_contexts_.push_back(std::move(context));
108 ActivateLoaderContexts(LoaderMethod::None);
111 void LoaderManager::ActivateLoaderContexts(LoaderMethod method) {
112 for (auto& context : loader_contexts_) {
113 if (!context->IsTouched() && context->IsOnBoot() &&
114 context->GetOnBootTimeout() > 0)
115 context->SetOnBootTimer(context->GetOnBootTimeout());
117 if (!context->IsActivated())
120 if (context->GetLoaderPath() == "null")
123 if (!context->IsTouched() && !context->IsOnBoot())
126 if (context->GetPid() > 0)
129 if (!context->IsTouched() || context->CanActivate(method)) {
130 context->UnsetTimer();
131 context->SetLoaderMethod(method);
132 sequencer_->Add(context);
138 std::shared_ptr<LoaderContext> LoaderManager::PrepareAppDefinedLoaderContext(
139 const std::string& name, pid_t caller_pid) {
140 auto info = app_defined_loader_info_manager_->Find(name.c_str());
141 if (info == nullptr) {
142 _E("There is no loaders. loader_name: %s", name.c_str());
146 auto context = FindLoaderContextFromName(name);
147 if (context == nullptr) {
148 context = LoaderFactory::GetInst().CreateLoaderContext(info, caller_pid);
149 if (context == nullptr) {
150 _E("Failed to create loader context. loader_name: %s",
155 loader_contexts_.push_back(context);
158 if (context->GetPid() < 1)
164 std::shared_ptr<LoaderContext> LoaderManager::AddLoaderContext(
165 tizen_base::Bundle b) {
166 auto context = LoaderFactory::GetInst().CreateLoaderContext(std::move(b));
167 if (context == nullptr)
170 context->SetEventListener(this);
172 loader_contexts_.push_back(context);
176 void LoaderManager::HandleDirectLaunch(std::shared_ptr<LoaderContext> context) {
177 if (context == nullptr)
180 if (context->ShouldCheckAppInstallation() && !context->IsAppInstalled())
183 if (context->GetPid() > 0)
186 if (sequencer_->Exist(context))
189 context->UnsetTimer();
190 context->UpdateState(LoaderMethod::Request, true);
194 void LoaderManager::UpdateAppInstallationStatus(const std::string& app_type,
195 bool app_installed) {
196 for (auto& info : loader_info_manager_->GetLoaderInfoList()) {
197 auto found = std::find_if(info->GetAppTypes().begin(),
198 info->GetAppTypes().end(),
199 [&](const std::string& type) -> bool { return type == app_type; });
200 if (found == info->GetAppTypes().end())
203 info->SetAppInstalled(app_installed);
204 UpdateLoaderContext(info->GetType());
208 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromPid(
210 for (auto& context : loader_contexts_) {
211 if (context->GetPid() == pid)
218 std::shared_ptr<HydraLoaderContext>
219 LoaderManager::FindHydraLoaderContextFromPid(pid_t pid) {
220 for (auto& context : loader_contexts_) {
221 auto* hydra_context = dynamic_cast<HydraLoaderContext*>(context.get());
222 if (hydra_context != nullptr && hydra_context->GetHydraPid() == pid) {
223 return std::dynamic_pointer_cast<HydraLoaderContext>(
224 hydra_context->shared_from_this());
231 void LoaderManager::RemoveLoaderContextsByCallerPid(pid_t caller_pid) {
232 auto iter = loader_contexts_.begin();
233 while (iter != loader_contexts_.end()) {
234 auto& context = (*iter);
235 if (context->GetCallerPid() == caller_pid) {
237 iter = loader_contexts_.erase(iter);
244 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromName(
245 const std::string& loader_name) {
246 for (auto& context : loader_contexts_) {
247 if (context->GetLoaderName() == loader_name)
254 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContext(LoaderType type,
256 if (type == LoaderType::Dynamic)
257 return FindLoaderContextFromLoaderId(loader_id);
259 return FindLoaderContextFromType(type);
262 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromLoaderId(
264 for (auto& context : loader_contexts_) {
265 if (context->GetLoaderId() == loader_id)
272 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromType(
274 if (type == LoaderType::Dynamic || type == LoaderType::None)
277 for (auto& context : loader_contexts_) {
278 if (context->GetType() == static_cast<int>(type))
285 std::shared_ptr<LoaderContext> LoaderManager::FindAvailableLoaderContext(
286 const std::string& hwacc, const std::string& app_type,
287 const std::string& loader_name) {
288 LoaderType type = LoaderType::None;
289 if (!loader_name.empty()) {
290 for (auto& info : loader_info_manager_->GetLoaderInfoList()) {
291 if (info->GetName() == loader_name) {
292 type = info->GetType();
297 if (IsHwAcceleration(hwacc))
298 type = loader_info_manager_->FindHwType(app_type);
300 type = loader_info_manager_->FindSwType(app_type);
303 return FindLoaderContext(type, PAD_LOADER_ID_STATIC);
306 std::shared_ptr<LoaderContext> LoaderManager::FindAlternativeLoaderContext(
308 auto alternative_types = loader_info_manager_->GetAlternativeTypes(type);
309 for (auto& alternative_type : alternative_types) {
310 auto context = FindLoaderContext(alternative_type, PAD_LOADER_ID_STATIC);
311 if (context == nullptr)
320 bool LoaderManager::IsHwAcceleration(const std::string& hwacc) {
321 if (hwacc == "USE" ||
322 (hwacc == "SYS" && hwacc_config_->Get() == SETTING_HW_ACCELERATION_ON))
328 void LoaderManager::UpdateLoaderContext(LoaderType type) {
329 auto loader_context = FindLoaderContextFromType(type);
330 if (loader_context == nullptr)
333 _W("type(%d), loader_name(%s), app_installed(%s:%s)",
334 static_cast<int>(type), loader_context->GetLoaderName().c_str(),
335 loader_context->ShouldCheckAppInstallation() ? "yes" : "no",
336 loader_context->IsAppInstalled() ? "yes" : "no");
337 if (loader_context->ShouldCheckAppInstallation() &&
338 !loader_context->IsAppInstalled()) {
339 loader_context->Dispose();
340 sequencer_->Remove(loader_context);
342 if (!loader_context->IsActivated())
345 if (!loader_context->IsTouched() && !loader_context->IsOnBoot())
348 loader_context->UnsetTimer();
349 if (loader_context->GetPid() < 1) {
350 sequencer_->Add(loader_context);
356 void LoaderManager::RemoveLoaderContext(LoaderType type, int loader_id) {
357 auto iter = loader_contexts_.begin();
358 while (iter != loader_contexts_.end()) {
359 auto& loader_context = *iter;
360 if (loader_context->GetType() == static_cast<int>(type) &&
361 loader_context->GetLoaderId() == loader_id)
362 iter = loader_contexts_.erase(iter);
368 void LoaderManager::RemoveLoaderContext(const std::string_view loader_name) {
369 auto iter = loader_contexts_.begin();
370 while (iter != loader_contexts_.end()) {
371 auto& loader_context = *iter;
372 if (loader_context->GetLoaderName() == loader_name)
373 iter = loader_contexts_.erase(iter);
379 void LoaderManager::UpdateLoaderContexts(bool low_memory) {
380 for (auto& loader_context : loader_contexts_) {
382 loader_context->UpdateState(LoaderMethod::OutOfMemory, true);
384 loader_context->UpdateState(LoaderMethod::AvailableMemory, true);
388 void LoaderManager::HandleMemoryStatusChangedEvent(bool low_memory) {
391 UpdatePssMemoryOfLoaderContexts();
392 SortLoaderContexts();
393 DeactivateLoaderContexts();
395 ActivateLoaderContexts();
399 void LoaderManager::UpdatePssMemoryOfLoaderContexts() {
400 for (auto& loader_context : loader_contexts_) {
401 if (loader_context->GetPid() > 0)
402 loader_context->UpdatePssMemory();
406 void LoaderManager::SortLoaderContexts() {
407 std::sort(loader_contexts_.begin(), loader_contexts_.end(),
408 [&](const std::shared_ptr<LoaderContext> context_a,
409 const std::shared_ptr<LoaderContext> context_b) -> bool {
410 if (context_a->IsHydraMode() && !context_b->IsHydraMode())
413 if (!context_a->IsHydraMode() && context_b->IsHydraMode())
416 if (context_a->GetScore() > context_b->GetScore())
419 if (context_a->GetScore() < context_b->GetScore())
422 return context_a->GetPssMemory() < context_b->GetPssMemory();
426 void LoaderManager::DeactivateLoaderContexts() {
427 for (auto& loader_context : loader_contexts_) {
428 if (loader_context->IsHydraMode())
431 loader_context->UpdateState(LoaderMethod::OutOfMemory, true);
432 if (!MemoryMonitor::GetInst().IsLowMemory())
437 void LoaderManager::ActivateLoaderContexts() {
438 for (auto& loader_context : loader_contexts_)
439 loader_context->UpdateState(LoaderMethod::AvailableMemory, true);
442 LoaderManager::LoaderManager() : sequencer_(new Sequencer(this)) {}
444 LoaderManager::~LoaderManager() {
448 void LoaderManager::OnAppLabelsChanged() {
449 for (auto& context : loader_contexts_) {
450 if (context->IsHydraMode()) {
451 auto* hydra_context = dynamic_cast<HydraLoaderContext*>(context.get());
452 if (hydra_context != nullptr && hydra_context->GetPid() > 0) {
453 hydra_context->Dispose();
454 hydra_context->Prepare();
456 } else if (context->GetPid() > 0) {
462 LoaderExecutor::GetInst().DisposeCandidateProcess();
465 void LoaderManager::OnMemoryStatusChanged(bool low_memory,
466 bool should_check_pss) {
467 if (should_check_pss)
468 HandleMemoryStatusChangedEvent(low_memory);
470 UpdateLoaderContexts(low_memory);
473 void LoaderManager::OnLoaderInfoAdded(const std::string_view name) {
474 _W("%s is added", name.data());
477 void LoaderManager::OnLoaderInfoRemoved(const std::string_view name) {
478 _W("%s is removed", name.data());
479 RemoveLoaderContext(name);
482 void LoaderManager::OnTimeoutEvent(LoaderContext* context) {
483 _W("type(%d), loader_name(%s), state(%d)",
484 context->GetType(), context->GetLoaderName().c_str(),
485 context->IsActivated());
487 if (context->GetPid() > 0) {
488 _W("The loader is already running");
492 sequencer_->Add(context->shared_from_this());
496 bool LoaderManager::OnIdleCheck(LoaderContext* context) {
497 _W("Loader(%s), type(%d), pid(%d)",
498 context->GetLoaderName().c_str(), context->GetType(), context->GetPid());
500 if (!context->IsLaunchable())
503 if (context->GetCPUChecker()->IsIdle()) {
508 int count = context->IncreaseCPUCheckCount();
509 if (count == Config::GetInst().GetCPUChecker().GetMaxCount()) {
510 _W("CPU check count has exceeded %d times", count);
511 sequencer_->Add(context->shared_from_this());
517 void LoaderManager::OnLoaderLaunch(LoaderContext* context) {
518 _W("Loader(%s), type(%d), pid(%d)",
519 context->GetLoaderName().c_str(), context->GetType(), context->GetPid());
521 if (!context->IsLaunchable())
527 void LoaderManager::OnLoaderPrepared(LoaderContext* context) {
528 if (event_listener_ != nullptr)
529 event_listener_->OnLoaderPrepared(context);
532 } // namespace launchpad