Support Local Execution Mode for C# Generator 58/298758/4
authorjusung son <jusung07.son@samsung.com>
Wed, 13 Sep 2023 07:16:47 +0000 (16:16 +0900)
committerjusung son <jusung07.son@samsung.com>
Thu, 14 Sep 2023 01:41:03 +0000 (01:41 +0000)
Change-Id: I334e779f472e3a6b0fe7c128db69c3eed21b8621
Signed-off-by: jusung son <jusung07.son@samsung.com>
idlc/gen/version2/cs_generator_base.cc
idlc/gen/version2/cs_generator_base.h
idlc/gen/version2/cs_generator_base_cb.h
idlc/gen/version2/cs_proxy_generator.cc
idlc/gen/version2/cs_proxy_generator.h
idlc/gen/version2/cs_proxy_generator_cb.h
idlc/gen/version2/cs_stub_generator.cc
idlc/gen/version2/cs_stub_generator.h
idlc/gen/version2/cs_stub_generator_cb.h

index 17dadfe..8c7aa5d 100644 (file)
@@ -385,11 +385,9 @@ std::string CsGeneratorBase::ConvertTypeToDeserializer(
   ret += map + ".Read(" + "\"" + param_id + "\", out ";
   if (IsDelegateType(type)) {
     ret += "CallbackBase del_" + gen_id + ");\n";
-    ret +=
-        new_type + " " + gen_id + " = new " + new_type +
-        "(GetPort(Port.Type.Callback, instance), new WeakReference(b), del_" +
-        gen_id + ");\n";
-
+    ret += ReplaceAll(CB_DLELGATGE_CREATE)
+                    .Change("<TYPE>", new_type)
+                    .Change("<GEN_ID>", gen_id);
   } else {
     if (make_new_type) {
       ret += new_type + " " + gen_id + ");\n";
@@ -855,7 +853,7 @@ void CsGeneratorBase::GenInvokeMethod(std::ofstream& stream,
         for (const auto& i : decl.GetParameters()) {
           m += ConvertTypeToSerializer(i->GetID(), i->GetID(), "map");
         }
-        return AddIndent(TAB_SIZE * 6, m);
+        return AddIndent(TAB_SIZE * 5, m);
       });
 }
 
index f177206..39ffa75 100644 (file)
@@ -106,10 +106,10 @@ class CsGeneratorBase : public Generator {
   std::string GenUnitMapParamInit(const Interface& iface,
                                   const BaseType& base_type,
                                   const std::string& type_str);
-    std::string GetStructureSerialize(const Structure& st);
-    std::string GetStructureDeserialize(const Structure& st);
-    std::string GetStructTypeString(const BaseType& base_type);
-    std::string GetStructTypeString(const Structure& st);
+  std::string GetStructureSerialize(const Structure& st);
+  std::string GetStructureDeserialize(const Structure& st);
+  std::string GetStructTypeString(const BaseType& base_type);
+  std::string GetStructTypeString(const Structure& st);
 
  private:
   std::map<std::string, std::string> type_map_;
index 638438f..60aae64 100644 (file)
@@ -21,12 +21,14 @@ const char CB_USING_NAMESPACE[] =
 R"__cs_cb(
 using System;
 using System.Collections.Generic;
+using System.Collections.Concurrent;
+using System.Threading;
+using System.Reflection;
 using Tizen.Applications;
 using Tizen.Applications.RPCPort;
 
 )__cs_cb";
 
-
 const char CB_REMOTE_EXCEPTION_BASE[] =
 R"__cs_cb(
     public class RemoteException : Exception
@@ -253,33 +255,40 @@ const char CB_CALLBACK_STUB_MEMBERS[] =
 R"__cs_cb(                private Port _port;
                 private WeakReference _service;
                 private bool _valid = true;
-
+                internal LocalExecution _lem;
 )__cs_cb";
 
 const char CB_CALLBACK_INVOKE_METHOD[] =
 R"__cs_cb(
                 public void Invoke($$)
                 {
-                    if (_port == null)
+                    if (_port == null && _lem == null)
                         throw new NotConnectedSocketException();
                     if (!_service.IsAlive)
                         throw new InvalidProtocolException();
                     if (Once && !_valid)
                         throw new InvalidCallbackException();
+                    if (_lem != null && _lem._online == false)
+                        throw new NotConnectedSocketException();
 
-                    using (var p = new Parcel())
-                    {
-                        UnitMap map = new UnitMap();
+                    var p = new Parcel();
+                    UnitMap map = new UnitMap();
 
-                        map.Write("[METHOD]", (int)MethodId.__Callback);
-                        map.Write("delegate", this);
+                    map.Write("[METHOD]", (int)MethodId.__Callback);
+                    map.Write("delegate", this);
 
 $$
-                        map.Serialize(p);
+                    map.Serialize(p);
+
+                    if (_lem != null)
+                    {
+                        _lem.SendRequest(p);
+                    } else
+                    {
                         // Send
                         p.Send(_port);
-                        _valid = false;
                     }
+                    _valid = false;
                 }
 )__cs_cb";
 
