X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=NativeLauncher%2Flauncher%2Fdotnet%2Fdotnet_launcher.cc;h=c13c4068009bb330645cb7fb75922e670f3b88ff;hb=92d8fe2e5a122d3d499fb7186176c5df60a52d10;hp=6adff4b09a01dd0c46a6b18db5e89f6fe2d4411d;hpb=6d179f13ad595875a0843741036930b1bf683760;p=platform%2Fcore%2Fdotnet%2Flauncher.git diff --git a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc index 6adff4b..c13c406 100644 --- a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc +++ b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc @@ -16,88 +16,305 @@ #include +#include #include #include #include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "injection.h" #include "utils.h" #include "log.h" #include "launcher.h" #include "dotnet_launcher.h" - -#define PLUGIN_PATH "/usr/share/dotnet.tizen/lib/libdotnet_plugin.so" +#include "plugin_manager.h" +#include "path_manager.h" +#include "log_manager.h" namespace tizen { namespace runtime { namespace dotnetcore { -CoreRuntime::CoreRuntime() : +#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"}; + +#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 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 __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(__envList[i].c_str())); + } + } else { + _INFO("coreclr_env.list file is not found. skip"); + } +} + +#define _unused(x) ((void)(x)) + +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); + 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); +} + +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"); + } +} + +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; +} + +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(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(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(path), 1); + free(path); + path = NULL; + } +} + +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(); + } +} + +CoreRuntime::CoreRuntime(const char* mode) : initializeClr(nullptr), executeAssembly(nullptr), shutdown(nullptr), createDelegate(nullptr), + setEnvironmentVariable(nullptr), __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), + __isProfileMode(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 + _INFO("Constructor called!!"); - // 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"); - } + char *env = nullptr; + env = getenv("CORECLR_ENABLE_PROFILING"); + if (env != nullptr && !strcmp(env, "1")) { + _INFO("profiling mode on"); + __isProfileMode = true; } - if (pluginInitialize) - pluginInitialize(); + // 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"); + } - _DBG("Constructor called!!"); + 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::preinitialize(bool standalone) { + // 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 + +#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 +329,37 @@ int CoreRuntime::initialize(bool standalone) putenv(const_cast("UNW_ARM_UNWIND_METHOD=6")); #endif // __arm__ - if (__deviceAPIDirectory.empty()) { - _ERR("Empty Device API Directory"); - return 1; - } else { - __deviceAPIDirectory = absolutePath(__deviceAPIDirectory); - } + // Disable debug pipes and semaphores creation in case of non-standlone mode + if (!standalone) + putenv(const_cast("COMPlus_EnableDiagnostics=0")); - if (__runtimeDirectory.empty()) { - _ERR("Empty Runtime Directory"); - return 1; - } else { - __runtimeDirectory = absolutePath(__runtimeDirectory); - } + // Write Debug.WriteLine to stderr + putenv(const_cast("COMPlus_DebugWriteToStdErr=1")); - // set Reference API directory - __refAPIDirectory = __deviceAPIDirectory + "/ref"; +#ifdef USE_DEFAULT_BASE_ADDR + putenv(const_cast("COMPlus_UseDefaultBaseAddr=1")); +#endif // USE_DEFAULT_BASE_ADDR -#ifdef USE_MANAGED_LAUNCHER - if (__launcherAssembly.empty()) { - _ERR("Empty Launcher Assembly"); - return 1; - } else { - __launcherAssembly = absolutePath(__launcherAssembly); - } -#endif + // read string from external file and set them to environment value. + setEnvFromFile(); + + // Set environment for System.Environment.SpecialFolder + initEnvForSpecialFolder(); - std::string libCoreclr(concatPath(__runtimeDirectory, "libcoreclr.so")); + if (initializePathManager(std::string(), std::string(), std::string()) < 0) { + _ERR("Failed to initialize PathManager"); + 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; + if (access(libCoreclr.c_str(), R_OK) == -1) + _ERR("access '%s': %s\n", libCoreclr.c_str(), strerror(errno)); + return -1; } #define CORELIB_RETURN_IF_NOSYM(type, variable, name) \ @@ -154,7 +367,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,18 +378,81 @@ int CoreRuntime::initialize(bool standalone) #undef CORELIB_RETURN_IF_NOSYM - _DBG("libcoreclr dlopen and dlsym success"); - _DBG("this addr : %x", this); - _DBG("coreclr_initialize : %x", initializeClr); + _INFO("libcoreclr dlopen and dlsym success"); + + return 0; +} + +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 - if (!standalone && pluginPreload) + 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; + } + } + + 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; } bool CoreRuntime::initializeCoreClr(const char* appId, const char* assemblyProbePaths, + const char* NIProbePaths, const char* pinvokeProbePaths, const char* tpaList) { @@ -191,7 +467,7 @@ bool CoreRuntime::initializeCoreClr(const char* appId, const char *propertyValues[] = { tpaList, assemblyProbePaths, - assemblyProbePaths, + NIProbePaths, pinvokeProbePaths, "UseLatestBehaviorWhenTFMNotSpecified" }; @@ -211,156 +487,96 @@ bool CoreRuntime::initializeCoreClr(const char* appId, return false; } - _DBG("Initialize core clr success"); + pluginSetCoreclrInfo(__hostHandle, __domainId, createDelegate); + + _INFO("Initialize core clr success"); return true; } -int CoreRuntime::runManagedLauncher(const char* appId, const char* appBase, const char* tpaList) +void CoreRuntime::dispose() { - 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(preparedFunctionDelegate); + // call plugin finalize function to notify finalize to plugin + // dlclose shoud be done after coreclr shutdown to avoid breaking signal chain + pluginFinalize(); - if (preparedFunction != nullptr) - preparedFunction(); + // ignore the signal generated by an exception that occurred during shutdown + checkOnTerminate = true; - 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(launchFunctionDelegate); -#endif - return 0; -} - -void CoreRuntime::dispose() -{ if (__hostHandle != nullptr) { 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 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; } + + registerSigHandler(); } - 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); + pluginSetAppInfo(appId, path); - if (pluginBeforeExecute) - pluginBeforeExecute(); + int fd2 = open(root, O_DIRECTORY); + dup3(fd2, fd, O_CLOEXEC); + if (fd2 >= 0) + close(fd2); -#ifdef USE_MANAGED_LAUNCHER - runManagedLauncher(appId, probePath.c_str(), tpa.c_str()); + // 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); + } - 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