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"
20 #include <bundle_cpp.h>
22 #include <sys/types.h>
27 #include <app_info.hh>
28 #include <client_socket.hh>
29 #include <exception.hh>
31 #include <sched_priority.hh>
36 #include "launchpad/log_private.hh"
37 #include "launchpad/step_prepare_execution.hh"
38 #include "launchpad/thread_control.hh"
39 #include "launchpad-common/sched_priority.hh"
44 const uint32_t kMaxRetryingCount = 600;
45 constexpr const char kLaunchpadLoaderSocketName[] = ".launchpad-type";
47 tizen_base::Bundle loader_bundle;
48 LaunchpadLoader* context = nullptr;
52 LaunchpadLoader::LaunchpadLoader(int argc, char** argv)
53 : argc_(argc), argv_(argv) {
54 if (context != nullptr) {
60 _E("Too few argument");
64 int is_hydra = argv_[LoaderArg::Hydra][0] - '0';
66 _E("Cannot run in hydra mode");
70 loader_type_ = atoi(argv_[LoaderArg::Type]);
71 if (loader_type_ < 0 || loader_type_ >= LoaderType::Max) {
72 _E("Invalid argument. type: %d", loader_type_);
76 loader_id_ = atoi(argv_[LoaderArg::Id]);
77 _W("loader type: %d, loader id: %d", loader_type_, loader_id_);
81 LaunchpadLoader::~LaunchpadLoader() {
82 if (app_argv_ != nullptr) {
83 for (int i = 0; i < app_argc_; ++i)
92 int LaunchpadLoader::Run(loader_lifecycle_callback_s* callback,
93 loader_adapter_s* adapter, void* user_data) {
94 if (callback == nullptr || adapter == nullptr) {
95 _E("Invalid argument");
99 if (adapter->loop_begin == nullptr || adapter->loop_quit == nullptr ||
100 adapter->add_fd == nullptr || adapter->remove_fd == nullptr) {
101 _E("Invalid argument. adapter callback is nullptr");
105 callback_ = *callback;
106 adapter_callback_ = *adapter;
107 user_data_ = user_data;
110 _E("OnCreate() returns false");
114 SchedPriority::Set(0);
115 OnAdapterLoopBegin();
116 return OnTerminate();
119 void LaunchpadLoader::Quit() {
123 const tizen_base::Bundle& LaunchpadLoader::GetBundle() const {
124 return app_info_.GetBundle();
127 void LaunchpadLoader::ResetArgs() {
128 memset(argv_[LoaderArg::Type], 0, strlen(argv_[LoaderArg::Type]));
129 memset(argv_[LoaderArg::Id], 0, strlen(argv_[LoaderArg::Id]));
130 memset(argv_[LoaderArg::Extra], 0, strlen(argv_[LoaderArg::Extra]));
133 void LaunchpadLoader::WaitForThreads(int threads) {
134 uint32_t retrying_count = 0;
139 _W("Thread count = %u", threads);
141 int thread_count = ThreadControl::GetInst().GetCount();
142 if (thread_count >= threads) {
143 _E("Threads(%u) are ready", thread_count);
147 _D("Current thread count = %u", thread_count);
150 } while (retrying_count < kMaxRetryingCount);
151 _E("Maximum retyring count exceeded");
154 int LaunchpadLoader::ConnectToLaunchpad() {
155 std::string endpoint = "/run/aul/daemons/" + std::to_string(getuid()) +
156 "/" + std::string(kLaunchpadLoaderSocketName) +
157 std::to_string(loader_type_) + "-" + std::to_string(loader_id_);
158 ClientSocket client_socket;
159 client_socket.Connect(endpoint);
160 client_socket.SetReceiveBufferSize(Socket::kSocketMaxBufferSize);
161 client_socket.SetReceiveTimeout(5000);
163 pid_t pid = getpid();
164 int ret = client_socket.Send(static_cast<void*>(&pid), sizeof(pid));
166 _E("Send() is failed. error: %d", ret);
170 return client_socket.RemoveFd();
173 bool LaunchpadLoader::OnCreate() {
175 tizen_base::Bundle extra(argv_[LoaderArg::Extra]);
178 if (callback_.create == nullptr) {
179 _E("create callback is nullptr");
184 std::string threads_str = extra.GetString("threads");
185 if (!threads_str.empty() && std::isdigit(threads_str[0])) {
186 _W("threads: %s", threads_str.c_str());
187 threads = std::stoi(threads_str);
190 callback_.create(extra.GetHandle(), loader_type_, user_data_);
191 aul_launch_worker_init();
192 WaitForThreads(threads);
196 int fd = ConnectToLaunchpad();
198 _E("Connection to launchpad was failed. error: %d", fd);
203 } catch (const Exception& e) {
204 _E("Exception occurs. error: %s", e.what());
208 language_config_.reset(new LanguageConfig());
209 region_format_config_.reset(new RegionFormatConfig());
213 void LaunchpadLoader::OnPrelaunch(int argc, char** argv, AppInfo* app_info) {
214 if (callback_.prelaunch) {
215 int ret = callback_.prelaunch(argc, argv, app_info->GetAppPath().c_str(),
216 app_info->GetAppId().c_str(), app_info->GetPkgId().c_str(),
217 app_info->GetPkgType().c_str(), user_data_);
219 _E("prelaunch returns an error: %d", ret);
225 void LaunchpadLoader::DefaultLaunch(AppInfo* app_info) {
226 StepPrepareExecution step_prepare_execution;
227 if (step_prepare_execution.Prepare(app_info) != 0) {
228 _E("Failed to prepare execution");
233 void LaunchpadLoader::ChangeArgs(int argc, char** argv) {
234 auto* env = getenv("TIZEN_LOADER_ARGS");
235 if (env != nullptr) {
236 auto* loader_args = reinterpret_cast<char*>(strtoul(env, nullptr, 10));
237 if (loader_args != nullptr)
238 argv_[0] = loader_args;
241 memset(argv_[0], '\0', strlen(argv_[0]));
242 snprintf(argv_[0], kLoaderArgLength, "%s", argv[0]);
245 int LaunchpadLoader::OnLaunch(int argc, char** argv, AppInfo* app_info) {
246 if (callback_.launch == nullptr)
249 return callback_.launch(argc, argv, app_info->GetAppPath().c_str(),
250 app_info->GetAppId().c_str(), app_info->GetPkgId().c_str(),
251 app_info->GetPkgType().c_str(), user_data_);
254 int LaunchpadLoader::OnTerminate() {
255 _D("Terminating...");
256 region_format_config_.reset();
257 language_config_.reset();
259 if (app_argc_ == 0 || app_argv_ == nullptr)
262 if (callback_.terminate != nullptr)
263 return callback_.terminate(app_argc_, app_argv_, user_data_);
268 void LaunchpadLoader::OnAdapterLoopBegin() {
270 adapter_callback_.loop_begin(user_data_);
273 void LaunchpadLoader::OnAdapterLoopQuit() {
275 adapter_callback_.loop_quit(user_data_);
278 void LaunchpadLoader::OnAdapterAddFd(int fd) {
279 _W("Add fd: %d", fd);
280 adapter_callback_.add_fd(user_data_, fd, ReceiverCb);
283 void LaunchpadLoader::OnAdapterRemovefd(int fd) {
284 _W("Remove fd: %d", fd);
285 adapter_callback_.remove_fd(user_data_, fd);
288 void LaunchpadLoader::HandleReceiverEvent(int fd) {
290 ClientSocket socket(fd);
291 size_t data_size = 0;
292 int ret = socket.Receive(static_cast<void*>(&data_size), sizeof(data_size));
294 _E("Failed to receive the data from socket. error(%d)", ret);
298 std::vector<uint8_t> data(data_size);
299 ret = socket.Receive(data.data(), data.size());
301 _E("Failed to receive the data from socket. error(%d)", ret);
305 tizen_base::Parcel parcel(data.data(), data.size());
306 OnAdapterRemovefd(fd);
308 ProcessLaunchRequest(&parcel);
313 void LaunchpadLoader::ReceiverCb(int fd) {
314 context->HandleReceiverEvent(fd);
317 void LaunchpadLoader::ProcessLaunchRequest(tizen_base::Parcel* parcel) {
318 parcel->ReadParcelable(&app_info_);
319 SECURE_LOGD("App Id: %s, Package Id: %s, Loader Type: %d",
320 app_info_.GetAppId().c_str(), app_info_.GetPkgId().c_str(), loader_type_);
321 if (app_info_.GetAppPath().empty() || app_info_.GetAppPath()[0] != '/') {
322 _E("AppPath is not absolute path");
326 Util::SetEnvironments(&app_info_);
327 auto exported_args = app_info_.GetBundle().Export();
328 exported_args[0] = app_info_.GetAppPath();
329 app_argc_ = exported_args.size();
330 app_argv_ = static_cast<char**>(calloc(app_argc_, sizeof(char*)));
331 if (app_argv_ == nullptr) {
332 _E("calloc() is failed");
336 for (int i = 0; i < app_argc_; ++i) {
337 app_argv_[i] = strdup(exported_args[i].c_str());
338 if (app_argv_[i] == nullptr) {
339 _E("strdup() is failed. [%d] %s", i, exported_args[i].c_str());
343 SECURE_LOGD("Input argument %d : %s##", i, app_argv_[i]);
346 OnPrelaunch(app_argc_, app_argv_, &app_info_);
347 DefaultLaunch(&app_info_);
348 OnLaunch(app_argc_, app_argv_, &app_info_);
349 ChangeArgs(app_argc_, app_argv_);
352 } // namespace launchpad
354 using namespace launchpad;
356 extern "C" EXPORT_API bundle* launchpad_loader_get_bundle(void) {
360 return ::context->GetBundle().GetHandle();
363 extern "C" EXPORT_API int launchpad_loader_main(int argc, char** argv,
364 loader_lifecycle_callback_s* callback, loader_adapter_s* adapter,
368 LaunchpadLoader loader(argc, argv);
369 ret = loader.Run(callback, adapter, user_data);
370 } catch (const Exception& e) {
371 _E("Exception occurs. error: %s", e.what());
372 return e.GetErrorCode();
378 extern "C" EXPORT_API int launchpad_loader_set_priority(int prio) {
379 return SchedPriority::Set(prio);
382 extern "C" EXPORT_API int launchpad_loader_block_threads(void) {
383 return ThreadControl::GetInst().BlockThreads();
386 extern "C" EXPORT_API int launchpad_loader_unblock_threads(void) {
387 return ThreadControl::GetInst().UnblockThreads();