Implement dbus ondemaind launch
authorChanggyu Choi <changyu.choi@samsung.com>
Thu, 10 Apr 2025 01:16:43 +0000 (10:16 +0900)
committerChanggyu Choi <changyu.choi@samsung.com>
Wed, 14 May 2025 09:02:19 +0000 (18:02 +0900)
Signed-off-by: Changgyu Choi <changyu.choi@samsung.com>
27 files changed:
CMakeLists.txt
include/service.h
packaging/united-service.spec
src/CMakeLists.txt
src/activation_method/dbus_info.cc [new file with mode: 0644]
src/activation_method/dbus_info.hh [new file with mode: 0644]
src/activation_method/dbus_monitor.cc [new file with mode: 0644]
src/activation_method/dbus_monitor.hh [new file with mode: 0644]
src/activation_method/fd_monitor.cc [new file with mode: 0644]
src/activation_method/fd_monitor.hh [new file with mode: 0644]
src/activation_method/file_info.cc [new file with mode: 0644]
src/activation_method/file_info.hh [new file with mode: 0644]
src/activation_method/file_monitor.cc [new file with mode: 0644]
src/activation_method/file_monitor.hh [new file with mode: 0644]
src/activation_method/socket_info.cc [new file with mode: 0644]
src/activation_method/socket_info.hh [new file with mode: 0644]
src/activation_method/vconf_info.hh [new file with mode: 0644]
src/activation_method/vconf_monitor.hh [new file with mode: 0644]
src/event_listener.hh [new file with mode: 0644]
src/service.cc
src/service.hh
src/service_assembly.hh
src/service_context.cc [new file with mode: 0644]
src/service_info.cc
src/service_info.hh
src/service_loader.cc
src/service_loader.hh

index 80c510b8e8b6094e0cf5a31d99db57c42b99809f..9594845fb401e4762e4da73238c5525e5a4537ee 100644 (file)
@@ -32,6 +32,7 @@ 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)
 PKG_CHECK_MODULES(AUL_DEPS REQUIRED aul)
+PKG_CHECK_MODULES(LIBSYSTEMD_DEPS REQUIRED libsystemd)
 
 ADD_SUBDIRECTORY(src)
 
index 0971c192e6db6cc68a18fa9ce86f9271ee4a5ed3..027eb0a5c2d685ffa4bd5eafee13891a4d4e2ecb 100644 (file)
@@ -101,7 +101,7 @@ typedef struct {
  * @retval #SERVICE_ERROR_ALREADY_EXIST Service already exists
  * @see service_unregister()
  * @see #service_lifecycle_callback_s
- * 
+ *
  * @code
 #include <service.h>
 #include <dlog.h>
index 72d0f79dbddae6b490636a26eda78d8795f14018..5c135912f06dace5a0f1e6c6c269c62bb42f1023 100644 (file)
@@ -15,6 +15,7 @@ BuildRequires:  pkgconfig(tizen-libopener)
 BuildRequires:  pkgconfig(glib-2.0)
 BuildRequires:  pkgconfig(iniparser)
 BuildRequires:  pkgconfig(aul)
+BuildRequires:  pkgconfig(libsystemd)
 
 Requires(post): /sbin/ldconfig
 Requires(postun): /sbin/ldconfig
index b27f00b06d6301e0e481e0f2bc2e303cbc31729e..b8a263e296cee2d62a6329e0a29af27f7d777cd2 100644 (file)
@@ -1,7 +1,8 @@
 AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} SRCS)
 AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/watchdog WATCHDOG_SRCS)
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/activation_method ACTIVATION_METHOD_SRCS)
 
-ADD_LIBRARY(${TARGET_UNITED_SERVICE} SHARED ${SRCS} ${WATCHDOG_SRCS})
+ADD_LIBRARY(${TARGET_UNITED_SERVICE} SHARED ${SRCS} ${WATCHDOG_SRCS} ${ACTIVATION_METHOD_SRCS})
 
 SET_TARGET_PROPERTIES(${TARGET_UNITED_SERVICE} PROPERTIES SOVERSION ${MAJORVER})
 SET_TARGET_PROPERTIES(${TARGET_UNITED_SERVICE} PROPERTIES VERSION ${FULLVER})
