unified-system-service: Add unified-system-service to support unified system service 58/324158/1
authorSangYoun Kwak <sy.kwak@samsung.com>
Tue, 13 May 2025 10:58:11 +0000 (19:58 +0900)
committerSangYoun Kwak <sy.kwak@samsung.com>
Tue, 13 May 2025 10:59:05 +0000 (19:59 +0900)
To support the new functionality 'unified-system-service',
unified-system-service is newly added.
For the unified-system-service, .service and .socket files are added.
Also unified-system-service-common.h is added which includes structure
which is required by services.

Change-Id: I0bf6440194c61d1e346364af6c3f55fc65189ff9
Signed-off-by: SangYoun Kwak <sy.kwak@samsung.com>
CMakeLists.txt
include/unified-system-service-common.h [new file with mode: 0644]
packaging/hal-api-common.spec
unified-system-service/CMakeLists.txt [new file with mode: 0644]
unified-system-service/unified-system-service.c [new file with mode: 0644]
unified-system-service/unified-system-service.service [new file with mode: 0644]
unified-system-service/unified-system-service.socket [new file with mode: 0644]

index 0553a4a617b8a516c9f571329dbea261e8d6f8aa..3e1a7c5540dcabfdfe88a27d88929c9de6a18e9e 100644 (file)
@@ -67,7 +67,11 @@ CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/packaging/${PROJECT_NAME}.pc.in
 INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIBDIR}/hal)
 INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
        DESTINATION ${INCLUDEDIR}/hal
-       FILES_MATCHING PATTERN "*.h")
+       FILES_MATCHING
+       PATTERN "*.h"
+       PATTERN unified-system-service-common.h EXCLUDE)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/unified-system-service-common.h
+       DESTINATION ${INCLUDEDIR})
 INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/${PROJECT_NAME}.pc
        DESTINATION ${LIBDIR}/pkgconfig)
 
@@ -81,3 +85,7 @@ endif()
 if (${ENABLE_HAL_BACKEND_SERVICE})
 ADD_SUBDIRECTORY(hal-backend-service)
 endif()
+
+if (${ENABLE_UNIFIED_SYSTEM_SERVICE})
+ADD_SUBDIRECTORY(unified-system-service)
+endif()
diff --git a/include/unified-system-service-common.h b/include/unified-system-service-common.h
new file mode 100644 (file)
index 0000000..2c6ccf2
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Unified System Service API
+ *
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Unified System Service
+ */
+typedef struct __unified_system_service {
+       const char *name;
+       int (*early_init) (void *data);
+       int (*init) (void *data);
+       int (*exit) (void *data);
+       int (*late_exit) (void *data);
+} unified_system_service;
+
+#ifdef __cplusplus
+}
+#endif
index e67db99558fa33c9562b9c7aec87af988c88bf85..6c7bcdb5e54e92abb061fceb27fdbe165014bfc7 100644 (file)
 %define enable_hal_backend_service 0
 %endif
 
+%if "%{WITH_VD}" != "1" && "%{WITH_VD_MV}" != "1" && "%{WITH_DA}" != "1"
+%define enable_unified_system_service 1
+%else
+%define enable_unified_system_service 0
+%endif
+
 ### main package #########
 Name:       %{name}
 Summary:    %{name} interface
@@ -82,6 +88,15 @@ Requires: hal-api-common = %{version}
 %description -n %{test_name}
 Haltests for hal-api-common
 
+%if %{enable_unified_system_service}
+### unified-system-service package #########
+%package unified-system-service
+Summary: Package for unified-system-service
+
+%description unified-system-service
+Package for unified-system-service
+%endif
+
 ### build and install #########
 %prep
 %setup -q
@@ -109,6 +124,7 @@ cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} \
        -DCMAKE_LIBDIR_PREFIX=%{_libdir} \
        -DENABLE_HALCC=%{enable_halcc} \
        -DENABLE_HAL_BACKEND_SERVICE=%{enable_hal_backend_service} \
+       -DENABLE_UNIFIED_SYSTEM_SERVICE=%{enable_unified_system_service} \
        -DENABLE_DLOG=1
 
 %build
@@ -151,6 +167,11 @@ done
 
 %endif
 
+%if %{enable_unified_system_service}
+%install_service basic.target.wants unified-system-service.service
+%install_service sockets.target.wants unified-system-service.socket
+%endif
+
 %clean
 rm -rf %{buildroot}
 
