Support local execution mode 56/295656/4
authorjusung son <jusung07.son@samsung.com>
Wed, 12 Jul 2023 07:42:32 +0000 (16:42 +0900)
committerjusung son <jusung07.son@samsung.com>
Thu, 13 Jul 2023 05:02:04 +0000 (14:02 +0900)
Change-Id: I513c91723010011fe6329d786ac3a0ea4e890ae9
Signed-off-by: jusung son <jusung07.son@samsung.com>
idlc/gen/c_body_gen_base_cb.h
idlc/gen/version2/c_body_generator_base.cc
idlc/gen/version2/c_body_generator_base.hh
idlc/gen/version2/c_body_generator_base_cb.hh
idlc/gen/version2/c_proxy_body_generator.cc
idlc/gen/version2/c_proxy_body_generator.hh
idlc/gen/version2/c_proxy_body_generator_cb.hh
idlc/gen/version2/c_stub_body_generator.cc
idlc/gen/version2/c_stub_body_generator.hh
idlc/gen/version2/c_stub_body_generator_cb.hh
tests/build_tests/CMakeLists.txt

index 4cb55d61ef5e11505594789debd4315527875eff..acfe626f3f0a671d5a2de12625b15ce7e2d948ef 100644 (file)
@@ -64,6 +64,11 @@ R"__c_cb(
 #ifndef STRING_GET
 #define STRING_GET(x) ((x) ? x : "")
 #endif
