From ff0921bea8ac44486889b2649ac8dac98bdb23a3 Mon Sep 17 00:00:00 2001 From: "pius.lee" Date: Fri, 26 Aug 2016 16:40:52 +0900 Subject: [PATCH] Split Native Parts to SharedObject and Executable Make libdnclauncher.so for waiting and launchpad callbacks. Modify dotnet-launcher to execute managed launcher with libcoreclr.so. Managed Launcher read ini file to read dll lists for preloading. Add Targets file building csproj with corefx and device apis. --- NativeLauncher/CMakeLists.txt | 20 +- NativeLauncher/dotnet-launcher.ini | 3 +- NativeLauncher/src/launcher.cc | 294 ++++++++++----------- NativeLauncher/src/launcher.h | 30 ++- NativeLauncher/src/waiter.cc | 133 +++++++--- NativeLauncher/src/waiter.h | 55 +++- Tizen.Runtime/Tizen.CoreFX.Ref.Targets | 20 +- Tizen.Runtime/Tizen.Runtime.csproj | 29 +- Tizen.Runtime/Tizen.Runtime/AssemblyLoader.cs | 57 +++- Tizen.Runtime/Tizen.Runtime/AssemblyManager.cs | 142 +++++++++- .../Tizen.Runtime/DefaultConfigAttribute.cs | 27 ++ Tizen.Runtime/Tizen.Runtime/Ini.cs | 139 ++++++++++ Tizen.Runtime/Tizen.Runtime/Interop.cs | 20 ++ packaging/dotnet-launcher.spec | 6 +- test_build_on_desktop.sh | 19 ++ 15 files changed, 755 insertions(+), 239 deletions(-) create mode 100644 Tizen.Runtime/Tizen.Runtime/DefaultConfigAttribute.cs create mode 100644 Tizen.Runtime/Tizen.Runtime/Ini.cs create mode 100644 Tizen.Runtime/Tizen.Runtime/Interop.cs create mode 100755 test_build_on_desktop.sh diff --git a/NativeLauncher/CMakeLists.txt b/NativeLauncher/CMakeLists.txt index e55c12c..8e203a3 100644 --- a/NativeLauncher/CMakeLists.txt +++ b/NativeLauncher/CMakeLists.txt @@ -14,14 +14,18 @@ FOREACH(flag ${${PROJECT_NAME}_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") ENDFOREACH(flag) -IF(DEFINED LAUNCHER_PATH) - SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DLAUNCHER_PATH=${LAUNCHER_PATH}") -ENDIF(DEFINED LAUNCHER_PATH) +IF(DEFINED LAUNCHER_CONFIG_PATH) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DLAUNCHER_CONFIG_PATH=${LAUNCHER_CONFIG_PATH}") +ENDIF(DEFINED LAUNCHER_CONFIG_PATH) + +IF(DEFINED LAUNCHER_ASSEMBLY_PATH) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DLAUNCHER_ASSEMBLY_PATH=${LAUNCHER_ASSEMBLY_PATH}") +ENDIF(DEFINED LAUNCHER_ASSEMBLY_PATH) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -std=c++11") SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" ) -SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") +#SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") 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") @@ -48,8 +52,16 @@ SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SKIP_BUILD_RPATH TRUE ) # remove rpath option that is automatically generated by cmake. +SET(LAUNCHER_LIB "dnclauncher") +ADD_LIBRARY(${LAUNCHER_LIB} SHARED src/waiter.cc) +IF(NOT DEFINED NO_TIZEN) + TARGET_LINK_LIBRARIES(${LAUNCHER_LIB} aul) +ENDIF(NOT DEFINED NO_TIZEN) +TARGET_LINK_LIBRARIES(${LAUNCHER_LIB} ${${PROJECT_NAME}_LDFLAGS} "-ldl") + IF(NOT DEFINED NO_TIZEN) INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${BINDIR}) + INSTALL(TARGETS ${LAUNCHER_LIB} DESTINATION ${LIBDIR}) INSTALL(FILES dotnet.loader DESTINATION ${LOADERDIR}) INSTALL(FILES dotnet-launcher.ini DESTINATION ${CONFIGDIR}) ENDIF(NOT DEFINED NO_TIZEN) diff --git a/NativeLauncher/dotnet-launcher.ini b/NativeLauncher/dotnet-launcher.ini index 9d4809c..ad1d22b 100644 --- a/NativeLauncher/dotnet-launcher.ini +++ b/NativeLauncher/dotnet-launcher.ini @@ -1,5 +1,6 @@ [dotnet] -libcoreclr = libcoreclr.so +libcoreclr = /opt/usr/share/dotnet/shared/Microsoft.NETCore.App/1.0.0/libcoreclr.so coreclr_dir = /opt/usr/share/dotnet/shared/Microsoft.NETCore.App/1.0.0 tpa_dirs = /opt/usr/share/dotnet/shared/Microsoft.NETCore.App/1.0.0:/usr/share/assembly native_so_search_dirs = /opt/usr/share/dotnet/shared/Microsoft.NETCore.App/1.0.0:/usr/share/assembly +launcher_assembly = /usr/bin/Tizen.Runtime.dll diff --git a/NativeLauncher/src/launcher.cc b/NativeLauncher/src/launcher.cc index fcd1555..84c3811 100644 --- a/NativeLauncher/src/launcher.cc +++ b/NativeLauncher/src/launcher.cc @@ -1,9 +1,5 @@ #include -#ifdef LAUNCHING_TIME_MEASURE -#include -#endif - #include #include #include @@ -17,36 +13,76 @@ #include #include +#include +#include + #include "environment.h" #include "waiter.h" #include "log.h" #include "tini.hpp" -#include "launcher.h" - -namespace dotnet { -namespace runtime { - -#ifdef LAUNCHER_PATH #define __STR(x) #x #define __XSTR(x) __STR(x) -#define LAUNCHER_CONFIG __XSTR(LAUNCHER_PATH) + +#ifdef LAUNCHER_CONFIG_PATH +#define LAUNCHER_CONFIG __XSTR(LAUNCHER_CONFIG_PATH) #else #define LAUNCHER_CONFIG "/etc/dotnet-launcher.ini" #endif static const std::string LauncherConfig(LAUNCHER_CONFIG); -#ifdef LAUNCHER_PATH -#undef __STR -#undef __XSTR +#ifdef LAUNCHER_CONFIG_PATH #undef LAUNCHER_CONFIG -#undef LAUNCHER_PATH +#undef LAUNCHER_CONFIG_PATH #endif +#undef __STR +#undef __XSTR #ifndef PATH_SEPARATOR #define PATH_SEPARATOR '/' #endif +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); + +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 ""; +} + +/* static std::string ConcatPath(const std::string& path1, const std::string& path2) { std::string path(path1); @@ -74,6 +110,7 @@ static void AppendPath(std::string& path1, const std::string& path2) path1.append(path2); } } +*/ static std::string AbsolutePath(const std::string& path) { @@ -134,6 +171,8 @@ static std::string AssembliesInDirectory(const char *directory) return std::string(); } + _DBG("assemblies in %s", directory); + std::set addedAssemblies; struct dirent *entry; @@ -198,20 +237,8 @@ static std::string AssembliesInDirectory(const char *directory) return tpaList; } -Launcher::Launcher() +static int RunLauncherDll(int argc, char* argv[]) { -} - -Launcher::~Launcher() -{ -} - -void Launcher::Initialize() -{ -#ifdef LAUNCHING_TIME_MEASURE - std::clock_t start = std::clock(); -#endif - std::ifstream iniStream(LauncherConfig); std::stringstream iniString; iniString << iniStream.rdbuf(); @@ -221,82 +248,56 @@ void Launcher::Initialize() _DBG("%s", launcherIni.to_string().c_str()); auto &dotnet = launcherIni["dotnet"]; - if (dotnet.find("libcoreclr") == dotnet.end()) - dotnet["libcoreclr"] = "libcoreclr.so"; - if (dotnet.find("coreclr_dir") == dotnet.end()) - dotnet["coreclr_dir"] = "/usr/share/dotnet"; - if (dotnet.find("tpa_dir") == dotnet.end()) - dotnet["tpa_dir"] = dotnet["coreclr_dir"] + ":" + "/usr/share/assemblies"; - if (dotnet.find("native_so_search_dirs") == dotnet.end()) - dotnet["native_so_search_dirs"] = dotnet["tpa_dir"]; - - _DBG("libcoreclr : %s", dotnet["libcoreclr"].c_str()); - _DBG("coreclr_dir : %s", dotnet["coreclr_dir"].c_str()); - _DBG("tpa_dir : %s", dotnet["tpa_dir"].c_str()); - _DBG("native_so_search_dirs : %s", dotnet["native_so_search_dirs"].c_str()); - - std::string libcoreclr = dotnet["coreclr_dir"] + "/" + dotnet["libcoreclr"]; - std::string tpaDirs = dotnet["tpa_dirs"]; - std::string nativeSoSearchDirs = dotnet["native_so_search_dirs"]; - - _DBG("libcoreclr.so : [%s]", libcoreclr.c_str()); - -#ifdef LAUNCHING_TIME_MEASURE - std::clock_t config_read_time = std::clock(); - _DBG("Reading Config file... : %Lf ms ", (config_read_time - start) / (double)(CLOCKS_PER_SEC / 1000)); -#endif - coreclrLib = dlopen(libcoreclr.c_str(), RTLD_NOW | RTLD_LOCAL); - if (coreclrLib == nullptr) +#define DOTNET_FIND(key, defaultValue) \ + ((dotnet.find(key) == dotnet.end()) ? defaultValue : dotnet[key]) + std::string libcoreclr = DOTNET_FIND("libcoreclr", "libcoreclr.so"); + std::string coreclr_dir = DOTNET_FIND("coreclr_dir", "/opt/usr/share/dotnet/shared/Microsoft.NETCore.App/1.0.0/"); + std::string tpa_dirs = DOTNET_FIND("tpa_dirs", coreclr_dir + ":" + "/usr/share/assembly"); + std::string native_so_search_dirs = DOTNET_FIND("native_so_search_dirs", tpa_dirs); + std::string launcher_assembly = AbsolutePath(DOTNET_FIND("launcher_assembly", "/usr/bin/Tizen.Runtime.dll")); +#undef DOTNET_FIND + + std::string launcher_dir = Basename(launcher_assembly); + std::string trusted_assemblies = launcher_assembly + ":"; + + std::istringstream f(tpa_dirs); + std::string s; + while (std::getline(f, s, ':')) { - char *err = dlerror(); - _ERR("dlopen failed to open libcoreclr.so with error %s", err); - return; + trusted_assemblies += AssembliesInDirectory(s.c_str()); } - initializeCoreCLR = (coreclr_initialize_ptr)dlsym(coreclrLib, "coreclr_initialize"); - executeAssembly = (coreclr_execute_assembly_ptr)dlsym(coreclrLib, "coreclr_execute_assembly"); - shutdownCoreCLR = (coreclr_shutdown_ptr)dlsym(coreclrLib, "coreclr_shutdown"); + _DBG("libcoreclr : %s", libcoreclr.c_str()); + _DBG("coreclr_dir : %s", coreclr_dir.c_str()); + _DBG("tpa_dirs : %s", tpa_dirs.c_str()); + _DBG("native_so_search_dir : %s", native_so_search_dirs.c_str()); + _DBG("launcher_assembly : %s", launcher_assembly.c_str()); + _DBG("launcher_dir : %s", launcher_dir.c_str()); + _DBG("-------------------------------------------------"); - if (initializeCoreCLR == nullptr) - { - _ERR("coreclr_initialize not found in the libcoreclr.so"); - } - else if (executeAssembly == nullptr) - { - _ERR("coreclr_execute_assembly_ptr not found in the libcoreclr.so"); - } - else if (shutdownCoreCLR == nullptr) - { - _ERR("coreclr_shutdown_ptr not found in the libcoreclr.so"); - } - else + void *coreclrLib = dlopen(libcoreclr.c_str(), RTLD_NOW | RTLD_LOCAL); + if (coreclrLib == nullptr) { - std::istringstream f(tpaDirs); - std::string s; - while (std::getline(f, s, ':')) - { - TrustedPlatformAssemblies += AssembliesInDirectory(s.c_str()); - } - NativeDllSearchDirectories = nativeSoSearchDirs; - AppDomainCompatSwitch = "UseLatestBehaviorWhenTFMNotSpecified"; + char *err = dlerror(); + _ERR("dlopen failed to open libcoreclr.so with error %s", err); + return 1; } -#ifdef LAUNCHING_TIME_MEASURE - std::clock_t dlopen_time = std::clock(); - _DBG("dlopen and dlsym time... : %Lf ms ", (dlopen_time - config_read_time) / (double)(CLOCKS_PER_SEC / 1000)); - _DBG("initialize time... : %Lf ms ", (dlopen_time - start) / (double)(CLOCKS_PER_SEC / 1000)); -#endif +#define CORELIB_RETURN_IF_NOSYM(type, variable, name) \ + type variable; \ + 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, coreclr_initialize, "coreclr_initialize"); + CORELIB_RETURN_IF_NOSYM(coreclr_execute_assembly_ptr, coreclr_execute_assembly, "coreclr_execute_assembly"); + CORELIB_RETURN_IF_NOSYM(coreclr_shutdown_ptr, coreclr_shutdown, "coreclr_shutdown"); + CORELIB_RETURN_IF_NOSYM(coreclr_create_delegate_ptr, coreclr_create_delegate, "coreclr_create_delegate"); -void Launcher::Launch(const string& exe_path, const string& app_root, int argc, char *argv[]) -{ - std::string bin_path = Basename(AbsolutePath(exe_path)); - std::string lib_path = ConcatPath(AbsolutePath(app_root), "lib"); - std::string app_path = bin_path + ":" + lib_path; - std::string app_ni_path = app_path; - std::string nativeDllSearchDirectories = NativeDllSearchDirectories + app_path; +#undef CORELIB_RETURN_IF_NOSYM const char *propertyKeys[] = { @@ -309,28 +310,27 @@ void Launcher::Launch(const string& exe_path, const string& app_root, int argc, const char *propertyValues[] = { - TrustedPlatformAssemblies.c_str(), - app_path.c_str(), - app_ni_path.c_str(), - nativeDllSearchDirectories.c_str(), - AppDomainCompatSwitch.c_str() + trusted_assemblies.c_str(), + launcher_dir.c_str(), + launcher_dir.c_str(), + native_so_search_dirs.c_str(), + "UseLatestBehaviorWhenTFMNotSpecified" }; - //_DBG("trusted platform assemblies : %s", propertyValues[0]); + _DBG("trusted platform assemblies : %s", propertyValues[0]); _DBG("app_path : %s", propertyValues[1]); _DBG("app_ni_path : %s", propertyValues[2]); _DBG("native dll search path : %s", propertyValues[3]); _DBG("app domain compat switch : %s", propertyValues[4]); + _DBG("before initialize coreclr"); + void* hostHandle; unsigned int domainId; - _DBG("before initialize coreclr"); + std::string selfPath = ReadSelfPath(); -#ifdef LAUNCHING_TIME_MEASURE - std::clock_t start = std::clock(); -#endif - int st = initializeCoreCLR(exe_path.c_str(), + int st = coreclr_initialize(selfPath.c_str(), "tizen_dotnet_launcher", sizeof(propertyKeys) / sizeof(propertyKeys[0]), propertyKeys, @@ -339,76 +339,50 @@ void Launcher::Launch(const string& exe_path, const string& app_root, int argc, &domainId); _DBG("after initialize coreclr"); -#ifdef LAUNCHING_TIME_MEASURE - std::clock_t initialize_coreclr_time = std::clock(); - _DBG("call coreclr_initialize ... : %Lf ms ", (initialize_coreclr_time - start) / (double)(CLOCKS_PER_SEC / 1000)); -#endif if (st < 0) { // initialize coreclr fail _ERR("initialize core clr fail! (0x%08x)", st); _DBG("check your smack label dll and every directories on the way to dlls"); + return 1; } - else + + struct stat sb; + if (stat(launcher_assembly.c_str(), &sb) == -1) { - unsigned int exitCode; - const char** argvc = const_cast(argv); - st = executeAssembly(hostHandle, domainId, argc, argvc, exe_path.c_str(), &exitCode); - _DBG("after execute coreclr"); - if (st < 0) - { - // execute coreclr fail - _ERR("execute core clr fail! (0x%08x / %d)", st, exitCode); - } - st = shutdownCoreCLR(hostHandle, domainId); - if (st < 0) - { - // shutdown fail - _ERR("shutdown core clr fail! (0x%08x)", st); - } -#ifdef LAUNCHING_TIME_MEASURE - std::clock_t execute_assembly_time = std::clock(); - _DBG("call execute_assembly_time ... : %Lf ms ", (execute_assembly_time - initialize_coreclr_time) / (double)(CLOCKS_PER_SEC / 1000)); -#endif + _ERR("Launcher assembly is not exist in %s", launcher_assembly.c_str()); + return 1; + } + + unsigned int exitCode; + const char** cargv = const_cast(argv); + st = coreclr_execute_assembly(hostHandle, domainId, + argc, cargv, launcher_assembly.c_str(), &exitCode); + _DBG("after execute coreclr"); + if (st < 0) + { + _ERR("execute core clr fail! (0x%08x / %d)", st, exitCode); + return 1; } + + st = coreclr_shutdown(hostHandle, domainId); + if (st < 0) + { + _ERR("shutdown core clr fail! (0x%08x)", st); + return 1; + } + if (dlclose(coreclrLib) != 0) { _ERR("libcoreclr.so close failed"); + return 1; } -#ifdef LAUNCHING_TIME_MEASURE - std::clock_t after_launching_time = std::clock(); - _DBG("launching end time ... : %Lf ms ", (after_launching_time - start) / (double)(CLOCKS_PER_SEC / 1000)); -#endif -} - -} // namespace runtime -} // namespace dotnet -using dotnet::runtime::Launcher; -using dotnet::runtime::Waiter; + return 0; +} int main(int argc, char *argv[]) { _DBG("launcher started"); - - for (int i=0; i launcher(new Launcher()); - auto on_prepare = [&launcher]() - { - launcher->Initialize(); - }; - auto on_requested = [&launcher]() - { - }; - auto on_executed = [&launcher](const std::string& path, const std::string& app_root, int argc, char *argv[]) - { - _DBG("EXECUTE %s", path.c_str()); - launcher->Launch(path, app_root, argc, argv); - }; - std::unique_ptr waiter(new Waiter(on_prepare, on_requested, on_executed)); - waiter->WaitToLaunching(argc, argv); + return RunLauncherDll(argc, argv); } diff --git a/NativeLauncher/src/launcher.h b/NativeLauncher/src/launcher.h index acba908..4800ddf 100644 --- a/NativeLauncher/src/launcher.h +++ b/NativeLauncher/src/launcher.h @@ -25,6 +25,24 @@ 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); + +typedef bool (*AssemblyManager_Initialize)( + const char* searchableDirectories, + const char* preloadDllPaths); + +typedef void (*AssemblyManager_AddAssemblyDir)(const char* dir); +typedef void (*AssemblyManager_RemoveAssemblyDir)(const char* dir); + +typedef void (*AssemblyManager_Execute)(const char* dllPath); +typedef void (*AssemblyManager_Finish)(void); + using std::string; using std::vector; @@ -34,18 +52,26 @@ class Launcher Launcher(); ~Launcher(); void Initialize(); - void Launch(const string& exe_path, const string& app_root, int argc, char *argv[]); private: coreclr_initialize_ptr initializeCoreCLR; - coreclr_execute_assembly_ptr executeAssembly; +// coreclr_execute_assembly_ptr executeAssembly; coreclr_shutdown_ptr shutdownCoreCLR; + coreclr_create_delegate_ptr createDelegate; string TrustedPlatformAssemblies; string NativeDllSearchDirectories; string AppDomainCompatSwitch; void *coreclrLib; + + AssemblyManager_Initialize assemblyManagerInitialize; + AssemblyManager_Execute assemblyManagerExecute; + AssemblyManager_Finish assemblyManagerFinish; + AssemblyManager_AddAssemblyDir assemblyManagerAddDir; + AssemblyManager_RemoveAssemblyDir assemblyManagerRemoveDir; + + bool initialized; }; } // namespace runtime diff --git a/NativeLauncher/src/waiter.cc b/NativeLauncher/src/waiter.cc index 6f83482..c7cb794 100644 --- a/NativeLauncher/src/waiter.cc +++ b/NativeLauncher/src/waiter.cc @@ -30,16 +30,30 @@ static std::vector Fdlist_; static std::map Handlers_; static Waiter::AppInfo AppInfo_; -void Waiter::OnPrepare() +void Waiter::OnPrepared() { - // preload the libraries. - if (prepare_ != nullptr) - prepare_(); + if (!context.Prepare()) + { + _DBG("Fail to Prepare..."); + } } -void Waiter::OnLaunchRequested(const AppInfo& info) +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() @@ -98,18 +112,6 @@ void Waiter::DeregisterFd(int fd) Handlers_.erase(fd); } - -Waiter::Waiter(Action prepare, Action requested, Executor executor) -{ - prepare_ = prepare; - requested_ = requested; - executor_ = executor; -} - -Waiter::~Waiter() -{ -} - int Waiter::WaitToLaunching(int argc, char *argv[]) { #ifndef NO_TIZEN @@ -117,7 +119,7 @@ int Waiter::WaitToLaunching(int argc, char *argv[]) { _DBG("on_create..."); // XXX Waiter* waiter = static_cast(user_data); - waiter->OnPrepare(); + waiter->OnPrepared(); }; auto on_launch = [](int argc, char **argv, const char *app_path, @@ -139,7 +141,7 @@ int Waiter::WaitToLaunching(int argc, char *argv[]) PkgType : pkg_type }; - waiter->OnLaunchRequested(info); + waiter->OnRequested(info); return 0; }; @@ -149,7 +151,7 @@ int Waiter::WaitToLaunching(int argc, char *argv[]) string app_root(aul_get_app_root_path()); Waiter* waiter = static_cast(user_data); - waiter->executor_(argv[0], app_root, argc, argv); + waiter->OnExecuted(argv[0], app_root.c_str(), argc, argv); return 0; }; @@ -197,7 +199,12 @@ int Waiter::WaitToLaunching(int argc, char *argv[]) return launchpad_loader_main(argc, argv, &callbacks, &adapter, this); #else - if (argc < 2) return -1; + 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('/'); @@ -206,17 +213,83 @@ int Waiter::WaitToLaunching(int argc, char *argv[]) else app_root = "."; - this->OnPrepare(); - AppInfo info = { - AppPath : argv[1], - AppId : "", - PkgId : "", - PkgType : "" - }; - this->OnLaunchRequested(info); - this->executor_(app_path, app_root, argc, argv); + 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)) + { + 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.h b/NativeLauncher/src/waiter.h index f233317..c4b98fb 100644 --- a/NativeLauncher/src/waiter.h +++ b/NativeLauncher/src/waiter.h @@ -1,13 +1,50 @@ #include #include -using std::string; +#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: @@ -18,28 +55,22 @@ class Waiter string PkgId; string PkgType; }; - using Action = std::function; - using Executor = std::function; - - Waiter(Action prepare, Action requested, Executor executor); - ~Waiter(); int WaitToLaunching(int argc, char *argv[]); void Stop(); void RegisterFd(int fd, Receiver receiver); void DeregisterFd(int fd); + void SetContext(WaiterContext ctx); protected: - void OnPrepare(); - void OnLaunchRequested(const AppInfo&); + void OnPrepared(); + void OnRequested(const AppInfo&); void OnWaiting(); + void OnExecuted(const char *path, const char *app_root, int argc, char *argv[]); private: - - Action prepare_; - Action requested_; - Executor executor_; + WaiterContext context; }; } // namespace runtime diff --git a/Tizen.Runtime/Tizen.CoreFX.Ref.Targets b/Tizen.Runtime/Tizen.CoreFX.Ref.Targets index f2484c1..8c1d628 100644 --- a/Tizen.Runtime/Tizen.CoreFX.Ref.Targets +++ b/Tizen.Runtime/Tizen.CoreFX.Ref.Targets @@ -1,8 +1,8 @@ - /opt/usr/share/tizen.net/ref - /usr/share/assembly + /opt/usr/share/tizen.net/ref + /usr/share/assembly @@ -11,7 +11,12 @@ $(CoreFXRefPath);$(TizenDeviceAPIPath) false - 1701 + 1701, 1702 + + + + $(ExternalCscDir) + $(ExternalCscExe) @@ -27,8 +32,11 @@ - + + + + @@ -40,8 +48,4 @@ - - - CheckEnvironment - diff --git a/Tizen.Runtime/Tizen.Runtime.csproj b/Tizen.Runtime/Tizen.Runtime.csproj index ffe4d9c..ed996ac 100644 --- a/Tizen.Runtime/Tizen.Runtime.csproj +++ b/Tizen.Runtime/Tizen.Runtime.csproj @@ -4,7 +4,7 @@ Debug AnyCPU - Library + exe Tizen.Runtime @@ -22,21 +22,44 @@ TRACE + + + + $(DefineConstants);CLOG + + - + + + + + + + <_Parameter1>ConfigPath=$(LauncherConfigPath) + + + + + + + - + diff --git a/Tizen.Runtime/Tizen.Runtime/AssemblyLoader.cs b/Tizen.Runtime/Tizen.Runtime/AssemblyLoader.cs index e959146..a80e781 100644 --- a/Tizen.Runtime/Tizen.Runtime/AssemblyLoader.cs +++ b/Tizen.Runtime/Tizen.Runtime/AssemblyLoader.cs @@ -9,37 +9,80 @@ namespace Tizen.Runtime public class AssemblyLoader : AssemblyLoadContext { private SortedSet _dllDirectories = new SortedSet(); + private SortedSet _nativeDirectories = new SortedSet(); + public IEnumerable DllDirectories { get { return _dllDirectories; } } + public IEnumerable NativeDirectories + { + get { return _nativeDirectories; } + } + public void AddSearchableDirectory(string directory) { if (Directory.Exists(directory)) { _dllDirectories.Add(directory); + _nativeDirectories.Add(directory); } } public void RemoveSearchableDirectory(string directory) { _dllDirectories.Remove(directory); + _nativeDirectories.Remove(directory); } protected override Assembly Load(AssemblyName assemblyName) { - ALog.Debug($"Load!! : {assemblyName.Name}"); - foreach (string dir in DllDirectories) + ALog.Debug($"Load DLL : {assemblyName.Name}"); + Assembly asm = null; + + try + { + asm = Assembly.Load(assemblyName); + } + catch (Exception ex) + when (ex is FileNotFoundException || + ex is BadImageFormatException || + ex is FileLoadException) { - FileInfo f = new FileInfo(Path.Combine(dir, $"{assemblyName.Name}.dll")); - ALog.Debug(f.FullName); - if (File.Exists(f.FullName)) + ALog.Debug("Search DLL in added directories"); + foreach (string dir in DllDirectories) { - return LoadFromAssemblyPath(f.FullName); + FileInfo f = new FileInfo(Path.Combine(dir, $"{assemblyName.Name}.dll")); + if (File.Exists(f.FullName)) + { + asm = LoadFromAssemblyPath(f.FullName); + break; + } } } - return Assembly.Load(assemblyName); + return asm; + } + + protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) + { + ALog.Debug($"Load Native : {unmanagedDllName}"); + IntPtr native = base.LoadUnmanagedDll(unmanagedDllName); + if (native == IntPtr.Zero) + { + ALog.Debug("Search native lib in added directories"); + foreach (string dir in NativeDirectories) + { + FileInfo f = new FileInfo(Path.Combine(dir, unmanagedDllName)); + if (File.Exists(f.FullName)) + { + native = LoadUnmanagedDllFromPath(f.FullName); + break; + } + } + } + + return native; } } } diff --git a/Tizen.Runtime/Tizen.Runtime/AssemblyManager.cs b/Tizen.Runtime/Tizen.Runtime/AssemblyManager.cs index f7a7810..1f50867 100644 --- a/Tizen.Runtime/Tizen.Runtime/AssemblyManager.cs +++ b/Tizen.Runtime/Tizen.Runtime/AssemblyManager.cs @@ -2,25 +2,128 @@ using System.IO; using System.Reflection; using System.Runtime.Loader; +using System.Linq; namespace Tizen.Runtime { public static class AssemblyManager { - private static void PrintException(Exception exception) + public static int Prepared(IntPtr data) { - while (exception != null) + try { - ALog.Debug(exception.Message); - ALog.Debug(exception.StackTrace); - exception = exception.InnerException; + string configPath = "file:///etc/dotnet-launcher.ini"; + ICustomAttributeProvider assembly = typeof(AssemblyManager).GetTypeInfo().Assembly; + var attributes = assembly.GetCustomAttributes(typeof(DefaultConfigAttribute), false); + if (attributes.Length > 0 && attributes[0] is DefaultConfigAttribute) + { + DefaultConfigAttribute dca = (DefaultConfigAttribute)attributes[0]; + FileInfo f = new FileInfo(dca.Config["ConfigPath"]); + if (File.Exists(f.FullName)) + { + configPath = "file://"+f.FullName; + } + } + + Ini ini = new Ini(new Uri(configPath)); + var dotnet = ini["dotnet"]; + foreach(var kv in dotnet) + { + ALog.Debug(kv.Key + " = " + kv.Value); + } + + string preloadDlls = ""; + string preloadDllDirs = ""; + var preloads = ini["preloads"]; + if (preloads != null) + { + foreach (string key in preloads.Keys) + { + FileInfo f = new FileInfo(key); + if (File.Exists(f.FullName)) + { + preloadDlls += f.FullName + ":"; + preloadDllDirs += f.Directory + ":"; + } + } + } + + if (!Initialize(preloadDllDirs, preloadDlls)) + { + return 1; + } } + catch(Exception e) + { + ALog.Debug("Exception at Preparing"); + PrintException(e); + return 1; + } + return 0; } - public static AssemblyLoader CurrentAssemblyLoaderContext + public static int Requested(IntPtr data) { - get; - private set; + return 0; + } + + public static int Executed(string path, string app_root, int argc, string[] argv, IntPtr data) + { + try + { + FileInfo f = new FileInfo(path); + CurrentAssemblyLoaderContext.AddSearchableDirectory(f.Directory.FullName); + DirectoryInfo d = new DirectoryInfo(app_root); + CurrentAssemblyLoaderContext.AddSearchableDirectory(d.FullName); + Execute(path); + } + catch(Exception e) + { + ALog.Debug("Exception at Executing"); + PrintException(e); + return 1; + } + + try + { + Finish(); + } + catch(Exception e) + { + ALog.Debug("Exception at Finishing"); + PrintException(e); + return 1; + } + return 0; + } + + static Interop.PreparedCallback preparedCallback; + static Interop.RequestedCallback requestedCallback; + static Interop.ExecutedCallback executedCallback; + + public static void Main(string[] args) + { + try + { + preparedCallback = Prepared; + requestedCallback = Requested; + executedCallback = Executed; + Interop.register_launching_callback(preparedCallback, requestedCallback, executedCallback, IntPtr.Zero); + Interop.wait_for_launching(args.Length, args); + } + catch(Exception e) + { + PrintException(e); + } + } + + private static void PrintException(Exception exception) + { + while (exception != null) + { + ALog.Debug(exception.ToString()); + exception = exception.InnerException; + } } public static bool Initialize(string searchableDirectories, string preloadDllPaths) @@ -31,7 +134,7 @@ namespace Tizen.Runtime if (searchableDirectories != null) { - string[] dirs = searchableDirectories.Split(':'); + string[] dirs = searchableDirectories.Split(new char[]{':'}, StringSplitOptions.None); foreach (string dir in dirs) { CurrentAssemblyLoaderContext.AddSearchableDirectory(dir); @@ -40,9 +143,10 @@ namespace Tizen.Runtime if (preloadDllPaths != null) { - string[] dllPaths = preloadDllPaths.Split(':'); + string[] dllPaths = preloadDllPaths.Split(new char[]{':'}, StringSplitOptions.None); foreach (string dllPath in dllPaths) { + if (string.IsNullOrWhiteSpace(dllPath)) continue; FileInfo f = new FileInfo(dllPath); if (File.Exists(f.FullName)) { @@ -82,6 +186,24 @@ namespace Tizen.Runtime public static void Finish() { + ALog.Debug("-------- Dll Search Dir"); + foreach (string dir in CurrentAssemblyLoaderContext.DllDirectories) + { + ALog.Debug(dir); + } + + ALog.Debug("-------- Native Search Dir"); + foreach (string dir in CurrentAssemblyLoaderContext.NativeDirectories) + { + ALog.Debug(dir); + } + } + + public static AssemblyLoader CurrentAssemblyLoaderContext + { + get; + private set; } + } } diff --git a/Tizen.Runtime/Tizen.Runtime/DefaultConfigAttribute.cs b/Tizen.Runtime/Tizen.Runtime/DefaultConfigAttribute.cs new file mode 100644 index 0000000..f5ba0b0 --- /dev/null +++ b/Tizen.Runtime/Tizen.Runtime/DefaultConfigAttribute.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +[AttributeUsage(AttributeTargets.Assembly)] +public class DefaultConfigAttribute : Attribute { + public DefaultConfigAttribute() : this(string.Empty) {} + public DefaultConfigAttribute(string txt) + { + Config = new Dictionary(); + string[] keyvalues = txt.Split(new string[] {","}, StringSplitOptions.None); + foreach (string kvstr in keyvalues) + { + int eq_pos = kvstr.IndexOf('='); + if (eq_pos == -1) + throw new FormatException("Config must be written like \"Key1=Value1, Key2=Value2\""); + + string key = kvstr.Substring(0, eq_pos).Trim(); + string value = kvstr.Substring(eq_pos+1).Trim(); + Config[key] = value; + } + } + public Dictionary Config + { + get; + set; + } +} diff --git a/Tizen.Runtime/Tizen.Runtime/Ini.cs b/Tizen.Runtime/Tizen.Runtime/Ini.cs new file mode 100644 index 0000000..d5c2544 --- /dev/null +++ b/Tizen.Runtime/Tizen.Runtime/Ini.cs @@ -0,0 +1,139 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; + +namespace Tizen.Runtime +{ + internal class Ini + { + public string GlobalName = "___GLOBAL"; + public Ini(Uri path) + { + if (path.Scheme != "file") + { + throw new NotSupportedException("Only File Uri is supported now"); + } + string absPath = path.AbsolutePath; + Initialize(); + Contents = File.ReadAllText(absPath); + } + + public Ini(string contents) + { + Initialize(); + Contents = contents; + } + + public string Contents + { + get { return contents; } + + set + { + contents = value; + ReadContents(contents); + } + } + + public Dictionary this[string name] + { + get + { + if (groups.ContainsKey(name)) + return groups[name]; + return null; + } + } + + public override string ToString() + { + string str = ""; + + if (groups.ContainsKey(GlobalName)) + { + foreach (var kv in groups[GlobalName]) + { + str += $"{kv.Key} = {kv.Value}" + Environment.NewLine; + } + } + + foreach (var gkv in groups) + { + if (gkv.Key == GlobalName) continue; + str += $"[{gkv.Key}]" + Environment.NewLine; + foreach (var kv in gkv.Value) + { + str += $"{kv.Key} = {kv.Value}" + Environment.NewLine; + } + } + + return str; + } + + public Dictionary Global + { + get + { + return groups[GlobalName]; + } + } + + private void Initialize() + { + groups = new Dictionary >(); + groups[GlobalName] = new Dictionary(); + } + + private string Uncommont(string str) + { + int comment_start = str.IndexOf('#'); + return str.Substring(0, comment_start); + } + + private bool GetHeader(string str, ref string groupName) + { + if (str.Length < 2 || str[0] != '[' || str[str.Length-1] != ']') return false; + string expected = str.Substring(1, str.Length-2); + groupName = expected.Trim(); + return true; + } + + private void GetKeyValueFromString(string str, out string key, out string value) + { + int eq_pos = str.IndexOf('='); + if (eq_pos == -1) + { + key = str.Trim(); + value = ""; + } + else + { + key = str.Substring(0, eq_pos).Trim(); + value = str.Substring(eq_pos+1).Trim(); + } + } + + private void ReadContents(string contents) + { + string key, value; + string groupName = GlobalName; + string[] lines = contents.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); + + foreach (string line in lines) + { + if (string.IsNullOrWhiteSpace(line)) continue; + if (GetHeader(line, ref groupName)) + { + groups[groupName] = new Dictionary(); + continue; + } + GetKeyValueFromString(line, out key, out value); + groups[groupName][key] = value; + } + } + + private Dictionary > groups; + private string contents; + } +} diff --git a/Tizen.Runtime/Tizen.Runtime/Interop.cs b/Tizen.Runtime/Tizen.Runtime/Interop.cs new file mode 100644 index 0000000..3476a81 --- /dev/null +++ b/Tizen.Runtime/Tizen.Runtime/Interop.cs @@ -0,0 +1,20 @@ +using System; +using System.Runtime.InteropServices; + +internal static class Interop +{ + public const string Launcher = "dotnet-launcher"; + + internal delegate int PreparedCallback(IntPtr userData); + internal delegate int RequestedCallback(IntPtr userData); + internal delegate int ExecutedCallback(string path, string app_root, int argc, string[] argv, IntPtr userData); + + [DllImport(Launcher)] + internal static extern void register_launching_callback( + [MarshalAs(UnmanagedType.FunctionPtr)] PreparedCallback prepared, + [MarshalAs(UnmanagedType.FunctionPtr)] RequestedCallback requested, + [MarshalAs(UnmanagedType.FunctionPtr)] ExecutedCallback executed, IntPtr userData); + + [DllImport(Launcher)] + internal static extern void wait_for_launching(int argc, string[] argv); +} diff --git a/packaging/dotnet-launcher.spec b/packaging/dotnet-launcher.spec index 353ab99..883fae0 100644 --- a/packaging/dotnet-launcher.spec +++ b/packaging/dotnet-launcher.spec @@ -43,6 +43,7 @@ Launchpad plugin for launching dotnet apps cmake \ -DCMAKE_INSTALL_PREFIX=%{_prefix} \ -DPACKAGE_NAME=%{name} \ + -DLIBDIR=%{_libdir} \ -DBINDIR=%{_bindir} \ -DLOADERDIR=%{_loaderdir} \ -DCONFIGDIR=%{_configdir} \ @@ -57,11 +58,12 @@ xbuild /p:Configuration=%{_buildmode} Tizen.Runtime/Tizen.Runtime.csproj %install rm -rf %{buildroot} %make_install -install -p -m 644 Tizen.Runtime/bin/Tizen.Runtime.dll %{buildroot}%{_bindir} +install -p -m 644 Tizen.Runtime/bin/Tizen.Runtime.exe %{buildroot}%{_bindir} %files %manifest dotnet-launcher.manifest %config /etc/dotnet-launcher.ini %{_loaderdir}/dotnet.loader %caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/dotnet-launcher -%caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/Tizen.Runtime.dll +%caps(cap_mac_admin,cap_setgid=ei) %{_libdir}/libdnclauncher.so +%caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/Tizen.Runtime.exe diff --git a/test_build_on_desktop.sh b/test_build_on_desktop.sh new file mode 100755 index 0000000..90a8583 --- /dev/null +++ b/test_build_on_desktop.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +#CoreFXRefPath=`readlink -e ../dlls/corefx_refs/` +#TizenDeviceAPIPath=`readlink -e ../dlls/tizen_deviceapis/` +CoreFXRefPath=`readlink -e ../dlls/desktop/` +TizenDeviceAPIPath=`readlink -e ../dlls/tizen_deviceapis/` +LauncherConfigPath=./dotnet-launcher.ini +RoslynCscDir=/home/idkiller/work/runtime/roslyn/Binaries/Debug/csccore +RoslynCscExe=csc + +mkdir build +cd build +cmake -DCMAKE_BUILD_TYPE=Debug -DNO_TIZEN=1 -DLAUNCHER_CONFIG_PATH=$LauncherConfigPath -DLAUNCHER_ASSEMBLY_PATH=Tizen.Runtime.dll ../NativeLauncher/ +make +xbuild /t:Clean ../Tizen.Runtime/Tizen.Runtime.csproj +#xbuild /verbosity:diagnostic /p:CLOG=1 /p:ExternalCscPath=/home/idkiller/work/runtime/roslyn/Binaries/Debug/csccore/csc.exe /p:LauncherConfigPath=$LauncherConfigPath /p:CoreFXRefPath=$CoreFXRefPath /p:TizenDeviceAPIPath=$TizenDeviceAPIPath ../Tizen.Runtime/Tizen.Runtime.csproj +xbuild /p:CLOG=1 /p:ExternalCscDir=$RoslynCscDir /p:ExternalCscExe=$RoslynCscExe /p:LauncherConfigPath=$LauncherConfigPath /p:CoreFXRefPath=$CoreFXRefPath /p:TizenDeviceAPIPath=$TizenDeviceAPIPath ../Tizen.Runtime/Tizen.Runtime.csproj +cp ../Tizen.Runtime/bin/Tizen.Runtime.* . +cp ../NativeLauncher/dotnet-launcher.ini . -- 2.7.4