SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
ENDFOREACH(flag)
-SET(target_hydra dotnet_hydra_launcher)
+SET(target_hydra dotnet_hydra_loader)
PKG_CHECK_MODULES(${target_hydra} REQUIRED liblaunchpad-hydra)
SET_TARGET_PROPERTIES(${DOTNET_LAUNCHER_UTIL} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_LIB})
TARGET_LINK_LIBRARIES(${DOTNET_LAUNCHER_UTIL} ${${PROJECT_NAME}_LDFLAGS} "-ldl" boost_filesystem boost_system)
+SET(DOTNET_LAUNCHER_CORE "dotnet_launcher_core")
+SET(${DOTNET_LAUNCHER_CORE}_SOURCE_FILES
+ launcher/lib/injection.cc
+ launcher/lib/dotnet_launcher.cc
+)
+ADD_LIBRARY(${DOTNET_LAUNCHER_CORE} SHARED ${${DOTNET_LAUNCHER_CORE}_SOURCE_FILES})
+SET_TARGET_PROPERTIES(${DOTNET_LAUNCHER_CORE} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_LIB})
+TARGET_LINK_LIBRARIES(${DOTNET_LAUNCHER_CORE} ${${PROJECT_NAME}_LDFLAGS} "-ldl" boost_filesystem boost_system ${DOTNET_LAUNCHER_UTIL})
+
SET(DOTNET_LAUNCHER "dotnet-launcher")
SET(${DOTNET_LAUNCHER}_SOURCE_FILES
- launcher/main.cc
- launcher/injection.cc
- launcher/launcher.cc
- launcher/dotnet/dotnet_launcher.cc
+ launcher/exec/launcher.cc
)
ADD_EXECUTABLE(${DOTNET_LAUNCHER} ${${DOTNET_LAUNCHER}_SOURCE_FILES})
SET_TARGET_PROPERTIES(${DOTNET_LAUNCHER} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_EXE})
-TARGET_LINK_LIBRARIES(${DOTNET_LAUNCHER} ${${PROJECT_NAME}_LDFLAGS} "-pie -ldl -lpthread" aul ${DOTNET_LAUNCHER_UTIL})
+TARGET_INCLUDE_DIRECTORIES(${DOTNET_LAUNCHER} PRIVATE "launcher/lib")
+TARGET_LINK_LIBRARIES(${DOTNET_LAUNCHER} ${${PROJECT_NAME}_LDFLAGS} "-pie -ldl -lpthread" aul ${DOTNET_LAUNCHER_UTIL} ${DOTNET_LAUNCHER_CORE})
SET_TARGET_PROPERTIES(${DOTNET_LAUNCHER}
PROPERTIES SKIP_BUILD_RPATH TRUE
) # remove rpath option that is automatically generated by cmake.
-SET(DOTNET_HYDRA_LAUNCHER "dotnet-hydra-launcher")
-SET(${DOTNET_HYDRA_LAUNCHER}_SOURCE_FILES
+SET(DOTNET_LOADER "dotnet-loader")
+SET(${DOTNET_LOADER}_SOURCE_FILES
+ launcher/exec/loader.cc
+)
+ADD_EXECUTABLE(${DOTNET_LOADER} ${${DOTNET_LOADER}_SOURCE_FILES})
+SET_TARGET_PROPERTIES(${DOTNET_LOADER} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_EXE})
+TARGET_INCLUDE_DIRECTORIES(${DOTNET_LOADER} PRIVATE "launcher/lib")
+TARGET_LINK_LIBRARIES(${DOTNET_LOADER} ${${PROJECT_NAME}_LDFLAGS} "-pie -ldl -lpthread" aul ${DOTNET_LAUNCHER_UTIL} ${DOTNET_LAUNCHER_CORE})
+
+SET_TARGET_PROPERTIES(${DOTNET_LOADER}
+ PROPERTIES SKIP_BUILD_RPATH TRUE
+) # remove rpath option that is automatically generated by cmake.
+
+SET(DOTNET_CORERUN "dotnet")
+SET(${DOTNET_CORERUN}_SOURCE_FILES
+ launcher/exec/corerun.cc
+)
+ADD_EXECUTABLE(${DOTNET_CORERUN} ${${DOTNET_CORERUN}_SOURCE_FILES})
+SET_TARGET_PROPERTIES(${DOTNET_CORERUN} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_EXE})
+TARGET_INCLUDE_DIRECTORIES(${DOTNET_CORERUN} PRIVATE "launcher/lib")
+TARGET_LINK_LIBRARIES(${DOTNET_CORERUN} ${${PROJECT_NAME}_LDFLAGS} "-pie -ldl -lpthread" aul ${DOTNET_LAUNCHER_UTIL} ${DOTNET_LAUNCHER_CORE})
+
+SET_TARGET_PROPERTIES(${DOTNET_CORERUN}
+ PROPERTIES SKIP_BUILD_RPATH TRUE
+) # remove rpath option that is automatically generated by cmake.
+
+SET(DOTNET_HYDRA_LOADER "dotnet-hydra-loader")
+SET(${DOTNET_HYDRA_LOADER}_SOURCE_FILES
hydra/hydra_main.cc
)
-ADD_EXECUTABLE(${DOTNET_HYDRA_LAUNCHER} ${${DOTNET_HYDRA_LAUNCHER}_SOURCE_FILES})
-TARGET_LINK_LIBRARIES(${DOTNET_HYDRA_LAUNCHER} ${${target_hydra}_LDFLAGS} "-pie -ldl")
-SET_TARGET_PROPERTIES(${DOTNET_HYDRA_LAUNCHER} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_HYDRA})
-SET_TARGET_PROPERTIES(${DOTNET_HYDRA_LAUNCHER}
+ADD_EXECUTABLE(${DOTNET_HYDRA_LOADER} ${${DOTNET_HYDRA_LOADER}_SOURCE_FILES})
+TARGET_LINK_LIBRARIES(${DOTNET_HYDRA_LOADER} ${${target_hydra}_LDFLAGS} "-pie -ldl")
+SET_TARGET_PROPERTIES(${DOTNET_HYDRA_LOADER} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_HYDRA})
+SET_TARGET_PROPERTIES(${DOTNET_HYDRA_LOADER}
PROPERTIES SKIP_BUILD_RPATH TRUE
) # remove rpath option that is automatically generated by cmake.
CONFIGURE_FILE(dotnet-launcher.pc.in dotnet-launcher.pc @ONLY)
INSTALL(TARGETS ${DOTNET_LAUNCHER_UTIL} DESTINATION ${LIBDIR})
+INSTALL(TARGETS ${DOTNET_LAUNCHER_CORE} DESTINATION ${LIBDIR})
INSTALL(TARGETS ${DOTNET_LAUNCHER} DESTINATION ${BINDIR})
-INSTALL(TARGETS ${DOTNET_HYDRA_LAUNCHER} DESTINATION ${BINDIR})
+INSTALL(TARGETS ${DOTNET_LOADER} DESTINATION ${BINDIR})
+INSTALL(TARGETS ${DOTNET_CORERUN} DESTINATION ${BINDIR})
+INSTALL(TARGETS ${DOTNET_HYDRA_LOADER} DESTINATION ${BINDIR})
INSTALL(TARGETS ${TAC_COMMON} DESTINATION ${LIBDIR})
INSTALL(TARGETS ${NI_COMMON} DESTINATION ${LIBDIR})
INSTALL(TARGETS ${NITOOL} DESTINATION ${BINDIR})
[LOADER]
-NAME dotnet-launcher
+NAME dotnet-loader
# for candidate mode
-EXE /usr/bin/dotnet-launcher
+EXE /usr/bin/dotnet-loader
# for hydra mode
-#EXE /usr/bin/dotnet-hydra-launcher
+#EXE /usr/bin/dotnet-hydra-loader
APP_TYPE dotnet
DETECTION_METHOD TIMEOUT|DEMAND
TIMEOUT 5000
#include "launcher_env.h"
const char* __coreclr_lib = "/usr/share/dotnet.tizen/netcoreapp/libcoreclr.so";
-const char* __dotnet_launcher = "/usr/bin/dotnet-launcher";
+const char* __dotnet_loader = "/usr/bin/dotnet-loader";
typedef int (*coreclr_preload_assembly_ptr)(const char* assemblyPath);
typedef int (*launcher_real_main_ptr)(int argc, char *argv[], const char* mode);
hydra_callback.fork = [](int argc, char **argv, void* user_data) -> int {
_INFO("hydra : fork");
- void* launcher_h = dlopen(__dotnet_launcher, RTLD_NOW | RTLD_GLOBAL);
+ void* launcher_h = dlopen(__dotnet_loader, RTLD_NOW | RTLD_GLOBAL);
if (launcher_h == nullptr) {
_DBG("dlopen failed to open dotnet-launcher");
return -1;
#ifndef __LOG_H__
#define __LOG_H__
-#ifndef NO_TIZEN
#include <dlog.h>
#define LOGX(fmt, arg...) \
({ do { \
dlog_print(DLOG_INFO, LOG_TAG, fmt, ##arg); \
} while (0); })
-#else
-#include <stdio.h>
-#define LOGE(fmt, args...) printf(fmt, ##args)
-#define LOGD(fmt, args...) printf(fmt, ##args)
-#define LOGI(fmt, args...) printf(fmt, ##args)
-#define LOGX(fmt, args...) printf(fmt, ##args)
-#endif
-
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define _LOGX(fmt, args...) LOGX(fmt "\n", ##args)
#endif
+#ifndef _SOUT
+#define _SOUT(fmt, args...) fprintf(stdout, fmt "\n", ##args)
+#endif
+
+#ifndef _SERR
+#define _SERR(fmt, args...) fprintf(stderr, fmt "\n", ##args)
+#endif
+
#endif /* __LOG_H__ */
*/
bool removeAll(const bf::path& path);
+/**
+ * @brief change command name of the current process for access via ps command
+ * @param[in] name
+ */
+void setCmdName(const char* name);
+
+/**
+ * @brief get file name from the path
+ * @param[in] file path
+ * @return return file name if exist otherwise null.
+ */
+char* getFileNameFromPath(char* path);
+
#endif /* __UTILS_H__ */
+++ /dev/null
-/*
- * 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 <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 <vconf.h>
-#include <app_common.h>
-
-#include <Ecore.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"
-
-#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 {
-namespace dotnetcore {
-
-#if defined (__aarch64__)
-#define ARCHITECTURE_IDENTIFIER "arm64"
-
-#elif defined (__arm__)
-#define ARCHITECTURE_IDENTIFIER "armel"
-
-#elif defined (__x86_64__)
-#define ARCHITECTURE_IDENTIFIER "x64"
-
-#elif defined (__i386__)
-#define ARCHITECTURE_IDENTIFIER "x86"
-
-#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<std::string> RID_FALLBACK_GRAPH;
- std::vector<std::string> RID_FALLBACK_TIZEN;
- char* tizen_rid = vconf_get_str(__TIZEN_RID_VERSION_KEY);
- if (tizen_rid) {
- std::vector<std::string> 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<std::string> 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()) {
- 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");
- } else if (!strncmp(ARCHITECTURE_IDENTIFIER, "armel", 5)) {
- candidate = candidate + ":" + concatPath(appRoot, "lib/arm");
- }
-
- 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");
-
- std::string token;
- while (std::getline(inFile, token, '\n')) {
- 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");
- }
-}
-
-#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);
- }
-
- 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<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;
- }
-}
-
-// terminate candidate process when language changed
-// icu related data (CultureInfo, etc) should be recreated.
-static void langChangedCB(keynode_t *key, void* data)
-{
- _INFO("terminiate candidate process to update language.");
- exit(0);
-}
-
-static void setLang()
-{
- char* lang = vconf_get_str(VCONFKEY_LANGSET);
- if (!lang) {
- _ERR("Fail to get language from vconf");
- return;
- }
-
- // In order to operate ICU (used for globalization) normally, the following
- // environment variables must be set before using ICU API.
- // When running Applicaiton, the following environment variables are set by AppFW.
- // But when preloading the dll in the candidate process, the following environment variables are not set
- // As a result, CultureInfo is incorrectly generated and malfunctions.
- // For example, uloc_getDefault() returns en_US_POSIX, CultureInfo is set to invariant mode.
- setenv("LANG", const_cast<char *>(lang), 1);
- setenv("LC_MESSAGES", const_cast<char *>(lang), 1);
- setenv("LC_ALL", const_cast<char *>(lang), 1);
-
- free(lang);
-}
-
-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),
- __coreclrLib(nullptr),
- __hostHandle(nullptr),
- __domainId(-1),
- __fd(-1),
- __initialized(false),
- __isProfileMode(false)
-{
- _INFO("Constructor called!!");
-
- // Intiailize ecore first (signal handlers, etc.) before runtime init.
- ecore_init();
-
- // set language environment to support ICU
- setLang();
-
- 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.
- // So, plugin initialize should be called before mainloop start.
- if (initializePluginManager(mode) < 0) {
- _ERR("Failed to initialize PluginManager");
- }
-}
-
-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, bool useDlog, const char* corerunRoot)
-{
- // 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.
- // 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();
-
- if (initializePathManager(std::string(), std::string(), std::string()) < 0) {
- _ERR("Failed to initialize PathManager");
- return -1;
- }
-
- if (useDlog && !pluginHasLogControl()) {
- if (initializeLogManager() < 0) {
- _ERR("Failed to initnialize LogManager");
- 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);
- 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) \
- 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();
-
- // terminate candidate process if language is changed.
- // CurrentCulture created for preloaded dlls should be updated.
- vconf_notify_key_changed(VCONFKEY_LANGSET, langChangedCB, NULL);
- }
-
- // 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();
-
- std::string tpa = getTPA();
- std::string runtimeDir = getRuntimeDir();
- std::string appName = std::string("dotnet-launcher-") + std::to_string(getpid());
- std::string probePath;
- std::string NIprobePath;
- std::string nativeLibPath;
-
- if (corerunRoot) {
- probePath = corerunRoot;
- NIprobePath = corerunRoot;
- nativeLibPath = corerunRoot;
- } else {
- __fd = open("/proc/self", O_DIRECTORY);
- if (__fd < 0) {
- _ERR("Failed to open /proc/self");
- return -1;
- }
- 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);
- probePath = appRoot + ":" + appBin + ":" + appLib + ":" + appTac;
- NIprobePath = concatPath(appBin, APP_NI_SUB_DIR) + ":" + concatPath(appLib, APP_NI_SUB_DIR) + ":" + appTac;
- nativeLibPath = getExtraNativeLibDirs(appRoot) + ":" + appBin + ":" + appLib + ":" + __nativeLibDirectory + ":" + runtimeDir;
- }
-
- 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)
-{
- 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;
-}
-
-void CoreRuntime::dispose()
-{
- // 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;
-
- 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;
- }
-
- // 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();
- }
-
- pluginSetAppInfo(appId, path);
-
- // override root path for application launch mode (candidate / standalone mode)
- if (__fd >= 0) {
- 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);
- }
-
- vconf_ignore_key_changed(VCONFKEY_LANGSET, langChangedCB);
-
- 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
-} // namespace runtime
-} // namespace tizen
+++ /dev/null
-/*
- * 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 __DOTNET_LAUNCHER_H__
-#define __DOTNET_LAUNCHER_H__
-
-#include "launcher.h"
-#include "coreclr_host.h"
-#include "plugin_manager.h"
-
-namespace tizen {
-namespace runtime {
-namespace dotnetcore {
-
-class CoreRuntime
-{
- public:
- CoreRuntime(const char* mode);
- ~CoreRuntime();
- int initialize(bool standalone, bool useDlog, const char* corerunRoot);
- void dispose();
- int launch(const char* appId, const char* root, const char* path, int argc, char* argv[]);
-
- private:
-
- bool initializeCoreClr(const char* appId, const char* assemblyProbePaths, const char* NIProbePaths, const char* pinvokeProbePaths, const char* tpaList);
- void preloadTypes();
- coreclr_initialize_ptr initializeClr;
- coreclr_execute_assembly_ptr executeAssembly;
- coreclr_shutdown_ptr shutdown;
- coreclr_create_delegate_ptr createDelegate;
- set_environment_variable_ptr setEnvironmentVariable;
- std::string __nativeLibDirectory;
- void* __coreclrLib;
- void* __hostHandle;
- unsigned int __domainId;
- int __fd;
- bool __initialized;
- bool __isProfileMode;
-
-};
-
-} // dotnetcore
-} // namespace runtime
-} // namespace tizen
-
-#endif /* __DOTNET_LAUNCHER_H__ */
--- /dev/null
+/*
+ * 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 "dotnet_launcher.h"
+#include "utils.h"
+#include "log.h"
+
+using tizen::runtime::dotnetcore::CoreRuntime;
+
+int main(int argc, char *argv[])
+{
+ _INFO("##### Run in corerun mode #####");
+
+ if (argc < 2) {
+ _SOUT("No parameter");
+ return -1;
+ }
+
+ if (!isManagedAssembly(argv[1]) && !isNativeImage(argv[1])) {
+ _SOUT("first parameter should be assembly file");
+ return -1;
+ }
+
+ // remove executable and assembly path form the arguments and pass that to managed code
+ int vargc = argc - 2;
+ std::vector<char*> vargs;
+ for (int i = 0; i < vargc; i++) {
+ vargs.push_back(argv[2 + i]);
+ }
+
+ // set command name to assembly file
+ char* fileName = getFileNameFromPath(argv[1]);
+ setCmdName(fileName);
+
+ CoreRuntime* runtime = new CoreRuntime("corerun");
+
+ // get absolute path of input dll file
+ std::string absoluteDllPath = absolutePath(argv[1]);
+
+ if (runtime->initialize(LaunchMode::corerun, false, absoluteDllPath.c_str()) != 0) {
+ _SOUT("Failed to initialize");
+ return -1;
+ }
+
+ // launch application
+ if (runtime->launch(fileName, baseName(absoluteDllPath).c_str(), absoluteDllPath.c_str(), vargc, &vargs[0])) {
+ _SOUT("Failed to launch");
+ return -1;
+ }
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * 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 "dotnet_launcher.h"
+#include "utils.h"
+#include "log.h"
+
+#include <cstdio>
+#include <vector>
+#include <memory>
+
+#include <aul.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <sys/prctl.h>
+
+using tizen::runtime::dotnetcore::CoreRuntime;
+
+// By the specification, application id must be shorter than 50 characters.
+// Current length of argv[0] is 25 with a space. ("/usr/bin/dotnet-launcher ")
+// To be able to change argv[0] when standalone mode padding for executable path is added.
+#define APPID_MAX_LENGTH (25 + 105)
+#define PRC_NAME_LENGTH 16
+
+static std::string StandaloneOption("--standalone");
+static std::string PaddingOption("--PADDING_TO_CHANGE_CMDLINE_PADDING_TO_CHANGE_CMDLINE_PADDING_TO_CHANGE_CMDLINE_PADDING_TO_CHANGE_CMDLINE");
+
+int main(int argc, char *argv[])
+{
+ _INFO("##### Run in standalone mode #####");
+
+ char* standalonePath = nullptr;
+ bool paddingExist = false;
+ const char* appRootPath = NULL;
+ char appId[APPID_MAX_LENGTH] = {0,};
+
+ std::vector<char*> vargs;
+
+ // start index 1 to avoid passing executable name "dotnet-launcher" as a parameter
+ for (int i = 1; i < argc; i++) {
+ if (StandaloneOption.compare(argv[i]) == 0) {
+ if (i > argc - 1) {
+ _ERR("Assembly path must be after \"--standalone\" option");
+ return -1;
+ }
+ i++;
+ standalonePath = argv[i];
+ } else if (PaddingOption.compare(argv[i]) == 0) {
+ paddingExist = true;
+ } else {
+ vargs.push_back(argv[i]);
+ }
+ }
+
+ CoreRuntime* runtime = new CoreRuntime("standalone");
+
+ // get app ID and app root path
+ if (AUL_R_OK == aul_app_get_appid_bypid(getpid(), appId, sizeof(appId))) {
+ _INFO("AUL_APPID : %s", appId);
+ // aul_get_app_root_path returns const char*, so there is no need to free after use.
+ appRootPath = aul_get_app_root_path();
+ if (appRootPath == nullptr) {
+ _ERR("Fail to get application root path");
+ return -1;
+ }
+ } else {
+ _ERR("Fail to get app_id");
+ return -1;
+ }
+
+ // set command name to assembly file
+ setCmdName(getFileNameFromPath(standalonePath));
+
+ // change cmdline from dotnet-launcher to executable path
+ int cmdlineSize = paddingExist ? APPID_MAX_LENGTH : APPID_MAX_LENGTH - PaddingOption.length();
+ memset(argv[0], '\0', cmdlineSize);
+ snprintf(argv[0], cmdlineSize - 1, "%s", standalonePath);
+
+ // initialize CoreRuntime (standalone mode enable, dlog redirection enable, root path NULL)
+ if (runtime->initialize(LaunchMode::launcher, true, appRootPath) != 0) {
+ _ERR("Failed to initialize");
+ return -1;
+ }
+
+ // launch application
+ if (runtime->launch(appId, appRootPath, standalonePath, vargs.size(), &vargs[0])) {
+ _ERR("Failed to launch");
+ return -1;
+ }
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * 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 "dotnet_launcher.h"
+#include "utils.h"
+#include "log.h"
+
+#include <cstdio>
+#include <vector>
+#include <memory>
+
+#include <Ecore.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/prctl.h>
+
+#include <launchpad.h>
+#include <aul.h>
+
+using tizen::runtime::dotnetcore::CoreRuntime;
+
+static Ecore_Fd_Handler *__fd_handler;
+static loader_receiver_cb __receiver;
+
+// To precreate window(EFL/DALI), argc and argv should be passed.
+// But, create callback of loader doesnot pass that to parameter.
+// So, store argc and argv and use that to precreation.
+// If window precreation code moves to managed, removed below code.
+static int __argc;
+static char **__argv;
+
+typedef struct AppInfo {
+ std::string root;
+ std::string app_path;
+ std::string appid;
+ std::string pkgid;
+} AppInfo;
+static AppInfo __appInfo;
+
+
+//################## Code for running event loop for loader ####################
+
+static Eina_Bool __process_fd_handler(void *data, Ecore_Fd_Handler *handler)
+{
+ int fd;
+
+ fd = ecore_main_fd_handler_fd_get(handler);
+ if (fd == -1) {
+ _ERR("[candidate] ECORE_FD_GET");
+ exit(-1);
+ }
+
+ if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) {
+ if (__receiver)
+ __receiver(fd);
+ } else if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR)) {
+ _ERR("[candidate] ECORE_FD_ERROR");
+ close(fd);
+ exit(-1);
+ }
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static void __adapter_loop_begin(void *user_data)
+{
+ ecore_main_loop_begin();
+}
+
+static void __adapter_loop_quit(void *user_data)
+{
+ ecore_main_loop_quit();
+}
+
+static void __adapter_add_fd(void *user_data, int fd,
+ loader_receiver_cb receiver)
+{
+ __fd_handler = ecore_main_fd_handler_add(fd,
+ static_cast<Ecore_Fd_Handler_Flags>(ECORE_FD_READ | ECORE_FD_ERROR),
+ __process_fd_handler, NULL, NULL, NULL);
+
+ if (__fd_handler == NULL) {
+ _ERR("fd_handler is NULL");
+ close(fd);
+ exit(-1);
+ }
+
+ __receiver = receiver;
+}
+
+static void __adapter_remove_fd(void *user_data, int fd)
+{
+ if (__fd_handler) {
+ ecore_main_fd_handler_del(__fd_handler);
+ __fd_handler = NULL;
+ __receiver = NULL;
+ }
+}
+
+//################## Code for managing loader life-cycle #######################
+
+static void __loader_create_cb(bundle *extra, int type, void *user_data)
+{
+ CoreRuntime* runtime = (CoreRuntime*)user_data;
+
+ {
+ // do native window precreation here
+ }
+
+ // initialize CoreRuntime (launchmode, dlog redirection enable, root path NULL)
+ if (runtime->initialize(LaunchMode::loader, true, NULL) != 0) {
+ _ERR("Failed to initialized");
+ } else {
+ _INFO("Success to initialized");
+ }
+}
+
+static int __loader_launch_cb(int argc, char **argv, const char *app_path,
+ const char *appid, const char *pkgid, const char *pkg_type,
+ void *user_data)
+{
+ const char* root_path = aul_get_app_root_path();
+ if (root_path != NULL) {
+ __appInfo.root = root_path;
+ }
+
+ __appInfo.app_path = app_path;
+ __appInfo.appid = appid;
+ __appInfo.pkgid = pkgid;
+
+ return 0;
+}
+
+static int __loader_terminate_cb(int argc, char **argv, void *user_data)
+{
+ CoreRuntime* runtime = (CoreRuntime*)user_data;
+
+ _INFO("launch request with app path : %s", __appInfo.app_path.c_str());
+
+ // The launchpad pass the name of exe file to the first argument.
+ // For the C# spec, we have to skip this first argument.
+ if (runtime->launch(__appInfo.appid.c_str(), __appInfo.root.c_str(),
+ __appInfo.app_path.c_str(), argc - 1, argv + 1)) {
+ _ERR("Failed to launch");
+ }
+
+ return 0;
+}
+
+//################## Main Code #################################################
+
+extern "C" int realMain(int argc, char *argv[], const char* mode)
+{
+ _INFO("##### Run in candidate mode #####");
+
+ CoreRuntime* runtime = new CoreRuntime(mode);
+
+ // change cmdline from dotnet-hydra-loader to dotnet-loader
+ if (strcmp(argv[0], "/usr/bin/dotnet-hydra-loader") == 0) {
+ memset(argv[0], '\0', strlen("/usr/bin/dotnet-hydra-loader"));
+ snprintf(argv[0], strlen("/usr/bin/dotnet-loader") + 1,
+ "/usr/bin/dotnet-loader");
+ }
+
+ setCmdName("dotnet-loader");
+
+ loader_lifecycle_callback_s callbacks = {
+ .create = __loader_create_cb,
+ .launch = __loader_launch_cb,
+ .terminate = __loader_terminate_cb
+ };
+
+ loader_adapter_s adapter = {
+ .loop_begin = __adapter_loop_begin,
+ .loop_quit = __adapter_loop_quit,
+ .add_fd = __adapter_add_fd,
+ .remove_fd = __adapter_remove_fd
+ };
+
+ return launchpad_loader_main(argc, argv, &callbacks, &adapter, runtime);
+}
+
+int main(int argc, char *argv[])
+{
+ __argc = argc;
+ __argv = argv;
+
+ return realMain(argc, argv, "candidate");
+}
+
+++ /dev/null
-/*
- * 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 <cstdlib>
-#include <cstring>
-
-#include <dlfcn.h>
-
-#define HT_PATH "/home/owner/share/tmp/sdk_tools/heaptrack/"
-#define HT_LIB_PATH HT_PATH "libprofiler.so"
-#define HT_INJECTION_LIB_PATH HT_PATH "libheaptrack_inject.so"
-
-static int injectLibrary(const char path[])
-{
- 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);
-
- // Current implementation of heaptrack CLR profiler requires RTLD_GLOBAL
- lib = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
- if (lib == nullptr) {
- _ERR("%s", dlerror());
- return res;
- }
-
- inject = reinterpret_cast<inject_func*>(dlsym(lib, inject_sym));
- if (inject == nullptr) {
- _ERR("%s is not found in the %s", inject_sym, path);
- return res;
- }
-
- res = inject();
- return res;
-}
-
-int checkInjection()
-{
- char *env = nullptr;
-
- env = getenv("CORECLR_PROFILER_PATH");
- if (env == nullptr) {
- return 0;
- }
-
- // At the moment, this mechanism is used only when the Memory Profiler is started.
- if (strcmp(env, HT_LIB_PATH) != 0) {
- return 0;
- }
-
- _INFO("##### Perform injection #########");
-
- if (injectLibrary(HT_INJECTION_LIB_PATH) != 0) {
- _INFO("##### Injection failed #########");
- return -1;
- }
-
- _INFO("##### Injection finished #########");
- return 0;
-}
+++ /dev/null
-/*
- * 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 checkInjection();
-
-#endif // __INJETION_INTERFACE_H__
+++ /dev/null
-/*
- * 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 "launcher.h"
-#include "log.h"
-
-#include <launchpad.h>
-#include <aul.h>
-
-#include <Ecore.h>
-#include <bundle_internal.h>
-
-#include <map>
-#include <vector>
-#include <functional>
-
-#include <unistd.h>
-#include <dlfcn.h>
-
-
-namespace tizen {
-namespace runtime {
-
-struct FdHandler {
- Ecore_Fd_Handler *handler;
- loader_receiver_cb receiver;
-};
-
-static int __argc;
-static char **__argv;
-
-class LaunchpadAdapterImpl : public LaunchpadAdapter
-{
- public:
- LaunchpadAdapterImpl() :
- callbacks(),
- adapter(),
- __isLaunched(false)
- { }
- int loaderMain(int argc, char* argv[]) override;
-
- std::map<int, FdHandler> handlers;
-
- private:
- AppInfo appInfo;
- loader_lifecycle_callback_s callbacks;
- loader_adapter_s adapter;
- bool __isLaunched;
- std::string __launchPath;
-};
-
-LaunchpadAdapterImpl LaunchpadImpl;
-LaunchpadAdapter& Launchpad = LaunchpadImpl;
-
-#define WITH_SELF(data) \
- LaunchpadAdapterImpl* self = static_cast<LaunchpadAdapterImpl*>(data); \
- if (self == nullptr) \
- _ERR("No LaunchpadImplData"); \
- else
-
-static Eina_Bool fdHandler(void *data, Ecore_Fd_Handler* handler)
-{
- WITH_SELF(data) {
- int fd = ecore_main_fd_handler_fd_get(handler);
- if (fd == -1) {
- _ERR("Failed to get the Ecore FD");
- exit(-1);
- }
-
- if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) {
- if (self->handlers.find(fd) != self->handlers.end())
- self->handlers[fd].receiver(fd);
- } else if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR)) {
- _ERR("Ecore FD Handler Have Error");
- close(fd);
- exit(-1);
- }
- }
-
- return ECORE_CALLBACK_CANCEL;
-}
-
-static void fdAdd(void *data, int fd, loader_receiver_cb receiver)
-{
- Ecore_Fd_Handler* handler = ecore_main_fd_handler_add(fd,
- static_cast<Ecore_Fd_Handler_Flags>(ECORE_FD_READ | ECORE_FD_ERROR),
- fdHandler, data, nullptr, nullptr);
- if (handler == nullptr) {
- _ERR("Failed to add a FD handler to ecore main loop");
- close(fd);
- exit(-1);
- } WITH_SELF(data) {
- self->handlers[fd] = {handler, receiver};
- }
-}
-
-static void fdRemove(void *data, int fd)
-{
- WITH_SELF(data) {
- if (self->handlers.find(fd) != self->handlers.end()) {
- Ecore_Fd_Handler* handler = self->handlers[fd].handler;
- ecore_main_fd_handler_del(handler);
- self->handlers.erase(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()
-{
- struct stat sb;
- if (stat(ELEMENTARY_PATH, &sb) != 0) {
- _ERR("[candidate] libelementary is not exist. skip precreation");
- return;
- }
-
- 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;
- }
- }
-
- 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_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[])
-{
- __argc = argc;
- __argv = argv;
- callbacks.create = [](bundle *extra, int type, void *userData) {
- preCreateWindow();
- WITH_SELF(userData) {
- if (self->onCreate != nullptr)
- self->onCreate();
- }
- };
- callbacks.launch = [](int argc, char** argv, const char* appPath,
- const char* appId, const char* pkgId,
- const char* pkgType, void* userData) -> int {
- WITH_SELF(userData) {
- const char* appRootPath = aul_get_app_root_path();
- if (appRootPath != nullptr) {
- self->appInfo.root = std::string(appRootPath);
- }
- self->appInfo.path = appPath;
- self->appInfo.id = appId;
- self->appInfo.pkg = pkgId;
- self->appInfo.type = pkgType;
- if (self->onLaunch != nullptr)
- self->onLaunch(self->appInfo, argc, argv);
- }
-
- return 0;
- };
- callbacks.terminate = [](int argc, char **argv, void* userData) -> int {
- WITH_SELF(userData) {
- if (self->onTerminate != nullptr)
- self->onTerminate(self->appInfo, argc, argv);
- }
- return 0;
- };
-
- adapter.loop_begin = [](void *data) {
- ecore_main_loop_begin();
- };
-
- adapter.loop_quit = [](void *data) {
- ecore_main_loop_quit();
- };
- adapter.add_fd = fdAdd;
- adapter.remove_fd = fdRemove;
-
- _INFO("launchpad_loader_main is start");
- int r = launchpad_loader_main(argc, argv, &(this->callbacks), &(this->adapter), this);
- _INFO("launchpad_loader_main is finished with [%d]", r);
-
- return r;
-}
-
-#undef WITH_SELF
-
-} // namespace runtime
-} // namespace tizen
+++ /dev/null
-/*
- * 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 __LAUNCHER_INTERFACE_H__
-#define __LAUNCHER_INTERFACE_H__
-
-#include <string>
-#include <functional>
-
-namespace tizen {
-namespace runtime {
-
-struct AppInfo {
- std::string root;
- std::string path;
- std::string id;
- std::string pkg;
- std::string type;
-};
-
-class LaunchpadAdapter
-{
- public:
- virtual int loaderMain(int argc, char* argv[]) = 0;
- std::function<void()> onCreate = nullptr;
- std::function<void(const AppInfo&, int, char**)> onLaunch = nullptr;
- std::function<void(const AppInfo&, int, char**)> onTerminate = nullptr;
-};
-
-extern LaunchpadAdapter& Launchpad;
-
-} // namespace runtime
-} // namespace tizen
-
-#endif /* __LAUNCHER_INTERFACE_H__ */
--- /dev/null
+/*
+ * 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 <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 <vconf.h>
+#include <app_common.h>
+
+#include <Ecore.h>
+
+#include "injection.h"
+#include "utils.h"
+#include "log.h"
+#include "dotnet_launcher.h"
+#include "plugin_manager.h"
+#include "path_manager.h"
+#include "log_manager.h"
+
+#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 {
+namespace dotnetcore {
+
+#if defined (__aarch64__)
+#define ARCHITECTURE_IDENTIFIER "arm64"
+
+#elif defined (__arm__)
+#define ARCHITECTURE_IDENTIFIER "armel"
+
+#elif defined (__x86_64__)
+#define ARCHITECTURE_IDENTIFIER "x64"
+
+#elif defined (__i386__)
+#define ARCHITECTURE_IDENTIFIER "x86"
+
+#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<std::string> RID_FALLBACK_GRAPH;
+ std::vector<std::string> RID_FALLBACK_TIZEN;
+ char* tizen_rid = vconf_get_str(__TIZEN_RID_VERSION_KEY);
+ if (tizen_rid) {
+ std::vector<std::string> 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<std::string> 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()) {
+ 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");
+ } else if (!strncmp(ARCHITECTURE_IDENTIFIER, "armel", 5)) {
+ candidate = candidate + ":" + concatPath(appRoot, "lib/arm");
+ }
+
+ 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");
+
+ std::string token;
+ while (std::getline(inFile, token, '\n')) {
+ 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");
+ }
+}
+
+#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);
+ }
+
+ 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<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;
+ }
+}
+
+// terminate candidate process when language changed
+// icu related data (CultureInfo, etc) should be recreated.
+static void langChangedCB(keynode_t *key, void* data)
+{
+ _INFO("terminiate candidate process to update language.");
+ exit(0);
+}
+
+static void setLang()
+{
+ char* lang = vconf_get_str(VCONFKEY_LANGSET);
+ if (!lang) {
+ _ERR("Fail to get language from vconf");
+ return;
+ }
+
+ // In order to operate ICU (used for globalization) normally, the following
+ // environment variables must be set before using ICU API.
+ // When running Applicaiton, the following environment variables are set by AppFW.
+ // But when preloading the dll in the candidate process, the following environment variables are not set
+ // As a result, CultureInfo is incorrectly generated and malfunctions.
+ // For example, uloc_getDefault() returns en_US_POSIX, CultureInfo is set to invariant mode.
+ setenv("LANG", const_cast<char *>(lang), 1);
+ setenv("LC_MESSAGES", const_cast<char *>(lang), 1);
+ setenv("LC_ALL", const_cast<char *>(lang), 1);
+
+ free(lang);
+}
+
+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),
+ __coreclrLib(nullptr),
+ __hostHandle(nullptr),
+ __domainId(-1),
+ __fd(-1),
+ __initialized(false),
+ __isProfileMode(false)
+{
+ _INFO("Constructor called!!");
+
+ // Intiailize ecore first (signal handlers, etc.) before runtime init.
+ ecore_init();
+
+ // set language environment to support ICU
+ setLang();
+
+ 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.
+ // So, plugin initialize should be called before mainloop start.
+ if (initializePluginManager(mode) < 0) {
+ _ERR("Failed to initialize PluginManager");
+ }
+}
+
+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(LaunchMode launchMode, bool useDlog, const char* rootPath)
+{
+ // 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.
+ // 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 (launchMode == LaunchMode::loader)
+ 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();
+
+ if (initializePathManager(std::string(), std::string(), std::string()) < 0) {
+ _ERR("Failed to initialize PathManager");
+ return -1;
+ }
+
+ if (useDlog && !pluginHasLogControl()) {
+ if (initializeLogManager() < 0) {
+ _ERR("Failed to initnialize LogManager");
+ 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);
+ 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) \
+ 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 (launchMode == LaunchMode::loader) {
+ pluginPreload();
+
+ // terminate candidate process if language is changed.
+ // CurrentCulture created for preloaded dlls should be updated.
+ vconf_notify_key_changed(VCONFKEY_LANGSET, langChangedCB, NULL);
+ }
+
+ // 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();
+
+ std::string tpa = getTPA();
+ std::string runtimeDir = getRuntimeDir();
+ std::string appName = std::string("dotnet-launcher-") + std::to_string(getpid());
+ std::string probePath;
+ std::string NIprobePath;
+ std::string nativeLibPath;
+
+ if (launchMode == LaunchMode::corerun) {
+ probePath = rootPath;
+ NIprobePath = rootPath;
+ nativeLibPath = rootPath;
+ } else {
+ __fd = open("/proc/self", O_DIRECTORY);
+ if (__fd < 0) {
+ _ERR("Failed to open /proc/self");
+ return -1;
+ }
+ 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);
+ probePath = appRoot + ":" + appBin + ":" + appLib + ":" + appTac;
+ NIprobePath = concatPath(appBin, APP_NI_SUB_DIR) + ":" + concatPath(appLib, APP_NI_SUB_DIR) + ":" + appTac;
+ nativeLibPath = getExtraNativeLibDirs(appRoot) + ":" + appBin + ":" + appLib + ":" + __nativeLibDirectory + ":" + runtimeDir;
+ }
+
+ 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 (launchMode == LaunchMode::loader) {
+ 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)
+{
+ 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;
+}
+
+void CoreRuntime::dispose()
+{
+ // 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;
+
+ 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;
+ }
+
+ // 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();
+ }
+
+ pluginSetAppInfo(appId, path);
+
+ // override root path for application launch mode (candidate / standalone mode)
+ if (__fd >= 0) {
+ 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);
+ }
+
+ vconf_ignore_key_changed(VCONFKEY_LANGSET, langChangedCB);
+
+ 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
+} // namespace runtime
+} // namespace tizen
--- /dev/null
+/*
+ * 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 __DOTNET_LAUNCHER_H__
+#define __DOTNET_LAUNCHER_H__
+
+#include <string>
+
+#include "coreclr_host.h"
+#include "plugin_manager.h"
+
+enum LaunchMode {
+ corerun = 0,
+ loader,
+ launcher
+};
+
+namespace tizen {
+namespace runtime {
+namespace dotnetcore {
+
+class CoreRuntime
+{
+ public:
+ CoreRuntime(const char* mode);
+ ~CoreRuntime();
+ int initialize(LaunchMode mode, bool useDlog, const char* rootPath);
+ void dispose();
+ int launch(const char* appId, const char* root, const char* path, int argc, char* argv[]);
+
+ private:
+ bool initializeCoreClr(const char* appId, const char* assemblyProbePaths, const char* NIProbePaths, const char* pinvokeProbePaths, const char* tpaList);
+ void preloadTypes();
+ coreclr_initialize_ptr initializeClr;
+ coreclr_execute_assembly_ptr executeAssembly;
+ coreclr_shutdown_ptr shutdown;
+ coreclr_create_delegate_ptr createDelegate;
+ set_environment_variable_ptr setEnvironmentVariable;
+ std::string __nativeLibDirectory;
+ void* __coreclrLib;
+ void* __hostHandle;
+ unsigned int __domainId;
+ int __fd;
+ bool __initialized;
+ bool __isProfileMode;
+
+};
+
+} // dotnetcore
+} // namespace runtime
+} // namespace tizen
+
+#endif /* __DOTNET_LAUNCHER_H__ */
--- /dev/null
+/*
+ * 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 <cstdlib>
+#include <cstring>
+
+#include <dlfcn.h>
+
+#define HT_PATH "/home/owner/share/tmp/sdk_tools/heaptrack/"
+#define HT_LIB_PATH HT_PATH "libprofiler.so"
+#define HT_INJECTION_LIB_PATH HT_PATH "libheaptrack_inject.so"
+
+static int injectLibrary(const char path[])
+{
+ 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);
+
+ // Current implementation of heaptrack CLR profiler requires RTLD_GLOBAL
+ lib = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
+ if (lib == nullptr) {
+ _ERR("%s", dlerror());
+ return res;
+ }
+
+ inject = reinterpret_cast<inject_func*>(dlsym(lib, inject_sym));
+ if (inject == nullptr) {
+ _ERR("%s is not found in the %s", inject_sym, path);
+ return res;
+ }
+
+ res = inject();
+ return res;
+}
+
+int checkInjection()
+{
+ char *env = nullptr;
+
+ env = getenv("CORECLR_PROFILER_PATH");
+ if (env == nullptr) {
+ return 0;
+ }
+
+ // At the moment, this mechanism is used only when the Memory Profiler is started.
+ if (strcmp(env, HT_LIB_PATH) != 0) {
+ return 0;
+ }
+
+ _INFO("##### Perform injection #########");
+
+ if (injectLibrary(HT_INJECTION_LIB_PATH) != 0) {
+ _INFO("##### Injection failed #########");
+ return -1;
+ }
+
+ _INFO("##### Injection finished #########");
+ return 0;
+}
--- /dev/null
+/*
+ * 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 checkInjection();
+
+#endif // __INJETION_INTERFACE_H__
+++ /dev/null
-/*
- * 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 "dotnet/dotnet_launcher.h"
-#include "utils.h"
-#include "log.h"
-
-#include <cstdio>
-#include <vector>
-#include <memory>
-
-#include <Eina.h>
-#include <aul.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-// By the specification, application id must be shorter than 50 characters.
-// Current length of argv[0] is 25 with a space. ("/usr/bin/dotnet-launcher ")
-// To be able to change argv[0] when standalone mode padding for executable path is added.
-#define APPID_MAX_LENGTH (25 + 105)
-
-static std::string StandaloneOption("--standalone");
-static std::string PaddingOption("--PADDING_TO_CHANGE_CMDLINE_PADDING_TO_CHANGE_CMDLINE_PADDING_TO_CHANGE_CMDLINE_PADDING_TO_CHANGE_CMDLINE");
-
-extern "C" int realMain(int argc, char *argv[], const char* mode)
-{
- int i;
- bool standaloneMode = false;
- char* standalonePath = nullptr;
- bool corerunMode = false;
- bool paddingExist = false;
-
- std::vector<char*> vargs;
-
- // start index 1 to avoid passing executable name "dotnet-launcher" as a parameter
- for (i = 1; i < argc; i++) {
- if (StandaloneOption.compare(argv[i]) == 0) {
- standaloneMode = true;
-
- if (i > argc - 1) {
- fprintf(stderr, "Assembly path must be after \"--standalone\" option\n");
- return 1;
- }
- i++;
- standalonePath = argv[i];
- } else if (PaddingOption.compare(argv[i]) == 0) {
- paddingExist = true;
- } else {
- vargs.push_back(argv[i]);
- }
- }
-
- if (isManagedAssembly(argv[1]) || isNativeImage(argv[1])) {
- corerunMode = true;
- }
-
- using tizen::runtime::Launchpad;
- using tizen::runtime::AppInfo;
- using tizen::runtime::dotnetcore::CoreRuntime;
-
- std::unique_ptr<CoreRuntime> runtime(new CoreRuntime(mode));
-
- if (corerunMode) {
- _INFO("##### Run in corerun mode #####");
- char appId[APPID_MAX_LENGTH] = {0,};
- std::string appRoot;
- snprintf(appId, 16, "%s", "dotnet-launcher");
- std::string absoluteDllPath = absolutePath(argv[1]);
- appRoot = baseName(absoluteDllPath);
-
- if (runtime->initialize(true, false, appRoot.c_str()) != 0) {
- _ERR("Failed to initialize");
- return 1;
- }
-
- int argsLen = vargs.size() - 1;
- char** args = &vargs[1];
- if (runtime->launch(appId, appRoot.c_str(), absoluteDllPath.c_str(), argsLen, args)) {
- _ERR("Failed to launch");
- return 1;
- }
- } else if (standaloneMode) {
- _INFO("##### Run in standalone mode #####");
- char appId[APPID_MAX_LENGTH] = {0,};
- std::string appRoot;
- if (AUL_R_OK == aul_app_get_appid_bypid(getpid(), appId, sizeof(appId))) {
- const char* appRootPath = aul_get_app_root_path();
- if (appRootPath != nullptr)
- appRoot = std::string(appRootPath);
- } else {
- // If appId is not set, it is executed directly by cmdline.
- // In this case, appRoot is passed as an argument.
- snprintf(appId, 16, "%s", "dotnet-launcher");
- appRoot = baseName(baseName(standalonePath));
- }
- _INFO("AUL_APPID : %s", appId);
-
- if (runtime->initialize(true, true, NULL) != 0) {
- _ERR("Failed to initialize");
- return 1;
- }
-
- // change cmdline from dotnet-launcher to executable path
- int cmdlineSize = paddingExist ? APPID_MAX_LENGTH : APPID_MAX_LENGTH - PaddingOption.length();
- memset(argv[0], '\0', cmdlineSize);
- snprintf(argv[0], cmdlineSize, "%s", standalonePath);
-
- int argsLen = vargs.size();
- char** args = &vargs[0];
- if (runtime->launch(appId, appRoot.c_str(), standalonePath, argsLen, args)) {
- _ERR("Failed to launch");
- return 1;
- }
- } else {
- // change cmdline from dotnet-hydra-launcher to dotnet-launcher
- if (strcmp(argv[0], "/usr/bin/dotnet-hydra-launcher") == 0) {
- memset(argv[0], '\0', strlen("/usr/bin/dotnet-hydra-launcher"));
- snprintf(argv[0], strlen("/usr/bin/dotnet-launcher") + 1, "/usr/bin/dotnet-launcher");
- }
-
- Launchpad.onCreate = [&runtime]() {
- if (runtime->initialize(false, true, NULL) != 0) {
- _ERR("Failed to initialized");
- } else {
- _INFO("Success to initialized");
- }
- };
-
- Launchpad.onTerminate = [&runtime](const AppInfo& appInfo, int argc, char** argv) {
- _INFO("launch request with app path : %s", appInfo.path.c_str());
- _INFO("appId : %s", appInfo.id.c_str());
- _INFO("pkg : %s", appInfo.pkg.c_str());
-
- // aul_get_app_root_path() can return NULL for error case.
- if (appInfo.root.empty()) {
- _ERR("Failed to launch. root path is set to NULL");
- } else {
- // The launchpad pass the name of exe file to the first argument.
- // For the C# spec, we have to skip this first argument.
- if (runtime->launch(appInfo.id.c_str(), appInfo.root.c_str(), appInfo.path.c_str(), argc-1, argv+1))
- _ERR("Failed to launch");
- }
- };
- int ret = Launchpad.loaderMain(argc, argv);
- if (ret < 0) {
- _ERR("fail to start loaderMain. candidate process is not created.");
- return 1;
- }
- }
-
- return 0;
-}
-
-int main(int argc, char *argv[])
-{
- return realMain(argc, argv, "default");
-}
#include <pkgmgr-info.h>
#include <pkgmgr_installer_info.h>
#include <sys/smack.h>
+#include <sys/prctl.h>
#include <cstdlib>
#include <cstring>
}
return true;
}
+
+void setCmdName(const char* name)
+{
+ #define PRC_NAME_LENGTH 16
+
+ char processName[PRC_NAME_LENGTH] = {0, };
+
+ if (name == NULL || *name == '\0') {
+ return;
+ }
+
+ memset(processName, '\0', PRC_NAME_LENGTH);
+ snprintf(processName, PRC_NAME_LENGTH, "%s", name);
+ prctl(PR_SET_NAME, processName);
+}
+
+char* getFileNameFromPath(char* path)
+{
+ char* fileName = strrchr(path, PATH_SEPARATOR);
+ if (fileName != NULL && *fileName != '\0') {
+ return ++fileName;
+ }
+
+ return NULL;
+}
+
</request>
<assign>
<filesystem path="/opt/usr/dotnet" label="System::Shared" type="transmutable" />
+ <filesystem path="/usr/bin/dotnet-loader" label="User" exec_label="User" />
+ <filesystem path="/usr/bin/dotnet" label="System::Tools" exec_label="User" />
</assign>
</manifest>
mkdir -p /opt/etc/skel/.dotnet
chsmack -t -a User::App::Shared /opt/etc/skel/.dotnet
%{_bindir}/dotnettool --ni-dll %{_runtime_dir}/System.Private.CoreLib.dll
+setcap cap_setgid,cap_sys_admin+ei /usr/bin/dotnet-launcher
+setcap cap_setgid,cap_sys_admin+ei /usr/bin/dotnet-loader
+setcap cap_setgid,cap_sys_admin+ei /usr/bin/dotnet
%files
%manifest dotnet-launcher.manifest
%{_install_mdplugin_dir}/libprefer_nuget_cache_plugin.so
%{_install_mdplugin_dir}/libprefer_dotnet_aot_plugin.so
%{_bindir}/dotnet-launcher
-%{_bindir}/dotnet-hydra-launcher
+%{_bindir}/dotnet-loader
+%{_bindir}/dotnet
+%{_bindir}/dotnet-hydra-loader
%{_libdir}/libdotnet_launcher_util.so
+%{_libdir}/libdotnet_launcher_core.so
%{_libdir}/libni_common.so
%{_libdir}/libtac_common.so
/etc/tmpfiles.d/%{name}.conf