@@ -293,6 +302,21 @@ $$
         }
 )__cs_cb";
 
+const char CB_DLELGATGE_CREATE[] =
+R"__cs_cb(
+Port cb_port;
+if (b._lem != null)
+    cb_port = null;
+else
+    cb_port = GetPort(Port.Type.Callback, instance);
+
+<TYPE> <GEN_ID>  = new <TYPE>(cb_port, new WeakReference(b), del_<GEN_ID>);
+
+if (b._lem != null)
+    param3._lem = b._lem;
+)__cs_cb";
+
+
 const char CB_WRITE_BUNDLE[] =
 R"__cs_cb(
                 if (param.$$ != null)
index bf8e5bd..8218a32 100644 (file)
@@ -39,6 +39,7 @@ void CsProxyGen::GenNamespace(std::ofstream& stream) {
   GenBrace(stream, 0, [&]() {
     stream << "namespace " << GetFileNamespace() << NLine(1);
     GenBrace(stream, 0, [&]() {
+      GenLemBase(stream);
       GenRemoteException(stream);
       GenStructures(stream);
       stream << Tab(1) << "namespace Proxy" << NLine(1);
@@ -49,6 +50,10 @@ void CsProxyGen::GenNamespace(std::ofstream& stream) {
   });
 }
 
+void CsProxyGen::GenLemBase(std::ofstream& stream) {
+  stream << CB_LEM_BASE;
+}
+
 void CsProxyGen::GenInterfaces(std::ofstream& stream) {
   for (auto& i : GetDocument().GetBlocks()) {
     if (i->GetType() != Block::TYPE_INTERFACE) continue;
@@ -97,11 +102,9 @@ void CsProxyGen::GenEventMethod(std::ofstream& stream, const Interface& iface) {
 }
 
 void CsProxyGen::GenCtor(std::ofstream& stream, const Interface& iface) {
-  const char* m = "public $$(string appId) => _appId = appId;\n";
-
-  stream << NLine(1);
-  GenTemplate(AddIndent(TAB_SIZE * 3, m), stream,
-              [&]() -> std::string { return iface.GetID(); });
+  ReplaceAll(CB_CONSTRUCTOR_METHOD)
+      .Change("<NAME>", iface.GetID())
+      .Out(stream);
 }
 
 void CsProxyGen::GenConnectMethod(std::ofstream& stream,
@@ -179,12 +182,15 @@ void CsProxyGen::GenInvocation(std::ofstream& stream, const Declaration& decl) {
     st += Tab(5) + "{" + NLine(1);
     if (!l.empty()) st += AddIndent(TAB_SIZE * 6, l) + NLine(1);
 
-    st += CB_INVOCATION_MID + NLine(1);
+
 
     // Deserialize
     if (decl.GetMethodType() == Declaration::MethodType::ASYNC) {
+      st += CB_INVOCATION_ASYNC_MID + NLine(1);
       st += Tab(5) + "}";
       return st;
+    } else {
+      st += CB_INVOCATION_SYNC_MID + NLine(1);
     }
 
     st += NLine(1) + AddIndent(TAB_SIZE * 5, CB_INVOCATION_RECEIVE);
index 03850f1..a929041 100644 (file)
@@ -43,6 +43,7 @@ class CsProxyGen : public CsGeneratorBase {
   void GenInvocation(std::ofstream& stream, const Declaration& decl);
   void GenEventMethod(std::ofstream& stream, const Interface& iface);
   void GenMemberData(std::ofstream& stream, const Interface& iface);
+  void GenLemBase(std::ofstream& stream);
 };
 
 }  // namespace version2
index 81d4955..4901392 100644 (file)
@@ -29,17 +29,154 @@ R"__cs_cb(            public event EventHandler Connected;
             private bool _online = false;
             private string _appId;
             private Object _lock = new Object();
+            private bool _connecting = false;
+            private LocalExecution _lem;
+            private SynchronizationContext _async_context = TizenSynchronizationContext.Current;
 <CALLBACK_LIST>
 )__cs_cb";
 
+
+const char CB_LEM_BASE[] =
+R"__cs_cb(    internal class LocalExecution
+    {
+        internal bool IsListen = false;
+        object _instance = null;
+        string _instance_id = null;
+        string _appId = null;
+        static int _seq = 0;
+        MethodInfo _send = null;
+        MethodInfo _connect = null;
+        MethodInfo _disconnect = null;
+        ConcurrentQueue<Parcel> _result = new ConcurrentQueue<Parcel>();
+
+        internal LocalExecution(string appId,  string interfaceName)
+        {
+            string current_appid = Application.Current.ApplicationInfo.ApplicationId;
+
+            if (current_appid != appId)
+                return;
+
+            _seq++;
+            _instance_id = appId + "::" + _seq.ToString();
+            _appId = appId;
+
+            Assembly assembly = Assembly.GetExecutingAssembly();
+            Type type = null;
+
+            foreach (Type t in assembly.GetTypes())
+            {
+                if (t.Name != interfaceName)
+                    continue;
+
+                string[] name = t.FullName?.Split('.');
+
+                if (name == null || name.Length != 4)
+                    continue;
+
+                if (name[0] == "RPCPort" && name[2] == "Stub")
+                {
+                    if (type == null)
+                    {
+                        type = t;
+                    }
+                    else
+                    {
+                        type = null;
+                        break;
+                    }
+                }
+            }
+
+            if (type == null)
+                return;
+
+            MethodInfo getInstance = type.GetMethod("GetInstance", BindingFlags.Static | BindingFlags.NonPublic);
+            if (getInstance == null) { return; }
+
+            _instance = getInstance.Invoke(null, null);
+            if (_instance == null) { return; }
+
+            _send = type.GetMethod("OnLemReceivedEvent", BindingFlags.NonPublic | BindingFlags.Instance);
+            if (_send == null) { return; }
+
+            _connect = type.GetMethod("OnLemConnectedEvent", BindingFlags.NonPublic | BindingFlags.Instance);
+            if (_connect == null) { return; }
+
+            _disconnect = type.GetMethod("OnLemDisconnectedEvent", BindingFlags.NonPublic | BindingFlags.Instance);
+            if (_disconnect == null) { return; }
+
+            MethodInfo getListen = type.GetMethod("GetListenStatus", BindingFlags.NonPublic | BindingFlags.Instance);
+            if (getListen == null) { return; }
+
+            object ret = getListen.Invoke(_instance, null);
+            if (ret == null) { return; }
+            IsListen = (bool)ret;
+        }
+
+        internal void Connect(object proxy_instance)
+        {
+            _connect.Invoke(_instance, new object[] { proxy_instance, _appId, _instance_id });
+        }
+
+        internal void Disconnect()
+        {
+            _disconnect.Invoke(_instance, new object[] { _appId, _instance_id });
+        }
+
+        internal void Send(Parcel p)
+        {
+            _send.Invoke(_instance, new object[] { _instance_id, p});
+        }
+
+        internal void Send(Parcel p, ref Parcel resutl)
+        {
+            Send(p);
+
+            int count = 0;
+            while (_result.IsEmpty && count++ < 100)
+                Thread.Sleep(100);
+
+            if (ResultQueuePop(out resutl))
+            {
+                Tizen.Log.Error("RPC_PORT", "ResultQueuePop");
+                return;
+            }
+
+            Tizen.Log.Error("RPC_PORT_PROXY", "Failed to get result from server");
+            throw new InvalidIOException();
+        }
+
+        internal void ResultQueuePush(Parcel p)
+        {
+            _result.Enqueue(p);
+        }
+
+        internal bool ResultQueuePop(out Parcel p)
+        {
+            return _result.TryDequeue(out p);
+        }
+    }
+)__cs_cb";
+
 const char CB_DATA_CALLBACK_LIST[] =
 R"__cs_cb(
             private List<CallbackBase> _delegateList = new List<CallbackBase>();
 )__cs_cb";
 const char CB_EVENT_PROCESS_EVENT_BASE[] =
 R"__cs_cb(
-            private void ProcessReceivedEvent(UnitMap map)
+            private void ProcessReceivedEvent(Parcel parcelReceived)
             {
+                UnitMap map = new UnitMap();
+                map.Deserialize(parcelReceived);
+
+                int cmd;
+                map.Read("[METHOD]", out cmd);
+
+                if (cmd != (int)MethodId.__Callback)
+                {
+                    return;
+                }
+
                 CallbackBase cb;
                 map.Read("delegate", out cb);
 
@@ -54,6 +191,16 @@ R"__cs_cb(
                     }
                 }
             }
+
+            internal void OnLemReceivedEvent(Parcel parcelReceived)
+            {
+                _async_context.Post((data) =>
+                {
+                    ProcessReceivedEvent(parcelReceived);
+
+                }, null);
+            }
+
 )__cs_cb";
 
 const char CB_EVENT_RECEIVE_EVENT_BASE[] =