@@ -10,6 +11,7 @@ TARGET_INCLUDE_DIRECTORIES(${TARGET_UNITED_SERVICE} PUBLIC
   ${CMAKE_CURRENT_SOURCE_DIR}
   ${CMAKE_CURRENT_SOURCE_DIR}/../
   ${CMAKE_CURRENT_SOURCE_DIR}/../include/
+  ${CMAKE_CURRENT_SOURCE_DIR}/activation_method/
 )
 
 APPLY_PKG_CONFIG(${TARGET_UNITED_SERVICE} PUBLIC
@@ -20,6 +22,7 @@ APPLY_PKG_CONFIG(${TARGET_UNITED_SERVICE} PUBLIC
   TIZEN_LIBOPENER_DEPS
   INIPARSER_DEPS
   AUL_DEPS
+  LIBSYSTEMD_DEPS
 )
 
 TARGET_LINK_LIBRARIES(${TARGET_UNITED_SERVICE} PUBLIC "-lpthread -ldl")
diff --git a/src/activation_method/dbus_info.cc b/src/activation_method/dbus_info.cc
new file mode 100644 (file)
index 0000000..6371b11
--- /dev/null
@@ -0,0 +1,14 @@
+#include "dbus_info.hh"
+
+#include <utility>
+
+namespace tizen_base {
+
+tizen_base::DBusInfo::DBusInfo(std::string bus_name)
+    : bus_name_(std::move(bus_name)) {}
+
+const std::string& DBusInfo::GetBusName() const {
+  return bus_name_;
+}
+
+}  // namespace tizen_base
diff --git a/src/activation_method/dbus_info.hh b/src/activation_method/dbus_info.hh
new file mode 100644 (file)
index 0000000..9b89738
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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 ACTIVATION_METHOD_DBUS_INFO_HH_
+#define ACTIVATION_METHOD_DBUS_INFO_HH_
+
+#include <string>
+
+namespace tizen_base {
+
+class DBusInfo {
+ public:
+  explicit DBusInfo(std::string bus_name);
+
+  const std::string& GetBusName() const;
+ private:
+  std::string bus_name_;
+};
+
+}  // namespace tizen_base
+
+#endif  // ACTIVATION_METHOD_DBUS_INFO_HH_
diff --git a/src/activation_method/dbus_monitor.cc b/src/activation_method/dbus_monitor.cc
new file mode 100644 (file)
index 0000000..afe94e4
--- /dev/null
@@ -0,0 +1,65 @@
+#include "dbus_monitor.hh"
+
+#include <stdexcept>
+#include <utility>
+
+#include "log_private.hh"
+
+namespace tizen_base {
+
+DBusMonitor::DBusMonitor(std::string name,
+                         std::string bus_name,
+                         IEventListener* listener)
+    : name_(std::move(name)),
+      bus_name_(std::move(bus_name)),
+      listener_(listener) {
+  static GDBusConnection* conn = nullptr;
+  GError* error = nullptr;
+  if (!conn)
+    conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
+
+  if (conn == nullptr) {
+    if (error != nullptr) {
+      _E("Failed to get dbus [%s]", error->message);
+      g_error_free(error);
+    }
+
+    throw std::runtime_error("Failed to get dbus connection");
+  }
+
+  own_id_ = g_bus_own_name(G_BUS_TYPE_SYSTEM, bus_name_.c_str(),
+                             G_BUS_NAME_OWNER_FLAGS_NONE, BusAcquiredCb,
+                             NameAppearedCb, NameVanishedCb, this, nullptr);
+  if (own_id_ == 0)
+    throw std::runtime_error("Fail to watch name " + bus_name_);
+}
+
+DBusMonitor::~DBusMonitor() {
+  if (own_id_) {
+    g_bus_unown_name(own_id_);
+  }
+}
+
+void DBusMonitor::BusAcquiredCb(GDBusConnection* connection,
+                                const gchar* name,
+                                gpointer user_data) {
+  _I("bus acquired : %s", name);
+}
+
+void DBusMonitor::NameAppearedCb(GDBusConnection* connection,
+                                 const gchar* name,
+                                 gpointer user_data) {
+  _I("name appeared : %s", name);
+  auto* self = static_cast<DBusMonitor*>(user_data);
+  if (self->bus_name_ == name) {
+    self->listener_->OnEvent(self->name_);
+  }
+}
+
+void DBusMonitor::NameVanishedCb(GDBusConnection* connection,
+                                 const gchar* name,
+                                 gpointer user_data) {
+  _E("name vanished : %s", name);
+}
+
+}  // namespace tizen_base
diff --git a/src/activation_method/dbus_monitor.hh b/src/activation_method/dbus_monitor.hh
new file mode 100644 (file)
index 0000000..35d02b1
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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 ACTIVATION_METHOD_DBUS_MONITOR_HH_
+#define ACTIVATION_METHOD_DBUS_MONITOR_HH_
+
+#include <gio/gio.h>
+#include <glib.h>
+
+#include <string>
+
+#include "event_listener.hh"
+
+namespace tizen_base {
+
+class DBusMonitor {
+ public:
+  DBusMonitor(std::string name, std::string bus_name, IEventListener* listener);
+  ~DBusMonitor();
+
+  static void BusAcquiredCb(GDBusConnection* connection,
+                            const gchar* name,
+                            gpointer user_data);
+
+  static void NameAppearedCb(GDBusConnection* connection,
+                             const gchar* name,
+                             gpointer user_data);
+  static void NameVanishedCb(GDBusConnection* connection,
+                             const gchar* name,
+                             gpointer user_data);
+
+ private:
+  std::string name_;
+  std::string bus_name_;
+  gint own_id_ = 0;
+  IEventListener* listener_;
+};
+
+};  // namespace tizen_base
+
+#endif  // ACTIVATION_METHOD_DBUS_MONITOR_HH_
diff --git a/src/activation_method/fd_monitor.cc b/src/activation_method/fd_monitor.cc
new file mode 100644 (file)
index 0000000..e93b192
--- /dev/null
@@ -0,0 +1,16 @@
+#include "fd_monitor.hh"
+
+tizen_base::FdMonitor::FdMonitor(std::string,
+                                 int fd,
+                                 IEventListener* listener) {}
+
+tizen_base::FdMonitor::FdMonitor(std::string name,
+                                 std::string path,
+                                 IEventListener* listener) {}
+
+gboolean tizen_base::FdMonitor::UnixFdSourceFunc(gint fd,
+                                                 GIOCondition cond,
+                                                 gpointer data) {
+  // TODO
+  return FALSE;
+}
diff --git a/src/activation_method/fd_monitor.hh b/src/activation_method/fd_monitor.hh
new file mode 100644 (file)
index 0000000..78da363
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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 ACTIVATION_METHOD_FD_MONITOR_HH_
+#define ACTIVATION_METHOD_FD_MONITOR_HH_
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <string>
+
+#include "event_listener.hh"
+
+namespace tizen_base {
+
+class FdMonitor {
+ public:
+  FdMonitor(std::string, int fd, IEventListener* listener);
+  FdMonitor(std::string name, std::string path, IEventListener* listener);
+
+  static gboolean UnixFdSourceFunc(gint fd, GIOCondition cond, gpointer data);
+};
+
+};
+
+ #endif  // ACTIVATION_METHOD_FD_MONITOR_HH_
diff --git a/src/activation_method/file_info.cc b/src/activation_method/file_info.cc
new file mode 100644 (file)
index 0000000..3c97927
--- /dev/null
@@ -0,0 +1,18 @@
+#include "file_info.hh"
+
+#include <utility>
+
+namespace tizen_base {
+
+FileInfo::FileInfo(std::string path, FileMode mode)
+    : path_(std::move(path)), mode_(mode) {}
+
+const std::string& FileInfo::GetPath() const {
+  return path_;
+}
+
+FileMode FileInfo::GetMode() const {
+  return mode_;
+}
+
+}  // namespace tizen_base
diff --git a/src/activation_method/file_info.hh b/src/activation_method/file_info.hh
new file mode 100644 (file)
index 0000000..5a9fe7a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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 ACTIVATION_METHOD_FILE_INFO_HH_
+#define ACTIVATION_METHOD_FILE_INFO_HH_
+
+#include <string>
+
+namespace tizen_base {
+
+enum FileMode {
+// TODO
+};
+
+class FileInfo {
+ public:
+  FileInfo(std::string path, FileMode mode);
+  const std::string& GetPath() const;
+  FileMode GetMode() const;
+
+ private:
+  std::string path_;
+  FileMode mode_;
+};
+
+}  // namespace tizen_base
+
+#endif  // ACTIVATION_METHOD_FILE_INFO_HH_
diff --git a/src/activation_method/file_monitor.cc b/src/activation_method/file_monitor.cc
new file mode 100644 (file)
index 0000000..82656e0
--- /dev/null
@@ -0,0 +1,12 @@
+#include "file_monitor.hh"
+
+tizen_base::FileMonitor::FileMonitor(std::string name,
+                                     std::string path,
+                                     IEventListener* listener) {}
+
+gboolean tizen_base::FileMonitor::UnixFdSourceFunc(gint fd,
+                                                   GIOCondition cond,
+                                                   gpointer data) {
+  // TODO
+  return FALSE;
+}
diff --git a/src/activation_method/file_monitor.hh b/src/activation_method/file_monitor.hh
new file mode 100644 (file)
index 0000000..797c118
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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 ACTIVATION_METHOD_FILE_MONITOR_HH_
+#define ACTIVATION_METHOD_FILE_MONITOR_HH_
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <string>
+
+#include "event_listener.hh"
+
+namespace tizen_base {
+
+class FileMonitor {
+ public:
+  FileMonitor(std::string name, std::string path, IEventListener* listener);
+
+  static gboolean UnixFdSourceFunc(gint fd, GIOCondition cond, gpointer data);
+};
+
+};
+
+#endif  // ACTIVATION_METHOD_FILE_MONITOR_HH_
diff --git a/src/activation_method/socket_info.cc b/src/activation_method/socket_info.cc
new file mode 100644 (file)
index 0000000..54b3de8
--- /dev/null
@@ -0,0 +1,18 @@
+#include "socket_info.hh"
+
+#include <utility>
+
+namespace tizen_base {
+
+SocketInfo::SocketInfo(std::string path, int mode)
+    : path_(std::move(path)), mode_(mode) {}
+
+const std::string& SocketInfo::GetPath() const {
+  return path_;
+}
+
+int SocketInfo::GetMode() const {
+  return mode_;
+}
+
+}  // namespace tizen_base
diff --git a/src/activation_method/socket_info.hh b/src/activation_method/socket_info.hh
new file mode 100644 (file)
index 0000000..3b26a69
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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 ACTIVATION_METHOD_SOCKET_INFO_HH_
+#define ACTIVATION_METHOD_SOCKET_INFO_HH_
+
+#include <string>
+
+namespace tizen_base {
+
+class SocketInfo {
+ public:
+  SocketInfo(std::string path, int mode);
+  const std::string& GetPath() const;
+  int GetMode() const;
+
+ private:
+  std::string path_;
+  int mode_;
+};
+
+}  // namespace tizen_base
+
+#endif  // ACTIVATION_METHOD_SOCKET_INFO_HH_
diff --git a/src/activation_method/vconf_info.hh b/src/activation_method/vconf_info.hh
new file mode 100644 (file)
index 0000000..6fb336f
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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 ACTIVATION_METHOD_VCONF_INFO_HH_
+#define ACTIVATION_METHOD_VCONF_INFO_HH_
+
+#include <string>
+
+namespace tizen_base {
+
+template<typename T>
+class VconfInfo {
+ public:
+  VconfInfo(std::string key, T value);
+  const std::string& GetKey() const;
+  const T& GetValue() const;
+
+ private:
+  std::string key_;
+  T value_;
+};
+
+};
+
+#endif  // ACTIVATION_METHOD_VCONF_INFO_HH_
diff --git a/src/activation_method/vconf_monitor.hh b/src/activation_method/vconf_monitor.hh
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/event_listener.hh b/src/event_listener.hh
new file mode 100644 (file)
index 0000000..1b4ed63
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#ifndef EVENT_LISTENER_HH_
+#define EVENT_LISTENER_HH_
+
+#include <string>
+
+namespace tizen_base {
+
+class IEventListener {
+ public:
+  virtual void OnEvent(const std::string& name) = 0;
+};
+
+}  // namespace tizen_base
+
+#endif  // EVENT_LISTENER_HH_
index a474bceb578670a150606ebc7a44d93f2d6942c2..a7e346f9f2785d2b2d3f8a8fdc79f3ba42967541 100644 (file)
@@ -233,6 +233,20 @@ void Service::SetStateChangedCb(StateChangedCb cb) {
   state_changed_cb_ = std::move(cb);
 }
 
+void Service::Listen(IEventListener* listener) {
+  auto type = info_->GetType();
+  if (type == "socket") {
+    const auto& socket_info = info_->GetSocketInfo();
+    fd_monitor_.reset(new FdMonitor(info_->GetName(), socket_info->GetPath(), listener));
+  } else if (type == "file") {
+    const auto& file_info = info_->GetFileInfo();
+    file_monitor_.reset(new FileMonitor(info_->GetName(), file_info->GetPath(), listener));
+  } else if (type == "dbus") {
+    const auto& dbus_info = info_->GetDbusInfo();
+    dbus_monitor_.reset(new DBusMonitor(info_->GetName(), dbus_info->GetBusName(), listener));
+  }
+}
+
 void Service::NotifyStateChanged() {
   auto* args = new ServiceStateChangedEventArgs(this, state_);
   g_idle_add(
index 45c2f3457815eac0a13ccdfd57e831663b6dc04e..037021544f12caf2f50069016553649b5b53900c 100644 (file)
 #include <functional>
 #include <string>
 
+#include "event_listener.hh"
 #include "service_info.hh"
 
+#include "activation_method/dbus_monitor.hh"
+#include "activation_method/fd_monitor.hh"
+#include "activation_method/file_monitor.hh"
+
 namespace tizen_base {
 
 class Service : public std::enable_shared_from_this<Service> {
@@ -66,6 +71,7 @@ class Service : public std::enable_shared_from_this<Service> {
   tizen_core_channel_sender_h GetChannelSender() const;
   void SendMessage(const tizen_base::Bundle& envelope);
   void SetStateChangedCb(StateChangedCb cb);
+  void Listen(IEventListener* listener);
 
  private:
   void OnBaseCreate();
@@ -92,6 +98,10 @@ class Service : public std::enable_shared_from_this<Service> {
   std::atomic<bool> running_{false};
   pid_t tid_ = -1;
   StateChangedCb state_changed_cb_ = nullptr;
+
+  std::unique_ptr<FdMonitor> fd_monitor_;
+  std::unique_ptr<FileMonitor> file_monitor_;
+  std::unique_ptr<DBusMonitor> dbus_monitor_;
 };
 
 } // namespace tizen_base
index 2b4a47470c0ed712629e2a713d0e8eecfe0ca3f6..d7040bbdac868a9fa6b89c33898d0bb7359126a0 100644 (file)
 
 #include <libopener.hpp>
 
+#include "activation_method/dbus_monitor.hh"
+#include "activation_method/fd_monitor.hh"
+#include "activation_method/file_monitor.hh"
+
 namespace tizen_base {
 
 class ServiceAssembly {
diff --git a/src/service_context.cc b/src/service_context.cc
new file mode 100644 (file)
index 0000000..b8dba0e
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * 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();
+}
+
+void ServiceContext::Listen(IEventListener* listener) {
+  auto type = info_->GetType();
+  if (type == "socket") {
+    const auto& socket_info = info_->GetSocketInfo();
+    fd_monitor_.reset(new FdMonitor(info_->GetName(), socket_info->GetPath(), listener));
+  } else if (type == "file") {
+    const auto& file_info = info_->GetFileInfo();
+    file_monitor_.reset(new FileMonitor(info_->GetName(), file_info->GetPath(), listener));
+  } else if (type == "dbus") {
+    const auto& dbus_info = info_->GetDbusInfo();
+    dbus_monitor_.reset(new DBusMonitor(info_->GetName(), dbus_info->GetBusName(), listener));
+  }
+}
+
+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
+
index b2cf9e93f5e442a7de7575ce0e12345ded69a63e..3f9ed7882e329c04f574d89e764a9c3cbea75892 100644 (file)
@@ -30,6 +30,11 @@ static const std::string kMode = kTagUnitedService + ":mode";
 static const std::string kType = kTagUnitedService + ":type";
 static const std::string kPath = kTagUnitedService + ":path";
 static const std::string kPriority = kTagUnitedService + ":priority";
+static const std::string kActivationMethod = "activation-method";
+static const std::string kSocketActivation = kActivationMethod + ":socket";
+static const std::string kFileActivation = kActivationMethod + ":file";
+static const std::string kDBusActivation = kActivationMethod + ":busname";
+static const std::string kVconfActivation = kActivationMethod + ":vconf";
 
 static const int kMinPriority = 1;
 static const int kMaxPriority = 99;
@@ -71,6 +76,34 @@ ServiceInfo::ServiceInfo(std::string conf_name,
     _E("Failed to get priority : %s", e.what());
     priority_ = 0;
   }
+
+  if (mode_ != "on-demand")
+    return;
+
+  if (type_ == "socket") {
+    std::string socket = dictionary->Get(kSocketActivation);
+    if (socket.empty())
+      throw std::runtime_error("No socket activation method defined in configuration file: " + conf_name_);
+
+    socket_info_ = std::make_shared<SocketInfo>(std::move(socket), 0);
+  }
+  else if (type_ == "file") {
+    std::string file = dictionary->Get(kFileActivation);
+    if (file.empty())
+      throw std::runtime_error("No file activation method defined in configuration file: " + conf_name_);
+
+    file_info_ = std::make_shared<FileInfo>(std::move(file), FileMode());
+  }
+  else if (type_ == "dbus") {
+    std::string bus_name = dictionary->Get(kDBusActivation);
+    if (bus_name.empty())
+      throw std::runtime_error("No DBus activation method defined in configuration file: " + conf_name_);
+
+    dbus_info_ = std::make_shared<DBusInfo>(std::move(bus_name));
+  }
+  // std::string vconf = dictionary->Get(kVconfActivation);
+  // if (!vconf.empty())
+  //   vconf_info_ = std::make_shared<VconfInfo<std::string>>(std::move(vconf), std::string(""));
 }
 
 ServiceInfo::~ServiceInfo() {}
@@ -93,4 +126,16 @@ std::shared_ptr<ServiceAssembly> ServiceInfo::GetAssembly() const {
   return assembly_;
 }
 
+std::shared_ptr<DBusInfo> ServiceInfo::GetDbusInfo() const {
+  return dbus_info_;
+}
+
+std::shared_ptr<FileInfo> ServiceInfo::GetFileInfo() const {
+  return file_info_;
+}
+
+std::shared_ptr<SocketInfo> ServiceInfo::GetSocketInfo() const {
+  return socket_info_;
+}
+
 }  // namespace tizen_base
index 66b74f51ec7f68aaff531f959593abe428e86072..345cf6ab32453ab04fbc7fa0ef60362ef50f7fe3 100644 (file)
 #include "dictionary.hh"
 #include "service_assembly.hh"
 
+#include "activation_method/dbus_info.hh"
+#include "activation_method/file_info.hh"
+#include "activation_method/socket_info.hh"
+#include "activation_method/vconf_info.hh"
+
 namespace tizen_base {
 
 class ServiceInfo {
@@ -39,6 +44,11 @@ class ServiceInfo {
   const unsigned int GetPriority() const;
   std::shared_ptr<ServiceAssembly> GetAssembly() const;
 
+  std::shared_ptr<DBusInfo> GetDbusInfo() const;
+  std::shared_ptr<FileInfo> GetFileInfo() const;
+  std::shared_ptr<SocketInfo> GetSocketInfo() const;
+  // std::shared_ptr<VconfInfo> GetVconfInfo() const;
+
  private:
   std::string conf_name_;
   std::string name_;
@@ -48,6 +58,11 @@ class ServiceInfo {
   std::string path_;
   unsigned int priority_;
   std::shared_ptr<ServiceAssembly> assembly_;
+
+  std::shared_ptr<DBusInfo> dbus_info_;
+  std::shared_ptr<FileInfo> file_info_;
+  std::shared_ptr<SocketInfo> socket_info_;
+  // std::shared_ptr<VconfInfo> vconf_info_;
 };
 
 }  // namespace tizen_base
index 4baf2b8d508bcb9edfb2213051f373fdb0f42359..2b56b710bff3adc6b875a6ebbe10a1406e69958d 100755 (executable)
@@ -19,6 +19,7 @@
 #include <tizen_core.h>
 #include <tizen_core_channel.h>
 
+#include <algorithm>
 #include <filesystem>
 #include <utility>
 
@@ -177,6 +178,10 @@ void ServiceLoader::LoadServices() {
         assembly->Load();
         assembly->ModuleInit(info->GetName());
       }
+
+      if (info->GetMode() == "on-demand") {
+
+      }
     } catch (const Exception& e) {
       _E("Error=%s", e.what());
       THROW(e.GetErrorCode());
@@ -197,7 +202,8 @@ int ServiceLoader::Run() {
 }
 
 void ServiceLoader::Quit() {
-  if (!running_) return;
+  if (!running_)
+    return;
 
   tizen_core_task_quit(task_);
 }
@@ -286,17 +292,52 @@ void ServiceLoader::QuitService(const std::string& name) {
 
 void ServiceLoader::QuitAllServices() {
   for (auto& [name, service] : services_) {
-    if (service->IsRunning()) service->Quit();
+    if (service->IsRunning())
+      service->Quit();
+  }
+}
+
+void ServiceLoader::ListenService(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->Listen();
 }
 
 void ServiceLoader::LoadService(const std::string& name) {
   auto found = infos_.find(name);
-  if (found == infos_.end()) THROW(SERVICE_ERROR_INVALID_PARAMETER);
+  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);
+  if (assembly->IsLoaded())
+    THROW(SERVICE_ERROR_INVALID_CONTEXT);
 
   try {
     assembly->Load();
@@ -309,11 +350,13 @@ void ServiceLoader::LoadService(const std::string& name) {
 
 void ServiceLoader::UnloadService(const std::string& name) {
   auto found = infos_.find(name);
-  if (found == infos_.end()) THROW(SERVICE_ERROR_NO_SUCH_SERVICE);
+  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);
+  if (!assembly->IsLoaded())
+    THROW(SERVICE_ERROR_INVALID_CONTEXT);
 
   try {
     assembly->ModuleShutdown(name.c_str());
@@ -335,7 +378,8 @@ void ServiceLoader::OnCreate() {
 
 void ServiceLoader::OnDestroy() {
   for (auto& [name, service] : services_) {
-    if (service->IsRunning()) service->Quit();
+    if (service->IsRunning())
+      service->Quit();
   }
 }
 
@@ -345,6 +389,19 @@ void ServiceLoader::OnMessageReceived(const std::string& sender,
 void ServiceLoader::OnServiceStateChanged(const Service* service,
                                           Service::State state) {}
 
+void ServiceLoader::OnEvent(const std::string& name) {
+  auto it = std::find_if(services_.begin(), services_.end(),
+                         [&](const std::shared_ptr<Service>& service) {
+                           return service->GetName() == name;
+                         });
+
+  if (it != services_.end()) {
+    _I("%s on-demand launch", name.c_str());
+    auto& service = *it;
+    service->Run();
+  }
+}
+
 void ServiceLoader::ChannelReceiveCb(tizen_core_channel_object_h object,
                                      void* user_data) {
   bundle* data = nullptr;
@@ -359,14 +416,16 @@ void ServiceLoader::ChannelReceiveCb(tizen_core_channel_object_h object,
 std::shared_ptr<ServiceInfo> ServiceLoader::GetServiceInfo(
     const std::string& name) {
   auto found = infos_.find(name);
-  if (found == infos_.end()) return nullptr;
+  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;
+  if (found == services_.end())
+    return nullptr;
 
   return found->second;
 }
@@ -393,4 +452,4 @@ void ServiceLoader::ServiceStateChangedCb(const Service* service,
   }
 }
 
-} // namespace tizen_base
+}  // namespace tizen_base
index 8f2972cd8a730c7f4aeed9e24050ec433e9e4f33..54379c9c56f601d4bb691a1aeeed4930e9044671 100644 (file)
@@ -27,6 +27,9 @@
 #include <queue>
 
 #include "service.hh"
+#include <vector>
+
+#include "event_listener.hh"
 #include "service_info.hh"
 
 #include "watchdog/watchdog_manager.hh"
@@ -35,7 +38,7 @@
 
 namespace tizen_base {
 
-class ServiceLoader {
+class ServiceLoader : IEventListener {
  public:
   ServiceLoader(int argc, char** argv, std::string name);
   ~ServiceLoader();
@@ -48,6 +51,7 @@ class ServiceLoader {
   void RunAllServices();
   void QuitService(const std::string& name);
   void QuitAllServices();
+  void ListenService(const std::string& name);
   void LoadService(const std::string& name);
   void UnloadService(const std::string& name);
 
@@ -58,6 +62,8 @@ class ServiceLoader {
   virtual void OnServiceStateChanged(const Service* service,
                                      Service::State state);
 
+  void OnEvent(const std::string& name) override;
+
  private:
   std::shared_ptr<Service> GetService(const std::string& name);
   std::shared_ptr<ServiceInfo> GetServiceInfo(const std::string& name);