From b73905c1c5c1cc6746c5246433e95433754a8c3f Mon Sep 17 00:00:00 2001 From: Aleksei Vereshchagin Date: Thu, 13 Sep 2018 21:37:25 +0300 Subject: [PATCH 01/16] Implement injection logic with injectLibrary() stub --- NativeLauncher/CMakeLists.txt | 2 +- NativeLauncher/launcher/injection.cc | 68 ++++++++++++++++++++++++++++++++++++ NativeLauncher/launcher/injection.h | 22 ++++++++++++ NativeLauncher/launcher/main.cc | 7 +++- README.md | 8 +++++ 5 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 NativeLauncher/launcher/injection.cc create mode 100644 NativeLauncher/launcher/injection.h diff --git a/NativeLauncher/CMakeLists.txt b/NativeLauncher/CMakeLists.txt index 93cd551..e9ddfc7 100644 --- a/NativeLauncher/CMakeLists.txt +++ b/NativeLauncher/CMakeLists.txt @@ -78,6 +78,7 @@ TARGET_LINK_LIBRARIES(${DOTNET_LAUNCHER_UTIL} ${${PROJECT_NAME}_LDFLAGS}) SET(DOTNET_LAUNCHER "dotnet-launcher") SET(${DOTNET_LAUNCHER}_SOURCE_FILES launcher/main.cc + launcher/injection.cc launcher/launcher.cc launcher/dotnet/dotnet_launcher.cc ) @@ -139,4 +140,3 @@ INSTALL(FILES inc/coreclr_host.h DESTINATION ${INCLUDEDIR}) INSTALL(FILES inc/dotnet_launcher_plugin.h DESTINATION ${INCLUDEDIR}) INSTALL(FILES installer-plugin/ni_common.h DESTINATION ${INCLUDEDIR}) INSTALL(FILES ../dotnet-launcher.pc DESTINATION ${LIBDIR}/pkgconfig) - diff --git a/NativeLauncher/launcher/injection.cc b/NativeLauncher/launcher/injection.cc new file mode 100644 index 0000000..6aeaa61 --- /dev/null +++ b/NativeLauncher/launcher/injection.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016 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 "log.h" + +#include +#include + +static int injectLibrary(const char path[]) +{ + return 0; +} + +int doInjection() +{ + int res = -1; + char *env = nullptr; + char* injectableLibs = nullptr; + const char *delim = ", "; + char *lib = nullptr; + + env = getenv("DOTNET_LAUNCHER_INJECT"); + if (env == nullptr) { + res = 0; + goto ret; + } + + _INFO("##### Perform injection #########"); + + injectableLibs = strdup(env); + if (injectableLibs == nullptr) { + _ERR("Fail to allocate memory for injectable library paths\n"); + goto ret; + } + + res = 0; + lib = strtok(injectableLibs, delim); + for(; lib != nullptr; lib = strtok(nullptr, delim)) { + if (injectLibrary(lib) != 0) { + res = -1; + break; + } + } + + if (res == 0) { + _INFO("##### Injection finished #########"); + } else { + _INFO("##### Injection failed #########"); + } + +ret: + free(injectableLibs); + + return res; +} diff --git a/NativeLauncher/launcher/injection.h b/NativeLauncher/launcher/injection.h new file mode 100644 index 0000000..3a08992 --- /dev/null +++ b/NativeLauncher/launcher/injection.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2016 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. + */ + +#ifndef __INJETION_INTERFACE_H__ +#define __INJETION_INTERFACE_H__ + +int doInjection(); + +#endif // __INJETION_INTERFACE_H__ diff --git a/NativeLauncher/launcher/main.cc b/NativeLauncher/launcher/main.cc index d1e3ce4..c11c423 100644 --- a/NativeLauncher/launcher/main.cc +++ b/NativeLauncher/launcher/main.cc @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "injection.h" #include "dotnet/dotnet_launcher.h" #include "utils.h" #include "log.h" @@ -151,6 +152,10 @@ extern "C" int realMain(int argc, char *argv[], const char* mode) int main(int argc, char *argv[]) { + int res = doInjection(); + if (res != 0) { + return 1; + } + return realMain(argc, argv, "default"); } - diff --git a/README.md b/README.md index e85863e..1ac01f9 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,14 @@ dotnet-launcher [options...] [args...] * --standalone [assembly path] Run assembly with the current user environment. +#### environment + +* DOTNET_LAUNCHER_INJECT + A list of additional libraries to be loaded with `dlopen()` and call to + `int dotnet_launcher_inject()` initialization hook. If hook returns non-zero + status initialization will be failed. The items of the list can be separated + by spaces or colons, and there is no support for escaping either separator. + ---- ### Anatomy -- 2.7.4 From dbccdcdcca24e04282e1d4558dc3b1935b6e6737 Mon Sep 17 00:00:00 2001 From: Alexey Vereschagin Date: Thu, 13 Sep 2018 02:35:27 +0300 Subject: [PATCH 02/16] Implement injectLibrary() function --- NativeLauncher/launcher/injection.cc | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/NativeLauncher/launcher/injection.cc b/NativeLauncher/launcher/injection.cc index 6aeaa61..31134f6 100644 --- a/NativeLauncher/launcher/injection.cc +++ b/NativeLauncher/launcher/injection.cc @@ -19,9 +19,36 @@ #include #include +#include + static int injectLibrary(const char path[]) { - return 0; + typedef int inject_func(); + + int res = -1; + void *lib = nullptr; + inject_func *inject = nullptr; + const char *inject_sym = "dotnet_launcher_inject"; + + _INFO("Inject %s library", path); + + // FIXME: remove RTLD_GLOBAL? + lib = dlopen(path, RTLD_NOW | RTLD_GLOBAL); + if (lib == nullptr) { + _ERR("%s", dlerror()); + goto ret; + } + + inject = reinterpret_cast(dlsym(lib, inject_sym)); + if (inject == nullptr) { + _ERR("%s is not found in the %s", inject_sym, path); + goto ret; + } + + res = inject(); + +ret: + return res; } int doInjection() -- 2.7.4 From f83e650eefade65c1799e54f4cc693cd873e6660 Mon Sep 17 00:00:00 2001 From: Aleksei Vereshchagin Date: Thu, 13 Sep 2018 22:37:54 +0300 Subject: [PATCH 03/16] Use DOTNET_LAUNCHER_INJECT instead of LD_PRELOAD for HEAPTRACK configuration --- NativeLauncher/dotnet.debugger | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NativeLauncher/dotnet.debugger b/NativeLauncher/dotnet.debugger index 30d9f5b..fea3b4a 100644 --- a/NativeLauncher/dotnet.debugger +++ b/NativeLauncher/dotnet.debugger @@ -32,7 +32,7 @@ DEFAULT_OPT /home/owner/share/tmp/sdk_tools/heaptrack/heaptrack_interpret DEFAULT_OPT -o DEFAULT_OPT /home/owner/share/tmp/sdk_tools/profctl/profctl_heaptrack.log DEFAULT_OPT -E -DEFAULT_OPT LD_PRELOAD=/home/owner/share/tmp/sdk_tools/heaptrack/libheaptrack_preload.so +DEFAULT_OPT DOTNET_LAUNCHER_INJECT=/home/owner/share/tmp/sdk_tools/heaptrack/libheaptrack_inject.so DEFAULT_OPT DUMP_HEAPTRACK_OUTPUT=/home/owner/share/tmp/sdk_tools/heaptrack/heaptrack_fifo DEFAULT_OPT CORECLR_PROFILER={C7BAD323-25F0-4C0B-B354-566390B215CA} DEFAULT_OPT CORECLR_PROFILER_PATH=/home/owner/share/tmp/sdk_tools/heaptrack/libprofiler.so -- 2.7.4 From 8d528a44de9255383d74aefc1eb5ca701d7e58be Mon Sep 17 00:00:00 2001 From: Petr Bred Date: Fri, 28 Sep 2018 13:16:34 +0300 Subject: [PATCH 04/16] Refactoring and add detail comments Signed-off-by: Petr Bred --- NativeLauncher/launcher/injection.cc | 2 +- NativeLauncher/launcher/injection.h | 2 +- NativeLauncher/launcher/main.cc | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/NativeLauncher/launcher/injection.cc b/NativeLauncher/launcher/injection.cc index 31134f6..5e18e90 100644 --- a/NativeLauncher/launcher/injection.cc +++ b/NativeLauncher/launcher/injection.cc @@ -51,7 +51,7 @@ ret: return res; } -int doInjection() +int checkInjection() { int res = -1; char *env = nullptr; diff --git a/NativeLauncher/launcher/injection.h b/NativeLauncher/launcher/injection.h index 3a08992..6bcf111 100644 --- a/NativeLauncher/launcher/injection.h +++ b/NativeLauncher/launcher/injection.h @@ -17,6 +17,6 @@ #ifndef __INJETION_INTERFACE_H__ #define __INJETION_INTERFACE_H__ -int doInjection(); +int checkInjection(); #endif // __INJETION_INTERFACE_H__ diff --git a/NativeLauncher/launcher/main.cc b/NativeLauncher/launcher/main.cc index c11c423..78441e3 100644 --- a/NativeLauncher/launcher/main.cc +++ b/NativeLauncher/launcher/main.cc @@ -152,7 +152,11 @@ extern "C" int realMain(int argc, char *argv[], const char* mode) int main(int argc, char *argv[]) { - int res = doInjection(); + /* checkInjection checks dotnet-launcher run mode, + if it contains DOTNET_LAUNCHER_INJECT variable, it injects library. + At the moment, this mechanism is used only when the Memory Profiler is started. + */ + int res = checkInjection(); if (res != 0) { return 1; } -- 2.7.4 From 016766f042b94b8d803d7fbaa5b961343fce6880 Mon Sep 17 00:00:00 2001 From: Igor Kulaychuk Date: Mon, 1 Oct 2018 12:22:46 +0300 Subject: [PATCH 05/16] Injection refactoring: code cleanup Remove gotos, add comments Change-Id: I87d7be179225c3e4ad5a28d167a862b08f1ce0fb Signed-off-by: Igor Kulaychuk --- NativeLauncher/launcher/injection.cc | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/NativeLauncher/launcher/injection.cc b/NativeLauncher/launcher/injection.cc index 5e18e90..3efd3a9 100644 --- a/NativeLauncher/launcher/injection.cc +++ b/NativeLauncher/launcher/injection.cc @@ -32,22 +32,20 @@ static int injectLibrary(const char path[]) _INFO("Inject %s library", path); - // FIXME: remove RTLD_GLOBAL? + // Current implementation of heaptrack CLR profiler requires RTLD_GLOBAL lib = dlopen(path, RTLD_NOW | RTLD_GLOBAL); if (lib == nullptr) { _ERR("%s", dlerror()); - goto ret; + return res; } inject = reinterpret_cast(dlsym(lib, inject_sym)); if (inject == nullptr) { _ERR("%s is not found in the %s", inject_sym, path); - goto ret; + return res; } res = inject(); - -ret: return res; } @@ -58,11 +56,12 @@ int checkInjection() char* injectableLibs = nullptr; const char *delim = ", "; char *lib = nullptr; + char *saveptr = nullptr; env = getenv("DOTNET_LAUNCHER_INJECT"); if (env == nullptr) { res = 0; - goto ret; + return res; } _INFO("##### Perform injection #########"); @@ -70,12 +69,12 @@ int checkInjection() injectableLibs = strdup(env); if (injectableLibs == nullptr) { _ERR("Fail to allocate memory for injectable library paths\n"); - goto ret; + return res; } res = 0; - lib = strtok(injectableLibs, delim); - for(; lib != nullptr; lib = strtok(nullptr, delim)) { + lib = strtok_r(injectableLibs, delim, &saveptr); + for(; lib != nullptr; lib = strtok_r(nullptr, delim, &saveptr)) { if (injectLibrary(lib) != 0) { res = -1; break; @@ -88,8 +87,6 @@ int checkInjection() _INFO("##### Injection failed #########"); } -ret: free(injectableLibs); - return res; } -- 2.7.4 From fe50c5d3f2f72fb9aeb16b706d928278641a03d8 Mon Sep 17 00:00:00 2001 From: Igor Kulaychuk Date: Mon, 1 Oct 2018 14:19:40 +0300 Subject: [PATCH 06/16] Move injection to realMain Change-Id: I33a114b0d1f524b922c4dc0f81bbfaac08168f6c --- NativeLauncher/launcher/main.cc | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/NativeLauncher/launcher/main.cc b/NativeLauncher/launcher/main.cc index 78441e3..3db30b3 100644 --- a/NativeLauncher/launcher/main.cc +++ b/NativeLauncher/launcher/main.cc @@ -35,6 +35,14 @@ static std::string StandaloneOption("--standalone"); extern "C" int realMain(int argc, char *argv[], const char* mode) { + // checkInjection checks dotnet-launcher run mode, + // if it contains DOTNET_LAUNCHER_INJECT variable, it injects library. + // At the moment, this mechanism is used only when the Memory Profiler is started. + int res = checkInjection(); + if (res != 0) { + return 1; + } + int i; bool standaloneMode = false; char* standalonePath = nullptr; @@ -152,14 +160,5 @@ extern "C" int realMain(int argc, char *argv[], const char* mode) int main(int argc, char *argv[]) { - /* checkInjection checks dotnet-launcher run mode, - if it contains DOTNET_LAUNCHER_INJECT variable, it injects library. - At the moment, this mechanism is used only when the Memory Profiler is started. - */ - int res = checkInjection(); - if (res != 0) { - return 1; - } - return realMain(argc, argv, "default"); } -- 2.7.4 From e894220826ea81c7d3911912de45ba6e53ba48e4 Mon Sep 17 00:00:00 2001 From: Woongsuk Cho Date: Tue, 2 Oct 2018 13:38:24 +0900 Subject: [PATCH 07/16] add missing else --- NativeLauncher/installer-plugin/nitool.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NativeLauncher/installer-plugin/nitool.cc b/NativeLauncher/installer-plugin/nitool.cc index 5d7edcc..5c1ea0a 100644 --- a/NativeLauncher/installer-plugin/nitool.cc +++ b/NativeLauncher/installer-plugin/nitool.cc @@ -125,7 +125,7 @@ int main(int argc, char* argv[]) return -1; } } - } if (pkgDllMode) { + } else if (pkgDllMode) { if (createNiDllUnderPkgRoot(args[0], args[1], enableR2R) != 0) { fprintf(stderr, "Failed to get root path from [%s]\n", args[0].c_str()); return -1; -- 2.7.4 From 4b5e1f5102321d72859c2648aea630d32174680b Mon Sep 17 00:00:00 2001 From: Woongsuk Cho Date: Tue, 2 Oct 2018 13:31:37 +0900 Subject: [PATCH 08/16] check size before calling substr() --- NativeLauncher/installer-plugin/ni_common.cc | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/NativeLauncher/installer-plugin/ni_common.cc b/NativeLauncher/installer-plugin/ni_common.cc index f9e81b8..4c5ca44 100644 --- a/NativeLauncher/installer-plugin/ni_common.cc +++ b/NativeLauncher/installer-plugin/ni_common.cc @@ -71,20 +71,19 @@ static void waitInterval() static bool niExist(const std::string& path, std::string& ni) { - static std::string possibleExts[] = { - ".ni.dll", ".NI.dll", ".NI.DLL", ".ni.DLL", - ".ni.exe", ".NI.exe", ".NI.EXE", ".ni.EXE" - }; - std::string fName = path.substr(0, path.size() - 4); - - struct stat sb; - - for (std::string ext : possibleExts) { - std::string f = fName + ext; - if (stat(f.c_str(), &sb) == 0) { - ni = f; - return true; - } + size_t index = path.find_last_of("."); + if (index == std::string::npos) { + return false; + } + std::string fName = path.substr(0, index); + std::string fExt = path.substr(index, path.length()); + + // crossgen generate file with lower case extension only + std::transform(fExt.begin(), fExt.end(), fExt.begin(), ::tolower); + std::string f = fName + ".ni" + fExt; + if (isFileExist(f)) { + ni = f; + return true; } // native image of System.Private.CoreLib.dll should have to overwrite -- 2.7.4 From b80976b7f822c8a502720178d8686aca21532add Mon Sep 17 00:00:00 2001 From: Woongsuk Cho Date: Fri, 5 Oct 2018 08:11:31 +0900 Subject: [PATCH 09/16] assgin return value to unused variable to avoid build warning message --- NativeLauncher/launcher/dotnet/dotnet_launcher.cc | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc index 9757464..c7e28e8 100644 --- a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc +++ b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc @@ -121,36 +121,39 @@ static void setEnvFromFile() } } +#define _unused(x) ((void)(x)) + struct sigaction sig_abrt_new; struct sigaction sig_abrt_old; static bool checkOnSigabrt = false; + static void onSigabrt(int signum) { - // ignore return value of write(). - // this function is called when process go to die - // there is no need to handle return value for logging. - write(2, "onSigabrt called\n", 17); + // use unused variable to avoid build warning + ssize_t ret = write(STDERR_FILENO, "onSigabrt called\n", 17); if (checkOnSigabrt) { - write(2, "onSigabrt called again. go to exit\n", 35); + ret = write(STDERR_FILENO, "onSigabrt called again. go to exit\n", 35); + _unused(ret); exit(0); } if (hasException()) { - write(2, "******************************************************\n", 55); - write(2, "Unhandled exception is occured. check application code\n", 55); - write(2, "******************************************************\n", 55); + ret = write(STDERR_FILENO, "******************************************************\n", 55); + ret = write(STDERR_FILENO, "Unhandled exception is occured. check application code\n", 55); + ret = write(STDERR_FILENO, "******************************************************\n", 55); } checkOnSigabrt = true; if (sigaction(SIGABRT, &sig_abrt_old, NULL) == 0) { if (raise(signum) < 0) { - write(2, "Fail to raise SIGABRT\n", 22); + ret = write(STDERR_FILENO, "Fail to raise SIGABRT\n", 22); } } else { - write(2, "Fail to set original SIGABRT handler\n", 37); + ret = write(STDERR_FILENO, "Fail to set original SIGABRT handler\n", 37); } + _unused(ret); } static void registerSigHandler() -- 2.7.4 From 6ea547542ecf4d2b798b5e3c5e2673a4b96ace23 Mon Sep 17 00:00:00 2001 From: Woongsuk Cho Date: Wed, 7 Nov 2018 19:21:13 +0900 Subject: [PATCH 10/16] Allow ni common initialization for arm architecture only. AOTed dlls which generated under x86 architecture do not work correctly. So, skip ni file generation except arm architecture. NI_COMMON module can be used by other tools (for example vd-nitool) So, add architecture checking code in the initNICommon() function --- NativeLauncher/installer-plugin/ni_common.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NativeLauncher/installer-plugin/ni_common.cc b/NativeLauncher/installer-plugin/ni_common.cc index 4c5ca44..9ca229e 100644 --- a/NativeLauncher/installer-plugin/ni_common.cc +++ b/NativeLauncher/installer-plugin/ni_common.cc @@ -254,6 +254,7 @@ static void createCoreLibNI(bool enableR2R) int initNICommon(NiCommonOption* option) { +#if defined(__arm__) // get interval value const char* intervalFile = "/usr/share/dotnet.tizen/lib/crossgen_interval.txt"; std::ifstream inFile(intervalFile); @@ -274,6 +275,10 @@ int initNICommon(NiCommonOption* option) __tpa = getTPA(); return 0; +#else + fprintf(stderr, "crossgen supports arm architecture only. skip ni file generation\n"); + return -1; +#endif } void finalizeNICommon() -- 2.7.4 From d0f3a07e5fede74cc7b83634ad1c5b0fff36d02d Mon Sep 17 00:00:00 2001 From: Woongsuk Cho Date: Mon, 26 Nov 2018 17:12:57 +0900 Subject: [PATCH 11/16] If the native upcall comes after starting coreclr shutdown steps, SIGABRT is raised by the PalException. To avoid that kind of crash, ignore SIGABRT after starting coreclr shutdown. --- NativeLauncher/launcher/dotnet/dotnet_launcher.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc index c7e28e8..7cd16b9 100644 --- a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc +++ b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc @@ -127,12 +127,19 @@ struct sigaction sig_abrt_new; struct sigaction sig_abrt_old; static bool checkOnSigabrt = false; +static bool checkOnTerminate = false; static void onSigabrt(int signum) { // use unused variable to avoid build warning ssize_t ret = write(STDERR_FILENO, "onSigabrt called\n", 17); + if (checkOnTerminate) { + ret = write(STDERR_FILENO, "onSigabrt called while terminate. go to exit\n", 45); + _unused(ret); + exit(0); + } + if (checkOnSigabrt) { ret = write(STDERR_FILENO, "onSigabrt called again. go to exit\n", 35); _unused(ret); @@ -403,6 +410,12 @@ bool CoreRuntime::initializeCoreClr(const char* appId, void CoreRuntime::dispose() { + // call finalize plugin callback before shutdown coreclr + finalizePluginManager(); + + // ignore the signal generated by an exception that occurred during shutdown + checkOnTerminate = true; + if (__hostHandle != nullptr) { int st = shutdown(__hostHandle, __domainId); if (st < 0) @@ -418,7 +431,6 @@ void CoreRuntime::dispose() __coreclrLib = nullptr; } - finalizePluginManager(); finalizePathManager(); __envList.clear(); -- 2.7.4 From 0727ca64ea80a2ca5588c849c4ed164649173cb3 Mon Sep 17 00:00:00 2001 From: Woongsuk Cho Date: Tue, 4 Dec 2018 15:56:46 +0900 Subject: [PATCH 12/16] Sometimes a process terminates abnormally due to a signal generated during coreclr_shutdown. In order to handle this situation, plugin must get notification before coreclr_shutdown. So, call pluginFinalize before coreclr_shutdown. And unload the plugin library after coreclr_shutdown() to avoid breaking the signal chain. --- NativeLauncher/inc/plugin_manager.h | 1 + NativeLauncher/launcher/dotnet/dotnet_launcher.cc | 6 ++++-- NativeLauncher/util/plugin_manager.cc | 11 ++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/NativeLauncher/inc/plugin_manager.h b/NativeLauncher/inc/plugin_manager.h index f029750..534e0f8 100644 --- a/NativeLauncher/inc/plugin_manager.h +++ b/NativeLauncher/inc/plugin_manager.h @@ -51,6 +51,7 @@ void pluginSetAppInfo(const char* appId, const char* managedAssemblyPath); void pluginSetCoreclrInfo(void* hostHandle, unsigned int domainId, coreclr_create_delegate_ptr delegateFunc); char* pluginGetDllPath(); void pluginBeforeExecute(); +void pluginFinalize(); // initialize / finalize plugin manager int initializePluginManager(const char* mode); diff --git a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc index 7cd16b9..b0f78c5 100644 --- a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc +++ b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc @@ -410,8 +410,9 @@ bool CoreRuntime::initializeCoreClr(const char* appId, void CoreRuntime::dispose() { - // call finalize plugin callback before shutdown coreclr - finalizePluginManager(); + // call plugin finalize function to notify finalize to plugin + // dlclose shoud be done after coreclr shutdown to avoid breaking signal chain + pluginFinalize(); // ignore the signal generated by an exception that occurred during shutdown checkOnTerminate = true; @@ -431,6 +432,7 @@ void CoreRuntime::dispose() __coreclrLib = nullptr; } + finalizePluginManager(); finalizePathManager(); __envList.clear(); diff --git a/NativeLauncher/util/plugin_manager.cc b/NativeLauncher/util/plugin_manager.cc index 227e0a2..44b401d 100644 --- a/NativeLauncher/util/plugin_manager.cc +++ b/NativeLauncher/util/plugin_manager.cc @@ -55,10 +55,8 @@ int initializePluginManager(const char* mode) void finalizePluginManager() { + _INFO("Plugin manager finalize called"); if (__pluginFunc) { - if (__pluginFunc->finalize) { - __pluginFunc->finalize(); - } free(__pluginFunc); __pluginFunc = NULL; } @@ -115,3 +113,10 @@ void pluginBeforeExecute() } } +void pluginFinalize() +{ + if (__pluginFunc && __pluginFunc->finalize) { + __pluginFunc->finalize(); + } +} + -- 2.7.4 From 8fce4a9e6baaf4fef82223b07bd69968ff4d496f Mon Sep 17 00:00:00 2001 From: Woongsuk Cho Date: Tue, 4 Dec 2018 16:17:04 +0900 Subject: [PATCH 13/16] To support headless devices, it is necessary to remove graphics related dependencies. This patch is the first one that uses liblaunchpad instead of launchpad which has a EFL dependency. --- NativeLauncher/CMakeLists.txt | 2 +- packaging/dotnet-launcher.spec | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NativeLauncher/CMakeLists.txt b/NativeLauncher/CMakeLists.txt index e9ddfc7..600f4a6 100644 --- a/NativeLauncher/CMakeLists.txt +++ b/NativeLauncher/CMakeLists.txt @@ -4,7 +4,7 @@ PROJECT("dotnet-tools") MESSAGE("CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(${PROJECT_NAME} REQUIRED aul pkgmgr-info pkgmgr-installer dlog ecore bundle dlog launchpad elementary glib-2.0 libsmack capi-appfw-app-common storage) +PKG_CHECK_MODULES(${PROJECT_NAME} REQUIRED aul pkgmgr-info pkgmgr-installer dlog ecore bundle dlog liblaunchpad elementary glib-2.0 libsmack capi-appfw-app-common storage) FOREACH(flag ${${PROJECT_NAME}_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") diff --git a/packaging/dotnet-launcher.spec b/packaging/dotnet-launcher.spec index d7d100f..bfe292b 100644 --- a/packaging/dotnet-launcher.spec +++ b/packaging/dotnet-launcher.spec @@ -12,7 +12,7 @@ BuildRequires: pkgconfig(aul) BuildRequires: pkgconfig(bundle) BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(ecore) -BuildRequires: pkgconfig(launchpad) +BuildRequires: pkgconfig(liblaunchpad) BuildRequires: pkgconfig(pkgmgr-info) BuildRequires: pkgconfig(pkgmgr-installer) BuildRequires: pkgconfig(elementary) @@ -29,7 +29,7 @@ BuildRequires: compiler-rt %endif Requires: aul -Requires: launchpad +Requires: liblaunchpad Requires(post): /sbin/ldconfig Requires(post): /usr/bin/systemctl -- 2.7.4 From b265543fadea666adc70956e4e676d7032a4f05c Mon Sep 17 00:00:00 2001 From: Woongsuk Cho Date: Fri, 7 Dec 2018 11:07:04 +0900 Subject: [PATCH 14/16] Remove dependency from Elementary To use dotnet-launcher on the headless device (device without a graphical user interface), remove build and runtime dependency from Elementary. Elementary is used in ther launcher.cc file to precreate elm_window for enhancing application startup time. To remove dependency, load elementary library with dlopen. If libelementary.so.1 file doesnot exist, precreation is skipped. --- NativeLauncher/CMakeLists.txt | 4 +-- NativeLauncher/launcher/launcher.cc | 64 ++++++++++++++++++++++++++++--------- packaging/dotnet-launcher.spec | 1 - 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/NativeLauncher/CMakeLists.txt b/NativeLauncher/CMakeLists.txt index 600f4a6..5b98b24 100644 --- a/NativeLauncher/CMakeLists.txt +++ b/NativeLauncher/CMakeLists.txt @@ -4,7 +4,7 @@ PROJECT("dotnet-tools") MESSAGE("CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(${PROJECT_NAME} REQUIRED aul pkgmgr-info pkgmgr-installer dlog ecore bundle dlog liblaunchpad elementary glib-2.0 libsmack capi-appfw-app-common storage) +PKG_CHECK_MODULES(${PROJECT_NAME} REQUIRED aul pkgmgr-info pkgmgr-installer dlog ecore bundle dlog liblaunchpad glib-2.0 libsmack capi-appfw-app-common storage) FOREACH(flag ${${PROJECT_NAME}_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") @@ -73,7 +73,7 @@ SET(${DOTNET_LAUNCHER_UTIL}_SOURCE_FILES ) ADD_LIBRARY(${DOTNET_LAUNCHER_UTIL} SHARED ${${DOTNET_LAUNCHER_UTIL}_SOURCE_FILES}) SET_TARGET_PROPERTIES(${DOTNET_LAUNCHER_UTIL} PROPERTIES COMPILE_FLAGS "-fPIC") -TARGET_LINK_LIBRARIES(${DOTNET_LAUNCHER_UTIL} ${${PROJECT_NAME}_LDFLAGS}) +TARGET_LINK_LIBRARIES(${DOTNET_LAUNCHER_UTIL} ${${PROJECT_NAME}_LDFLAGS} "-ldl") SET(DOTNET_LAUNCHER "dotnet-launcher") SET(${DOTNET_LAUNCHER}_SOURCE_FILES diff --git a/NativeLauncher/launcher/launcher.cc b/NativeLauncher/launcher/launcher.cc index 04eef9b..0bec483 100644 --- a/NativeLauncher/launcher/launcher.cc +++ b/NativeLauncher/launcher/launcher.cc @@ -21,7 +21,6 @@ #include #include -#include #include #include @@ -42,7 +41,6 @@ struct FdHandler { static int __argc; static char **__argv; -static Evas_Object *__win; class LaunchpadAdapterImpl : public LaunchpadAdapter { @@ -120,26 +118,62 @@ static void fdRemove(void *data, int fd) } } +// To run dotnet-launcher on the headless device, remove build dependency from EFL. +#define ELEMENTARY_PATH "/usr/lib/libelementary.so.1" +static void* __win; +typedef int (*elm_init_ptr)(int argc, char **argv); +typedef void (*elm_config_accel_preference_set_ptr)(const char *pref); +typedef void* (*elm_win_add_ptr)(void* parent, const char* name, int type); +typedef void (*elm_win_precreated_object_set_ptr)(void* win); + static void preCreateWindow(bundle *extra, int type, void *userData) { - int elmInitCnt = 0; - - // Precreate window - elmInitCnt = elm_init(__argc, __argv); - if (!elmInitCnt) { - _ERR("[candidate] elm_init() failed"); + struct stat sb; + if (stat(ELEMENTARY_PATH, &sb) != 0) { + _ERR("[candidate] libelememantary is not exist. skip precreation"); return; } - elm_config_accel_preference_set("hw"); + int elmInitCnt = 0; + void* handle = nullptr; + elm_init_ptr elm_init = nullptr; + elm_config_accel_preference_set_ptr elm_config_accel_preference_set = nullptr; + elm_win_add_ptr elm_win_add = nullptr; + elm_win_precreated_object_set_ptr elm_win_precreated_object_set = nullptr; + + handle = dlopen(ELEMENTARY_PATH, RTLD_NOW | RTLD_GLOBAL); + if (handle) { + elm_init = (elm_init_ptr)dlsym(handle, "elm_init"); + if (elm_init) { + elmInitCnt = elm_init(__argc, __argv); + + if (!elmInitCnt) { + _ERR("[candidate] elm_init() failed"); + return; + } + } - __win = elm_win_add(NULL, "package_name", ELM_WIN_BASIC); - if (__win == NULL) { - _ERR("[candidate] elm_win_add() failed"); - return; - } + elm_config_accel_preference_set = (elm_config_accel_preference_set_ptr)dlsym(handle, "elm_config_accel_preference_set"); + if (elm_config_accel_preference_set) { + elm_config_accel_preference_set("hw"); + } - elm_win_precreated_object_set(__win); + elm_win_add = (elm_win_add_ptr)dlsym(handle, "elm_win_add"); + if (elm_win_add) { + // enum value of "ELM_WIN_BASIC" is 0 + __win = elm_win_add(NULL, "package_name", 0); + if (__win == NULL) { + _ERR("[candidate] elm_win_add() failed"); + return; + } + } + + elm_win_precreated_object_set = (elm_win_precreated_object_set_ptr)dlsym(handle, "elm_win_precreated_object_set"); + if (elm_win_precreated_object_set) { + elm_win_precreated_object_set(__win); + } + _INFO("elm window precreation is done"); + } } int LaunchpadAdapterImpl::loaderMain(int argc, char* argv[]) diff --git a/packaging/dotnet-launcher.spec b/packaging/dotnet-launcher.spec index bfe292b..1c4f4a4 100644 --- a/packaging/dotnet-launcher.spec +++ b/packaging/dotnet-launcher.spec @@ -15,7 +15,6 @@ BuildRequires: pkgconfig(ecore) BuildRequires: pkgconfig(liblaunchpad) BuildRequires: pkgconfig(pkgmgr-info) BuildRequires: pkgconfig(pkgmgr-installer) -BuildRequires: pkgconfig(elementary) BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(libsmack) BuildRequires: pkgconfig(capi-appfw-app-common) -- 2.7.4 From 535cbb1080507cee95564358a93d47bc1b828a36 Mon Sep 17 00:00:00 2001 From: Hyungju Lee Date: Wed, 19 Dec 2018 10:08:03 +0900 Subject: [PATCH 15/16] Free localDataPath after done using it Change-Id: I336bb29ed005c5a750176a064ef4e7d837c73046 --- NativeLauncher/launcher/dotnet/dotnet_launcher.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc index b0f78c5..c27f213 100644 --- a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc +++ b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc @@ -487,7 +487,10 @@ int CoreRuntime::launch(const char* appId, const char* root, const char* path, i if (!setEnvironmentVariable(u"XDG_DATA_HOME", envval)) { _ERR("Failed to set XDG_DATA_HOME"); + } + + free(localDataPath); } pluginBeforeExecute(); -- 2.7.4 From fc6c90920d17085aa872f345dd44bf06acf04af2 Mon Sep 17 00:00:00 2001 From: Igor Kulaychuk Date: Thu, 24 Jan 2019 23:21:27 +0300 Subject: [PATCH 16/16] Call injectLibrary() after plugin initialization Change-Id: Ief3c954196f6e41c841943f100b884d67f2a704f --- NativeLauncher/launcher/dotnet/dotnet_launcher.cc | 9 +++++++++ NativeLauncher/launcher/main.cc | 9 --------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc index c27f213..920092c 100644 --- a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc +++ b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc @@ -33,6 +33,7 @@ #include #include +#include "injection.h" #include "utils.h" #include "log.h" #include "launcher.h" @@ -257,6 +258,14 @@ CoreRuntime::~CoreRuntime() int CoreRuntime::initialize(bool standalone) { + // checkInjection checks dotnet-launcher run mode, + // if it contains DOTNET_LAUNCHER_INJECT variable, it injects library. + // At the moment, this mechanism is used only when the Memory Profiler is started. + int res = checkInjection(); + if (res != 0) { + _ERR("Failed to initnialize Memory Profiler"); + return -1; + } #define __XSTR(x) #x #define __STR(x) __XSTR(x) diff --git a/NativeLauncher/launcher/main.cc b/NativeLauncher/launcher/main.cc index 3db30b3..17f69ab 100644 --- a/NativeLauncher/launcher/main.cc +++ b/NativeLauncher/launcher/main.cc @@ -14,7 +14,6 @@ * limitations under the License. */ -#include "injection.h" #include "dotnet/dotnet_launcher.h" #include "utils.h" #include "log.h" @@ -35,14 +34,6 @@ static std::string StandaloneOption("--standalone"); extern "C" int realMain(int argc, char *argv[], const char* mode) { - // checkInjection checks dotnet-launcher run mode, - // if it contains DOTNET_LAUNCHER_INJECT variable, it injects library. - // At the moment, this mechanism is used only when the Memory Profiler is started. - int res = checkInjection(); - if (res != 0) { - return 1; - } - int i; bool standaloneMode = false; char* standalonePath = nullptr; -- 2.7.4