@@ -70,18 +217,7 @@ R"__cs_cb(            Parcel parcelReceived;
 
                 using (parcelReceived)
                 {
-                    UnitMap map = new UnitMap();
-                    map.Deserialize(parcelReceived);
-
-                    int cmd;
-                    map.Read("[METHOD]", out cmd);
-
-                    if (cmd != (int)MethodId.__Callback)
-                    {
-                        return;
-                    }
-
-                    ProcessReceivedEvent(map);
+                    ProcessReceivedEvent(parcelReceived);
                 }
 )__cs_cb";
 
@@ -90,6 +226,7 @@ R"__cs_cb(
             protected override void OnConnectedEvent(string endPoint, string portName, Port port)
             {
                 _online = true;
+                _connecting = false;
                 Connected?.Invoke(this, null);
             }
 
@@ -99,8 +236,24 @@ R"__cs_cb(
                 Disconnected?.Invoke(this, null);
             }
 
+            internal void OnLemDisconnectedEvent()
+            {
+                _async_context.Post((data) =>
+                {
+                    OnDisconnectedEvent(null, null);
+
+                }, null);
+
+            }
+
+            internal void OnLemResultEvent(Parcel result)
+            {
+                    _lem.ResultQueuePush(result);
+            }
+
             protected override void OnRejectedEvent(string endPoint, string portName)
             {
+                _connecting = false;
                 Rejected?.Invoke(this, null);
             }
 <PROCESS_EVENT_BASE>
