diff options
author | pius.lee <pius.lee@samsung.com> | 2016-10-10 14:12:09 +0900 |
---|---|---|
committer | pius.lee <pius.lee@samsung.com> | 2016-10-10 14:12:09 +0900 |
commit | f15cc24b978a6650d51ccb3d62cef85ec2ad0306 (patch) | |
tree | 5909ea4cbfd762697dbefba88a625ff565632dd6 | |
parent | 1d184dbef0419136311f9ca300df581721511d27 (diff) | |
download | launcher-f15cc24b978a6650d51ccb3d62cef85ec2ad0306.tar.gz launcher-f15cc24b978a6650d51ccb3d62cef85ec2ad0306.tar.bz2 launcher-f15cc24b978a6650d51ccb3d62cef85ec2ad0306.zip |
Coreclr & Mono Supported launcher and standalone
Switch launcher engine with "/etc/.use_mono" file
Now can run assembly standalone with "--standalone" option
Change-Id: I120053756f4d86107dfe716cf5675389b7a9760d
20 files changed, 887 insertions, 676 deletions
diff --git a/NativeLauncher/CMakeLists.txt b/NativeLauncher/CMakeLists.txt index 203ffb7..00657be 100644 --- a/NativeLauncher/CMakeLists.txt +++ b/NativeLauncher/CMakeLists.txt @@ -18,9 +18,13 @@ 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) +IF(DEFINED CORECLR_LAUNCHER_ASSEMBLY_PATH) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DCORECLR_LAUNCHER_ASSEMBLY_PATH=${CORECLR_LAUNCHER_ASSEMBLY_PATH}") +ENDIF(DEFINED CORECLR_LAUNCHER_ASSEMBLY_PATH) + +IF(DEFINED MONO_LAUNCHER_ASSEMBLY_PATH) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DMONO_LAUNCHER_ASSEMBLY_PATH=${MONO_LAUNCHER_ASSEMBLY_PATH}") +ENDIF(DEFINED MONO_LAUNCHER_ASSEMBLY_PATH) IF(DEFINED DEVICE_API_DIR) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DDEVICE_API_DIR=${DEVICE_API_DIR}") @@ -30,7 +34,7 @@ IF(DEFINED RUNTIME_DIR) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DRUNTIME_DIR=${RUNTIME_DIR}") ENDIF(DEFINED RUNTIME_DIR) -SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -pthread -std=c++11 -Wl,--no-as-needed") +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") @@ -49,10 +53,11 @@ SET(DOTNET_LAUNCHER "dotnet-launcher") SET(MONO_LAUNCHER "mono-launcher") SET(${DOTNET_LAUNCHER}_SOURCE_FILES + src/main.cc src/utils.cc src/launcher.cc src/dotnet/dotnet_launcher.cc - src/dotnet/base64.cc + src/mono/mono_launcher.cc ) ADD_EXECUTABLE(${DOTNET_LAUNCHER} ${${PROJECT_NAME}_SOURCE_FILES}) diff --git a/NativeLauncher/inc/launcher.h b/NativeLauncher/inc/launcher.h index f4309b4..399bef5 100644 --- a/NativeLauncher/inc/launcher.h +++ b/NativeLauncher/inc/launcher.h @@ -1,28 +1,37 @@ #ifndef __LAUNCHER_INTERFACE_H__ #define __LAUNCHER_INTERFACE_H__ +#include <string> +#include <functional> + namespace tizen { namespace runtime { class LauncherInterface { public: - virtual int Initialize() = 0; + virtual int Initialize(bool standalone) = 0; virtual void Dispose() = 0; virtual int RunManagedLauncher() = 0; - virtual int Launch(const char* path, int argc, char* argv[]) = 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(LauncherInterface* launcher, int argc, char* argv[]) = 0; - virtual void WaitUtilLaunched() = 0; - - protected: - virtual void OnCreate() = 0; - virtual void OnLaunch() = 0; - virtual void OnTerminate() = 0; + virtual void LoaderMain(int argc, char* argv[]) = 0; + std::function<void()> OnCreate = nullptr; + std::function<void(const AppInfo&, int, char**)> OnLaunch = nullptr; + std::function<void(const AppInfo&, int, char**)> OnTerminate = nullptr; }; extern LaunchpadAdapter& Launchpad; diff --git a/NativeLauncher/src/dotnet/base64.cc b/NativeLauncher/src/dotnet/base64.cc deleted file mode 100644 index 3330082..0000000 --- a/NativeLauncher/src/dotnet/base64.cc +++ /dev/null @@ -1,94 +0,0 @@ -#include "base64.h" -#include <iostream> - -static const std::string base64_chars = -"ABCDEFGHIJKLMNOPQRSTUVWXYZ" -"abcdefghijklmnopqrstuvwxyz" -"0123456789+/"; - - -static inline bool is_base64(BYTE c) { - return (isalnum(c) || (c == '+') || (c == '/')); -} - -std::string base64_encode(BYTE const* buf, unsigned int bufLen) { - std::string ret; - int i = 0; - int j = 0; - BYTE char_array_3[3]; - BYTE char_array_4[4]; - - while (bufLen--) { - char_array_3[i++] = *(buf++); - if (i == 3) { - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for(i = 0; (i <4) ; i++) - ret += base64_chars[char_array_4[i]]; - i = 0; - } - } - - if (i) - { - for(j = i; j < 3; j++) - char_array_3[j] = '\0'; - - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (j = 0; (j < i + 1); j++) - ret += base64_chars[char_array_4[j]]; - - while((i++ < 3)) - ret += '='; - } - - return ret; -} - -std::vector<BYTE> base64_decode(std::string const& encoded_string) { - int in_len = encoded_string.size(); - int i = 0; - int j = 0; - int in_ = 0; - BYTE char_array_4[4], char_array_3[3]; - std::vector<BYTE> ret; - - while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++] = encoded_string[in_]; in_++; - if (i ==4) { - for (i = 0; i <4; i++) - char_array_4[i] = base64_chars.find(char_array_4[i]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (i = 0; (i < 3); i++) - ret.push_back(char_array_3[i]); - i = 0; - } - } - - if (i) { - for (j = i; j <4; j++) - char_array_4[j] = 0; - - for (j = 0; j <4; j++) - char_array_4[j] = base64_chars.find(char_array_4[j]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (j = 0; (j < i - 1); j++) ret.push_back(char_array_3[j]); - } - - return ret; -} diff --git a/NativeLauncher/src/dotnet/base64.h b/NativeLauncher/src/dotnet/base64.h deleted file mode 100644 index 1a6b6ba..0000000 --- a/NativeLauncher/src/dotnet/base64.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _BASE64_H_ -#define _BASE64_H_ - -#include <vector> -#include <string> -typedef unsigned char BYTE; - -std::string base64_encode(BYTE const* buf, unsigned int bufLen); -std::vector<BYTE> base64_decode(std::string const&); - -#endif diff --git a/NativeLauncher/src/dotnet/dotnet_launcher.cc b/NativeLauncher/src/dotnet/dotnet_launcher.cc index 4942710..62738a3 100644 --- a/NativeLauncher/src/dotnet/dotnet_launcher.cc +++ b/NativeLauncher/src/dotnet/dotnet_launcher.cc @@ -3,7 +3,6 @@ #include <string> #include <fstream> -#include <thread> #include <vector> #include "utils.h" @@ -15,43 +14,12 @@ namespace tizen { namespace runtime { namespace dotnetcore { - -void CoreRuntime::SetStandaloneExe(const char* exePath, int argc, char* argv[]) -{ - if (exePath == nullptr) - { - _ERR("executable path is null"); - return; - } - - if (FileNotExist(exePath)) - { - _ERR("File not exist : %s", exePath); - return; - } - - isLaunched = true; - LaunchParam.path = exePath; - LaunchParam.argc = argc; - LaunchParam.argv = argv; - - 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; -} - CoreRuntime::CoreRuntime() : coreclrLib(nullptr), hostHandle(nullptr), domainId(-1), + PreparedFunction(nullptr), LaunchFunction(nullptr), - isLaunched(false), InitializeClr(nullptr), ExecuteAssembly(nullptr), Shutdown(nullptr), @@ -66,8 +34,8 @@ CoreRuntime::CoreRuntime() : #ifdef RUNTIME_DIR RuntimeDirectory = __STR(RUNTIME_DIR); #endif -#ifdef LAUNCHER_ASSEMBLY_PATH - LauncherAssembly = __STR(LAUNCHER_ASSEMBLY_PATH); +#ifdef CORECLR_LAUNCHER_ASSEMBLY_PATH + LauncherAssembly = __STR(CORECLR_LAUNCHER_ASSEMBLY_PATH); #endif #undef __STR @@ -81,9 +49,22 @@ CoreRuntime::~CoreRuntime() Dispose(); } -int CoreRuntime::Initialize() +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"); @@ -190,7 +171,7 @@ int CoreRuntime::RunManagedLauncher() "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]); @@ -224,40 +205,34 @@ int CoreRuntime::RunManagedLauncher() _DBG("Initialize core clr success"); - void *launchFunctionDelegate; + void *preparedFunctionDelegate; st = CreateDelegate(hostHandle, domainId, - "Tizen.Runtime", - "Tizen.Runtime.AssemblyManager", - "Launch", &launchFunctionDelegate); + "Tizen.Runtime.Coreclr", + "Tizen.Runtime.Coreclr.AssemblyManager", + "Prepared", &preparedFunctionDelegate); if (st < 0) { - _ERR("Create delegate for Launch managed function is fail! (0x%08x)", st); + _ERR("Create delegate for Launch prepared function is fail (0x%08x)", st); return 1; } - LaunchFunction = reinterpret_cast<LaunchFunctionPtr>(launchFunctionDelegate); + PreparedFunction = reinterpret_cast<PreparedFunctionPtr>(preparedFunctionDelegate); - if (isLaunched) + if(PreparedFunction != nullptr) { - bool success = LaunchFunction(LaunchParam.path.c_str(), - LaunchParam.argc, LaunchParam.argv); - if (!success) - { - _ERR("Failed to Launching"); - } + PreparedFunction(); } - /* - unsigned int exitCode; - const char* argv[] = {LauncherAssembly.c_str()}; - st = ExecuteAssembly(hostHandle, domainId, - 1, argv, LauncherAssembly.c_str(), &exitCode); - _DBG("after execute coreclr"); + void *launchFunctionDelegate; + st = CreateDelegate(hostHandle, domainId, + "Tizen.Runtime.Coreclr", + "Tizen.Runtime.Coreclr.AssemblyManager", + "Launch", &launchFunctionDelegate); if (st < 0) { - _ERR("execute core clr fail! (0x%08x / %d)", st, exitCode); + _ERR("Create delegate for Launch managed function is fail! (0x%08x)", st); return 1; } - */ + LaunchFunction = reinterpret_cast<LaunchFunctionPtr>(launchFunctionDelegate); return 0; } @@ -282,67 +257,32 @@ void CoreRuntime::Dispose() _DBG("Dotnet runtime disposed"); } -int CoreRuntime::Launch(const char* path, int argc, char* argv[]) +int CoreRuntime::Launch(const char* root, const char* path, int argc, char* argv[]) { - if (LaunchFunction != nullptr) + if (path == nullptr) { - LaunchFunction(path, argc, argv); + _ERR("executable path is null"); + return 1; } - else + + if (FileNotExist(path)) { - LaunchParam.path = path; - LaunchParam.argc = argc; - LaunchParam.argv = argv; + _ERR("File not exist : %s", path); + return 1; } - isLaunched = true; - return 0; -} - -} // namespace dotnetcore -} // namespace runtime -} // namespace tizen - -static std::string StandaloneOption("--standalone"); - -#include "base64.h" - -int main(int argc, char *argv[]) -{ - int i; - bool standalone = false; - const char* standalonePath = nullptr; - - for (i=1; i<argc; i++) + bool success = false; + if (LaunchFunction != nullptr) { - if (StandaloneOption.compare(argv[i]) == 0) - { - standalone = true; - } - else + success = LaunchFunction(root, path, argc, argv); + if (!success) { - if (standalonePath == nullptr) - standalonePath = argv[i]; + _ERR("Failed to launch Application %s", path); } } - - tizen::runtime::dotnetcore::CoreRuntime runtime; - if (standalone) - { - runtime.SetStandaloneExe(standalonePath, argc, argv); - } - else - { - tizen::runtime::Launchpad.LoaderMain(&runtime, argc, argv); - } - - runtime.Initialize(); - runtime.RunManagedLauncher(); - - if (!standalone) - { - tizen::runtime::Launchpad.WaitUtilLaunched(); - } - - return 0; + return success ? 0 : 1; } + +} // namespace dotnetcore +} // namespace runtime +} // namespace tizen diff --git a/NativeLauncher/src/dotnet/dotnet_launcher.h b/NativeLauncher/src/dotnet/dotnet_launcher.h index e1a86b0..92567f6 100644 --- a/NativeLauncher/src/dotnet/dotnet_launcher.h +++ b/NativeLauncher/src/dotnet/dotnet_launcher.h @@ -36,25 +36,18 @@ namespace tizen { namespace runtime { namespace dotnetcore { -typedef bool (*LaunchFunctionPtr)(const char* path, int argc, char* argv[]); - -struct LaunchParameter -{ - std::string path; - int argc; - char** argv; -}; +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() override; + int Initialize(bool standalone) override; void Dispose() override; int RunManagedLauncher() override; - int Launch(const char* path, int argc, char* argv[]) override; - void SetStandaloneExe(const char* exePath, int argc, char* argv[]); + int Launch(const char* root, const char* path, int argc, char* argv[]) override; private: coreclr_initialize_ptr InitializeClr; @@ -67,9 +60,8 @@ class CoreRuntime : public tizen::runtime::LauncherInterface void* coreclrLib; void* hostHandle; unsigned int domainId; + PreparedFunctionPtr PreparedFunction; LaunchFunctionPtr LaunchFunction; - bool isLaunched; - LaunchParameter LaunchParam; }; } // dotnetcore diff --git a/NativeLauncher/src/launcher.cc b/NativeLauncher/src/launcher.cc index 518a1d9..9efd49e 100644 --- a/NativeLauncher/src/launcher.cc +++ b/NativeLauncher/src/launcher.cc @@ -2,55 +2,46 @@ #include "log.h" #include <launchpad.h> +#include <aul.h> -#include <poll.h> +#include <Ecore.h> #include <map> #include <vector> #include <functional> -#include <thread> + +#include <unistd.h> + namespace tizen { namespace runtime { struct FdHandler { - pollfd *info; - std::function<void(int)> receiver; + Ecore_Fd_Handler *handler; + loader_receiver_cb receiver; }; class LaunchpadAdapterImpl : public LaunchpadAdapter { public: LaunchpadAdapterImpl() : isLaunched(false) { } - void LoaderMain(LauncherInterface* launcher, int argc, char* argv[]) override; - void WaitUtilLaunched() override; + void LoaderMain(int argc, char* argv[]) override; - protected: - void OnCreate() override; - void OnLaunch() override; - void OnTerminate() override; + std::map<int, FdHandler> Handlers; private: + AppInfo appinfo; loader_lifecycle_callback_s callbacks; loader_adapter_s adapter; LauncherInterface* launcher; bool isLaunched; std::string launchPath; - - bool Waiting; - std::vector<pollfd> FdList; - std::map<int, FdHandler> Handlers; - - std::thread pollingThread; }; LaunchpadAdapterImpl LaunchpadImpl; LaunchpadAdapter& Launchpad = LaunchpadImpl; -void LaunchpadAdapterImpl::LoaderMain(LauncherInterface* launcher, int argc, char* argv[]) -{ - this->launcher = launcher; #define WITH_SELF(data) \ LaunchpadAdapterImpl* self = static_cast<LaunchpadAdapterImpl*>(data); \ if (self == nullptr) \ @@ -58,12 +49,75 @@ void LaunchpadAdapterImpl::LoaderMain(LauncherInterface* launcher, int argc, cha _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_Handler_Flags>(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) { - self->OnCreate(); + if (self->OnCreate != nullptr) + self->OnCreate(); } }; callbacks.launch = [](int argc, char** argv, const char* app_path, @@ -72,8 +126,13 @@ void LaunchpadAdapterImpl::LoaderMain(LauncherInterface* launcher, int argc, cha { WITH_SELF(user_data) { - self->OnLaunch(); - self->launchPath = std::string(app_path); + 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; @@ -83,108 +142,30 @@ void LaunchpadAdapterImpl::LoaderMain(LauncherInterface* launcher, int argc, cha _DBG("Terminate!!"); WITH_SELF(user_data) { - self->OnTerminate(); - //self->launcher->Launch(self->launchPath.c_str(), argc, argv); + if (self->OnTerminate != nullptr) + self->OnTerminate(self->appinfo, argc, argv); } return 0; }; adapter.loop_begin = [](void *data) { - _DBG("start polling..."); - WITH_SELF(data) - { - self->Waiting = true; - while(self->Waiting) - { - if (poll(self->FdList.data(), self->FdList.size(), -1) < 0) - continue; - - _DBG("-----------------------------------------------------------4"); - for (auto &p : self->FdList) - { - if ( (p.revents | POLLIN) != 0) - self->Handlers[p.fd].receiver(p.fd); - } - _DBG("-----------------------------------------------------------5"); - } - } - _DBG("end polling..."); + ecore_main_loop_begin(); }; adapter.loop_quit = [](void *data) { - WITH_SELF(data) - { - self->Waiting = false; - } - }; - - adapter.add_fd = [](void *data, int fd, loader_receiver_cb receiver) - { - WITH_SELF(data) - { - pollfd info; - FdHandler handler; - - info.fd = fd; - info.events = POLLIN; - info.revents = 0; - - self->FdList.push_back(info); - handler.info = &((self->FdList).back()); - handler.receiver = receiver; - - self->Handlers[fd] = handler; - } - }; - - adapter.remove_fd = [](void *user_data, int fd) - { - WITH_SELF(user_data) - { - pollfd *info = self->Handlers[fd].info; - self->FdList.erase(self->FdList.begin() - (info - &(self->FdList.front()))); - self->Handlers.erase(fd); - } + ecore_main_loop_quit(); }; + adapter.add_fd = Fd_Add; + adapter.remove_fd = Fd_Remove; - pollingThread = std::thread([this, argc, argv]() - { - _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); - }); - //pollingThread.detach(); -} - -void LaunchpadAdapterImpl::WaitUtilLaunched() -{ - try - { - if (pollingThread.joinable()) - { - pollingThread.join(); - } - } - catch (const std::exception& ex) - { - _ERR("Exception : %s", ex.what()); - } -} - -void LaunchpadAdapterImpl::OnCreate() -{ -} - -void LaunchpadAdapterImpl::OnLaunch() -{ -} - -void LaunchpadAdapterImpl::OnTerminate() -{ + _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 new file mode 100644 index 0000000..97ff67c --- /dev/null +++ b/NativeLauncher/src/main.cc @@ -0,0 +1,108 @@ +#include "dotnet/dotnet_launcher.h" +#include "mono/mono_launcher.h" +#include "utils.h" +#include "log.h" + +#include <memory> + +#include <Ecore.h> +#include <Eina.h> + +static std::string StandaloneOption("--standalone"); + +int main(int argc, char *argv[]) +{ + int i; + bool standalone = false; + const char* standalonePath = nullptr; + + for (i=1; i<argc; i++) + { + if (StandaloneOption.compare(argv[i]) == 0) + { + standalone = true; + } + else + { + if (standalonePath == nullptr) + standalonePath = argv[i]; + } + } + + using tizen::runtime::LauncherInterface; + using tizen::runtime::Launchpad; + using tizen::runtime::AppInfo; + std::unique_ptr<LauncherInterface> runtime; + + bool useMono = !FileNotExist("/etc/.use_mono"); + + if (!useMono) + { + using tizen::runtime::dotnetcore::CoreRuntime; + std::unique_ptr<LauncherInterface> coreRuntime(new CoreRuntime()); + runtime = std::move(coreRuntime); + } + else + { + using tizen::runtime::mono::MonoRuntime; + std::unique_ptr<LauncherInterface> monoRuntime(new MonoRuntime()); + runtime = std::move(monoRuntime); + } + + if (standalone) + { + std::string base = Basename(standalonePath); + if (runtime->Initialize(true) != 0) + { + _ERR("Failed to initialize"); + return 1; + } + if (runtime->RunManagedLauncher() != 0) + { + _ERR("Failed to run managed launcher"); + return 1; + } + if (!runtime->Launch(base.c_str(), standalonePath, argc, argv)) + { + _ERR("Failed to launch"); + return 1; + } + } + else + { + Launchpad.OnCreate = [&runtime] + { + auto idle_task = [](void *data) -> Eina_Bool + { + LauncherInterface* runtime = static_cast<LauncherInterface*>(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 new file mode 100644 index 0000000..fff1104 --- /dev/null +++ b/NativeLauncher/src/mono/mono_launcher.cc @@ -0,0 +1,213 @@ + +#include "mono_launcher.h" +#include "utils.h" +#include "log.h" + +#include <dlfcn.h> +#include <string> + +namespace tizen { +namespace runtime { +namespace mono { + +static const char* LIBMONO = "/usr/lib/libmono-2.0.so.1"; + +MonoRuntime::MonoRuntime() : + monolib(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"); + +#undef MONOLIB_RETURN_IF_NOSYM + + _DBG("libmono dlopen and dlsym success"); + + return 0; +} + +void MonoRuntime::Dispose() +{ + 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("tizen_mono_domain"); + 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[]) +{ + MonoString *rootMonoString = NewString(domain, root); + MonoString *pathMonoString = NewString(domain, path); + MonoArray *argvMonoArray = ArrayNew(domain, GetStringClass(), argc); + for (int i=0; i<argc; i++) + { + MonoString *arg = NewString(domain, argv[i]); + ArraySet(argvMonoArray, MonoString*, i, arg); + } + + void **args = new void*[argc+2]; + args[0] = rootMonoString; + args[1] = pathMonoString; + args[2] = &argc; + args[3] = argvMonoArray; + + MonoObject* exception = nullptr; + RuntimeInvoke(launch, nullptr, args, &exception); + if (exception != nullptr) + { + MonoString * exceptionMsg = ObjectToString(exception, nullptr); + char* cstringMsg = StringToUtf8(exceptionMsg); + _ERR("Failed to invoke launch method in runtime"); + _ERR("%s", cstringMsg); + free(cstringMsg); + return 1; + } + return 0; +} + +} // namespace dotnetcore +} // namespace runtime +} // namespace mono diff --git a/NativeLauncher/src/mono/mono_launcher.h b/NativeLauncher/src/mono/mono_launcher.h new file mode 100644 index 0000000..8aa5a4b --- /dev/null +++ b/NativeLauncher/src/mono/mono_launcher.h @@ -0,0 +1,78 @@ +#include "launcher.h" + +extern "C" +{ + typedef struct _MonoDomain MonoDomain; + typedef struct _NonoAssembly MonoAssembly; + typedef struct _MonoImage MonoImage; + typedef struct _MonoClass MonoClass; + typedef struct _MonoObject MonoObject; + typedef struct _MonoMethod MonoMethod; + typedef struct _MonoString MonoString; + typedef struct _MonoArray MonoArray; + + typedef void (*mono_set_dirs_ptr) (const char *, const char *); + typedef void (*mono_set_assemblies_path_ptr) (const char*); + typedef MonoDomain* (*mono_jit_init_ptr) (const char *); + typedef void (*mono_config_parse_ptr) (const char *); + typedef MonoAssembly* (*mono_domain_assembly_open_ptr) (MonoDomain *, const char *); + typedef MonoImage* (*mono_assembly_get_image_ptr) (MonoAssembly *); + typedef MonoClass* (*mono_class_from_name_ptr) (MonoImage *, const char *, const char *); + typedef MonoObject* (*mono_runtime_invoke_ptr) (MonoMethod *, void *, void **, MonoObject **); + typedef MonoMethod* (*mono_class_get_method_from_name_ptr) (MonoClass *, const char *, int param_count); + typedef MonoString* (*mono_string_new_ptr) (MonoDomain *, const char *); + typedef MonoString* (*mono_object_to_string_ptr) (MonoObject *, MonoObject **); + typedef char* (*mono_string_to_utf8_ptr) (MonoString *string_obj); + + typedef MonoClass* (*mono_get_string_class_ptr) (); + typedef MonoArray* (*mono_array_new_ptr) (MonoDomain *, MonoClass *, uintptr_t); + typedef char* (*mono_array_addr_with_size_ptr) (MonoArray *, int, uintptr_t); +} + +namespace tizen { +namespace runtime { +namespace mono { + +class MonoRuntime : public tizen::runtime::LauncherInterface +{ + public: + MonoRuntime(); + ~MonoRuntime(); + 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: + void* monolib; + mono_set_dirs_ptr SetDirs; + mono_set_assemblies_path_ptr SetAssembliesPath; + mono_jit_init_ptr JitInit; + mono_domain_assembly_open_ptr DomainAssemblyOpen; + mono_assembly_get_image_ptr AssemblyGetImage; + mono_class_from_name_ptr ClassFromName; + mono_runtime_invoke_ptr RuntimeInvoke; + mono_class_get_method_from_name_ptr ClassGetMethodFromName; + mono_object_to_string_ptr ObjectToString; + mono_string_to_utf8_ptr StringToUtf8; + mono_string_new_ptr NewString; + mono_get_string_class_ptr GetStringClass; + mono_array_new_ptr ArrayNew; + mono_array_addr_with_size_ptr ArrayAddrWithSize; + + MonoDomain* domain; + MonoAssembly* launcherAssembly; + MonoImage* monoImage; + MonoClass* assemblyManagerClass; + MonoMethod* prepareLaunch; + MonoMethod* launch; + + std::string launcherAssemblyPath; + std::string deviceAPIDirectory; + std::string runtimeDirectory; +}; + + +} // namespace mono +} // namespace runtime +} // namespace tizen diff --git a/Tizen.Runtime/Tizen.Runtime.csproj b/Tizen.Runtime/Tizen.Runtime.Coreclr.csproj index a0fce08..32864ed 100644 --- a/Tizen.Runtime/Tizen.Runtime.csproj +++ b/Tizen.Runtime/Tizen.Runtime.Coreclr.csproj @@ -4,8 +4,8 @@ <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <OutputType>exe</OutputType> - <AssemblyName>Tizen.Runtime</AssemblyName> + <OutputType>library</OutputType> + <AssemblyName>Tizen.Runtime.Coreclr</AssemblyName> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)' == 'Debug'"> @@ -34,11 +34,9 @@ </PropertyGroup> <ItemGroup> - <Compile Include="Tizen.Runtime/AssemblyManager.cs" /> - <Compile Include="Tizen.Runtime/AssemblyLoader.cs" /> + <Compile Include="Tizen.Runtime.Coreclr/AssemblyManager.cs" /> + <Compile Include="Tizen.Runtime.Coreclr/AssemblyLoader.cs" /> <Compile Include="Tizen.Runtime/Log.cs" /> - <Compile Include="Tizen.Runtime/Interop.cs" /> - <Compile Include="Tizen.Runtime/Ini.cs" /> <Compile Include="Tizen.Runtime/DefaultConfigAttribute.cs" /> </ItemGroup> diff --git a/Tizen.Runtime/Tizen.Runtime/AssemblyLoader.cs b/Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyLoader.cs index 4b4a30b..2e21c7b 100644 --- a/Tizen.Runtime/Tizen.Runtime/AssemblyLoader.cs +++ b/Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyLoader.cs @@ -4,7 +4,7 @@ using System.Reflection; using System.Runtime.Loader; using System.Collections.Generic; -namespace Tizen.Runtime +namespace Tizen.Runtime.Coreclr { public class AssemblyLoader : AssemblyLoadContext { diff --git a/Tizen.Runtime/Tizen.Runtime/AssemblyManager.cs b/Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyManager.cs index 6a13648..ec342d5 100644 --- a/Tizen.Runtime/Tizen.Runtime/AssemblyManager.cs +++ b/Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyManager.cs @@ -5,28 +5,43 @@ using System.Runtime.Loader; using System.Linq; using System.Runtime.InteropServices; -namespace Tizen.Runtime +namespace Tizen.Runtime.Coreclr { public static class AssemblyManager { public static bool Launch( + [In] string rootPath, [In] string path, [In] int argc, - [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] + [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] [In] string[] argv) { - Console.WriteLine($"path : {path}"); - Console.WriteLine($"argc : {argc}"); - for (int i=0; i<argc; i++) + ALog.Debug($"Application Launch path : {path}"); + try { - Console.WriteLine($"argv[{i}] : " + argv[i]); + DirectoryInfo bindir = new DirectoryInfo(Path.Combine(rootPath, "bin")); + DirectoryInfo libdir = new DirectoryInfo(Path.Combine(rootPath, "lib")); + if (Directory.Exists(bindir.FullName)) + { + CurrentAssemblyLoaderContext.AddSearchableDirectory(bindir.FullName); + } + if (Directory.Exists(libdir.FullName)) + { + CurrentAssemblyLoaderContext.AddSearchableDirectory(libdir.FullName); + } + Execute(path, argv); + } + catch(Exception e) + { + ALog.Debug("Exception in Launch()"); + PrintException(e); + return false; } - Console.WriteLine(); return true; } - public static int Prepared(IntPtr data) + public static void Prepared() { try { @@ -44,74 +59,13 @@ namespace Tizen.Runtime if (!Initialize(preloadPath)) { - return 1; + ALog.Debug($"Failed to Initialized with {preloadPath}"); } } catch(Exception e) { ALog.Debug("Exception at Preparing"); PrintException(e); - return 1; - } - return 0; - } - - public static int Requested(IntPtr data) - { - return 0; - } - - public static int Executed(string path, string app_root, int argc, string[] argv, IntPtr data) - { - try - { - DirectoryInfo libdir = new DirectoryInfo(Path.Combine(app_root, "lib")); - if (Directory.Exists(libdir.FullName)) - { - CurrentAssemblyLoaderContext.AddSearchableDirectory(libdir.FullName); - } - Execute(path, argv); - } - 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); - */ - Console.WriteLine("HelloWorld!!"); - } - catch(Exception e) - { - PrintException(e); } } @@ -146,35 +100,6 @@ namespace Tizen.Runtime } } } - - /* - string LD_LIBRARY_PATH = Environment.GetEnvironmentVariable("LD_LIBRARY_PATH"); - if (!string.IsNullOrEmpty(LD_LIBRARY_PATH)) - { - string[] dirs = LD_LIBRARY_PATH.Split(new char[]{':'}, StringSplitOptions.None); - foreach (string dir in dirs) - { - DirectoryInfo d = new DirectoryInfo(dir); - if (Directory.Exists(d.FullName)) - { - CurrentAssemblyLoaderContext.AddSearchableDirectory(d.FullName); - } - } - } - - DirectoryInfo libdir = new DirectoryInfo("/lib"); - if (Directory.Exists(libdir.FullName)) - { - CurrentAssemblyLoaderContext.AddSearchableDirectory(libdir.FullName); - } - - DirectoryInfo usrlibdir = new DirectoryInfo("/usr/lib"); - if (Directory.Exists(usrlibdir.FullName)) - { - CurrentAssemblyLoaderContext.AddSearchableDirectory(usrlibdir.FullName); - } - */ - } catch (Exception e) { @@ -205,21 +130,6 @@ 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; diff --git a/Tizen.Runtime/Tizen.Runtime.Mono.csproj b/Tizen.Runtime/Tizen.Runtime.Mono.csproj new file mode 100644 index 0000000..e570697 --- /dev/null +++ b/Tizen.Runtime/Tizen.Runtime.Mono.csproj @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="14.0" InitialTargets="CheckConfig" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <OutputType>library</OutputType> + <AssemblyName>Tizen.Runtime.Mono</AssemblyName> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + </PropertyGroup> + + <PropertyGroup Condition=" '$(Configuration)' == 'Debug'"> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <OutputPath>bin/</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + </PropertyGroup> + + <PropertyGroup Condition=" '$(Configuration)' == 'Release'"> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin/</OutputPath> + <DefineConstants>TRACE</DefineConstants> + </PropertyGroup> + +<!-- Roslyn Not Support Assembly Signing yet. + <PropertyGroup> + <SignAssembly>true</SignAssembly> + <AssemblyOriginatorKeyFile>Tizen.Runtime.snk</AssemblyOriginatorKeyFile> + </PropertyGroup> +--> + + <PropertyGroup> + <DefineConstants Condition=" '$(CLOG)' != '' ">$(DefineConstants);CLOG</DefineConstants> + </PropertyGroup> + + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Xml" /> + </ItemGroup> + + <ItemGroup> + <Compile Include="Tizen.Runtime.Mono/AssemblyManager.cs" /> + <Compile Include="Tizen.Runtime/Log.cs" /> + <Compile Include="Tizen.Runtime/DefaultConfigAttribute.cs" /> + </ItemGroup> + + <Target Name="CheckConfig"> + <Message Text="MSBuildProjectDirectory = $(MSBuildProjectDirectory)"/> + </Target> + + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + + <Target Name="BeforeCompile"> + <ItemGroup> + <AssemblyAttributes Include="DefaultConfigAttribute" Condition=" $(PreloadPath) != '' "> + <_Parameter1>PreloadPath=$(PreloadPath)</_Parameter1> + </AssemblyAttributes> + </ItemGroup> + + <WriteCodeFragment AssemblyAttributes="@(AssemblyAttributes)" + Language="C#" + OutputDirectory="$(IntermediateOutputPath)" + OutputFile="Config.cs"> + <Output TaskParameter="OutputFile" ItemName="Compile" /> + </WriteCodeFragment> + + </Target> +</Project> diff --git a/Tizen.Runtime/Tizen.Runtime.Mono/AssemblyManager.cs b/Tizen.Runtime/Tizen.Runtime.Mono/AssemblyManager.cs new file mode 100644 index 0000000..ec65ca6 --- /dev/null +++ b/Tizen.Runtime/Tizen.Runtime.Mono/AssemblyManager.cs @@ -0,0 +1,153 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using Tizen.Runtime; + +namespace Tizen.Runtime.Mono +{ + public static class AssemblyManager + { + + private static SortedSet<string> ResolveDirectories = new SortedSet<string>(); + private static SortedSet<string> ResolveFiles = new SortedSet<string>(); + + public static bool Launch( + [In] string rootPath, + [In] string path, + [In] int argc, + [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] + [In] string[] argv) + { + ALog.Debug($"Application Launch path : {path}"); + try + { + DirectoryInfo bindir = new DirectoryInfo(Path.Combine(rootPath, "bin")); + DirectoryInfo libdir = new DirectoryInfo(Path.Combine(rootPath, "lib")); + if (Directory.Exists(bindir.FullName)) + { + ResolveDirectories.Add(bindir.FullName); + } + if (Directory.Exists(libdir.FullName)) + { + ResolveDirectories.Add(libdir.FullName); + } + ResolveFiles.Add(path); + Execute(path, argv); + } + catch(Exception e) + { + ALog.Debug("Exception in Launch()"); + PrintException(e); + return false; + } + + return true; + } + + static readonly string[] assemblyExtensions = {".dll", ".exe"}; + + public static Assembly AssemblyResolverHandler(object sender, ResolveEventArgs args) + { + // find dll name + ext in paths for resolving + foreach (string path in ResolveDirectories) + { + foreach (string ext in assemblyExtensions) + { + string assemblyPath = Path.Combine(path, new AssemblyName(args.Name).Name + ext); + if (File.Exists(assemblyPath)) + { + Assembly assembly = Assembly.LoadFrom(assemblyPath); + return assembly; + } + } + } + + return null; + } + + public static void Prepared() + { + try + { + string preloadPath = ""; + ICustomAttributeProvider assembly = typeof(AssemblyManager).GetTypeInfo().Assembly; + var attributes = assembly.GetCustomAttributes(typeof(DefaultConfigAttribute), false); + foreach (DefaultConfigAttribute dca in attributes) + { + ALog.Debug($"{dca.Key} = {dca.Value}"); + if (dca.Key == "PreloadPath") + { + preloadPath = dca.Value; + } + } + + if (!Initialize(preloadPath)) + { + ALog.Debug($"Failed to Initialized with {preloadPath}"); + } + + AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolverHandler; + } + catch(Exception e) + { + ALog.Debug("Exception at Preparing"); + PrintException(e); + } + } + + private static void PrintException(Exception exception) + { + while (exception != null) + { + ALog.Debug(exception.ToString()); + exception = exception.InnerException; + } + } + + public static bool Initialize(string preloadDirectory) + { + try + { + if (!string.IsNullOrEmpty(preloadDirectory)) + { + Console.WriteLine($"[{preloadDirectory}]"); + DirectoryInfo d = new DirectoryInfo(preloadDirectory); + if (Directory.Exists(d.FullName)) + { + ResolveDirectories.Add(d.FullName); + } + } + } + catch (Exception e) + { + ALog.Debug("Exception on Initialized"); + PrintException(e); + return false; + } + return true; + } + + + public static void Execute(string dllPath, string[] argv) + { + try + { + FileInfo f = new FileInfo(dllPath); + if (File.Exists(f.FullName)) + { + Assembly asm = Assembly.LoadFile(f.FullName); + if (asm.EntryPoint == null) throw new ArgumentException($"{f.FullName} did not have EntryPoint"); + asm.EntryPoint.Invoke(null, new object[]{argv}); + } + } + catch (Exception e) + { + ALog.Debug("Exception on Execute"); + PrintException(e); + } + } + + } +} diff --git a/Tizen.Runtime/Tizen.Runtime/Ini.cs b/Tizen.Runtime/Tizen.Runtime/Ini.cs deleted file mode 100644 index d5c2544..0000000 --- a/Tizen.Runtime/Tizen.Runtime/Ini.cs +++ /dev/null @@ -1,139 +0,0 @@ -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<string, string> 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<string, string> Global - { - get - { - return groups[GlobalName]; - } - } - - private void Initialize() - { - groups = new Dictionary<string, Dictionary<string, string> >(); - groups[GlobalName] = new Dictionary<string, string>(); - } - - 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<string, string>(); - continue; - } - GetKeyValueFromString(line, out key, out value); - groups[groupName][key] = value; - } - } - - private Dictionary<string, Dictionary<string, string> > groups; - private string contents; - } -} diff --git a/Tizen.Runtime/Tizen.Runtime/Interop.cs b/Tizen.Runtime/Tizen.Runtime/Interop.cs deleted file mode 100644 index 52ceeac..0000000 --- a/Tizen.Runtime/Tizen.Runtime/Interop.cs +++ /dev/null @@ -1,28 +0,0 @@ -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); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate int ExecutedCallback( - [In] string path, - [In] string app_root, - [In] int argc, - [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] - [In] string[] argv, - [In] 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/Tizen.Runtime/Tizen.Runtime/Log.cs b/Tizen.Runtime/Tizen.Runtime/Log.cs index 064a5f3..b27a329 100644 --- a/Tizen.Runtime/Tizen.Runtime/Log.cs +++ b/Tizen.Runtime/Tizen.Runtime/Log.cs @@ -1,7 +1,7 @@ using System; -#if !CLOG -using Tizen; -#endif +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; namespace Tizen.Runtime { @@ -35,21 +35,54 @@ namespace Tizen.Runtime #endif internal static class ALog { - static string TAG = "Tizen.Runtime"; + const string Library = "libdlog.so.0"; + const string TAG = "Tizen.Runtime"; + + public static void Debug(string message, + [CallerFilePath] string file = "", + [CallerMemberName] string func = "", + [CallerLineNumber] int line = 0) + { + Print(LogPriority.DLOG_DEBUG, TAG, message, file, func, line); + } - public static void Debug(string message) + public static void Info(string message, + [CallerFilePath] string file = "", + [CallerMemberName] string func = "", + [CallerLineNumber] int line = 0) { - Log.Debug(TAG, message); + Print(LogPriority.DLOG_DEBUG, TAG, message, file, func, line); } - public static void Info(string message) + public static void Error(string message, + [CallerFilePath] string file = "", + [CallerMemberName] string func = "", + [CallerLineNumber] int line = 0) { - Log.Info(TAG, message); + Print(LogPriority.DLOG_DEBUG, TAG, message, file, func, line); } - public static void Error(string message) + internal enum LogPriority { - Log.Error(TAG, message); + DLOG_UNKNOWN = 0, + DLOG_DEFAULT, + DLOG_VERBOSE, + DLOG_DEBUG, + DLOG_INFO, + DLOG_WARN, + DLOG_ERROR, + DLOG_FATAL, + DLOG_SILENT, + DLOG_PRIO_MAX, } + + private static void Print(LogPriority priority, string tag, string message, string file, string func, int line) + { + FileInfo finfo = new FileInfo(file); + Print(priority, tag, "%s: %s(%d) > %s", finfo.Name, func, line, message); + } + + [DllImportAttribute(Library, EntryPoint = "dlog_print")] + internal static extern int Print(LogPriority prio, string tag, string fmt, string file, string func, int line, string msg); } } diff --git a/Tizen.Runtime/Tizen.Runtime/test.cs b/Tizen.Runtime/Tizen.Runtime/test.cs deleted file mode 100644 index 1c65dbe..0000000 --- a/Tizen.Runtime/Tizen.Runtime/test.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Tizen.Runtime; - -public class Program -{ - public static void Main(string[] args) - { - if (args.Length < 2) - { - ALog.Debug("Cancel.."); - return; - } - string preload = Environment.GetEnvironmentVariable("PRELOAD_DLLS"); - string searchable = String.Join(":", args, 1, args.Length - 1); - - if (AssemblyManager.Initialize(searchable, preload)) - { - ALog.Debug("After Initialized..."); - AssemblyManager.Execute(args[0]); - } - } -} diff --git a/packaging/dotnet-launcher.spec b/packaging/dotnet-launcher.spec index c82b091..ee96df0 100644 --- a/packaging/dotnet-launcher.spec +++ b/packaging/dotnet-launcher.spec @@ -56,7 +56,8 @@ cmake \ -DCMAKE_BUILD_TYPE=%{_buildmode} \ -DDEVICE_API_DIR=%{_device_api_dir} \ -DRUNTIME_DIR=%{_runtime_dir} \ - -DLAUNCHER_ASSEMBLY_PATH=%{_bindir}/Tizen.Runtime.exe \ + -DCORECLR_LAUNCHER_ASSEMBLY_PATH=%{_bindir}/Tizen.Runtime.Coreclr.dll \ + -DMONO_LAUNCHER_ASSEMBLY_PATH=%{_bindir}/Tizen.Runtime.Mono.dll \ -DVERSION=%{version} \ NativeLauncher @@ -66,15 +67,23 @@ xbuild \ /p:Configuration=%{_buildmode} \ /p:PreloadPath=%{_preload_dir} \ /p:TizenDeviceAPIPath=%{_device_api_dir} \ - Tizen.Runtime/Tizen.Runtime.csproj + Tizen.Runtime/Tizen.Runtime.Coreclr.csproj + +xbuild \ + /p:Configuration=%{_buildmode} \ + /p:PreloadPath=%{_preload_dir} \ + /p:TizenDeviceAPIPath=%{_device_api_dir} \ + Tizen.Runtime/Tizen.Runtime.Mono.csproj %install rm -rf %{buildroot} %make_install -install -p -m 644 Tizen.Runtime/bin/Tizen.Runtime.exe %{buildroot}%{_bindir} +install -p -m 644 Tizen.Runtime/bin/Tizen.Runtime.Coreclr.dll %{buildroot}%{_bindir} +install -p -m 644 Tizen.Runtime/bin/Tizen.Runtime.Mono.dll %{buildroot}%{_bindir} %files %manifest dotnet-launcher.manifest %{_loaderdir}/dotnet.loader %caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/dotnet-launcher -%caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/Tizen.Runtime.exe +%caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/Tizen.Runtime.Coreclr.dll +%caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/Tizen.Runtime.Mono.dll |