X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=NativeLauncher%2Flauncher%2Fdotnet%2Fdotnet_launcher.cc;h=e6d3bc7374111350602851fd8d78674285ad8eab;hb=d31dd71a0a72bcf3d95bb635d6598d1b874a0752;hp=b0f78c54d693bbae8272697040ce8867dd895d23;hpb=0727ca64ea80a2ca5588c849c4ed164649173cb3;p=platform%2Fcore%2Fdotnet%2Flauncher.git diff --git a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc index b0f78c5..e6d3bc7 100644 --- a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc +++ b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc @@ -23,6 +23,9 @@ #include #include +#include +#include + #include #include #include @@ -31,8 +34,12 @@ #include #include +#include #include +#include + +#include "injection.h" #include "utils.h" #include "log.h" #include "launcher.h" @@ -41,8 +48,11 @@ #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" +#define __XSTR(x) #x +#define __STR(x) __XSTR(x) +static const char* __FRAMEWORK_DIR = __STR(FRAMEWORK_DIR); +#undef __STR +#undef __XSTR namespace tizen { namespace runtime { @@ -50,33 +60,55 @@ namespace dotnetcore { #if defined (__aarch64__) #define ARCHITECTURE_IDENTIFIER "arm64" -const static std::vector RID_FALLBACK_GRAPH = - {"linux-arm64", "linux", "unix-arm64", "unix", "any", "base"}; #elif defined (__arm__) -#define ARCHITECTURE_IDENTIFIER "arm" -const static std::vector 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"}; +#define ARCHITECTURE_IDENTIFIER "armel" #elif defined (__x86_64__) #define ARCHITECTURE_IDENTIFIER "x64" -const static std::vector RID_FALLBACK_GRAPH = - {"linux-x64", "linux", "unix-x64", "unix", "any", "base"}; #elif defined (__i386__) #define ARCHITECTURE_IDENTIFIER "x86" -const static std::vector 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"}; #else #error "Unknown target" #endif +static const char* __TIZEN_RID_VERSION_KEY = "db/dotnet/tizen_rid_version"; + +// The sequence of RID_FALLBACK graphs must be: +// 1. Tizen + Version + Architecture +// 2. Tizen + Version +// 3. OS(tizen, linux, unix) + Architecture +// 4. OS(tizen, linux, unix) +// 5. any, base static std::string getExtraNativeLibDirs(const std::string& appRoot) { + std::vector RID_FALLBACK_GRAPH; + std::vector RID_FALLBACK_TIZEN; + char* tizen_rid = vconf_get_str(__TIZEN_RID_VERSION_KEY); + if (tizen_rid) { + std::vector version; + splitPath(tizen_rid, version); + std::reverse(std::begin(version), std::end(version)); + for (unsigned int i = 0; i < version.size(); i++) { + RID_FALLBACK_TIZEN.push_back(std::string("tizen." + version[i] + "-" + ARCHITECTURE_IDENTIFIER)); + RID_FALLBACK_TIZEN.push_back(std::string("tizen." + version[i])); + } + free(tizen_rid); + } + + std::vector RID_FALLBACK_OS = {"tizen", "linux", "unix"}; + for (unsigned int i = 0; i < RID_FALLBACK_OS.size(); i++) { + RID_FALLBACK_GRAPH.push_back(std::string(RID_FALLBACK_OS[i] + "-" + ARCHITECTURE_IDENTIFIER)); + RID_FALLBACK_GRAPH.push_back(std::string(RID_FALLBACK_OS[i])); + } + RID_FALLBACK_GRAPH.push_back("any"); + RID_FALLBACK_GRAPH.push_back("base"); + std::string candidate; for (unsigned int i = 0; i < RID_FALLBACK_GRAPH.size(); i++) { - if(!candidate.empty()) { + if (!candidate.empty()) { candidate += ":"; } candidate += concatPath(appRoot, "bin/runtimes/" + RID_FALLBACK_GRAPH[i] + "/native"); @@ -85,6 +117,8 @@ static std::string getExtraNativeLibDirs(const std::string& appRoot) candidate = candidate + ":" + concatPath(appRoot, "lib/" ARCHITECTURE_IDENTIFIER); if (!strncmp(ARCHITECTURE_IDENTIFIER, "arm64", 5)) { candidate = candidate + ":" + concatPath(appRoot, "lib/aarch64"); + } else if (!strncmp(ARCHITECTURE_IDENTIFIER, "armel", 5)) { + candidate = candidate + ":" + concatPath(appRoot, "lib/arm"); } return candidate; @@ -102,12 +136,9 @@ static void setEnvFromFile() if (inFile) { _INFO("coreclr_env.list is found"); - inFile >> envList; - std::istringstream ss(envList); std::string token; - - while (std::getline(ss, token, ':')) { + while (std::getline(inFile, token, '\n')) { if (!token.empty()) { __envList.push_back(token); } @@ -146,12 +177,6 @@ static void onSigabrt(int signum) 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) { @@ -220,21 +245,56 @@ static void initEnvForSpecialFolder() } } +void CoreRuntime::preloadTypes() +{ + const static std::string initDllPath = concatPath(__FRAMEWORK_DIR, "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(); + } +} + CoreRuntime::CoreRuntime(const char* mode) : initializeClr(nullptr), executeAssembly(nullptr), shutdown(nullptr), createDelegate(nullptr), setEnvironmentVariable(nullptr), - multiByteToWideChar(nullptr), __coreclrLib(nullptr), __hostHandle(nullptr), __domainId(-1), fd(0), - __initialized(false) + __initialized(false), + __isProfileMode(false) { _INFO("Constructor called!!"); + // Intiailize ecore first (signal handlers, etc.) before runtime init. + ecore_init(); + + char *env = nullptr; + env = getenv("CORECLR_ENABLE_PROFILING"); + if (env != nullptr && !strcmp(env, "1")) { + _INFO("profiling mode on"); + __isProfileMode = true; + } + // 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. @@ -242,21 +302,30 @@ CoreRuntime::CoreRuntime(const char* mode) : if (initializePluginManager(mode) < 0) { _ERR("Failed to initialize PluginManager"); } - - if (pluginHasLogControl()) { - __enableLogManager = false; - } else { - __enableLogManager = true; - } } CoreRuntime::~CoreRuntime() { + // workaround : to prevent crash while process terminate on profiling mode, + // kill process immediately. + // see https://github.com/dotnet/coreclr/issues/26687 + if (__isProfileMode) { + _INFO("shutdown process immediately."); + _exit(0); + } + dispose(); } -int CoreRuntime::initialize(bool standalone) +int CoreRuntime::initialize(bool standalone, bool useDlog) { + // 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) @@ -285,32 +354,26 @@ int CoreRuntime::initialize(bool standalone) if (!standalone) putenv(const_cast("COMPlus_EnableDiagnostics=0")); + // Write Debug.WriteLine to stderr + putenv(const_cast("COMPlus_DebugWriteToStdErr=1")); + +#ifdef USE_DEFAULT_BASE_ADDR + putenv(const_cast("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 (useDlog && !pluginHasLogControl()) { 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")); @@ -319,6 +382,8 @@ int CoreRuntime::initialize(bool standalone) if (__coreclrLib == nullptr) { char *err = dlerror(); _ERR("dlopen failed to open libcoreclr.so with error %s", err); + if (access(libCoreclr.c_str(), R_OK) == -1) + _ERR("access '%s': %s\n", libCoreclr.c_str(), strerror(errno)); return -1; } @@ -335,32 +400,50 @@ int CoreRuntime::initialize(bool standalone) 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"); - CORELIB_RETURN_IF_NOSYM(set_environment_variable_ptr, setEnvironmentVariable, "SetEnvironmentVariableW"); - CORELIB_RETURN_IF_NOSYM(multi_byte_to_wide_char_ptr, multiByteToWideChar, "MultiByteToWideChar"); #undef CORELIB_RETURN_IF_NOSYM _INFO("libcoreclr dlopen and dlsym success"); - if (!standalone) + if (!standalone) { pluginPreload(); + } + + // Set environment for System.Environment.SpecialFolder + // Below function creates dbus connection by callging storage API. + // If dbus connection is created bofere fork(), forked process cannot use dbus. + // To avoid gdbus blocking issue, below function should be called after fork() + initEnvForSpecialFolder(); 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 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 nativeLibPath = getExtraNativeLibDirs(appRoot) + ":" + appBin + ":" + appLib + ":" + __nativeLibDirectory; + 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(), nativeLibPath.c_str(), tpa.c_str())) { + 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; @@ -368,6 +451,7 @@ int CoreRuntime::initialize(bool standalone) bool CoreRuntime::initializeCoreClr(const char* appId, const char* assemblyProbePaths, + const char* NIProbePaths, const char* pinvokeProbePaths, const char* tpaList) { @@ -382,7 +466,7 @@ bool CoreRuntime::initializeCoreClr(const char* appId, const char *propertyValues[] = { tpaList, assemblyProbePaths, - assemblyProbePaths, + NIProbePaths, pinvokeProbePaths, "UseLatestBehaviorWhenTFMNotSpecified" }; @@ -457,14 +541,16 @@ int CoreRuntime::launch(const char* appId, const char* root, const char* path, i 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; - } + // launchpad override stdout and stderr to journalctl before launch application. + // we have to re-override that to input pipe for logging thread. + // if LogManager is not initialized, below redirectFD will return 0; + if (redirectFD() < 0) { + _ERR("Failed to redirect FD"); + return -1; + } + // VD has their own signal handler. + if (!pluginHasLogControl()) { registerSigHandler(); } @@ -479,15 +565,8 @@ int CoreRuntime::launch(const char* appId, const char* root, const char* path, i // 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) { - char16_t envval[PATH_MAX] = {0}; - int copied = multiByteToWideChar(0 /* CP_ACP */, 0, localDataPath, -1, envval, PATH_MAX); - if (copied >= PATH_MAX) { - _ERR("Data Path is bigger than PATH_MAX"); - } - - if (!setEnvironmentVariable(u"XDG_DATA_HOME", envval)) { - _ERR("Failed to set XDG_DATA_HOME"); - } + setEnvironmentVariable("XDG_DATA_HOME", localDataPath); + free(localDataPath); } pluginBeforeExecute();