Support UI Thread Separate (UTS) App Model (#464) accepted/tizen/unified/20230627.025434
author조웅석/MDE Lab(SR)/삼성전자 <ws77.cho@samsung.com>
Mon, 26 Jun 2023 04:16:49 +0000 (13:16 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Mon, 26 Jun 2023 04:16:49 +0000 (13:16 +0900)
define new apptype dotnet-uts for UI Thread Separate App Model

In the UI Thread Separate App Model, the main thread operates with the gmainloop
and UI-related tasks operate with the ecoreloop in a separate thread.
Therefore, ecore_init() should not be called in the main thread of the candidate process
for the UI Thread Separate App Model.
Also, candidate process should run with the gmainloop.

To run by the UI Thread Separate App Model, the environment variable "TIZEN_UI_THREAD" should be set to "true".
If this environment variable is set, then NUI would work on UI Thread Separate Mode.

NativeLauncher/dotnet.launcher
NativeLauncher/dotnet.loader
NativeLauncher/launcher/exec/launcher.cc
NativeLauncher/launcher/exec/loader.cc
NativeLauncher/launcher/lib/core_runtime.cc
NativeLauncher/tool/privilege_common.cc
NativeLauncher/tool/profile_common.cc
packaging/dotnet-launcher.spec

index 0895e2d..b42202e 100644 (file)
@@ -7,6 +7,18 @@ EXTRA_ARG    --profile
 EXTRA_ARG    --appType
 EXTRA_ARG    dotnet
 EXTRA_ARG    TIZEN_UIFW
-EXTRA_ARG    NUI 
+EXTRA_ARG    NUI
 EXTRA_ARG    --standalone
 
+[LAUNCHER]
+NAME         dotnet-uts-launcher
+EXE          /usr/bin/dotnet-launcher
+APP_TYPE     dotnet-uts
+EXTRA_ARG    --PADDING_TO_CHANGE_CMDLINE_PADDING_TO_CHANGE_CMDLINE_PADDING_TO_CHANGE_CMDLINE_PADDING_TO_CHANGE_CMDLINE
+EXTRA_ARG    --profile
+EXTRA_ARG    --appType
+EXTRA_ARG    dotnet-uts
+EXTRA_ARG    TIZEN_UIFW
+EXTRA_ARG    NUI
+EXTRA_ARG    TIZEN_UI_THREAD
+EXTRA_ARG    --standalone
\ No newline at end of file
index 237b1c3..76179de 100644 (file)
@@ -12,3 +12,19 @@ HYDRA               OFF
 EXTRA               --appType     dotnet
 EXTRA               TIZEN_UIFW    NUI 
 EXTRA               --profile     true
+
+[LOADER]
+NAME                dotnet-uts-loader
+# for candidate mode
+EXE                 /usr/bin/dotnet-uts-loader
+# for hydra mode
+#EXE                /usr/bin/dotnet-hydra-loader
+APP_TYPE            dotnet-uts
+DETECTION_METHOD    TIMEOUT|DEMAND
+TIMEOUT             5000
+ON_BOOT             OFF
+HYDRA               OFF
+EXTRA               --appType     dotnet-uts
+EXTRA               TIZEN_UIFW    NUI
+EXTRA               --profile     true
+EXTRA               TIZEN_UI_THREAD    true
\ No newline at end of file
index d7cc8e6..2ef357f 100644 (file)
@@ -42,6 +42,7 @@ static std::string PaddingOption("--PADDING_TO_CHANGE_CMDLINE_PADDING_TO_CHANGE_
 static std::string AppTypeOption("--appType");
 static std::string UIFWOption(KEY_TIZEN_UIFW);
 static std::string ProfileOption("--profile");
+static std::string UTSOption("TIZEN_UI_THREAD");
 static std::string GlobalizationInvariantOption("--invariant");
 
 int main(int argc, char *argv[])
@@ -90,6 +91,9 @@ int main(int argc, char *argv[])
                        }
                        i++;
                        UIFWType = argv[i];
+               } else if (UTSOption.compare(argv[i]) == 0) {
+                       setenv("TIZEN_UI_THREAD", "true", 1);
+                       _INFO("TIZEN_UI_THREAD is set");
                } else {
                        vargs.push_back(argv[i]);
                }
index af74eae..62fccdc 100644 (file)
 #include <vector>
 #include <memory>
 
-#include <Ecore.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <sys/prctl.h>
 
+#include <glib.h>
+#include <glib-unix.h>
+
 #include <launchpad.h>
 #include <aul.h>
 
@@ -36,7 +38,7 @@ static const char* KEY_APP_TYPE = "--appType";
 static const char* KEY_TIZEN_UIFW = "TIZEN_UIFW";
 static const char* KEY_PROFILE = "--profile";
 
-static Ecore_Fd_Handler *__fd_handler;
+static guint __fd_handler;
 static loader_receiver_cb __receiver;
 
 // To precreate window(EFL/DALI), argc and argv should be passed.
@@ -57,49 +59,47 @@ static AppInfo __appInfo;
 // Collect/use multicorejit profile or not
 static bool profile;
 
+namespace {
+GMainLoop* __loop = nullptr;
+}  // namespace
 
 //################## Code for running event loop for loader ####################
 
-static Eina_Bool __process_fd_handler(void *data, Ecore_Fd_Handler *handler)
+static gboolean __process_fd_handler(int fd, GIOCondition condition, gpointer user_data)
 {
-       int fd;
-
-       fd = ecore_main_fd_handler_fd_get(handler);
-       if (fd == -1) {
-               _ERR("[candidate] ECORE_FD_GET");
-               exit(-1);
-       }
-
-       if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) {
-               if (__receiver)
+       if (condition & G_IO_IN) {
+               if (__receiver) {
                        __receiver(fd);
-       } else if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR)) {
-               _ERR("[candidate] ECORE_FD_ERROR");
+               }
+       } else if (condition & (G_IO_HUP | G_IO_ERR)) {
+               _ERR("[candidate] error condition: %d", static_cast<int>(condition));
                close(fd);
                exit(-1);
        }
 
