Add setup of COMPlus_UseDefaultBaseAddr environment variable
[platform/core/dotnet/launcher.git] / NativeLauncher / launcher / dotnet / dotnet_launcher.cc
index ef42921..57b6005 100644 (file)
 
 
 #include <dlfcn.h>
+#include <signal.h>
 
 #include <string>
 #include <fstream>
 #include <vector>
+#include <sstream>
 
+#include <locale>
+#include <codecvt>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <linux/limits.h>
+
+#include <storage.h>
+#include <app_common.h>
+
+#include "injection.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"
 
 namespace tizen {
 namespace runtime {
 namespace dotnetcore {
 
-CoreRuntime::CoreRuntime() :
-  InitializeClr(nullptr),
-  ExecuteAssembly(nullptr),
-  Shutdown(nullptr),
-  CreateDelegate(nullptr),
-  coreclrLib(nullptr),
-  hostHandle(nullptr),
-  domainId(-1),
-  PreparedFunction(nullptr),
-  LaunchFunction(nullptr)
-{
-#define __XSTR(x) #x
-#define __STR(x) __XSTR(x)
+#if defined (__aarch64__)
+#define ARCHITECTURE_IDENTIFIER "arm64"
+const static std::vector<std::string> RID_FALLBACK_GRAPH =
+       {"linux-arm64", "linux", "unix-arm64", "unix", "any", "base"};
 
-#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
+#elif defined (__arm__)
+#define ARCHITECTURE_IDENTIFIER "arm"
+const static std::vector<std::string> RID_FALLBACK_GRAPH =
+       {"tizen.5.0.0-armel", "tizen.5.0.0", "tizen.4.0.0-armel", "tizen.4.0.0", "tizen-armel", "tizen", "linux-armel", "linux", "unix-armel", "unix", "any", "base"};
 
-#ifdef USE_MANAGED_LAUNCHER
-#ifdef CORECLR_LAUNCHER_ASSEMBLY_PATH
-  LauncherAssembly = __STR(CORECLR_LAUNCHER_ASSEMBLY_PATH);
-#endif
-#endif
+#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"};
 
-#undef __STR
-#undef __XSTR
+#elif defined (__i386__)
+#define ARCHITECTURE_IDENTIFIER "x86"
+const static std::vector<std::string> RID_FALLBACK_GRAPH =
+       {"tizen.5.0.0-x86", "tizen.5.0.0", "tizen.4.0.0-x86", "tizen.4.0.0", "tizen-x86", "tizen", "linux-x86", "linux", "unix-x86", "unix", "any", "base"};
 
-  _DBG("Constructor called!!");
-}
+#else
+#error "Unknown target"
+#endif
 
-CoreRuntime::~CoreRuntime()
+static std::string getExtraNativeLibDirs(const std::string& appRoot)
 {
-  Dispose();
+       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;
 }
 
-int CoreRuntime::Initialize(bool standalone)
+
+static std::vector<std::string> __envList;
+
+static void setEnvFromFile()
 {
-  if (standalone)
-  {
-    const char *_deviceapi_directory = getenv("DeviceAPIDirectory");
-    const char *_runtime_directory = getenv("RuntimeDirectory");
-    if (_deviceapi_directory != nullptr)
-      DeviceAPIDirectory = _deviceapi_directory;
-    if (_runtime_directory != nullptr)
-      RuntimeDirectory = _runtime_directory;
-
-#ifdef USE_MANAGED_LAUNCHER
-    const char *_launcher_assembly = getenv("LauncherAssembly");
-    if (_launcher_assembly != nullptr)
-      LauncherAssembly = _launcher_assembly;
-#endif
-  }
-
-  if (DeviceAPIDirectory.empty())
-  {
-    _ERR("Empty Device API Directory");
-    return 1;
-  }
-  else
-  {
-    DeviceAPIDirectory = AbsolutePath(DeviceAPIDirectory);
-  }
-
-  if (RuntimeDirectory.empty())
-  {
-    _ERR("Empty Runtime Directory");
-    return 1;
-  }
-  else
-  {
-    RuntimeDirectory = AbsolutePath(RuntimeDirectory);
-  }
-
-#ifdef USE_MANAGED_LAUNCHER
-  if (LauncherAssembly.empty())
-  {
-    _ERR("Empty Launcher Assembly");
-    return 1;
-  }
-  else
-  {
-    LauncherAssembly = AbsolutePath(LauncherAssembly);
-  }
-#endif
+       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");
+       }
+}
 
-  std::string libcoreclr(ConcatPath(RuntimeDirectory, "libcoreclr.so"));
+#define _unused(x) ((void)(x))
 
-  _DBG("libcoreclr : %s", libcoreclr.c_str());
+struct sigaction sig_abrt_new;
+struct sigaction sig_abrt_old;
 
-  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;
-  }
+static bool checkOnSigabrt = false;
+static bool checkOnTerminate = false;
 
-#define CORELIB_RETURN_IF_NOSYM(type, variable, name) \
-  do { variable = (type)dlsym(coreclrLib, name); \
-    if (variable == nullptr) { \
-      _ERR(name " is not found in the libcoreclr.so"); \
-      return 1; \
-    }} while(0)
+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);
+               exit(0);
+       }
+
+       if (hasException()) {
+               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) {
+                       ret = write(STDERR_FILENO, "Fail to raise SIGABRT\n", 22);
+               }
+       } else {
+               ret = write(STDERR_FILENO, "Fail to set original SIGABRT handler\n", 37);
+       }
+       _unused(ret);
+}
 