+
+#ifndef EXPORT_API
+#define EXPORT_API extern "C" __attribute__ ((visibility("default")))
+#endif
+
 )__c_cb";
 
 /**
index fe696ece6df376edec2be0a3683a4c57cd505afb..8c53c31216371b5ddcee9f908cade94b870af14f 100644 (file)
@@ -30,6 +30,9 @@ namespace tidl {
 namespace version2 {
 namespace {
 
+constexpr const char PREFIX_RPC_PORT_PROXY[] = "rpc_port_proxy";
+constexpr const char PREFIX_RPC_PORT_STUB[] = "rpc_port_stub";
+
 bool IsPtrType(const BaseType& type) {
   if (type.GetUserDefinedType() == BaseType::UserType::STRUCTURE ||
       type.GetUserDefinedType() == BaseType::UserType::DELEGATE ||
@@ -104,6 +107,14 @@ void CBodyGeneratorBase::AddTypeName(const Structure& st) {
   struct_types_[std::move(name)] = std::move(type_name);
 }
 
+void CBodyGeneratorBase::GenIncludeLemHeaders(std::ofstream& stream) {
+  stream << SmartIndent(CB_LEM_HEADER);
+}
+
+void CBodyGeneratorBase::GenLemBaseDefinition(std::ofstream& stream) {
+  stream << SmartIndent(CB_LEM_BASE_DEFS);
+}
+
 void CBodyGeneratorBase::GenStructureDefinition(std::ofstream& stream) {
   for (auto& b : GetDocument().GetBlocks()) {
     if (b->GetType() == Block::TYPE_STRUCTURE) {
@@ -131,6 +142,15 @@ bool CBodyGeneratorBase::HasDelegate() {
   return has_delegate_;
 }
 
+std::string CBodyGeneratorBase::GetHandlePrefixReverse() {
+  std::string prefix =
+      IsProxy() ? PREFIX_RPC_PORT_STUB : PREFIX_RPC_PORT_PROXY;
+  if (!HasNamespace())
+    return prefix;
+
+  return prefix + "_" + GetFileNamespace();
+}
+
 void CBodyGeneratorBase::GenStructureArrayBaseDefinition(std::ofstream& stream,
     const Structure& st) {
   auto& elm = *(st.GetElements().begin());
index 66172b9ccceb51409482cbbc6757d6cefe15c52f..dfdca332d9e10dac979cc5174b018d6acd778f3c 100644 (file)
@@ -37,6 +37,9 @@ class CBodyGeneratorBase : public tidl::CBodyGeneratorBase {
   void GenUnitMapDefinition(std::ofstream& stream);
   void GenUnitMapBase(std::ofstream& stream);
   bool HasDelegate();
+  void GenLemBaseDefinition(std::ofstream& stream);
+  void GenIncludeLemHeaders(std::ofstream& stream);
+  std::string GetHandlePrefixReverse();
 
  private:
   void AddTypeName(const Structure& st);
index 1fc3fffa30fbdbd2a9994b8bc16c80bf0a66993a..95ffe827f1770bfc72ce102c992cc5e13d774158 100644 (file)
 namespace tidl {
 namespace version2 {
 
+constexpr const char CB_LEM_HEADER[] =
+R"__c_cb(
+#include <unistd.h>
+#include <dlfcn.h>
+#include <app_common.h>
+)__c_cb";
+
+constexpr const char CB_LEM_BASE_DEFS[] =
+R"__c_cb(
+typedef struct {
+  int ret;
+  rpc_port_unit_map_h lem_ret;
+} rpc_port_result_s;
+
+typedef bool (*rpc_port_stub_is_listen)();
+typedef int(*rpc_port_proxy_LEM_received)(const char *endpoint, const char *port_name, rpc_port_unit_map_h map, void *data);
+typedef rpc_port_result_s (*rpc_port_stub_LEM_received_event_cb)(const char *sender, const char *instance, rpc_port_parcel_h parcel, void *user_data);
+
+typedef struct {
+  rpc_port_stub_LEM_received_event_cb send;
+  rpc_port_stub_connected_event_cb connect;
+  rpc_port_stub_disconnected_event_cb disconnect;
+  rpc_port_stub_is_listen is_listen;
+} rpc_port_stub_LEM_callback_s;
+
+typedef struct {
+  rpc_port_proxy_LEM_received send;
+  rpc_port_proxy_connected_event_cb connect;
+  rpc_port_proxy_disconnected_event_cb disconnect;
+  bool is_LEM;
+  void *user_data;
+} rpc_port_proxy_LEM_callback_s;
+)__c_cb";
+
 constexpr const char CB_UNIT_MAP_DEFS[] =
 R"__c_cb(
 typedef struct rpc_port_unit_s {
index 54380df2bb88e1b539a5c50d7a91850c59e05b11..7f4f7fbc8353ae3862ed696ef1f0a9ad72547b68 100644 (file)
@@ -33,12 +33,14 @@ void CProxyBodyGenerator::OnInitGen(std::ofstream& stream) {
   GenVersion(stream);
   GenGNUSourceDefinition(stream);
   GenIncludeDefaultHeaders(stream);
+  GenIncludeLemHeaders(stream);
   GenIncludeHeader(stream);
   GenLogTag(stream, std::string("RPC_PORT_PROXY"));
   GenLogDefinition(stream);
   GenVersionDefinition(stream);
   GenBaseDefinition(stream);
   GenUnitMapDefinition(stream);
+  GenLemDefinition(stream);
   GenDelegateDefinition(stream);
   GenInterfaceDelegateCallback(stream);
   GenStructureDefinition(stream);
@@ -53,6 +55,11 @@ void CProxyBodyGenerator::OnInitGen(std::ofstream& stream) {
 void CProxyBodyGenerator::OnFiniGen(std::ofstream& stream) {
 }
 
+void CProxyBodyGenerator::GenLemDefinition(std::ofstream& stream) {
+  GenLemBaseDefinition(stream);
+  stream << SmartIndent(CB_LEM_PROXY_BASE_DEF);
+}
+
 void CProxyBodyGenerator::GenDelegateDefinition(std::ofstream& stream) {
   if (HasDelegate())
     stream << SmartIndent(CB_DELEGATE_DEFS);
@@ -389,11 +396,14 @@ void CProxyBodyGenerator::GenInterfaceBase(std::ofstream& stream,
   std::string prefix = GetHandlePrefix();
   std::string name = iface.GetID();
   std::string event = HasDelegate() ? CB_INTERFACE_DELEGATE_REGISTER_EVENT : "";
+  std::string callback = HasDelegate() ? CB_INTERFACE_DELEGATE_LEM_RECEIVE_CALLBACK : "";
 
   ReplaceAll(CB_INTERFACE_BASE)
       .Change("<DELEGATE_REGISTER_EVENT>", event)
+      .Change("<DELEGATE_LEM_RECEIVE_CALLBACK>", callback)
       .Change("<PREFIX>", prefix)
       .Change("<NAME>", name)
+      .Change("<PREFIX_REVERSE>", GetHandlePrefixReverse())
       .ChangeToUpper("<UPPERCASE_PREFIX>", prefix)
       .ChangeToUpper("<UPPERCASE_NAME>", name)
       .Transform([&](std::string code) { return SmartIndent(code); })
index c4bb347296e887ca31bcf6187db226ea7b559ea6..806ef3e76b3065f37c74471ffe97bfb0f6cb7b85 100644 (file)
@@ -86,6 +86,7 @@ class CProxyBodyGenerator : public CBodyGeneratorBase {
       const Interface& iface);
   void GenDelegateDefinition(std::ofstream& stream);
   void GenDelegateBase(std::ofstream& stream);
+  void GenLemDefinition(std::ofstream& stream);
 
  private:
   std::shared_ptr<Options> options_;
index 9deb02aa421d776b85dc14c23dbbcc826d422da4..07505ac67893b2d09470c1096f602b0c665d7148 100644 (file)
 
 namespace tidl {
 namespace version2 {
+constexpr const char CB_LEM_PROXY_BASE_DEF[] =
+R"__c_cb(
+typedef void (*rpc_port_stub_LEM_init)(rpc_port_stub_LEM_callback_s *cb);
+char *__proxy_appid;
+
+)__c_cb";
 
 constexpr const char CB_DELEGATE_DEFS[] =
 R"__c_cb(
@@ -573,8 +579,14 @@ typedef struct <PREFIX>_<NAME>_s {
   <PREFIX>_<NAME>_callback_s callback;
   void *user_data;
   GList *delegates;
+  bool is_LEM;
+  bool is_LEM_connected;
+  rpc_port_stub_LEM_callback_s lem_cb;
+  char *lem_instance_id;
   GRecMutex mutex;
 } <PREFIX>_<NAME>_t;
+
+<PREFIX>_<NAME>_h __<PREFIX>_<NAME>_handle;
 )__c_cb";
 
 /**
@@ -608,6 +620,16 @@ static void __<PREFIX>_<NAME>_process_received_event(GList **delegates, rpc_port
   rpc_port_delegate_destroy(delegate);
 }
 
+static int __<PREFIX>_<NAME>_LEM_received(const char *endpoint, const char *port_name, rpc_port_unit_map_h map, void *data)
+{
+  <PREFIX>_<NAME>_h h = data;
+
+  _W("endpoint(%s), port_name(%s)", endpoint, port_name);
+  __<PREFIX>_<NAME>_process_received_event(&h->delegates, map);
+
+  return RPC_PORT_ERROR_NONE;
+}
+
 static void __<PREFIX>_<NAME>_received(const char *endpoint, const char *port_name, void *data)
 {
   <PREFIX>_<NAME>_h h = data;
@@ -643,7 +665,6 @@ static void __<PREFIX>_<NAME>_received(const char *endpoint, const char *port_na
   __<PREFIX>_<NAME>_process_received_event(&h->delegates, map);
   rpc_port_unit_map_destroy(map);
 }
-
 )__c_cb";
 
 /**
@@ -660,6 +681,15 @@ if (ret != RPC_PORT_ERROR_NONE) {
 }
 )__c_cb";
 
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_DELEGATE_LEM_RECEIVE_CALLBACK[] =
+R"__c_cb(cb->send = __<PREFIX>_<NAME>_LEM_received;
+)__c_cb";
+
 /**
  * <PREFIX> The prefix of the interface.
  * <NAME> The name of the interface.
@@ -725,8 +755,12 @@ static void __<PREFIX>_<NAME>_connected(const char *endpoint, const char *port_n
   <PREFIX>_<NAME>_h h = data;
 
   _I("endpoint(%s), port_name(%s)", endpoint, port_name);
-  h->port = port;
-  rpc_port_proxy_get_port(h->proxy, RPC_PORT_PORT_CALLBACK, &h->callback_port);
+  if(h->is_LEM) {
+    h->is_LEM_connected = true;
+  } else {
+    h->port = port;
+    rpc_port_proxy_get_port(h->proxy, RPC_PORT_PORT_CALLBACK, &h->callback_port);
+  }
   h->callback.connected(h, h->user_data);
 }
 
@@ -735,6 +769,7 @@ static void __<PREFIX>_<NAME>_disconnected(const char *endpoint, const char *por
   <PREFIX>_<NAME>_h h = data;
 
   _W("endpoint(%s), port_name(%s)", endpoint, port_name);
+  h->is_LEM_connected = false;
   h->port = nullptr;
   h->callback.disconnected(h, h->user_data);
 }
@@ -748,10 +783,24 @@ static void __<PREFIX>_<NAME>_rejected(const char *endpoint, const char *port_na
   h->callback.rejected(h, h->user_data);
 }
 
+static gboolean __<PREFIX>_<NAME>_LEM_connected(gpointer user_data) {
+  __<PREFIX>_<NAME>_connected(__proxy_appid, "<NAME>", nullptr, user_data);
+  return FALSE;
+}
+
+EXPORT_API void <PREFIX>_<NAME>_LEM_init(rpc_port_proxy_LEM_callback_s *cb) {
+  cb->connect = __<PREFIX>_<NAME>_connected;
+  cb->disconnect = __<PREFIX>_<NAME>_disconnected;
+  cb->is_LEM = __<PREFIX>_<NAME>_handle->is_LEM;
+  cb->user_data = __<PREFIX>_<NAME>_handle;
+  <DELEGATE_LEM_RECEIVE_CALLBACK>
+}
+
 int <PREFIX>_<NAME>_create(const char *stub_appid, <PREFIX>_<NAME>_callback_s *callback, void *user_data, <PREFIX>_<NAME>_h *h)
 {
   <PREFIX>_<NAME>_t *handle;
   int ret;
+  rpc_port_stub_LEM_init lem_init;
 
   if (stub_appid == nullptr || callback == nullptr || h == nullptr) {
     _E("Invalid parameter");
@@ -811,6 +860,18 @@ int <PREFIX>_<NAME>_create(const char *stub_appid, <PREFIX>_<NAME>_callback_s *c
   <DELEGATE_REGISTER_EVENT>
   *h = handle;
 
+  __<PREFIX>_<NAME>_handle = handle;
+
+  void *plugin_handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
+  if (plugin_handle == NULL)
+    return RPC_PORT_ERROR_NONE;
+
+  lem_init = dlsym(plugin_handle, "<PREFIX_REVERSE>_<NAME>_LEM_init");
+  if (lem_init == NULL)
+    return RPC_PORT_ERROR_NONE;
+
+  lem_init(&handle->lem_cb);
+
   return RPC_PORT_ERROR_NONE;
 }
 
@@ -834,6 +895,12 @@ int <PREFIX>_<NAME>_destroy(<PREFIX>_<NAME>_h h)
   if (h->stub_appid)
     free(h->stub_appid);
 
+  if (h->is_LEM && h->is_LEM_connected) {
+    _I("LEM destroy (%s)", __proxy_appid);
+    h->is_LEM_connected = false;
+    h->lem_cb.disconnect(__proxy_appid, h->lem_instance_id, nullptr);
+  }
+
   free(h);
 
   return RPC_PORT_ERROR_NONE;
@@ -841,14 +908,37 @@ int <PREFIX>_<NAME>_destroy(<PREFIX>_<NAME>_h h)
 
 int <PREFIX>_<NAME>_connect(<PREFIX>_<NAME>_h h)
 {
-  int ret;
+  int ret = RPC_PORT_ERROR_NONE;
+  char instance_id[512];
 
   if (h == nullptr || h->proxy == nullptr) {
     _E("Invalid parameter");
     return RPC_PORT_ERROR_INVALID_PARAMETER;
   }
 
-  ret = rpc_port_proxy_connect(h->proxy, h->stub_appid, "<NAME>");
+  if (__proxy_appid == nullptr)
+    app_get_id(&__proxy_appid);
+
+  if (__proxy_appid != nullptr && !strcmp(__proxy_appid, h->stub_appid)) {
+    if (h->lem_cb.is_listen != nullptr)
+      h->is_LEM =  h->lem_cb.is_listen();
+
+    _I("LEM appid (%s) (%d)", __proxy_appid, h->is_LEM);
+  }
+
+  if (h->is_LEM) {
+    snprintf(instance_id, sizeof(instance_id), "LEM_<NAME>@%s", __proxy_appid);
+
+    h->lem_instance_id = strdup(instance_id);
+    h->lem_cb.connect(__proxy_appid, h->lem_instance_id ? h->lem_instance_id : "LEM_<NAME>", &ret);
+
+    if (ret == RPC_PORT_ERROR_NONE)
+      g_idle_add(__<PREFIX>_<NAME>_LEM_connected, h);
+
+  } else {
+    ret = rpc_port_proxy_connect(h->proxy, h->stub_appid, "<NAME>");
+  }
+
   if (ret != RPC_PORT_ERROR_NONE) {
     _E("Failed to connect to stub. error(%d)", ret);
     return ret;
@@ -859,14 +949,33 @@ int <PREFIX>_<NAME>_connect(<PREFIX>_<NAME>_h h)
 
 int <PREFIX>_<NAME>_connect_sync(<PREFIX>_<NAME>_h h)
 {
-  int ret;
+  int ret = RPC_PORT_ERROR_NONE;
+  char instance_id[512];
 
   if (h == nullptr || h->proxy == nullptr) {
     _E("Invalid parameter");
     return RPC_PORT_ERROR_INVALID_PARAMETER;
   }
 
-  ret = rpc_port_proxy_connect_sync(h->proxy, h->stub_appid, "<NAME>");
+  if (__proxy_appid == nullptr)
+    app_get_id(&__proxy_appid);
+
+  if (__proxy_appid != nullptr && !strcmp(__proxy_appid, h->stub_appid)) {
+    if (h->lem_cb.is_listen != nullptr)
+      h->is_LEM = h->lem_cb.is_listen();
+
+    _I("LEM appid (%s) (%d)", __proxy_appid, h->is_LEM);
+  }
+
+  if (h->is_LEM) {
+    snprintf(instance_id, sizeof(instance_id), "LEM_<NAME>@%s", __proxy_appid);
+
+    h->lem_instance_id = strdup(instance_id);
+    h->lem_cb.connect(__proxy_appid, h->lem_instance_id ? h->lem_instance_id : "LEM_<NAME>", &ret);
+  } else {
+    ret = rpc_port_proxy_connect_sync(h->proxy, h->stub_appid, "<NAME>");
+  }
+
   if (ret != RPC_PORT_ERROR_NONE) {
     _E("Failed to connect to stub. error(%d)", ret);
     return ret;
@@ -879,15 +988,26 @@ int <PREFIX>_<NAME>_disconnect(<PREFIX>_<NAME>_h h)
 {
   int ret;
 
-  if (h == nullptr || h->proxy == nullptr) {
+  if (h == nullptr ) {
     _E("Invalid parameter");
     return RPC_PORT_ERROR_INVALID_PARAMETER;
   }
 
-  ret = rpc_port_disconnect(h->port);
-  if (ret != RPC_PORT_ERROR_NONE) {
-    _E("Failed to disconnect from stub. error(%d)", ret);
-    return ret;
+  if (h->proxy == nullptr && h->is_LEM_connected == false) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  if (h->is_LEM) {
+    _I("LEM disconnect (%s)", __proxy_appid);
+    h->is_LEM_connected = false;
+    h->lem_cb.disconnect(__proxy_appid, h->lem_instance_id, nullptr);
+  } else {
+    ret = rpc_port_disconnect(h->port);
+    if (ret != RPC_PORT_ERROR_NONE) {
+      _E("Failed to disconnect from stub. error(%d)", ret);
+      return ret;
+    }
   }
 
   return RPC_PORT_ERROR_NONE;
@@ -915,6 +1035,7 @@ void <PREFIX>_<NAME>_invoke_<METHOD_NAME>(<PREFIX>_<NAME>_h h<METHOD_PARAMS>)
   rpc_port_unit_map_h map_;
   int seq_num_ = -1;
   int res_;
+  rpc_port_result_s stub_result;
 
   if (h == nullptr<METHOD_PARAMS_CHECK>) {
     _E("Invalid parameter");
@@ -922,7 +1043,7 @@ void <PREFIX>_<NAME>_invoke_<METHOD_NAME>(<PREFIX>_<NAME>_h h<METHOD_PARAMS>)
     return;
   }
 
-  if (h->port == nullptr) {
+  if (h->port == nullptr && h->is_LEM_connected == false) {
     _E("Not connected");
     set_last_result(RPC_PORT_ERROR_INVALID_PARAMETER);
     return;
@@ -956,7 +1077,13 @@ void <PREFIX>_<NAME>_invoke_<METHOD_NAME>(<PREFIX>_<NAME>_h h<METHOD_PARAMS>)
   rpc_port_unit_map_destroy(map_);
 
   g_rec_mutex_lock(&h->mutex);
-  res_ = rpc_port_parcel_send(parcel_, h->port);
+  if (h->is_LEM_connected) {
+    stub_result = h->lem_cb.send(__proxy_appid, h->lem_instance_id, parcel_, nullptr);
+    res_ = stub_result.ret;
+  } else {
+    res_ = rpc_port_parcel_send(parcel_, h->port);
+  }
+
   rpc_port_parcel_destroy(parcel_);
   if (res_ != RPC_PORT_ERROR_NONE)
     _E("Failed to send parcel. error(%d)", res_);
@@ -991,6 +1118,7 @@ R"__c_cb(
   rpc_port_unit_map_h map_;
   int seq_num_ = -1;
   int res_;
+  rpc_port_result_s stub_result;
   <RETURN_TYPE>ret_ = <ERROR_VALUE>;
   <METHOD_ARGS>
 
@@ -1000,7 +1128,7 @@ R"__c_cb(
     return ret_;
   }
 
-  if (h->port == nullptr) {
+  if (h->port == nullptr && h->is_LEM_connected == false) {
     _E("Not connected");
     set_last_result(RPC_PORT_ERROR_INVALID_PARAMETER);
     return ret_;
@@ -1035,7 +1163,12 @@ R"__c_cb(
 
 
   g_rec_mutex_lock(&h->mutex);
-  res_ = rpc_port_parcel_send(parcel_, h->port);
+  if (h->is_LEM_connected) {
+    stub_result = h->lem_cb.send(__proxy_appid, h->lem_instance_id, parcel_, nullptr);
+    res_ = stub_result.ret;
+  } else {
+    res_ = rpc_port_parcel_send(parcel_, h->port);
+  }
   rpc_port_parcel_destroy(parcel_);
   if (res_ != RPC_PORT_ERROR_NONE) {
     _E("Failed to send parcel. error(%d)", res_);
@@ -1046,8 +1179,12 @@ R"__c_cb(
 
   do {
     map_ = nullptr;
-    __<PREFIX>_<NAME>_consume_command(h->port, seq_num_, &map_);
-    if (parcel_ == nullptr) {
+    if (h->is_LEM_connected) {
+      map_ = stub_result.lem_ret;
+    } else {
+      __<PREFIX>_<NAME>_consume_command(h->port, seq_num_, &map_);
+    }
+    if (map_ == nullptr) {
       _E("Invalid protocol");
       res_ = RPC_PORT_ERROR_IO_ERROR;
       break;
index 828f298590d114ad777817bd586320dca020359b..d8c9e5ae325096ed6795df24d3d8e6f659496b55 100644 (file)
@@ -32,6 +32,7 @@ void CStubBodyGenerator::OnInitGen(std::ofstream& stream) {
   GenGNUSourceDefinition(stream);
   GenIncludeDefaultHeaders(stream);
   GenIncludePrivateHeaders(stream);
+  GenIncludeLemHeaders(stream);
   GenIncludeHeader(stream);
   GenLogTag(stream, std::string("RPC_PORT_STUB"));
   GenLogDefinition(stream);
@@ -40,6 +41,7 @@ void CStubBodyGenerator::OnInitGen(std::ofstream& stream) {
   GenThreadEnableDefinition(stream);
   GenInterfaceEnums(stream);
   GenUnitMapDefinition(stream);
+  GenLemDefinition(stream);
   GenInterfaceMethodHandlerType(stream);
   GenDelegateDefinition(stream);
   GenStructureDefinition(stream);
@@ -54,6 +56,11 @@ void CStubBodyGenerator::OnInitGen(std::ofstream& stream) {
 void CStubBodyGenerator::OnFiniGen(std::ofstream& stream) {
 }
 
+void CStubBodyGenerator::GenLemDefinition(std::ofstream& stream) {
+  GenLemBaseDefinition(stream);
+  stream << SmartIndent(CB_LEM_STUB_BASE_DEF);
+}
+
 void CStubBodyGenerator::GenIncludePrivateHeaders(std::ofstream& stream) {
   stream << CB_PRIVATE_HEADERS;
 }
@@ -816,6 +823,7 @@ void CStubBodyGenerator::GenInterfaceBase(std::ofstream& stream,
     const Interface& iface) {
   std::string code(ReplaceAll(CB_INTERFACE_BASE, {
       { "<PREFIX>", GetHandlePrefix() },
+      { "<PREFIX_REVERSE>", GetHandlePrefixReverse() },
       { "<NAME>", iface.GetID() },
       { "<ACCESS_CONTROL_SET>", GenAccessControlSet(iface) }
   }));
index 39439d67166b1694cf2d4f8f7c37025389cf05aa..91bd231fd31f8af133dfee9d9921f2ea8f36f3fa 100644 (file)
@@ -104,6 +104,7 @@ class CStubBodyGenerator : public CBodyGeneratorBase {
   std::string GenAccessControlSet(const Interface& iface);
   void GenDelegateDefinition(std::ofstream& stream);
   void GenDelegateBase(std::ofstream& stream);
+  void GenLemDefinition(std::ofstream& stream);
 
  private:
   std::shared_ptr<Options> options_;
index c94dfc3264e58ac77d4ffd872b575071e4b5d212..9d6c1998f89473f3b5feddfa9c3ca30d187b39ae 100644 (file)
@@ -23,6 +23,14 @@ R"__c_cb(
 #include <package_manager.h>
 )__c_cb";
 
+
+constexpr const char CB_LEM_STUB_BASE_DEF[] =
+R"__c_cb(
+typedef void (*rpc_port_proxy_LEM_init)(rpc_port_proxy_LEM_callback_s *cb);
+char *__stub_appid;
+
+)__c_cb";
+
 constexpr const char CB_DELEGATE_DEFS[] =
 R"__c_cb(
 typedef struct rpc_port_delegate_s {
@@ -103,7 +111,7 @@ R"__c_cb(
 
 constexpr const char CB_INTERFACE_METHOD_HANDLER_TYPE[] =
 R"__c_cb(
-typedef int (*rpc_port_stub_method_handler)(rpc_port_h port, rpc_port_parcel_h parcel, rpc_port_unit_map_h map, void *data);
+typedef rpc_port_result_s (*rpc_port_stub_method_handler)(rpc_port_h port, rpc_port_parcel_h parcel, rpc_port_unit_map_h map, void *data);
 )__c_cb";
 
 /**
@@ -185,6 +193,7 @@ typedef struct <PREFIX>_<NAME>_context_s {
   void *user_data;
   app_info_h app_info;
   GHashTable *privileges;
+  rpc_port_proxy_LEM_callback_s lem_cb;
 #ifdef TIDL_THREAD_ENABLE
   GThread *thread;
   GQueue *queue;
@@ -203,6 +212,7 @@ typedef int (*<PREFIX>_<NAME>_privilege_checker)(<PREFIX>_<NAME>_context_h h, bo
 constexpr const char CB_INTERFACE_CALLBACK_PORT_CHECK_DEF[] =
 R"__c_cb(
 static bool __<PREFIX>_<NAME>_exist_callback_port(rpc_port_h callback_port);
+static <PREFIX>_<NAME>_context_h __<PREFIX>_<NAME>_find_context(const char *instance);
 )__c_cb";
 
 /**
@@ -219,6 +229,7 @@ typedef struct <PREFIX>_<NAME>_<DELEGATE_NAME>_s {
   int seq_id;
   bool once;
   bool valid;
+  char *lem_instance;
 } <PREFIX>_<NAME>_<DELEGATE_NAME>_t;
 )__c_cb";
 
@@ -275,17 +286,18 @@ static void __<PREFIX>_<NAME>_throw_remote_exception(rpc_port_h port, rpc_port_p
   rpc_port_parcel_destroy(result_parcel);
 }
 
-static int __<PREFIX>_<NAME>_context_handle_request(<PREFIX>_<NAME>_context_h h, rpc_port_parcel_h parcel)
+static rpc_port_result_s __<PREFIX>_<NAME>_context_handle_request(<PREFIX>_<NAME>_context_h h, rpc_port_parcel_h parcel)
 {
-  int ret = RPC_PORT_ERROR_NONE;
   int cmd = -1;
   rpc_port_unit_map_h map;
   bool sync = false;
+  rpc_port_result_s stub_result = { 0, };
 
   map = rpc_port_unit_map_create();
   if (map == nullptr) {
     _E("Failed to create unit map");
-    return RPC_PORT_ERROR_OUT_OF_MEMORY;
+    stub_result.ret = RPC_PORT_ERROR_OUT_OF_MEMORY;
+    return stub_result;
   }
 
   rpc_port_parcel_read(parcel, &map->parcelable, map);
@@ -293,26 +305,27 @@ static int __<PREFIX>_<NAME>_context_handle_request(<PREFIX>_<NAME>_context_h h,
   rpc_port_unit_map_read_int(map, "[METHOD]", &cmd);
 
   if (cmd > 1 && cmd < ARRAY_SIZE(__<NAME>_method_table)) {
-    if (h->app_info && __<NAME>_privilege_checkers[cmd]) {
-      ret = __<NAME>_privilege_checkers[cmd](h, &sync);
-      if (ret != RPC_PORT_ERROR_NONE) {
+    if (h->lem_cb.is_LEM == false && h->app_info && __<NAME>_privilege_checkers[cmd]) {
+      stub_result.ret = __<NAME>_privilege_checkers[cmd](h, &sync);
+      if (stub_result.ret != RPC_PORT_ERROR_NONE) {
         rpc_port_unit_map_destroy(map);
         if (sync)
-          __<PREFIX>_<NAME>_throw_remote_exception(h->port, parcel, ret, "Permission denied");
+          __<PREFIX>_<NAME>_throw_remote_exception(h->port, parcel, stub_result.ret, "Permission denied");
 
-        return RPC_PORT_ERROR_NONE;
+        stub_result.ret = RPC_PORT_ERROR_NONE;
+        return stub_result;
       }
     }
 
     if (__<NAME>_method_table[cmd])
-      ret = __<NAME>_method_table[cmd](h->port, parcel, map, h);
+      stub_result = __<NAME>_method_table[cmd](h->port, parcel, map, h);
   } else {
     _W("Invalid protocol. cmd(%d)", cmd);
-    ret = RPC_PORT_ERROR_INVALID_PARAMETER;
+    stub_result.ret = RPC_PORT_ERROR_INVALID_PARAMETER;
   }
   rpc_port_unit_map_destroy(map);
 
-  return ret;
+  return stub_result;
 }
 
 #ifdef TIDL_THREAD_ENABLE
@@ -462,11 +475,16 @@ static int __<PREFIX>_<NAME>_context_load_privileges(<PREFIX>_<NAME>_context_h h
   return ret;
 }
 
-static <PREFIX>_<NAME>_context_h __<PREFIX>_<NAME>_context_create(const char *sender, const char *instance, rpc_port_h callback_port)
+static <PREFIX>_<NAME>_context_h __<PREFIX>_<NAME>_context_create(const char *sender, const char *instance, rpc_port_h callback_port, rpc_port_proxy_LEM_callback_s *lem_cb)
 {
   <PREFIX>_<NAME>_context_t *handle;
 
-  if (sender == nullptr || instance == nullptr || callback_port == nullptr) {
+  if (sender == nullptr || instance == nullptr) {
+    _E("Invalid parameter");
+    return nullptr;
+  }
+
+  if (lem_cb->is_LEM == false && callback_port == nullptr) {
     _E("Invalid parameter");
     return nullptr;
   }
@@ -522,6 +540,7 @@ static <PREFIX>_<NAME>_context_h __<PREFIX>_<NAME>_context_create(const char *se
   }
 #endif /* TIDL_THREAD_ENABLE */
 
