Dispose candidate process of process pool
[platform/core/appfw/launchpad.git] / src / launchpad-process-pool / loader_manager.cc
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "launchpad-process-pool/loader_manager.hh"
18
19 #include <algorithm>
20 #include <utility>
21
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"
26
27 namespace launchpad {
28 namespace {
29
30 constexpr const char kInfoDirectoryPath[] = "/usr/share/aul";
31
32 }  // namespace
33
34 LoaderManager& LoaderManager::GetInst() {
35   static LoaderManager inst;
36   inst.Init();
37   return inst;
38 }
39
40 void LoaderManager::Dispose() {
41   if (disposed_)
42     return;
43
44   hwacc_config_.reset();
45   app_defined_loader_info_manager_.reset();
46   loader_info_manager_.reset();
47   MemoryMonitor::GetInst().Dispose();
48   AppLabelsMonitor::GetInst().Dispose();
49   disposed_ = true;
50 }
51
52 void LoaderManager::Init() {
53   if (!disposed_)
54     return;
55
56   try {
57     sequencer_.reset(new Sequencer(this));
58     auto& label_monitor = AppLabelsMonitor::GetInst();
59     label_monitor.Init();
60     label_monitor.SetEventListener(this);
61     MemoryMonitor::GetInst().SetEventListener(this);
62
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());
68     return;
69   }
70
71   disposed_ = false;
72 }
73
74 void LoaderManager::SetEventListener(LoaderManager::IEvent* event_listener) {
75   event_listener_ = event_listener;
76 }
77
78 void LoaderManager::HandleSigchld(pid_t pid) {
79   auto context = FindLoaderContextFromPid(pid);
80   if (context != nullptr) {
81     context->SetPid(0);
82     context->Dispose();
83     context->Prepare();
84   } else {
85     auto hydra_context = FindHydraLoaderContextFromPid(pid);
86     if (hydra_context != nullptr) {
87       hydra_context->SetHydraPid(0);
88       hydra_context->Dispose();
89       hydra_context->Prepare();
90     }
91   }
92
93   RemoveLoaderContextsByCallerPid(pid);
94 }
95
96 void LoaderManager::AddDefaultLoaderContexts() {
97   loader_info_manager_.reset(new LoaderInfoManager(kInfoDirectoryPath));
98   loader_info_manager_->Load();
99
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));
105     }
106   }
107
108   ActivateLoaderContexts(LoaderMethod::None);
109 }
110
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());
116
117     if (!context->IsActivated())
118       continue;
119
120     if (context->GetLoaderPath() == "null")
121       continue;
122
123     if (!context->IsTouched() && !context->IsOnBoot())
124       continue;
125
126     if (context->GetPid() > 0)
127       continue;
128
129     if (!context->IsTouched() || context->CanActivate(method)) {
130       context->UnsetTimer();
131       context->SetLoaderMethod(method);
132       sequencer_->Add(context);
133       sequencer_->Run();
134     }
135   }
136 }
137
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());
143     return nullptr;
144   }
145
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",
151           name.c_str());
152       return nullptr;
153     }
154
155     loader_contexts_.push_back(context);
156   }
157
158   if (context->GetPid() < 1)
159     context->Prepare();
160
161   return context;
162 }
163
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)
168     return nullptr;
169
170   context->SetEventListener(this);
171   context->SetTimer();
172   loader_contexts_.push_back(context);
173   return context;
174 }
175
176 void LoaderManager::HandleDirectLaunch(std::shared_ptr<LoaderContext> context) {
177   if (context == nullptr)
178     return;
179
180   if (context->ShouldCheckAppInstallation() && !context->IsAppInstalled())
181     return;
182
183   if (context->GetPid() > 0)
184     return;
185
186   if (sequencer_->Exist(context))
187     return;
188
189   context->UnsetTimer();
190   context->UpdateState(LoaderMethod::Request, true);
191   context->SetTimer();
192 }
193
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())
201       continue;
202
203     info->SetAppInstalled(app_installed);
204     UpdateLoaderContext(info->GetType());
205   }
206 }
207
208 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromPid(
209     pid_t pid) {
210   for (auto& context : loader_contexts_) {
211     if (context->GetPid() == pid)
212       return context;
213   }
214
215   return nullptr;
216 }
217
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());
225     }
226   }
227
228   return nullptr;
229 }
230
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) {
236       context->Dispose();
237       iter = loader_contexts_.erase(iter);
238     } else {
239       iter++;
240     }
241   }
242 }
243
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)
248       return context;
249   }
250
251   return nullptr;
252 }
253
254 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContext(LoaderType type,
255     int loader_id) {
256   if (type == LoaderType::Dynamic)
257     return FindLoaderContextFromLoaderId(loader_id);
258
259   return FindLoaderContextFromType(type);
260 }
261
262 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromLoaderId(
263     int loader_id) {
264   for (auto& context : loader_contexts_) {
265     if (context->GetLoaderId() == loader_id)
266       return context;
267   }
268
269   return nullptr;
270 }
271
272 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromType(
273     LoaderType type) {
274   if (type == LoaderType::Dynamic || type == LoaderType::None)
275     return nullptr;
276
277   for (auto& context : loader_contexts_) {
278     if (context->GetType() == static_cast<int>(type))
279       return context;
280   }
281
282   return nullptr;
283 }
284
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();
293         break;
294       }
295     }
296   } else {
297     if (IsHwAcceleration(hwacc))
298       type = loader_info_manager_->FindHwType(app_type);
299     else
300       type = loader_info_manager_->FindSwType(app_type);
301   }
302
303   return FindLoaderContext(type, PAD_LOADER_ID_STATIC);
304 }
305
306 std::shared_ptr<LoaderContext> LoaderManager::FindAlternativeLoaderContext(
307     LoaderType type) {
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)
312       continue;
313
314     return context;
315   }
316
317   return nullptr;
318 }
319
320 bool LoaderManager::IsHwAcceleration(const std::string& hwacc) {
321   if (hwacc == "USE" ||
322       (hwacc == "SYS" && hwacc_config_->Get() == SETTING_HW_ACCELERATION_ON))
323     return true;
324
325   return false;
326 }
327
328 void LoaderManager::UpdateLoaderContext(LoaderType type) {
329   auto loader_context = FindLoaderContextFromType(type);
330   if (loader_context == nullptr)
331     return;
332
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);
341   } else {
342     if (!loader_context->IsActivated())
343       return;
344
345     if (!loader_context->IsTouched() && !loader_context->IsOnBoot())
346       return;
347
348     loader_context->UnsetTimer();
349     if (loader_context->GetPid() < 1) {
350       sequencer_->Add(loader_context);
351       sequencer_->Run();
352     }
353   }
354 }
355
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);
363     else
364       iter++;
365   }
366 }
367
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);
374     else
375       iter++;
376   }
377 }
378
379 void LoaderManager::UpdateLoaderContexts(bool low_memory) {
380   for (auto& loader_context : loader_contexts_) {
381     if (low_memory)
382       loader_context->UpdateState(LoaderMethod::OutOfMemory, true);
383     else
384       loader_context->UpdateState(LoaderMethod::AvailableMemory, true);
385   }
386 }
387
388 void LoaderManager::HandleMemoryStatusChangedEvent(bool low_memory) {
389   if (low_memory) {
390     _W("Low memory");
391     UpdatePssMemoryOfLoaderContexts();
392     SortLoaderContexts();
393     DeactivateLoaderContexts();
394   } else {
395     ActivateLoaderContexts();
396   }
397 }
398
399 void LoaderManager::UpdatePssMemoryOfLoaderContexts() {
400   for (auto& loader_context : loader_contexts_) {
401     if (loader_context->GetPid() > 0)
402       loader_context->UpdatePssMemory();
403   }
404 }
405
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())
411           return false;
412
413         if (!context_a->IsHydraMode() && context_b->IsHydraMode())
414           return true;
415
416         if (context_a->GetScore() > context_b->GetScore())
417           return false;
418
419         if (context_a->GetScore() < context_b->GetScore())
420           return true;
421
422         return context_a->GetPssMemory() < context_b->GetPssMemory();
423       });
424 }
425
426 void LoaderManager::DeactivateLoaderContexts() {
427   for (auto& loader_context : loader_contexts_) {
428     if (loader_context->IsHydraMode())
429       continue;
430
431     loader_context->UpdateState(LoaderMethod::OutOfMemory, true);
432     if (!MemoryMonitor::GetInst().IsLowMemory())
433       return;
434   }
435 }
436
437 void LoaderManager::ActivateLoaderContexts() {
438   for (auto& loader_context : loader_contexts_)
439     loader_context->UpdateState(LoaderMethod::AvailableMemory, true);
440 }
441
442 LoaderManager::LoaderManager() : sequencer_(new Sequencer(this)) {}
443
444 LoaderManager::~LoaderManager() {
445   Dispose();
446 }
447
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();
455       }
456     } else if (context->GetPid() > 0) {
457       context->Dispose();
458       context->Prepare();
459     }
460   }
461
462   LoaderExecutor::GetInst().DisposeCandidateProcess();
463 }
464
465 void LoaderManager::OnMemoryStatusChanged(bool low_memory,
466     bool should_check_pss) {
467   if (should_check_pss)
468     HandleMemoryStatusChangedEvent(low_memory);
469   else
470     UpdateLoaderContexts(low_memory);
471 }
472
473 void LoaderManager::OnLoaderInfoAdded(const std::string_view name) {
474   _W("%s is added", name.data());
475 }
476
477 void LoaderManager::OnLoaderInfoRemoved(const std::string_view name) {
478   _W("%s is removed", name.data());
479   RemoveLoaderContext(name);
480 }
481
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());
486
487   if (context->GetPid() > 0) {
488     _W("The loader is already running");
489     return;
490   }
491
492   sequencer_->Add(context->shared_from_this());
493   sequencer_->Run();
494 }
495
496 bool LoaderManager::OnIdleCheck(LoaderContext* context) {
497   _W("Loader(%s), type(%d), pid(%d)",
498       context->GetLoaderName().c_str(), context->GetType(), context->GetPid());
499
500   if (!context->IsLaunchable())
501     return false;
502
503   if (context->GetCPUChecker()->IsIdle()) {
504     context->Prepare();
505     return false;
506   }
507
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());
512   }
513
514   return true;
515 }
516
517 void LoaderManager::OnLoaderLaunch(LoaderContext* context) {
518   _W("Loader(%s), type(%d), pid(%d)",
519       context->GetLoaderName().c_str(), context->GetType(), context->GetPid());
520
521   if (!context->IsLaunchable())
522     return;
523
524   context->Prepare();
525 }
526
527 void LoaderManager::OnLoaderPrepared(LoaderContext* context) {
528   if (event_listener_ != nullptr)
529     event_listener_->OnLoaderPrepared(context);
530 }
531
532 }  // namespace launchpad