-  CORELIB_RETURN_IF_NOSYM(coreclr_initialize_ptr, InitializeClr, "coreclr_initialize");
-  CORELIB_RETURN_IF_NOSYM(coreclr_execute_assembly_ptr, ExecuteAssembly, "coreclr_execute_assembly");
-  CORELIB_RETURN_IF_NOSYM(coreclr_shutdown_ptr, Shutdown, "coreclr_shutdown");
-  CORELIB_RETURN_IF_NOSYM(coreclr_create_delegate_ptr, CreateDelegate, "coreclr_create_delegate");
+static void registerSigHandler()
+{
+       sig_abrt_new.sa_handler = onSigabrt;
+       if (sigemptyset(&sig_abrt_new.sa_mask) != 0) {
+               _ERR("Fail to sigemptyset");
+       }
+
+       if (sigaction(SIGABRT, &sig_abrt_new, &sig_abrt_old) < 0) {
+               _ERR("Fail to add sig handler");
+       }
+}
 
-#undef CORELIB_RETURN_IF_NOSYM
+static bool storage_cb(int id, storage_type_e type, storage_state_e state, const char *path, void *user_data)
+{
+       int* tmp = (int*)user_data;
+       if (type == STORAGE_TYPE_INTERNAL)
+       {
+               *tmp = id;
+               return false;
+       }
+
+       return true;
+}
 
-  _DBG("libcoreclr dlopen and dlsym success");
+static void initEnvForSpecialFolder()
+{
+       int storageId;
+       int error;
+       char *path = NULL;
+
+       error = storage_foreach_device_supported(storage_cb, &storageId);
+       if (error != STORAGE_ERROR_NONE) {
+               return;
+       }
+
+       error = storage_get_directory(storageId, STORAGE_DIRECTORY_IMAGES, &path);
+       if (error == STORAGE_ERROR_NONE && path != NULL) {
+               setenv("XDG_PICTURES_DIR", const_cast<char *>(path), 1);
+               free(path);
+               path = NULL;
+       }
+
+       error = storage_get_directory(storageId, STORAGE_DIRECTORY_MUSIC, &path);
+       if (error == STORAGE_ERROR_NONE && path != NULL) {
+               setenv("XDG_MUSIC_DIR", const_cast<char *>(path), 1);
+               free(path);
+               path = NULL;
+       }
+
+       error = storage_get_directory(storageId, STORAGE_DIRECTORY_VIDEOS, &path);
+       if (error == STORAGE_ERROR_NONE && path != NULL) {
+               setenv("XDG_VIDEOS_DIR", const_cast<char *>(path), 1);
+               free(path);
+               path = NULL;
+       }
+}
 
