Handle SIGCHLD event for 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 <types.hh>
23
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"
28
29 namespace launchpad {
30 namespace {
31
32 constexpr const char kInfoDirectoryPath[] = "/usr/share/aul";
33
34 }  // namespace
35
36 LoaderManager& LoaderManager::GetInst() {
37   static LoaderManager inst;
38   inst.Init();
39   return inst;
40 }
41
42 void LoaderManager::Dispose() {
43   if (disposed_)
44     return;
45
46   hwacc_config_.reset();
47   app_defined_loader_info_manager_.reset();
48   loader_info_manager_.reset();
49   MemoryMonitor::GetInst().Dispose();
50   AppLabelsMonitor::GetInst().Dispose();
51   disposed_ = true;
52 }
53
54 void LoaderManager::Init() {
55   if (!disposed_)
56     return;
57
58   try {
59     sequencer_.reset(new Sequencer(this));
60     auto& label_monitor = AppLabelsMonitor::GetInst();
61     label_monitor.Init();
62     label_monitor.SetEventListener(this);
63     MemoryMonitor::GetInst().SetEventListener(this);
64
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());
70     return;
71   }
72
73   disposed_ = false;
74 }
75
76 void LoaderManager::SetEventListener(LoaderManager::IEvent* event_listener) {
77   event_listener_ = event_listener;
78 }
79
80 void LoaderManager::HandleSigchld(pid_t pid) {
81   auto context = FindLoaderContextFromPid(pid);
82   if (context != nullptr) {
83     context->SetPid(0);
84     context->Dispose();
85     context->Prepare();
86   } else {
87     auto hydra_context = FindHydraLoaderContextFromPid(pid);
88     if (hydra_context != nullptr) {
89       hydra_context->SetHydraPid(0);
90       hydra_context->Dispose();
91       hydra_context->Prepare();
92     }
93   }
94
95   RemoveLoaderContextsByCallerPid(pid);
96   LoaderExecutor::GetInst().HandleSigchld(pid);
97 }
98
99 void LoaderManager::AddDefaultLoaderContexts() {
100   loader_info_manager_.reset(new LoaderInfoManager(kInfoDirectoryPath));
101   loader_info_manager_->Load();
102
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));
108     }
109   }
110
111   ActivateLoaderContexts(LoaderMethod::None);
112 }
113
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());
119
120     if (!context->IsActivated())
121       continue;
122
123     if (context->GetLoaderPath() == "null")
124       continue;
125
126     if (!context->IsTouched() && !context->IsOnBoot())
127       continue;
128
129     if (context->GetPid() > 0)
130       continue;
131
132     if (!context->IsTouched() || context->CanBeDetected(method)) {
133       context->UnsetTimer();
134       context->SetLoaderMethod(method);
135       sequencer_->Add(context);
136       sequencer_->Run();
137     }
138   }
139 }
140
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());
146     return nullptr;
147   }
148
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",
154           name.c_str());
155       return nullptr;
156     }
157
158     loader_contexts_.push_back(context);
159   }
160
161   if (context->GetPid() < 1)
162     context->Prepare();
163
164   return context;
165 }
166
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)
171     return nullptr;
172
173   context->SetEventListener(this);
174   context->SetTimer();
175   loader_contexts_.push_back(context);
176   return context;
177 }
178
179 void LoaderManager::HandleDirectLaunch(std::shared_ptr<LoaderContext> context) {
180   if (context == nullptr)
181     return;
182
183   if (context->ShouldCheckAppInstallation() && !context->IsAppInstalled())
184     return;
185
186   if (context->GetPid() > 0)
187     return;
188
189   if (sequencer_->Exist(context))
190     return;
191
192   context->UnsetTimer();
193   context->UpdateState(LoaderMethod::Request, true);
194   context->SetTimer();
195 }
196
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())
204       continue;
205
206     info->SetAppInstalled(app_installed);
207     UpdateLoaderContext(info->GetType());
208   }
209 }
210
211 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromPid(
212     pid_t pid) {
213   for (auto& context : loader_contexts_) {
214     if (context->GetPid() == pid)
215       return context;
216   }
217
218   return nullptr;
219 }
220
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());
228     }
229   }
230
231   return nullptr;
232 }
233
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) {
239       context->Dispose();
240       iter = loader_contexts_.erase(iter);
241     } else {
242       iter++;
243     }
244   }
245 }
246
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)
251       return context;
252   }
253
254   return nullptr;
255 }
256
257 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContext(LoaderType type,
258     int loader_id) {
259   if (type == LoaderType::Dynamic)
260     return FindLoaderContextFromLoaderId(loader_id);
261
262   return FindLoaderContextFromType(type);
263 }
264
265 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromLoaderId(
266     int loader_id) {
267   for (auto& context : loader_contexts_) {
268     if (context->GetLoaderId() == loader_id)
269       return context;
270   }
271
272   return nullptr;
273 }
274
275 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromType(
276     LoaderType type) {
277   if (type == LoaderType::Dynamic || type == LoaderType::None)
278     return nullptr;
279
280   for (auto& context : loader_contexts_) {
281     if (context->GetType() == static_cast<int>(type))
282       return context;
283   }
284
285   return nullptr;
286 }
287
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();
296         break;
297       }
298     }
299   } else {
300     if (IsHwAcceleration(hwacc))
301       type = loader_info_manager_->FindHwType(app_type);
302     else
303       type = loader_info_manager_->FindSwType(app_type);
304   }
305
306   return FindLoaderContext(type, PadLoaderId::Static);
307 }
308
309 std::shared_ptr<LoaderContext> LoaderManager::FindAlternativeLoaderContext(
310     LoaderType type) {
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)
315       continue;
316
317     return context;
318   }
319
320   return nullptr;
321 }
322
323 bool LoaderManager::IsHwAcceleration(const std::string& hwacc) {
324   if (hwacc == "USE" ||
325       (hwacc == "SYS" && hwacc_config_->Get() == SETTING_HW_ACCELERATION_ON))
326     return true;
327
328   return false;
329 }
330
331 void LoaderManager::UpdateLoaderContext(LoaderType type) {
332   auto loader_context = FindLoaderContextFromType(type);
333   if (loader_context == nullptr)
334     return;
335
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);
344   } else {
345     if (!loader_context->IsActivated())
346       return;
347
348     if (!loader_context->IsTouched() && !loader_context->IsOnBoot())
349       return;
350
351     loader_context->UnsetTimer();
352     if (loader_context->GetPid() < 1) {
353       sequencer_->Add(loader_context);
354       sequencer_->Run();
355     }
356   }
357 }
358
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);
366     else
367       iter++;
368   }
369 }
370
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);
377     else
378       iter++;
379   }
380 }
381
382 void LoaderManager::UpdateLoaderContexts(bool low_memory) {
383   for (auto& loader_context : loader_contexts_) {
384     if (low_memory)
385       loader_context->UpdateState(LoaderMethod::OutOfMemory, true);
386     else
387       loader_context->UpdateState(LoaderMethod::AvailableMemory, true);
388   }
389 }
390
391 void LoaderManager::HandleMemoryStatusChangedEvent(bool low_memory) {
392   if (low_memory) {
393     _W("Low memory");
394     UpdatePssMemoryOfLoaderContexts();
395     SortLoaderContexts();
396     DeactivateLoaderContexts();
397   } else {
398     ActivateLoaderContexts();
399   }
400 }
401
402 void LoaderManager::UpdatePssMemoryOfLoaderContexts() {
403   for (auto& loader_context : loader_contexts_) {
404     if (loader_context->GetPid() > 0)
405       loader_context->UpdatePssMemory();
406   }
407 }
408
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())
414           return false;
415
416         if (!context_a->IsHydraMode() && context_b->IsHydraMode())
417           return true;
418
419         if (context_a->GetScore() > context_b->GetScore())
420           return false;
421
422         if (context_a->GetScore() < context_b->GetScore())
423           return true;
424
425         return context_a->GetPssMemory() < context_b->GetPssMemory();
426       });
427 }
428
429 void LoaderManager::DeactivateLoaderContexts() {
430   for (auto& loader_context : loader_contexts_) {
431     if (loader_context->IsHydraMode())
432       continue;
433
434     loader_context->UpdateState(LoaderMethod::OutOfMemory, true);
435     if (!MemoryMonitor::GetInst().IsLowMemory())
436       return;
437   }
438 }
439
440 void LoaderManager::ActivateLoaderContexts() {
441   for (auto& loader_context : loader_contexts_)
442     loader_context->UpdateState(LoaderMethod::AvailableMemory, true);
443 }
444
445 LoaderManager::LoaderManager() : sequencer_(new Sequencer(this)) {}
446
447 LoaderManager::~LoaderManager() {
448   Dispose();
449 }
450
451 void LoaderManager::OnAppLabelsChanged() {
452   _W("BEGIN");
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();
460       }
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(),
465             context->GetPid());
466         continue;
467       }
468
469       context->Dispose();
470       context->Prepare();
471     }
472   }
473   _W("END");
474 }
475
476 void LoaderManager::OnMemoryStatusChanged(bool low_memory,
477     bool should_check_pss) {
478   if (should_check_pss)
479     HandleMemoryStatusChangedEvent(low_memory);
480   else
481     UpdateLoaderContexts(low_memory);
482 }
483
484 void LoaderManager::OnLoaderInfoAdded(const std::string_view name) {
485   _W("%s is added", name.data());
486 }
487
488 void LoaderManager::OnLoaderInfoRemoved(const std::string_view name) {
489   _W("%s is removed", name.data());
490   RemoveLoaderContext(name);
491 }
492
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());
497
498   if (context->GetPid() > 0) {
499     _W("The loader is already running");
500     return;
501   }
502
503   sequencer_->Add(context->shared_from_this());
504   sequencer_->Run();
505 }
506
507 bool LoaderManager::OnIdleCheck(LoaderContext* context) {
508   _W("Loader(%s), type(%d), pid(%d)",
509       context->GetLoaderName().c_str(), context->GetType(), context->GetPid());
510
511   if (!context->IsLaunchable())
512     return false;
513
514   if (context->GetCPUChecker()->IsIdle()) {
515     context->Prepare();
516     return false;
517   }
518
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());
523   }
524
525   return true;
526 }
527
528 void LoaderManager::OnLoaderLaunch(LoaderContext* context) {
529   _D("Loader(%s), type(%d), pid(%d)",
530       context->GetLoaderName().c_str(), context->GetType(), context->GetPid());
531
532   if (!context->IsLaunchable())
533     return;
534
535   context->Prepare();
536 }
537
538 void LoaderManager::OnLoaderPrepared(LoaderContext* context) {
539   if (event_listener_ != nullptr)
540     event_listener_->OnLoaderPrepared(context);
541 }
542
543 void LoaderManager::OnLoaderLaunched(LoaderContext* context) {
544   if (event_listener_ != nullptr)
545     event_listener_->OnLoaderLaunched(context);
546 }
547
548 }  // namespace launchpad