Mount gadget resource paths for NUIGadget
[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   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();
52   disposed_ = true;
53 }
54
55 void LoaderManager::Init() {
56   if (!disposed_)
57     return;
58
59   try {
60     sequencer_.reset(new Sequencer(this));
61     auto& label_monitor = AppLabelsMonitor::GetInst();
62     label_monitor.Init();
63     label_monitor.SetEventListener(this);
64     MemoryMonitor::GetInst().SetEventListener(this);
65
66     app_defined_loader_info_manager_.reset(new AppDefinedLoaderInfoManager());
67     app_defined_loader_info_manager_->SetEventListener(this);
68     hwacc_config_.reset(new HWAccelerationConfig());
69
70     if (!label_monitor.IsDisposed()) {
71       setenv("LOADER_MOUNT", "1", 1);
72       loader_mount_.reset(new LoaderMount());
73     }
74   } catch (const Exception& e) {
75     _E("Exception occurs. error: %s", e.what());
76     return;
77   }
78
79   disposed_ = false;
80 }
81
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);
86 }
87
88 void LoaderManager::SetEventListener(LoaderManager::IEvent* event_listener) {
89   event_listener_ = event_listener;
90 }
91
92 void LoaderManager::HandleSigchld(pid_t pid) {
93   auto context = FindLoaderContextFromPid(pid);
94   if (context != nullptr) {
95     context->SetPid(0);
96     context->Dispose();
97     context->Prepare();
98   } else {
99     auto hydra_context = FindHydraLoaderContextFromPid(pid);
100     if (hydra_context != nullptr) {
101       hydra_context->SetHydraPid(0);
102       hydra_context->Dispose();
103       hydra_context->Prepare();
104     }
105   }
106
107   RemoveLoaderContextsByCallerPid(pid);
108   LoaderExecutor::GetInst().HandleSigchld(pid);
109   if (loader_mount_) loader_mount_->HandleSigchld(pid);
110 }
111
112 void LoaderManager::AddDefaultLoaderContexts() {
113   loader_info_manager_.reset(new LoaderInfoManager(kInfoDirectoryPath));
114   loader_info_manager_->Load();
115
116   for (auto& info : loader_info_manager_->GetLoaderInfoList()) {
117     auto context =
118         LoaderFactory::GetInst().CreateLoaderContext(info, loader_mount_);
119     if (context != nullptr) {
120       context->SetEventListener(this);
121       loader_contexts_.push_back(std::move(context));
122     }
123   }
124
125   ActivateLoaderContexts(LoaderMethod::None);
126 }
127
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());
133
134     if (!context->IsActivated())
135       continue;
136
137     if (context->GetLoaderPath() == "null")
138       continue;
139
140     if (!context->IsTouched() && !context->IsOnBoot())
141       continue;
142
143     if (context->GetPid() > 0)
144       continue;
145
146     if (!context->IsTouched() || context->CanBeDetected(method)) {
147       context->UnsetTimer();
148       context->SetLoaderMethod(method);
149       sequencer_->Add(context);
150       sequencer_->Run();
151     }
152   }
153 }
154
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());
160     return nullptr;
161   }
162
163   auto context = FindLoaderContextFromName(name);
164   if (context == nullptr) {
165     context = LoaderFactory::GetInst().CreateLoaderContext(info, caller_pid,
166                                                            loader_mount_);
167     if (context == nullptr) {
168       _E("Failed to create loader context. loader_name: %s",
169           name.c_str());
170       return nullptr;
171     }
172
173     loader_contexts_.push_back(context);
174   }
175
176   if (context->GetPid() < 1)
177     context->Prepare();
178
179   return context;
180 }
181
182 std::shared_ptr<LoaderContext> LoaderManager::AddLoaderContext(
183     tizen_base::Bundle b) {
184   auto context =
185       LoaderFactory::GetInst().CreateLoaderContext(std::move(b), loader_mount_);
186   if (context == nullptr)
187     return nullptr;
188
189   context->SetEventListener(this);
190   context->SetTimer();
191   loader_contexts_.push_back(context);
192   return context;
193 }
194
195 void LoaderManager::HandleDirectLaunch(std::shared_ptr<LoaderContext> context) {
196   if (context == nullptr)
197     return;
198
199   if (context->ShouldCheckAppInstallation() && !context->IsAppInstalled())
200     return;
201
202   if (context->GetPid() > 0)
203     return;
204
205   if (sequencer_->Exist(context))
206     return;
207
208   context->UnsetTimer();
209   context->UpdateState(LoaderMethod::Request, true);
210   context->SetTimer();
211 }
212
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())
220       continue;
221
222     info->SetAppInstalled(app_installed);
223     UpdateLoaderContext(info->GetType());
224   }
225 }
226
227 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromPid(
228     pid_t pid) {
229   for (auto& context : loader_contexts_) {
230     if (context->GetPid() == pid)
231       return context;
232   }
233
234   return nullptr;
235 }
236
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());
244     }
245   }
246
247   return nullptr;
248 }
249
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) {
255       context->Dispose();
256       iter = loader_contexts_.erase(iter);
257     } else {
258       iter++;
259     }
260   }
261 }
262
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)
267       return context;
268   }
269
270   return nullptr;
271 }
272
273 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContext(LoaderType type,
274     int loader_id) {
275   if (type == LoaderType::Dynamic)
276     return FindLoaderContextFromLoaderId(loader_id);
277
278   return FindLoaderContextFromType(type);
279 }
280
281 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromLoaderId(
282     int loader_id) {
283   for (auto& context : loader_contexts_) {
284     if (context->GetLoaderId() == loader_id)
285       return context;
286   }
287
288   return nullptr;
289 }
290
291 std::shared_ptr<LoaderContext> LoaderManager::FindLoaderContextFromType(
292     LoaderType type) {
293   if (type == LoaderType::Dynamic || type == LoaderType::None)
294     return nullptr;
295
296   for (auto& context : loader_contexts_) {
297     if (context->GetType() == static_cast<int>(type))
298       return context;
299   }
300
301   return nullptr;
302 }
303
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();
312         break;
313       }
314     }
315   } else {
316     if (IsHwAcceleration(hwacc))
317       type = loader_info_manager_->FindHwType(app_type);
318     else
319       type = loader_info_manager_->FindSwType(app_type);
320   }
321
322   return FindLoaderContext(type, PadLoaderId::Static);
323 }
324
325 std::shared_ptr<LoaderContext> LoaderManager::FindAlternativeLoaderContext(
326     LoaderType type) {
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)
331       continue;
332
333     return context;
334   }
335
336   return nullptr;
337 }
338
339 bool LoaderManager::IsHwAcceleration(const std::string& hwacc) {
340   if (hwacc == "USE" ||
341       (hwacc == "SYS" && hwacc_config_->Get() == SETTING_HW_ACCELERATION_ON))
342     return true;
343
344   return false;
345 }
346
347 void LoaderManager::UpdateLoaderContext(LoaderType type) {
348   auto loader_context = FindLoaderContextFromType(type);
349   if (loader_context == nullptr)
350     return;
351
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);
360   } else {
361     if (!loader_context->IsActivated())
362       return;
363
364     if (!loader_context->IsTouched() && !loader_context->IsOnBoot())
365       return;
366
367     loader_context->UnsetTimer();
368     if (loader_context->GetPid() < 1) {
369       sequencer_->Add(loader_context);
370       sequencer_->Run();
371     }
372   }
373 }
374
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);
382     else
383       iter++;
384   }
385 }
386
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);
393     else
394       iter++;
395   }
396 }
397
398 void LoaderManager::UpdateLoaderContexts(bool low_memory) {
399   for (auto& loader_context : loader_contexts_) {
400     if (low_memory)
401       loader_context->UpdateState(LoaderMethod::OutOfMemory, true);
402     else
403       loader_context->UpdateState(LoaderMethod::AvailableMemory, true);
404   }
405 }
406
407 void LoaderManager::HandleMemoryStatusChangedEvent(bool low_memory) {
408   if (low_memory) {
409     _W("Low memory");
410     UpdatePssMemoryOfLoaderContexts();
411     SortLoaderContexts();
412     DeactivateLoaderContexts();
413   } else {
414     ActivateLoaderContexts();
415   }
416 }
417
418 void LoaderManager::UpdatePssMemoryOfLoaderContexts() {
419   for (auto& loader_context : loader_contexts_) {
420     if (loader_context->GetPid() > 0)
421       loader_context->UpdatePssMemory();
422   }
423 }
424
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())
430           return false;
431
432         if (!context_a->IsHydraMode() && context_b->IsHydraMode())
433           return true;
434
435         if (context_a->GetScore() > context_b->GetScore())
436           return false;
437
438         if (context_a->GetScore() < context_b->GetScore())
439           return true;
440
441         return context_a->GetPssMemory() < context_b->GetPssMemory();
442       });
443 }
444
445 void LoaderManager::DeactivateLoaderContexts() {
446   for (auto& loader_context : loader_contexts_) {
447     if (loader_context->IsHydraMode())
448       continue;
449
450     loader_context->UpdateState(LoaderMethod::OutOfMemory, true);
451     if (!MemoryMonitor::GetInst().IsLowMemory())
452       return;
453   }
454 }
455
456 void LoaderManager::ActivateLoaderContexts() {
457   for (auto& loader_context : loader_contexts_)
458     loader_context->UpdateState(LoaderMethod::AvailableMemory, true);
459 }
460
461 LoaderManager::LoaderManager() : sequencer_(new Sequencer(this)) {}
462
463 LoaderManager::~LoaderManager() {
464   Dispose();
465 }
466
467 void LoaderManager::OnAppLabelsChanged() {
468   _W("BEGIN");
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();
476       }
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(),
481             context->GetPid());
482         continue;
483       }
484
485       context->Dispose();
486       context->Prepare();
487     }
488   }
489   _W("END");
490 }
491
492 void LoaderManager::OnMemoryStatusChanged(bool low_memory,
493     bool should_check_pss) {
494   if (should_check_pss)
495     HandleMemoryStatusChangedEvent(low_memory);
496   else
497     UpdateLoaderContexts(low_memory);
498 }
499
500 void LoaderManager::OnLoaderInfoAdded(const std::string_view name) {
501   _W("%s is added", name.data());
502 }
503
504 void LoaderManager::OnLoaderInfoRemoved(const std::string_view name) {
505   _W("%s is removed", name.data());
506   RemoveLoaderContext(name);
507 }
508
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());
513
514   if (context->GetPid() > 0) {
515     _W("The loader is already running");
516     return;
517   }
518
519   sequencer_->Add(context->shared_from_this());
520   sequencer_->Run();
521 }
522
523 bool LoaderManager::OnIdleCheck(LoaderContext* context) {
524   _W("Loader(%s), type(%d), pid(%d)",
525       context->GetLoaderName().c_str(), context->GetType(), context->GetPid());
526
527   if (!context->IsLaunchable())
528     return false;
529
530   if (context->GetCPUChecker()->IsIdle()) {
531     context->Prepare();
532     return false;
533   }
534
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());
539   }
540
541   return true;
542 }
543
544 void LoaderManager::OnLoaderLaunch(LoaderContext* context) {
545   _D("Loader(%s), type(%d), pid(%d)",
546       context->GetLoaderName().c_str(), context->GetType(), context->GetPid());
547
548   if (!context->IsLaunchable())
549     return;
550
551   context->Prepare();
552 }
553
554 void LoaderManager::OnLoaderPrepared(LoaderContext* context) {
555   if (event_listener_ != nullptr)
556     event_listener_->OnLoaderPrepared(context);
557 }
558
559 void LoaderManager::OnLoaderLaunched(LoaderContext* context) {
560   if (event_listener_ != nullptr)
561     event_listener_->OnLoaderLaunched(context);
562 }
563
564 }  // namespace launchpad