Add SetSwitch API to Tizen.Runtime
[platform/core/dotnet/launcher.git] / NativeLauncher / launcher / lib / core_runtime.cc
index 8795ac3..b9e75ac 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <dlfcn.h>
 #include <signal.h>
+#include <dirent.h>
 
 #include <string>
 #include <fstream>
@@ -45,7 +46,6 @@
 #include "core_runtime.h"
 #include "plugin_manager.h"
 #include "path_manager.h"
-#include "log_manager.h"
 
 namespace tizen {
 namespace runtime {
@@ -56,6 +56,8 @@ static coreclr_execute_assembly_ptr executeAssembly = nullptr;
 static coreclr_shutdown_ptr shutdown = nullptr;
 static coreclr_create_delegate_ptr createDelegate = nullptr;
 static set_environment_variable_ptr setEnvironmentVariable = nullptr;
+static stop_profile_after_delay_ptr stopProfileAfterDelay = nullptr;
+static set_switch_ptr setSwitch = nullptr;
 static void* __coreclrLib = nullptr;
 static void* __hostHandle = nullptr;
 static unsigned int __domainId = -1;
@@ -63,6 +65,8 @@ static bool __initialized = false;
 static bool __isProfileMode = false;
 PathManager* CoreRuntime::__pm = nullptr;
 
+#define MAX_DELAY_SEC 100
+
 static std::vector<std::string> __envList;
 
 static void setEnvFromFile()
@@ -223,6 +227,31 @@ static std::string readSelfPath()
        return "";
 }
 
+static void removeDebugPipe()
+{
+       DIR *dir;
+       struct dirent* entry;
+       char debugPipeFiles[PATH_MAX];;
+       sprintf(debugPipeFiles, "/tmp/clr-debug-pipe-%d-", getpid());
+
+       dir = opendir("/tmp");
+       if (dir == nullptr) {
+               _ERR("Fail to open /tmp directory");
+               return;
+       }
+
+       while ((entry = readdir(dir)) != nullptr) {
+               std::string path = concatPath("/tmp", entry->d_name);
+               if (path.find(debugPipeFiles) != std::string::npos) {
+                       if (!removeFile(path)) {
+                               _ERR("Fail to remove file (%s)", path.c_str());
+                       }
+               }
+       }
+
+       closedir(dir);
+}
+
 void preload()
 {
        typedef void (*PreloadDelegate)();
@@ -354,18 +383,18 @@ int CoreRuntime::initialize(const char* appType, LaunchMode launchMode)
                return -1;
        }
 
-       char* pluginPath = pluginGetDllPath();
-       if (pluginPath) {
-               __pm->addPlatformAssembliesPaths(pluginPath);
+       char* pluginDllPaths = pluginGetDllPath();
+       if (pluginDllPaths && pluginDllPaths[0] != '\0') {
+               __pm->addPlatformAssembliesPaths(pluginDllPaths, true);
        }
 
-       if (!pluginHasLogControl()) {
-               if (initializeLogManager() < 0) {
-                       _ERR("Failed to initnialize LogManager");
-                       return -1;
-               }
+       char* pluginNativePaths = pluginGetNativeDllSearchingPath();
+       if (pluginNativePaths && pluginNativePaths[0] != '\0') {
+               __pm->addNativeDllSearchingPaths(pluginNativePaths, true);
        }
 
+       pluginHasLogControl();
+
        std::string libCoreclr(concatPath(__pm->getRuntimePath(), "libcoreclr.so"));
 
        __coreclrLib = dlopen(libCoreclr.c_str(), RTLD_NOW | RTLD_LOCAL);
@@ -401,7 +430,7 @@ int CoreRuntime::initialize(const char* appType, LaunchMode launchMode)
 
        std::string tpa;
        char* pluginTPA = pluginGetTPA();
-       if (pluginTPA) {
+       if (pluginTPA && pluginTPA[0] != '\0') {
                tpa = std::string(pluginTPA);
        } else {
                addAssembliesFromDirectories(__pm->getPlatformAssembliesPaths(), tpa);
@@ -418,6 +447,18 @@ int CoreRuntime::initialize(const char* appType, LaunchMode launchMode)
                return -1;
        }
 
+       st = createDelegate(__hostHandle, __domainId, "Tizen.Runtime", "Tizen.Runtime.Profiler", "StopProfileAfterDelay", (void**)&stopProfileAfterDelay);
+       if (st < 0 || stopProfileAfterDelay == nullptr) {
+               _ERR("Create delegate for Tizen.Runtime.dll -> Tizen.Runtime.Profiler -> StopProfileAfterDelay failed (0x%08x)", st);
+               return -1;
+       }
+
+       st = createDelegate(__hostHandle, __domainId, "Tizen.Runtime", "Tizen.Runtime.AppSetting", "SetSwitch", (void**)&setSwitch);
+       if (st < 0 || setSwitch == nullptr) {
+               _ERR("Create delegate for Tizen.Runtime.dll -> Tizen.Runtime.AppSetting -> SetSwitch failed (0x%08x)", st);
+               return -1;
+       }
+
        if (launchMode == LaunchMode::loader) {
                // terminate candidate process if language is changed.
                // CurrentCulture created for preloaded dlls should be updated.
@@ -425,6 +466,13 @@ int CoreRuntime::initialize(const char* appType, LaunchMode launchMode)
 
                // preload libraries and manage dlls for optimizing startup time
                preload();
+
+               // The debug pipe created in the candidate process has a "User" label.
+               // As a result, smack deny occurs when app process try to access the debug pipe.
+               // Also, since debugging is performed only in standalone mode,
+               // the debug pipe doesnot be used in the candidate process.
+               // So, to avoid smack deny error, delete unused debug pipe files.
+               removeDebugPipe();
        }
 
        __initialized = true;
@@ -476,7 +524,7 @@ void CoreRuntime::finalize()
        _INFO("CoreRuntime finalized");
 }
 
-int CoreRuntime::launch(const char* appId, const char* root, const char* path, int argc, char* argv[])
+int CoreRuntime::launch(const char* appId, const char* root, const char* path, int argc, char* argv[], bool profile)
 {
        if (!__initialized) {
                _ERR("Runtime is not initialized");
@@ -493,14 +541,6 @@ int CoreRuntime::launch(const char* appId, const char* root, const char* path, i
                return -1;
        }
 
-       // launchpad override stdout and stderr to journalctl before launch application.
-       // we have to re-override that to input pipe for logging thread.
-       // if LogManager is not initialized, below redirectFD will return 0;
-       if (redirectFD() < 0) {
-               _ERR("Failed to redirect FD");
-               return -1;
-       }
-
        // VD has their own signal handler.
        if (!pluginHasLogControl()) {
                registerSigHandler();
@@ -516,9 +556,36 @@ int CoreRuntime::launch(const char* appId, const char* root, const char* path, i
        char* localDataPath = app_get_data_path();
        if (localDataPath != nullptr) {
                setEnvironmentVariable("XDG_DATA_HOME", localDataPath);
+
+               // set profile.data path and collect/use it if it non-exists/exists.
+               if (profile) {
+                       char multiCoreJitProfile[strlen(localDataPath) + strlen(PROFILE_BASENAME) + 1];
+                       memcpy(multiCoreJitProfile, localDataPath, strlen(localDataPath) + 1);
+                       strncat(multiCoreJitProfile, PROFILE_BASENAME, strlen(PROFILE_BASENAME));
+
+                       setEnvironmentVariable("COMPlus_MultiCoreJitProfile", multiCoreJitProfile);
+                       setEnvironmentVariable("COMPlus_MultiCoreJitMinNumCpus", "1");
+
+                       // stop profiling and write collected data after delay if env value is set.
+                       char *env = getenv("CLR_MCJ_PROFILE_WRITE_DELAY");
+                       if (env != nullptr) {
+                               int delay = std::atoi(env);
+                               // To avoid undefined behavior by out-of-range input(atoi), set max delay value to 100.
+                               if (delay > 0) {
+                                       if (delay > MAX_DELAY_SEC) delay = MAX_DELAY_SEC;
+                                       stopProfileAfterDelay(delay);
+                               }
+                       }
+
+                       if (exist(multiCoreJitProfile)) {
+                               setEnvironmentVariable("COMPlus_MultiCoreJitNoProfileGather", "1");
+                       }
+               }
                free(localDataPath);
        }
 
+       setSwitch("Switch.System.Diagnostics.StackTrace.ShowILOffsets", true);
+
        vconf_ignore_key_changed(VCONFKEY_LANGSET, langChangedCB);
 
        pluginBeforeExecute();