@@ -163,6 +316,15 @@ R"__cs_cb(
             }
 )__cs_cb";
 
+const char CB_CONSTRUCTOR_METHOD[] =
+R"__cs_cb(
+            public <NAME>(string appId)
+            {
+                _appId = appId;
+                _lem = new LocalExecution(appId, "<NAME>");
+            }
+)__cs_cb";
+
 const char CB_CONNECT_METHOD[] =
 R"__cs_cb(
             /// <summary>
@@ -182,7 +344,23 @@ R"__cs_cb(
             /// <remark> If you want to use this method, you must add privileges.</remark>
             public void Connect()
             {
-                Connect(_appId, "$$");
+                if (_lem.IsListen)
+                {
+                    if (_online || _connecting)
+                        throw new InvalidIDException();
+
+                    _connecting = true;
+                    _lem.Connect(this);
+
+                    _async_context.Post((data) =>
+                    {
+                        OnConnectedEvent(null, null, null);
+                    }, null);
+                }
+                else
+                {
+                    Connect(_appId, "$$");
+                }
             }
 
             /// <summary>
@@ -193,7 +371,16 @@ R"__cs_cb(
             /// </exception>
             public void Disconnect()
             {
-                Port?.Disconnect();
+                if (_lem.IsListen)
+                {
+                    if (_online)
+                        _lem.Disconnect();
+                }
+                else
+                {
+                    Port?.Disconnect();
+                }
+                _online = false;
             }
 
             /// <summary>
@@ -213,7 +400,19 @@ R"__cs_cb(
             /// <remark> If you want to use this method, you must add privileges.</remark>
             public void ConnectSync()
             {
-                ConnectSync(_appId, "$$");
+                if (_lem.IsListen)
+                {
+                    if (_online || _connecting)
+                        throw new InvalidIDException();
+
+                    _connecting = true;
+                    _lem.Connect(this);
+                    OnConnectedEvent(null, null, null);
+                }
+                else
+                {
+                    ConnectSync(_appId, "$$");
+                }
             }
 )__cs_cb";
 