+  handle->lem_cb = *lem_cb;
   handle->callback_port = callback_port;
   handle->callback = __<NAME>.callback;
   handle->user_data = __<NAME>.user_data;
@@ -529,6 +548,53 @@ static <PREFIX>_<NAME>_context_h __<PREFIX>_<NAME>_context_create(const char *se
   return handle;
 }
 
+static <PREFIX>_<NAME>_context_h __<PREFIX>_<NAME>_find_context(const char *instance)
+{
+  <PREFIX>_<NAME>_context_h context;
+  GList *iter;
+
+  g_rec_mutex_lock(&__<NAME>.mutex);
+  iter = __<NAME>.contexts;
+  while (iter) {
+    context = iter->data;
+    if (!strcmp(context->instance, instance)) {
+      g_rec_mutex_unlock(&__<NAME>.mutex);
+      return context;
+    }
+
+    iter = g_list_next(iter);
+  }
+  g_rec_mutex_unlock(&__<NAME>.mutex);
+
+  return nullptr;
+}
+
+static void __<PREFIX>_<NAME>_add_context(<PREFIX>_<NAME>_context_h context)
+{
+  g_rec_mutex_lock(&__<NAME>.mutex);
+  __<NAME>.contexts = g_list_append(__<NAME>.contexts, context);
+  g_rec_mutex_unlock(&__<NAME>.mutex);
+}
+
+static void __<PREFIX>_<NAME>_remove_context(<PREFIX>_<NAME>_context_h context)
+{
+  g_rec_mutex_lock(&__<NAME>.mutex);
+  __<NAME>.contexts = g_list_remove(__<NAME>.contexts, context);
+  g_rec_mutex_unlock(&__<NAME>.mutex);
+}
+
+static void __<PREFIX>_<NAME>_clear_context(gpointer data)
+{
+  <PREFIX>_<NAME>_context_h context = data;
+
+  if (context->lem_cb.is_LEM) {
+    _I("LEM disconnect %s:<NAME>", __stub_appid);
+    context->lem_cb.disconnect(__stub_appid, "<NAME>", context->lem_cb.user_data);
+    __<PREFIX>_<NAME>_remove_context(context);
+  }
+  __<PREFIX>_<NAME>_context_destroy(context);
+}
+
 int <PREFIX>_<NAME>_context_set_tag(<PREFIX>_<NAME>_context_h context, void *tag)
 {
   if (context == nullptr) {
@@ -595,7 +661,7 @@ int <PREFIX>_<NAME>_context_get_instance(<PREFIX>_<NAME>_context_h context, char
 
 int <PREFIX>_<NAME>_context_disconnect(<PREFIX>_<NAME>_context_h context)
 {
-  int ret;
+  int ret = RPC_PORT_ERROR_NONE;
 
   if (context == nullptr) {
     _E("Invalid parameter");
@@ -604,49 +670,21 @@ int <PREFIX>_<NAME>_context_disconnect(<PREFIX>_<NAME>_context_h context)
 
   g_rec_mutex_lock(&__<NAME>.mutex);
 
-  ret = rpc_port_disconnect(context->callback_port);
-  if (ret != RPC_PORT_ERROR_NONE)
-    _E("Failed to disconnect. error(%d)", ret);
-
-  g_rec_mutex_unlock(&__<NAME>.mutex);
-
-  return ret;
-}
-
-static <PREFIX>_<NAME>_context_h __<PREFIX>_<NAME>_find_context(const char *instance)
-{
-  <PREFIX>_<NAME>_context_h context;
-  GList *iter;
-
-  g_rec_mutex_lock(&__<NAME>.mutex);
-  iter = __<NAME>.contexts;
-  while (iter) {
-    context = iter->data;
-    if (!strcmp(context->instance, instance)) {
-      g_rec_mutex_unlock(&__<NAME>.mutex);
-      return context;
-    }
-
-    iter = g_list_next(iter);
+  if (context->lem_cb.is_LEM) {
+    _I("LEM disconnect %s:<NAME>", __stub_appid);
+    context->lem_cb.disconnect(__stub_appid, "<NAME>", context->lem_cb.user_data);
+    __<PREFIX>_<NAME>_remove_context(context);
+    __<PREFIX>_<NAME>_context_destroy(context);
+  } else {
+    ret = rpc_port_disconnect(context->callback_port);
+    if (ret != RPC_PORT_ERROR_NONE)
+      _E("Failed to disconnect. error(%d)", ret);
   }
   g_rec_mutex_unlock(&__<NAME>.mutex);
 
-  return nullptr;
-}
-
-static void __<PREFIX>_<NAME>_add_context(<PREFIX>_<NAME>_context_h context)
-{
-  g_rec_mutex_lock(&__<NAME>.mutex);
-  __<NAME>.contexts = g_list_append(__<NAME>.contexts, context);
-  g_rec_mutex_unlock(&__<NAME>.mutex);
+  return ret;
 }
 
-static void __<PREFIX>_<NAME>_remove_context(<PREFIX>_<NAME>_context_h context)
-{
-  g_rec_mutex_lock(&__<NAME>.mutex);
-  __<NAME>.contexts = g_list_remove(__<NAME>.contexts, context);
-  g_rec_mutex_unlock(&__<NAME>.mutex);
-}
 )__c_cb";
 
 /**
@@ -773,6 +811,9 @@ int <PREFIX>_<NAME>_<DELEGATE_NAME>_destroy(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h)
 
   _W("id(%d), seq_id(%d), once(%s)", h->id, h->seq_id, h->once ? "true" : "false");
 
+  if (h->lem_instance)
+    free(h->lem_instance);
+
   free(h);
 
   return RPC_PORT_ERROR_NONE;
@@ -806,6 +847,15 @@ int <PREFIX>_<NAME>_<DELEGATE_NAME>_clone(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, <
 
   (*clone)->port = h->port;
 
+  if (h->lem_instance) {
+    (*clone)->lem_instance = strdup(h->lem_instance);
+    if ((*clone)->lem_instance == nullptr) {
+      _E("Out of memory");
+      <PREFIX>_<NAME>_<DELEGATE_NAME>_destroy(*clone);
+      return RPC_PORT_ERROR_OUT_OF_MEMORY;
+    }
+  }
+
   return ret;
 }
 
@@ -884,15 +934,28 @@ int <PREFIX>_<NAME>_<DELEGATE_NAME>_invoke(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h<D
   rpc_port_parcel_h parcel_;
   int ret_;
   rpc_port_unit_map_h map_;
+  <PREFIX>_<NAME>_context_h context = nullptr;
 
-  if (h == nullptr || h->port == nullptr<DELEGATE_PARAMS_CHECK>) {
+  if (h == nullptr <DELEGATE_PARAMS_CHECK>) {
     _E("Invalid parameter");
     return RPC_PORT_ERROR_INVALID_PARAMETER;
   }
 
-  if (!__<PREFIX>_<NAME>_exist_callback_port(h->port)) {
-    _E("Not connected");
-    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  if (h->lem_instance) {
+    context = __<PREFIX>_<NAME>_find_context(h->lem_instance);
+    if (context == nullptr)   {
+       _E("Not connected");
+      return RPC_PORT_ERROR_INVALID_PARAMETER;
+    }
+  } else {
+    if (h->port == nullptr) {
+      _E("Invalid parameter");
+      return RPC_PORT_ERROR_INVALID_PARAMETER;
+    }
+    if (!__<PREFIX>_<NAME>_exist_callback_port(h->port)) {
+      _E("Not connected");
+      return RPC_PORT_ERROR_INVALID_PARAMETER;
+    }
   }
 
   if (h->once && !h->valid) {
@@ -919,10 +982,14 @@ int <PREFIX>_<NAME>_<DELEGATE_NAME>_invoke(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h<D
   rpc_port_unit_map_write_delegate(map_, "delegate", (rpc_port_delegate_h)h);
 
   <DELEGATE_UNIT_MAP_WRITE>
-  rpc_port_parcel_write(parcel_, &map_->parcelable, map_);
+    if (context && context->lem_cb.is_LEM) {
+    ret_ = context->lem_cb.send("endpoint", "Message", map_, context->lem_cb.user_data);
+  } else {
+    rpc_port_parcel_write(parcel_, &map_->parcelable, map_);
+    ret_ = rpc_port_parcel_send(parcel_, h->port);
+  }
 
   rpc_port_unit_map_destroy(map_);
-  ret_ = rpc_port_parcel_send(parcel_, h->port);
   rpc_port_parcel_destroy(parcel_);
   h->valid = false;
 
@@ -1047,8 +1114,17 @@ if (ret_ != RPC_PORT_ERROR_NONE) {
   _E("Failed to read delegate. error(%d)", ret_);
   goto out;
 }
-<PREFIX>_<TYPE_NAME>_set_port(<ARG>, callback_port_);
 
+if (context_->lem_cb.is_LEM) {
+  <ARG>->lem_instance = strdup(context_->instance);
+  if (<ARG>->lem_instance == nullptr) {
+    _E("Failed to duplicate sender");
+    ret_ = RPC_PORT_ERROR_OUT_OF_MEMORY;
+    goto out;
+  }
+} else {
+  <PREFIX>_<TYPE_NAME>_set_port(<ARG>, callback_port_);
+}
 )__c_cb";
 
 
@@ -1079,20 +1155,23 @@ if (ret_ != RPC_PORT_ERROR_NONE) {
  */
 constexpr const char CB_INTERFACE_METHOD_HANDLER_BASE[] =
 R"__c_cb(
-static int __<PREFIX>_<NAME>_method_<METHOD_NAME>_handler(rpc_port_h port, rpc_port_parcel_h parcel, rpc_port_unit_map_h map, void *user_data)
+static rpc_port_result_s __<PREFIX>_<NAME>_method_<METHOD_NAME>_handler(rpc_port_h port, rpc_port_parcel_h parcel, rpc_port_unit_map_h map, void *user_data)
 {
   <PREFIX>_<NAME>_context_h context_ = user_data;
   rpc_port_parcel_header_h header_;
   int seq_num_ = -1;
   rpc_port_h callback_port_;
-  int ret_;
+  int ret_ = RPC_PORT_ERROR_NONE;
+  rpc_port_result_s stub_result_ = { 0, };
 
   <METHOD_HANDLER_ARGS_DECL>
 
-  ret_ = rpc_port_stub_get_port(__<NAME>.stub, RPC_PORT_PORT_CALLBACK, context_->instance, &callback_port_);
-  if (ret_ != RPC_PORT_ERROR_NONE) {
-    _E("Failed to get callback port. error(%d)", ret_);
-    goto out;
+  if (context_->lem_cb.is_LEM == false) {
+    ret_ = rpc_port_stub_get_port(__<NAME>.stub, RPC_PORT_PORT_CALLBACK, context_->instance, &callback_port_);
+    if (ret_ != RPC_PORT_ERROR_NONE) {
+      _E("Failed to get callback port. error(%d)", ret_);
+      goto out;
+    }
   }
 
   rpc_port_parcel_get_header(parcel, &header_);
@@ -1105,7 +1184,8 @@ static int __<PREFIX>_<NAME>_method_<METHOD_NAME>_handler(rpc_port_h port, rpc_p
 out:
   <METHOD_HANDLER_ARGS_FREE>
 
-  return ret_;
+  stub_result_.ret = ret_;
+  return stub_result_;
 }
 )__c_cb";
 
@@ -1241,11 +1321,15 @@ R"__c_cb(
 if (__<PREFIX>_<NAME>_remote_exception != nullptr)
   rpc_port_unit_map_write_<NAME>_remote_exception(map_, "[REMOTE_EXCEPTION]", __<PREFIX>_<NAME>_remote_exception);
 
-rpc_port_parcel_write(parcel_, &map_->parcelable, map_);
-rpc_port_unit_map_destroy(map_);
+ if (context_->lem_cb.is_LEM) {
+  stub_result_.lem_ret = map_;
+} else {
+  rpc_port_parcel_write(parcel_, &map_->parcelable, map_);
+  rpc_port_unit_map_destroy(map_);
 
-ret_ = rpc_port_parcel_send(parcel_, port);
-rpc_port_parcel_destroy(parcel_);
+  ret_ = rpc_port_parcel_send(parcel_, port);
+  rpc_port_parcel_destroy(parcel_);
+}
 
 )__c_cb";
 
@@ -1326,21 +1410,47 @@ static void __<PREFIX>_<NAME>_connected_event_cb(const char *sender, const char
   <PREFIX>_<NAME>_context_h context;
   rpc_port_h callback_port = nullptr;
   int ret;
-
+  rpc_port_proxy_LEM_callback_s lem_cb = { 0, };
+  rpc_port_proxy_LEM_init lem_init;
+
+  if (__stub_appid == nullptr)
+    app_get_id(&__stub_appid);
+
+  if (__stub_appid != nullptr) {
+    if (!strcmp(__stub_appid, sender)) {
+      void *plugin_handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
+      if (plugin_handle) {
+        lem_init = dlsym(plugin_handle, "<PREFIX_REVERSE>_<NAME>_LEM_init");
+        if (lem_init)
+          lem_init(&lem_cb);
+      }
+    }
+  }
   _W("sender(%s), instance(%s)", sender, instance);
-  ret = rpc_port_stub_get_port(__<NAME>.stub, RPC_PORT_PORT_CALLBACK, instance, &callback_port);
-  if (ret != RPC_PORT_ERROR_NONE) {
-    _E("Failed to get callback port. error(%d)", ret);
-    return;
+  if (lem_cb.is_LEM == false) {
+    ret = rpc_port_stub_get_port(__<NAME>.stub, RPC_PORT_PORT_CALLBACK, instance, &callback_port);
+    if (ret != RPC_PORT_ERROR_NONE) {
+      _E("Failed to get callback port. error(%d)", ret);
+      return;
+    }
   }
 
-  context = __<PREFIX>_<NAME>_context_create(sender, instance, callback_port);
-  if (context == nullptr)
+  context = __<PREFIX>_<NAME>_context_create(sender, instance, callback_port, &lem_cb);
+  if (context == nullptr) {
+    if (lem_cb.is_LEM)
+      *((int *)user_data) = RPC_PORT_ERROR_IO_ERROR;
     return;
+  }
 
   __<PREFIX>_<NAME>_add_context(context);
-  __<PREFIX>_<NAME>_add_callback_port(context->callback_port);
+
+  if (lem_cb.is_LEM == false)
+    __<PREFIX>_<NAME>_add_callback_port(context->callback_port);
+
   context->callback.create(context, context->user_data);
+
+  if (lem_cb.is_LEM)
+    *((int *)user_data) = RPC_PORT_ERROR_NONE;
 }
 
 static void __<PREFIX>_<NAME>_disconnected_event_cb(const char *sender, const char *instance, void *user_data)
@@ -1353,7 +1463,9 @@ static void __<PREFIX>_<NAME>_disconnected_event_cb(const char *sender, const ch
   if (context == nullptr)
     return;
 
-  __<PREFIX>_<NAME>_remove_callback_port(context->callback_port);
+  if (context->lem_cb.is_LEM == false)
+    __<PREFIX>_<NAME>_remove_callback_port(context->callback_port);
+
   context->callback.terminate(context, context->user_data);
   __<PREFIX>_<NAME>_remove_context(context);
   __<PREFIX>_<NAME>_context_destroy(context);
@@ -1364,6 +1476,7 @@ static int __<PREFIX>_<NAME>_received_event_cb(const char *sender, const char *i
   <PREFIX>_<NAME>_context_h context;
   rpc_port_parcel_h parcel;
   int ret;
+  rpc_port_result_s stub_result = { 0, };
 
   _W("sender(%s), instance(%s)", sender, instance);
   context = __<PREFIX>_<NAME>_find_context(instance);
@@ -1380,13 +1493,42 @@ static int __<PREFIX>_<NAME>_received_event_cb(const char *sender, const char *i
   }
 
 #ifdef TIDL_THREAD_ENABLE
-  ret = __<PREFIX>_<NAME>_context_push(context, parcel);
+  stub_result.ret = __<PREFIX>_<NAME>_context_push(context, parcel);
 #else
-  ret = __<PREFIX>_<NAME>_context_handle_request(context, parcel);
+  stub_result = __<PREFIX>_<NAME>_context_handle_request(context, parcel);
   rpc_port_parcel_destroy(parcel);
 #endif /* TIDL_THREAD_ENABLE */
 
-  return ret;
+  return stub_result.ret;
+}
+
+rpc_port_result_s __<PREFIX>_<NAME>_LEM_received_event_cb(const char *sender, const char *instance, rpc_port_parcel_h parcel, void *user_data)
+{
+  <PREFIX>_<NAME>_context_h context;
+  rpc_port_result_s stub_result = { 0, };
+
+  _W("sender(%s), instance(%s)", sender, instance);
+  context = __<PREFIX>_<NAME>_find_context(instance);
+  if (context == nullptr) {
+    _E("Failed to find context. instance(%s)", instance);
+    stub_result.ret = RPC_PORT_ERROR_INVALID_PARAMETER;
+    return stub_result;
+  }
+
+  stub_result = __<PREFIX>_<NAME>_context_handle_request(context, parcel);
+
+  return stub_result;
+}
+
+static bool __<PREFIX>_<NAME>_received_event_cb_is_listen() {
+   return __<NAME>.stub != NULL;
+}
+
+EXPORT_API void <PREFIX>_<NAME>_LEM_init(rpc_port_stub_LEM_callback_s *cb) {
+  cb->connect = __<PREFIX>_<NAME>_connected_event_cb;
+  cb->disconnect = __<PREFIX>_<NAME>_disconnected_event_cb;
+  cb->send = __<PREFIX>_<NAME>_LEM_received_event_cb;
+  cb->is_listen = __<PREFIX>_<NAME>_received_event_cb_is_listen;
 }
 
 static int __<PREFIX>_<NAME>_set_access_control(void)
@@ -1471,7 +1613,7 @@ int <PREFIX>_<NAME>_unregister(void)
   g_rec_mutex_clear(&__<NAME>.mutex);
 
   if (__<NAME>.contexts) {
-    g_list_free_full(__<NAME>.contexts, __<PREFIX>_<NAME>_context_destroy);
+    g_list_free_full(__<NAME>.contexts, __<PREFIX>_<NAME>_clear_context);
     __<NAME>.contexts = nullptr;
   }
 
index dc629f9da2a01ede2e9f7508cb240553c881e7d0..85689a5eefec4ebe7cdf0a055b1c143636be1d12 100644 (file)
@@ -120,6 +120,6 @@ ADD_EXECUTABLE(${TARGET_TIDL_BUILD_TESTS}
   ${TIDL_GEN_SRCS}
 )
 
-TARGET_LINK_LIBRARIES(${TARGET_TIDL_BUILD_TESTS} ${PKGS_LDFLAGS} "-lpthread")
+TARGET_LINK_LIBRARIES(${TARGET_TIDL_BUILD_TESTS} ${PKGS_LDFLAGS} "-ldl -lpthread")
 
 INSTALL(TARGETS ${TARGET_TIDL_BUILD_TESTS} DESTINATION bin)