CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT("dotnet-launcher")
-INCLUDE(FindPkgConfig)
-PKG_CHECK_MODULES(${PROJECT_NAME} REQUIRED
- aul
- dlog
- ecore
- bundle
- dlog
- launchpad
- )
+MESSAGE("CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
+
+IF(DEFINED NO_TIZEN)
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DNO_TIZEN")
+ELSE(DEFINED NO_TIZEN)
+ INCLUDE(FindPkgConfig)
+ PKG_CHECK_MODULES(${PROJECT_NAME} REQUIRED aul dlog ecore bundle dlog launchpad)
+ENDIF(DEFINED NO_TIZEN)
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)
+
+
+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} -fPIE")
SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fdata-sections -ffunction-sections -Wl,--gc-sections")
SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -D_FILE_OFFSET_BITS=64")
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
-SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
-SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_CXX_FLAGS_RELEASE "-O2")
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed")
SET(${PROJECT_NAME}_SOURCE_FILES
src/launcher.cc
src/waiter.cc
)
+
ADD_EXECUTABLE(${PROJECT_NAME} ${${PROJECT_NAME}_SOURCE_FILES})
-TARGET_LINK_LIBRARIES(${PROJECT_NAME} aul)
-TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${${PROJECT_NAME}_LDFLAGS} "-pie")
+IF(NOT DEFINED NO_TIZEN)
+ TARGET_LINK_LIBRARIES(${PROJECT_NAME} aul)
+ENDIF(NOT DEFINED NO_TIZEN)
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${${PROJECT_NAME}_LDFLAGS} "-pie -ldl")
SET_TARGET_PROPERTIES(${PROJECT_NAME}
PROPERTIES SKIP_BUILD_RPATH TRUE
) # remove rpath option that is automatically generated by cmake.
-CONFIGURE_FILE(${PACKAGE_NAME}.xml.in ${PACKAGE_NAME}.xml)
-
-INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin)
-INSTALL(FILES ${PACKAGE_NAME}.xml DESTINATION ${MANIFESTDIR})
-INSTALL(FILES packaging/dotnet.loader DESTINATION ${LOADERDIR})
-
+IF(NOT DEFINED NO_TIZEN)
+ INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${BINDIR})
+ INSTALL(FILES packaging/dotnet.loader DESTINATION ${LOADERDIR})
+ INSTALL(FILES packaging/dotnet-launcher.ini DESTINATION ${CONFIGDIR})
+ENDIF(NOT DEFINED NO_TIZEN)
Name: dotnet-launcher
Summary: Launchpad plugin for dotnet apps
-Version: 0.1.0
+Version: 0.0.1
Release: 1
-Group: Application Framework/Daemons
+Group: Application Framework/Application State Management
License: Apache License, Version 2.0
Source0: %{name}-%{version}.tar.gz
Requires(postun): /usr/bin/systemctl
Requires(preun): /usr/bin/systemctl
-%define _sys_bin %{TZ_SYS_BIN}
-%define _sys_sbin %{TZ_SYS_SBIN}
-%define _sys_share %{TZ_SYS_RO_SHARE}
-%define _manifestdir %{TZ_SYS_RO_PACKAGES}
-%define _loaderdir %{TZ_SYS_RO_SHARE}/aul
+%define _loaderdir %{_prefix}/share/aul
+%define _configdir /etc
%description
-Launchpad for dotnet apps
+Launchpad plugin for launching dotnet apps
%prep
%setup -q
%build
+%if 0%{?tizen_build_devel_mode}
+%define _buildmode Debug
+%else
+%define _buildmode Release
+%endif
cmake \
-DCMAKE_INSTALL_PREFIX=%{_prefix} \
- -DMANIFESTDIR=%{_manifestdir} \
-DPACKAGE_NAME=%{name} \
-DBINDIR=%{_bindir} \
-DLOADERDIR=%{_loaderdir} \
+ -DCONFIGDIR=%{_configdir} \
+ -DCMAKE_BUILD_TYPE=%{_buildmode} \
-DVERSION=%{version}
make %{?jobs:-j%jobs}
rm -rf %{buildroot}
%make_install
-%post
-
%files
-%manifest dotnet-launchpad.manifest
-%{_manifestdir}/%{name}.xml
+%manifest dotnet-launcher.manifest
+%config /etc/dotnet-launcher.ini
%{_loaderdir}/dotnet.loader
-%attr(0755,root,root) %{_bindir}/dotnet-loader
-%caps(cap_mac_admin,cap_mac_override,cap_setgid=ei) %{_bindir}/dotnet-loader
+%caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/dotnet-launcher
[LOADER]
-NAME dotnet-loader
-EXE /usr/bin/dotnet-loader
+NAME dotnet-launcher
+EXE /usr/bin/dotnet-launcher
APP_TYPE dotnet
DETECTION_METHOD TIMEOUT|DEMAND
TIMEOUT 5000
+#include <dlfcn.h>
+
#include <cstdlib>
#include <cstring>
#include <vector>
#include <string>
#include <set>
#include <sstream>
+#include <fstream>
+#include <memory>
#include <dirent.h>
#include <sys/stat.h>
#include "tini.hpp"
-#ifndef LAUNCHER_CONFIG
-#define LAUNCHER_CONFIG "/usr/share/dotnet/dotnet-launcher.ini"
+#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)
+#else
+#define LAUNCHER_CONFIG "/etc/dotnet-launcher.ini"
+#endif
+static const std::string LauncherConfig(LAUNCHER_CONFIG);
+#ifdef LAUNCHER_PATH
+#undef __STR
+#undef __XSTR
+#undef LAUNCHER_CONFIG
+#undef LAUNCHER_PATH
#endif
static std::string AbsolutePath(const std::string& path)
std::string absPath;
char realPath[PATH_MAX];
- if (realpath(path, realPath) != nullptr && realPath[0] != '\0')
+ if (realpath(path.c_str(), realPath) != nullptr && realPath[0] != '\0')
{
absPath.assign(realPath);
}
DIR* dir = opendir(directory);
- if (dir == nullptr) return std::string();
+ if (dir == nullptr)
+ {
+ _ERR("can not open directory : %s", directory);
+ return std::string();
+ }
std::map<std::pair<std::string, std::string>, bool> addedAssemblies;
std::string filename(entry->d_name);
int extPos = filename.find_last_of('.');
if (extPos <= 0) continue;
+ bool notUsedExtension = true;
for (auto ext : tpaExtensions)
{
int extLength = strlen(ext);
- if (filename.compare(extPos-1, extLength, ext) != 0)
- continue;
- }
+ if (filename.compare(extPos, extLength, ext) == 0)
+ {
+ notUsedExtension = false;
+ break;
+ }
+ }
+ if (notUsedExtension) continue;
std::string filenameWithoutExt;
bool isNativeImage = extPos > niExtensionSize ?
std::string ext = filename.substr(extPos);
std::pair<std::string, std::string> key(filenameWithoutExt, ext);
- std::cout << " " << filenameWithoutExt << ext << " " << isNativeImage << std::endl;
if (addedAssemblies.count(key))
{
isNativeImage = isNativeImage || addedAssemblies[key];
}
tpaList.append(pair.first.second);
tpaList.append(":");
+ _DBG("TPA : %s/%s%s", directory, pair.first.first.c_str(), pair.first.second.c_str());
}
closedir(dir);
void Launcher::Initialize()
{
- std::ifstream iniStream(LAUNCHER_CONFIG);
+ std::ifstream iniStream(LauncherConfig);
std::stringstream iniString;
iniString << iniStream.rdbuf();
tini::ini launcherIni(iniString);
- auto &dotnet = ini["dotnet"];
+ _DBG("config file [%s]", LauncherConfig.c_str());
+ _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 (dontet.find("native_so_search_dirs") == dotnet.end())
+ 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"];
- void* coreclrLib = dlopen(libcoreclr, RTLD_NOW | RTLD_LOCAL);
+ _DBG("libcoreclr.so : [%s]", libcoreclr.c_str());
+
+ coreclrLib = dlopen(libcoreclr.c_str(), RTLD_NOW | RTLD_LOCAL);
if (coreclrLib == nullptr)
{
char *err = dlerror();
_ERR("dlopen failed to open libcoreclr.so with error %s", err);
- goto CoreClrLibClose;
+ return;
}
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");
- if (coreclr_initialize_ptr == nullptr)
+ if (initializeCoreCLR == nullptr)
{
- _ERR("coreclr_initialize_ptr not found in the libcoreclr.so");
+ _ERR("coreclr_initialize not found in the libcoreclr.so");
}
- else if (coreclr_execute_assembly_ptr == nullptr)
+ else if (executeAssembly == nullptr)
{
_ERR("coreclr_execute_assembly_ptr not found in the libcoreclr.so");
}
- else if (coreclr_shutdown_ptr == nullptr)
+ else if (shutdownCoreCLR == nullptr)
{
_ERR("coreclr_shutdown_ptr not found in the libcoreclr.so");
}
std::string s;
while (std::getline(f, s, ':'))
{
- TrustedPlatformAssemblies += AssembliesInDirectory(s);
+ TrustedPlatformAssemblies += AssembliesInDirectory(s.c_str());
}
NativeDllSearchDirectories = nativeSoSearchDirs;
AppDomainCompatSwitch = "UseLatestBehaviorWhenTFMNotSpecified";
}
+}
-CoreClrLibClose:
+void Launcher::Dispose()
+{
if (dlclose(coreclrLib) != 0)
{
_ERR("libcoreclr.so close failed");
}
}
-void Launcher::Dispose()
-{
-}
-
void Launcher::Launch(const string& exe_path, int argc, char *argv[])
{
- std::string bin_path = Basename(exe_path);
- std::string app_home = Basename(app_path);
+ std::string bin_path = Basename(AbsolutePath(exe_path));
+ std::string app_home = Basename(bin_path);
std::string lib_path = app_home + "/lib";
- std::string app_path = bin_path + ":" + lib_path
+ std::string app_path = bin_path + ":" + lib_path;
std::string app_ni_path = app_path;
std::string nativeDllSearchDirectories = NativeDllSearchDirectories + app_path;
AppDomainCompatSwitch.c_str()
};
+ //_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]);
+
void* hostHandle;
unsigned int domainId;
- int st = initializeCoreCLR(exe_path,
+ _DBG("before initialize coreclr");
+
+ int st = initializeCoreCLR(exe_path.c_str(),
"tizen_dotnet_launcher",
sizeof(propertyKeys) / sizeof(propertyKeys[0]),
propertyKeys,
propertyValues,
&hostHandle,
&domainId);
+
+ _DBG("after initialize coreclr");
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");
exit(-1);
}
unsigned int exitCode;
- st = executeAssembly(hostHandle, domainId, argc, argv, exe_path, &exitCode);
+ st = executeAssembly(hostHandle, domainId,
+ argc, const_cast<const char**>(argv), exe_path.c_str(), &exitCode);
if (st < 0)
{
// execute coreclr fail
+ _ERR("execute core clr fail! (0x%08x)", st);
exit(-1);
}
+ _DBG("after execute coreclr");
st = shutdownCoreCLR(hostHandle, domainId);
if (st < 0)
{
// shutdown fail
+ _ERR("shutdown core clr fail! (0x%08x)", st);
exit(-1);
}
}
+} // namespace runtime
+} // namespace dotnet
+
+using dotnet::runtime::Launcher;
+using dotnet::runtime::Waiter;
+
int main(int argc, char *argv[])
{
+ _DBG("launcher started");
+
+ for (int i=0; i<argc; i++)
+ {
+ _DBG("argv[%d](%d) : [%s]", i, strlen(argv[i]), argv[i]);
+ }
+
std::unique_ptr<Launcher> launcher(new Launcher());
auto on_prepare = [&launcher]()
{
- launcher.Initialize();
+ launcher->Initialize();
};
auto on_requested = [&launcher]()
{
};
auto on_executed = [&launcher](const std::string& path, int argc, char *argv[])
{
- launcher.launch(path, argc, argv);
- }
+ _DBG("EXECUTE %s", path.c_str());
+ launcher->Launch(path, argc, argv);
+ };
std::unique_ptr<Waiter> waiter(new Waiter(on_prepare, on_requested, on_executed));
+ waiter->WaitToLaunching(argc, argv);
}
string TrustedPlatformAssemblies;
string NativeDllSearchDirectories;
string AppDomainCompatSwitch;
+
+ void *coreclrLib;
};
} // namespace runtime
#ifndef __LOG_H__
#define __LOG_H__
+#ifndef NO_TIZEN
#include <dlog.h>
+#else
+#include <stdio.h>
+#define LOGE(fmt, args...) printf(fmt, ##args)
+#define LOGD(fmt, args...) printf(fmt, ##args)
+#define LOGI(fmt, args...) printf(fmt, ##args)
+#endif
#ifdef LOG_TAG
#undef LOG_TAG
#define LOG_TAG "NETCORE_LAUNCHER"
#ifndef _ERR
-#define _ERR(fmt, args...) LOGE(fmt "\n", __func__, __LINE__, ##args)
+#define _ERR(fmt, args...) LOGE(fmt "\n", ##args)
#endif
#ifndef _DBG
-#define _DBG(fmt, args...) LOGD(fmt "\n", __func__, __LINE__, ##args)
+#define _DBG(fmt, args...) LOGD(fmt "\n", ##args)
#endif
#ifndef _INFO
-#define _INFO(fmt, args...) LOGI(fmt "\n", __func__, __LINE__, ##args)
+#define _INFO(fmt, args...) LOGI(fmt "\n", ##args)
#endif
#endif /* __LOG_H__ */
-#include "waiter.h"
#include <poll.h>
+
+#ifndef NO_TIZEN
#include <launchpad.h>
+#endif
#include <memory>
#include <vector>
#include <map>
#include <poll.h>
+#include <iostream>
+
+#include "waiter.h"
+#include "log.h"
+
namespace dotnet {
namespace runtime {
-struct Waiter::FdHandler;
+struct FdHandler
{
pollfd *info;
- Receiver re;
+ Receiver receiver;
};
static volatile bool Waiting_;
void Waiter::OnPrepare()
{
// preload the libraries.
+ if (prepare_ != nullptr)
+ prepare_();
}
-void Waiter::OnLaunchRequested()
+void Waiter::OnLaunchRequested(const AppInfo& info)
{
// do some job on user id is still system
}
// Start the loop
Waiting_ = true;
+ _DBG("start polling...");
while (Waiting_)
{
if (poll(Fdlist_.data(), Fdlist_.size(), -1) < 0)
for (auto &p : Fdlist_)
{
if ( (p.revents | POLLIN) != 0 )
- Handlers_[p.fd].receiver();
+ Handlers_[p.fd].receiver(p.fd);
}
}
+ _DBG("end polling...");
}
void Waiter::Stop()
{
// register fd should be caught in event loop
+ _DBG("Register fd %d", fd);
+
pollfd info;
info.fd = fd;
info.events = POLLIN;
{
}
-void Waiter::WaitToLaunching(int argc, char *argv[])
+int Waiter::WaitToLaunching(int argc, char *argv[])
{
+#ifndef NO_TIZEN
auto on_create = [](bundle *extra, int type, void *user_data)
{
+ _DBG("on_create..."); // XXX
Waiter* waiter = static_cast<Waiter*>(user_data);
waiter->OnPrepare();
};
auto on_launch = [](int argc, char **argv, const char *app_path,
const char *appid, const char *pkgid,
- const char *pkg_type, void *user_data)
+ const char *pkg_type, void *user_data) -> int
{
+ _DBG("on_launch..."); // XXX
Waiter* waiter = static_cast<Waiter*>(user_data);
+ _DBG ("app path : %s", app_path);
+ _DBG ("app id : %s", appid);
+ _DBG ("pkg id : %s", pkgid);
+ _DBG ("pkg type : %s", pkg_type);
+
AppInfo info = {
AppPath : app_path,
AppId : appid,
};
waiter->OnLaunchRequested(info);
+ return 0;
};
- auto on_terminate = [](int argc, char **argv, void *user_data)
+ auto on_terminate = [](int argc, char **argv, void *user_data) -> int
{
+ _DBG("on_terminate..."); // XXX
Waiter* waiter = static_cast<Waiter*>(user_data);
- waiter->executor_(argv[LOADER_ARG_PATH], argc, argv);
+ waiter->executor_(argv[0], argc, argv);
+ return 0;
};
auto on_start_loop = [](void *user_data)
{
+ _DBG("on_start_loop..."); // XXX
Waiter* waiter = static_cast<Waiter*>(user_data);
waiter->OnWaiting();
};
auto on_quit_loop = [](void *user_data)
{
+ _DBG("on_quit_loop..."); // XXX
Waiter* waiter = static_cast<Waiter*>(user_data);
waiter->Stop();
};
auto on_add_fd = [](void *user_data, int fd, loader_receiver_cb receiver)
{
+ _DBG("on_add_fd..."); // XXX
Waiter* waiter = static_cast<Waiter*>(user_data);
waiter->RegisterFd(fd, receiver);
};
auto on_remove_fd = [](void *user_data, int fd)
{
+ _DBG("on_remove_fd..."); // XXX
Waiter* waiter = static_cast<Waiter*>(user_data);
waiter->DeregisterFd(fd);
};
+ _DBG("launcher wait..."); // XXX
loader_lifecycle_callback_s callbacks = {
.create = on_create,
.launch = on_launch,
.terminate = on_terminate
- }
+ };
loader_adapter_s adapter = {
.loop_begin = on_start_loop,
};
return launchpad_loader_main(argc, argv, &callbacks, &adapter, this);
+#else
+ if (argc < 2) return -1;
+ this->OnPrepare();
+ AppInfo info = {
+ AppPath : argv[1],
+ AppId : "",
+ PkgId : "",
+ PkgType : ""
+ };
+ this->OnLaunchRequested(info);
+ this->executor_(argv[1], argc, argv);
+#endif
}
} // namespace runtime
#include <string>
+#include <functional>
using std::string;
namespace dotnet {
namespace runtime {
+using Receiver = std::function<void(int)>;
+
class Waiter
{
public:
string PkgType;
};
using Action = std::function<void(void)>;
- using Receiver = std::function<void(int)>;
using Executor = std::function<void(const string&, int, char**)>;
Waiter(Action prepare, Action requested, Executor executor);