From 1c9a87dca5fb04388284b35f41106dd7111d9e29 Mon Sep 17 00:00:00 2001 From: hyunho Date: Thu, 20 Feb 2020 11:11:36 +0900 Subject: [PATCH] Add app_defined_loader Change-Id: I9ec6d2202ec3e6596a19b787a204703771996669 Signed-off-by: hyunho --- packaging/app-defined-loader.manifest | 8 + packaging/launchpad.spec | 14 + src/CMakeLists.txt | 2 + src/app_defined_loader/CMakeLists.txt | 69 +++++ src/app_defined_loader/src/app_defined_loader.cc | 330 +++++++++++++++++++++++ src/common/inc/launchpad_common.h | 14 + src/launchpad/src/launchpad.c | 12 +- src/loader/src/launchpad_loader.c | 5 - 8 files changed, 440 insertions(+), 14 deletions(-) create mode 100644 packaging/app-defined-loader.manifest create mode 100644 src/app_defined_loader/CMakeLists.txt create mode 100644 src/app_defined_loader/src/app_defined_loader.cc diff --git a/packaging/app-defined-loader.manifest b/packaging/app-defined-loader.manifest new file mode 100644 index 0000000..bd30b8b --- /dev/null +++ b/packaging/app-defined-loader.manifest @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packaging/launchpad.spec b/packaging/launchpad.spec index db73636..5935833 100644 --- a/packaging/launchpad.spec +++ b/packaging/launchpad.spec @@ -10,6 +10,7 @@ Source102: launchpad-process-pool.socket Source1001: %{name}.manifest Source1002: lib%{name}.manifest Source1003: %{name}-loader.manifest +Source1004: app-defined-loader.manifest BuildRequires: cmake BuildRequires: pkgconfig(bundle) @@ -72,6 +73,13 @@ Group: Application Framework/Application Launcher %description -n launchpad-loader Launchpad-Loader for launching applications +%package -n app-defined-loader +Summary: App-Defined-Loader for launching applications +Group: Application Framework/Application Launcher + +%description -n app-defined-loader +App-Defined-Loader for launching applications + %package -n liblaunchpad Summary: Launchpad library Group: Development/Libraries @@ -92,6 +100,7 @@ Launchpad library (devel) cp %{SOURCE1001} . cp %{SOURCE1002} . cp %{SOURCE1003} . +cp %{SOURCE1004} . %build %if 0%{?sec_build_binary_debug_enable} @@ -160,6 +169,11 @@ ln -sf ../launchpad-process-pool.service %{buildroot}%{_unitdir_user}/basic.targ %{_prefix}/share/aul/default.loader %{_bindir}/launchpad-loader +%files -n app-defined-loader +%manifest app-defined-loader.manifest +%license LICENSE +%{_bindir}/app-defined-loader + %files -n liblaunchpad %manifest liblaunchpad.manifest %license LICENSE diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3a0a104..dbab7f3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,7 +3,9 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) ADD_SUBDIRECTORY(launchpad) ADD_SUBDIRECTORY(lib) ADD_SUBDIRECTORY(loader) +ADD_SUBDIRECTORY(app_defined_loader) ADD_SUBDIRECTORY(hydra) ADD_SUBDIRECTORY(parser) ADD_DEPENDENCIES(launchpad-loader launchpad-lib) +ADD_DEPENDENCIES(app-defined-loader launchpad-lib) diff --git a/src/app_defined_loader/CMakeLists.txt b/src/app_defined_loader/CMakeLists.txt new file mode 100644 index 0000000..b0f869e --- /dev/null +++ b/src/app_defined_loader/CMakeLists.txt @@ -0,0 +1,69 @@ +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 diff --git a/src/app_defined_loader/src/app_defined_loader.cc b/src/app_defined_loader/src/app_defined_loader.cc new file mode 100644 index 0000000..39ba7d1 --- /dev/null +++ b/src/app_defined_loader/src/app_defined_loader.cc @@ -0,0 +1,330 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include + +#include +#include + +#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(new loader_lifecycle_callback_s()); + lifecycle_cb_->create = OnCreate; + lifecycle_cb_->launch = OnLaunch; + lifecycle_cb_->terminate = OnTerminate; + + adapter_ = shared_ptr(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 GetLifeCycle() { + return lifecycle_cb_; + } + + shared_ptr 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 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 lifecycle_cb_ = nullptr; + shared_ptr 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 diff --git a/src/common/inc/launchpad_common.h b/src/common/inc/launchpad_common.h index dc60559..5d97b77 100644 --- a/src/common/inc/launchpad_common.h +++ b/src/common/inc/launchpad_common.h @@ -17,7 +17,9 @@ #ifndef __LAUNCHPAD_COMMON_H__ #define __LAUNCHPAD_COMMON_H__ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif #include #include @@ -57,6 +59,11 @@ #define PAD_LOADER_ID_DIRECT 1 #define PAD_LOADER_ID_DYNAMIC_BASE 10 +#define KEY_LOADER_TYPE "loader_type" +#define LOADER_TYPE_COMMON "common-loader" +#define LOADER_TYPE_HW "hw-loader" +#define LOADER_TYPE_SW "sw-loader" + #define _E(fmt, arg...) LOGE(fmt, ##arg) #define _D(fmt, arg...) LOGD(fmt, ##arg) #define _W(fmt, arg...) LOGW(fmt, ##arg) @@ -72,6 +79,10 @@ #define ARRAY_SIZE(x) ((sizeof(x)) / sizeof(x[0])) #define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER) +#ifdef __cplusplus +extern "C" { +#endif + typedef struct _app_pkt_t { int cmd; int len; @@ -125,5 +136,8 @@ int _verify_proc_caps(void); int _prepare_id_file(void); void _print_hwc_log(const char *format, ...); +#ifdef __cplusplus +} +#endif #endif /* __LAUNCHPAD_COMMON_H__ */ diff --git a/src/launchpad/src/launchpad.c b/src/launchpad/src/launchpad.c index 6d7b43b..f1a7d09 100644 --- a/src/launchpad/src/launchpad.c +++ b/src/launchpad/src/launchpad.c @@ -1600,7 +1600,6 @@ static int __dispatch_cmd_add_loader(bundle *kb) static int __dispatch_cmd_add_app_defined_loader(bundle *kb) { const char *loader_name; - const char *loader_path; int lid, len; candidate_process_context_t *cpc; const loader_info_t *info; @@ -1614,15 +1613,10 @@ static int __dispatch_cmd_add_app_defined_loader(bundle *kb) return -EINVAL; } - /* TODO: use app-defined-loader */ - loader_path = _loader_info_find_loader_path_by_loader_name( - loader_info_list, COMMON_LOADER_NAME); - info = _loader_info_find_loader_by_loader_name( app_defined_loader_info_list, loader_name); - if (loader_path == NULL || info == NULL || info->extra == NULL) { - _E("loader_name %s, loader_path %d, info %d", - loader_name, loader_path != NULL, info != NULL); + if (info == NULL || info->extra == NULL) { + _E("loader_name %s, info %d", loader_name, info != NULL); return -EINVAL; } @@ -1630,7 +1624,7 @@ static int __dispatch_cmd_add_app_defined_loader(bundle *kb) lid = __make_loader_id(); cpc = __add_slot(LAUNCHPAD_LOADER_TYPE_DYNAMIC, lid, 0, - loader_path, (const char *)extra, + "/usr/bin/app-defined-loader", (const char *)extra, METHOD_TIMEOUT | METHOD_VISIBILITY, METHOD_REQUEST | METHOD_AVAILABLE_MEMORY, METHOD_TTL | METHOD_OUT_OF_MEMORY, diff --git a/src/loader/src/launchpad_loader.c b/src/loader/src/launchpad_loader.c index 4dc371e..fee50e6 100644 --- a/src/loader/src/launchpad_loader.c +++ b/src/loader/src/launchpad_loader.c @@ -37,11 +37,6 @@ #define PR_TASK_PERF_USER_TRACE 666 #endif -#define KEY_LOADER_TYPE "loader_type" -#define LOADER_TYPE_COMMON "common-loader" -#define LOADER_TYPE_HW "hw-loader" -#define LOADER_TYPE_SW "sw-loader" - #define PATH_LIB_VC_ELM "/usr/lib/libvc-elm.so.0" extern bundle *launchpad_loader_get_bundle(void); -- 2.7.4