Merge branch 'master' of https://github.sec.samsung.net/appfw/united-service into...
authorSukhyungKang <shine.kang@samsung.com>
Thu, 10 Apr 2025 22:50:09 +0000 (07:50 +0900)
committerSukhyungKang <shine.kang@samsung.com>
Tue, 15 Apr 2025 04:28:44 +0000 (13:28 +0900)
1  2 
include/service.h
src/service.cc
src/service.hh
src/service_info.cc
src/service_info.hh
src/service_loader.cc
src/service_loader.hh
src/stub_service_loader.cc

index 24158005a468c06f7e3fc2b35ea67729c03e6da8,050bea7ef2994c384e618a01339419908ae04c32..868cfa05790e2be2846125e8c2638f1224675f5c
@@@ -26,27 -27,15 +27,14 @@@ 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.
@@@ -185,10 -158,7 +157,6 @@@ int service_register(const char *name, 
   *         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>
@@@ -208,15 -174,20 +172,20 @@@ 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) {
++extern "C" void UNITED_SERVICE_SHUTDOWN(const char* name) {
+   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.
   * @retval #SERVICE_ERROR_NONE Successful
   * @retval #SERVICE_ERROR_INVALID_PARAMETER Invalid parameter
   * @retval #SERVICE_ERROR_INVALID_CONTEXT Invalid context
-- * @see service_create()
   * @see service_run()
   * @see service_destroy_cb()
   *
@@@ -386,7 -317,7 +314,6 @@@ int service_send_message(service_h serv
   * @retval #SERVICE_ERROR_NONE Successful
   * @retval #SERVICE_ERROR_INVALID_PARAMETER Invalid parameter
   * @retval #SERVICE_ERROR_OUT_OF_MEMORY Out of memory
-- * @see service_create()
   *
   * @code
  #include <service.h>
diff --cc src/service.cc
index 21ffa56147b44ec64b0855aee9573c2e6261f0f4,1dade7f114dbb32d7e59e2f5c446683f961093a8..092999a6c4832bce0459efb81387260e9efcfc0a
@@@ -189,8 -217,25 +217,29 @@@ void Service::ChannelReceiveCb(tizen_co
    const char* task_name = nullptr;
    tizen_core_channel_object_get_sender_task_name(object, &task_name);
    auto* service = static_cast<Service*>(user_data);
-   service->OnMessageReceived(task_name != nullptr ? task_name : "",
-                              tizen_base::Bundle(data, false, true));
+   service->OnBaseMessageReceived(task_name != nullptr ? task_name : "",
+                                  tizen_base::Bundle(data, false, true));
+ }
+ void Service::SetStateChangedCb(StateChangedCb cb) {
+   state_changed_cb_ = std::move(cb);
+ }
+ void Service::NotifyStateChanged() {
+   auto* args = new ServiceStateChangedEventArgs(this, state_);
+   g_idle_add(
+       [](gpointer user_data) {
+         auto* args = static_cast<ServiceStateChangedEventArgs*>(user_data);
+         auto& cb = args->GetService()->state_changed_cb_;
++
++        int state = static_cast<int>(args->GetService()->GetState());
++        _E("NotifyStateChanged : %d", state);
++
+         if (cb != nullptr) cb(args->GetService(), args->GetState());
+         delete args;
+         return G_SOURCE_REMOVE;
+       },
+       args);
  }
  
  } // namespace tizen_base
diff --cc src/service.hh
index d1a15c9e66157a51e1077daef105e967fd7f6b55,b06288ecb567d80f4dae6066ecdb3ff5d4277b2a..eb79e0e4c992a132f5ef2074d3a968e8c48e4942
  #include <tizen_core.h>
  #include <tizen_core_channel.h>
  
- #include <condition_variable>
- #include <memory>
- #include <mutex>
+ #include <atomic>
 -#include <condition_variable>
+ #include <functional>
 -#include <mutex>
  #include <string>
  
+ #include "service_info.hh"
  namespace tizen_base {
  
  class Service : public std::enable_shared_from_this<Service> {
index abd9108c31508e8d152db9d2e686e5323831a0db,3287b5096865c3fafdcfbaf0b1c7c759c9f7164e..e38e9c2b7a31979c1f4b29667615bd9d950bec88
@@@ -48,17 -46,7 +48,21 @@@ ServiceInfo::ServiceInfo(std::string co
    _D("Type=%s", type_.c_str());
    path_ = dictionary->Get(kPath);
    _D("Path=%s", path_.c_str());
-     if (priority_ < 1 || priority_ > 99)
 +
+   assembly_ = std::make_shared<ServiceAssembly>(path_);
++
 +  try {
 +    priority_ = stoul(dictionary->Get(kPriority));
 +    _D("Priority=%d", priority_);
 +
++    if (priority_ < 1 || priority_ > 99) {
++      _E("Invalid priority");
 +      priority_ = 0;
++    }
 +  } catch (const Exception& e) {
 +    _E("Failed to get priority : %s", e.what());
 +    priority_ = 0;
 +  }
  }
  
  ServiceInfo::~ServiceInfo() {}
@@@ -75,6 -63,8 +79,10 @@@ const std::string& ServiceInfo::GetType
  
  const std::string& ServiceInfo::GetPath() const { return path_; }
  
 +const unsigned int ServiceInfo::GetPriority() const { return priority_; }
 +
+ std::shared_ptr<ServiceAssembly> ServiceInfo::GetAssembly() const {
+   return assembly_;
+ }
  }  // namespace tizen_base
index d91225405768790b37f545e700fc9876fc1e5524,6ce08b53e2d4d22e5ff2768414ad5a5726b5293c..66b74f51ec7f68aaff531f959593abe428e86072
@@@ -35,7 -36,7 +36,8 @@@ class ServiceInfo 
    const std::string& GetMode() const;
    const std::string& GetType() const;
    const std::string& GetPath() const;
 +  const unsigned int GetPriority() const;
+   std::shared_ptr<ServiceAssembly> GetAssembly() const;
  
   private:
    std::string conf_name_;
@@@ -44,7 -45,7 +46,8 @@@
    std::string mode_;
    std::string type_;
    std::string path_;
 +  unsigned int priority_;
+   std::shared_ptr<ServiceAssembly> assembly_;
  };
  
  }  // namespace tizen_base
index 86a64e4dea51aafa1f2986c853449ec057f91095,a361766b0f34fcbec528fbd5a90759224f9807b3..ec27f14d8a93f75bd42980e2564f6f5e417b6f8c
mode 100644,100644..100755
@@@ -32,31 -32,6 +32,25 @@@ namespace 
  constexpr const char kPathUnitedService[] = "/usr/share/united-service/";
  constexpr const char kConf[] = "/conf/";
  
- bool compare_context(const std::shared_ptr<tizen_base::ServiceContext>& context1,
-     const std::shared_ptr<tizen_base::ServiceContext>& context2) {
-   return context1->GetPriority() > context2->GetPriority();
++bool compare_priority(const std::pair<std::string, unsigned int>& pair1,
++    const std::pair<std::string, unsigned int>& pair2) {
++  return pair1.second > pair2.second;
 +}
 +
- void PrintState(const std::shared_ptr<tizen_base::ServiceContext>& context) {
-   switch(context->GetService()->GetState()) {
++std::string GetServiceState(tizen_base::Service::State state) {
++  switch(state) {
 +    case tizen_base::Service::State::Initialized:
-       _W("%s : state Initialized", context->GetService()->GetName().c_str());
-       break;
++      return std::string("Initialized");
 +    case tizen_base::Service::State::Created:
-       _W("%s : state Created", context->GetService()->GetName().c_str());
-         break;
++      return std::string("Created");
 +    case tizen_base::Service::State::Running:
-       _W("%s : state Running", context->GetService()->GetName().c_str());
-         break;
++      return std::string("Running");
 +    case tizen_base::Service::State::Destroyed:
-       _W("%s : state Destroyed", context->GetService()->GetName().c_str());
-         break;
-     default:
-       _W("invalid state");
-       break;
++      return std::string("Destroyed");
 +  }
++  return "";
 +}
 +
  }  // namespace
  
  namespace tizen_base {
@@@ -134,55 -109,23 +128,28 @@@ 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));
++        
++        orders_.push_back(std::make_pair(info->GetName(), info->GetPriority()));
+         infos_[info->GetName()] = std::move(info);
        }
      }
    }
  
