Modify ServiceLoader Implementation
authorHwankyu Jhun <h.jhun@samsung.com>
Mon, 7 Apr 2025 11:55:11 +0000 (20:55 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Mon, 7 Apr 2025 11:55:11 +0000 (20:55 +0900)
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
24 files changed:
CMakeLists.txt
include/service.h
include/service_loader.h
include/service_manager.h
include/service_types.h [new file with mode: 0644]
packaging/united-service.spec
src/CMakeLists.txt
src/exception.cc
src/exception.hh
src/iniparser.cc
src/service.cc
src/service.hh
src/service_assembly.cc [new file with mode: 0644]
src/service_assembly.hh [new file with mode: 0644]
src/service_context.cc [deleted file]
src/service_context.hh [deleted file]
src/service_info.cc
src/service_info.hh
src/service_loader.cc
src/service_loader.hh
src/service_manager.cc
src/service_manager.hh
src/stub_service.cc
src/stub_service_loader.cc

index ffc28014bde7197908b1e89228d89c82befc3ed5..2f4187653a1271545d4dfded63db3363d54320bd 100644 (file)
@@ -29,6 +29,7 @@ PKG_CHECK_MODULES(BUNDLE_DEPS REQUIRED bundle)
 PKG_CHECK_MODULES(DLOG_DEPS REQUIRED dlog)
 PKG_CHECK_MODULES(GLIB_DEPS REQUIRED glib-2.0)
 PKG_CHECK_MODULES(TIZEN_CORE_DEPS REQUIRED tizen-core)
+PKG_CHECK_MODULES(TIZEN_LIBOPENER_DEPS REQUIRED tizen-libopener)
 PKG_CHECK_MODULES(INIPARSER_DEPS REQUIRED iniparser)
 
 ADD_SUBDIRECTORY(src)
index 24158005a468c06f7e3fc2b35ea67729c03e6da8..050bea7ef2994c384e618a01339419908ae04c32 100644 (file)
@@ -18,6 +18,7 @@
 #define __SERVICE_H__
 
 #include <bundle.h>
+#include <service_types.h>
 #include <tizen_core.h>
 #include <tizen_error.h>
 
@@ -26,66 +27,57 @@ extern "C" {
 #endif
 
 /**
- * @breif Enumeration for the service result.
- * @since_tizen 10.0
- */
-typedef enum {
-  SERVICE_ERROR_NONE = TIZEN_ERROR_NONE,  /**< Successful */
-  SERVICE_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER,  /**< Invalid parameter */
-  SERVICE_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY,  /**< Out of memory */
-  SERVICE_ERROR_INVALID_CONTEXT = TIZEN_ERROR_APPLICATION | 0x01,  /**< Invalid context */
-  SERVICE_ERROR_ALREADY_EXIST = TIZEN_ERROR_FILE_EXISTS,  /**<Service already exists */
-} service_error_e;
-
-/**
- * @brief Enumeration for the service state.
+ * @brief The service handle.
  * @since_tizen 10.0
+ * @see service_create()
+ * @see service_destroy()
+ * @see service_run()
+ * @see service_quit()
+ * @see service_send_message()
  */
-typedef enum {
-  SERVICE_STATE_INITIALIZED,  /**< The service is initialized */
-  SERVICE_STATE_CREATED,  /**< The service is created. */
-  SERVICE_STATE_RUNNING,  /**< The service is running. */
-  SERVICE_STATE_DESTROYED,  /**< The service is destroyed. */
-} service_state_e;
+typedef void *service_h;
 
 /**
  * @brief Called when the service starts.
  * @details The callback function is called when the main loop of the service starts.
  * @since_tizen 10.0
+ * @param[in] service The service handle.
  * @param[in] user_data The user data passed from the registration function
  * @pre @service_run() will invoke this callback function.
  * @see service_run()
  * @see #service_lifecycle_callback_s
  */
-typedef void (*service_create_cb)(void *user_data);
+typedef void (*service_create_cb)(service_h service, void *user_data);
 
 /**
  * @brief Called when the main loop of the service exits.
  * @details You should release resources of the service in this function.
  * @since_tizen 10.0
+ * @param[in] service The service handle.
  * @param[in] user_data The user data passed from the registration function
  * @see service_quit()
  * @see #service_lifecycle_callback_s
  */
-typedef void (*service_destroy_cb)(void *user_data);
+typedef void (*service_destroy_cb)(service_h service, void *user_data);
 
 /**
  * @brief Called when a message is delivered.
  * @since_tizen 10.0
+ * @param[in] service The service handle.
  * @param[in] sender The name of the sender
  * @param[in] envelope The message
  * @param[in] user_data The user data passed from the registration function
  * @see service_send_message()
  * @see #service_lifecycle_callback_s
  */
-typedef void (*service_message_cb)(const char *sender, bundle *envelope,
-                                   void *user_data);
+typedef void (*service_message_cb)(service_h service, const char *sender,
+                                   bundle *envelope, void *user_data);
 
 /**
  * @brief Thr structure type containing the set of callback functions for handling service lifecycle events.
- * @details It's one of the input parmaeters of the service_create() function.
+ * @details It's one of the input parmaeters of the service_register() function.
  * @since_tizen 10.0
- * @see service_create()
+ * @see service_register()
  * @see service_create_cb()
  * @see service_destroy_cb()
  * @see service_message_cb()
@@ -97,32 +89,18 @@ typedef struct {
 } service_lifecycle_callback_s;
 
 /**
- * @brief The service handle.
- * @since_tizen 10.0
- * @see service_create()
- * @see service_destroy()
- * @see service_run()
- * @see service_quit()
- * @see service_send_message()
- */
-typedef void *service_h;
-
-/**
- * @brief Creates a new service instance.
+ * @brief Registers a structure containing the set of callback functions of the service.
  * @since_tizen 10.0
- * @remarks @a service must be released using service_destroy().
  * @param[in] name The name of the service
  * @param[in] callback The set of callback functions for handling service lifecycle events
  * @param[in] user_data The user data to be passed to the callback functions
- * @param[out] service The service handle
  * @return @c 0 on success,
  *         otherwise a negative error value
  * @retval #SERVICE_ERROR_NONE Successful
  * @retval #SERVICE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #SERVICE_ERROR_OUT_OF_MEMORY Out of memory
  * @retval #SERVICE_ERROR_ALREADY_EXIST Service already exists
- * @see service_destroy()
- * @see service_run()
+ * @see service_unregister()
  * @see #service_lifecycle_callback_s
  * 
  * @code
@@ -135,21 +113,19 @@ typedef void *service_h;
 #undef EXPORT
 #define EXPORT __attribute__((visibility("default")))
 
-static service_h __service;
-
-static void ServiceCreateCb(void* user_data) {
+static void ServiceCreateCb(service_h service, void* user_data) {
   // ...
 }
 
-static void ServiceDestroyCb(void* user_data) {
+static void ServiceDestroyCb(service_h service, void* user_data) {
   // ...
 }
 
-static void ServiceMessageCb(const char* sender, bundle* envelope, void* user_data) {
+static void ServiceMessageCb(service_h service, const char* sender, bundle* envelope, void* user_data) {
   // ...
 }
 
-extern "C" service_h UNITED_SERVICE_INIT(const char* name) {
+extern "C" int UNITED_SERVICE_INIT(const char* name) {
   LOGD("UNITED_SERVICE_INIT. name=%s", name);
   service_lifecycle_callback_s callback = {
     .create = ServiceCreateCb,
@@ -157,16 +133,13 @@ extern "C" service_h UNITED_SERVICE_INIT(const char* name) {
     .message = ServiceMessageCb,
   };
 
-  service_h service = nullptr;
-  int ret = service_create(name, &callback, nullptr, &service);
+  int ret = service_register(name, &callback, nullptr);
   if (ret != SERVICE_ERROR_NONE) {
     LOGE("Failed to create service");
-    return nullptr;
+    return -1;
   }
 
-  service_run(service);
-  __service = service;
-  return service;
+  return 0;
 }
 
 extern "C" void UNITED_SERVICE_SHUTDOWN(void) {
@@ -174,21 +147,18 @@ extern "C" void UNITED_SERVICE_SHUTDOWN(void) {
 }
  * @endcode
  */
-int service_create(const char *name, service_lifecycle_callback_s *callback,
-                   void *user_data, service_h *service);
+int service_register(const char *name, service_lifecycle_callback_s *callback,
+                     void *user_data);
 
 /**
- * @brief Runs the service instance.
+ * @brief Unregisters the registered the set of callback functions of the service.
  * @since_tizen 10.0
- * @param[in] service The service handle
+ * @param[in] name The name of the service.
  * @return @c 0 on success,
  *         otherwise a negative error value
  * @retval #SERVICE_ERROR_NONE Successful
  * @retval #SERVICE_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #SERVICE_ERROR_INVALID_CONTEXT Invalid context
  * @see service_create()
- * @see service_quit()
- * @see service_create_cb()
  *
  * @code
 #include <service.h>
@@ -200,23 +170,24 @@ int service_create(const char *name, service_lifecycle_callback_s *callback,
 #undef EXPORT
 #define EXPORT __attribute__((visibility("default")))
 
-static service_h __service;
-
-static void ServiceCreateCb(void* user_data) {
-  LOGD("Alarm Service Created");
-}
+static char* __name;
 
 extern "C" service_h UNITED_SERVICE_INIT(const char* name) {
   LOGD("UNITED_SERVICE_INIT. name=%s", name);
+  __name = strdup(name);
   // ...
-
-  service_run(service);
-  __service = service;
   return service;
 }
+
+extern "C" void UNITED_SERVICE_SHUTDOWN(void) {
+  LOGD("UNITED_SERVICE_SHUTDOWN");
+  service_unregister(__name);
+  free(__name);
+  __name = nullptr;
+}
  * @endcode
  */
-int service_run(service_h service);
+int service_unregister(const char *name);
 
 /**
  * @brief Exits the service instance.
@@ -243,7 +214,7 @@ int service_run(service_h service);
 
 static service_h __service;
 
-static void ServiceDestroyCb(void* user_data) {
+static void ServiceDestroyCb(service_h service, void* user_data) {
   // ...
 }
 
@@ -257,7 +228,6 @@ extern "C" void UNITED_SERVICE_SHUTDOWN(void) {
   LOGD("UNITED_SERVICE_SHUTDOWN");
   if (__service) {
     service_quit(__service);
-    service_destroy(__service);
     __service = nullptr;
   }
 }
@@ -289,7 +259,7 @@ int service_quit(service_h service);
 
 static service_h __service;
 
-static void ServiceMessageCb(const char* sender, bundle* envelope, void* user_data) {
+static void ServiceMessageCb(service_h service, const char* sender, bundle* envelope, void* user_data) {
   char* message = nullptr;
 
   if (bundle_get_str(envelope, "MESSAGE", &message) == BUNDLE_ERROR_NONE) {
@@ -336,45 +306,6 @@ extern "C" void UNITED_SERVICE_SHUTDOWN(void) {
  */
 int service_send_message(service_h service, bundle *envelope);
 
-/**
- * @brief Destroys the service instance.
- * @since_tizen 10.0
- * @param[in] service The service handle
- * @return @c 0 on success,
- *         otherwise a negative error value
- * @retval #SERVICE_ERROR_NONE Successful
- * @retval #SERVICE_ERROR_INVALID_PARAMETER Invalid parameter
- * @see service_create()
- *
- * @code
-#include <service.h>
-#include <dlog.h>
-
-#undef LOG_TAG
-#define LOG_TAG "ALARM_SERVICE"
-
-#undef EXPORT
-#define EXPORT __attribute__((visibility("default")))
-
-static service_h __service;
-
-extern "C" service_h UNITED_SERVICE_INIT(const char* name) {
-  LOGD("UNITED_SERVICE_INIT. name=%s", name);
-  // ...
-  return service;
-}
-
-extern "C" void UNITED_SERVICE_SHUTDOWN(void) {
-  LOGD("UNITED_SERVICE_SHUTDOWN");
-  if (__service) {
-    service_destroy(__service);
-    __service = nullptr;
-  }
-}
- * @endcode
- */
-int service_destroy(service_h service);
-
 /**
  * @brief Gets the name of the service.
  * @details The @a name must be released using free().
index 11ef9ffb2606fd859666eb087cee24ad738ec34e..2e34a381b59f6fe9ffa96fb3cbba81575fddc916 100644 (file)
@@ -18,6 +18,7 @@
 #define __SERVICE_LOADER_H__
 
 #include <bundle.h>
+#include <service_types.h>
 #include <tizen_error.h>
 
 #ifdef __cplusplus
@@ -98,10 +99,10 @@ typedef struct {
  * @param[in] user_data The user data to be passed to the callback functions
  * @return @c 0 on success,
  *         otherwise a negative error value
- * @retval #SERVICE_LOADER_ERROR_NONE Successful
- * @retval #SERVICE_LOADER_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #SERVICE_LOADER_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #SERVICE_LOADER_ERROR_ALREADY_RUNNING The service loader is already running
+ * @retval #SERVICE_ERROR_NONE Successful
+ * @retval #SERVICE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #SERVICE_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #SERVICE_ERROR_ALREADY_RUNNING The service loader is already running
  * @see service_loader_create_cb()
  * @see service_loader_destroy_cb()
  * @see service_loader_message_cb()
@@ -183,9 +184,9 @@ void service_loader_quit(void);
  * @param[in] envelope The envelope of the message
  * @return @c 0 on success,
  *         otherwise a negative error value
- * @retval #SERVICE_LOADER_ERROR_NONE Successful
- * @retval #SERVICE_LOADER_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #SERVICE_LOADER_ERROR_INVALID_CONTEXT Invalid context
+ * @retval #SERVICE_ERROR_NONE Successful
+ * @retval #SERVICE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #SERVICE_ERROR_INVALID_CONTEXT Invalid context
  * @see service_loader_message_cb()
  *
  * @code
@@ -227,6 +228,18 @@ static void SendMessage(const char* message) {
  */
 int service_loader_send_message(bundle *envelope);
 
+int service_loader_run_service(const char *name);
+
+int service_loader_run_all_services(void);
+
+int service_loader_quit_service(const char *name);
+
+int service_loader_quit_all_services(void);
+
+int service_loader_load_service(const char *name);
+
+int service_loader_unload_service(const char *name);
+
 #ifdef __cplusplus
 }
 #endif
index a1d8d24cbc8f3892e0ab114b0070a62beb3f2e9c..4769d86593fb34845ff57ba2e8332a81b322c431 100644 (file)
 #define __SERVICE_MANAGER_H__
 
 #include <service.h>
+#include <service_types.h>
 #include <tizen.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/**
- * @brief Enumeration for the service manager result.
- * @since_tizen 10.0
- */
-typedef enum {
-  SERVICE_MANAGER_ERROR_NONE = TIZEN_ERROR_NONE,  /**< Successful */
-  SERVICE_MANAGER_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER,  /**< Invalid parameter */
-  SERVICE_MANAGER_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY,  /**< Out of memory */
-} service_manager_error_e;
-
 /**
  * @brief The handle for the service manager event handler.
  * @since_tizen 10.0
@@ -61,9 +52,9 @@ typedef void (*service_state_changed_cb)(service_h service,
  * @param[out] event_handler The event handler
  * @return @c 0 on success,
  *         otherwise a negative error value
- * @retval #SERVICE_MANAGER_ERROR_NONE Successful
- * @retval #SERVICE_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #SERVICE_MANAGER_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #SERVICE_ERROR_NONE Successful
+ * @retval #SERVICE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #SERVICE_ERROR_OUT_OF_MEMORY Out of memory
  * @see service_manager_remove_event_handler()
  * @see service_state_changed_cb()
  * @remarks The @a event_handler should be released using service_manager_remove_event_handler().
@@ -108,8 +99,8 @@ int service_manager_add_event_handler(service_state_changed_cb callback,
  * @param[in] event_handler The event handler
  * @return @c 0 on success,
  *         otherwise a negative error value
- * @retval #SERVICE_MANAGER_ERROR_NONE Successful
- * @retval #SERVICE_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #SERVICE_ERROR_NONE Successful
+ * @retval #SERVICE_ERROR_INVALID_PARAMETER Invalid parameter
  * @see service_manager_add_event_handler()
  *
  * @code
@@ -137,8 +128,8 @@ int service_manager_remove_event_handler(service_manager_event_h event_handler);
  * @param[out] service The service handle
  * @return @c 0 on success,
  *         otherwise a negative error value
- * @retval #SERVICE_MANAGER_ERROR_NONE Successful
- * @retval #SERVICE_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #SERVICE_ERROR_NONE Successful
+ * @retval #SERVICE_ERROR_INVALID_PARAMETER Invalid parameter
  * @remarks The @a service should not be released using service_destroy().
  *
  * @code
diff --git a/include/service_types.h b/include/service_types.h
new file mode 100644 (file)
index 0000000..3ada27d
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2025 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.
+ * 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.
+ */
+
+#ifndef __SERVICE_TYPES_H__
+#define __SERVICE_TYPES_H__
+
+#include <tizen_error.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @breif Enumeration for the service result.
+ * @since_tizen 10.0
+ */
+typedef enum {
+  SERVICE_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
+  SERVICE_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+  SERVICE_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
+  SERVICE_ERROR_INVALID_CONTEXT = TIZEN_ERROR_APPLICATION | 0x01, /**< Invalid context */
+  SERVICE_ERROR_ALREADY_EXIST = TIZEN_ERROR_FILE_EXISTS, /**< Already exists */
+  SERVICE_ERROR_ALREADY_RUNNING = TIZEN_ERROR_ALREADY_IN_PROGRESS, /**< Already running */
+  SERVICE_ERROR_NO_SUCH_SERVICE = TIZEN_ERROR_NO_SUCH_FILE, /**< No such service */
+  SERVICE_ERROR_IO_ERROR = TIZEN_ERROR_IO_ERROR, /**< I/O error */
+} service_error_e;
+
+/**
+ * @brief Enumeration for the service state.
+ * @since_tizen 10.0
+ */
+typedef enum {
+  SERVICE_STATE_INITIALIZED, /**< The service is initialized */
+  SERVICE_STATE_CREATED,     /**< The service is created. */
+  SERVICE_STATE_RUNNING,     /**< The service is running. */
+  SERVICE_STATE_DESTROYED,   /**< The service is destroyed. */
+} service_state_e;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SERVICE_TYPES_H__ */
index c84cbfecee9e652a73a214c0c77dd08109111ea9..4da13e284399ee4319a8368aeb2dda08092c0f9a 100644 (file)
@@ -11,6 +11,7 @@ BuildRequires:  hash-signer
 BuildRequires:  pkgconfig(dlog)
 BuildRequires:  pkgconfig(bundle)
 BuildRequires:  pkgconfig(tizen-core)
+BuildRequires:  pkgconfig(tizen-libopener)
 BuildRequires:  pkgconfig(glib-2.0)
 BuildRequires:  pkgconfig(iniparser)
 
index 68ee30e92c2af68cc7fde06020179d049c38a649..fe289255d1f37755e68221bde81eb73e387427de 100644 (file)
@@ -16,6 +16,7 @@ APPLY_PKG_CONFIG(${TARGET_UNITED_SERVICE} PUBLIC
   DLOG_DEPS
   GLIB_DEPS
   TIZEN_CORE_DEPS
+  TIZEN_LIBOPENER_DEPS
   INIPARSER_DEPS
 )
 
index 006461cd4a9f5d140376bf929bc196a6b575793c..7b4276a96a4a1f74dfd0dfa0c503ee1d64fffd13 100644 (file)
@@ -26,7 +26,7 @@ Exception::Exception(int error_code, const std::string& file, int line)
 
 const char* Exception::what() const noexcept { return message_.c_str(); }
 
-int Exception::GetErrorCode() { return error_code_; }
+int Exception::GetErrorCode() const { return error_code_; }
 
 std::string Exception::GetErrorMessage(int error_code, const std::string& file,
                                        int line) {
index 10ac7eabbf761ace842a8d100c31fc397a381bc2..d86cca7abe69d9c30de1b0d1221a57feb8791e02 100644 (file)
@@ -20,6 +20,7 @@
 #include <exception>
 #include <string>
 
+#include "service_types.h"
 #include "log_private.hh"
 
 #define THROW(error_code) throw Exception(error_code, __FUNCTION__, __LINE__)
@@ -32,7 +33,7 @@ class Exception : public std::exception {
   virtual ~Exception() = default;
 
   virtual const char* what() const noexcept;
-  int GetErrorCode();
+  int GetErrorCode() const;
 
  private:
   static std::string GetErrorMessage(int error_code, const std::string& file,
index 86fb615f48f86aa8e1103aaf9294858a2147c3c5..618086bdd135b120ddf8b871122b6ef38bb3d291 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <errno.h>
 
+#include "service_types.h"
 #include "exception.hh"
 #include "log_private.hh"
 
@@ -27,7 +28,7 @@ std::shared_ptr<Dictionary> IniParser::Parse(const std::string& path) {
   dictionary* d = iniparser_load(path.c_str());
   if (d == nullptr) {
     _E("iniparser_load(%s) is failed", path.c_str());
-    THROW(-errno);
+    THROW(SERVICE_ERROR_IO_ERROR);
   }
 
   auto d_ptr = std::unique_ptr<dictionary, decltype(iniparser_freedict)*>(
index 5351531f9b1dd91395f5fb9d3925b6c8d317546c..975f766614074b339e6eb7b27a2e89791ef3a746 100644 (file)
@@ -26,7 +26,9 @@
 
 namespace tizen_base {
 
-Service::Service(std::string name) : name_(std::move(name)) {
+Service::Service(std::shared_ptr<ServiceInfo> info,
+                 std::shared_ptr<IEvent> listener)
+    : info_(std::move(info)), listener_(std::move(listener)) {
   if (!Init()) {
     Shutdown();
     throw new std::runtime_error("Failed to initialize service");
@@ -42,9 +44,9 @@ Service::~Service() {
 
 bool Service::Init() {
   tizen_core_init();
-  int ret = tizen_core_task_create(name_.c_str(), true, &task_);
+  int ret = tizen_core_task_create(GetName().c_str(), true, &task_);
   if (ret != TIZEN_CORE_ERROR_NONE) {
-    _E("tizen_core_task_create() is failed. name=%s", name_.c_str());
+    _E("tizen_core_task_create() is failed. name=%s", GetName().c_str());
     return false;
   }
 
@@ -89,16 +91,24 @@ void Service::Shutdown() {
   }
 }
 
-const std::string& Service::GetName() const { return name_; }
+const std::shared_ptr<ServiceInfo>& Service::GetServiceInfo() const {
+  return info_;
+}
+
+const std::string& Service::GetName() const { return info_->GetName(); }
 
 Service::State Service::GetState() const { return state_; }
 
 tizen_core_h Service::GetCore() const { return core_; }
 
-tizen_core_channel_sender_h Service::GetChannelSender() const { return sender_; }
+tizen_core_channel_sender_h Service::GetChannelSender() const {
+  return sender_;
+}
+
+bool Service::IsRunning() const { return running_; }
 
 void Service::Run() {
-  if (running_) {
+  if (IsRunning()) {
     _E("Already running");
     return;
   }
@@ -123,7 +133,7 @@ void Service::Run() {
 }
 
 void Service::Quit() {
-  if (!running_) return;
+  if (!IsRunning()) return;
 
   std::unique_lock<std::mutex> lock(mutex_);
   tizen_core_source_h source = nullptr;
@@ -161,16 +171,21 @@ void Service::SendMessage(const tizen_base::Bundle& envelope) {
 
 void Service::OnCreate() {
   state_ = State::Created;
+  if (listener_.use_count() > 1) listener_->OnCreate(this);
   ServiceManager::GetInst().NotifyServiceStateChanged(this);
 }
 
 void Service::OnDestroy() {
   state_ = State::Destroyed;
+  if (listener_.use_count() > 1) listener_->OnDestroy(this);
   ServiceManager::GetInst().NotifyServiceStateChanged(this);
 }
 
 void Service::OnMessageReceived(const std::string& sender,
-                                const tizen_base::Bundle& envelope) {}
+                                const tizen_base::Bundle& envelope) {
+  if (listener_.use_count() > 1)
+    listener_->OnMessageReceived(this, sender, envelope);
+}
 
 void Service::ChannelReceiveCb(tizen_core_channel_object_h object,
                                void* user_data) {
index 354ad592e084efe2c5dae75f0179d0de4d3eb365..7dff68c60637c0aeee16b5980c36e5960ffd039f 100644 (file)
 #include <tizen_core.h>
 #include <tizen_core_channel.h>
 
+#include <atomic>
 #include <condition_variable>
 #include <memory>
 #include <mutex>
 #include <string>
 
+#include "service_info.hh"
+
 namespace tizen_base {
 
 class Service : public std::enable_shared_from_this<Service> {
@@ -37,22 +40,34 @@ class Service : public std::enable_shared_from_this<Service> {
     Destroyed,
   };
 
-  Service(std::string name);
+  class IEvent {
+   public:
+    virtual ~IEvent() = default;
+    virtual void OnCreate(const Service* service) = 0;
+    virtual void OnDestroy(const Service* service) = 0;
+    virtual void OnMessageReceived(const Service* service,
+                                   const std::string& sender,
+                                   const Bundle& envelope) = 0;
+  };
+
+  Service(std::shared_ptr<ServiceInfo> info, std::shared_ptr<IEvent> listener);
   virtual ~Service();
 
   void Run();
   void Quit();
 
+  bool IsRunning() const;
+  const std::shared_ptr<ServiceInfo>& GetServiceInfo() const;
   const std::string& GetName() const;
   State GetState() const;
   tizen_core_h GetCore() const;
   tizen_core_channel_sender_h GetChannelSender() const;
   void SendMessage(const tizen_base::Bundle& envelope);
 
-  virtual void OnCreate();
-  virtual void OnDestroy();
-  virtual void OnMessageReceived(const std::string& sender,
-                                 const tizen_base::Bundle& envelope);
+  void OnCreate();
+  void OnDestroy();
+  void OnMessageReceived(const std::string& sender,
+                         const tizen_base::Bundle& envelope);
 
  private:
   bool Init();
@@ -61,14 +76,15 @@ class Service : public std::enable_shared_from_this<Service> {
                                void* user_data);
 
  private:
-  std::string name_;
+  std::shared_ptr<ServiceInfo> info_;
+  std::shared_ptr<IEvent> listener_;
   State state_ = State::Initialized;
   tizen_core_task_h task_ = nullptr;
   tizen_core_h core_ = nullptr;
   tizen_core_channel_sender_h sender_ = nullptr;
   tizen_core_channel_receiver_h receiver_ = nullptr;
   tizen_core_source_h source_ = nullptr;
-  bool running_ = false;
+  std::atomic<bool> running_{false};
   std::mutex mutex_;
   std::condition_variable cond_var_;
   pid_t tid_ = -1;
diff --git a/src/service_assembly.cc b/src/service_assembly.cc
new file mode 100644 (file)
index 0000000..fce967b
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2025 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.
+ * 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 "service_assembly.hh"
+
+#include <filesystem>
+#include <string>
+
+#include "exception.hh"
+#include "log_private.hh"
+
+namespace {
+
+constexpr const char kUnitedServiceInit[] = "UNITED_SERVICE_INIT";
+constexpr const char kUnitedServiceShutdown[] = "UNITED_SERVICE_SHUTDOWN";
+
+}  // namespace
+
+namespace tizen_base {
+
+ServiceAssembly::ServiceAssembly(std::string assembly_path)
+    : assembly_path_(std::move(assembly_path)) {}
+
+ServiceAssembly::~ServiceAssembly() {}
+
+bool ServiceAssembly::IsLoaded() const { return lib_opener_.get(); }
+
+void ServiceAssembly::Load() {
+  try {
+    lib_opener_.reset(new tizen_base::LibOpener(assembly_path_));
+  } catch (const std::filesystem::filesystem_error& e) {
+    _E("Error=%s", e.what());
+    THROW(SERVICE_ERROR_IO_ERROR);
+  }
+}
+
+void ServiceAssembly::Unload() { lib_opener_.reset(); }
+
+void ServiceAssembly::ModuleInit(const std::string& name) {
+  try {
+    auto init_func =
+        lib_opener_->Bind<int (*)(const char*)>(kUnitedServiceInit);
+    int ret = init_func(name.c_str());
+    if (ret != 0) {
+      _E("Failed to initialize service. name=%s", name.c_str());
+      THROW(SERVICE_ERROR_INVALID_CONTEXT);
+    }
+  } catch (const std::exception& e) {
+    _E("Error=%s", e.what());
+    THROW(SERVICE_ERROR_NO_SUCH_SERVICE);
+  }
+}
+
+void ServiceAssembly::ModuleShutdown() {
+  try {
+    auto shutdown_func = lib_opener_->Bind<void (*)()>(kUnitedServiceShutdown);
+    shutdown_func();
+  } catch (const std::exception& e) {
+    _E("Error=%s", e.what());
+    THROW(SERVICE_ERROR_NO_SUCH_SERVICE);
+  }
+}
+
+}  // namespace tizen_base
diff --git a/src/service_assembly.hh b/src/service_assembly.hh
new file mode 100644 (file)
index 0000000..6424a59
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2025 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.
+ * 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.
+ */
+
+#ifndef SERVICE_ASSEMBLY_HH_
+#define SERVICE_ASSEMBLY_HH_
+
+#include <memory>
+#include <string>
+
+#include <libopener.hpp>
+
+namespace tizen_base {
+
+class ServiceAssembly {
+ public:
+  ServiceAssembly(std::string assembly_path);
+  virtual ~ServiceAssembly();
+
+  bool IsLoaded() const;
+  void Load();
+  void Unload();
+
+  void ModuleInit(const std::string& name);
+  void ModuleShutdown();
+
+ private:
+  std::string assembly_path_;
+  std::unique_ptr<LibOpener> lib_opener_{nullptr};
+};
+
+}  // namespace tizen_base
+
+#endif  // SERVICE_ASSEMBLY_HH_
\ No newline at end of file
diff --git a/src/service_context.cc b/src/service_context.cc
deleted file mode 100644 (file)
index 8864417..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2025 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.
- * 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 "service_context.hh"
-
-#include <dlfcn.h>
-
-#include <string>
-#include <utility>
-
-#include "log_private.hh"
-
-namespace {
-
-constexpr const char kUnitedServiceInit[] = "UNITED_SERVICE_INIT";
-constexpr const char kUnitedServiceShutdown[] = "UNITED_SERVICE_SHUTDOWN";
-
-}  // namespace
-
-namespace tizen_base {
-
-ServiceContext::ServiceContext(std::shared_ptr<ServiceInfo> info)
-    : info_(std::move(info)) {}
-
-ServiceContext::~ServiceContext() { Shutdown(); }
-
-bool ServiceContext::Init() {
-  if (!Load()) return false;
-
-  auto* init_func = reinterpret_cast<void* (*)(const char*)>(
-      dlsym(handle_, kUnitedServiceInit));
-  if (init_func == nullptr) {
-    _E("dlsym() is failed. error=%s", dlerror());
-    Unload();
-    return false;
-  }
-
-  auto* handle = init_func(info_->GetName().c_str());
-  if (handle == nullptr) {
-    _E("Failed to initialize united service");
-    Unload();
-    return false;
-  }
-
-  auto* service = static_cast<Service*>(handle);
-  service_ = service->shared_from_this();
-  return true;
-}
-
-void ServiceContext::Shutdown() {
-  if (!handle_) return;
-
-  if (service_) service_->Quit();
-
-  auto* shutdown_func =
-      reinterpret_cast<void (*)(void)>(dlsym(handle_, kUnitedServiceShutdown));
-  if (shutdown_func == nullptr) {
-    _E("dlsym() is failed. error=%s", dlerror());
-  } else {
-    shutdown_func();
-  }
-
-  Unload();
-}
-
-std::shared_ptr<Service> ServiceContext::GetService() const { return service_; }
-
-std::shared_ptr<ServiceInfo> ServiceContext::GetServiceInfo() const {
-  return info_;
-}
-
-const std::string& ServiceContext::GetName() const { return info_->GetName(); }
-
-bool ServiceContext::Load() {
-  if (handle_) return true;
-
-  _D("Load(): %s", info_->GetPath().c_str());
-  handle_ = dlopen(info_->GetPath().c_str(), RTLD_LAZY | RTLD_GLOBAL);
-  if (handle_ == nullptr) {
-    _E("dlopen() is failed. path=%s, error=%s", info_->GetPath().c_str(),
-       dlerror());
-    return false;
-  }
-
-  return true;
-}
-
-void ServiceContext::Unload() {
-  if (!handle_) return;
-
-  _D("Unload(): %s", info_->GetPath().c_str());
-  dlclose(handle_);
-  handle_ = nullptr;
-}
-
-}  // namespace tizen_base
-
diff --git a/src/service_context.hh b/src/service_context.hh
deleted file mode 100644 (file)
index 54939a9..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2025 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.
- * 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.
- */
-
-#ifndef SERVICE_CONTEXT_HH_
-#define SERVICE_CONTEXT_HH_
-
-#include <memory>
-#include <string>
-
-#include "service.hh"
-#include "service_info.hh"
-
-namespace tizen_base {
-
-class ServiceContext {
- public:
-  ServiceContext(std::shared_ptr<ServiceInfo> info);
-  ~ServiceContext();
-
-  bool Init();
-  void Shutdown();
-  std::shared_ptr<Service> GetService() const;
-  std::shared_ptr<ServiceInfo> GetServiceInfo() const;
-  const std::string& GetName() const;
-
- private:
-  bool Load();
-  void Unload();
-
- private:
-  std::shared_ptr<ServiceInfo> info_;
-  std::shared_ptr<Service> service_;
-  void* handle_ = nullptr;
-};
-
-}  // namespace tizen_base
-
-#endif  // SERVICE_CONTEXT_HH_
index 0c17c59a1347e54cc35aee273eabc83019d696af..3287b5096865c3fafdcfbaf0b1c7c759c9f7164e 100644 (file)
@@ -46,6 +46,7 @@ ServiceInfo::ServiceInfo(std::string conf_name,
   _D("Type=%s", type_.c_str());
   path_ = dictionary->Get(kPath);
   _D("Path=%s", path_.c_str());
+  assembly_ = std::make_shared<ServiceAssembly>(path_);
 }
 
 ServiceInfo::~ServiceInfo() {}
@@ -62,4 +63,8 @@ const std::string& ServiceInfo::GetType() const { return type_; }
 
 const std::string& ServiceInfo::GetPath() const { return path_; }
 
+std::shared_ptr<ServiceAssembly> ServiceInfo::GetAssembly() const {
+  return assembly_;
+}
+
 }  // namespace tizen_base
index 3a6baa8b821b385d9731cdf76565376211057ad6..6ce08b53e2d4d22e5ff2768414ad5a5726b5293c 100644 (file)
@@ -21,6 +21,7 @@
 #include <string>
 
 #include "dictionary.hh"
+#include "service_assembly.hh"
 
 namespace tizen_base {
 
@@ -35,6 +36,7 @@ class ServiceInfo {
   const std::string& GetMode() const;
   const std::string& GetType() const;
   const std::string& GetPath() const;
+  std::shared_ptr<ServiceAssembly> GetAssembly() const;
 
  private:
   std::string conf_name_;
@@ -43,6 +45,7 @@ class ServiceInfo {
   std::string mode_;
   std::string type_;
   std::string path_;
+  std::shared_ptr<ServiceAssembly> assembly_;
 };
 
 }  // namespace tizen_base
index 95f00077963204a0ef9e891ce2cc6085f6f5ee94..29e5c7e727c88266ba0712e6bf613ab075cae626 100644 (file)
@@ -25,6 +25,7 @@
 #include "exception.hh"
 #include "iniparser.hh"
 #include "log_private.hh"
+#include "service_manager.hh"
 
 namespace {
 
@@ -108,12 +109,23 @@ void ServiceLoader::LoadServices() {
         auto dictionary = IniParser::Parse(file.string());
         auto info =
             std::make_shared<ServiceInfo>(file.string(), std::move(dictionary));
-        auto context = std::make_shared<ServiceContext>(std::move(info));
-        context->Init();
-        contexts_.push_back(std::move(context));
+        infos_[info->GetName()] = std::move(info);
       }
     }
   }
+
+  for (auto& [name, info] : infos_) {
+    try {
+      auto assembly = info->GetAssembly();
+      if (!assembly->IsLoaded()) {
+        assembly->Load();
+        assembly->ModuleInit(info->GetName());
+      }
+    } catch (const Exception& e) {
+      _E("Error=%s", e.what());
+      THROW(e.GetErrorCode());
+    }
+  }
 }
 
 int ServiceLoader::Run() {
@@ -141,7 +153,94 @@ void ServiceLoader::SendMessage(const tizen_base::Bundle& envelope) {
   tizen_core_channel_object_destroy(object);
   if (ret != TIZEN_CORE_ERROR_NONE) {
     _E("tizen_core_channel_send() is failed. error=%d", ret);
-    throw new std::runtime_error("Failed to send message");
+    THROW(SERVICE_ERROR_IO_ERROR);
+  }
+}
+
+void ServiceLoader::RunService(const std::string& name) {
+  auto service = GetService(name);
+  if (service != nullptr && service->IsRunning()) {
+    _E("Already running. name=%s", name.c_str());
+    THROW(SERVICE_ERROR_ALREADY_RUNNING);
+  }
+
+  auto info = GetServiceInfo(name);
+  if (info == nullptr) {
+    _E("No such service. name=%s", name.c_str());
+    THROW(SERVICE_ERROR_NO_SUCH_SERVICE);
+  }
+
+  auto listener = ServiceManager::GetInst().GetServiceEventListener(name);
+  if (listener == nullptr) {
+    _E("No such event listener. name=%s", name.c_str());
+    THROW(SERVICE_ERROR_INVALID_CONTEXT);
+  }
+
+  service = std::make_shared<Service>(std::move(info), std::move(listener));
+  if (service == nullptr) {
+    _E("Out of memory. name=%s", name.c_str());
+    THROW(SERVICE_ERROR_OUT_OF_MEMORY);
+  }
+
+  service->Run();
+}
+
+void ServiceLoader::RunAllServices() {
+  for (auto& [name, _] : infos_) {
+    try {
+      RunService(name);
+    } catch (const Exception& e) {
+      _E("Error=%s", e.what());
+    }
+  }
+}
+
+void ServiceLoader::QuitService(const std::string& name) {
+  auto service = GetService(name);
+  if (service == nullptr || !service->IsRunning()) {
+    _E("Not running. name=%s", name.c_str());
+    THROW(SERVICE_ERROR_INVALID_CONTEXT);
+  }
+
+  service->Quit();
+}
+
+void ServiceLoader::QuitAllServices() {
+  for (auto& [name, service] : services_) {
+    if (service->IsRunning()) service->Quit();
+  }
+}
+
+void ServiceLoader::LoadService(const std::string& name) {
+  auto found = infos_.find(name);
+  if (found == infos_.end()) THROW(SERVICE_ERROR_INVALID_PARAMETER);
+
+  auto& info = found->second;
+  auto assembly = info->GetAssembly();
+  if (assembly->IsLoaded()) THROW(SERVICE_ERROR_INVALID_CONTEXT);
+
+  try {
+    assembly->Load();
+    assembly->ModuleInit(info->GetName());
+  } catch (const Exception& e) {
+    _E("Error=%s", e.what());
+    THROW(e.GetErrorCode());
+  }
+}
+
+void ServiceLoader::UnloadService(const std::string& name) {
+  auto found = infos_.find(name);
+  if (found == infos_.end()) THROW(SERVICE_ERROR_NO_SUCH_SERVICE);
+
+  auto& info = found->second;
+  auto assembly = info->GetAssembly();
+  if (!assembly->IsLoaded()) THROW(SERVICE_ERROR_INVALID_CONTEXT);
+
+  try {
+    assembly->ModuleShutdown();
+    assembly->Unload();
+  } catch (const Exception& e) {
+    _E("Error=%s", e.what());
   }
 }
 
@@ -156,8 +255,8 @@ void ServiceLoader::OnCreate() {
 }
 
 void ServiceLoader::OnDestroy() {
-  for (auto& context : contexts_) {
-    context->Shutdown();
+  for (auto& [name, service] : services_) {
+    if (service->IsRunning()) service->Quit();
   }
 }
 
@@ -175,4 +274,19 @@ void ServiceLoader::ChannelReceiveCb(tizen_core_channel_object_h object,
                              tizen_base::Bundle(data, false, true));
 }
 
+std::shared_ptr<ServiceInfo> ServiceLoader::GetServiceInfo(
+    const std::string& name) {
+  auto found = infos_.find(name);
+  if (found == infos_.end()) return nullptr;
+
+  return found->second;
+}
+
+std::shared_ptr<Service> ServiceLoader::GetService(const std::string& name) {
+  auto found = services_.find(name);
+  if (found == services_.end()) return nullptr;
+
+  return found->second;
+}
+
 } // namespace tizen_base
index a4bc63df5b4103d67a1bc6536f0b09863ea1ed92..772b0e268c6c791836966d6524f721380c72d23f 100644 (file)
  * limitations under the License.
  */
 
+#ifndef SERVICE_LOADER_HH_
+#define SERVICE_LOADER_HH_
+
 #include <bundle_cpp.h>
 #include <tizen_core.h>
 
 #include <memory>
 #include <string>
+#include <unordered_map>
 
-#include "service_context.hh"
+#include "service.hh"
 #include "service_info.hh"
 
 namespace tizen_base {
@@ -34,12 +38,22 @@ class ServiceLoader {
   void Quit();
   void SendMessage(const tizen_base::Bundle& envelope);
 
+  void RunService(const std::string& name);
+  void RunAllServices();
+  void QuitService(const std::string& name);
+  void QuitAllServices();
+  void LoadService(const std::string& name);
+  void UnloadService(const std::string& name);
+
   virtual void OnCreate();
   virtual void OnDestroy();
   virtual void OnMessageReceived(const std::string& sender,
                                  const tizen_base::Bundle& envelope);
 
  private:
+  std::shared_ptr<Service> GetService(const std::string& name);
+  std::shared_ptr<ServiceInfo> GetServiceInfo(const std::string& name);
+
   bool Init();
   void Shutdown();
   void LoadServices();
@@ -56,7 +70,10 @@ class ServiceLoader {
   tizen_core_channel_receiver_h receiver_ = nullptr;
   tizen_core_source_h source_ = nullptr;
   bool running_ = false;
-  std::vector<std::shared_ptr<ServiceContext>> contexts_;
+  std::unordered_map<std::string, std::shared_ptr<ServiceInfo>> infos_;
+  std::unordered_map<std::string, std::shared_ptr<Service>> services_;
 };
 
 } // namespace tizen_base
+
+#endif  // SERVICE_LOADER_HH_
index b2cf7c55592eecf1faf794ed14967ebaa2429b51..b8ff414cfd93f6c9746483e6b0dd83a12c4332ac 100644 (file)
@@ -108,6 +108,31 @@ void ServiceManager::NotifyServiceStateChanged(Service* service) {
   }
 }
 
+void ServiceManager::RegisterServiceEventListener(
+    std::string name, std::shared_ptr<Service::IEvent> listener) {
+  if (!Contains(name)) {
+    _E("Invalid parameter");
+    return;
+  }
+
+  service_listeners_[std::move(name)] = std::move(listener);
+}
+
+void ServiceManager::UnregisterServiceEventListener(const std::string& name) {
+  auto found = service_listeners_.find(name);
+  if (found == service_listeners_.end()) return;
+
+  service_listeners_.erase(found);
+}
+
+std::shared_ptr<Service::IEvent> ServiceManager::GetServiceEventListener(
+    const std::string& name) {
+  auto found = service_listeners_.find(name);
+  if (found == service_listeners_.end()) return nullptr;
+
+  return found->second;
+}
+
 std::shared_ptr<Service> ServiceManager::FindFromThisThread() {
   tizen_core_h core = nullptr;
   tizen_core_find_from_this_thread(&core);
index 286491f747a0542ba3f18b0e0232193c802d1c70..d2f9fa187c2754cc0632125d7be6f8ea0a28f772 100644 (file)
@@ -46,6 +46,11 @@ class ServiceManager {
   void RemoveEventListener(const std::shared_ptr<Service>& service,
                            IEvent* listener);
   void NotifyServiceStateChanged(Service* service);
+  void RegisterServiceEventListener(std::string name,
+                                    std::shared_ptr<Service::IEvent> listener);
+  void UnregisterServiceEventListener(const std::string& name);
+  std::shared_ptr<Service::IEvent> GetServiceEventListener(
+      const std::string& name);
 
   std::shared_ptr<Service> FindFromThisThread();
 
@@ -54,6 +59,8 @@ class ServiceManager {
   ~ServiceManager();
 
  private:
+  std::unordered_map<std::string, std::shared_ptr<Service::IEvent>>
+      service_listeners_;
   std::unordered_map<std::string, std::shared_ptr<Service>> services_;
   std::unordered_map<std::shared_ptr<Service>, std::vector<IEvent*>> listeners_;
 };
index d066f5518d84b73aeb2e510564b2022507126c80..055ca78925080ebd1c6153038dcc0eb50717daf6 100644 (file)
 
 namespace {
 
-class ServiceExt : public tizen_base::Service {
+class ServiceEvent : public tizen_base::Service::IEvent {
  public:
-  ServiceExt(std::string name) : tizen_base::Service(std::move(name)) {}
+  ServiceEvent(service_lifecycle_callback_s* callback, void* user_data)
+      : callback_(*callback), user_data_(user_data) {}
 
-  virtual ~ServiceExt() {}
-
-  void SetCallback(service_lifecycle_callback_s* callback, void* user_data) {
-    callback_ = *callback;
-    user_data_ = user_data;
-  }
+  virtual ~ServiceEvent() {}
 
  private:
-  void OnCreate() override {
-    tizen_base::Service::OnCreate();
-    if (callback_.create) callback_.create(user_data_);
+  void OnCreate(const tizen_base::Service* service) override {
+    if (callback_.create) {
+      auto* handle =
+          static_cast<service_h>(const_cast<tizen_base::Service*>(service));
+      callback_.create(handle, user_data_);
+    }
   }
 
-  void OnDestroy() override {
-    tizen_base::Service::OnDestroy();
-    if (callback_.destroy) callback_.destroy(user_data_);
+  void OnDestroy(const tizen_base::Service* service) override {
+    if (callback_.destroy) {
+      auto* handle =
+          static_cast<service_h>(const_cast<tizen_base::Service*>(service));
+      callback_.destroy(handle, user_data_);
+    }
   }
 
-  void OnMessageReceived(const std::string& sender,
+  void OnMessageReceived(const tizen_base::Service* service,
+                         const std::string& sender,
                          const tizen_base::Bundle& envelope) override {
-    tizen_base::Service::OnMessageReceived(sender, envelope);
     if (callback_.message) {
-      callback_.message(sender.c_str(), envelope.GetHandle(), user_data_);
+      auto* handle =
+          static_cast<service_h>(const_cast<tizen_base::Service*>(service));
+      callback_.message(handle, sender.c_str(), envelope.GetHandle(),
+                        user_data_);
     }
   }
 
  private:
-  service_lifecycle_callback_s callback_ = { nullptr, };
+  service_lifecycle_callback_s callback_;
   void* user_data_ = nullptr;
 };
 
@@ -92,21 +97,21 @@ class EventHandler : public tizen_base::ServiceManager::IEvent {
 
 }  // namespace
 
-API int service_create(const char* name, service_lifecycle_callback_s* callback,
-                       void* user_data, service_h* service) {
-  if (!name || !callback || !service) {
+API int service_register(const char* name,
+                         service_lifecycle_callback_s* callback,
+                         void* user_data) {
+  if (!name || !callback || !callback->create) {
     _E("Invalid parameter");
     return SERVICE_ERROR_INVALID_PARAMETER;
   }
 
   auto& inst = tizen_base::ServiceManager::GetInst();
-  if (inst.Contains(name)) return SERVICE_ERROR_ALREADY_EXIST;
+  auto listener = inst.GetServiceEventListener(name);
+  if (listener != nullptr) return SERVICE_ERROR_ALREADY_EXIST;
 
   try {
-    auto handle = std::make_shared<ServiceExt>(name);
-    handle->SetCallback(callback, user_data);
-    *service = reinterpret_cast<service_h>(handle.get());
-    inst.Insert(name, std::move(handle));
+    auto handle = std::make_shared<ServiceEvent>(callback, user_data);
+    inst.RegisterServiceEventListener(name, std::move(handle));
   } catch (const std::bad_alloc&) {
     _E("Out of memory");
     return SERVICE_ERROR_OUT_OF_MEMORY;
@@ -118,20 +123,13 @@ API int service_create(const char* name, service_lifecycle_callback_s* callback,
   return SERVICE_ERROR_NONE;
 }
 
-API int service_run(service_h service) {
-  if (!service) {
+API int service_unregister(const char* name) {
+  if (!name) {
     _E("Invalid parameter");
     return SERVICE_ERROR_INVALID_PARAMETER;
   }
 
-  auto* handle = reinterpret_cast<ServiceExt*>(service);
-  try {
-    handle->Run();
-  } catch (const std::runtime_error&) {
-    _E("Failed to run service");
-    return SERVICE_ERROR_INVALID_CONTEXT;
-  }
-
+  tizen_base::ServiceManager::GetInst().UnregisterServiceEventListener(name);
   return SERVICE_ERROR_NONE;
 }
 
@@ -141,7 +139,7 @@ API int service_quit(service_h service) {
     return SERVICE_ERROR_INVALID_PARAMETER;
   }
 
-  auto* handle = reinterpret_cast<ServiceExt*>(service);
+  auto* handle = reinterpret_cast<tizen_base::Service*>(service);
   handle->Quit();
   return SERVICE_ERROR_NONE;
 }
@@ -152,7 +150,7 @@ API int service_send_message(service_h service, bundle* envelope) {
     return SERVICE_ERROR_INVALID_PARAMETER;
   }
 
-  auto* handle = reinterpret_cast<ServiceExt*>(service);
+  auto* handle = reinterpret_cast<tizen_base::Service*>(service);
   try {
     handle->SendMessage(tizen_base::Bundle(envelope));
   } catch (const std::runtime_error&) {
@@ -163,24 +161,13 @@ API int service_send_message(service_h service, bundle* envelope) {
   return SERVICE_ERROR_NONE;
 }
 
-API int service_destroy(service_h service) {
-  if (!service) {
-    _E("Invalid parameter");
-    return SERVICE_ERROR_INVALID_PARAMETER;
-  }
-
-  auto* handle = reinterpret_cast<ServiceExt*>(service);
-  tizen_base::ServiceManager::GetInst().Remove(handle->GetName());
-  return SERVICE_ERROR_NONE;
-}
-
 API int service_get_name(service_h service, char** name) {
   if (!service || !name) {
     _E("Invalid parameter");
     return SERVICE_ERROR_INVALID_PARAMETER;
   }
 
-  auto* handle = reinterpret_cast<ServiceExt*>(service);
+  auto* handle = reinterpret_cast<tizen_base::Service*>(service);
   *name = strdup(handle->GetName().c_str());
   if (*name == nullptr) {
     _E("Out of memory");
@@ -196,7 +183,7 @@ int service_get_state(service_h service, service_state_e* state) {
     return SERVICE_ERROR_INVALID_PARAMETER;
   }
 
-  auto* handle = reinterpret_cast<ServiceExt*>(service);
+  auto* handle = reinterpret_cast<tizen_base::Service*>(service);
   *state = static_cast<service_state_e>(handle->GetState());
   return SERVICE_ERROR_NONE;
 }
@@ -207,7 +194,7 @@ int service_get_tizen_core(service_h service, tizen_core_h* core) {
     return SERVICE_ERROR_INVALID_PARAMETER;
   }
 
-  auto* handle = reinterpret_cast<ServiceExt*>(service);
+  auto* handle = reinterpret_cast<tizen_base::Service*>(service);
   *core = handle->GetCore();
   return SERVICE_ERROR_NONE;
 }
@@ -219,7 +206,7 @@ int service_get_tizen_core_channel_sender(service_h service,
     return SERVICE_ERROR_INVALID_PARAMETER;
   }
 
-  auto* handle = reinterpret_cast<ServiceExt*>(service);
+  auto* handle = reinterpret_cast<tizen_base::Service*>(service);
   *sender = handle->GetChannelSender();
   return SERVICE_ERROR_NONE;
 }
@@ -229,13 +216,13 @@ API int service_manager_add_event_handler(service_state_changed_cb callback,
                                       service_manager_event_h *event_handler) {
   if (!callback || !event_handler) {
     _E("Invalid parameter");
-    return SERVICE_MANAGER_ERROR_INVALID_PARAMETER;
+    return SERVICE_ERROR_INVALID_PARAMETER;
   }
 
   auto* handle = new (std::nothrow) EventHandler(callback, user_data);
   if (!handle) {
     _E("Out of memory");
-    return SERVICE_MANAGER_ERROR_OUT_OF_MEMORY;
+    return SERVICE_ERROR_OUT_OF_MEMORY;
   }
 
   auto& inst = tizen_base::ServiceManager::GetInst();
@@ -247,14 +234,14 @@ API int service_manager_add_event_handler(service_state_changed_cb callback,
 
   tizen_base::ServiceManager::GetInst().AddEventListener(service, handle);
   *event_handler = reinterpret_cast<service_manager_event_h>(handle);
-  return SERVICE_MANAGER_ERROR_NONE;
+  return SERVICE_ERROR_NONE;
 }
 
 API int service_manager_remove_event_handler(
     service_manager_event_h event_handler) {
   if (!event_handler) {
     _E("Invalid parameter");
-    return SERVICE_MANAGER_ERROR_INVALID_PARAMETER;
+    return SERVICE_ERROR_INVALID_PARAMETER;
   }
 
   auto* handle = reinterpret_cast<EventHandler*>(event_handler);
@@ -268,18 +255,18 @@ API int service_manager_remove_event_handler(
 
   inst.RemoveEventListener(service, handle);
   delete handle;
-  return SERVICE_MANAGER_ERROR_NONE;
+  return SERVICE_ERROR_NONE;
 }
 
 API int service_manager_get_service(const char* name, service_h* service) {
   if (!name || !service) {
     _E("Invalid parameter");
-    return SERVICE_MANAGER_ERROR_INVALID_PARAMETER;
+    return SERVICE_ERROR_INVALID_PARAMETER;
   }
 
   auto& inst = tizen_base::ServiceManager::GetInst();
-  if (!inst.Contains(name)) return SERVICE_MANAGER_ERROR_INVALID_PARAMETER;
+  if (!inst.Contains(name)) return SERVICE_ERROR_INVALID_PARAMETER;
 
   *service = reinterpret_cast<service_h>(inst.Get(name).get());
-  return SERVICE_MANAGER_ERROR_NONE;
+  return SERVICE_ERROR_NONE;
 }
index 1871a88700b4d7a60e1b8142db55f794d1b01284..7fed162e9991c3afac823ce099fdc0696e6fb737 100644 (file)
  * limitations under the License.
  */
 
- #include "service_loader.h"
- #include <new>
- #include <stdexcept>
- #include <utility>
- #include "log_private.hh"
- #include "service_loader.hh"
- #undef EXPORT
- #define EXPORT __attribute__((visibility("default")))
- #undef API
- #define API extern "C" EXPORT
+#include "service_loader.h"
+
+#include <new>
+#include <stdexcept>
+#include <utility>
+
+#include "exception.hh"
+#include "log_private.hh"
+#include "service_loader.hh"
+
+#undef EXPORT
+#define EXPORT __attribute__((visibility("default")))
+
+#undef API
+#define API extern "C" EXPORT
 
 namespace {
 
@@ -78,12 +79,12 @@ API int service_loader_run(int argc, char** argv, const char* name,
                            void* user_data) {
   if (argc < 1 || argv == nullptr || name == nullptr || callback == nullptr) {
     _E("Invalid parameter");
-    return SERVICE_LOADER_ERROR_INVALID_PARAMETER;
+    return SERVICE_ERROR_INVALID_PARAMETER;
   }
 
   if (::context != nullptr) {
     _E("Already running");
-    return SERVICE_LOADER_ERROR_ALREADY_RUNNING;
+    return SERVICE_ERROR_ALREADY_RUNNING;
   }
 
   try {
@@ -92,30 +93,132 @@ API int service_loader_run(int argc, char** argv, const char* name,
     loader.Run();
   } catch (const std::runtime_error& e) {
     _E("Exception occurs. error: %s", e.what());
-    return SERVICE_LOADER_ERROR_INVALID_CONTEXT;
+    return SERVICE_ERROR_INVALID_CONTEXT;
   }
 
-  return SERVICE_LOADER_ERROR_NONE;
+  return SERVICE_ERROR_NONE;
 }
 
 API void service_loader_quit(void) {
   if (!::context) {
-    set_last_result(SERVICE_LOADER_ERROR_INVALID_CONTEXT);
+    set_last_result(SERVICE_ERROR_INVALID_CONTEXT);
     return;
   }
 
   ::context->Quit();
-  set_last_result(SERVICE_LOADER_ERROR_NONE);
+  set_last_result(SERVICE_ERROR_NONE);
 }
 
 API int service_loader_send_message(bundle* envelope) {
   if (!envelope) {
     _E("Invalid parameter");
-    return SERVICE_LOADER_ERROR_INVALID_PARAMETER;
+    return SERVICE_ERROR_INVALID_PARAMETER;
   }
 
-  if (!::context) return SERVICE_LOADER_ERROR_INVALID_CONTEXT;
+  if (!::context) return SERVICE_ERROR_INVALID_CONTEXT;
 
   ::context->SendMessage(tizen_base::Bundle(envelope));
-  return SERVICE_LOADER_ERROR_NONE;
+  return SERVICE_ERROR_NONE;
+}
+
+API int service_loader_run_service(const char *name) {
+  if (!name) {
+    _E("Invalid parameter");
+    return SERVICE_ERROR_INVALID_PARAMETER;
+  }
+
+  if (!::context) {
+    _E("Invalid context");
+    return SERVICE_ERROR_INVALID_CONTEXT;
+  }
+
+  try {
+    ::context->RunService(name);
+  } catch (const tizen_base::Exception& e) {
+    _E("Exception occurs. error: %s", e.what());
+    return e.GetErrorCode();
+  }
+
+  return SERVICE_ERROR_NONE;
+}
+
+API int service_loader_run_all_services(void) {
+  if (!::context) {
+    _E("Invalid context");
+    return SERVICE_ERROR_INVALID_CONTEXT;
+  }
+
+  ::context->RunAllServices();
+  return SERVICE_ERROR_NONE;
+}
+
+API int service_loader_quit_service(const char *name) {
+  if (!name) {
+    _E("Invalid parameter");
+    return SERVICE_ERROR_INVALID_PARAMETER;
+  }
+
+  if (!::context) {
+    _E("Invalid context");
+    return SERVICE_ERROR_INVALID_CONTEXT;
+  }
+
+  try {
+    ::context->QuitService(name);
+  } catch (const tizen_base::Exception& e) {
+    _E("Exception occurs. error: %s", e.what());
+    return e.GetErrorCode();
+  }
+
+  return SERVICE_ERROR_NONE;
+}
+
+API int service_loader_quit_all_services(void) {
+  if (!::context) {
+    _E("Invalid context");
+    return SERVICE_ERROR_INVALID_CONTEXT;
+  }
+
+  ::context->QuitAllServices();
+  return SERVICE_ERROR_NONE;
+}
+
+API int service_loader_load_service(const char *name) {
+  if (!name) {
+    _E("Invalid parameter");
+    return SERVICE_ERROR_INVALID_PARAMETER;
+  }
+
+  if (!::context) {
+    _E("Invalid context");
+    return SERVICE_ERROR_INVALID_CONTEXT;
+  }
+
+  try {
+    ::context->LoadService(name);
+  } catch (const tizen_base::Exception& e) {
+    _E("Exception occurs. error: %s", e.what());
+    return e.GetErrorCode();
+  }
+  return SERVICE_ERROR_NONE;
+}
+
+API int service_loader_unload_service(const char* name) {
+  if (!name) {
+    _E("Invalid parameter");
+    return SERVICE_ERROR_INVALID_PARAMETER;
+  }
+
+  if (!::context) {
+    _E("Invalid context");
+    return SERVICE_ERROR_INVALID_CONTEXT;
+  }
+
+  try {
+    ::context->UnloadService(name);
+  } catch (const tizen_base::Exception& e) {
+    _E("Exception occurs. error: %s", e.what());
+    return e.GetErrorCode();
+  }
+  return SERVICE_ERROR_NONE;
 }