donot create coredump file for unhandled exception
[platform/core/dotnet/launcher.git] / NativeLauncher / launcher / dotnet / dotnet_launcher.cc
index 682d532..18a5c3e 100644 (file)
 
 
 #include <dlfcn.h>
+#include <signal.h>
 
 #include <string>
 #include <fstream>
 #include <vector>
+#include <sstream>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
 
 #include "utils.h"
 #include "log.h"
 #include "launcher.h"
 #include "dotnet_launcher.h"
+#include "plugin_manager.h"
+#include "path_manager.h"
+#include "log_manager.h"
 
 #define PLUGIN_PATH "/usr/share/dotnet.tizen/lib/libdotnet_plugin.so"
+#define ENV_FILE_PATH "/usr/share/dotnet.tizen/lib/coreclr_env.list"
 
 namespace tizen {
 namespace runtime {
 namespace dotnetcore {
 
-CoreRuntime::CoreRuntime() :
+#if defined (__aarch64__)
+#define ARCHITECTURE_IDENTIFIER "arm64"
+const static std::vector<std::string> RID_FALLBACK_GRAPH =
+       {"linux-arm64", "linux", "unix-arm64", "unix", "any", "base"};
+
+#elif defined (__arm__)
+#define ARCHITECTURE_IDENTIFIER "arm"
+const static std::vector<std::string> RID_FALLBACK_GRAPH =
+       {"tizen.4.0.0-armel", "tizen.4.0.0", "tizen-armel", "tizen", "linux-armel", "linux", "unix-armel", "unix", "any", "base"};
+
+#elif defined (__x86_64__)
+#define ARCHITECTURE_IDENTIFIER "x64"
+const static std::vector<std::string> RID_FALLBACK_GRAPH =
+       {"linux-x64", "linux", "unix-x64", "unix", "any", "base"};
+
+#elif defined (__i386__)
+#define ARCHITECTURE_IDENTIFIER "x86"
+const static std::vector<std::string> RID_FALLBACK_GRAPH =
+       {"linux-x86", "linux", "unix-x86", "unix", "any", "base"};
+
+#else
+#error "Unknown target"
+#endif
+
+static std::string getExtraNativeLibDirs(const std::string& appRoot)
+{
+       std::string candidate;
+       for (unsigned int i = 0; i < RID_FALLBACK_GRAPH.size(); i++) {
+               if(!candidate.empty()) {
+                       candidate += ":";
+               }
+               candidate += concatPath(appRoot, "bin/runtimes/" + RID_FALLBACK_GRAPH[i] + "/native");
+       }
+
+       candidate = candidate + ":" + concatPath(appRoot, "lib/" ARCHITECTURE_IDENTIFIER);
+       if (!strncmp(ARCHITECTURE_IDENTIFIER, "arm64", 5)) {
+               candidate = candidate + ":" + concatPath(appRoot, "lib/aarch64");
+       }
+
+       return candidate;
+}
+
+
+static std::vector<std::string> __envList;
+
+static void setEnvFromFile()
+{
+       std::string envList;
+       std::ifstream inFile(ENV_FILE_PATH);
+
+       __envList.clear();
+
+       if (inFile) {
+               _INFO("coreclr_env.list is found");
+               inFile >> envList;
+
+               std::istringstream ss(envList);
+               std::string token;
+
+               while (std::getline(ss, token, ':')) {
+                       if (!token.empty()) {
+                               __envList.push_back(token);
+                       }
+               }
+
+               for (unsigned int i = 0; i < __envList.size(); i++) {
+                       putenv(const_cast<char *>(__envList[i].c_str()));
+               }
+       } else {
+               _INFO("coreclr_env.list file is not found. skip");
+       }
+}
+
+struct sigaction sig_abrt_new;
+struct sigaction sig_abrt_old;
+
+static bool checkOnSigabrt = false;
+static void onSigabrt(int signum)
+{
+    fprintf(stderr, "onSigabrt is called!!!\n");
+
+    if (checkOnSigabrt) {
+        fprintf(stderr, "SIGABRT is already handled. Go to exit\n");
+        exit(0);
+    }
+
+    if (hasException()) {
+        fprintf(stderr, "Unhandled exception is occured. Ignore coredump creation and terminate normally\n");
+        exit(0);
+    } else {
+        fprintf(stderr, "SIGABRT from native. raise(%d)\n", signum);
+        checkOnSigabrt = true;
+               if (sigaction(SIGABRT, &sig_abrt_old, NULL) == 0) {
+                       if (raise(signum) < 0) {
+                               fprintf(stderr, "Fail to raise SIGABRT\n");
+                       }
+               } else {
+                       fprintf(stderr, "Fail to set original SIGABRT handler\n");
+               }
+    }
+}
+
+static void registerSigHandler()
+{
+       sig_abrt_new.sa_handler = onSigabrt;
+       if (sigemptyset(&sig_abrt_new.sa_mask) == 0) {
+               _ERR("Fail to initialize signal set");
+       }
+
+       if (sigaction(SIGABRT, &sig_abrt_new, &sig_abrt_old) < 0) {
+               _ERR("Fail to add sig handler");
+       }
+}
+
+CoreRuntime::CoreRuntime(const char* mode) :
        initializeClr(nullptr),
        executeAssembly(nullptr),
        shutdown(nullptr),
@@ -40,55 +166,24 @@ CoreRuntime::CoreRuntime() :
        __coreclrLib(nullptr),
        __hostHandle(nullptr),
        __domainId(-1),
-       preparedFunction(nullptr),
-       launchFunction(nullptr),
-       __pluginLib(nullptr),
-       pluginInitialize(nullptr),
-       pluginPreload(nullptr),
-       pluginSetAppInfo(nullptr),
-       pluginGetDllPath(nullptr),
-       pluginBeforeExecute(nullptr),
-       pluginFinalize(nullptr)
+       fd(0),
+       __initialized(false)
 {
-#define __XSTR(x) #x
-#define __STR(x) __XSTR(x)
-
-#ifdef DEVICE_API_DIR
-       __deviceAPIDirectory = __STR(DEVICE_API_DIR);
-#endif
-#ifdef RUNTIME_DIR
-       __runtimeDirectory = __STR(RUNTIME_DIR);
-#endif
-#ifdef NATIVE_LIB_DIR
-       __nativeLibDirectory = __STR(NATIVE_LIB_DIR);
-#endif
-
-#ifdef USE_MANAGED_LAUNCHER
-#ifdef CORECLR_LAUNCHER_ASSEMBLY_PATH
-       __launcherAssembly = __STR(CORECLR_LAUNCHER_ASSEMBLY_PATH);
-#endif
-#endif
-
-#undef __STR
-#undef __XSTR
-
-       // support launcher plugin
-       if (!fileNotExist(PLUGIN_PATH)) {
-               __pluginLib = dlopen(PLUGIN_PATH, RTLD_NOW | RTLD_LOCAL);
-               if (__pluginLib) {
-                       pluginInitialize  = (plugin_initialize_ptr)dlsym(__pluginLib, "plugin_initialize");
-                       pluginPreload  = (plugin_preload_ptr)dlsym(__pluginLib, "plugin_preload");
-                       pluginSetAppInfo  = (plugin_set_app_info_ptr)dlsym(__pluginLib, "plugin_set_app_info");
-                       pluginGetDllPath  = (plugin_get_dll_path_ptr)dlsym(__pluginLib, "plugin_get_dll_path");
-                       pluginBeforeExecute  = (plugin_before_execute_ptr)dlsym(__pluginLib, "plugin_before_execute");
-                       pluginFinalize  = (plugin_finalize_ptr)dlsym(__pluginLib, "plugin_finalize");
-               }
+       _INFO("Constructor called!!");
+
+       // plugin initialize should be called before start loader mainloop.
+       // In case of VD plugins, attaching secure zone is done in the plugin_initialize().
+       // When attaching to a secure zone, if there is a created thread, it will failed.
+       // So, plugin initialize should be called before mainloop start.
+       if (initializePluginManager(mode) < 0) {
+               _ERR("Failed to initialize PluginManager");
        }
 
-       if (pluginInitialize)
-               pluginInitialize();
-
-       _DBG("Constructor called!!");
+       if (pluginHasLogControl()) {
+               __enableLogManager = false;
+       } else {
+               __enableLogManager = true;
+       }
 }
 
 CoreRuntime::~CoreRuntime()
@@ -98,6 +193,16 @@ CoreRuntime::~CoreRuntime()
 
 int CoreRuntime::initialize(bool standalone)
 {
+#define __XSTR(x) #x
+#define __STR(x) __XSTR(x)
+
+#ifdef NATIVE_LIB_DIR
+       __nativeLibDirectory = __STR(NATIVE_LIB_DIR);
+#endif
+
+#undef __STR
+#undef __XSTR
+
 #ifdef __arm__
        // libunwind library is used to unwind stack frame, but libunwind for ARM
        // does not support ARM vfpv3/NEON registers in DWARF format correctly.
@@ -112,41 +217,38 @@ int CoreRuntime::initialize(bool standalone)
        putenv(const_cast<char *>("UNW_ARM_UNWIND_METHOD=6"));
 #endif // __arm__
 
-       if (__deviceAPIDirectory.empty()) {
-               _ERR("Empty Device API Directory");
-               return 1;
-       } else {
-               __deviceAPIDirectory = absolutePath(__deviceAPIDirectory);
-       }
+       // read string from external file and set them to environment value.
+       setEnvFromFile();
 
-       if (__runtimeDirectory.empty()) {
-               _ERR("Empty Runtime Directory");
-               return 1;
-       } else {
-               __runtimeDirectory = absolutePath(__runtimeDirectory);
+       if (initializePathManager(std::string(), std::string(), std::string()) < 0) {
+               _ERR("Failed to initialize PathManager");
+               return -1;
        }
 
-       // set Reference API directory
-       __refAPIDirectory = __deviceAPIDirectory + "/ref";
+       if (__enableLogManager) {
+               if (initializeLogManager() < 0) {
+                       _ERR("Failed to initnialize LogManager");
+                       return -1;
+               }
 
-#ifdef USE_MANAGED_LAUNCHER
-       if (__launcherAssembly.empty()) {
-               _ERR("Empty Launcher Assembly");
-               return 1;
-       } else {
-               __launcherAssembly = absolutePath(__launcherAssembly);
-       }
-#endif
+               if (redirectFD() < 0) {
+                       _ERR("Failed to redirect FD");
+                       return -1;
+               }
 
-       std::string libCoreclr(concatPath(__runtimeDirectory, "libcoreclr.so"));
+               if (runLoggingThread() < 0) {
+                       _ERR("Failed to create and run logging thread to redicrect log");
+                       return -1;
+               }
+       }
 
-       _DBG("libcoreclr : %s", libCoreclr.c_str());
+       std::string libCoreclr(concatPath(getRuntimeDir(), "libcoreclr.so"));
 
        __coreclrLib = dlopen(libCoreclr.c_str(), RTLD_NOW | RTLD_LOCAL);
        if (__coreclrLib == nullptr) {
                char *err = dlerror();
                _ERR("dlopen failed to open libcoreclr.so with error %s", err);
-               return 1;
+               return -1;
        }
 
 #define CORELIB_RETURN_IF_NOSYM(type, variable, name) \
@@ -154,7 +256,7 @@ int CoreRuntime::initialize(bool standalone)
                variable = (type)dlsym(__coreclrLib, name); \
                if (variable == nullptr) { \
                        _ERR(name " is not found in the libcoreclr.so"); \
-                       return 1; \
+                       return -1; \
                } \
        } while (0)
 
@@ -165,11 +267,29 @@ int CoreRuntime::initialize(bool standalone)
 
 #undef CORELIB_RETURN_IF_NOSYM
 
-       _DBG("libcoreclr dlopen and dlsym success");
+       _INFO("libcoreclr dlopen and dlsym success");
 
-       if (!standalone && pluginPreload)
+       if (!standalone)
                pluginPreload();
 
+       fd = open("/proc/self", O_DIRECTORY);
+       std::string appRoot = std::string("/proc/self/fd/") + std::to_string(fd);
+       std::string appBin = concatPath(appRoot, "bin");
+       std::string appLib = concatPath(appRoot, "lib");
+       std::string probePath = appBin + ":" + appLib;
+       std::string tpa = getTPA();
+       std::string nativeLibPath = getExtraNativeLibDirs(appRoot) + ":" + appBin + ":" + appLib + ":" + __nativeLibDirectory;
+       std::string appName = std::string("dotnet-launcher-") + std::to_string(getpid());
+
+       if (!initializeCoreClr(appName.c_str(), probePath.c_str(), nativeLibPath.c_str(), tpa.c_str())) {
+               _ERR("Failed to initialize coreclr");
+               return -1;
+       }
+
+       __initialized = true;
+
+       _INFO("CoreRuntime initialize success");
+
        return 0;
 }
 
@@ -209,49 +329,10 @@ bool CoreRuntime::initializeCoreClr(const char* appId,
                return false;
        }
 
-       _DBG("Initialize core clr success");
-       return true;
-}
+       pluginSetCoreclrInfo(__hostHandle, __domainId, createDelegate);
 
-int CoreRuntime::runManagedLauncher(const char* appId, const char* appBase, const char* tpaList)
-{
-       if (fileNotExist(__launcherAssembly)) {
-               _ERR("Launcher assembly is not exist in %s", __launcherAssembly.c_str());
-               return 1;
-       }
-
-       if (!initializeCoreClr(appId, appBase, appBase, tpaList)) {
-               _ERR("Failed to initialize coreclr");
-               return 1;
-       }
-
-#ifdef USE_MANAGED_LAUNCHER
-       void *preparedFunctionDelegate;
-       int st = createDelegate(__hostHandle, __domainId,
-                                                       "Tizen.Runtime",
-                                                       "Tizen.Runtime.Coreclr.AssemblyManager",
-                                                       "Prepared", &preparedFunctionDelegate);
-       if (st < 0) {
-               _ERR("Create delegate for Launch prepared function is fail (0x%08x)", st);
-               return 1;
-       }
-       preparedFunction = reinterpret_cast<PreparedFunctionPtr>(preparedFunctionDelegate);
-
-       if (preparedFunction != nullptr)
-               preparedFunction();
-
-       void *launchFunctionDelegate;
-       st = createDelegate(__hostHandle, __domainId,
-                                               "Tizen.Runtime",
-                                               "Tizen.Runtime.Coreclr.AssemblyManager",
-                                               "Launch", &launchFunctionDelegate);
-       if (st < 0) {
-               _ERR("Create delegate for Launch managed function is fail! (0x%08x)", st);
-               return 1;
-       }
-       launchFunction = reinterpret_cast<LaunchFunctionPtr>(launchFunctionDelegate);
-#endif
-       return 0;
+       _INFO("Initialize core clr success");
+       return true;
 }
 
 void CoreRuntime::dispose()
@@ -260,105 +341,69 @@ void CoreRuntime::dispose()
                int st = shutdown(__hostHandle, __domainId);
                if (st < 0)
                        _ERR("shutdown core clr fail! (0x%08x)", st);
+               __hostHandle = nullptr;
        }
 
-       if (dlclose(__coreclrLib) != 0)
-               _ERR("libcoreclr.so close failed");
-
-       __coreclrLib = nullptr;
+       if (__coreclrLib != nullptr) {
+               if (dlclose(__coreclrLib) != 0) {
+                       _ERR("libcoreclr.so close failed");
+               }
 
-       if (pluginFinalize)
-               pluginFinalize();
+               __coreclrLib = nullptr;
+       }
 
-       if (__pluginLib != nullptr) {
-               if (dlclose(__pluginLib) != 0)
-                       _ERR("libdotnet_plugin.so close failed");
+       finalizePluginManager();
+       finalizePathManager();
 
-               __pluginLib = nullptr;
-               pluginInitialize = nullptr;
-               pluginPreload = nullptr;
-               pluginSetAppInfo = nullptr;
-               pluginGetDllPath = nullptr;
-               pluginBeforeExecute = nullptr;
-               pluginFinalize = nullptr;
-       }
+       __envList.clear();
 
-       _DBG("Dotnet runtime disposed");
+       _INFO("Dotnet runtime disposed");
 }
 
 int CoreRuntime::launch(const char* appId, const char* root, const char* path, int argc, char* argv[])
 {
+       if (!__initialized) {
+               _ERR("Runtime is not initialized");
+               return -1;
+       }
+
        if (path == nullptr) {
                _ERR("executable path is null");
-               return 1;
+               return -1;
        }
 
-       if (fileNotExist(path)) {
+       if (!isFileExist(path)) {
                _ERR("File not exist : %s", path);
-               return 1;
+               return -1;
        }
 
-       if (pluginSetAppInfo)
-               pluginSetAppInfo(appId, path);
-
-       std::string tpa;
-       std::string appRoot = root;
-       std::string appBin = concatPath(appRoot, "bin");
-       std::string appLib = concatPath(appRoot, "lib");
-       std::string probePath = appBin + ":" + appLib + ":" + __nativeLibDirectory;
-
-       std::vector<std::string> searchDirectories;
-       searchDirectories.push_back(appBin);
-       searchDirectories.push_back(appLib);
-       if (pluginGetDllPath) {
-               std::string pluginPath = pluginGetDllPath();
-               if (!pluginPath.empty()) {
-                       probePath = probePath + ":" + pluginPath;
-                       searchDirectories.push_back(pluginPath);
+       if (__enableLogManager) {
+               // launchpad override stdout and stderr to journalctl before launch application.
+               // we have to re-override that to input pipe for logging thread.
+               if (redirectFD() < 0) {
+                       _ERR("Failed to redirect FD");
+                       return -1;
                }
-       }
-       searchDirectories.push_back(__runtimeDirectory);
-       searchDirectories.push_back(__deviceAPIDirectory);
-       searchDirectories.push_back(__refAPIDirectory);
-#ifdef USE_MANAGED_LAUNCHER
-       searchDirectories.push_back(baseName(__launcherAssembly));
-#endif
 
-       assembliesInDirectory(searchDirectories, tpa);
+               registerSigHandler();
+       }
 
-       if (pluginBeforeExecute)
-               pluginBeforeExecute();
+       pluginSetAppInfo(appId, path);
 
-#ifdef USE_MANAGED_LAUNCHER
-       runManagedLauncher(appId, probePath.c_str(), tpa.c_str());
+       int fd2 = open(root, O_DIRECTORY);
+       dup3(fd2, fd, O_CLOEXEC);
+       if (fd2 >= 0)
+               close(fd2);
 
-       bool success = false;
-       if (launchFunction != nullptr) {
-               std::string cppPath(path);
+       pluginBeforeExecute();
 
-               if (isManagedAssembly(cppPath) && !isNativeImage(cppPath)) {
-                       size_t extindex = cppPath.size() - 4;
-                       cppPath = cppPath.substr(0, extindex) + ".ni" + cppPath.substr(extindex, 4);
-                       if (!fileNotExist(cppPath))
-                               path = cppPath.c_str();
-               }
+       _INFO("execute assembly : %s", path);
 
-               success = launchFunction(root, path, argc, argv);
-               if (!success)
-                       _ERR("Failed to launch Application %s", path);
-               return success ? 0 : 1;
-       } else {
-               _ERR("Failed to find launch function");
-               return 1;
-       }
-#else
-       int st = initializeCoreClr(appId, probePath.c_str(), probePath.c_str(), tpa.c_str());
        unsigned int ret = 0;
-       st = executeAssembly(__hostHandle, __domainId, argc, (const char**)argv, path, &ret);
+       int st = executeAssembly(__hostHandle, __domainId, argc, (const char**)argv, path, &ret);
        if (st < 0)
                _ERR("Failed to Execute Assembly %s (0x%08x)", path, st);
        return ret;
-#endif
 }
 
 }  // namespace dotnetcore