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/launchpad.hh"
19 #include <bundle_internal.h>
22 #include <security-manager.h>
23 #include <sys/prctl.h>
24 #include <systemd/sd-daemon.h>
30 #include <app_info.hh>
31 #include <aul_keys.hh>
32 #include <cpu_boost_controller.hh>
33 #include <exception.hh>
34 #include <executor.hh>
36 #include <sched_priority.hh>
38 #include <user_tracer.hh>
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"
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;
67 class CleanupInfo : public launchpad::Worker::Job {
69 CleanupInfo(std::string appid, pid_t pid)
70 : appid_(std::move(appid)), pid_(pid) {}
73 _W("security_manager_cleanup_app() ++");
74 security_manager_cleanup_app(appid_.c_str(), getuid(), pid_);
75 _W("security_manager_cleanup_app() --");
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)
92 _W("There is no socket stream");
96 int GetLaunchpadFdFromEnvironment() {
97 auto* value = getenv("LAUNCHPAD_LISTEN_FD");
98 if (value == nullptr || !isdigit(value[0])) {
99 _E("Failed to get launchpad fd");
107 ServerSocket* GetLaunchpadSocket() {
108 int fd = GetLaunchpadFdFromSystemd();
110 fd = GetLaunchpadFdFromEnvironment();
113 return new ServerSocket(fd);
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);
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());
134 int CheckCallerPermission(pid_t caller_pid) {
135 std::string attr_current = Procfs::GetAttrCurrent(caller_pid);
136 if (attr_current.empty())
139 if (attr_current.compare("User") == 0 ||
140 attr_current.compare("System") == 0 ||
141 attr_current.compare("System::Privileged") == 0)
147 int GetLoaderIdFromBundle(const tizen_base::Bundle& b) {
148 auto loader_id = b.GetString(kAulLoaderId);
149 if (loader_id.empty())
152 _W("Requested loader id: %s", loader_id.c_str());
153 return std::stoi(loader_id);
158 Launchpad::Launchpad(int argc, char** argv)
161 loop_(g_main_loop_new(nullptr, FALSE)) {
162 LaunchpadArgs::GetInst().Set(argc_, argv_);
164 { PadCmd::Visibility,
165 std::bind(&Launchpad::HandleVisibilityRequest, this,
166 std::placeholders::_1) },
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) },
180 std::bind(&Launchpad::HandleDemandRequest, this,
181 std::placeholders::_1) },
183 std::bind(&Launchpad::HandlePingRequest, this,
184 std::placeholders::_1) },
185 { PadCmd::UpdateAppType,
186 std::bind(&Launchpad::HandleUpdateAppTypeRequest, this,
187 std::placeholders::_1) },
189 std::bind(&Launchpad::HandleConnectRequest, this,
190 std::placeholders::_1) },
192 std::bind(&Launchpad::HandleLaunchRequest, this,
193 std::placeholders::_1) },
194 { PadCmd::KillLoader,
195 std::bind(&Launchpad::HandleKillLoaderRequest, this,
196 std::placeholders::_1) },
199 CPUBoostController::Level level;
200 int ret = CPUBoostController::GetBoostLevel(getpid(), &level);
202 CPUBoostController::Clear(getpid());
205 level == CPUBoostController::Level::None ||
206 level == CPUBoostController::Level::Weak) {
207 CPUBoostController::DoBoost(getpid(), CPUBoostController::Level::Strong,
211 g_timeout_add(1000, [](gpointer data) {
212 CPUBoostController::Clear(getpid());
213 return G_SOURCE_REMOVE;
215 mode_ = Config::GetInst().GetLaunchMode().GetMode();
218 Launchpad::~Launchpad() {
219 if (loop_ != nullptr)
220 g_main_loop_unref(loop_);
223 int Launchpad::Run() {
229 #ifdef TIZEN_FEATURE_PRIORITY_CHANGE
233 std::string(__FUNCTION__) + "(" + std::to_string(__LINE__) +
234 "): g_main_loop_run()");
235 g_main_loop_run(loop_);
240 void Launchpad::Quit() {
241 g_main_loop_quit(loop_);
244 bool Launchpad::OnCreate() {
245 UserTracer user_tracer(
246 std::string(__FUNCTION__) + "(" + std::to_string(__LINE__) + ")");
247 launchpad::SignalManager::GetInst().SetEventListener(this);
250 app_executor_.reset(new AppExecutor());
251 socket_.reset(GetLaunchpadSocket());
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());
260 cleaner_.reset(new Worker("cleaner+"));
263 LoaderManager::GetInst().AddDefaultLoaderContexts();
264 LoaderManager::GetInst().SetEventListener(this);
265 launchpad::Debug::GetInst().Init();
267 Util::SendCmdToAmd(AmdCmd::LaunchpadLaunchSignal);
268 lang_config_.reset(new LanguageConfig());
269 region_format_config_.reset(new RegionFormatConfig());
275 void Launchpad::OnTerminate() {
277 region_format_config_.reset();
278 lang_config_.reset();
281 Util::SendCmdToAmd(AmdCmd::LaunchpadDeadSignal);
282 Debug::GetInst().Dispose();
286 LoaderManager::GetInst().Dispose();
289 SignalManager::GetInst().Dispose();
292 void Launchpad::HandleVisibilityRequest(std::shared_ptr<Request> request) {
293 LoaderManager::GetInst().ActivateLoaderContexts(LoaderMethod::Visibility);
294 request->SendResult(0);
295 _D("[PAD_CMD_VISIBILITY]");
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");
307 request->SendResult(context->GetLoaderId());
308 _D("[PAD_CMD_ADD_LOADER]");
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);
320 LoaderManager::GetInst().RemoveLoaderContext(LoaderType::Dynamic,
321 std::stoi(loader_id_str));
322 request->SendResult(0);
323 _D("[PAD_CMD_REMOVE_LOADER]");
326 void Launchpad::HandleMakeDefaultSlotsRequest(
327 std::shared_ptr<Request> request) {
328 LoaderManager::GetInst().AddDefaultLoaderContexts();
329 _D("[PAD_CMD_MAKE_DEFAULT_SLOTS]");
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);
342 auto context = LoaderManager::GetInst().PrepareAppDefinedLoaderContext(
343 loader_name, request->GetCallerPid());
344 if (context == nullptr) {
345 request->SendResult(-EINVAL);
349 request->SendResult(context->GetLoaderId());
350 _D("[PAD_CMD_PREPARE_APP_DEFINED_LOADER] result: %d", context->GetLoaderId());
353 void Launchpad::HandleDemandRequest(std::shared_ptr<Request> request) {
354 LoaderManager::GetInst().ActivateLoaderContexts(LoaderMethod::Demand);
355 request->SendResult(0);
356 _D("[PAD_CMD_DEMAND]");
359 void Launchpad::HandlePingRequest(std::shared_ptr<Request> request) {
360 request->SendResult(getpid());
361 _D("[PAD_CMD_PING]");
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");
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]");
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());
385 bool Launchpad::CanUseLoaderContext(
386 const std::shared_ptr<LoaderContext>& context) {
387 if (context->IsPrepared())
390 if (mode_ == Config::LaunchMode::Mode::PreviousOperation)
393 if (mode_ == Config::LaunchMode::Mode::DefaultOperation) {
394 if (context->IsHydraMode())
397 return context->GetPid() > 0 && context->RefCount() == 0;
400 // Config::LaunchMode::Mode::AlwaysLoader
401 // Config::LaunchMode::Mode::AlwaysLoaderWithoutCPUChecker
402 // Config::LaunchMode::Mode::AlwaysLoaderWithLowPriority
403 if (context->GetPid() > 0)
406 return context->IsLaunchable();
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;
417 request->SetAppInfo(std::unique_ptr<AppInfo>(app_info));
418 if (app_info->GetAppPath().empty()) {
419 _E("AppPath is empty");
420 return LaunchResult::Fail;
423 PrintAppInfo(app_info);
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));
435 request->SetLoaderId(PadLoaderId::Direct);
437 } else if (comp_type == "widget" && app_info->GetAppType() == "webapp") {
438 request->SetLoaderId(PadLoaderId::Direct);
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));
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));
457 auto context = loader_manager.FindLoaderContext(LoaderType::Dynamic,
458 request->GetLoaderId());
459 if (context != nullptr && CanUseLoaderContext(context))
460 request->SetAvailableLoaderContext(std::move(context));
464 return LaunchResult::Success;
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();
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());
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;
489 return LaunchResult::Success;
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);
499 return LaunchResult::Continue;
502 _W("Loader context is not prepared");
503 loader_context->Ref();
504 if (loader_context->GetPid() <= 0)
505 loader_context->Prepare();
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());
514 pending_requests_.push_back(std::move(request));
515 return LaunchResult::Pending;
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);
528 if (LaunchRequestPend(request) == LaunchResult::Pending)
529 return LaunchResult::Pending;
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));
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();
543 return LaunchResult::Success;
546 void Launchpad::LaunchRequestComplete(std::shared_ptr<Request> request) {
547 MemoryMonitor::GetInst().Reset();
548 request->SendResult(request->GetPid());
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());
560 void Launchpad::HandleLaunchRequest(std::shared_ptr<Request> request) {
561 Tracer tracer("LAUNCHPAD:LAUNCH");
562 if (LaunchRequestPrepare(request) == LaunchResult::Fail) {
563 request->SendResult(-1);
567 if (LaunchRequestDo(request) == LaunchResult::Pending)
570 LaunchRequestComplete(request);
571 _D("[PAD_CMD_LAUNCH] appid: %s, result: %d",
572 request->GetAppInfo()->GetAppId().c_str(), request->GetPid());
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());
585 if (loader_context->RefCount() == 0)
586 loader_context->Dispose();
588 _D("[PAD_CMD_KILL_LOADER] loader_name: %s", loader_name.c_str());
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");
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);
609 auto found = handlers_.find(request->GetCmd());
610 if (found == handlers_.end()) {
611 _E("Unknown command: %d", request->GetCmd());
612 request->SendResult(-EINVAL);
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());
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);
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) {
637 auto* app_info = request->GetAppInfo();
638 launchpad::DBus::SendAppLaunchSignal(context->GetPid(),
639 app_info->GetAppId().c_str());
640 pending_requests_.erase(iter);
647 launchpad::Log::Print("[SIGCHLD]", "pid(%7d)", pid);
648 LoaderManager::GetInst().HandleSigchld(pid);
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)
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);
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);
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());
692 } // namespace launchpad
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();