-   if (!contexts_.empty())
-     std::sort(contexts_.begin(), contexts_.end(), compare_context);
- }
- void ServiceLoader::RunServices() {
-   unsigned int previous_priority = 0;
-   std::shared_ptr<ServiceContext> previous_service = nullptr;
-   for (auto& context : contexts_) {
-     if (context->GetServiceInfo()->GetMode().compare("on-demand") == 0) {
-       _W("%s is on-demand mode. it's skipped to run", context->GetName().c_str());
-       continue;
-     }
-     if (previous_priority == 0)
-       previous_priority = context->GetPriority();
-     if (previous_priority == context->GetPriority()) {
-       _E("@@ Priority : %d, pre-priority : %d,  name : %s", context->GetPriority(), previous_priority, context->GetName().c_str());
-       context->Run();
-       PrintState(context);
-       previous_service = context;
-     } else {
-       _E("@@ Priority : %d, pre-priority : %d,  name : %s", context->GetPriority(), previous_priority, context->GetName().c_str());
-       previous_service->GetService()->WaitRun();
-       _E("@@ Previous state");
-       PrintState(previous_service);
-       context->Run();
-       _E("@@ Current state");
-       PrintState(context);
-       previous_service = context;
-       previous_priority = context->GetPriority();
+   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());
      }
    }
