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/launchpad_loader.hh"
21 #include <bundle_cpp.h>
23 #include <sys/types.h>
28 #include <app_info.hh>
29 #include <client_socket.hh>
30 #include <exception.hh>
32 #include <sched_priority.hh>
37 #include "launchpad/log_private.hh"
38 #include "launchpad/step_prepare_execution.hh"
39 #include "launchpad/thread_control.hh"
40 #include "launchpad-common/sched_priority.hh"
45 const uint32_t kMaxRetryingCount = 600;
46 constexpr const char kLaunchpadLoaderSocketName[] = ".launchpad-type";
47 constexpr const char kLaunchpadProcessPoolSock[] =
48 ".launchpad-process-pool-sock";
50 tizen_base::Bundle loader_bundle;
51 LaunchpadLoader* context = nullptr;
55 LaunchpadLoader::LaunchpadLoader(int argc, char** argv)
56 : argc_(argc), argv_(argv) {
57 if (context != nullptr) {
63 _E("Too few argument");
67 int is_hydra = argv_[LoaderArg::Hydra][0] - '0';
69 _E("Cannot run in hydra mode");
73 loader_type_ = atoi(argv_[LoaderArg::Type]);
74 if (loader_type_ < 0 || loader_type_ >= LoaderType::Max) {
75 _E("Invalid argument. type: %d", loader_type_);
79 loader_id_ = atoi(argv_[LoaderArg::Id]);
80 _W("loader type: %d, loader id: %d", loader_type_, loader_id_);
84 LaunchpadLoader::~LaunchpadLoader() {
85 if (app_argv_ != nullptr) {
86 for (int i = 0; i < app_argc_; ++i)
95 int LaunchpadLoader::Run(loader_lifecycle_callback_s* callback,
96 loader_adapter_s* adapter, void* user_data) {
97 if (callback == nullptr || adapter == nullptr) {
98 _E("Invalid argument");
102 if (adapter->loop_begin == nullptr || adapter->loop_quit == nullptr ||
103 adapter->add_fd == nullptr || adapter->remove_fd == nullptr) {
104 _E("Invalid argument. adapter callback is nullptr");
108 callback_ = *callback;
109 adapter_callback_ = *adapter;
110 user_data_ = user_data;
113 _E("OnCreate() returns false");
117 OnAdapterLoopBegin();
118 return OnTerminate();
121 void LaunchpadLoader::Quit() {
125 const tizen_base::Bundle& LaunchpadLoader::GetBundle() const {
126 return app_info_.GetBundle();
129 void LaunchpadLoader::ResetArgs() {
130 memset(argv_[LoaderArg::Type], 0, strlen(argv_[LoaderArg::Type]));
131 memset(argv_[LoaderArg::Id], 0, strlen(argv_[LoaderArg::Id]));
132 memset(argv_[LoaderArg::Extra], 0, strlen(argv_[LoaderArg::Extra]));
135 void LaunchpadLoader::WaitForThreads(int threads) {
136 uint32_t retrying_count = 0;
141 _W("Thread count = %u", threads);
143 int thread_count = ThreadControl::GetInst().GetCount();
144 if (thread_count >= threads) {
145 _E("Threads(%u) are ready", thread_count);
149 _D("Current thread count = %u", thread_count);
152 } while (retrying_count < kMaxRetryingCount);
153 _E("Maximum retyring count exceeded");
156 int LaunchpadLoader::ConnectToLaunchpad() {
157 std::string endpoint = "/run/aul/daemons/" + std::to_string(getuid()) +
158 "/" + std::string(kLaunchpadLoaderSocketName) +
159 std::to_string(loader_type_) + "-" + std::to_string(loader_id_);
160 ClientSocket client_socket;
161 client_socket.Connect(endpoint);
162 client_socket.SetReceiveBufferSize(Socket::kSocketMaxBufferSize);
163 client_socket.SetReceiveTimeout(5000);
165 pid_t pid = getpid();
166 int ret = client_socket.Send(static_cast<void*>(&pid), sizeof(pid));
168 _E("Send() is failed. error: %d", ret);
172 return client_socket.RemoveFd();
175 bool LaunchpadLoader::OnCreate() {
177 tizen_base::Bundle extra(argv_[LoaderArg::Extra]);
180 if (callback_.create == nullptr) {
181 _E("create callback is nullptr");
186 std::string threads_str = extra.GetString("threads");
187 if (!threads_str.empty() && std::isdigit(threads_str[0])) {
188 _W("threads: %s", threads_str.c_str());
189 threads = std::stoi(threads_str);
192 callback_.create(extra.GetHandle(), loader_type_, user_data_);
193 aul_launch_worker_init();
194 WaitForThreads(threads);
198 int fd = ConnectToLaunchpad();
200 _E("Connection to launchpad was failed. error: %d", fd);
205 } catch (const Exception& e) {
206 _E("Exception occurs. error: %s", e.what());
210 language_config_.reset(new LanguageConfig());
211 region_format_config_.reset(new RegionFormatConfig());
215 void LaunchpadLoader::OnPrelaunch(int argc, char** argv, AppInfo* app_info) {
216 if (callback_.prelaunch) {
217 int ret = callback_.prelaunch(argc, argv, app_info->GetAppPath().c_str(),
218 app_info->GetAppId().c_str(), app_info->GetPkgId().c_str(),
219 app_info->GetPkgType().c_str(), user_data_);
221 _E("prelaunch returns an error: %d", ret);
227 void LaunchpadLoader::DefaultLaunch(AppInfo* app_info) {
228 StepPrepareExecution step_prepare_execution;
229 if (step_prepare_execution.Prepare(app_info) != 0) {
230 _E("Failed to prepare execution");
235 void LaunchpadLoader::ChangeArgs(int argc, char** argv) {
236 auto* env = getenv("TIZEN_LOADER_ARGS");
237 if (env != nullptr) {
238 auto* loader_args = reinterpret_cast<char*>(strtoul(env, nullptr, 10));
239 if (loader_args != nullptr)
240 argv_[0] = loader_args;
243 memset(argv_[0], '\0', strlen(argv_[0]));
244 snprintf(argv_[0], kLoaderArgLength, "%s", argv[0]);
247 int LaunchpadLoader::OnLaunch(int argc, char** argv, AppInfo* app_info) {
248 if (callback_.launch == nullptr)
251 return callback_.launch(argc, argv, app_info->GetAppPath().c_str(),
252 app_info->GetAppId().c_str(), app_info->GetPkgId().c_str(),
253 app_info->GetPkgType().c_str(), user_data_);
256 int LaunchpadLoader::OnTerminate() {
257 _D("Terminating...");
258 region_format_config_.reset();
259 language_config_.reset();
261 if (app_argc_ == 0 || app_argv_ == nullptr)
264 if (callback_.terminate != nullptr)
265 return callback_.terminate(app_argc_, app_argv_, user_data_);
270 void LaunchpadLoader::OnAdapterLoopBegin() {
272 adapter_callback_.loop_begin(user_data_);
275 void LaunchpadLoader::OnAdapterLoopQuit() {
277 adapter_callback_.loop_quit(user_data_);
280 void LaunchpadLoader::OnAdapterAddFd(int fd) {
281 _W("Add fd: %d", fd);
282 adapter_callback_.add_fd(user_data_, fd, ReceiverCb);
285 void LaunchpadLoader::OnAdapterRemovefd(int fd) {
286 _W("Remove fd: %d", fd);
287 adapter_callback_.remove_fd(user_data_, fd);
290 void LaunchpadLoader::HandleReceiverEvent(int fd) {
292 ClientSocket socket(fd);
293 size_t data_size = 0;
294 int ret = socket.Receive(static_cast<void*>(&data_size), sizeof(data_size));
296 _E("Failed to receive the data from socket. error(%d)", ret);
300 std::vector<uint8_t> data(data_size);
301 ret = socket.Receive(data.data(), data.size());
303 _E("Failed to receive the data from socket. error(%d)", ret);
307 tizen_base::Parcel parcel(data.data(), data.size());
308 OnAdapterRemovefd(fd);
310 ProcessLaunchRequest(&parcel);
315 void LaunchpadLoader::ReceiverCb(int fd) {
316 context->HandleReceiverEvent(fd);
319 void LaunchpadLoader::ProcessLaunchRequest(tizen_base::Parcel* parcel) {
320 parcel->ReadParcelable(&app_info_);
321 SECURE_LOGD("App Id: %s, Package Id: %s, Loader Type: %d",
322 app_info_.GetAppId().c_str(), app_info_.GetPkgId().c_str(), loader_type_);
323 if (app_info_.GetAppPath().empty() || app_info_.GetAppPath()[0] != '/') {
324 _E("AppPath is not absolute path");
328 Util::SetEnvironments(&app_info_);
329 auto exported_args = app_info_.GetBundle().Export();
330 exported_args[0] = app_info_.GetAppPath();
331 app_argc_ = exported_args.size();
332 app_argv_ = static_cast<char**>(calloc(app_argc_, sizeof(char*)));
333 if (app_argv_ == nullptr) {
334 _E("calloc() is failed");
338 for (int i = 0; i < app_argc_; ++i) {
339 app_argv_[i] = strdup(exported_args[i].c_str());
340 if (app_argv_[i] == nullptr) {
341 _E("strdup() is failed. [%d] %s", i, exported_args[i].c_str());
345 SECURE_LOGD("Input argument %d : %s##", i, app_argv_[i]);
348 OnPrelaunch(app_argc_, app_argv_, &app_info_);
349 DefaultLaunch(&app_info_);
350 OnLaunch(app_argc_, app_argv_, &app_info_);
351 ChangeArgs(app_argc_, app_argv_);
354 } // namespace launchpad
356 using namespace launchpad;
358 extern "C" EXPORT_API bundle* launchpad_loader_get_bundle(void) {
362 return ::context->GetBundle().GetHandle();
365 extern "C" EXPORT_API int launchpad_loader_main(int argc, char** argv,
366 loader_lifecycle_callback_s* callback, loader_adapter_s* adapter,
370 LaunchpadLoader loader(argc, argv);
371 ret = loader.Run(callback, adapter, user_data);
372 } catch (const Exception& e) {
373 _E("Exception occurs. error: %s", e.what());
374 return e.GetErrorCode();
380 extern "C" EXPORT_API int launchpad_loader_set_priority(int prio) {
381 return SchedPriority::Set(prio);
384 extern "C" EXPORT_API int launchpad_loader_block_threads(void) {
385 return ThreadControl::GetInst().BlockThreads();
388 extern "C" EXPORT_API int launchpad_loader_unblock_threads(void) {
389 return ThreadControl::GetInst().UnblockThreads();
392 extern "C" EXPORT_API int launchpad_loader_dispose(void) {
394 aul_sock_create_launchpad_client(kLaunchpadProcessPoolSock, getuid());
396 _E("Failed to create launchpad client socket. error(%d)", fd);
400 tizen_base::Bundle b;
402 aul_sock_send_bundle_with_fd(fd, static_cast<int>(PadCmd::DisposeLoader),
403 b.GetHandle(), AUL_SOCK_NONE);
404 if (ret != AUL_R_OK) {
405 _E("Failed to send disposal request. error(%d)", ret);
409 _W("Success to send disposal request");