Add new functions for component port 57/253157/11
authorHwankyu Jhun <h.jhun@samsung.com>
Fri, 5 Feb 2021 03:31:14 +0000 (12:31 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Mon, 15 Feb 2021 06:22:17 +0000 (15:22 +0900)
Adds:
 - component_port_is_running()
 - component_port_watch()
 - component_port_unwatch()

Change-Id: I0618aa0e87ffa3f24712fe93b3370b7be7fc9ccf
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
component_based/port/api/component_port.h
component_based/port/port.cc
component_based/port/port_watcher.cc [new file with mode: 0644]
component_based/port/port_watcher.hh [new file with mode: 0644]
component_based/port/stub.cc

index b9378b11076e73e11a925cdcd8f952891f88f8fd..ecf74c22a729b80a6a4739e5594c3ab2b6698ab6 100644 (file)
@@ -72,6 +72,27 @@ typedef void (*component_port_request_cb)(const char *sender, parcel_h request,
  */
 typedef void (*component_port_sync_request_cb)(const char *sender, parcel_h request, parcel_h response, void *user_data);
 
+/**
+ * @breif Called when the port is appeared.
+ * @details The function is called when a component port is registered.
+ * @since_tizen 6.5
+ * @param[in] endpoint The endpoint name
+ * @param[in] owner The process ID of the owner
+ * @param[in] user_data The user data passed from the registeration function
+ * @see component_port_watch()
+ */
+typedef void (*component_port_appeared_cb)(const char *endpoint, pid_t owner, void *user_data);
+
+/**
+ * @breif Called when the port is vanished.
+ * @details The function is called when a component port is deregistered.
+ * @since_tizen 6.5
+ * @param[in] endpoint The endpoint name
+ * @param[in] user_data The user data passed from the registeration function
+ * @see component_port_watch();
+ */
+typedef void (*component_port_vanished_cb)(const char *endpoint, void *user_data);
+
 /**
  * @brief Creates the component port handle.
  * @since_tizen 6.5
@@ -202,6 +223,54 @@ int component_port_send(component_port_h port, const char *endpoint, int timeout
  */
 int component_port_send_sync(component_port_h port, const char *endpoint, int timeout, parcel_h request, parcel_h *response);
 
+/**
+ * @brief Checks whether the endpoint is running or not.
+ * @since_tizen 6.5
+ * @param[in] endpoint The endpoint name
+ * @param[out] is_running true, if the endpoint is running
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #COMPONENT_PORT_ERROR_NONE Successful
+ * @retval #COMPONENT_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #COMPONENT_PORT_ERROR_IO_ERROR I/O error
+ */
+int component_port_is_running(const char *endpoint, bool *is_running);
+
+/**
+ * @brief Starts watching the endpoint.
+ * @details The component_port_appeared_cb() is invoked when the endpoint of component port is registered.
+ *          The component_port_vanished_cb() is invoked when the endpoint of component port is deregistered.
+ * @since_tizen 6.5
+ * @param[in] endpoint The endpoint name
+ * @param[in] appeared_cb The callback function to invoke
+ * @param[in] vanished_cb The callback function to invoke
+ * @param[in] user_data The user data to be passed to the callback function
+ * @param[out] watcher_id The identifier that can be used with component_port_unwatch() to stop watching the endpoint
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #COMPONENT_PORT_ERROR_NONE Successful
+ * @retval #COMPONENT_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #COMPONENT_PORT_ERROR_IO_ERROR I/O error
+ * @retval #COMPONENT_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ * @see component_port_set_appeared_cb()
+ * @see component_port_set_vanished_cb()
+ * @see component_port_unwatch()
+ */
+int component_port_watch(const char *endpoint, component_port_appeared_cb appeared_cb, component_port_vanished_cb vanished_cb, void *user_data, unsigned int *watcher_id);
+
+/**
+ * @brief Stops watching the endpoint.
+ * @since_tizen 6.5
+ * @param[in] watcher_id The identifier obtained from component_port_watch()
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #COMPONENT_PORT_ERROR_NONE Successful
+ * @retval #COMPONENT_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #COMPONENT_PORT_ERROR_IO_ERROR I/O error
+ * @see component_port_watch()
+ */
+int component_port_unwatch_endpoint(unsigned int watcher_id);
+
 #ifdef __cplusplus
 }
 #endif
index 9f7994af008aec24b37f1058f9e0dc8065eb47a6..bd7e0d7c931379bac2cecb9fdae830417790b158 100644 (file)
  * limitations under the License.
  */
 
+#include <aul.h>
+#include <aul_component_port.h>
 #include <errno.h>
 #include <tizen.h>
 
+#include <bundle_cpp.h>
+
 #include "component_based/port/client.hh"
 #include "component_based/port/exception.hh"
 #include "component_based/port/log_private.hh"
@@ -27,8 +31,7 @@
 
 namespace component_based {
 
-Port::Impl::~Impl() {
-}
+Port::Impl::~Impl() = default;
 
 Port::Impl::Impl(Port* parent, std::string name, Port::IEvent* listener)
     : parent_(parent),
diff --git a/component_based/port/port_watcher.cc b/component_based/port/port_watcher.cc
new file mode 100644 (file)
index 0000000..296afa7
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bundle_cpp.h>
+#include <errno.h>
+
+#include "component_based/port/exception.hh"
+#include "component_based/port/log_private.hh"
+#include "component_based/port/port_watcher.hh"
+
+namespace component_based {
+
+PortWatcher::PortWatcher(IEvent* listener) : listener_(listener) {
+}
+
+PortWatcher::~PortWatcher() {
+  Unwatch();
+}
+
+void PortWatcher::Watch() {
+  if (conn_)
+    return;
+
+  int ret = aul_app_com_create("component.port.watch", nullptr, AppComCb,
+      this, &conn_);
+  if (ret != AUL_R_OK) {
+    _E("aul_app_com_create() is failed. error(%d)", ret);
+    THROW(-EIO);
+  }
+}
+
+void PortWatcher::Unwatch() {
+  if (conn_) {
+    aul_app_com_leave(conn_);
+    conn_ = nullptr;
+  }
+}
+
+int PortWatcher::AppComCb(const char* endpoint, aul_app_com_result_e result,
+    bundle* envelope, void* user_data) {
+  tizen_base::Bundle b(envelope, false, false);
+  std::string port_name = b.GetString(AUL_K_COMPONENT_PORT);
+  std::string event = b.GetString(AUL_K_EVENT_NAME);
+  _D("event(%s), endpoint(%s)", event.c_str(), port_name.c_str());
+  if (event == "appeared") {
+    pid_t pid = std::stoi(b.GetString(AUL_K_PID));
+    auto* handle = static_cast<PortWatcher*>(user_data);
+    handle->listener_->OnPortAppeared(port_name, pid);
+  } else {
+    auto* handle = static_cast<PortWatcher*>(user_data);
+    handle->listener_->OnPortVanished(port_name);
+  }
+  return 0;
+}
+
+}  // namespace component_based
diff --git a/component_based/port/port_watcher.hh b/component_based/port/port_watcher.hh
new file mode 100644 (file)
index 0000000..fd44b79
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021 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 COMPONENT_BASED_PORT_PORT_WATCHER_HH_
+#define COMPONENT_BASED_PORT_PORT_WATCHER_HH_
+
+#include <aul.h>
+#include <aul_app_com.h>
+#include <bundle.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+namespace component_based {
+
+class PortWatcher {
+ public:
+  class IEvent {
+   public:
+    virtual void OnPortAppeared(const std::string& endpoint, pid_t owner) = 0;
+    virtual void OnPortVanished(const std::string& endpoint) = 0;
+  };
+
+  PortWatcher(IEvent* listener);
+  virtual ~PortWatcher();
+
+  void Watch();
+  void Unwatch();
+
+ private:
+  static int AppComCb(const char* endpoint, aul_app_com_result_e result,
+      bundle* envelope, void* user_data);
+
+ private:
+  IEvent* listener_ = nullptr;
+  aul_app_com_connection_h conn_ = nullptr;
+};
+
+}  // namespace component_based
+
+#endif  // COMPONENT_BASED_PORT_PORT_WATCHER_HH_
index f0645534d34945727943348d17e835760ccfae6e..6d6bbb54da88082b18255af474b6d68c4b953040 100644 (file)
  * limitations under the License.
  */
 
+#include <aul_component_port.h>
+#include <tizen.h>
+
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+
 #include "component_based/port/api/component_port.h"
 #include "component_based/port/exception.hh"
 #include "component_based/port/export_api.hh"
 #include "component_based/port/log_private.hh"
 #include "component_based/port/port.hh"
+#include "component_based/port/port_watcher.hh"
 
 namespace {
 
@@ -32,11 +42,13 @@ class PortStub : public component_based::Port,
   virtual ~PortStub() = default;
 
   void SetRequestCb(component_port_request_cb cb, void* user_data) {
+    std::lock_guard<std::recursive_mutex> lock(GetMutex());
     request_cb_ = cb;
     request_cb_user_data_ = user_data;
   }
 
   void SetSyncRequestCb(component_port_sync_request_cb cb, void* user_data) {
+    std::lock_guard<std::recursive_mutex> lock(GetMutex());
     sync_request_cb_ = cb;
     sync_request_cb_user_data_ = user_data;
   }
@@ -44,6 +56,7 @@ class PortStub : public component_based::Port,
  private:
   void OnRequest(const std::shared_ptr<component_based::SenderInfo>& sender,
       const std::shared_ptr<tizen_base::Parcel>& request) override {
+    std::lock_guard<std::recursive_mutex> lock(GetMutex());
     if (request_cb_) {
       parcel_h parcel = static_cast<parcel_h>(request.get());
       request_cb_(sender->GetName().c_str(), parcel, request_cb_user_data_);
@@ -53,6 +66,7 @@ class PortStub : public component_based::Port,
   void OnSyncRequest(const std::shared_ptr<component_based::SenderInfo>& sender,
       const std::shared_ptr<tizen_base::Parcel>& request,
       std::shared_ptr<tizen_base::Parcel>& response) override {
+    std::lock_guard<std::recursive_mutex> lock(GetMutex());
     if (sync_request_cb_) {
       parcel_h req_parcel = static_cast<parcel_h>(request.get());
       parcel_h res_parcel = static_cast<parcel_h>(response.get());
@@ -61,13 +75,109 @@ class PortStub : public component_based::Port,
     }
   }
 
+  std::recursive_mutex& GetMutex() const {
+    return mutex_;
+  }
+
  private:
   component_port_request_cb request_cb_ = nullptr;
   void* request_cb_user_data_ = nullptr;
   component_port_sync_request_cb sync_request_cb_ = nullptr;
   void* sync_request_cb_user_data_ = nullptr;
+  mutable std::recursive_mutex mutex_;
+};
+
+class Watcher {
+ public:
+  Watcher(std::string endpoint,
+      component_port_appeared_cb appeared_cb,
+      component_port_vanished_cb vanished_cb,
+      void* user_data)
+      : endpoint_(std::move(endpoint)),
+        appeared_cb_(appeared_cb),
+        vanished_cb_(vanished_cb),
+        user_data_(user_data) {
+  }
+
+  std::string endpoint_;
+  component_port_appeared_cb appeared_cb_;
+  component_port_vanished_cb vanished_cb_;
+  void* user_data_;
+};
+
+class PortWatcherStub : public component_based::PortWatcher,
+                        public component_based::PortWatcher::IEvent {
+ public:
+  PortWatcherStub() : component_based::PortWatcher(this) {
+  }
+
+  unsigned int Watch(std::string endpoint,
+      component_port_appeared_cb appeared_cb,
+      component_port_vanished_cb vanished_cb,
+      void* user_data) {
+    std::lock_guard<std::recursive_mutex> lock(GetMutex());
+    try {
+      component_based::PortWatcher::Watch();
+    } catch (component_based::Exception& e) {
+      return 0;
+    }
+
+    unsigned int watcher_id = CreateWatcherId();
+    watchers_[watcher_id] = std::make_unique<Watcher>(
+        endpoint, appeared_cb, vanished_cb, user_data);
+    return watcher_id;
+  }
+
+  void Unwatch(unsigned int watcher_id) {
+    std::lock_guard<std::recursive_mutex> lock(GetMutex());
+    auto found = watchers_.find(watcher_id);
+    if (found == watchers_.end())
+      return;
+
+    watchers_.erase(found);
+  }
+
+ private:
+  std::recursive_mutex& GetMutex() const {
+    return mutex_;
+  }
+
+  void OnPortAppeared(const std::string& endpoint, pid_t owner) override {
+    std::lock_guard<std::recursive_mutex> lock(GetMutex());
+    auto iter = watchers_.begin();
+    while (iter != watchers_.end()) {
+      auto& watcher = iter->second;
+      iter++;
+      if (watcher->endpoint_ == endpoint)
+        watcher->appeared_cb_(endpoint.c_str(), owner, watcher->user_data_);
+    }
+  }
+
+  void OnPortVanished(const std::string& endpoint) override {
+    std::lock_guard<std::recursive_mutex> lock(GetMutex());
+    auto iter = watchers_.begin();
+    while (iter != watchers_.end()) {
+      auto& watcher = iter->second;
+      iter++;
+      if (watcher->endpoint_ == endpoint)
+        watcher->vanished_cb_(endpoint.c_str(), watcher->user_data_);
+    }
+  }
+
+  static int CreateWatcherId() {
+    static std::atomic<unsigned int> id { 0 };
+    if (id + 1 == 0)
+      id.exchange(0);
+    return ++id;
+  }
+
+ private:
+  std::unordered_map<unsigned int, std::unique_ptr<Watcher>> watchers_;
+  mutable std::recursive_mutex mutex_;
 };
 
+PortWatcherStub port_watcher;
+
 }  // namespace
 
 extern "C" EXPORT_API int component_port_create(const char* port_name,
@@ -226,3 +336,52 @@ extern "C" EXPORT_API int component_port_send_sync(component_port_h port,
   return COMPONENT_PORT_ERROR_NONE;
 }
 
+extern "C" EXPORT_API int component_port_is_running(const char* endpoint,
+    bool* is_running) {
+  if (endpoint == nullptr || is_running == nullptr) {
+    _E("Invalid parameter");
+    return COMPONENT_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  int ret = aul_component_port_exist(endpoint, is_running);
+  if (ret != AUL_R_OK) {
+    _E("aul_component_port_exist() is failed. error(%d)", ret);
+    return COMPONENT_PORT_ERROR_IO_ERROR;
+  }
+
+  _D("%s is %s", endpoint, *is_running ? "running" : "not running");
+  return COMPONENT_PORT_ERROR_NONE;
+}
+
+extern "C" EXPORT_API int component_port_watch(const char *endpoint,
+    component_port_appeared_cb appeared_cb,
+    component_port_vanished_cb vanished_cb,
+    void* user_data,
+    unsigned int* watcher_id) {
+  if (endpoint == nullptr || appeared_cb == nullptr || vanished_cb == nullptr ||
+      watcher_id == nullptr) {
+    _E("Invalid parameter");
+    return COMPONENT_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  *watcher_id = ::port_watcher.Watch(endpoint, appeared_cb, vanished_cb,
+      user_data);
+  if (*watcher_id == 0) {
+    _E("Watch() is failed");
+    return COMPONENT_PORT_ERROR_IO_ERROR;
+  }
+
+  _D("endpoint(%s), watcher_id(%u)", endpoint, *watcher_id);
+  return COMPONENT_PORT_ERROR_NONE;
+}
+
+extern "C" EXPORT_API int component_port_unwatch(unsigned int watcher_id) {
+  if (watcher_id == 0) {
+    _E("Invalid parameter");
+    return COMPONENT_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  ::port_watcher.Unwatch(watcher_id);
+  _D("watcher_id(%u)", watcher_id);
+  return COMPONENT_PORT_ERROR_NONE;
+}