@@ -190,6 +211,7 @@ rm -f %{_unitdir}/sysinit.target.wants/hal-compatibility-checker.service
 %files -n %{devel_name}
 %defattr(-,root,root,-)
 %{_includedir}/hal/*.h
+%{_includedir}/*.h
 %{_libdir}/pkgconfig/*.pc
 %{_sysconfdir}/rpm/macros.hal-api
 
@@ -197,3 +219,15 @@ rm -f %{_unitdir}/sysinit.target.wants/hal-compatibility-checker.service
 %{_unitdir}/haltest.target
 %{_bindir}/reboot-haltest
 %{_bindir}/reboot-normal
+
+%if %{enable_unified_system_service}
+%files unified-system-service
+%license LICENSE
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%{_bindir}/unified-system-service
+%{_unitdir}/sockets.target.wants/unified-system-service.socket
+%{_unitdir}/basic.target.wants/unified-system-service.service
+%{_unitdir}/unified-system-service.socket
+%{_unitdir}/unified-system-service.service
+%endif
diff --git a/unified-system-service/CMakeLists.txt b/unified-system-service/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c9062ac
--- /dev/null
@@ -0,0 +1,43 @@
+PROJECT(unified-system-service C CXX)
+
+IF(${LIBDIR} STREQUAL "/usr/lib64")
+       ADD_DEFINITIONS(-DLIB64)
+ENDIF()
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR})
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src)
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
+
+ADD_DEFINITIONS("-DLOG_TAG=\"UNIFIED_SYSTEM_SERVICE\"")
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(gtest_pkgs REQUIRED
+       dlog
+       glib-2.0
+       rpc-port
+       bundle
+       tizen-core
+)
+
+FOREACH(flag ${gtest_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -fPIC")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -g -fno-omit-frame-pointer -finstrument-functions")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fstack-protector-strong -D_FORTIFY_SOURCE=2 -O2 -Wl,-z,relro")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -lrt")
+SET(CMAKE_EXE_LINKER_FLAGS "-pie")
+
+SET(src
+       ${CMAKE_SOURCE_DIR}/src/hal-api-conf.c
+       ${CMAKE_SOURCE_DIR}/unified-system-service/unified-system-service.c
+)
+ADD_EXECUTABLE(${PROJECT_NAME} ${src})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${gtest_LDFLAGS} ${gtest_pkgs_LDFLAGS} -ldl -L${LIBDIR}/hal)
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/bin)
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/unified-system-service.service
+       DESTINATION lib/systemd/system)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/unified-system-service.socket
+       DESTINATION lib/systemd/system)
diff --git a/unified-system-service/unified-system-service.c b/unified-system-service/unified-system-service.c
new file mode 100644 (file)
index 0000000..fcc72b4
--- /dev/null
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+#include <dlfcn.h>
+#include <dirent.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib-unix.h>
+
+#include <rpc-port-internal.h>
+#include <bundle_internal.h>
+#include <tizen_core.h>
+
+#include "common.h"
+#include "unified-system-service-common.h"
+
+#define COMMANDLINE_OPTION_SERVICE_PLUGIN "service-plugin"
+
+#ifdef LIB64
+#define PLUGIN_LIB_DIR "/usr/lib64"
+#else
+#define PLUGIN_LIB_DIR "/usr/lib"
+#endif
+
+#define PLUGIN_LIB_PREFIX "libunified-system-service"
+#define PLUGIN_DATA_SYMBOL_PREFIX "unified_system_service"
+#define PLUGIN_DATA_SYMBOL_POSTFIX "data"
+
+struct unified_system_service_data {
+       char *service_name;
+       void *service_handle;
+       unified_system_service *service;
+       tizen_core_task_h task;
+       bool is_initialized;
+};
+
+static tizen_core_task_h g_main_task = NULL;
+static GSList *g_unified_system_service_data_list = NULL;
+
+G_LOCK_DEFINE_STATIC(unified_system_service_lock);
+
+static int unified_system_service_get_backend_service(const char *service_plugin_name,
+                                               void **service_handle,
+                                               unified_system_service **service)
+{
+       int ret = 0;
+
+       char plugin_path[PATH_MAX] = { 0, };
+       int plugin_path_len = 0;
+
+       char plugin_data_symbol[PATH_MAX] = { 0, };
+       int plugin_data_symbol_len = 0;
+
+       void *temp_service_handle = NULL;
+       unified_system_service *temp_service = NULL;
+
+       if (service_plugin_name == NULL || service_handle == NULL || service == NULL)
+               return -EINVAL;
+
+       plugin_path_len = snprintf(plugin_path, sizeof(plugin_path),
+                       "%s/%s-%s.so",
+                       PLUGIN_LIB_DIR, PLUGIN_LIB_PREFIX, service_plugin_name);
+       if (plugin_path_len >= sizeof(plugin_path)) {
+               _E("Plugin path is too long: length(%d)", plugin_path_len);
+               return -EINVAL;
+       }
+
+       temp_service_handle = dlopen(plugin_path, RTLD_LAZY);
+       if (temp_service_handle == NULL) {
+               _E("Failed to load service plugin for %s: path(%s), %s",
+                               service_plugin_name, plugin_path, dlerror());
+               return -EINVAL;
+       }
+
+       plugin_data_symbol_len = snprintf(plugin_data_symbol,
+                       sizeof(plugin_data_symbol), "%s_%s_%s",
+                       PLUGIN_DATA_SYMBOL_PREFIX, service_plugin_name,
+                       PLUGIN_DATA_SYMBOL_POSTFIX);
+       if (plugin_data_symbol_len >= sizeof(plugin_data_symbol)) {
+               _E("Plugin data symbol is too long: length(%d)", plugin_data_symbol_len);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       temp_service = dlsym(temp_service_handle, plugin_data_symbol);
+       if (temp_service == NULL) {
+               _E("Failed to find plugin data symbol for %s: symbol(%s), %s",
+                               service_plugin_name, plugin_data_symbol,
+                               dlerror());
+               ret = -EINVAL;
+               goto error;
+       }
+
+       *service_handle = temp_service_handle;
+       *service = temp_service;
+
+       return 0;
+error:
+       if (temp_service_handle != NULL)
+               dlclose(temp_service_handle);
+
+       return ret;
+}
+
+static int unified_system_service_open_and_add_plugin(char **service_plugin_names)
+{
+       int ret = 0;
+       size_t service_plugin_names_len = 0;
+       struct unified_system_service_data *service_data = NULL;
+       size_t service_data_count = 0;
+
+       for (size_t i = 0; service_plugin_names[i]; ++i)
+               ++service_plugin_names_len;
+
+       for (size_t i = 0; i < service_plugin_names_len; ++i) {
+               service_data = calloc(1, sizeof(*service_data));
+               if (service_data == NULL) {
+                       _W("Cannot allocate memory for service plugin: %s", service_plugin_names[i]);
+                       continue;
+               }
+               service_data->service_name = strdup(service_plugin_names[i]);
+               if (service_data->service_name == NULL) {
+                       _W("Cannot allocate memory for service name: %s", service_plugin_names[i]);
+                       free(service_data);
+                       service_data = NULL;
+                       continue;
+               }
+
+               ret = unified_system_service_get_backend_service(service_plugin_names[i],
+                                               &(service_data->service_handle),
+                                               &(service_data->service));
+               if (ret != 0) {
+                       _W("Cannot get service plugin: %s", service_plugin_names[i]);
+                       free(service_data->service_name);
+                       free(service_data);
+                       service_data = NULL;
+                       continue;
+               }
+
+               g_unified_system_service_data_list = g_slist_prepend(g_unified_system_service_data_list,
+                                                       (gpointer)service_data);
+               service_data = NULL;
+               ++service_data_count;
+       }
+
+       if (service_data_count == 0) {
+               _E("Failed to get service plugin");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void delete_unified_system_service(
+               struct unified_system_service_data *unified_system_service_data,
+               gpointer data)
+{
+       int ret = 0;
+
+       if (unified_system_service_data == NULL) {
+               _E("Invallid parameter: unified_system_service_data(NULL)");
+               return;
+       }
+
+       if (unified_system_service_data->service_handle != NULL) {
+               unified_system_service_data->service = NULL;
+               dlclose(unified_system_service_data->service_handle);
+               unified_system_service_data->service_handle = NULL;
+       }
+
+       free(unified_system_service_data->service_name);
+       free(unified_system_service_data);
+
+       return;
+}
+
+static int unified_system_service_delete_and_close_plugin(void)
+{
+       enum hal_module module;
+       int ret;
+
+       g_slist_foreach(g_unified_system_service_data_list,
+                       (GFunc)delete_unified_system_service, NULL);
+
+       g_slist_free(g_unified_system_service_data_list);
+       g_unified_system_service_data_list = NULL;
+
+       return 0;
+}
+
+static bool unified_system_service_initialize_cb(tizen_core_source_h source, int *timeout, void *data)
+{
+       struct unified_system_service_data *service_data = NULL;
+       int ret = 0;
+
+       /* FIXME: This is error situation, task should be terminated? */
+       if (data == NULL) {
+               _E("Invalid unified_system_service(NULL)");
+               return false;
+       }
+       service_data = (struct unified_system_service_data *)data;
+
+       if (service_data->is_initialized)
+               return false;
+
+       G_LOCK(unified_system_service_lock);
+
+       /**
+        * FIXME: If early_init succeed and init failed, should early_init
+        * called?
+        */
+       if (service_data->service->early_init) {
+               ret = service_data->service->early_init(NULL);
+               if (ret != 0) {
+                       _E("Failed to early initialize %s: ret(%d)",
+                                       service_data->service_name, ret);
+                       goto error;
+               }
+       }
+
+       if (service_data->service->init) {
+               ret = service_data->service->init(NULL);
+               if (ret != 0) {
+                       _E("Failed to initialize %s: ret(%d)",
+                                       service_data->service_name, ret);
+                       goto error;
+               }
+       }
+
+       service_data->is_initialized = true;
+       G_UNLOCK(unified_system_service_lock);
+
+       return false;
+
+error:
+       G_UNLOCK(unified_system_service_lock);
+
+       return false;
+}
+
+static void unified_system_service_finalize_cb(tizen_core_source_h source, void *data)
+{
+       struct unified_system_service_data *service_data = NULL;
+       int ret = 0;
+
+       if (data == NULL) {
+               _E("Invalid unified_system_service(NULL)");
+               return;
+       }
+       service_data = (struct unified_system_service_data *)data;
+
+       G_LOCK(unified_system_service_lock);
+
+       if (service_data->service->exit) {
+               ret = service_data->service->exit(NULL);
+               if (ret != 0) {
+                       _E("Cannot exit %s: ret(%d)",
+                                       service_data->service_name, ret);
+               }
+       }
+
+       if (service_data->service->late_exit) {
+               ret = service_data->service->late_exit(NULL);
+               if (ret != 0) {
+                       _E("Cannot late exit %s: ret(%d)",
+                                       service_data->service_name, ret);
+               }
+       }
+
+       service_data->is_initialized = false;
+       G_UNLOCK(unified_system_service_lock);
+
+       _D("Exit done.");
+}
+
+static void create_unified_system_service_task(gpointer data, gpointer user_data)
+{
+       tizen_core_task_h task = NULL;
+       tizen_core_h core = NULL;
+       tizen_core_source_h source = NULL;
+
+       struct unified_system_service_data *service_data = NULL;
+       size_t *failed_count = NULL;
+       int ret = 0;
+
+       if (data == NULL || user_data == NULL) {
+               _E("Invalid parameter: data(%p), user_data(%p)", data, user_data);
+               return;
+       }
+
+       service_data = (struct unified_system_service_data *)data;
+       failed_count = (size_t *)user_data;
+
+       if (service_data->service_name == NULL) {
+               _E("Service name is not initialized");
+               goto error;
+       }
+
+       ret = tizen_core_task_create(service_data->service_name, true, &task);
+       if (ret != TIZEN_CORE_ERROR_NONE) {
+               _E("Failed to create tizen_core task: ret(%d)", ret);
+               goto error;
+       }
+
+       ret = tizen_core_source_create(&source);
+       if (ret != TIZEN_CORE_ERROR_NONE) {
+               _E("Failed to create tizen_core source: ret(%d)", ret);
+               goto error;
+       }
+
+       ret = tizen_core_task_get_tizen_core(task, &core);
+       if (ret != TIZEN_CORE_ERROR_NONE) {
+               _E("Failed to get tizen_core core from task: ret(%d)", ret);
+               goto error;
+       }
+
+       ret = tizen_core_source_set_prepare_cb(source, unified_system_service_initialize_cb, service_data);
+       if (ret != TIZEN_CORE_ERROR_NONE) {
+               _E("Failed to set prepare callback: ret(%d)", ret);
+               goto error;
+       }
+
+       ret = tizen_core_source_set_finalize_cb(source, unified_system_service_finalize_cb, service_data);
+       if (ret != TIZEN_CORE_ERROR_NONE) {
+               _E("Failed to set finalize callback: ret(%d)", ret);
+               goto error;
+       }
+
+       ret = tizen_core_add_source(core, source);
+       if (ret != TIZEN_CORE_ERROR_NONE) {
+               _E("Failed to add tizen_core source to core: ret(%d)", ret);
+               goto error;
+       }
+
+       service_data->task = task;
+
+       _D("Task created for %s", service_data->service_name);
+
+       ret = tizen_core_task_run(task);
+       if (ret != TIZEN_CORE_ERROR_NONE) {
+               _E("Failed to run tizen_core task for %s: ret(%d)",
+                               service_data->service_name, ret);
+               goto error;
+       }
+
+       return;
+
+error:
+       if (source != NULL)
+               tizen_core_source_destroy(source);
+
+       if (task != NULL)
+               tizen_core_task_destroy(task);
+
+       (*failed_count)++;
+
+       return;
+}
+
+static void delete_unified_system_service_task(gpointer data, gpointer user_data)
+{
+       struct unified_system_service_data *service_data = NULL;
+       int ret = 0;
+
+       if (data == NULL) {
+               _E("Invalid parameter: data(NULL)");
+               return;
+       }
+       service_data = (struct unified_system_service_data *)data;
+
+       if (service_data->task == NULL) {
+               _D("No task for %s", service_data->service_name);
+               return;
+       }
+
+       ret = tizen_core_task_quit(service_data->task);
+       if (ret != TIZEN_CORE_ERROR_NONE) {
+               _E("Failed to quit task for %s", service_data->service_name);
+               return;
+       }
+
+       ret = tizen_core_task_destroy(service_data->task);
+       if (ret != TIZEN_CORE_ERROR_NONE) {
+               _E("Failed to destroy task for %s", service_data->service_name);
+               return;
+       }
+
+       service_data->task = NULL;
+
+       _D("Task destroyed for %s", service_data->service_name);
+}
+
+static int unified_system_service_start(void)
+{
+       size_t failed_count = 0;
+       size_t services_len = g_slist_length(g_unified_system_service_data_list);
+
+       /* Create tasks for unified-system-service and then tie them */
+       g_slist_foreach(g_unified_system_service_data_list,
+                       (GFunc)create_unified_system_service_task,
+                       &failed_count);
+
+       if (failed_count > 0) {
+               _W("Cannot register %zu/%zu service(s)",
+                               failed_count, services_len);
+       }
+
+       if (failed_count == services_len) {
+               _E("Failed to start unified system service, no task is created");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void unified_system_service_stop(void)
+{
+       g_slist_foreach(g_unified_system_service_data_list,
+                       delete_unified_system_service_task, NULL);
+}
+
+static gboolean handle_signal_glib(gpointer data)
+{
+       int signal_number = GPOINTER_TO_INT(data);
+
+       _D("Received signal(%d)", signal_number);
+       if (g_main_task != NULL)
+               tizen_core_task_quit(g_main_task);
+
+       return G_SOURCE_REMOVE;
+}
+
+static void handle_signal_std(int signal_number)
+{
+       _W("Received signal(%d)", signal_number);
+       raise(SIGTERM);
+}
+
+static void attach_signal_handlers(void)
+{
+       g_unix_signal_add(SIGINT, handle_signal_glib, GINT_TO_POINTER(SIGINT));
+       g_unix_signal_add(SIGHUP, handle_signal_glib, GINT_TO_POINTER(SIGHUP));
+       g_unix_signal_add(SIGTERM, handle_signal_glib, GINT_TO_POINTER(SIGTERM));
+
+       signal(SIGQUIT, handle_signal_std);
+       signal(SIGABRT, handle_signal_std);
+}
+
+static void print_usage(const char *exec_name)
+{
+       _E("Usage: %s --%s <service names>\n",
+                       exec_name, COMMANDLINE_OPTION_SERVICE_PLUGIN);
+}
+
+static int parse_arguments(int argc, char **argv, char **service_plugin_names_str)
+{
+       int opt_flag = 0;
+       char *parsed_service_plugin_names = NULL;
+
+       struct option options[] = {
+               {
+                       .name = COMMANDLINE_OPTION_SERVICE_PLUGIN,
+                       .has_arg = required_argument,
+                       .flag = &opt_flag,
+                       .val = 1
+               }, {
+                       .name = NULL,
+                       .has_arg = 0,
+                       .flag = NULL,
+                       .val = 0
+               },
+       };
+
+       if (service_plugin_names_str == NULL) {
+               _E("Invalid argument: service_plugin_names_str should not be NULL");
+               return -EINVAL;
+       }
+
+       opt_flag = 0;
+       opterr = 0;
+       while (getopt_long(argc, argv, "", options, NULL) != -1) {
+               switch (opt_flag) {
+               case 1:
+                       if (parsed_service_plugin_names != NULL) {
+                               _E("Invalid commandline argument: <service-plugin> provided twice\n");
+                               return -EINVAL;
+                       }
+                       parsed_service_plugin_names = optarg;
+                       break;
+               default:
+                       _E("Invalid commandline argument: %s", argv[optind - 1]);
+                       return -EINVAL;
+               }
+
+               opt_flag = 0;
+       }
+
+       if (parsed_service_plugin_names == NULL) {
+               _E("Invalid commandline argument: <service-plugin> is not provided\n");
+               return -EINVAL;
+       }
+
+       *service_plugin_names_str = parsed_service_plugin_names;
+
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       int ret = 0;
+       char *service_plugin_names_str = NULL;
+       gchar **service_plugin_names = NULL;
+
+       ret = parse_arguments(argc, argv, &service_plugin_names_str);
+       if (ret != 0) {
+               print_usage(argv[0]);
+               return ret;
+       }
+
+       _D("Initialize unified-system-service");
+
+       tizen_core_init();
+
+       ret = tizen_core_task_create("main", false, &g_main_task);
+       if (ret != TIZEN_CORE_ERROR_NONE) {
+               _E("Failed to create tizen_core main task: ret(%d)", ret);
+               tizen_core_shutdown();
+               return 1;
+       }
+
+       service_plugin_names = g_strsplit(service_plugin_names_str, ",", 0);
+       unified_system_service_open_and_add_plugin(service_plugin_names);
+       g_strfreev(service_plugin_names);
+       service_plugin_names = NULL;
+
+       if (g_slist_length(g_unified_system_service_data_list) == 0) {
+               _W("No available service plugin, exit");
+
+               tizen_core_task_destroy(g_main_task);
+               tizen_core_shutdown();
+
+               return 0;
+       }
+
+       ret = unified_system_service_start();
+       if (ret != 0) {
+               _E("Failed to start unified-system-service: ret(%d)", ret);
+
+               unified_system_service_delete_and_close_plugin();
+               tizen_core_task_destroy(g_main_task);
+               tizen_core_shutdown();
+
+               return 1;
+       }
+
+       attach_signal_handlers();
+
+       tizen_core_task_run(g_main_task);
+
+       /* Un-load unified-system-service plugin */
+       unified_system_service_stop();
+       unified_system_service_delete_and_close_plugin();
+
+       tizen_core_task_destroy(g_main_task);
+
+       tizen_core_shutdown();
+
+       _D("Exit unified-system-service");
+
+       return 0;
+}
diff --git a/unified-system-service/unified-system-service.service b/unified-system-service/unified-system-service.service
new file mode 100644 (file)
index 0000000..875b885
--- /dev/null
@@ -0,0 +1,23 @@
+[Unit]
+Description=Unified system service daemon
+Requires=local-fs.target tizen-system-env.service systemd-tmpfiles-setup.service wait-mount@opt-usr.service dbus.socket
+After=wait-mount@opt-usr.service dbus.service local-fs.target tizen-system-env.service systemd-tmpfiles-setup.service
+
+# Caution: never uncomment belwo "Wants=" and "After=" entries.
+# Just information, deviced internally wait for /run/.wm_ready
+# Wants=display-manager.service
+# After=display-manager.service
+
+[Service]
+Type=notify
+SmackProcessLabel=System::Privileged
+Environment=XDG_RUNTIME_DIR=/run
+EnvironmentFile=/run/xdg-root-env
+ExecStart=/usr/bin/unified-system-service --service-plugin sensord,storaged,deviced
+Restart=always
+RestartSec=0
+KillSignal=SIGUSR1
+MemoryMax=20M
+
+[Install]
+WantedBy=multi-user.target
diff --git a/unified-system-service/unified-system-service.socket b/unified-system-service/unified-system-service.socket
new file mode 100644 (file)
index 0000000..9fb78ea
--- /dev/null
@@ -0,0 +1,9 @@
+[Unit]
+Description=Unified system service socket
+
+[Socket]
+ListenStream=/run/.sensord.socket
+SocketMode=0777
+PassCredentials=yes
+SmackLabelIPIn=*
+SmackLabelIPOut=@