-       return ECORE_CALLBACK_CANCEL;
+  return G_SOURCE_REMOVE;
 }
 
 static void __adapter_loop_begin(void *user_data)
 {
-       ecore_main_loop_begin();
+       __loop = g_main_loop_new(nullptr, FALSE);
+       g_main_loop_run(__loop);
 }
 
 static void __adapter_loop_quit(void *user_data)
 {
-       ecore_main_loop_quit();
+       if (__loop != nullptr) {
+               g_main_loop_quit(__loop);
+               g_main_loop_unref(__loop);
+               __loop = nullptr;
+       }
 }
 
-static void __adapter_add_fd(void *user_data, int fd,
-               loader_receiver_cb receiver)
+static void __adapter_add_fd(void *user_data, int fd, loader_receiver_cb receiver)
 {
-       __fd_handler = ecore_main_fd_handler_add(fd,
-                       static_cast<Ecore_Fd_Handler_Flags>(ECORE_FD_READ | ECORE_FD_ERROR),
-                       __process_fd_handler, NULL, NULL, NULL);
-
-       if (__fd_handler == NULL) {
+       __fd_handler = g_unix_fd_add(fd,
+       static_cast<GIOCondition>(G_IO_IN | G_IO_HUP | G_IO_ERR), __process_fd_handler, nullptr);
+       if (__fd_handler == 0) {
                _ERR("fd_handler is NULL");
                close(fd);
                exit(-1);
@@ -110,9 +110,9 @@ static void __adapter_add_fd(void *user_data, int fd,
 
 static void __adapter_remove_fd(void *user_data, int fd)
 {
-       if (__fd_handler) {
-               ecore_main_fd_handler_del(__fd_handler);
-               __fd_handler = NULL;
+       if (__fd_handler != 0) {
+               g_source_remove(__fd_handler);
+               __fd_handler = 0;
                __receiver = NULL;
        }
 }
@@ -146,6 +146,13 @@ static void __loader_create_cb(bundle *extra, int type, void *user_data)
            }
        }
 
+       char *ui_thread = nullptr;
+       bundle_get_str(extra, "TIZEN_UI_THREAD", &ui_thread);
+       if (ui_thread != nullptr && !strcmp(ui_thread, "true")) {
+               setenv("TIZEN_UI_THREAD", "true", 1);
+               _INFO("TIZEN_UI_THREAD is set");
+       }
+
        // initialize CoreRuntime (launchmode, dlog redirection enable, root path NULL)
        if (CoreRuntime::initialize(appType ? appType : "dotnet", LaunchMode::loader) != 0) {
                _ERR("Failed to initialized");
index 88b999c..f8c685b 100644 (file)
@@ -321,9 +321,6 @@ int CoreRuntime::initialize(const char* appType, LaunchMode launchMode)
                return -1;
        }
 
-       // Intiailize ecore first (signal handlers, etc.) before runtime init.
-       ecore_init();
-
        // set language environment to support ICU
        setLang();
 
index 737a971..66f38eb 100644 (file)
@@ -64,8 +64,22 @@ void checkInternetPrivilegeAndDisableIPv6(const char* pkgId, const std::string&
 
 static int checkAppPrivilegeListCb(pkgmgrinfo_appinfo_h handle, void *user_data)
 {
+       int ret = 0;
+       char* appType = NULL;
+
+       ret = pkgmgrinfo_appinfo_get_apptype(handle, &appType);
+       if (ret != PMINFO_R_OK) {
+               _SERR("Failed to get apptype");
+               return 0;
+       }
+
+       // skip if appType is NULL or appType does not contains "dotnet",
+       if (appType == NULL || (appType != NULL && strstr(appType, "dotnet") == NULL)) {
+               return 0;
+       }
+
        char *pkgId = NULL;
-       int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
+       ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
        if (ret != PMINFO_R_OK || pkgId == NULL) {
                _SERR("Failed to get package id");
                return 0;
@@ -83,40 +97,10 @@ static int checkAppPrivilegeListCb(pkgmgrinfo_appinfo_h handle, void *user_data)
        return 0;
 }
 
-static void checkAppPrivilegeByAppType(const char* type)
-{
-       pkgmgrinfo_appinfo_filter_h filter;
-
-       int ret = pkgmgrinfo_appinfo_filter_create(&filter);
-       if (ret != PMINFO_R_OK) {
-               _SERR("Failed to create appinfo filter");
-               return;
-       }
-
-       ret = pkgmgrinfo_appinfo_filter_add_string(filter, PMINFO_APPINFO_PROP_APP_TYPE, type);
-       if (ret != PMINFO_R_OK) {
-               pkgmgrinfo_appinfo_filter_destroy(filter);
-               _SERR("Failed to add appinfo filter (%s)", type);
-               return;
-       }
-
-       ret = pkgmgrinfo_appinfo_filter_foreach_appinfo(filter, checkAppPrivilegeListCb, NULL);
-       if (ret != PMINFO_R_OK) {
-               _SERR("Failed to pkgmgrinfo_appinfo_filter_foreach_appinfo");
-               pkgmgrinfo_appinfo_filter_destroy(filter);
-               return;
-       }
-
-       pkgmgrinfo_appinfo_filter_destroy(filter);
-
-       return;
-}
-
 void checkAllAppPrivilege()
 {
-       std::vector<const char*> appTypeList = {"dotnet", "dotnet-nui", "dotnet-inhouse"};
-
-       for (auto& type : appTypeList) {
-               checkAppPrivilegeByAppType(type);
+       int ret = pkgmgrinfo_appinfo_get_installed_list(checkAppPrivilegeListCb, NULL);
+       if (ret != PMINFO_R_OK) {
+               _SERR("Failed to get installed list");
        }
 }
index ace461e..91065f1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved\r
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * Licensed under the Apache License, Version 2.0 (the License);
  * you may not use this file except in compliance with the License.
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- */\r
-\r
+ */
+
 #include "log.h"
-#include "utils.h"\r
-#include "profile_common.h"\r
-#include "launcher_env.h"\r
-\r
-#include <sys/types.h>\r
-#include <pwd.h>\r
-#include <tzplatform_config.h>\r
-\r
-static std::vector<uid_t> getUserIds()\r
+#include "utils.h"
+#include "profile_common.h"
+#include "launcher_env.h"
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <tzplatform_config.h>
+
+static std::vector<uid_t> getUserIds()
 {
        std::vector<uid_t> list;
 
@@ -59,12 +59,12 @@ static std::string getAppDataPath(const std::string& pkgId, uid_t uid)
        tzplatform_reset_user();
 
        return pDataFile;
-}\r
-\r
-profile_error_e removeAppProfileData(const std::string& pkgId)\r
+}
+
+profile_error_e removeAppProfileData(const std::string& pkgId)
 {
        if (pkgId.empty()) {
-               return PROFILE_ERROR_INVALID_PARAMETER;\r
+               return PROFILE_ERROR_INVALID_PARAMETER;
        }
 
        std::vector<uid_t> uidList = getUserIds();
@@ -76,68 +76,51 @@ profile_error_e removeAppProfileData(const std::string& pkgId)
 
                        if (exist(pDataFile)) {
                                if (!removeFile(pDataFile)) {
-                                       _SERR("Failed to remove profile data file (%s).", pDataFile.c_str());\r
-                                       return PROFILE_ERROR_UNKNOWN;\r
+                                       _SERR("Failed to remove profile data file (%s).", pDataFile.c_str());
+                                       return PROFILE_ERROR_UNKNOWN;
                                }
                                _SOUT("Profile data (%s) is removed successfully", pDataFile.c_str());
                        }
                }
        }
 
-       return PROFILE_ERROR_NONE;\r
-}
-
-static int removeAppProfileListCb(pkgmgrinfo_appinfo_h handle, void *user_data)\r
-{
-       char *pkgId = NULL;
-       int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
-       if (ret != PMINFO_R_OK || pkgId == NULL) {
-               _SERR("Failed to get package id");\r
-               return 0;
-       }
-
-       if (removeAppProfileData(pkgId) != PROFILE_ERROR_NONE) {\r
-               _SERR("Failed to remove profile data for (%s)", pkgId);\r
-       }
-
-       return 0;
+       return PROFILE_ERROR_NONE;
 }
 
-static void removeAppProfileByAppType(const char* type)\r
+static int removeAppProfileListCb(pkgmgrinfo_appinfo_h handle, void *user_data)
 {
-       pkgmgrinfo_appinfo_filter_h filter;\r
+       int ret = 0;
+       char* appType = NULL;
 
-       int ret = pkgmgrinfo_appinfo_filter_create(&filter);\r
+       ret = pkgmgrinfo_appinfo_get_apptype(handle, &appType);
        if (ret != PMINFO_R_OK) {
-               _SERR("Failed to create appinfo filter");\r
-               return;\r
+               _SERR("Failed to get apptype");
+               return 0;
        }
 
-       ret = pkgmgrinfo_appinfo_filter_add_string(filter, PMINFO_APPINFO_PROP_APP_TYPE, type);
-       if (ret != PMINFO_R_OK) {
-               pkgmgrinfo_appinfo_filter_destroy(filter);
-               _SERR("Failed to add appinfo filter (%s)", type);\r
-               return;\r
+       // skip if appType is NULL or appType does not contains "dotnet",
+       if (appType == NULL || (appType != NULL && strstr(appType, "dotnet") == NULL)) {
+               return 0;
        }
 
-       ret = pkgmgrinfo_appinfo_filter_foreach_appinfo(filter, removeAppProfileListCb, NULL);\r
-       if (ret != PMINFO_R_OK) {
-               _SERR("Failed to pkgmgrinfo_pkginfo_filter_foreach_pkginfo");\r
-               pkgmgrinfo_appinfo_filter_destroy(filter);
-               return;\r
+       char *pkgId = NULL;
+       ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
+       if (ret != PMINFO_R_OK || pkgId == NULL) {
+               _SERR("Failed to get package id");
+               return 0;
        }
 
-       pkgmgrinfo_appinfo_filter_destroy(filter);
+       if (removeAppProfileData(pkgId) != PROFILE_ERROR_NONE) {
+               _SERR("Failed to remove profile data for (%s)", pkgId);
+       }
 
-       return;\r
+       return 0;
 }
 
 void removeAllAppProfileData()
 {
-       std::vector<const char*> appTypeList = {"dotnet", "dotnet-nui", "dotnet-inhouse"};
-
-       for (auto& type : appTypeList) {
-               removeAppProfileByAppType(type);\r
+       int ret = pkgmgrinfo_appinfo_get_installed_list(removeAppProfileListCb, NULL);
+       if (ret != PMINFO_R_OK) {
+               _SERR("Failed to get installed list");
        }
-}\r
-\r
+}
index a352ce5..b8d0c58 100644 (file)
@@ -190,6 +190,8 @@ install -m 0755 packaging/%{_rw_dotnet_update_script} %{buildroot}/%{_rw_update_
 %post
 mkdir -p /opt/etc/skel/.dotnet
 chsmack -t -a User::App::Shared /opt/etc/skel/.dotnet
+ln -sf /usr/bin/dotnet-loader /usr/bin/dotnet-uts-loader
+chsmack -a User /usr/bin/dotnet-uts-loader
 
 %files
 %manifest dotnet-launcher.manifest