-  _DBG("this addr : %x", this);
-  _DBG("coreclr_initialize : %x", InitializeClr);
+void CoreRuntime::preloadTypes()
+{
+       const static std::string initDllPath = "/usr/share/dotnet.tizen/framework/Tizen.Init.dll";
+       if (!isFileExist(initDllPath)) {
+               _ERR("Failed to locate Tizen.Init.dll");
+               return;
+       }
+
+       typedef void (*InitDelegate)();
+       InitDelegate initDelegate;
+
+       int ret = createDelegate(__hostHandle,
+               __domainId,
+               "Tizen.Init",
+               "Tizen.Init.TypeLoader",
+               "PreloadTypes",
+               (void**)&initDelegate);
+
+       if (ret < 0) {
+               _ERR("Failed to create delegate for PreloadTypes (0x%08x)", ret);
+       } else {
+               initDelegate();
+       }
+}
 
-  return 0;
+CoreRuntime::CoreRuntime(const char* mode) :
+       initializeClr(nullptr),
+       executeAssembly(nullptr),
+       shutdown(nullptr),
+       createDelegate(nullptr),
+       setEnvironmentVariable(nullptr),
+       __coreclrLib(nullptr),
+       __hostHandle(nullptr),
+       __domainId(-1),
+       fd(0),
+       __initialized(false)
+{
+       _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 (pluginHasLogControl()) {
+               __enableLogManager = false;
+       } else {
+               __enableLogManager = true;
+       }
 }
 
-bool CoreRuntime::InitializeCoreClr(const char* app_id,
-                                    const char* assembly_probe_paths,
-                                    const char* pinvoke_probe_paths,
-                                    const char* tpa_list)
+CoreRuntime::~CoreRuntime()
 {
-  const char *propertyKeys[] =
-  {
-    "TRUSTED_PLATFORM_ASSEMBLIES",
-    "APP_PATHS",
-    "APP_NI_PATHS",
-    "NATIVE_DLL_SEARCH_DIRECTORIES",
-    "AppDomainCompatSwitch"
-  };
-
-  const char *propertyValues[] =
-  {
-    tpa_list,
-    assembly_probe_paths,
-    assembly_probe_paths,
-    pinvoke_probe_paths,
-    "UseLatestBehaviorWhenTFMNotSpecified"
-  };
-
-  std::string selfPath = ReadSelfPath();
-
-  int st = InitializeClr(
-      selfPath.c_str(),
-      app_id,
-      sizeof(propertyKeys) / sizeof(propertyKeys[0]),
-      propertyKeys,
-      propertyValues,
-      &hostHandle,
-      &domainId);
-
-  if (st < 0)
-  {
-    _ERR("initialize core clr fail! (0x%08x)", st);
-    return false;
-  }
-
-  _DBG("Initialize core clr success");
-  return true;
+       dispose();
 }
 
