4733c99a90491bdc43614b7af18bf3cfe73f571a
[platform/core/appfw/launchpad.git] / src / launchpad-process-pool / launchpad.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/launchpad.hh"
18
19 #include <bundle_internal.h>
20 #include <errno.h>
21 #include <glib.h>
22 #include <security-manager.h>
23 #include <sys/prctl.h>
24 #include <systemd/sd-daemon.h>
25
26 #include <algorithm>
27 #include <string>
28 #include <utility>
29
30 #include <app_info.hh>
31 #include <aul_keys.hh>
32 #include <cpu_boost_controller.hh>
33 #include <exception.hh>
34 #include <executor.hh>
35 #include <procfs.hh>
36 #include <sched_priority.hh>
37 #include <types.hh>
38 #include <user_tracer.hh>
39 #include <util.hh>
40
41 #include "launchpad-process-pool/config.hh"
42 #include "launchpad-process-pool/dbus.hh"
43 #include "launchpad-process-pool/debug.hh"
44 #include "launchpad-process-pool/launcher_info.hh"
45 #include "launchpad-process-pool/launchpad_args.hh"
46 #include "launchpad-process-pool/loader_manager.hh"
47 #include "launchpad-process-pool/loader_executor.hh"
48 #include "launchpad-process-pool/log.hh"
49 #include "launchpad-process-pool/log_private.hh"
50 #include "launchpad-process-pool/memory_monitor.hh"
51 #include "launchpad-process-pool/signal_manager.hh"
52 #include "launchpad-process-pool/tracer.hh"
53 #include "launchpad-process-pool/util.hh"
54 #include "launchpad-process-pool/worker.hh"
55
56 namespace launchpad {
57 namespace {
58
59 constexpr const char kRunAulDaemonsPath[] = "/run/aul/daemons/";
60 constexpr const char kLaunchpadProcessPoolSock[] =
61     ".launchpad-process-pool-sock";
62 constexpr const char kInfoDirectoryPath[] = "/usr/share/aul";
63 const int kReceivedBufferSize = 131071;
64 const int kMaxPendingConnection = 128;
65 const uid_t kRegularUidMin = 5000;
66
67 class CleanupInfo : public launchpad::Worker::Job {
68  public:
69   CleanupInfo(std::string appid, pid_t pid)
70       : appid_(std::move(appid)), pid_(pid) {}
71
72   void Do() override {
73     _W("security_manager_cleanup_app() ++");
74     security_manager_cleanup_app(appid_.c_str(), getuid(), pid_);
75     _W("security_manager_cleanup_app() --");
76   }
77
78  private:
79   std::string appid_;
80   pid_t pid_;
81 };
82
83 int GetLaunchpadFdFromSystemd() {
84   const std::string path = kRunAulDaemonsPath + std::to_string(getuid()) +
85       "/" + std::string(kLaunchpadProcessPoolSock);
86   int fds = sd_listen_fds(0);
87   for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fds; ++fd) {
88     if (sd_is_socket_unix(fd, SOCK_STREAM, 1, path.c_str(), 0) > 0)
89       return fd;
90   }
91
92   _W("There is no socket stream");
93   return -1;
94 }
95
96 int GetLaunchpadFdFromEnvironment() {
97   auto* value = getenv("LAUNCHPAD_LISTEN_FD");
98   if (value == nullptr || !isdigit(value[0])) {
99     _E("Failed to get launchpad fd");
100     return -1;
101   }
102
103   _W("fd: %s", value);
104   return atoi(value);
105 }
106
107 ServerSocket* GetLaunchpadSocket() {
108   int fd = GetLaunchpadFdFromSystemd();
109   if (fd < 0)
110     fd = GetLaunchpadFdFromEnvironment();
111
112   if (fd > -1)
113     return new ServerSocket(fd);
114
115   auto* socket = new ServerSocket();
116   const std::string endpoint = kRunAulDaemonsPath + std::to_string(getuid()) +
117       "/" + kLaunchpadProcessPoolSock;
118   socket->Bind(endpoint);
119   socket->SetReceiveBufferSize(kReceivedBufferSize);
120   socket->Listen(kMaxPendingConnection);
121   return socket;
122 }
123
124 void PrintAppInfo(const AppInfo* app_info) {
125   SECURE_LOGD("appid: %s", app_info->GetAppId().c_str());
126   SECURE_LOGD("app_path: %s", app_info->GetAppPath().c_str());
127   SECURE_LOGD("comp_type: %s", app_info->GetCompType().c_str());
128   SECURE_LOGD("internal pool: %s", app_info->GetInternalPool().c_str());
129   SECURE_LOGD("hwacc: %s", app_info->GetHwacc().c_str());
130   SECURE_LOGD("app_type: %s", app_info->GetAppType().c_str());
131   SECURE_LOGD("pkg_type: %s", app_info->GetPkgType().c_str());
132 }
133
134 int CheckCallerPermission(pid_t caller_pid) {
135   std::string attr_current = Procfs::GetAttrCurrent(caller_pid);
136   if (attr_current.empty())
137     return -1;
138
139   if (attr_current.compare("User") == 0 ||
140       attr_current.compare("System") == 0 ||
141       attr_current.compare("System::Privileged") == 0)
142     return 0;
143
144   return -1;
145 }
146
147 int GetLoaderIdFromBundle(const tizen_base::Bundle& b) {
148   auto loader_id = b.GetString(kAulLoaderId);
149   if (loader_id.empty())
150     return -1;
151
152   _W("Requested loader id: %s", loader_id.c_str());
153   return std::stoi(loader_id);
154 }
155
156 }  // namespace
157
158 Launchpad::Launchpad(int argc, char** argv)
159     : argc_(argc),
160       argv_(argv),
161       loop_(g_main_loop_new(nullptr, FALSE)) {
162   LaunchpadArgs::GetInst().Set(argc_, argv_);
163   handlers_ = {
164     { PadCmd::Visibility,
165       std::bind(&Launchpad::HandleVisibilityRequest, this,
166           std::placeholders::_1) },
167     { PadCmd::AddLoader,
168       std::bind(&Launchpad::HandleAddLoaderRequest, this,
169           std::placeholders::_1) },
170     { PadCmd::RemoveLoader,
171       std::bind(&Launchpad::HandleRemoveLoaderRequest, this,
172           std::placeholders::_1) },
173     { PadCmd::MakeDefaultSlots,
174       std::bind(&Launchpad::HandleMakeDefaultSlotsRequest, this,
175           std::placeholders::_1) },
176     { PadCmd::PrepareAppDefinedLoader,
177       std::bind(&Launchpad::HandlePrepareAppDefinedLoaderRequest, this,
178           std::placeholders::_1) },
179     { PadCmd::Demand,
180       std::bind(&Launchpad::HandleDemandRequest, this,
181           std::placeholders::_1) },
182     { PadCmd::Ping,
183       std::bind(&Launchpad::HandlePingRequest, this,
184           std::placeholders::_1) },
185     { PadCmd::UpdateAppType,
186       std::bind(&Launchpad::HandleUpdateAppTypeRequest, this,
187           std::placeholders::_1) },
188     { PadCmd::Connect,
189       std::bind(&Launchpad::HandleConnectRequest, this,
190           std::placeholders::_1) },
191     { PadCmd::Launch,
192       std::bind(&Launchpad::HandleLaunchRequest, this,
193           std::placeholders::_1) },
194     { PadCmd::KillLoader,
195       std::bind(&Launchpad::HandleKillLoaderRequest, this,
196           std::placeholders::_1) },
197   };
198
199   CPUBoostController::Level level;
200   int ret = CPUBoostController::GetBoostLevel(getpid(), &level);
201   if (ret != 0)
202     CPUBoostController::Clear(getpid());
203
204   if (ret != 0 ||
205       level == CPUBoostController::Level::None ||
206       level == CPUBoostController::Level::Weak) {
207     CPUBoostController::DoBoost(getpid(), CPUBoostController::Level::Strong,
208         -1);
209   }
210
211   g_timeout_add(1000, [](gpointer data) {
212         CPUBoostController::Clear(getpid());
213         return G_SOURCE_REMOVE;
214       }, this);
215   mode_ = Config::GetInst().GetLaunchMode().GetMode();
216 }
217
218 Launchpad::~Launchpad() {
219   if (loop_ != nullptr)
220     g_main_loop_unref(loop_);
221 }
222
223 int Launchpad::Run() {
224   if (!OnCreate()) {
225     OnTerminate();
226     return -1;
227   }
228
229 #ifdef TIZEN_FEATURE_PRIORITY_CHANGE
230   _set_priority(-12);
231 #endif
232   UserTracer::Print(
233       std::string(__FUNCTION__) + "(" + std::to_string(__LINE__) +
234       "): g_main_loop_run()");
235   g_main_loop_run(loop_);
236   OnTerminate();
237   return 0;
238 }
239
240 void Launchpad::Quit() {
241   g_main_loop_quit(loop_);
242 }
243
244 bool Launchpad::OnCreate() {
245   UserTracer user_tracer(
246       std::string(__FUNCTION__) + "(" + std::to_string(__LINE__) + ")");
247   launchpad::SignalManager::GetInst().SetEventListener(this);
248
249   try {
250     app_executor_.reset(new AppExecutor());
251     socket_.reset(GetLaunchpadSocket());
252     channel_.reset(
253         new IOChannel(socket_->GetFd(), IOChannel::IOCondition::IO_IN, this));
254     channel_->SetCloseOnDestroy(false);
255   } catch (const Exception& e) {
256     _E("Exception occurs. error: %s", e.what());
257     return false;
258   }
259
260   cleaner_.reset(new Worker("cleaner+"));
261   DBus::Init();
262
263   LoaderManager::GetInst().AddDefaultLoaderContexts();
264   LoaderManager::GetInst().SetEventListener(this);
265   launchpad::Debug::GetInst().Init();
266
267   Util::SendCmdToAmd(AmdCmd::LaunchpadLaunchSignal);
268   lang_config_.reset(new LanguageConfig());
269   region_format_config_.reset(new RegionFormatConfig());
270
271   Log::Init();
272   return true;
273 }
274
275 void Launchpad::OnTerminate() {
276   Log::Finish();
277   region_format_config_.reset();
278   lang_config_.reset();
279
280   pid_map_.clear();
281   Util::SendCmdToAmd(AmdCmd::LaunchpadDeadSignal);
282   Debug::GetInst().Dispose();
283   DBus::Finish();
284   cleaner_.reset();
285
286   LoaderManager::GetInst().Dispose();
287   channel_.reset();
288   socket_.reset();
289   SignalManager::GetInst().Dispose();
290 }
291
292 void Launchpad::HandleVisibilityRequest(std::shared_ptr<Request> request) {
293   LoaderManager::GetInst().ActivateLoaderContexts(LoaderMethod::Visibility);
294   request->SendResult(0);
295   _D("[PAD_CMD_VISIBILITY]");
296 }
297
298 void Launchpad::HandleAddLoaderRequest(std::shared_ptr<Request> request) {
299   auto context = LoaderManager::GetInst().AddLoaderContext(
300       request->GetBundle());
301   if (context == nullptr) {
302     request->SendResult(-1);
303     _W("[PAD_CMD_ADD_LOADER] Can not add loader context");
304     return;
305   }
306
307   request->SendResult(context->GetLoaderId());
308   _D("[PAD_CMD_ADD_LOADER]");
309 }
310
311 void Launchpad::HandleRemoveLoaderRequest(std::shared_ptr<Request> request) {
312   auto& b = request->GetBundle();
313   auto loader_id_str = b.GetString(kAulLoaderId);
314   if (loader_id_str.empty()) {
315     _E("Failed to get loader id");
316     request->SendResult(-1);
317     return;
318   }
319
320   LoaderManager::GetInst().RemoveLoaderContext(LoaderType::Dynamic,
321       std::stoi(loader_id_str));
322   request->SendResult(0);
323   _D("[PAD_CMD_REMOVE_LOADER]");
324 }
325
326 void Launchpad::HandleMakeDefaultSlotsRequest(
327   std::shared_ptr<Request> request) {
328   LoaderManager::GetInst().AddDefaultLoaderContexts();
329   _D("[PAD_CMD_MAKE_DEFAULT_SLOTS]");
330 }
331
332 void Launchpad::HandlePrepareAppDefinedLoaderRequest(
333     std::shared_ptr<Request> request) {
334   auto& b = request->GetBundle();
335   auto loader_name = b.GetString(kAulLoaderName);
336   if (loader_name.empty()) {
337     _E("Failed to get loader name");
338     request->SendResult(-EINVAL);
339     return;
340   }
341
342   auto context = LoaderManager::GetInst().PrepareAppDefinedLoaderContext(
343       loader_name, request->GetCallerPid());
344   if (context == nullptr) {
345     request->SendResult(-EINVAL);
346     return;
347   }
348
349   request->SendResult(context->GetLoaderId());
350   _D("[PAD_CMD_PREPARE_APP_DEFINED_LOADER] result: %d", context->GetLoaderId());
351 }
352
353 void Launchpad::HandleDemandRequest(std::shared_ptr<Request> request) {
354   LoaderManager::GetInst().ActivateLoaderContexts(LoaderMethod::Demand);
355   request->SendResult(0);
356   _D("[PAD_CMD_DEMAND]");
357 }
358
359 void Launchpad::HandlePingRequest(std::shared_ptr<Request> request) {
360   request->SendResult(getpid());
361   _D("[PAD_CMD_PING]");
362 }
363
364 void Launchpad::HandleUpdateAppTypeRequest(std::shared_ptr<Request> request) {
365   auto& b = request->GetBundle();
366   auto app_type = b.GetString(kAulAppType);
367   if (app_type.empty()) {
368     _E("Failed to get app type");
369     return;
370   }
371
372   auto installed = b.GetString(kAulIsInstalled);
373   _I("type: %s, installed: %s", app_type.c_str(), installed.c_str());
374   bool app_installed = (installed == "true") ? true : false;
375   LoaderManager::GetInst().UpdateAppInstallationStatus(app_type, app_installed);
376   _D("[PAD_CMD_UPDATE_APP_TYPE]");
377 }
378
379 void Launchpad::HandleConnectRequest(std::shared_ptr<Request> request) {
380   client_socket_.reset(
381       new ClientSocket(request->GetClientSocket()->RemoveFd()));
382   _D("[PAD_CMD_CONNECT] client fd: %d", client_socket_->GetFd());
383 }
384
385 bool Launchpad::CanUseLoaderContext(
386     const std::shared_ptr<LoaderContext>& context) {
387   if (context->IsPrepared())
388     return true;
389
390   if (mode_ == Config::LaunchMode::Mode::PreviousOperation)
391     return false;
392
393   if (mode_ == Config::LaunchMode::Mode::DefaultOperation) {
394     if (context->IsHydraMode())
395       return true;
396
397     return context->GetPid() > 0 && context->RefCount() == 0;
398   }
399
400   // Config::LaunchMode::Mode::AlwaysLoader
401   // Config::LaunchMode::Mode::AlwaysLoaderWithoutCPUChecker
402   // Config::LaunchMode::Mode::AlwaysLoaderWithLowPriority
403   if (context->GetPid() > 0)
404     return true;
405
406   return context->IsLaunchable();
407 }
408
409 Launchpad::LaunchResult Launchpad::LaunchRequestPrepare(
410     std::shared_ptr<Request> request) {
411   auto* app_info = AppInfo::Create(request->GetBundle());
412   if (app_info == nullptr) {
413     _E("Failed to create AppInfo");
414     return LaunchResult::Fail;
415   }
416
417   request->SetAppInfo(std::unique_ptr<AppInfo>(app_info));
418   if (app_info->GetAppPath().empty()) {
419     _E("AppPath is empty");
420     return LaunchResult::Fail;
421   }
422
423   PrintAppInfo(app_info);
424
425   auto& loader_manager = LoaderManager::GetInst();
426   auto& comp_type = app_info->GetCompType();
427   if (comp_type == "svcapp") {
428     request->SetLoaderId(GetLoaderIdFromBundle(request->GetBundle()));
429     if (request->GetLoaderId() > PadLoaderId::DynamicBase) {
430       auto context = loader_manager.FindLoaderContext(LoaderType::Dynamic,
431           request->GetLoaderId());
432       if (context != nullptr && CanUseLoaderContext(context))
433         request->SetAvailableLoaderContext(std::move(context));
434     } else {
435       request->SetLoaderId(PadLoaderId::Direct);
436     }
437   } else if (comp_type == "widget" && app_info->GetAppType() == "webapp") {
438     request->SetLoaderId(PadLoaderId::Direct);
439   } else {
440     request->SetLoaderId(GetLoaderIdFromBundle(request->GetBundle()));
441     if (request->GetLoaderId() <= PadLoaderId::Static) {
442       auto context = loader_manager.FindAvailableLoaderContext(
443           app_info->GetHwacc(), app_info->GetAppType(),
444           app_info->GetLoaderName());
445       if (context != nullptr) {
446         request->SetLoaderContext(context);
447         if (CanUseLoaderContext(context)) {
448           request->SetAvailableLoaderContext(std::move(context));
449         } else {
450           auto alt_context = loader_manager.FindAlternativeLoaderContext(
451               static_cast<LoaderType>(context->GetType()));
452           if (alt_context != nullptr && CanUseLoaderContext(alt_context))
453             request->SetAvailableLoaderContext(std::move(alt_context));
454         }
455       }
456     } else {
457       auto context = loader_manager.FindLoaderContext(LoaderType::Dynamic,
458           request->GetLoaderId());
459       if (context != nullptr && CanUseLoaderContext(context))
460         request->SetAvailableLoaderContext(std::move(context));
461     }
462   }
463
464   return LaunchResult::Success;
465 }
466
467 Launchpad::LaunchResult Launchpad::ForkProcessing(
468     std::shared_ptr<Request> request) {
469   if (request->GetBundle().GetType(kAulSdk) != BUNDLE_TYPE_NONE) {
470     if (Debug::GetInst().Load())
471       app_executor_->DisposeCandidateProcess();
472   }
473
474   _W("appid: %s", request->GetAppInfo()->GetAppId().c_str());
475   request->SetPid(app_executor_->Execute(request->GetAppInfo()));
476   if (request->GetPid() == -1) {
477     _E("Failed to create a child process. appid: %s",
478         request->GetAppInfo()->GetAppId().c_str());
479   }
480
481   request->SendResult(request->GetPid());
482   _W("appid: %s, pid: %d",
483       request->GetAppInfo()->GetAppId().c_str(), request->GetPid());
484   LoaderManager::GetInst().HandleDirectLaunch(
485       std::move(request->GetLoaderContext()));
486   if (request->GetPid() == -1)
487     return LaunchResult::Fail;
488
489   return LaunchResult::Success;
490 }
491
492 Launchpad::LaunchResult Launchpad::LaunchRequestPend(
493     std::shared_ptr<Request> request) {
494   auto loader_context = request->GetAvailableLoaderContext();
495   if (loader_context->IsPrepared()) {
496     if (mode_ == Config::LaunchMode::Mode::AlwaysLoaderWithLowPriority)
497       SchedPriority::Set(loader_context->GetPid(), 0);
498
499     return LaunchResult::Continue;
500   }
501
502   _W("Loader context is not prepared");
503   loader_context->Ref();
504   if (loader_context->GetPid() <= 0)
505     loader_context->Prepare();
506
507   if (loader_context->GetPid() > 0) {
508     CPUBoostController::DoBoost(loader_context->GetPid(),
509         CPUBoostController::Level::Strong, 10000);
510     _W("Send result: %d", loader_context->GetPid());
511     request->SendResult(loader_context->GetPid());
512   }
513
514   pending_requests_.push_back(std::move(request));
515   return LaunchResult::Pending;
516 }
517
518 Launchpad::LaunchResult Launchpad::LaunchRequestDo(
519     std::shared_ptr<Request> request) {
520   auto loader_context = request->GetAvailableLoaderContext();
521   if (request->GetLoaderId() == PadLoaderId::Direct ||
522       loader_context == nullptr ||
523       launchpad::Debug::GetInst().CheckAsanApp(
524           request->GetAppInfo()->GetAppId())) {
525     return ForkProcessing(request);
526   }
527
528   if (LaunchRequestPend(request) == LaunchResult::Pending)
529     return LaunchResult::Pending;
530
531   auto* app_info = request->GetAppInfo();
532   _W("Launch %d type process. appid: %s",
533       static_cast<int>(loader_context->GetType()),
534       app_info->GetAppId().c_str());
535   request->SetPid(loader_context->Deploy(app_info));
536
537   if ((mode_ == Config::LaunchMode::Mode::AlwaysLoaderWithoutCPUChecker) ||
538       (mode_ == Config::LaunchMode::Mode::AlwaysLoaderWithLowPriority) ||
539       (mode_ == Config::LaunchMode::Mode::AlwaysLoader &&
540        loader_context->RefCount() > 0))
541     loader_context->Prepare();
542
543   return LaunchResult::Success;
544 }
545
546 void Launchpad::LaunchRequestComplete(std::shared_ptr<Request> request) {
547   MemoryMonitor::GetInst().Reset();
548   request->SendResult(request->GetPid());
549
550   if (request->GetPid() > 0) {
551     auto* app_info = request->GetAppInfo();
552     launchpad::DBus::SendAppLaunchSignal(request->GetPid(),
553         app_info->GetAppId().c_str());
554     pid_map_[request->GetPid()] = app_info->GetAppId();
555     launchpad::Log::Print("[LAUNCH]", "pid(%7d) | appid(%s)",
556         request->GetPid(), app_info->GetAppId().c_str());
557   }
558 }
559
560 void Launchpad::HandleLaunchRequest(std::shared_ptr<Request> request) {
561   Tracer tracer("LAUNCHPAD:LAUNCH");
562   if (LaunchRequestPrepare(request) == LaunchResult::Fail) {
563     request->SendResult(-1);
564     return;
565   }
566
567   if (LaunchRequestDo(request) == LaunchResult::Pending)
568     return;
569
570   LaunchRequestComplete(request);
571   _D("[PAD_CMD_LAUNCH] appid: %s, result: %d",
572       request->GetAppInfo()->GetAppId().c_str(), request->GetPid());
573 }
574
575 void Launchpad::HandleKillLoaderRequest(std::shared_ptr<Request> request) {
576   auto& b = request->GetBundle();
577   auto loader_name = b.GetString(kAulLoaderName);
578   auto loader_context =
579       LoaderManager::GetInst().FindLoaderContextFromName(loader_name);
580   if (loader_context == nullptr) {
581     _E("Failed to find loader context. loader_name(%s)", loader_name.c_str());
582     return;
583   }
584
585   if (loader_context->RefCount() == 0)
586     loader_context->Dispose();
587
588   _D("[PAD_CMD_KILL_LOADER] loader_name: %s", loader_name.c_str());
589 }
590
591 void Launchpad::OnIOEventReceived(int fd, int condition) {
592   auto client_socket = socket_->Accept();
593   if (!client_socket) {
594     _E("Failed to accept the client request");
595     return;
596   }
597
598   try {
599     auto request = std::make_shared<Request>(std::move(client_socket));
600     _W("cmd(%d), caller(%d)", request->GetCmd(), request->GetCallerPid());
601     if (request->GetCallerUid() >= kRegularUidMin) {
602       if (CheckCallerPermission(request->GetCallerPid()) < 0) {
603         _E("Permission denied. pid(%d)", request->GetCallerPid());
604         request->SendResult(-EPERM);
605         return;
606       }
607     }
608
609     auto found = handlers_.find(request->GetCmd());
610     if (found == handlers_.end()) {
611       _E("Unknown command: %d", request->GetCmd());
612       request->SendResult(-EINVAL);
613       return;
614     }
615
616     auto method_handler = found->second;
617     method_handler(std::move(request));
618   } catch (const Exception& e) {
619     _E("Exception occurs. error(%s)", e.what());
620   }
621 }
622
623 void Launchpad::OnSigchldReceived(pid_t pid) {
624   auto found = pid_map_.find(pid);
625   if (found != pid_map_.end()) {
626     auto appid = found->second;
627     cleaner_->Add(std::make_shared<CleanupInfo>(std::move(appid), pid));
628     pid_map_.erase(found);
629   }
630
631   auto iter = pending_requests_.begin();
632   while (iter != pending_requests_.end()) {
633     auto request = *iter;
634     auto context = request->GetAvailableLoaderContext();
635     if (context != nullptr && context->GetPid() == pid) {
636       context->Unref();
637       auto* app_info = request->GetAppInfo();
638       launchpad::DBus::SendAppLaunchSignal(context->GetPid(),
639         app_info->GetAppId().c_str());
640       pending_requests_.erase(iter);
641       break;
642     }
643
644     iter++;
645   }
646
647   launchpad::Log::Print("[SIGCHLD]", "pid(%7d)", pid);
648   LoaderManager::GetInst().HandleSigchld(pid);
649 }
650
651 void Launchpad::OnLoaderPrepared(LoaderContext* loader_context) {
652   _W("Loader is prepared. name(%s), pid(%d)",
653       loader_context->GetLoaderName().c_str(), loader_context->GetPid());
654   if (loader_context->RefCount() == 0)
655     return;
656
657   auto iter = pending_requests_.begin();
658   while (iter != pending_requests_.end()) {
659     auto request = *iter;
660     auto context = request->GetAvailableLoaderContext();
661     if (context != nullptr && context.get() == loader_context) {
662       loader_context->Unref();
663       pending_requests_.erase(iter);
664       LaunchRequestDo(request);
665       LaunchRequestComplete(request);
666       return;
667     }
668
669     iter++;
670   }
671 }
672
673 void Launchpad::OnLoaderLaunched(LoaderContext* loader_context) {
674   _W("Loader is launched. name(%s), pid(%d)",
675       loader_context->GetLoaderName().c_str(), loader_context->GetPid());
676   if (loader_context->RefCount() == 0) {
677     if (mode_ == Config::LaunchMode::Mode::AlwaysLoaderWithLowPriority)
678       SchedPriority::Set(loader_context->GetPid(), 19);
679
680     return;
681   }
682
683   for (auto& request : pending_requests_) {
684     auto context = request->GetAvailableLoaderContext();
685     if (context != nullptr && context.get() == loader_context) {
686       request->SendResult(loader_context->GetPid());
687       return;
688     }
689   }
690 }
691
692 }  // namespace launchpad
693
694 int main(int argc, char** argv) {
695   launchpad::UserTracer tracer(
696       std::string(__FUNCTION__) + "(" + std::to_string(__LINE__) + ")");
697   prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
698   launchpad::Launchpad launchpad(argc, argv);
699   return launchpad.Run();
700 }