-   // throw new std::runtime_error("Failed to Run service");
 +
++  if (!orders_.empty())
++    std::sort(orders_.begin(), orders_.end(), compare_priority);
  }
  
  int ServiceLoader::Run() {
@@@ -210,7 -153,98 +177,110 @@@ void ServiceLoader::SendMessage(const t
    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().Get(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->SetStateChangedCb(std::bind(&ServiceLoader::ServiceStateChangedCb,
+                                        this, std::placeholders::_1,
+                                        std::placeholders::_2));
+   services_[name] = service;
+   service->Run();
+ }
+ void ServiceLoader::RunAllServices() {
 -  for (auto& [name, _] : infos_) {
++  for (auto& order : orders_) {
+     try {
 -      RunService(name);
++      _E("Run service : %s, priority : %d", order.first.c_str(), order.second);
++
++      auto info = GetServiceInfo(order.first);
++      if (info->GetMode() == "on-demand") {
++        _E("%s is on-demand mode. skip to run", order.first.c_str());
++        continue;
++      }
++
++      RunService(order.first);
++
++      auto service = GetService(order.first);
++
++      _E("[%s] service state is %s", order.first.c_str(), GetServiceState(service->GetState()).c_str());
+     } 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(name.c_str());
+     assembly->Unload();
+   } catch (const Exception& e) {
+     _E("Error=%s", e.what());
    }
  }
  
@@@ -246,4 -281,27 +317,29 @@@ void ServiceLoader::ChannelReceiveCb(ti
                               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;
+ }
+ void ServiceLoader::ServiceStateChangedCb(const Service* service,
+                                           Service::State state) {
++  _W("ServiceStateChangedCb %s, state : %s", service->GetName().c_str(), GetServiceState(state).c_str());
++
+   OnServiceStateChanged(service, state);
+   if (state == Service::State::Destroyed) {
+     services_.erase(service->GetName());
+   }
+ }
  } // namespace tizen_base
index 4dab542c62b14ace26e9eee4db1098841d2e314b,12a74223d84d99dacd41b20978dceeb1d36a0ef9..78c144528368fa98e1f84acf032820ad4b1eba97
  
  #include <memory>
  #include <string>
+ #include <unordered_map>
++#include <algorithm>
  
  #include "service.hh"
- #include "service_context.hh"
  #include "service_info.hh"
  
  namespace tizen_base {
@@@ -58,7 -73,8 +74,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_;
++
++  std::vector<std::pair<std::string, unsigned int>> orders_;
  };
  
  } // namespace tizen_base
index 1871a88700b4d7a60e1b8142db55f794d1b01284,0539d96f4b7d176aec5c52d25d1c3b837627d4e9..5e29a55a18d1b67af4d04ec781449cc0ff19be97
@@@ -87,15 -91,15 +91,15 @@@ API int service_loader_run(int argc, ch
    }
  
    try {
--    ::ServiceLoaderExt loader(argc, argv, name);
--    loader.SetCallback(callback, user_data);
--    loader.Run();
++    ::context = new ::ServiceLoaderExt(argc, argv, name);
++    ::context->SetCallback(callback, user_data);
++    ::context->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) {