-int CoreRuntime::RunManagedLauncher(const char* app_id, const char* app_base, const char* tpa_list)
+int CoreRuntime::initialize(bool standalone)
 {
-  if (FileNotExist(LauncherAssembly))
-  {
-    _ERR("Launcher assembly is not exist in %s", LauncherAssembly.c_str());
-    return 1;
-  }
-
-  if (!InitializeCoreClr(app_id, app_base, app_base, tpa_list))
-  {
-    _ERR("Failed to initialize coreclr");
-    return 1;
-  }
-
-#ifdef USE_MANAGED_LAUNCHER
-  void *preparedFunctionDelegate;
-  int st = CreateDelegate(hostHandle, domainId,
-      "Tizen.Runtime.Coreclr",
-      "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.Coreclr",
-      "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);
+       // checkInjection checks dotnet-launcher run mode
+       // 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)
+
+#ifdef NATIVE_LIB_DIR
+       __nativeLibDirectory = __STR(NATIVE_LIB_DIR);
 #endif
-  return 0;
+
+#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.
+       // Therefore let's disable stack unwinding using DWARF information
+       // See https://github.com/dotnet/coreclr/issues/6698
+       //
+       // libunwind use following methods to unwind stack frame.
+       // UNW_ARM_METHOD_ALL          0xFF
+       // UNW_ARM_METHOD_DWARF        0x01
+       // UNW_ARM_METHOD_FRAME        0x02
+       // UNW_ARM_METHOD_EXIDX        0x04
+       putenv(const_cast<char *>("UNW_ARM_UNWIND_METHOD=6"));
+#endif // __arm__
+
+       // Disable debug pipes and semaphores creation in case of non-standlone mode
+       if (!standalone)
+               putenv(const_cast<char *>("COMPlus_EnableDiagnostics=0"));
+
+       // Write Debug.WriteLine to stderr
+       putenv(const_cast<char *>("COMPlus_DebugWriteToStdErr=1"));
+
+#ifdef USE_DEFAULT_BASE_ADDR
+       putenv(const_cast<char *>("COMPlus_UseDefaultBaseAddr=1"));
+#endif // USE_DEFAULT_BASE_ADDR
+
+       // read string from external file and set them to environment value.
+       setEnvFromFile();
+
+       // Set environment for System.Environment.SpecialFolder
+       initEnvForSpecialFolder();
+
+       if (initializePathManager(std::string(), std::string(), std::string()) < 0) {
+               _ERR("Failed to initialize PathManager");
+               return -1;
+       }
+
+       if (__enableLogManager) {
+               if (initializeLogManager() < 0) {
+                       _ERR("Failed to initnialize LogManager");
+                       return -1;
+               }
+
+               if (redirectFD() < 0) {
+                       _ERR("Failed to redirect FD");
+                       return -1;
+               }
+
+               if (runLoggingThread() < 0) {
+                       _ERR("Failed to create and run logging thread to redicrect log");
+                       return -1;
+               }
+       }
+
+       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;
+       }
+
+#define CORELIB_RETURN_IF_NOSYM(type, variable, name) \
+       do { \
+               variable = (type)dlsym(__coreclrLib, name); \
+               if (variable == nullptr) { \
+                       _ERR(name " is not found in the libcoreclr.so"); \
+                       return -1; \
+               } \
+       } while (0)
+
+       CORELIB_RETURN_IF_NOSYM(coreclr_initialize_ptr, initializeClr, "coreclr_initialize");
+       CORELIB_RETURN_IF_NOSYM(coreclr_execute_assembly_ptr, executeAssembly, "coreclr_execute_assembly");
+       CORELIB_RETURN_IF_NOSYM(coreclr_shutdown_ptr, shutdown, "coreclr_shutdown");
+       CORELIB_RETURN_IF_NOSYM(coreclr_create_delegate_ptr, createDelegate, "coreclr_create_delegate");
+
+#undef CORELIB_RETURN_IF_NOSYM
+
+       _INFO("libcoreclr dlopen and dlsym success");
+
+       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 appTac = concatPath(appBin, TAC_SYMLINK_SUB_DIR);
+       std::string probePath = appBin + ":" + appLib + ":" + appTac;
+       std::string NIprobePath = concatPath(appBin, APP_NI_SUB_DIR) + ":" + concatPath(appLib, APP_NI_SUB_DIR) + ":" + appTac;
+       std::string tpa = getTPA();
+       std::string runtimeDir = getRuntimeDir();
+       std::string nativeLibPath = getExtraNativeLibDirs(appRoot) + ":" + appBin + ":" + appLib + ":" + __nativeLibDirectory + ":" + runtimeDir;
+       std::string appName = std::string("dotnet-launcher-") + std::to_string(getpid());
+
+       if (!initializeCoreClr(appName.c_str(), probePath.c_str(), NIprobePath.c_str(), nativeLibPath.c_str(), tpa.c_str())) {
+               _ERR("Failed to initialize coreclr");
+               return -1;
+       }
+
+       int st = createDelegate(__hostHandle, __domainId, "Dotnet.Launcher", "Dotnet.Launcher.Environment", "SetEnvironmentVariable", (void**)&setEnvironmentVariable);
+       if (st < 0 || setEnvironmentVariable == nullptr) {
+               _ERR("Create delegate for Dotnet.Launcher.dll -> Dotnet.Launcher.Environment -> SetEnvironmentVariable failed (0x%08x)", st);
+               return -1;
+       }
+
+       __initialized = true;
+
+       if (!standalone)
+       {
+               preloadTypes();         // Preload common managed code
+       }
+
+       _INFO("CoreRuntime initialize success");
+
+       return 0;
 }
 