@@ -242,17 +441,44 @@ $$
                     }
 )__cs_cb";
 
-const char CB_INVOCATION_MID[] =
+const char CB_INVOCATION_ASYNC_MID[] =
 R"__cs_cb(                        // Send
-                        p.Send(Port);
+                        if (_lem.IsListen)
+                        {
+                            _lem.Send(p);
+                        }
+                        else
+                        {
+                            p.Send(Port);
+                        }
+)__cs_cb";
+
+const char CB_INVOCATION_SYNC_MID[] =
+R"__cs_cb(                        // Send
+                        Parcel ret_parcel = new Parcel();
+                        // Send
+                        if (_lem.IsListen)
+                        {
+                            _lem.Send(p, ref ret_parcel);
+                        }
+                        else
+                        {
+                            p.Send(Port);
+                        }
 )__cs_cb";
 
 const char CB_INVOCATION_RECEIVE[] =
 R"__cs_cb(    UnitMap mapReceived;
-
-    // Receive
-    ConsumeCommand(out mapReceived, Port, header);
-
+    if (_lem.IsListen)
+    {
+        mapReceived = new UnitMap();
+        mapReceived.Deserialize(ret_parcel);
+    }
+    else
+    {
+        // Receive
+        ConsumeCommand(out mapReceived, Port, header);
+    }
 
     if (mapReceived == null)
     {
index 2e9aced..a74d651 100644 (file)
@@ -39,6 +39,7 @@ void CsStubGen::GenNamespace(std::ofstream& stream) {
   GenBrace(stream, 0, [&]() {
     stream << "namespace " << GetFileNamespace() << NLine(1);
     GenBrace(stream, 0, [&]() {
+      GenLemBase(stream);
       GenRemoteException(stream);
       GenStructures(stream);
       stream << Tab(1) << "namespace Stub" << NLine(1);
@@ -47,6 +48,10 @@ void CsStubGen::GenNamespace(std::ofstream& stream) {
   });
 }
 
+void CsStubGen::GenLemBase(std::ofstream& stream) {
+  stream << CB_LEM_BASE;
+}
+
 void CsStubGen::GenInterfaces(std::ofstream& stream) {
   for (auto& i : GetDocument().GetBlocks()) {
     if (i->GetType() != Block::TYPE_INTERFACE) continue;
@@ -107,10 +112,10 @@ void CsStubGen::GenReceivedEvent(std::ofstream& stream,
   stream << CB_ON_RECEIVED_EVENT_FRONT;
   for (const auto& i : iface.GetDeclarations()) {
     if (i->GetMethodType() == Declaration::MethodType::DELEGATE) continue;
-    stream << Tab(7) << "case MethodId." << i->GetID() << ":" << NLine(1);
-    GenBrace(stream, TAB_SIZE * 8, [&]() {
+    stream << Tab(6) << "case MethodId." << i->GetID() << ":" << NLine(1);
+    GenBrace(stream, TAB_SIZE * 7, [&]() {
       GenInvocation(stream, *i);
-      stream << Tab(9) << "break;" << NLine(1);
+      stream << Tab(8) << "break;" << NLine(1);
     });
   }
   stream << CB_ON_RECEIVED_EVENT_BACK;
@@ -192,7 +197,7 @@ void CsStubGen::GenInvocation(std::ofstream& stream, const Declaration& decl) {
     std::string v = "param" + std::to_string(cnt);
     std::string c = ConvertTypeToDeserializer(
         i->GetParameterType().GetBaseType(), v, i->GetID(), "map");
-    stream << AddIndent(TAB_SIZE * 9, c);
+    stream << AddIndent(TAB_SIZE * 8, c);
     cnt++;
   }
 
@@ -205,17 +210,15 @@ void CsStubGen::GenInvocation(std::ofstream& stream, const Declaration& decl) {
            .Change("<INVOCATION>",
                    AddIndent(TAB_SIZE, GetInvocationMethod(decl)));
 
-  stream << AddIndent(TAB_SIZE * 9, m);
+  stream << AddIndent(TAB_SIZE * 8, m);
 
   // Serialize
   if (decl.GetMethodType() == Declaration::MethodType::ASYNC)
     return;
 
   cnt = 0;
-  m = CB_INVOCATION_RESULT_PRE;
-  m += "result_map.Serialize(result);\n";
-  m += "result.Send(port);\n";
-  stream << AddIndent(TAB_SIZE * 9, m);
+  m = CB_INVOCATION_RESULT;
+  stream << AddIndent(TAB_SIZE * 8, m);
 }
 
 void CsStubGen::GenConnectedEvent(std::ofstream& stream) {
index a04199a..a4e09ea 100644 (file)
@@ -51,6 +51,7 @@ class CsStubGen : public CsGeneratorBase {
   std::string GetInvocationMethodParam(const Declaration& decl, bool hasRet);
   std::string GetInvocationMethod(const Declaration& decl);
   std::string GetWriteOutParam(const Declaration& decl);
+  void GenLemBase(std::ofstream& stream);
 };
 
 }  // namespace version2
index 3da305f..23866a7 100644 (file)
@@ -25,6 +25,59 @@ R"__cs_cb(            private List<ServiceBase> _services = new List<ServiceBase
             private Type _serviceType;
             private static readonly string _tidlVersion = "<VERSION>";
             private Dictionary<MethodId, List<string>> _privilege_map = new Dictionary<MethodId, List<string>>();
+            private static Message _instance;
+            private bool _isListen = false;
+            private SynchronizationContext _async_context = TizenSynchronizationContext.Current;
+)__cs_cb";
+
+const char CB_LEM_BASE[] =
+R"__cs_cb(    internal class LocalExecution
+    {
+        object _instance = null;
+        MethodInfo _send_result = null;
+        MethodInfo _send_request = null;
+        MethodInfo _disconnect = null;
+
+       internal bool _online = false;
+
+        internal LocalExecution (object instance)
+        {
+            Type type = instance.GetType();
+
+            if (type == null)
+                return;
+
+            _send_result = type.GetMethod("OnLemResultEvent", BindingFlags.NonPublic | BindingFlags.Instance);
+            if (_send_result == null) { return; }
+
+            _send_request = type.GetMethod("OnLemReceivedEvent", BindingFlags.NonPublic | BindingFlags.Instance);
+
+            _disconnect = type.GetMethod("OnLemDisconnectedEvent", BindingFlags.NonPublic | BindingFlags.Instance);
+            if (_disconnect == null) { return; }
+
+            _instance = instance;
+            _online = true;
+
+            }
+
+            internal void SendResult(Parcel result)
+            {
+                _send_result.Invoke(_instance, new object[] {result});
+            }
+
+            internal void SendRequest(Parcel result)
+            {
+                if (_send_request != null)
+                    _send_request.Invoke(_instance, new object[] { result });
+            }
+
+            internal void Disconnect()
+            {
+                if (_online)
+                  _disconnect.Invoke(_instance, null);
+                _online = false;
+            }
+        }
 )__cs_cb";
 
 const char CB_SERVICE_BASE_FRONT[] =
@@ -33,6 +86,7 @@ R"__cs_cb(
             {
                 internal bool _is_app = true;
                 internal List<string> _privileges;
+                internal LocalExecution _lem;
 
                 /// <summary>
                 /// The client app ID
@@ -81,8 +135,15 @@ R"__cs_cb(
                 /// </exception>
                 public void Disconnect()
                 {
-                    Port?.Disconnect();
-                    Port = null;
+                    if(_lem != null)
+                    {
+                        _lem.Disconnect();
+                    }
+                    else
+                    {
+                        Port?.Disconnect();
+                        Port = null;
+                    }
                 }
 
                 /// <summary>
@@ -139,6 +200,26 @@ R"__cs_cb(
                     return false;
                 }
 
+                return OnReceivedEvent(instance, port, p);
+            }
+
+            internal void OnLemReceivedEvent(string instance, Parcel p)
+            {
+                if (Thread.CurrentThread.ManagedThreadId != 1)
+                {
+                    _async_context.Post((data) =>
+                    {
+                        ((Message)data).OnReceivedEvent(instance, null, p);
+                    }, this);
+                }
+                else
+                {
+                    OnReceivedEvent(instance, null, p);
+                }
+            }
+
+            internal  bool OnReceivedEvent(string instance, Port port, Parcel p)
+            {
                 try
                 {
                     ServiceBase b = null;
@@ -157,23 +238,22 @@ R"__cs_cb(
                         return false;
                     }
 
-                    using (var result = new Parcel())
-                    {
-                        int cmd;
-                        UnitMap map = new UnitMap();
-                        map.Deserialize(p);
+                    var result = new Parcel();
 
-                        map.Read("[METHOD]", out cmd);
+                    int cmd;
+                    UnitMap map = new UnitMap();
+                    map.Deserialize(p);
 
-                        switch ((MethodId)cmd)
-                        {
+                    map.Read("[METHOD]", out cmd);
+
+                    switch ((MethodId)cmd)
+                    {
 )__cs_cb";
 
 const char CB_ON_RECEIVED_EVENT_BACK[] =
 R"__cs_cb(
-                            default:
-                                return false;
-                        }
+                        default:
+                            return false;
                     }
 
                     return true;
@@ -198,8 +278,29 @@ R"__cs_cb(
                 s.LoadPrivilege();
                 s.Instance = instance;
                 s.Port = GetPort(Port.Type.Callback, instance);
+                _services.Add(s);
                 s.OnCreate();
+            }
+
+            internal void OnLemConnectedEvent(object proxy_instance, string sender, string instance)
+            {
+                ServiceBase s = Activator.CreateInstance(_serviceType) as ServiceBase;
+                s.Sender = sender;
+                s.LoadPrivilege();
+                s.Instance = instance;
+                s._lem = new LocalExecution(proxy_instance);
                 _services.Add(s);
+                if (Thread.CurrentThread.ManagedThreadId != 1)
+                {
+                    _async_context.Post((data) =>
+                    {
+                        ((ServiceBase)data).OnCreate();
+                    }, s);
+                }
+                else
+                {
+                    s.OnCreate();
+                }
             }
 )__cs_cb";
 
@@ -211,18 +312,47 @@ R"__cs_cb(
                 {
                     if (i.Instance.Equals(instance))
                     {
+                        if (i._lem != null)
+                            i._lem._online = false;
+
                         i.OnTerminate();
                         _services.Remove(i);
                         break;
                     }
                 }
             }
+
+            internal void OnLemDisconnectedEvent(string sender, string instance)
+            {
+                if (Thread.CurrentThread.ManagedThreadId != 1)
+                {
+                    _async_context.Post((data) =>
+                    {
+                        ((Message)data).OnDisconnectedEvent(sender, instance);
+                    }, this);
+                }
+                else
+                {
+                    OnDisconnectedEvent(sender, instance);
+                }
+            }
 )__cs_cb";
 
 const char CB_CTOR_FRONT[] =
 R"__cs_cb(
+            internal static Message GetInstance()
+            {
+                return _instance;
+            }
+
+            internal bool GetListenStatus()
+            {
+                    return _isListen;
+            }
+
             public $$() : base("$$")
             {
+                _instance = this;
 )__cs_cb";
 
 const char CB_COMMON_METHODS[] =
@@ -243,6 +373,7 @@ R"__cs_cb(
                     throw new ArgumentException("Invalid type");
                 _serviceType = serviceType;
                 Listen();
+                _isListen = true;
             }
 
             /// <summary>
@@ -261,6 +392,8 @@ R"__cs_cb(
             {
                 foreach (var i in _services)
                 {
+                    if (i._lem != null)
+                       i._lem._online = false;
                     i.OnTerminate();
                 }
             }
@@ -288,14 +421,20 @@ R"__cs_cb(try
     result_map.Write("[REMOTE_EXCEPTION]", ex);
 })__cs_cb";
 
-constexpr const char CB_INVOCATION_RESULT_PRE[] =
+constexpr const char CB_INVOCATION_RESULT[] =
 R"__cs_cb(
 ParcelHeader header = p.GetHeader();
 ParcelHeader resultHeader = result.GetHeader();
 resultHeader.SetTag(_tidlVersion);
 resultHeader.SetSequenceNumber(header.GetSequenceNumber());
-
 result_map.Write("[METHOD]", (int)MethodId.__Result);
+result_map.Serialize(result);
+
+if (b._lem != null)
+    b._lem.SendResult(result);
+else
+    result.Send(port);
+
 )__cs_cb";
 
 #endif  // IDLC_CS_GEN_VERSION2_CS_STUB_GENRATOR_CB_H_
\ No newline at end of file