Add app_defined_loader 34/225434/13
authorhyunho <hhstark.kang@samsung.com>
Thu, 20 Feb 2020 02:11:36 +0000 (11:11 +0900)
committerhyunho <hhstark.kang@samsung.com>
Mon, 24 Feb 2020 05:39:26 +0000 (14:39 +0900)
Change-Id: I9ec6d2202ec3e6596a19b787a204703771996669
Signed-off-by: hyunho <hhstark.kang@samsung.com>
packaging/app-defined-loader.manifest [new file with mode: 0644]
packaging/launchpad.spec
src/CMakeLists.txt
src/app_defined_loader/CMakeLists.txt [new file with mode: 0644]
src/app_defined_loader/src/app_defined_loader.cc [new file with mode: 0644]
src/common/inc/launchpad_common.h
src/launchpad/src/launchpad.c
src/loader/src/launchpad_loader.c

diff --git a/packaging/app-defined-loader.manifest b/packaging/app-defined-loader.manifest
new file mode 100644 (file)
index 0000000..bd30b8b
--- /dev/null
@@ -0,0 +1,8 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+       <assign>
+               <filesystem path="/usr/bin/app-defined-loader" label="User" exec_label="User" />
+       </assign>
+</manifest>
index db73636..5935833 100644 (file)
@@ -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
index 3a0a104..dbab7f3 100644 (file)
@@ -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 (file)
index 0000000..b0f869e
--- /dev/null
@@ -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 (file)
index 0000000..39ba7d1
--- /dev/null
@@ -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 <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
index dc60559..5d97b77 100644 (file)
@@ -17,7 +17,9 @@
 #ifndef __LAUNCHPAD_COMMON_H__
 #define __LAUNCHPAD_COMMON_H__
 
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
 
 #include <unistd.h>
 #include <ctype.h>
 #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)
 #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__ */
 
index 6d7b43b..f1a7d09 100644 (file)
@@ -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,
index 4dc371e..fee50e6 100644 (file)
 #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);