-void CoreRuntime::Dispose()
+bool CoreRuntime::initializeCoreClr(const char* appId,
+                                                                        const char* assemblyProbePaths,
+                                                                        const char* NIProbePaths,
+                                                                        const char* pinvokeProbePaths,
+                                                                        const char* tpaList)
 {
-  if (hostHandle != nullptr)
-  {
-    int st = Shutdown(hostHandle, domainId);
-    if (st < 0)
-    {
-      _ERR("shutdown core clr fail! (0x%08x)", st);
-    }
-  }
-
-  if (dlclose(coreclrLib) != 0)
-  {
-    _ERR("libcoreclr.so close failed");
-  }
-  coreclrLib = nullptr;
-
-  _DBG("Dotnet runtime disposed");
+       const char *propertyKeys[] = {
+               "TRUSTED_PLATFORM_ASSEMBLIES",
+               "APP_PATHS",
+               "APP_NI_PATHS",
+               "NATIVE_DLL_SEARCH_DIRECTORIES",
+               "AppDomainCompatSwitch"
+       };
+
+       const char *propertyValues[] = {
+               tpaList,
+               assemblyProbePaths,
+               NIProbePaths,
+               pinvokeProbePaths,
+               "UseLatestBehaviorWhenTFMNotSpecified"
+       };
+
+       std::string selfPath = readSelfPath();
+
+       int st = initializeClr(selfPath.c_str(),
+                                                       appId,
+                                                       sizeof(propertyKeys) / sizeof(propertyKeys[0]),
+                                                       propertyKeys,
+                                                       propertyValues,
+                                                       &__hostHandle,
+                                                       &__domainId);
+
+       if (st < 0) {
+               _ERR("initialize core clr fail! (0x%08x)", st);
+               return false;
+       }
+
+       pluginSetCoreclrInfo(__hostHandle, __domainId, createDelegate);
+
+       _INFO("Initialize core clr success");
+       return true;
 }
 
-int CoreRuntime::Launch(const char* app_id, const char* root, const char* path, int argc, char* argv[])
+void CoreRuntime::dispose()
 {
-  if (path == nullptr)
-  {
-    _ERR("executable path is null");
-    return 1;
-  }
-
-  if (FileNotExist(path))
-  {
-    _ERR("File not exist : %s", path);
-    return 1;
-  }
-
-  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);
-  searchDirectories.push_back(RuntimeDirectory);
-  searchDirectories.push_back(DeviceAPIDirectory);
-#ifdef USE_MANAGED_LAUNCHER
-  searchDirectories.push_back(LauncherAssembly);
-#endif
+       // call plugin finalize function to notify finalize to plugin
+       // dlclose shoud be done after coreclr shutdown to avoid breaking signal chain
+       pluginFinalize();
 
-  AssembliesInDirectory(searchDirectories, tpa);
-
-#ifdef USE_MANAGED_LAUNCHER
-  RunManagedLauncher(app_id, probePath.c_str(), tpa.c_str());
-
-  bool success = false;
-  if (LaunchFunction != nullptr)
-  {
-    std::string cpppath(path);
-
-    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();
-      }
-    }
-
-    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(app_id, probePath.c_str(), probePath.c_str(), tpa.c_str());
-  unsigned int ret = 0;
-  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
+       // ignore the signal generated by an exception that occurred during shutdown
+       checkOnTerminate = true;
+
+       if (__hostHandle != nullptr) {
+               int st = shutdown(__hostHandle, __domainId);
+               if (st < 0)
+                       _ERR("shutdown core clr fail! (0x%08x)", st);
+               __hostHandle = nullptr;
+       }
+
+       if (__coreclrLib != nullptr) {
+               if (dlclose(__coreclrLib) != 0) {
+                       _ERR("libcoreclr.so close failed");
+               }
+
+               __coreclrLib = nullptr;
+       }
+
+       finalizePluginManager();
+       finalizePathManager();
+
+       __envList.clear();
+
+       _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;
+       }
+
+       if (!isFileExist(path)) {
+               _ERR("File not exist : %s", path);
+               return -1;
+       }
+
+       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;
+               }
+
+               registerSigHandler();
+       }
+
+       pluginSetAppInfo(appId, path);
+
+       int fd2 = open(root, O_DIRECTORY);
+       dup3(fd2, fd, O_CLOEXEC);
+       if (fd2 >= 0)
+               close(fd2);
+
+       // set application data path to coreclr environment.
+       // application data path can be changed by owner. So, we have to set data path just before launching.
+       char* localDataPath = app_get_data_path();
+       if (localDataPath != nullptr) {
+               setEnvironmentVariable("XDG_DATA_HOME", localDataPath);
+               free(localDataPath);
+       }
+
+       pluginBeforeExecute();
+
+       _INFO("execute assembly : %s", path);
+
+       unsigned int ret = 0;
+       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;
 }
 
 }  // namespace dotnetcore