--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(app-defined-loader)
+SET(APP_DEFINED_LOADER "app-defined-loader")
+
+INCLUDE(FindPkgConfig)
+PKG_CHECK_MODULES(APP_DEFINED_LOADER_PKGS REQUIRED
+ dlog
+ ecore
+ ecore-core
+ bundle
+ aul
+ gio-2.0
+ dbus-1
+ libsystemd
+ )
+
+FOREACH(flag ${APP_DEFINED_LOADER_PKGS_CFLAGS})
+ SET(EXTRA_CFLAGS_loader "${EXTRA_CFLAGS_loader} ${flag}")
+ENDFOREACH(flag)
+
+SET(EXTRA_CFLAGS_common "${EXTRA_CFLAGS_common} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS_common "${EXTRA_CFLAGS_common} -fvisibility=hidden")
+SET(EXTRA_CFLAGS_common "${EXTRA_CFLAGS_common} -fdata-sections -ffunction-sections -Wl,--gc-sections")
+SET(EXTRA_CFLAGS_common "${EXTRA_CFLAGS_common} -D_FILE_OFFSET_BITS=64")
+SET(EXTRA_CFLAGS_common "${EXTRA_CFLAGS_common} -Werror")
+
+IF(_TIZEN_FEATURE_PRELINK)
+MESSAGE(STATUS "[__PRELINK__] Enable")
+SET(EXTRA_CFLAGS_loader "${EXTRA_CFLAGS_loader} ${EXTRA_CFLAGS_common}")
+ELSE(_TIZEN_FEATURE_PRELINK)
+MESSAGE(STATUS "[__PRELINK__] Disable")
+SET(EXTRA_CFLAGS_loader "${EXTRA_CFLAGS_loader} ${EXTRA_CFLAGS_common} -fPIE")
+ENDIF(_TIZEN_FEATURE_PRELINK)
+
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed")
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_CXX_FLAGS_RELEASE "-O2")
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/common/inc)
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/lib/inc)
+
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src SOURCES)
+AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src/common/src COMMON_SOURCES)
+
+SET(APP_DEFINED_LOADER_SOURCE_FILES
+ ${COMMON_SOURCES}
+ ${SOURCES})
+ADD_EXECUTABLE(${APP_DEFINED_LOADER} ${APP_DEFINED_LOADER_SOURCE_FILES})
+
+# To support 2.x applications which use their own shared libraries.
+# Since we cannot set LD_LIBRARY_PATH directly by security issue, we make the
+# dynamic linker looks in the CWD forcely.
+TARGET_LINK_LIBRARIES(${APP_DEFINED_LOADER} "-ldl -Wl,-rpath,: -Wl,--disable-new-dtags")
+
+IF(_TIZEN_FEATURE_PRELINK)
+TARGET_LINK_LIBRARIES(${APP_DEFINED_LOADER} ${APP_DEFINED_LOADER_PKGS_LDFLAGS} launchpad)
+ELSE(_TIZEN_FEATURE_PRELINK)
+TARGET_LINK_LIBRARIES(${APP_DEFINED_LOADER} ${APP_DEFINED_LOADER_PKGS_LDFLAGS} launchpad "-pie")
+ENDIF(_TIZEN_FEATURE_PRELINK)
+
+SET_TARGET_PROPERTIES(${APP_DEFINED_LOADER} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_loader})
+SET_TARGET_PROPERTIES(${APP_DEFINED_LOADER}
+ PROPERTIES SKIP_BUILD_RPATH TRUE
+ ) # remove rpath option that is automatically generated by cmake.
+INSTALL(TARGETS ${APP_DEFINED_LOADER} DESTINATION bin)
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <linux/limits.h>
+#include <dlfcn.h>
+#include <Ecore.h>
+#include <bundle_internal.h>
+#include <sys/prctl.h>
+
+#include <bundle_cpp.h>
+
+#include <memory>
+#include <vector>
+
+#include "launchpad_common.h"
+#include "launchpad_types.h"
+#include "launchpad.h"
+#include "key.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "APP_DEFINED_LOADER"
+
+#ifndef PR_TASK_PERF_USER_TRACE
+#define PR_TASK_PERF_USER_TRACE 666
+#endif
+
+#ifndef C_EXPORT
+#define C_EXPORT extern "C" __attribute__((visibility("default")))
+#endif
+
+using namespace tizen_base;
+using namespace std;
+namespace launchpad {
+
+class AppDefinedLoader {
+ public:
+ AppDefinedLoader(int argc, char** argv)
+ : argc_(argc), argv_(argv) {
+ lifecycle_cb_ = shared_ptr<loader_lifecycle_callback_s>(new loader_lifecycle_callback_s());
+ lifecycle_cb_->create = OnCreate;
+ lifecycle_cb_->launch = OnLaunch;
+ lifecycle_cb_->terminate = OnTerminate;
+
+ adapter_ = shared_ptr<loader_adapter_s>(new loader_adapter_s());
+ adapter_->loop_begin = OnLoopBegin;
+ adapter_->loop_quit = OnLoopQuit;
+ adapter_->add_fd = OnAddFd;
+ adapter_->remove_fd = OnRemoveFd;
+ }
+
+ ~AppDefinedLoader() {
+ _W("app defined loader destroyed");
+ }
+
+ shared_ptr<loader_lifecycle_callback_s> GetLifeCycle() {
+ return lifecycle_cb_;
+ }
+
+ shared_ptr<loader_adapter_s> GetAdapter() {
+ return adapter_;
+ }
+
+ void SetLoaderPriority(bool enable) {
+ loader_priority_enabled_ = enable;
+ }
+
+ void SetPriorityChanged(bool enable) {
+ priority_change_enabled_ = enable;
+ }
+
+ bool IsLoaderPriorityEnabled() {
+ return loader_priority_enabled_;
+ }
+
+ bool IsPriorityChangeEnabled() {
+ return priority_change_enabled_;
+ }
+
+ void SetFdHandler(Ecore_Fd_Handler* fd_handler) {
+ fd_handler_ = fd_handler;
+ }
+
+ Ecore_Fd_Handler* GetFdHandler() {
+ return fd_handler_;
+ }
+
+ void SetReceiver(loader_receiver_cb receiver) {
+ receiver_cb_ = receiver;
+ }
+
+ loader_receiver_cb GetReceiver() {
+ return receiver_cb_;
+ }
+
+ private:
+ static void PreloadLib(Bundle data) {
+ vector<std::string> so_array = data.GetStringArray("preload");
+ if (so_array.size() == 0)
+ return;
+ for (auto& i : so_array) {
+ if (i.empty())
+ continue;
+ void* handle = dlopen(i.c_str(), RTLD_NOW | RTLD_NODELETE);
+ if (handle == nullptr)
+ _E("fail to load : %s, err : %s", i.c_str(), dlerror());
+ else
+ _D("preload %s# - handle : %p", i.c_str(), handle);
+ }
+ }
+
+ static void OnCreate(bundle *extra, int type, void *user_data) {
+ _I("on create");
+ AppDefinedLoader* loader = (AppDefinedLoader*)user_data;
+ Bundle ex = Bundle(extra, false, false);
+ string loader_type = ex.GetString(KEY_LOADER_TYPE);
+ if (loader_type.empty()) {
+ _E("No loader type");
+ return;
+ }
+
+ if (loader->IsLoaderPriorityEnabled())
+ launchpad_loader_set_priority(19);
+ loader->PreloadLib(ex);
+ ecore_init();
+ setenv("AUL_LOADER_INIT", "1", 1);
+
+ if (loader_type == LOADER_TYPE_SW)
+ setenv("AUL_HWACC", "none", 1);
+ else if (loader_type == LOADER_TYPE_HW)
+ setenv("AUL_HWACC", "hw", 1);
+ }
+
+ static int OnLaunch(int argc, char **argv, const char *app_path,
+ const char *appid, const char *pkgid, const char *pkg_type, void *user_data) {
+ _I("on launch");
+ AppDefinedLoader* loader = (AppDefinedLoader*)user_data;
+ if (!loader->IsPriorityChangeEnabled())
+ return 0;
+
+ bundle *kb = launchpad_loader_get_bundle();
+ if (kb == nullptr)
+ return 0;
+
+ Bundle data(kb, false, false);
+ string high_priority = data.GetString(AUL_K_HIGHPRIORITY);
+ if (high_priority == "true")
+ launchpad_loader_set_priority(-12);
+ data.Delete(AUL_K_HIGHPRIORITY);
+ return 0;
+ }
+
+ void DoExec(string libdir) {
+ _I("do exec");
+ char err_str[MAX_LOCAL_BUFSZ];
+ if (access(argv_[LOADER_ARG_PATH], F_OK | R_OK)) {
+ SECURE_LOGE("access() failed for file: \"%s\", error: %d (%s)", argv_[LOADER_ARG_PATH], errno,
+ strerror_r(errno, err_str, sizeof(err_str)));
+ } else {
+ SECURE_LOGD("[candidate] Exec application (%s)",
+ argv_[LOADER_ARG_PATH]);
+ _close_all_fds();
+ if (!libdir.empty())
+ setenv("LD_LIBRARY_PATH", libdir.c_str(), 1);
+ unsetenv("AUL_LOADER_INIT");
+ unsetenv("AUL_HWACC");
+ if (execv(argv_[LOADER_ARG_PATH], argv_) < 0) {
+ _send_message_to_logger(argv_[LOADER_ARG_PATH],
+ "Failed to execute a file. error(%d:%s)", errno,
+ strerror_r(errno, err_str, sizeof(err_str)));
+ }
+ }
+ }
+
+ int DoDlOpen(bool restore, string old_cwd, string libdir) {
+ _I("do dlopen");
+ string hwc_message = "" + to_string(getpid()) + "|lib loading start";
+ prctl(PR_TASK_PERF_USER_TRACE, hwc_message.c_str(), hwc_message.size());
+ void* handle = dlopen(argv_[LOADER_ARG_PATH],
+ RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE);
+ if (handle == nullptr) {
+ _E("dlopen(%s) is failed. error(%s)", argv_[LOADER_ARG_PATH], dlerror());
+ DoExec(libdir);
+ return -1;
+ }
+
+ hwc_message = "" + to_string(getpid()) + "|lib loading end";
+ prctl(PR_TASK_PERF_USER_TRACE, hwc_message.c_str(), hwc_message.size());
+
+ if (restore && chdir(old_cwd.c_str()))
+ _E("failed to chdir: %d", errno);
+
+ void* dl_main = dlsym(handle, "main");
+ if (dl_main == nullptr) {
+ _E("dlsym not founded(%s). Please export 'main' function", dlerror());
+ dlclose(handle);
+ DoExec(libdir);
+ return -1;
+ }
+
+ _I("call main");
+ return ((int (*)(int, char**))dl_main)(argc_, argv_);
+ }
+
+ static int OnTerminate(int argc, char **argv, void *user_data) {
+ SECURE_LOGD("[candidate] Launch real application (%s)", argv[LOADER_ARG_PATH]);
+ char old_cwd[PATH_MAX] = {0, };
+ AppDefinedLoader* loader = (AppDefinedLoader*)user_data;
+ if (getcwd(old_cwd, sizeof(old_cwd)) == nullptr) {
+ loader->DoDlOpen(false, old_cwd, "");
+ } else {
+ char* libdir = _get_libdir(argv[LOADER_ARG_PATH]);
+ if (libdir == NULL) {
+ return loader->DoDlOpen(false, old_cwd, "");
+ } else {
+ /* To support 2.x applications which use their own shared libraries.
+ * We set '-rpath' to make the dynamic linker looks in the CWD forcely,
+ * so here we change working directory to find shared libraries well.
+ */
+ bool restore = false;
+ if (chdir(libdir))
+ _E("failed to chdir: %d", errno);
+ else
+ restore = true;
+ string libdir_str = string(libdir);
+ free(libdir);
+ return loader->DoDlOpen(restore, old_cwd, libdir_str);
+ }
+ }
+ return -1;
+ }
+
+ static void OnLoopBegin(void* user_data) {
+ _I("on loop begin");
+ ecore_main_loop_begin();
+ }
+
+ static void OnLoopQuit(void* user_data) {
+ _I("on loop quit");
+ ecore_main_loop_quit();
+ }
+
+ static void OnAddFd(void* user_data, int fd,
+ loader_receiver_cb receiver) {
+ AppDefinedLoader* loader = (AppDefinedLoader*)user_data;
+ Ecore_Fd_Handler* handler = ecore_main_fd_handler_add(fd,
+ (Ecore_Fd_Handler_Flags)(ECORE_FD_READ | ECORE_FD_ERROR),
+ FdHandler, loader, nullptr, nullptr);
+ if (handler == nullptr) {
+ _E("fd_handler is NULL");
+ close(fd);
+ exit(-1);
+ }
+ _I("set handler done (%d)", fd);
+ loader->SetFdHandler(handler);
+ loader->SetReceiver(receiver);
+ }
+
+ static Eina_Bool FdHandler(void *user_data, Ecore_Fd_Handler *handler) {
+ _I("fd handler");
+ AppDefinedLoader* loader = (AppDefinedLoader*)user_data;
+ int fd = ecore_main_fd_handler_fd_get(handler);
+ if (fd == -1) {
+ _E("[candidate] ECORE_FD_GET");
+ exit(-1);
+ }
+ if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) {
+ if (loader->GetReceiver())
+ loader->GetReceiver()(fd);
+ } else if (ecore_main_fd_handler_active_get(
+ handler, ECORE_FD_ERROR)) {
+ _E("[candidate] ECORE_FD_ERROR");
+ close(fd);
+ exit(-1);
+ }
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ static void OnRemoveFd(void *user_data, int fd) {
+ _I("remove fd");
+ AppDefinedLoader* loader = (AppDefinedLoader*)user_data;
+ if (loader->GetFdHandler() == nullptr)
+ return;
+ ecore_main_fd_handler_del(loader->GetFdHandler());
+ loader->SetFdHandler(nullptr);
+ loader->SetReceiver(nullptr);
+ }
+
+ private:
+ shared_ptr<loader_lifecycle_callback_s> lifecycle_cb_ = nullptr;
+ shared_ptr<loader_adapter_s> adapter_ = nullptr;
+ bool loader_priority_enabled_ = false;
+ bool priority_change_enabled_ = false;
+ loader_receiver_cb receiver_cb_;
+ Ecore_Fd_Handler* fd_handler_ = nullptr;
+ int argc_;
+ char** argv_;
+};
+
+}
+
+C_EXPORT int main(int argc, char **argv)
+{
+ launchpad::AppDefinedLoader loader(argc, argv);
+
+#ifdef TIZEN_FEATURE_LOADER_PRIORITY
+ loader->SetLoaderPriority(true);
+#endif
+#ifdef TIZEN_FEATURE_PRIORITY_CHANGE
+ loader->SetPriorityChanged(true);
+#endif
+
+ return launchpad_loader_main(argc, argv,
+ loader.GetLifeCycle().get(), loader.GetAdapter().get(), &loader);
+}
\ No newline at end of file