From: pius.lee Date: Thu, 10 Nov 2016 11:26:43 +0000 (+0900) Subject: Add installer plugin and tool for create a NI X-Git-Tag: submit/tizen/20161214.063015~11 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8cd6fb2c60ac74259fdce9615836949e9d0ef7fc;p=platform%2Fcore%2Fdotnet%2Flauncher.git Add installer plugin and tool for create a NI nitool : native image maker for system dlls and apps libui-application.so : native image creating plugin for app installer Fix bug on getting trusted platform dll. Change-Id: Ie0b18c9fcca2fa0b814d4056d87c2e5d67e4e0e4 --- diff --git a/NativeLauncher/CMakeLists.txt b/NativeLauncher/CMakeLists.txt index 0647e2a..cd273e1 100644 --- a/NativeLauncher/CMakeLists.txt +++ b/NativeLauncher/CMakeLists.txt @@ -1,5 +1,5 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -PROJECT("dotnet-launcher") +PROJECT("dotnet-tools") MESSAGE("CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") @@ -7,7 +7,7 @@ IF(DEFINED NO_TIZEN) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DNO_TIZEN") ELSE(DEFINED NO_TIZEN) INCLUDE(FindPkgConfig) - PKG_CHECK_MODULES(${PROJECT_NAME} REQUIRED aul dlog ecore bundle dlog launchpad) + PKG_CHECK_MODULES(${PROJECT_NAME} REQUIRED aul pkgmgr-info pkgmgr-installer dlog ecore bundle dlog launchpad) ENDIF(DEFINED NO_TIZEN) FOREACH(flag ${${PROJECT_NAME}_CFLAGS}) @@ -34,6 +34,10 @@ IF(DEFINED RUNTIME_DIR) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DRUNTIME_DIR=${RUNTIME_DIR}") ENDIF(DEFINED RUNTIME_DIR) +IF(DEFINED CROSSGEN_PATH) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DCROSSGEN_PATH=${CROSSGEN_PATH}") +ENDIF(DEFINED CROSSGEN_PATH) + IF(DEFINED VERSION) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DVERSION=${VERSION}") ENDIF(DEFINED VERSION) @@ -41,7 +45,7 @@ ENDIF(DEFINED VERSION) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -pthread -std=c++11 -Wl,--no-as-needed -ggdb") SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" ) #SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") -SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fPIE") +#SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fPIE") SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fdata-sections -ffunction-sections -Wl,--gc-sections") SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -D_FILE_OFFSET_BITS=64") #SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DLAUNCHING_TIME_MEASURE") @@ -51,19 +55,20 @@ SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") SET(CMAKE_CXX_FLAGS_RELEASE "-O2") SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed") -INCLUDE_DIRECTORIES(inc) +#SET(${PROJECT_NAME}_LDFLAGS ${${PROJECT_NAME}_LDFLAGS} "-pie") -SET(DOTNET_LAUNCHER "dotnet-launcher") -SET(MONO_LAUNCHER "mono-launcher") +INCLUDE_DIRECTORIES(inc launcher util) +SET(DOTNET_LAUNCHER "dotnet-launcher") SET(${DOTNET_LAUNCHER}_SOURCE_FILES - src/main.cc - src/utils.cc - src/launcher.cc - src/dotnet/dotnet_launcher.cc - src/mono/mono_launcher.cc + launcher/main.cc + util/utils.cc + launcher/launcher.cc + launcher/dotnet/dotnet_launcher.cc + launcher/mono/mono_launcher.cc ) -ADD_EXECUTABLE(${DOTNET_LAUNCHER} ${${PROJECT_NAME}_SOURCE_FILES}) +ADD_EXECUTABLE(${DOTNET_LAUNCHER} ${${DOTNET_LAUNCHER}_SOURCE_FILES}) +SET_TARGET_PROPERTIES(${DOTNET_LAUNCHER} PROPERTIES COMPILE_FLAGS "-fPIE") IF(NOT DEFINED NO_TIZEN) TARGET_LINK_LIBRARIES(${DOTNET_LAUNCHER} aul) @@ -72,11 +77,33 @@ TARGET_LINK_LIBRARIES(${DOTNET_LAUNCHER} ${${PROJECT_NAME}_LDFLAGS} "-pie -ldl - SET_TARGET_PROPERTIES(${DOTNET_LAUNCHER} PROPERTIES SKIP_BUILD_RPATH TRUE - ) # remove rpath option that is automatically generated by cmake. +) # remove rpath option that is automatically generated by cmake. + +SET(NITOOL "nitool") +SET(${NITOOL}_SOURCE_FILES + util/utils.cc + installer-plugin/common.cc + installer-plugin/nitool.cc +) +ADD_EXECUTABLE(${NITOOL} ${${NITOOL}_SOURCE_FILES}) +SET_TARGET_PROPERTIES(${NITOOL} PROPERTIES COMPILE_FLAGS "-fPIE") +TARGET_LINK_LIBRARIES(${NITOOL} ${${PROJECT_NAME}_LDFLAGS} "-pie") + +SET(INSTALLER_PLUGIN "ui-application") +SET(${INSTALLER_PLUGIN}_SOURCE_FILES + util/utils.cc + installer-plugin/common.cc + installer-plugin/ui-application.cc +) +ADD_LIBRARY(${INSTALLER_PLUGIN} SHARED ${${INSTALLER_PLUGIN}_SOURCE_FILES}) +SET_TARGET_PROPERTIES(${INSTALLER_PLUGIN} PROPERTIES COMPILE_FLAGS "-fPIC") +TARGET_LINK_LIBRARIES(${INSTALLER_PLUGIN} ${${PROJECT_NAME}_LDFLAGS}) IF(NOT DEFINED NO_TIZEN) INSTALL(TARGETS ${DOTNET_LAUNCHER} DESTINATION ${BINDIR}) + INSTALL(TARGETS ${NITOOL} DESTINATION ${BINDIR}) + INSTALL(TARGETS ${INSTALLER_PLUGIN} DESTINATION ${INSTALL_PLUGIN_DIR}) INSTALL(FILES dotnet.loader DESTINATION ${LOADERDIR}) INSTALL(FILES dotnet.launcher DESTINATION ${LOADERDIR}) - INSTALL(FILES dotnet.debugger DESTINATION ${LOADERDIR}) + INSTALL(FILES dotnet.debugger DESTINATION ${LOADERDIR}) ENDIF(NOT DEFINED NO_TIZEN) diff --git a/NativeLauncher/inc/launcher.h b/NativeLauncher/inc/launcher.h deleted file mode 100644 index 399bef5..0000000 --- a/NativeLauncher/inc/launcher.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __LAUNCHER_INTERFACE_H__ -#define __LAUNCHER_INTERFACE_H__ - -#include -#include - -namespace tizen { -namespace runtime { - -class LauncherInterface -{ - public: - virtual int Initialize(bool standalone) = 0; - virtual void Dispose() = 0; - virtual int RunManagedLauncher() = 0; - virtual int Launch(const char* root, const char* path, int argc, char* argv[]) = 0; -}; - -struct AppInfo -{ - std::string root; - std::string path; - std::string id; - std::string pkg; - std::string type; -}; - -class LaunchpadAdapter -{ - public: - virtual void LoaderMain(int argc, char* argv[]) = 0; - std::function OnCreate = nullptr; - std::function OnLaunch = nullptr; - std::function OnTerminate = nullptr; -}; - -extern LaunchpadAdapter& Launchpad; - -} // namespace runtime -} // namespace tizen - -#endif // __LAUNCHER_INTERFACE_H__ diff --git a/NativeLauncher/inc/utils.h b/NativeLauncher/inc/utils.h index 145a43d..ed993fa 100644 --- a/NativeLauncher/inc/utils.h +++ b/NativeLauncher/inc/utils.h @@ -3,11 +3,16 @@ #include #include +#include #ifndef PATH_SEPARATOR #define PATH_SEPARATOR '/' #endif +bool ICompare(const std::string& a, const std::string& b); +bool ICompare(const std::string& a, int a_offset, const std::string& b, int b_offset, int length); +bool IsManagedAssembly(const std::string& filename); +bool IsNativeImage(const std::string& filename); std::string ReadSelfPath (); std::string ConcatPath (const std::string& path1, const std::string& path2); void AppendPath (std::string& path1, const std::string& path2); @@ -18,4 +23,7 @@ void AssembliesInDirectory(const std::vector& directories, std::str bool FileNotExist(const std::string& path); std::string JoinStrings(const std::vector& strings, const char* const delimeter); +typedef std::function FileReader; +void ScanFilesInDir(const char* directory, FileReader reader, unsigned int depth); + #endif // __UTILS_H__ diff --git a/NativeLauncher/installer-plugin/common.cc b/NativeLauncher/installer-plugin/common.cc new file mode 100644 index 0000000..70b963f --- /dev/null +++ b/NativeLauncher/installer-plugin/common.cc @@ -0,0 +1,292 @@ +#include +#include +#include + +#include "log.h" +#include "utils.h" +#include "pkgmgr_parser_plugin_interface.h" + +#include +#include +#include + +#include +#include + +#include "common.h" + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "NETCORE_INSTALLER_PLUGIN" + +#ifndef DEVICE_API_DIR +#error "DEVICE_API_DIR is missed" +#endif + +#ifndef RUNTIME_DIR +#error "RUNTIME_DIR is missed" +#endif + +#ifndef CROSSGEN_PATH +#error "CROSSGEN_PATH is missed" +#endif + +#define __XSTR(x) #x +#define __STR(x) __XSTR(x) +static const char* DeviceAPIDir = __STR(DEVICE_API_DIR); +static const char* RuntimeDir = __STR(RUNTIME_DIR); +static const char* CrossgenPath = __STR(CROSSGEN_PATH); +static const char* JITPath = __STR(RUNTIME_DIR)"/libclrjit.so"; +#undef __STR +#undef __XSTR + +static void crossgen(const char* dll_path, const char* app_path); +static void smack_(const char* dll_path); + +void create_ni_platform() +{ + std::string corlib = ConcatPath(RuntimeDir, "System.Private.CoreLib.dll"); + std::string nicorlib = ConcatPath(RuntimeDir, "System.Private.CoreLib.ni.dll"); + + if (FileNotExist(nicorlib)) + { + crossgen(corlib.c_str(), nullptr); + smack_(nicorlib.c_str()); + } + + const char* platform_dirs[] = {RuntimeDir, DeviceAPIDir}; + const char* ignores[] = {corlib.c_str()}; + + create_ni_under_dirs(platform_dirs, 2, ignores, 1, [](const char* ni){ + smack_(ni); + }); +} + +static void smack_(const char* dll_path) +{ + static const char* CHKSMACK = "/usr/bin/chsmack"; + pid_t pid = fork(); + if (pid == -1) + { + return; + } + + if (pid > 0) + { + int status; + waitpid(pid, &status, 0); + if (WIFEXITED(status)) + { + return; + } + } + else + { + const char* args[] = { + CHKSMACK, + "-a", "_", + dll_path, + nullptr + }; + for (const char* arg : args) + { + printf("%s ", arg); + } + printf("\n"); + + execv(CHKSMACK, const_cast(args)); + + exit(0); + } +} + +static void crossgen(const char* dll_path, const char* app_path) +{ + //pid_t parent = getpid(); + pid_t pid = fork(); + if (pid == -1) + { + return; + } + + if (pid > 0) + { + int status; + waitpid(pid, &status, 0); + if (WIFEXITED(status)) + { + return; + } + } + else + { + std::vector tpaDir = { + RuntimeDir, DeviceAPIDir + }; + std::string tpa; + AssembliesInDirectory(tpaDir, tpa); + + std::vector argv = + { + CrossgenPath, + "/Trusted_Platform_Assemblies", tpa.c_str(), + "/JITPath", JITPath, + "/FragileNonVersionable" + }; + if (app_path != nullptr) + { + argv.push_back("/App_Paths"); + argv.push_back(app_path); + } + argv.push_back(dll_path); + argv.push_back(nullptr); + + /* + for (const char* arg : argv) + { + printf("%s ", arg); + } + printf("\n"); + */ + printf("+ %s\n", dll_path); + + execv(CrossgenPath, const_cast(argv.data())); + exit(0); + } +} + +static int get_root_path(const char *pkgid, std::string& root_path) +{ + int ret = 0; + char *path = 0; + + uid_t uid = 0; + + if (pkgmgr_installer_info_get_target_uid(&uid) < 0) + { + _ERR("Failed to get UID"); + return -1; + } + + _INFO("user id is %d", uid); + + pkgmgrinfo_pkginfo_h handle; + if (uid == 0) + { + ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgid, &handle); + if (ret != PMINFO_R_OK) + return -1; + } + else + { + ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid, uid, &handle); + if (ret != PMINFO_R_OK) + return -1; + } + + ret = pkgmgrinfo_pkginfo_get_root_path(handle, &path); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_destroy_pkginfo(handle); + return -1; + } + root_path = path; + pkgmgrinfo_pkginfo_destroy_pkginfo(handle); + + return 0; +} + +static bool NIExist(const std::string& path, std::string& ni) +{ + static const char* possible_exts[] = { + ".ni.dll", ".NI.dll", ".NI.DLL", ".ni.DLL" + }; + std::string fname = path.substr(0, path.size() - 4); + + struct stat sb; + + for (const char* ext : possible_exts) + { + std::string f = fname + ext; + if (stat(f.c_str(), &sb) == 0) + { + ni = f; + return true; + } + } + + return false; +} + +void create_ni_under_dirs(const char* root_paths[], int count, const char* ignores[], int igcount, after_create cb) +{ + std::string app_paths; + for (int i=0; i + +typedef std::function after_create; +void create_ni_under_dirs(const char* root_paths[], int count, const char* ignores[], int igcount, after_create cb); +void create_ni_under_dirs(const char* root_paths[], int count, after_create cb); +void create_ni_under_dirs(const char* root_paths[], int count); +int create_ni_under_pkg_root(const char* pkg_name); +void create_ni_platform(); + +#endif // __INSTALLER_PLUGIN_COMMON_H__ diff --git a/NativeLauncher/installer-plugin/nitool.cc b/NativeLauncher/installer-plugin/nitool.cc new file mode 100644 index 0000000..1fd4c8f --- /dev/null +++ b/NativeLauncher/installer-plugin/nitool.cc @@ -0,0 +1,93 @@ +#include "common.h" + +#include +#include + +#include + +std::vector get_cmd_args(char** begin, char** end) +{ + for (char** itr = end-1; itr != begin-1; --itr) + { + if (itr != end && strncmp(*itr, "--", 2) == 0) + { + itr++; + int len = end - itr; + return std::vector(len, *itr); + } + } + return std::vector(end-begin-1, *(begin+1)); +} + +bool cmd_option_exists(char** begin, char** end, const std::string& option) +{ + return std::find(begin, end, option) != end; +} + +static void help(const char *argv0) +{ + const char* helpdesc = + "Usage: %s [args] \n" + " --help - Display this screen\n" + " --system - Create NI under System DLLs\n" + " --pkg - Create NI for package\n" + "\n" + "Example:\n" + "Create native image for dlls and exes under platform directories\n" + "%s --system\n" + "Create native image under the package's bin and lib directory\n" + "%s --pkg org.tizen.FormsGallery\n\n"; + printf(helpdesc, argv0, argv0, argv0); +} + +int main(int argc, char* argv[]) +{ + bool pkg_mode = false; + + if (cmd_option_exists(argv, argv+argc, "--help")) + { + help(argv[0]); + return 0; + } + + if (cmd_option_exists(argv, argv+argc, "--system")) + { + create_ni_platform(); + return 0; + } + + if (cmd_option_exists(argv, argv+argc, "--pkg")) + { + pkg_mode = true; + } + + std::vector args = get_cmd_args(argv, argv+argc); + + if (args.size() < 1) + { + if (pkg_mode) + fprintf(stderr, "Package name is missed\n"); + else + fprintf(stderr, "DLL path is missed\n"); + help(argv[0]); + return 1; + } + + if (pkg_mode) + { + for (const char* pkg : args) + { + if (create_ni_under_pkg_root(pkg) != 0) + { + fprintf(stderr, "Failed to get root path from [%s]\n", pkg); + return 1; + } + } + } + else + { + create_ni_under_dirs(args.data(), args.size()); + } + + return 0; +} diff --git a/NativeLauncher/installer-plugin/pkgmgr_parser_plugin_interface.h b/NativeLauncher/installer-plugin/pkgmgr_parser_plugin_interface.h new file mode 100644 index 0000000..0f2d4a8 --- /dev/null +++ b/NativeLauncher/installer-plugin/pkgmgr_parser_plugin_interface.h @@ -0,0 +1,21 @@ +#ifndef __PKGMGR_PARSER_PLUGIN_INTERFACE__ +#define __PKGMGR_PARSER_PLUGIN_INTERFACE__ + +extern "C" +{ + typedef struct _xmlDoc xmlDoc; + typedef xmlDoc* xmlDocPtr; + int PKGMGR_PARSER_PLUGIN_PRE_INSTALL (const char *pkgid); + int PKGMGR_PARSER_PLUGIN_PRE_UPGRADE (const char *pkgid); + int PKGMGR_PARSER_PLUGIN_PRE_UNINSTALL (const char *pkgid); + + int PKGMGR_PARSER_PLUGIN_INSTALL (xmlDocPtr doc, const char* pkgid); + int PKGMGR_PARSER_PLUGIN_UPGRADE (xmlDocPtr doc, const char* pkgid); + int PKGMGR_PARSER_PLUGIN_UNINSTALL (xmlDocPtr doc, const char* pkgid); + + int PKGMGR_PARSER_PLUGIN_POST_INSTALL (const char *pkgid); + int PKGMGR_PARSER_PLUGIN_POST_UPGRADE (const char *pkgid); + int PKGMGR_PARSER_PLUGIN_POST_UNINSTALL (const char *pkgid); +} + +#endif // __PKGMGR_PARSER_PLUGIN_INTERFACE__ diff --git a/NativeLauncher/installer-plugin/ui-application.cc b/NativeLauncher/installer-plugin/ui-application.cc new file mode 100644 index 0000000..c0196e3 --- /dev/null +++ b/NativeLauncher/installer-plugin/ui-application.cc @@ -0,0 +1,96 @@ +#include "common.h" +#include "log.h" + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "NETCORE_INSTALLER_PLUGIN" + +#include +#include +#include + +/* + * forked crossgen from installer is not working. + * because crossgen's capability is not enough. + * following command is needed + * + * setcap cap_dac_override=eip /opt/usr/share/dotnet.tizen/framework/crossgen + * + */ + +extern "C" int PKGMGR_PARSER_PLUGIN_POST_INSTALL (const char *pkgid) +{ + _INFO("pkg : %s", pkgid); + + uid_t uid = 0; + + if (pkgmgr_installer_info_get_target_uid(&uid) < 0) + { + _ERR("Failed to get UID"); + return 0; + } + + pkgmgrinfo_pkginfo_h handle; + int ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid, uid, &handle); + if (ret != PMINFO_R_OK) + { + _ERR("Failed to get pkg info"); + return 0; + } + + _INFO("success to get pkg info"); + + bool dotnet_exist = false; + + auto dotnet_app_counter = [] (pkgmgrinfo_appinfo_h handle, void *user_data) -> int + { + char* appid = nullptr; + char* type = nullptr; + bool* dotnet = static_cast(user_data); + + if (pkgmgrinfo_appinfo_get_appid(handle, &appid) != PMINFO_R_OK) + { + _ERR("Failed to get app id"); + return 0; + } + + _INFO("App id : %s", appid); + + if (pkgmgrinfo_appinfo_get_apptype(handle, &type) != PMINFO_R_OK) + { + _ERR("Failed to get app type : %s", appid); + return 0; + } + + _INFO("App type : %s", type); + + if (strcmp(type, "dotnet") == 0) + { + *dotnet = true; + } + + return 0; + }; + + if (pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP, dotnet_app_counter, &dotnet_exist, uid) != PMINFO_R_OK) + { + _ERR("Failed to get list of app in pkg : %s", pkgid); + return -1; + } + + _INFO("Finish to get pkg list"); + + pkgmgrinfo_pkginfo_destroy_pkginfo(handle); + if (dotnet_exist) + { + _INFO("dotnet app is exist"); + return create_ni_under_pkg_root(pkgid) == 0 ? 0 : -1; + } + + return 0; +} +extern "C" int PKGMGR_PARSER_PLUGIN_POST_UPGRADE (const char *pkgid) +{ + return PKGMGR_PARSER_PLUGIN_POST_INSTALL(pkgid); +} diff --git a/NativeLauncher/launcher/dotnet/dotnet_launcher.cc b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc new file mode 100644 index 0000000..1bfbdec --- /dev/null +++ b/NativeLauncher/launcher/dotnet/dotnet_launcher.cc @@ -0,0 +1,300 @@ + +#include + +#include +#include +#include + +#include "utils.h" +#include "log.h" +#include "launcher.h" +#include "dotnet_launcher.h" + +namespace tizen { +namespace runtime { +namespace dotnetcore { + +CoreRuntime::CoreRuntime() : + InitializeClr(nullptr), + ExecuteAssembly(nullptr), + Shutdown(nullptr), + CreateDelegate(nullptr), + coreclrLib(nullptr), + hostHandle(nullptr), + domainId(-1), + PreparedFunction(nullptr), + LaunchFunction(nullptr) +{ +#define __XSTR(x) #x +#define __STR(x) __XSTR(x) + +#ifdef DEVICE_API_DIR + DeviceAPIDirectory = __STR(DEVICE_API_DIR); +#endif +#ifdef RUNTIME_DIR + RuntimeDirectory = __STR(RUNTIME_DIR); +#endif +#ifdef CORECLR_LAUNCHER_ASSEMBLY_PATH + LauncherAssembly = __STR(CORECLR_LAUNCHER_ASSEMBLY_PATH); +#endif + +#undef __STR +#undef __XSTR + + _DBG("Constructor called!!"); +} + +CoreRuntime::~CoreRuntime() +{ + Dispose(); +} + +int CoreRuntime::Initialize(bool standalone) +{ + + if (standalone) + { + const char *_deviceapi_directory = getenv("DeviceAPIDirectory"); + const char *_runtime_directory = getenv("RuntimeDirectory"); + const char *_launcher_assembly = getenv("LauncherAssembly"); + if (_deviceapi_directory != nullptr) + DeviceAPIDirectory = _deviceapi_directory; + if (_runtime_directory != nullptr) + RuntimeDirectory = _runtime_directory; + if (_launcher_assembly != nullptr) + LauncherAssembly = _launcher_assembly; + } + + if (DeviceAPIDirectory.empty()) + { + _ERR("Empty Device API Directory"); + return 1; + } + else + { + DeviceAPIDirectory = AbsolutePath(DeviceAPIDirectory); + } + if (RuntimeDirectory.empty()) + { + _ERR("Empty Runtime Directory"); + return 1; + } + else + { + RuntimeDirectory = AbsolutePath(RuntimeDirectory); + } + if (LauncherAssembly.empty()) + { + _ERR("Empty Launcher Assembly"); + return 1; + } + else + { + LauncherAssembly = AbsolutePath(LauncherAssembly); + } + + std::string libcoreclr(ConcatPath(RuntimeDirectory, "libcoreclr.so")); + + _DBG("libcoreclr : %s", libcoreclr.c_str()); + + coreclrLib = dlopen(libcoreclr.c_str(), RTLD_NOW | RTLD_LOCAL); + if (coreclrLib == nullptr) + { + char *err = dlerror(); + _ERR("dlopen failed to open libcoreclr.so with error %s", err); + return 1; + } + +#define CORELIB_RETURN_IF_NOSYM(type, variable, name) \ + do { variable = (type)dlsym(coreclrLib, name); \ + if (variable == nullptr) { \ + _ERR(name " is not found in the libcoreclr.so"); \ + return 1; \ + }} while(0) + + CORELIB_RETURN_IF_NOSYM(coreclr_initialize_ptr, InitializeClr, "coreclr_initialize"); + CORELIB_RETURN_IF_NOSYM(coreclr_execute_assembly_ptr, ExecuteAssembly, "coreclr_execute_assembly"); + CORELIB_RETURN_IF_NOSYM(coreclr_shutdown_ptr, Shutdown, "coreclr_shutdown"); + CORELIB_RETURN_IF_NOSYM(coreclr_create_delegate_ptr, CreateDelegate, "coreclr_create_delegate"); + +#undef CORELIB_RETURN_IF_NOSYM + + _DBG("libcoreclr dlopen and dlsym success"); + + _DBG("this addr : %x", this); + _DBG("coreclr_initialize : %x", InitializeClr); + + return 0; +} + +bool CoreRuntime::InitializeCoreClr(const char* assembly_probe_paths, const char* pinvoke_probe_paths) +{ + std::vector platformDirectories = { + RuntimeDirectory, DeviceAPIDirectory + }; + + std::string trusted_assemblies; + AssembliesInDirectory(platformDirectories, trusted_assemblies); + + const char *propertyKeys[] = + { + "TRUSTED_PLATFORM_ASSEMBLIES", + "APP_PATHS", + "APP_NI_PATHS", + "NATIVE_DLL_SEARCH_DIRECTORIES", + "AppDomainCompatSwitch" + }; + + const char *propertyValues[] = + { + trusted_assemblies.c_str(), + assembly_probe_paths, + assembly_probe_paths, + pinvoke_probe_paths, + "UseLatestBehaviorWhenTFMNotSpecified" + }; + + std::string selfPath = ReadSelfPath(); + + int st = InitializeClr( + selfPath.c_str(), + "dotnet-launcher", + sizeof(propertyKeys) / sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + &hostHandle, + &domainId); + + if (st < 0) + { + _ERR("initialize core clr fail! (0x%08x)", st); + return false; + } + + _DBG("Initialize core clr success"); + return true; +} + +int CoreRuntime::RunManagedLauncher() +{ + if (FileNotExist(LauncherAssembly)) + { + _ERR("Launcher assembly is not exist in %s", LauncherAssembly.c_str()); + return 1; + } + + std::string launcherDir = Basename(LauncherAssembly); + std::vector searchDirectories = { + RuntimeDirectory, DeviceAPIDirectory + }; + + std::string trusted_directories = JoinStrings(searchDirectories, ":"); + + _DBG("coreclr_dir : %s", RuntimeDirectory.c_str()); + _DBG("native_so_search_dir : %s", trusted_directories.c_str()); + _DBG("launcher_assembly : %s", LauncherAssembly.c_str()); + _DBG("launcher_dir : %s", launcherDir.c_str()); + + if (!InitializeCoreClr(launcherDir.c_str(), launcherDir.c_str())) + { + _ERR("Failed to initialize coreclr"); + return 1; + } + + void *preparedFunctionDelegate; + int st = CreateDelegate(hostHandle, domainId, + "Tizen.Runtime.Coreclr", + "Tizen.Runtime.Coreclr.AssemblyManager", + "Prepared", &preparedFunctionDelegate); + if (st < 0) + { + _ERR("Create delegate for Launch prepared function is fail (0x%08x)", st); + return 1; + } + PreparedFunction = reinterpret_cast(preparedFunctionDelegate); + + if(PreparedFunction != nullptr) + { + PreparedFunction(); + } + + void *launchFunctionDelegate; + st = CreateDelegate(hostHandle, domainId, + "Tizen.Runtime.Coreclr", + "Tizen.Runtime.Coreclr.AssemblyManager", + "Launch", &launchFunctionDelegate); + if (st < 0) + { + _ERR("Create delegate for Launch managed function is fail! (0x%08x)", st); + return 1; + } + LaunchFunction = reinterpret_cast(launchFunctionDelegate); + + return 0; +} + +void CoreRuntime::Dispose() +{ + if (hostHandle != nullptr) + { + int st = Shutdown(hostHandle, domainId); + if (st < 0) + { + _ERR("shutdown core clr fail! (0x%08x)", st); + } + } + + if (dlclose(coreclrLib) != 0) + { + _ERR("libcoreclr.so close failed"); + } + coreclrLib = nullptr; + + _DBG("Dotnet runtime disposed"); +} + +int CoreRuntime::Launch(const char* root, const char* path, int argc, char* argv[]) +{ + if (path == nullptr) + { + _ERR("executable path is null"); + return 1; + } + + if (FileNotExist(path)) + { + _ERR("File not exist : %s", path); + return 1; + } + + bool success = false; + if (LaunchFunction != nullptr) + { + success = LaunchFunction(root, path, argc, argv); + if (!success) + { + _ERR("Failed to launch Application %s", path); + } + return success ? 0 : 1; + } + else + { + std::string appRoot = root; + std::string appBin = ConcatPath(appRoot, "bin"); + std::string appLib = ConcatPath(appRoot, "lib"); + std::string probePath = appBin + ":" + appLib; + + int st = InitializeCoreClr(probePath.c_str(), probePath.c_str()); + unsigned int ret = 0; + st = ExecuteAssembly(hostHandle, domainId, argc, (const char**)argv, path, &ret); + if (st < 0) + { + _ERR("Failed to Execute Assembly %s (0x%08x)", path, st); + } + return ret; + } +} + +} // namespace dotnetcore +} // namespace runtime +} // namespace tizen diff --git a/NativeLauncher/launcher/dotnet/dotnet_launcher.h b/NativeLauncher/launcher/dotnet/dotnet_launcher.h new file mode 100644 index 0000000..fa72e11 --- /dev/null +++ b/NativeLauncher/launcher/dotnet/dotnet_launcher.h @@ -0,0 +1,70 @@ +#include "launcher.h" + +extern "C" +{ + typedef int (*coreclr_initialize_ptr)( + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); + + typedef int (*coreclr_execute_assembly_ptr)( + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); + + typedef int (*coreclr_shutdown_ptr)( + void* hostHandle, + unsigned int domainId); + + typedef int (*coreclr_create_delegate_ptr)( + void* hostHandle, + unsigned int domainId, + const char* entryPointAssemblyName, + const char* entryPointTypeName, + const char* entryPointMethodName, + void** delegate); +} + +namespace tizen { +namespace runtime { +namespace dotnetcore { + +typedef void (*PreparedFunctionPtr)(); +typedef bool (*LaunchFunctionPtr)(const char* root, const char* path, int argc, char* argv[]); + +class CoreRuntime : public tizen::runtime::LauncherInterface +{ + public: + CoreRuntime(); + ~CoreRuntime(); + int Initialize(bool standalone) override; + void Dispose() override; + int RunManagedLauncher() override; + int Launch(const char* root, const char* path, int argc, char* argv[]) override; + + private: + bool InitializeCoreClr(const char* assembly_probe_paths, const char* pinvoke_probe_paths); + coreclr_initialize_ptr InitializeClr; + coreclr_execute_assembly_ptr ExecuteAssembly; + coreclr_shutdown_ptr Shutdown; + coreclr_create_delegate_ptr CreateDelegate; + std::string DeviceAPIDirectory; + std::string RuntimeDirectory; + std::string LauncherAssembly; + void* coreclrLib; + void* hostHandle; + unsigned int domainId; + PreparedFunctionPtr PreparedFunction; + LaunchFunctionPtr LaunchFunction; +}; + +} // dotnetcore +} // namespace runtime +} // namespace tizen diff --git a/NativeLauncher/launcher/launcher.cc b/NativeLauncher/launcher/launcher.cc new file mode 100644 index 0000000..9efd49e --- /dev/null +++ b/NativeLauncher/launcher/launcher.cc @@ -0,0 +1,171 @@ +#include "launcher.h" +#include "log.h" + +#include +#include + +#include + +#include +#include +#include + +#include + + +namespace tizen { +namespace runtime { + +struct FdHandler +{ + Ecore_Fd_Handler *handler; + loader_receiver_cb receiver; +}; + +class LaunchpadAdapterImpl : public LaunchpadAdapter +{ + public: + LaunchpadAdapterImpl() : isLaunched(false) { } + void LoaderMain(int argc, char* argv[]) override; + + std::map Handlers; + + private: + AppInfo appinfo; + loader_lifecycle_callback_s callbacks; + loader_adapter_s adapter; + LauncherInterface* launcher; + bool isLaunched; + std::string launchPath; +}; + +LaunchpadAdapterImpl LaunchpadImpl; +LaunchpadAdapter& Launchpad = LaunchpadImpl; + +#define WITH_SELF(data) \ + LaunchpadAdapterImpl* self = static_cast(data); \ + if (self == nullptr) \ + { \ + _ERR("No LaunchpadImplData"); \ + } else + +static Eina_Bool Fd_Handler(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 Fd_Add(void *data, int fd, loader_receiver_cb receiver) +{ + Ecore_Fd_Handler* handler = ecore_main_fd_handler_add(fd, + static_cast(ECORE_FD_READ | ECORE_FD_ERROR), + Fd_Handler, 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 Fd_Remove(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); + } + } +} + +void LaunchpadAdapterImpl::LoaderMain(int argc, char* argv[]) +{ + + callbacks.create = [](bundle *extra, int type, void *user_data) + { + ecore_init(); + WITH_SELF(user_data) + { + if (self->OnCreate != nullptr) + self->OnCreate(); + } + }; + callbacks.launch = [](int argc, char** argv, const char* app_path, + const char* appid, const char* pkgid, + const char* pkg_type, void* user_data) -> int + { + WITH_SELF(user_data) + { + self->appinfo.root = std::string(aul_get_app_root_path()); + self->appinfo.path = app_path; + self->appinfo.id = appid; + self->appinfo.pkg = pkgid; + self->appinfo.type = pkg_type; + if (self->OnLaunch != nullptr) + self->OnLaunch(self->appinfo, argc, argv); + } + + return 0; + }; + callbacks.terminate = [](int argc, char **argv, void* user_data) -> int + { + _DBG("Terminate!!"); + WITH_SELF(user_data) + { + 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 = Fd_Add; + adapter.remove_fd = Fd_Remove; + + _DBG("launchpad_loader_main is start"); + int r = launchpad_loader_main(argc, argv, &(this->callbacks), &(this->adapter), this); + _DBG("launchpad_loader_main is finished with [%d]", r); +} + +#undef WITH_SELF + +} // namespace runtime +} // namespace tizen diff --git a/NativeLauncher/launcher/launcher.h b/NativeLauncher/launcher/launcher.h new file mode 100644 index 0000000..399bef5 --- /dev/null +++ b/NativeLauncher/launcher/launcher.h @@ -0,0 +1,42 @@ +#ifndef __LAUNCHER_INTERFACE_H__ +#define __LAUNCHER_INTERFACE_H__ + +#include +#include + +namespace tizen { +namespace runtime { + +class LauncherInterface +{ + public: + virtual int Initialize(bool standalone) = 0; + virtual void Dispose() = 0; + virtual int RunManagedLauncher() = 0; + virtual int Launch(const char* root, const char* path, int argc, char* argv[]) = 0; +}; + +struct AppInfo +{ + std::string root; + std::string path; + std::string id; + std::string pkg; + std::string type; +}; + +class LaunchpadAdapter +{ + public: + virtual void LoaderMain(int argc, char* argv[]) = 0; + std::function OnCreate = nullptr; + std::function OnLaunch = nullptr; + std::function OnTerminate = nullptr; +}; + +extern LaunchpadAdapter& Launchpad; + +} // namespace runtime +} // namespace tizen + +#endif // __LAUNCHER_INTERFACE_H__ diff --git a/NativeLauncher/launcher/main.cc b/NativeLauncher/launcher/main.cc new file mode 100644 index 0000000..c43c299 --- /dev/null +++ b/NativeLauncher/launcher/main.cc @@ -0,0 +1,154 @@ +#include "dotnet/dotnet_launcher.h" +#include "mono/mono_launcher.h" +#include "utils.h" +#include "log.h" + +#include +#include +#include + +#include +#include +#include + +#define __XSTR(x) #x +#define __STR(x) __XSTR(x) + +#ifndef VERSION +#define LAUNCHER_VERSION_STR "-Unknown-" +#else +#define LAUNCHER_VERSION_STR __STR(VERSION) +#endif + +static std::string VersionOption("--version"); +static std::string StandaloneOption("--standalone"); + +int main(int argc, char *argv[]) +{ + int i; + bool standalone = false; + const char* standalonePath = nullptr; + + std::vector vargs; + + for (i=0; i argc-1) + { + fprintf(stderr, "Assembly path must be after \"--standalone\" option\n"); + return 1; + } + i++; + standalonePath = argv[i]; + } + else + { + vargs.push_back(argv[i]); + } + } + + using tizen::runtime::LauncherInterface; + using tizen::runtime::Launchpad; + using tizen::runtime::AppInfo; + std::unique_ptr runtime; + + bool useMono = !FileNotExist("/etc/.use_mono"); + + if (!useMono) + { + using tizen::runtime::dotnetcore::CoreRuntime; + std::unique_ptr coreRuntime(new CoreRuntime()); + runtime = std::move(coreRuntime); + + _DBG("##### CoreCLR Launcher ######"); + } + else + { + using tizen::runtime::mono::MonoRuntime; + std::unique_ptr monoRuntime(new MonoRuntime()); + runtime = std::move(monoRuntime); + + _DBG("##### Mono Launcher ######"); + } + + if (standalone) + { + _DBG("##### Run it standalone #########"); + const char* appid = getenv("AUL_APPID"); + _DBG("AUL_APPID : %s", appid); + std::string approot; + if (appid != nullptr) + { + const char* approot_path = aul_get_app_root_path(); + if (approot_path != nullptr) + { + approot = std::string(approot_path); + } + } + if (approot.empty()) + { + approot = Basename(standalonePath); + } + if (runtime->Initialize(true) != 0) + { + _ERR("Failed to initialize"); + return 1; + } + + int args_len = vargs.size(); + char** args = &vargs[0]; + if (runtime->Launch(approot.c_str(), standalonePath, args_len, args)) + { + _ERR("Failed to launch"); + return 0; + } + } + else + { + Launchpad.OnCreate = [&runtime]() + { + if (runtime->Initialize(false) != 0) + { + _ERR("Failed to initialized"); + } + else + { + auto idle_task = [](void *data) -> Eina_Bool + { + LauncherInterface* runtime = static_cast(data); + if (runtime->RunManagedLauncher() != 0) + { + _ERR("Failed to run managed launcher"); + } + return ECORE_CALLBACK_CANCEL; + }; + ecore_idler_add(idle_task, runtime.get()); + } + }; + + Launchpad.OnTerminate = [&runtime](const AppInfo& info, int argc, char** argv) + { + _DBG("terminated with app path : %s", info.path.c_str()); + _DBG("appid : %s", info.id.c_str()); + _DBG("pkg : %s", info.pkg.c_str()); + _DBG("type : %s", info.type.c_str()); + + if (runtime->Launch(info.root.c_str(), info.path.c_str(), argc, argv)) + { + _ERR("Failed to launch"); + } + }; + Launchpad.LoaderMain(argc, argv); + } + + return 0; +} diff --git a/NativeLauncher/launcher/mono/mono_launcher.cc b/NativeLauncher/launcher/mono/mono_launcher.cc new file mode 100644 index 0000000..e0d0156 --- /dev/null +++ b/NativeLauncher/launcher/mono/mono_launcher.cc @@ -0,0 +1,248 @@ + +#include "mono_launcher.h" +#include "utils.h" +#include "log.h" + +#include +#include + +namespace tizen { +namespace runtime { +namespace mono { + +static const char* DOMAIN_NAME = "tizen_mono_domain"; +static const char* LIBMONO = "/usr/lib/libmono-2.0.so.1"; + +MonoRuntime::MonoRuntime() : + monolib(nullptr), + domain(nullptr), + launch(nullptr) +{ + +#define __XSTR(x) #x +#define __STR(x) __XSTR(x) + +#ifdef MONO_LAUNCHER_ASSEMBLY_PATH + launcherAssemblyPath = __STR(MONO_LAUNCHER_ASSEMBLY_PATH); +#endif + +#ifdef DEVICE_API_DIR + deviceAPIDirectory = __STR(DEVICE_API_DIR); +#endif +#ifdef RUNTIME_DIR + runtimeDirectory = __STR(RUNTIME_DIR); +#endif + +#undef __STR +#undef __XSTR +} + +MonoRuntime::~MonoRuntime() +{ + Dispose(); +} + +int MonoRuntime::Initialize(bool standalone) +{ + if (standalone) + { + const char *_deviceapi_directory = getenv("DeviceAPIDirectory"); + const char *_runtime_directory = getenv("RuntimeDirectory"); + const char *_launcher_assembly = getenv("LauncherAssembly"); + if (_deviceapi_directory != nullptr) + deviceAPIDirectory = _deviceapi_directory; + if (_runtime_directory != nullptr) + runtimeDirectory = _runtime_directory; + if (_launcher_assembly != nullptr) + launcherAssemblyPath = _launcher_assembly; + } + + if (FileNotExist(LIBMONO)) + { + _DBG("mono is not exist in %s", LIBMONO); + return 1; + } + + monolib = dlopen(LIBMONO, RTLD_LAZY); +#define MONOLIB_RETURN_IF_NOSYM(type, variable, name) \ + do { \ + variable = (type)dlsym(monolib, name); \ + if (variable == nullptr) { \ + _ERR(name " is not found in libmono"); \ + return 1; \ + }} while(0) + + MONOLIB_RETURN_IF_NOSYM(mono_set_dirs_ptr, SetDirs, "mono_set_dirs"); + MONOLIB_RETURN_IF_NOSYM(mono_set_assemblies_path_ptr, SetAssembliesPath, "mono_set_assemblies_path"); + MONOLIB_RETURN_IF_NOSYM(mono_jit_init_ptr, JitInit, "mono_jit_init"); + MONOLIB_RETURN_IF_NOSYM(mono_domain_assembly_open_ptr, DomainAssemblyOpen, "mono_domain_assembly_open"); + MONOLIB_RETURN_IF_NOSYM(mono_assembly_get_image_ptr, AssemblyGetImage, "mono_assembly_get_image"); + MONOLIB_RETURN_IF_NOSYM(mono_class_from_name_ptr, ClassFromName, "mono_class_from_name"); + MONOLIB_RETURN_IF_NOSYM(mono_runtime_invoke_ptr, RuntimeInvoke, "mono_runtime_invoke"); + MONOLIB_RETURN_IF_NOSYM(mono_class_get_method_from_name_ptr, ClassGetMethodFromName, "mono_class_get_method_from_name"); + MONOLIB_RETURN_IF_NOSYM(mono_object_to_string_ptr, ObjectToString, "mono_object_to_string"); + MONOLIB_RETURN_IF_NOSYM(mono_string_to_utf8_ptr, StringToUtf8, "mono_string_to_utf8"); + MONOLIB_RETURN_IF_NOSYM(mono_string_new_ptr, NewString, "mono_string_new"); + MONOLIB_RETURN_IF_NOSYM(mono_get_string_class_ptr, GetStringClass, "mono_get_string_class"); + MONOLIB_RETURN_IF_NOSYM(mono_array_new_ptr, ArrayNew, "mono_array_new"); + MONOLIB_RETURN_IF_NOSYM(mono_array_addr_with_size_ptr, ArrayAddrWithSize, "mono_array_addr_with_size"); + MONOLIB_RETURN_IF_NOSYM(mono_jit_cleanup_ptr, DomainCleanup, "mono_jit_cleanup"); + MONOLIB_RETURN_IF_NOSYM(mono_jit_exec_ptr, AssemblyExec, "mono_jit_exec"); + +#undef MONOLIB_RETURN_IF_NOSYM + + _DBG("libmono dlopen and dlsym success"); + + return 0; +} + +void MonoRuntime::Dispose() +{ + if (domain != nullptr) + { + DomainCleanup(domain); + } + if (monolib != nullptr && dlclose(monolib) != 0) + { + _ERR("libmono close failed"); + } + monolib = nullptr; +} + +int MonoRuntime::RunManagedLauncher() +{ + if (FileNotExist(launcherAssemblyPath.c_str())) + { + _ERR("Launcher Assembly is not exist in %s", launcherAssemblyPath.c_str()); + return 1; + } + +// _DBG("mono_set_dirs(\"%s\", nullptr);", runtimeDirectory.c_str()); +// _DBG("mono_set_assemblies_path(\"%s\");", deviceAPIDirectory.c_str()); + +// SetDirs(runtimeDirectory.c_str(), nullptr); +/* + std::string assembliesPath = runtimeDirectory+":"+deviceAPIDirectory; + _DBG("assembliesPath : %s", assembliesPath.c_str()); + SetAssembliesPath(assembliesPath.c_str()); + */ + SetAssembliesPath(deviceAPIDirectory.c_str()); + + domain = JitInit(DOMAIN_NAME); + if (domain == nullptr) + { + _ERR("Failed to init mono jit"); + return 1; + } + + launcherAssembly = DomainAssemblyOpen(domain, launcherAssemblyPath.c_str()); + if (launcherAssembly == nullptr) + { + _ERR("Failed to Load Launcher Assembly"); + return 1; + } + + monoImage = AssemblyGetImage(launcherAssembly); + if (monoImage == nullptr) + { + _ERR("Failed to get image from launcher assembly"); + return 1; + } + + assemblyManagerClass = ClassFromName(monoImage, "Tizen.Runtime.Mono", "AssemblyManager"); + if (assemblyManagerClass == nullptr) + { + _ERR("Failed to get AssemblyManager class in namespace Tizen.Runtime.Mono from launcher image"); + return 1; + } + + prepareLaunch = ClassGetMethodFromName(assemblyManagerClass, "Prepared", 0); + if (prepareLaunch == nullptr) + { + _ERR("Failed to get Prepared() method from Tizen.Runtime.Mono.AssemblyManager"); + return 1; + } + MonoObject* exception = nullptr; + RuntimeInvoke(prepareLaunch, nullptr, nullptr, &exception); + if (exception != nullptr) + { + MonoString * exceptionMsg = ObjectToString(exception, nullptr); + char* cstringMsg = StringToUtf8(exceptionMsg); + _ERR("Failed to invoke method in runtime"); + _ERR("%s", cstringMsg); + free(cstringMsg); + return 1; + } + + launch = ClassGetMethodFromName(assemblyManagerClass, "Launch", 4); + + return 0; +} + +#define ArrayAddr(array,type,index) ((type*)(void*) ArrayAddrWithSize (array, sizeof (type), index)) +#define ArraySet(array,type,index,value) \ + do { \ + type *__p = (type *) ArrayAddr ((array), type, (index)); \ + *__p = (value); \ + } while (0) + +int MonoRuntime::Launch(const char* root, const char* path, int argc, char* argv[]) +{ + if (domain == nullptr) + { + domain = JitInit(DOMAIN_NAME); + if (domain == nullptr) + { + _ERR("Failed to init mono jit"); + return 1; + } + } + if (launch != nullptr) + { + MonoString *rootMonoString = NewString(domain, root); + MonoString *pathMonoString = NewString(domain, path); + MonoArray *argvMonoArray = ArrayNew(domain, GetStringClass(), argc); + for (int i=0; i + +#ifndef NO_TIZEN +#include +#include +#endif + +#include +#include +#include +#include + +#include + +#include "waiter.h" +#include "log.h" + +namespace dotnet { +namespace runtime { + +struct FdHandler +{ + pollfd *info; + Receiver receiver; +}; + +static volatile bool Waiting_; +static std::vector Fdlist_; +static std::map Handlers_; +static Waiter::AppInfo AppInfo_; + +void Waiter::OnPrepared() +{ + if (!context.Prepare()) + { + _DBG("Fail to Prepare..."); + } +} + +void Waiter::OnRequested(const AppInfo& info) +{ + // do some job on user id is still system + + if (!context.Request()) + { + _DBG("Fail to Request..."); + } +} + +void Waiter::OnExecuted(const char *path, const char *app_root, int argc, char *argv[]) +{ + if (!context.Execute(path, app_root, argc, argv)) + { + _DBG("Fail to Execute..."); + } +} + +void Waiter::OnWaiting() +{ + // Start the loop + Waiting_ = true; + + _DBG("start polling..."); + while (Waiting_) + { + if (poll(Fdlist_.data(), Fdlist_.size(), -1) < 0) + continue; + + for (auto &p : Fdlist_) + { + if ( (p.revents | POLLIN) != 0 ) + Handlers_[p.fd].receiver(p.fd); + } + } + _DBG("end polling..."); +} + +void Waiter::Stop() +{ + // Stop the loop + + Waiting_ = false; +} + + +void Waiter::RegisterFd(int fd, Receiver receiver) +{ + // register fd should be caught in event loop + + _DBG("Register fd %d", fd); + + pollfd info; + info.fd = fd; + info.events = POLLIN; + info.revents = 0; + + FdHandler handler; + Fdlist_.push_back(info); + handler.info = &Fdlist_.back(); + handler.receiver = receiver; + + Handlers_[fd] = handler; +} + +void Waiter::DeregisterFd(int fd) +{ + // deregister fd should be caught in event loop + + pollfd *info = Handlers_[fd].info; + Fdlist_.erase(Fdlist_.begin() - (info - &Fdlist_.front())); + Handlers_.erase(fd); +} + +int Waiter::WaitToLaunching(int argc, char *argv[]) +{ +#ifndef NO_TIZEN + auto on_create = [](bundle *extra, int type, void *user_data) + { + _DBG("on_create..."); // XXX + Waiter* waiter = static_cast(user_data); + waiter->OnPrepared(); + }; + + auto on_launch = [](int argc, char **argv, const char *app_path, + const char *appid, const char *pkgid, + const char *pkg_type, void *user_data) -> int + { + _DBG("on_launch..."); // XXX + Waiter* waiter = static_cast(user_data); + + _DBG ("app path : %s", app_path); + _DBG ("app id : %s", appid); + _DBG ("pkg id : %s", pkgid); + _DBG ("pkg type : %s", pkg_type); + + AppInfo info = { + AppPath : app_path, + AppId : appid, + PkgId : pkgid, + PkgType : pkg_type + }; + + waiter->OnRequested(info); + return 0; + }; + + auto on_terminate = [](int argc, char **argv, void *user_data) -> int + { + _DBG("on_terminate..."); // XXX + + string app_root(aul_get_app_root_path()); + Waiter* waiter = static_cast(user_data); + waiter->OnExecuted(argv[0], app_root.c_str(), argc, argv); + return 0; + }; + + auto on_start_loop = [](void *user_data) + { + _DBG("on_start_loop..."); // XXX + Waiter* waiter = static_cast(user_data); + waiter->OnWaiting(); + }; + + auto on_quit_loop = [](void *user_data) + { + _DBG("on_quit_loop..."); // XXX + Waiter* waiter = static_cast(user_data); + waiter->Stop(); + }; + + auto on_add_fd = [](void *user_data, int fd, loader_receiver_cb receiver) + { + _DBG("on_add_fd..."); // XXX + Waiter* waiter = static_cast(user_data); + waiter->RegisterFd(fd, receiver); + }; + + auto on_remove_fd = [](void *user_data, int fd) + { + _DBG("on_remove_fd..."); // XXX + Waiter* waiter = static_cast(user_data); + waiter->DeregisterFd(fd); + }; + + _DBG("launcher wait..."); // XXX + loader_lifecycle_callback_s callbacks = { + .create = on_create, + .launch = on_launch, + .terminate = on_terminate + }; + + loader_adapter_s adapter = { + .loop_begin = on_start_loop, + .loop_quit = on_quit_loop, + .add_fd = on_add_fd, + .remove_fd = on_remove_fd + }; + + return launchpad_loader_main(argc, argv, &callbacks, &adapter, this); +#else + if (argc < 2) + { + _DBG("not enough args : %d", argc); + return -1; + } + _DBG("argv[1] = %s", argv[1]); + std::string app_path(argv[1]); + std::string app_root; + auto pos = app_path.find_last_of('/'); + if (pos != std::string::npos) + app_root = app_path.substr(0, pos); + else + app_root = "."; + + this->OnPrepared(); + AppInfo info = { + AppPath : argv[1], + AppId : "", + PkgId : "", + PkgType : "" + }; + this->OnRequested(info); + this->OnExecuted(app_path.c_str(), app_root.c_str(), argc, argv); +#endif +} + +void Waiter::SetContext(WaiterContext ctx) +{ + context = ctx; +} + +WaiterContext::WaiterContext() +{ + Step = Status::Started; +} + +bool WaiterContext::Prepare() +{ + if (Step == Status::Started && Prepared != nullptr && Prepared(Data) == 0) + { + Step = Status::Prepared; + return true; + } + return false; +} + +bool WaiterContext::Request() +{ + if (Step == Status::Prepared && Requested != nullptr && Requested(Data) == 0) + { + Step = Status::Requested; + return true; + } + return false; +} + +bool WaiterContext::Execute(const char *path, const char *app_root, int argc, char *argv[]) +{ + if (Step == Status::Requested && Executed != nullptr && + Executed(path, app_root, argc, argv, Data) == 0) + { + Step = Status::Executed; + return true; + } + return false; +} + +} // namespace runtime +} // namespace dotnet + +using dotnet::runtime::Waiter; +using dotnet::runtime::WaiterContext; + +static Waiter waiter; + +void register_launching_callback(prepared_callback prepared, + requested_callback requested, executed_callback executed, void *data) +{ + WaiterContext context; + context.Prepared = prepared; + context.Requested = requested; + context.Executed = executed; + context.Data = data; + + waiter.SetContext(context); +} + +void wait_for_launching(int argc, char *argv[]) +{ + _DBG("wait_for_launching..."); + + waiter.WaitToLaunching(argc, argv); +} + diff --git a/NativeLauncher/launcher/waiter/waiter.h b/NativeLauncher/launcher/waiter/waiter.h new file mode 100644 index 0000000..c4b98fb --- /dev/null +++ b/NativeLauncher/launcher/waiter/waiter.h @@ -0,0 +1,77 @@ +#include +#include + +#include + +extern "C" { + typedef int (*prepared_callback)(void *data); + typedef int (*requested_callback)(void *data); + typedef int (*executed_callback)(const char* path, const char* app_root, int argc, char *argv[], void *data); + + void register_launching_callback(prepared_callback prepared, + requested_callback requested, executed_callback executed, void *data); + void wait_for_launching(int argc, char *argv[]); +} + +namespace dotnet { +namespace runtime { + +using std::string; +using Receiver = std::function; + +enum Status +{ + Started, + Prepared, + Requested, + Executed +}; + +class WaiterContext +{ + public: + prepared_callback Prepared; + requested_callback Requested; + executed_callback Executed; + + void *Data; + + WaiterContext(); + bool Prepare(); + bool Request(); + bool Execute(const char *path, const char *app_root, int argc, char *argv[]); + + private: + Status Step; +}; + +class Waiter +{ + public: + struct AppInfo + { + string AppPath; + string AppId; + string PkgId; + string PkgType; + }; + + int WaitToLaunching(int argc, char *argv[]); + void Stop(); + + void RegisterFd(int fd, Receiver receiver); + void DeregisterFd(int fd); + void SetContext(WaiterContext ctx); + + protected: + void OnPrepared(); + void OnRequested(const AppInfo&); + void OnWaiting(); + void OnExecuted(const char *path, const char *app_root, int argc, char *argv[]); + + private: + WaiterContext context; +}; + +} // namespace runtime +} // namespace dotnet diff --git a/NativeLauncher/src/dotnet/dotnet_launcher.cc b/NativeLauncher/src/dotnet/dotnet_launcher.cc deleted file mode 100644 index ce880a9..0000000 --- a/NativeLauncher/src/dotnet/dotnet_launcher.cc +++ /dev/null @@ -1,300 +0,0 @@ - -#include - -#include -#include -#include - -#include "utils.h" -#include "log.h" -#include "launcher.h" -#include "dotnet_launcher.h" - -namespace tizen { -namespace runtime { -namespace dotnetcore { - -CoreRuntime::CoreRuntime() : - coreclrLib(nullptr), - hostHandle(nullptr), - domainId(-1), - PreparedFunction(nullptr), - LaunchFunction(nullptr), - InitializeClr(nullptr), - ExecuteAssembly(nullptr), - Shutdown(nullptr), - CreateDelegate(nullptr) -{ -#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 CORECLR_LAUNCHER_ASSEMBLY_PATH - LauncherAssembly = __STR(CORECLR_LAUNCHER_ASSEMBLY_PATH); -#endif - -#undef __STR -#undef __XSTR - - _DBG("Constructor called!!"); -} - -CoreRuntime::~CoreRuntime() -{ - Dispose(); -} - -int CoreRuntime::Initialize(bool standalone) -{ - - if (standalone) - { - const char *_deviceapi_directory = getenv("DeviceAPIDirectory"); - const char *_runtime_directory = getenv("RuntimeDirectory"); - const char *_launcher_assembly = getenv("LauncherAssembly"); - if (_deviceapi_directory != nullptr) - DeviceAPIDirectory = _deviceapi_directory; - if (_runtime_directory != nullptr) - RuntimeDirectory = _runtime_directory; - if (_launcher_assembly != nullptr) - LauncherAssembly = _launcher_assembly; - } - - if (DeviceAPIDirectory.empty()) - { - _ERR("Empty Device API Directory"); - return 1; - } - else - { - DeviceAPIDirectory = AbsolutePath(DeviceAPIDirectory); - } - if (RuntimeDirectory.empty()) - { - _ERR("Empty Runtime Directory"); - return 1; - } - else - { - RuntimeDirectory = AbsolutePath(RuntimeDirectory); - } - if (LauncherAssembly.empty()) - { - _ERR("Empty Launcher Assembly"); - return 1; - } - else - { - LauncherAssembly = AbsolutePath(LauncherAssembly); - } - - std::string libcoreclr(ConcatPath(RuntimeDirectory, "libcoreclr.so")); - - _DBG("libcoreclr : %s", libcoreclr.c_str()); - - coreclrLib = dlopen(libcoreclr.c_str(), RTLD_NOW | RTLD_LOCAL); - if (coreclrLib == nullptr) - { - char *err = dlerror(); - _ERR("dlopen failed to open libcoreclr.so with error %s", err); - return 1; - } - -#define CORELIB_RETURN_IF_NOSYM(type, variable, name) \ - do { variable = (type)dlsym(coreclrLib, name); \ - if (variable == nullptr) { \ - _ERR(name " is not found in the libcoreclr.so"); \ - return 1; \ - }} while(0) - - CORELIB_RETURN_IF_NOSYM(coreclr_initialize_ptr, InitializeClr, "coreclr_initialize"); - CORELIB_RETURN_IF_NOSYM(coreclr_execute_assembly_ptr, ExecuteAssembly, "coreclr_execute_assembly"); - CORELIB_RETURN_IF_NOSYM(coreclr_shutdown_ptr, Shutdown, "coreclr_shutdown"); - CORELIB_RETURN_IF_NOSYM(coreclr_create_delegate_ptr, CreateDelegate, "coreclr_create_delegate"); - -#undef CORELIB_RETURN_IF_NOSYM - - _DBG("libcoreclr dlopen and dlsym success"); - - _DBG("this addr : %x", this); - _DBG("coreclr_initialize : %x", InitializeClr); - - return 0; -} - -bool CoreRuntime::InitializeCoreClr(const char* assembly_probe_paths, const char* pinvoke_probe_paths) -{ - std::vector platformDirectories = { - RuntimeDirectory, DeviceAPIDirectory - }; - - std::string trusted_assemblies; - AssembliesInDirectory(platformDirectories, trusted_assemblies); - - const char *propertyKeys[] = - { - "TRUSTED_PLATFORM_ASSEMBLIES", - "APP_PATHS", - "APP_NI_PATHS", - "NATIVE_DLL_SEARCH_DIRECTORIES", - "AppDomainCompatSwitch" - }; - - const char *propertyValues[] = - { - trusted_assemblies.c_str(), - assembly_probe_paths, - assembly_probe_paths, - pinvoke_probe_paths, - "UseLatestBehaviorWhenTFMNotSpecified" - }; - - std::string selfPath = ReadSelfPath(); - - int st = InitializeClr( - selfPath.c_str(), - "dotnet-launcher", - sizeof(propertyKeys) / sizeof(propertyKeys[0]), - propertyKeys, - propertyValues, - &hostHandle, - &domainId); - - if (st < 0) - { - _ERR("initialize core clr fail! (0x%08x)", st); - return false; - } - - _DBG("Initialize core clr success"); - return true; -} - -int CoreRuntime::RunManagedLauncher() -{ - if (FileNotExist(LauncherAssembly)) - { - _ERR("Launcher assembly is not exist in %s", LauncherAssembly.c_str()); - return 1; - } - - std::string launcherDir = Basename(LauncherAssembly); - std::vector searchDirectories = { - RuntimeDirectory, DeviceAPIDirectory - }; - - std::string trusted_directories = JoinStrings(searchDirectories, ":"); - - _DBG("coreclr_dir : %s", RuntimeDirectory.c_str()); - _DBG("native_so_search_dir : %s", trusted_directories.c_str()); - _DBG("launcher_assembly : %s", LauncherAssembly.c_str()); - _DBG("launcher_dir : %s", launcherDir.c_str()); - - if (!InitializeCoreClr(launcherDir.c_str(), launcherDir.c_str())) - { - _ERR("Failed to initialize coreclr"); - return 1; - } - - void *preparedFunctionDelegate; - int st = CreateDelegate(hostHandle, domainId, - "Tizen.Runtime.Coreclr", - "Tizen.Runtime.Coreclr.AssemblyManager", - "Prepared", &preparedFunctionDelegate); - if (st < 0) - { - _ERR("Create delegate for Launch prepared function is fail (0x%08x)", st); - return 1; - } - PreparedFunction = reinterpret_cast(preparedFunctionDelegate); - - if(PreparedFunction != nullptr) - { - PreparedFunction(); - } - - void *launchFunctionDelegate; - st = CreateDelegate(hostHandle, domainId, - "Tizen.Runtime.Coreclr", - "Tizen.Runtime.Coreclr.AssemblyManager", - "Launch", &launchFunctionDelegate); - if (st < 0) - { - _ERR("Create delegate for Launch managed function is fail! (0x%08x)", st); - return 1; - } - LaunchFunction = reinterpret_cast(launchFunctionDelegate); - - return 0; -} - -void CoreRuntime::Dispose() -{ - if (hostHandle != nullptr) - { - int st = Shutdown(hostHandle, domainId); - if (st < 0) - { - _ERR("shutdown core clr fail! (0x%08x)", st); - } - } - - if (dlclose(coreclrLib) != 0) - { - _ERR("libcoreclr.so close failed"); - } - coreclrLib = nullptr; - - _DBG("Dotnet runtime disposed"); -} - -int CoreRuntime::Launch(const char* root, const char* path, int argc, char* argv[]) -{ - if (path == nullptr) - { - _ERR("executable path is null"); - return 1; - } - - if (FileNotExist(path)) - { - _ERR("File not exist : %s", path); - return 1; - } - - bool success = false; - if (LaunchFunction != nullptr) - { - success = LaunchFunction(root, path, argc, argv); - if (!success) - { - _ERR("Failed to launch Application %s", path); - } - return success ? 0 : 1; - } - else - { - std::string appRoot = root; - std::string appBin = ConcatPath(appRoot, "bin"); - std::string appLib = ConcatPath(appRoot, "lib"); - std::string probePath = appBin + ":" + appLib; - - int st = InitializeCoreClr(probePath.c_str(), probePath.c_str()); - unsigned int ret = 0; - st = ExecuteAssembly(hostHandle, domainId, argc, (const char**)argv, path, &ret); - if (st < 0) - { - _ERR("Failed to Execute Assembly %s (0x%08x)", path, st); - } - return ret; - } -} - -} // namespace dotnetcore -} // namespace runtime -} // namespace tizen diff --git a/NativeLauncher/src/dotnet/dotnet_launcher.h b/NativeLauncher/src/dotnet/dotnet_launcher.h deleted file mode 100644 index fa72e11..0000000 --- a/NativeLauncher/src/dotnet/dotnet_launcher.h +++ /dev/null @@ -1,70 +0,0 @@ -#include "launcher.h" - -extern "C" -{ - typedef int (*coreclr_initialize_ptr)( - const char* exePath, - const char* appDomainFriendlyName, - int propertyCount, - const char** propertyKeys, - const char** propertyValues, - void** hostHandle, - unsigned int* domainId); - - typedef int (*coreclr_execute_assembly_ptr)( - void* hostHandle, - unsigned int domainId, - int argc, - const char** argv, - const char* managedAssemblyPath, - unsigned int* exitCode); - - typedef int (*coreclr_shutdown_ptr)( - void* hostHandle, - unsigned int domainId); - - typedef int (*coreclr_create_delegate_ptr)( - void* hostHandle, - unsigned int domainId, - const char* entryPointAssemblyName, - const char* entryPointTypeName, - const char* entryPointMethodName, - void** delegate); -} - -namespace tizen { -namespace runtime { -namespace dotnetcore { - -typedef void (*PreparedFunctionPtr)(); -typedef bool (*LaunchFunctionPtr)(const char* root, const char* path, int argc, char* argv[]); - -class CoreRuntime : public tizen::runtime::LauncherInterface -{ - public: - CoreRuntime(); - ~CoreRuntime(); - int Initialize(bool standalone) override; - void Dispose() override; - int RunManagedLauncher() override; - int Launch(const char* root, const char* path, int argc, char* argv[]) override; - - private: - bool InitializeCoreClr(const char* assembly_probe_paths, const char* pinvoke_probe_paths); - coreclr_initialize_ptr InitializeClr; - coreclr_execute_assembly_ptr ExecuteAssembly; - coreclr_shutdown_ptr Shutdown; - coreclr_create_delegate_ptr CreateDelegate; - std::string DeviceAPIDirectory; - std::string RuntimeDirectory; - std::string LauncherAssembly; - void* coreclrLib; - void* hostHandle; - unsigned int domainId; - PreparedFunctionPtr PreparedFunction; - LaunchFunctionPtr LaunchFunction; -}; - -} // dotnetcore -} // namespace runtime -} // namespace tizen diff --git a/NativeLauncher/src/launcher.cc b/NativeLauncher/src/launcher.cc deleted file mode 100644 index 9efd49e..0000000 --- a/NativeLauncher/src/launcher.cc +++ /dev/null @@ -1,171 +0,0 @@ -#include "launcher.h" -#include "log.h" - -#include -#include - -#include - -#include -#include -#include - -#include - - -namespace tizen { -namespace runtime { - -struct FdHandler -{ - Ecore_Fd_Handler *handler; - loader_receiver_cb receiver; -}; - -class LaunchpadAdapterImpl : public LaunchpadAdapter -{ - public: - LaunchpadAdapterImpl() : isLaunched(false) { } - void LoaderMain(int argc, char* argv[]) override; - - std::map Handlers; - - private: - AppInfo appinfo; - loader_lifecycle_callback_s callbacks; - loader_adapter_s adapter; - LauncherInterface* launcher; - bool isLaunched; - std::string launchPath; -}; - -LaunchpadAdapterImpl LaunchpadImpl; -LaunchpadAdapter& Launchpad = LaunchpadImpl; - -#define WITH_SELF(data) \ - LaunchpadAdapterImpl* self = static_cast(data); \ - if (self == nullptr) \ - { \ - _ERR("No LaunchpadImplData"); \ - } else - -static Eina_Bool Fd_Handler(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 Fd_Add(void *data, int fd, loader_receiver_cb receiver) -{ - Ecore_Fd_Handler* handler = ecore_main_fd_handler_add(fd, - static_cast(ECORE_FD_READ | ECORE_FD_ERROR), - Fd_Handler, 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 Fd_Remove(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); - } - } -} - -void LaunchpadAdapterImpl::LoaderMain(int argc, char* argv[]) -{ - - callbacks.create = [](bundle *extra, int type, void *user_data) - { - ecore_init(); - WITH_SELF(user_data) - { - if (self->OnCreate != nullptr) - self->OnCreate(); - } - }; - callbacks.launch = [](int argc, char** argv, const char* app_path, - const char* appid, const char* pkgid, - const char* pkg_type, void* user_data) -> int - { - WITH_SELF(user_data) - { - self->appinfo.root = std::string(aul_get_app_root_path()); - self->appinfo.path = app_path; - self->appinfo.id = appid; - self->appinfo.pkg = pkgid; - self->appinfo.type = pkg_type; - if (self->OnLaunch != nullptr) - self->OnLaunch(self->appinfo, argc, argv); - } - - return 0; - }; - callbacks.terminate = [](int argc, char **argv, void* user_data) -> int - { - _DBG("Terminate!!"); - WITH_SELF(user_data) - { - 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 = Fd_Add; - adapter.remove_fd = Fd_Remove; - - _DBG("launchpad_loader_main is start"); - int r = launchpad_loader_main(argc, argv, &(this->callbacks), &(this->adapter), this); - _DBG("launchpad_loader_main is finished with [%d]", r); -} - -#undef WITH_SELF - -} // namespace runtime -} // namespace tizen diff --git a/NativeLauncher/src/main.cc b/NativeLauncher/src/main.cc deleted file mode 100644 index 18085b7..0000000 --- a/NativeLauncher/src/main.cc +++ /dev/null @@ -1,152 +0,0 @@ -#include "dotnet/dotnet_launcher.h" -#include "mono/mono_launcher.h" -#include "utils.h" -#include "log.h" - -#include -#include -#include - -#include -#include -#include - -#define __XSTR(x) #x -#define __STR(x) __XSTR(x) - -#ifndef VERSION -#define LAUNCHER_VERSION_STR "-Unknown-" -#else -#define LAUNCHER_VERSION_STR __STR(VERSION) -#endif - -static std::string VersionOption("--version"); -static std::string StandaloneOption("--standalone"); - -int main(int argc, char *argv[]) -{ - int i; - bool standalone = false; - const char* standalonePath = nullptr; - - std::vector vargs; - - for (i=0; i argc-1) - { - fprintf(stderr, "Assembly path must be after \"--standalone\" option\n"); - return 1; - } - i++; - standalonePath = argv[i]; - } - else - { - vargs.push_back(argv[i]); - } - } - - using tizen::runtime::LauncherInterface; - using tizen::runtime::Launchpad; - using tizen::runtime::AppInfo; - std::unique_ptr runtime; - - bool useMono = !FileNotExist("/etc/.use_mono"); - - if (!useMono) - { - using tizen::runtime::dotnetcore::CoreRuntime; - std::unique_ptr coreRuntime(new CoreRuntime()); - runtime = std::move(coreRuntime); - - _DBG("##### CoreCLR Launcher ######"); - } - else - { - using tizen::runtime::mono::MonoRuntime; - std::unique_ptr monoRuntime(new MonoRuntime()); - runtime = std::move(monoRuntime); - - _DBG("##### Mono Launcher ######"); - } - - if (standalone) - { - _DBG("##### Run it standalone #########"); - const char* appid = getenv("AUL_APPID"); - _DBG("AUL_APPID : %s", appid); - std::string approot; - if (appid != nullptr) - { - const char* approot_path = aul_get_app_root_path(); - if (approot_path != nullptr) - { - approot = std::string(approot_path); - } - } - if (approot.empty()) - { - approot = Basename(standalonePath); - } - if (runtime->Initialize(true) != 0) - { - _ERR("Failed to initialize"); - return 1; - } - - int args_len = vargs.size(); - char** args = &vargs[0]; - if (runtime->Launch(approot.c_str(), standalonePath, args_len, args)) - { - _ERR("Failed to launch"); - return 0; - } - } - else - { - Launchpad.OnCreate = [&runtime] - { - auto idle_task = [](void *data) -> Eina_Bool - { - LauncherInterface* runtime = static_cast(data); - if (runtime->RunManagedLauncher() != 0) - { - _ERR("Failed to run managed launcher"); - } - return ECORE_CALLBACK_CANCEL; - }; - if (runtime->Initialize(false) != 0) - { - _ERR("Failed to initialized"); - return 1; - } - ecore_idler_add(idle_task, runtime.get()); - }; - - Launchpad.OnTerminate = [&runtime](const AppInfo& info, int argc, char** argv) - { - _DBG("terminated with app path : %s", info.path.c_str()); - _DBG("appid : %s", info.id.c_str()); - _DBG("pkg : %s", info.pkg.c_str()); - _DBG("type : %s", info.type.c_str()); - - if (runtime->Launch(info.root.c_str(), info.path.c_str(), argc, argv)) - { - _ERR("Failed to launch"); - } - }; - Launchpad.LoaderMain(argc, argv); - } - - return 0; -} diff --git a/NativeLauncher/src/mono/mono_launcher.cc b/NativeLauncher/src/mono/mono_launcher.cc deleted file mode 100644 index 8636447..0000000 --- a/NativeLauncher/src/mono/mono_launcher.cc +++ /dev/null @@ -1,248 +0,0 @@ - -#include "mono_launcher.h" -#include "utils.h" -#include "log.h" - -#include -#include - -namespace tizen { -namespace runtime { -namespace mono { - -static const char* DOMAIN_NAME = "tizen_mono_domain"; -static const char* LIBMONO = "/usr/lib/libmono-2.0.so.1"; - -MonoRuntime::MonoRuntime() : - monolib(nullptr), - domain(nullptr), - launch(nullptr) -{ - -#define __XSTR(x) #x -#define __STR(x) __XSTR(x) - -#ifdef MONO_LAUNCHER_ASSEMBLY_PATH - launcherAssemblyPath = __STR(MONO_LAUNCHER_ASSEMBLY_PATH); -#endif - -#ifdef DEVICE_API_DIR - deviceAPIDirectory = __STR(DEVICE_API_DIR); -#endif -#ifdef RUNTIME_DIR - runtimeDirectory = __STR(RUNTIME_DIR); -#endif - -#undef __STR -#undef __XSTR -} - -MonoRuntime::~MonoRuntime() -{ - Dispose(); -} - -int MonoRuntime::Initialize(bool standalone) -{ - if (standalone) - { - const char *_deviceapi_directory = getenv("DeviceAPIDirectory"); - const char *_runtime_directory = getenv("RuntimeDirectory"); - const char *_launcher_assembly = getenv("LauncherAssembly"); - if (_deviceapi_directory != nullptr) - deviceAPIDirectory = _deviceapi_directory; - if (_runtime_directory != nullptr) - runtimeDirectory = _runtime_directory; - if (_launcher_assembly != nullptr) - launcherAssemblyPath = _launcher_assembly; - } - - if (FileNotExist(LIBMONO)) - { - _DBG("mono is not exist in %s", LIBMONO); - return 1; - } - - monolib = dlopen(LIBMONO, RTLD_LAZY); -#define MONOLIB_RETURN_IF_NOSYM(type, variable, name) \ - do { \ - variable = (type)dlsym(monolib, name); \ - if (variable == nullptr) { \ - _ERR(name " is not found in libmono"); \ - return 1; \ - }} while(0) - - MONOLIB_RETURN_IF_NOSYM(mono_set_dirs_ptr, SetDirs, "mono_set_dirs"); - MONOLIB_RETURN_IF_NOSYM(mono_set_assemblies_path_ptr, SetAssembliesPath, "mono_set_assemblies_path"); - MONOLIB_RETURN_IF_NOSYM(mono_jit_init_ptr, JitInit, "mono_jit_init"); - MONOLIB_RETURN_IF_NOSYM(mono_domain_assembly_open_ptr, DomainAssemblyOpen, "mono_domain_assembly_open"); - MONOLIB_RETURN_IF_NOSYM(mono_assembly_get_image_ptr, AssemblyGetImage, "mono_assembly_get_image"); - MONOLIB_RETURN_IF_NOSYM(mono_class_from_name_ptr, ClassFromName, "mono_class_from_name"); - MONOLIB_RETURN_IF_NOSYM(mono_runtime_invoke_ptr, RuntimeInvoke, "mono_runtime_invoke"); - MONOLIB_RETURN_IF_NOSYM(mono_class_get_method_from_name_ptr, ClassGetMethodFromName, "mono_class_get_method_from_name"); - MONOLIB_RETURN_IF_NOSYM(mono_object_to_string_ptr, ObjectToString, "mono_object_to_string"); - MONOLIB_RETURN_IF_NOSYM(mono_string_to_utf8_ptr, StringToUtf8, "mono_string_to_utf8"); - MONOLIB_RETURN_IF_NOSYM(mono_string_new_ptr, NewString, "mono_string_new"); - MONOLIB_RETURN_IF_NOSYM(mono_get_string_class_ptr, GetStringClass, "mono_get_string_class"); - MONOLIB_RETURN_IF_NOSYM(mono_array_new_ptr, ArrayNew, "mono_array_new"); - MONOLIB_RETURN_IF_NOSYM(mono_array_addr_with_size_ptr, ArrayAddrWithSize, "mono_array_addr_with_size"); - MONOLIB_RETURN_IF_NOSYM(mono_jit_cleanup_ptr, DomainCleanup, "mono_jit_cleanup"); - MONOLIB_RETURN_IF_NOSYM(mono_jit_exec_ptr, AssemblyExec, "mono_jit_exec"); - -#undef MONOLIB_RETURN_IF_NOSYM - - _DBG("libmono dlopen and dlsym success"); - - return 0; -} - -void MonoRuntime::Dispose() -{ - if (domain != nullptr) - { - DomainCleanup(domain); - } - if (monolib != nullptr && dlclose(monolib) != 0) - { - _ERR("libmono close failed"); - } - monolib = nullptr; -} - -int MonoRuntime::RunManagedLauncher() -{ - if (FileNotExist(launcherAssemblyPath.c_str())) - { - _ERR("Launcher Assembly is not exist in %s", launcherAssemblyPath.c_str()); - return 1; - } - -// _DBG("mono_set_dirs(\"%s\", nullptr);", runtimeDirectory.c_str()); -// _DBG("mono_set_assemblies_path(\"%s\");", deviceAPIDirectory.c_str()); - -// SetDirs(runtimeDirectory.c_str(), nullptr); -/* - std::string assembliesPath = runtimeDirectory+":"+deviceAPIDirectory; - _DBG("assembliesPath : %s", assembliesPath.c_str()); - SetAssembliesPath(assembliesPath.c_str()); - */ - SetAssembliesPath(deviceAPIDirectory.c_str()); - - domain = JitInit(DOMAIN_NAME); - if (domain == nullptr) - { - _ERR("Failed to init mono jit"); - return 1; - } - - launcherAssembly = DomainAssemblyOpen(domain, launcherAssemblyPath.c_str()); - if (launcherAssembly == nullptr) - { - _ERR("Failed to Load Launcher Assembly"); - return 1; - } - - monoImage = AssemblyGetImage(launcherAssembly); - if (monoImage == nullptr) - { - _ERR("Failed to get image from launcher assembly"); - return 1; - } - - assemblyManagerClass = ClassFromName(monoImage, "Tizen.Runtime.Mono", "AssemblyManager"); - if (assemblyManagerClass == nullptr) - { - _ERR("Failed to get AssemblyManager class in namespace Tizen.Runtime.Mono from launcher image"); - return 1; - } - - prepareLaunch = ClassGetMethodFromName(assemblyManagerClass, "Prepared", 0); - if (prepareLaunch == nullptr) - { - _ERR("Failed to get Prepared() method from Tizen.Runtime.Mono.AssemblyManager"); - return 1; - } - MonoObject* exception = nullptr; - RuntimeInvoke(prepareLaunch, nullptr, nullptr, &exception); - if (exception != nullptr) - { - MonoString * exceptionMsg = ObjectToString(exception, nullptr); - char* cstringMsg = StringToUtf8(exceptionMsg); - _ERR("Failed to invoke method in runtime"); - _ERR("%s", cstringMsg); - free(cstringMsg); - return 1; - } - - launch = ClassGetMethodFromName(assemblyManagerClass, "Launch", 4); - - return 0; -} - -#define ArrayAddr(array,type,index) ((type*)(void*) ArrayAddrWithSize (array, sizeof (type), index)) -#define ArraySet(array,type,index,value) \ - do { \ - type *__p = (type *) ArrayAddr ((array), type, (index)); \ - *__p = (value); \ - } while (0) - -int MonoRuntime::Launch(const char* root, const char* path, int argc, char* argv[]) -{ - if (domain == nullptr) - { - domain = JitInit(DOMAIN_NAME); - if (domain == nullptr) - { - _ERR("Failed to init mono jit"); - return 1; - } - } - if (launch != nullptr) - { - MonoString *rootMonoString = NewString(domain, root); - MonoString *pathMonoString = NewString(domain, path); - MonoArray *argvMonoArray = ArrayNew(domain, GetStringClass(), argc); - for (int i=0; i -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "utils.h" - -std::string ReadSelfPath() -{ - char buff[PATH_MAX]; - ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1); - if (len != -1) { - buff[len] = '\0'; - return std::string(buff); - } - - return ""; -} - -std::string ConcatPath(const std::string& path1, const std::string& path2) -{ - std::string path(path1); - if (path.back() == PATH_SEPARATOR) - { - path.append(path2); - } - else - { - path += PATH_SEPARATOR; - path.append(path2); - } - - return path; -} - -void AppendPath(std::string& path1, const std::string& path2) -{ - if (path1.back() == PATH_SEPARATOR) - { - path1.append(path2); - } - else - { - path1 += PATH_SEPARATOR; - path1.append(path2); - } -} - -std::string AbsolutePath(const std::string& path) -{ - std::string absPath; - - char realPath[PATH_MAX]; - if (realpath(path.c_str(), realPath) != nullptr && realPath[0] != '\0') - { - absPath.assign(realPath); - } - - return absPath; -} - -std::string Basename(const std::string& path) -{ - auto pos = path.find_last_of(PATH_SEPARATOR); - if (pos != std::string::npos) - { - return path.substr(0, pos); - } - else - { - return std::string("."); - } - return path; -} - -bool EndWithIgnoreCase(const std::string& str1, const std::string& str2, std::string& filename) -{ - std::string::size_type len1 = str1.length(); - std::string::size_type len2 = str2.length(); - if (len2 > len1) return false; - - int i = 0; - bool result = std::all_of(str1.cend() - len2, str1.end(), - [&i, &str2] (char x) { - return std::tolower(x) == std::tolower(str2[i++]); - }); - if (result) - { - filename = str1.substr(0, len1 - len2); - } - return result; -} - -bool FileNotExist(const std::string& path) -{ - struct stat sb; - return (stat(path.c_str(), &sb) != 0) || !S_ISREG(sb.st_mode); -} - -static bool ExtCheckAndGetFileNameIfExist(const std::string& dir, const std::string& ext, struct dirent* entry, std::string& filename) -{ - std::string fname(entry->d_name); - if (fname.length() < ext.length() || - fname.compare(fname.length() - ext.length(), ext.length(), ext) != 0) - { - return false; - } - std::string fullname = ConcatPath(dir, entry->d_name); - switch (entry->d_type) - { - case DT_REG: break; - case DT_LNK: - case DT_UNKNOWN: - if (FileNotExist(fullname)) - { - return false; - } - default: - return false; - } - - filename = fullname; - - return true; -} - -std::string StripNIDLL(const std::string& path) -{ - std::string npath(path); - if (path.size() < 5) return npath; - if (strncasecmp(path.c_str() + path.size() - 4, ".dll", 4)) - { - npath = path.substr(0, path.size()-4); - }else if (strncasecmp(path.c_str() + path.size() - 4, ".exe", 4)) - { - npath = path.substr(0, path.size()-4); - } - if (strncasecmp(npath.c_str() + npath.size() - 3, ".ni", 3)) - { - return npath.substr(0, npath.size()-3); - } - return npath; -} - -std::string JoinStrings(const std::vector& strings, const char* const delimeter) -{ - switch (strings.size()) - { - case 0: - return ""; - case 1: - return strings[0]; - default: - std::ostringstream os; - std::copy(strings.begin(), strings.end()-1, std::ostream_iterator(os, delimeter)); - os << *strings.rbegin(); - return os.str(); - } -} - -void AssembliesInDirectory(const std::vector& directories, std::string& tpaList) -{ - static const std::string tpaExtensions[] = - {".ni.dll", ".dll", ".ni.exe", ".exe"}; - - std::set addedAssemblies; - - DIR* dir = nullptr; - struct dirent* entry = nullptr; - - for (auto directory : directories) - { - dir = opendir(directory.c_str()); - if (dir == nullptr) - { - continue; - } - - for (auto ext : tpaExtensions) - { - while ((entry = readdir(dir)) != nullptr) - { - std::string fullname; - if (ExtCheckAndGetFileNameIfExist(directory.c_str(), ext, entry, fullname)) - { - std::string filename = StripNIDLL(fullname); - if (addedAssemblies.find(filename) == addedAssemblies.end()) - { - addedAssemblies.insert(filename); - tpaList += fullname + ':'; - } - } - } - rewinddir(dir); - } - closedir(dir); - } - if (tpaList.back() == ':') - tpaList.pop_back(); - -} diff --git a/NativeLauncher/src/waiter/waiter.cc b/NativeLauncher/src/waiter/waiter.cc deleted file mode 100644 index 6447d4a..0000000 --- a/NativeLauncher/src/waiter/waiter.cc +++ /dev/null @@ -1,295 +0,0 @@ - -#include - -#ifndef NO_TIZEN -#include -#include -#endif - -#include -#include -#include -#include - -#include - -#include "waiter.h" -#include "log.h" - -namespace dotnet { -namespace runtime { - -struct FdHandler -{ - pollfd *info; - Receiver receiver; -}; - -static volatile bool Waiting_; -static std::vector Fdlist_; -static std::map Handlers_; -static Waiter::AppInfo AppInfo_; - -void Waiter::OnPrepared() -{ - if (!context.Prepare()) - { - _DBG("Fail to Prepare..."); - } -} - -void Waiter::OnRequested(const AppInfo& info) -{ - // do some job on user id is still system - - if (!context.Request()) - { - _DBG("Fail to Request..."); - } -} - -void Waiter::OnExecuted(const char *path, const char *app_root, int argc, char *argv[]) -{ - if (!context.Execute(path, app_root, argc, argv)) - { - _DBG("Fail to Execute..."); - } -} - -void Waiter::OnWaiting() -{ - // Start the loop - Waiting_ = true; - - _DBG("start polling..."); - while (Waiting_) - { - if (poll(Fdlist_.data(), Fdlist_.size(), -1) < 0) - continue; - - for (auto &p : Fdlist_) - { - if ( (p.revents | POLLIN) != 0 ) - Handlers_[p.fd].receiver(p.fd); - } - } - _DBG("end polling..."); -} - -void Waiter::Stop() -{ - // Stop the loop - - Waiting_ = false; -} - - -void Waiter::RegisterFd(int fd, Receiver receiver) -{ - // register fd should be caught in event loop - - _DBG("Register fd %d", fd); - - pollfd info; - info.fd = fd; - info.events = POLLIN; - info.revents = 0; - - FdHandler handler; - Fdlist_.push_back(info); - handler.info = &Fdlist_.back(); - handler.receiver = receiver; - - Handlers_[fd] = handler; -} - -void Waiter::DeregisterFd(int fd) -{ - // deregister fd should be caught in event loop - - pollfd *info = Handlers_[fd].info; - Fdlist_.erase(Fdlist_.begin() - (info - &Fdlist_.front())); - Handlers_.erase(fd); -} - -int Waiter::WaitToLaunching(int argc, char *argv[]) -{ -#ifndef NO_TIZEN - auto on_create = [](bundle *extra, int type, void *user_data) - { - _DBG("on_create..."); // XXX - Waiter* waiter = static_cast(user_data); - waiter->OnPrepared(); - }; - - auto on_launch = [](int argc, char **argv, const char *app_path, - const char *appid, const char *pkgid, - const char *pkg_type, void *user_data) -> int - { - _DBG("on_launch..."); // XXX - Waiter* waiter = static_cast(user_data); - - _DBG ("app path : %s", app_path); - _DBG ("app id : %s", appid); - _DBG ("pkg id : %s", pkgid); - _DBG ("pkg type : %s", pkg_type); - - AppInfo info = { - AppPath : app_path, - AppId : appid, - PkgId : pkgid, - PkgType : pkg_type - }; - - waiter->OnRequested(info); - return 0; - }; - - auto on_terminate = [](int argc, char **argv, void *user_data) -> int - { - _DBG("on_terminate..."); // XXX - - string app_root(aul_get_app_root_path()); - Waiter* waiter = static_cast(user_data); - waiter->OnExecuted(argv[0], app_root.c_str(), argc, argv); - return 0; - }; - - auto on_start_loop = [](void *user_data) - { - _DBG("on_start_loop..."); // XXX - Waiter* waiter = static_cast(user_data); - waiter->OnWaiting(); - }; - - auto on_quit_loop = [](void *user_data) - { - _DBG("on_quit_loop..."); // XXX - Waiter* waiter = static_cast(user_data); - waiter->Stop(); - }; - - auto on_add_fd = [](void *user_data, int fd, loader_receiver_cb receiver) - { - _DBG("on_add_fd..."); // XXX - Waiter* waiter = static_cast(user_data); - waiter->RegisterFd(fd, receiver); - }; - - auto on_remove_fd = [](void *user_data, int fd) - { - _DBG("on_remove_fd..."); // XXX - Waiter* waiter = static_cast(user_data); - waiter->DeregisterFd(fd); - }; - - _DBG("launcher wait..."); // XXX - loader_lifecycle_callback_s callbacks = { - .create = on_create, - .launch = on_launch, - .terminate = on_terminate - }; - - loader_adapter_s adapter = { - .loop_begin = on_start_loop, - .loop_quit = on_quit_loop, - .add_fd = on_add_fd, - .remove_fd = on_remove_fd - }; - - return launchpad_loader_main(argc, argv, &callbacks, &adapter, this); -#else - if (argc < 2) - { - _DBG("not enough args : %d", argc); - return -1; - } - _DBG("argv[1] = %s", argv[1]); - std::string app_path(argv[1]); - std::string app_root; - auto pos = app_path.find_last_of('/'); - if (pos != std::string::npos) - app_root = app_path.substr(0, pos); - else - app_root = "."; - - this->OnPrepared(); - AppInfo info = { - AppPath : argv[1], - AppId : "", - PkgId : "", - PkgType : "" - }; - this->OnRequested(info); - this->OnExecuted(app_path.c_str(), app_root.c_str(), argc, argv); -#endif -} - -void Waiter::SetContext(WaiterContext ctx) -{ - context = ctx; -} - -WaiterContext::WaiterContext() -{ - Step = Status::Started; -} - -bool WaiterContext::Prepare() -{ - if (Step == Status::Started && Prepared != nullptr && Prepared(Data) == 0) - { - Step = Status::Prepared; - return true; - } - return false; -} - -bool WaiterContext::Request() -{ - if (Step == Status::Prepared && Requested != nullptr && Requested(Data) == 0) - { - Step = Status::Requested; - return true; - } - return false; -} - -bool WaiterContext::Execute(const char *path, const char *app_root, int argc, char *argv[]) -{ - if (Step == Status::Requested && Executed != nullptr && - Executed(path, app_root, argc, argv, Data) == 0) - { - Step = Status::Executed; - return true; - } - return false; -} - -} // namespace runtime -} // namespace dotnet - -using dotnet::runtime::Waiter; -using dotnet::runtime::WaiterContext; - -static Waiter waiter; - -void register_launching_callback(prepared_callback prepared, - requested_callback requested, executed_callback executed, void *data) -{ - WaiterContext context; - context.Prepared = prepared; - context.Requested = requested; - context.Executed = executed; - context.Data = data; - - waiter.SetContext(context); -} - -void wait_for_launching(int argc, char *argv[]) -{ - _DBG("wait_for_launching..."); - - waiter.WaitToLaunching(argc, argv); -} - diff --git a/NativeLauncher/src/waiter/waiter.h b/NativeLauncher/src/waiter/waiter.h deleted file mode 100644 index c4b98fb..0000000 --- a/NativeLauncher/src/waiter/waiter.h +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include - -#include - -extern "C" { - typedef int (*prepared_callback)(void *data); - typedef int (*requested_callback)(void *data); - typedef int (*executed_callback)(const char* path, const char* app_root, int argc, char *argv[], void *data); - - void register_launching_callback(prepared_callback prepared, - requested_callback requested, executed_callback executed, void *data); - void wait_for_launching(int argc, char *argv[]); -} - -namespace dotnet { -namespace runtime { - -using std::string; -using Receiver = std::function; - -enum Status -{ - Started, - Prepared, - Requested, - Executed -}; - -class WaiterContext -{ - public: - prepared_callback Prepared; - requested_callback Requested; - executed_callback Executed; - - void *Data; - - WaiterContext(); - bool Prepare(); - bool Request(); - bool Execute(const char *path, const char *app_root, int argc, char *argv[]); - - private: - Status Step; -}; - -class Waiter -{ - public: - struct AppInfo - { - string AppPath; - string AppId; - string PkgId; - string PkgType; - }; - - int WaitToLaunching(int argc, char *argv[]); - void Stop(); - - void RegisterFd(int fd, Receiver receiver); - void DeregisterFd(int fd); - void SetContext(WaiterContext ctx); - - protected: - void OnPrepared(); - void OnRequested(const AppInfo&); - void OnWaiting(); - void OnExecuted(const char *path, const char *app_root, int argc, char *argv[]); - - private: - WaiterContext context; -}; - -} // namespace runtime -} // namespace dotnet diff --git a/NativeLauncher/util/utils.cc b/NativeLauncher/util/utils.cc new file mode 100644 index 0000000..2cc1026 --- /dev/null +++ b/NativeLauncher/util/utils.cc @@ -0,0 +1,329 @@ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +bool ICompare(const std::string& a, const std::string& b) +{ + return a.length() == b.length() && + std::equal(b.begin(), b.end(), a.begin(), + [](unsigned char a, unsigned char b) + { return std::tolower(a) == std::tolower(b); }); +} + +bool ICompare(const std::string& a, int a_offset, const std::string& b, int b_offset, int length) +{ + return static_cast(a.length()) - length >= a_offset && + static_cast(b.length()) - length >= b_offset && + std::equal(b.begin() + b_offset, b.begin() + b_offset + length, a.begin() + a_offset, + [](unsigned char a, unsigned char b) + { return std::tolower(a) == std::tolower(b); }); +} + +bool IsManagedAssembly(const std::string& filename) +{ + return ICompare(filename, filename.size()-4, ".dll", 0, 4) || + ICompare(filename, filename.size()-4, ".exe", 0, 4); +} + +bool IsNativeImage(const std::string& filename) +{ + return ICompare(filename, filename.size()-7, ".ni", 0, 3); +} + +std::string ReadSelfPath() +{ + char buff[PATH_MAX]; + ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1); + if (len != -1) { + buff[len] = '\0'; + return std::string(buff); + } + + return ""; +} + +std::string ConcatPath(const std::string& path1, const std::string& path2) +{ + std::string path(path1); + if (path.back() == PATH_SEPARATOR) + { + path.append(path2); + } + else + { + path += PATH_SEPARATOR; + path.append(path2); + } + + return path; +} + +void AppendPath(std::string& path1, const std::string& path2) +{ + if (path1.back() == PATH_SEPARATOR) + { + path1.append(path2); + } + else + { + path1 += PATH_SEPARATOR; + path1.append(path2); + } +} + +std::string AbsolutePath(const std::string& path) +{ + std::string absPath; + + char realPath[PATH_MAX]; + if (realpath(path.c_str(), realPath) != nullptr && realPath[0] != '\0') + { + absPath.assign(realPath); + } + + return absPath; +} + +std::string Basename(const std::string& path) +{ + auto pos = path.find_last_of(PATH_SEPARATOR); + if (pos != std::string::npos) + { + return path.substr(0, pos); + } + else + { + return std::string("."); + } + return path; +} + +bool EndWithIgnoreCase(const std::string& str1, const std::string& str2, std::string& filename) +{ + std::string::size_type len1 = str1.length(); + std::string::size_type len2 = str2.length(); + if (len2 > len1) return false; + + int i = 0; + bool result = std::all_of(str1.cend() - len2, str1.end(), + [&i, &str2] (char x) { + return std::tolower(x) == std::tolower(str2[i++]); + }); + if (result) + { + filename = str1.substr(0, len1 - len2); + } + return result; +} + +bool FileNotExist(const std::string& path) +{ + struct stat sb; + return stat(path.c_str(), &sb) != 0; +} + +static bool ExtCheckAndGetFileNameIfExist(const std::string& dir, const std::string& ext, struct dirent* entry, std::string& filename) +{ + std::string fname(entry->d_name); + if (fname.length() < ext.length() || + fname.compare(fname.length() - ext.length(), ext.length(), ext) != 0) + { + return false; + } + std::string fullname = ConcatPath(dir, entry->d_name); + switch (entry->d_type) + { + case DT_REG: break; + case DT_LNK: + case DT_UNKNOWN: + if (FileNotExist(fullname)) + { + return false; + } + default: + return false; + } + + filename = fullname; + + return true; +} + +std::string StripNIDLL(const std::string& path) +{ + std::string npath(path); + if (path.size() < 5) return npath; + if (strncasecmp(path.c_str() + path.size() - 4, ".dll", 4)) + { + npath = path.substr(0, path.size()-4); + }else if (strncasecmp(path.c_str() + path.size() - 4, ".exe", 4)) + { + npath = path.substr(0, path.size()-4); + } + if (strncasecmp(npath.c_str() + npath.size() - 3, ".ni", 3)) + { + return npath.substr(0, npath.size()-3); + } + return npath; +} + +std::string JoinStrings(const std::vector& strings, const char* const delimeter) +{ + switch (strings.size()) + { + case 0: + return ""; + case 1: + return strings[0]; + default: + std::ostringstream os; + std::copy(strings.begin(), strings.end()-1, std::ostream_iterator(os, delimeter)); + os << *strings.rbegin(); + return os.str(); + } +} + +struct AssemblyFile +{ + std::string noext; + std::string ext; +}; + +bool operator == (const AssemblyFile& lhs, const AssemblyFile& rhs) +{ + return lhs.noext == rhs.noext && lhs.ext == rhs.ext; +} + +namespace std +{ + template<> + struct hash + { + std::size_t operator () (const AssemblyFile& f) const + { + const std::size_t h1 = std::hash{}(f.noext); + const std::size_t h2 = std::hash{}(f.ext); + + return h1 ^ (h2 << 1); + } + }; +} + +void AssembliesInDirectory(const std::vector& directories, std::string& tpaList) +{ + std::unordered_map addedAssemblies; + + auto reader = [&addedAssemblies] (const char* path) + { + std::string _path(path); + + std::string::size_type dotp = _path.rfind('.'); + std::string ext = dotp != std::string::npos ? _path.substr(dotp) : ""; + std::string noext; + bool ni = false; + + if (IsManagedAssembly(_path)) + { + if (IsNativeImage(_path)) + { + noext = _path.substr(0, _path.size()-7); + ni = true; + } + else + { + noext = _path.substr(0, _path.size()-4); + } + + AssemblyFile f = {noext, ext}; + addedAssemblies[f] = ni; + } + }; + + for (auto directory : directories) + { + ScanFilesInDir(directory.c_str(), reader, 1); + } + + for (auto kv : addedAssemblies) + { + tpaList += kv.first.noext + (kv.second ? ".ni" : "") + kv.first.ext + ':'; + } + + if (tpaList.back() == ':') + tpaList.pop_back(); +} + +void ScanFilesInDir(const char* directory, FileReader reader, unsigned int depth) +{ + DIR *dir; + struct dirent* entry; + bool isDir; + + dir = opendir(directory); + + if (dir == nullptr) + { + //_ERR("Can not open directory : %s", directory); + return; + } + + std::vector innerDirectories; + + while ((entry = readdir(dir)) != nullptr) + { + isDir = false; + std::string path = ConcatPath(directory, entry->d_name); + switch (entry->d_type) + { + case DT_REG: break; + case DT_DIR: + isDir = true; + break; + case DT_LNK: + case DT_UNKNOWN: + struct stat sb; + if (stat(path.c_str(), &sb) == -1) + { + continue; + } + + if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode)) + { + break; + } + default: + continue; + } + if (!isDir) + { + reader(path.c_str()); + } + else if (depth > 1 && strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) + { + innerDirectories.push_back(path); + } + } + + if (depth != 0) + { + for (auto& d : innerDirectories) + { + ScanFilesInDir(d.c_str(), reader, depth-1); + } + } + + closedir(dir); +} diff --git a/packaging/dotnet-launcher.spec b/packaging/dotnet-launcher.spec index fa0bb60..1050527 100644 --- a/packaging/dotnet-launcher.spec +++ b/packaging/dotnet-launcher.spec @@ -15,6 +15,8 @@ BuildRequires: pkgconfig(bundle) BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(ecore) BuildRequires: pkgconfig(launchpad) +BuildRequires: pkgconfig(pkgmgr-info) +BuildRequires: pkgconfig(pkgmgr-installer) BuildRequires: aul-devel BuildRequires: mono-compiler BuildRequires: mono-devel @@ -33,6 +35,7 @@ Requires(preun): /usr/bin/systemctl %define _device_api_dir %{dotnet_assembly_path} %define _runtime_dir /opt/usr/share/dotnet/shared/Microsoft.NETCore.App/1.0.0 %define _preload_dir /opt/usr/share/dotnet.tizen/preload +%define _install_plugin_dir /usr/etc/package-manager/parserlib %description Launchpad plugin for launching dotnet apps @@ -56,8 +59,10 @@ cmake \ -DCMAKE_BUILD_TYPE=%{_buildmode} \ -DDEVICE_API_DIR=%{_device_api_dir} \ -DRUNTIME_DIR=%{_runtime_dir} \ + -DCROSSGEN_PATH=%{_device_api_dir}/crossgen \ -DCORECLR_LAUNCHER_ASSEMBLY_PATH=%{_bindir}/Tizen.Runtime.Coreclr.dll \ -DMONO_LAUNCHER_ASSEMBLY_PATH=%{_bindir}/Tizen.Runtime.Mono.dll \ + -DINSTALL_PLUGIN_DIR=%{_install_plugin_dir} \ -DVERSION=%{version} \ NativeLauncher @@ -89,5 +94,7 @@ install -p -m 644 Tizen.Runtime/bin/Tizen.Runtime.Mono.dll %{buildroot}%{_bindir %{_loaderdir}/dotnet.launcher %{_loaderdir}/dotnet.debugger %caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/dotnet-launcher +%caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/nitool +%caps(cap_mac_admin,cap_setgid=ei) %{_install_plugin_dir}/libui-application.so %caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/Tizen.Runtime.Coreclr.dll %caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/Tizen.Runtime.Mono.dll