Release version 1.3.4
[platform/core/appfw/message-port.git] / src / message-port.c
index dacd5ae..3e6525b 100755 (executable)
@@ -1,25 +1,25 @@
-
 /*
- Message Port
- Copyright (c) 2015 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.
-*/
Message Port
Copyright (c) 2015 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.
+ */
 
 /**
  * @file       message-port.cpp
  * @brief      This is the implementation file for the MessagePort.
  */
+#define _GNU_SOURCE
 
 #include <sys/socket.h>
 #include <stdlib.h>
@@ -34,6 +34,9 @@
 #include <aul.h>
 #include <gio/gio.h>
 #include <gio/gunixfdlist.h>
+#include <pthread.h>
+#include <glib-unix.h>
+#include <poll.h>
 
 #include "message-port.h"
 #include "message-port-log.h"
 #define DBUS_RELEASE_NAME_REPLY_NON_EXISTENT    2 /* *< The given name does not exist on the bus */
 #define DBUS_RELEASE_NAME_REPLY_NOT_OWNER       3 /* *< Service is not an owner of the given name */
 #define HEADER_LEN 8
-#define MAX_RETRY_CNT 2
+#define MAX_RETRY_CNT 10
+#define SOCK_PAIR_SENDER 0
+#define SOCK_PAIR_RECEIVER 1
+
 
 #define retvm_if(expr, val, fmt, arg...) do { \
        if (expr) { \
 } while (0)
 
 static bool _initialized = false;
-static GDBusConnection *__gdbus_conn = NULL;
+static GDBusConnection *__gdbus_conn;
 static char *__app_id;
-static GHashTable *__local_port_info = NULL;
-static GHashTable *__remote_port_info = NULL;;
-static GHashTable *__sender_appid_hash = NULL;;
-static GHashTable *__trusted_app_list_hash = NULL;
+static GHashTable *__local_port_info;
+static GHashTable *__remote_app_info;
+static GHashTable *__sender_appid_hash;
+static GHashTable *__trusted_app_list_hash;
+static GHashTable *__callback_info_hash;
+static GHashTable *__registered_callback_info_hash;
 static const int MAX_MESSAGE_SIZE = 16 * 1024;
 
 enum __certificate_info_type {
@@ -115,32 +123,75 @@ typedef struct message_port_local_port_info {
 } message_port_local_port_info_s;
 
 typedef struct message_port_remote_port_info {
-       char *sender_id;
        char *remote_app_id;
        int certificate_info;
        GList *port_list;
 } message_port_remote_app_info_s;
 
 typedef struct port_list_info {
+       message_port_remote_app_info_s *remote_app_info;
        char *port_name;
        char *encoded_bus_name;
        bool is_trusted;
-       int sock_pair[2];
-       int watcher_id;
+       int send_sock_fd;
        bool exist;
+       GIOChannel *gio_read;
+       int g_src_id;
+       GList *delayed_message_list;
+       unsigned int delayed_message_size;
+       int delay_src_id;
 } port_list_info_s;
 
-static void __callback_info_free(message_port_callback_info_s *callback_info)
+typedef struct registered_callback_info {
+       char *remote_app_id;
+       char *remote_port;
+       bool is_trusted;
+       int watcher_id;
+       void *user_data;
+       messageport_registration_event_cb registered_cb;
+       messageport_registration_event_cb unregistered_cb;
+} registered_callback_info_s;
+
+enum transmission_sequence {
+       SEQUENCE_START = 0,
+       SEQUENCE_PORT_LEN,
+       SEQUENCE_PORT_NAME,
+       SEQUENCE_BIDIRECTION,
+       SEQUENCE_TRUSTED,
+       SEQUENCE_DTAT_LEN,
+       SEQUENCE_DATA,
+       SEQUENCE_END
+};
+
+typedef struct delay_message {
+       unsigned int size;
+       unsigned int sent_bytes;
+       int sequence;
+       int local_port_len;
+       char *local_port_name;
+       bool is_bidirection;
+       bool local_trusted;
+       int data_len;
+       bundle_raw *data;
+} delay_message_info_s;
+
+
+extern pthread_mutex_t mutex;
+static void __free_list_delay_message_info(gpointer data);
+
+
+static void __callback_info_free(gpointer data)
 {
+       message_port_callback_info_s *callback_info = (message_port_callback_info_s *)data;
        GError *error = NULL;
        if (callback_info == NULL)
                return;
 
        if (callback_info->remote_app_id)
-               free(callback_info->remote_app_id);
+               FREE_AND_NULL(callback_info->remote_app_id);
 
        if (callback_info->gio_read != NULL) {
-               g_io_channel_shutdown(callback_info->gio_read, FALSE, &error);
+               g_io_channel_shutdown(callback_info->gio_read, TRUE, &error);
                if (error) {
                        _LOGE("g_io_channel_shutdown error : %s", error->message);
                        g_error_free(error);
@@ -154,9 +205,50 @@ static void __callback_info_free(message_port_callback_info_s *callback_info)
                callback_info->g_src_id = 0;
        }
 
+       FREE_AND_NULL(callback_info);
+}
+
+static void __callback_info_free_by_info(message_port_callback_info_s *callback_info)
+{
+       GList *callback_info_list = g_hash_table_lookup(__callback_info_hash, GUINT_TO_POINTER(callback_info->local_id));
+       GList *find_list;
+
+       if (callback_info_list == NULL)
+               return;
+
+       find_list = g_list_find(callback_info_list, callback_info);
+       if (find_list == NULL)
+               return;
+
+       callback_info_list = g_list_remove_link(callback_info_list, find_list);
+       __callback_info_free(callback_info);
+       g_list_free(find_list);
+}
+
+static void __registered_callback_info_free(gpointer data)
+{
+       registered_callback_info_s *callback_info = (registered_callback_info_s *)data;
+       if (callback_info == NULL)
+               return;
+
+       if (callback_info->remote_app_id)
+               free(callback_info->remote_app_id);
+
+       if (callback_info->remote_port)
+               free(callback_info->remote_port);
+
        free(callback_info);
 }
 
+
+static void __hash_destroy_callback_info(gpointer data)
+{
+
+       GList *callback_list = (GList *)data;
+       if (callback_list != NULL)
+               g_list_free_full(callback_list, __callback_info_free);
+}
+
 static char *__get_encoded_name(const char *remote_app_id, const char *port_name, bool is_trusted)
 {
 
@@ -206,7 +298,7 @@ static char *__get_encoded_name(const char *remote_app_id, const char *port_name
        if (bus_name)
                free(bus_name);
 
-       _LOGI("encoded_bus_name : %s ", md5_interface);
+       _LOGD("encoded_bus_name : %s ", md5_interface);
 
        return md5_interface;
 }
@@ -225,7 +317,7 @@ static int __remote_port_compare_cb(gconstpointer a, gconstpointer b)
 
 static bool __is_preloaded(const char *local_appid, const char *remote_appid)
 {
-       _LOGI("IsPreloaded");
+       _LOGD("IsPreloaded");
 
        bool preload_local = false;
        bool preload_remote = false;
@@ -243,6 +335,8 @@ static bool __is_preloaded(const char *local_appid, const char *remote_appid)
                pkgmgrinfo_appinfo_destroy_appinfo(handle);
                return false;
        }
+       pkgmgrinfo_appinfo_destroy_appinfo(handle);
+
        ret = pkgmgrinfo_appinfo_get_usr_appinfo(remote_appid, getuid(), &handle);
        if (ret != PMINFO_R_OK) {
                _LOGE("Failed to get the appinfo. %d", ret);
@@ -266,7 +360,7 @@ static bool __is_preloaded(const char *local_appid, const char *remote_appid)
 
 static int __check_certificate(const char *local_appid, const char *remote_appid)
 {
-       _LOGI("CheckCertificate");
+       _LOGD("CheckCertificate");
 
        pkgmgrinfo_cert_compare_result_type_e res;
        int ret = pkgmgrinfo_pkginfo_compare_usr_app_cert_info(local_appid, remote_appid, getuid(), &res);
@@ -282,24 +376,6 @@ static int __check_certificate(const char *local_appid, const char *remote_appid
        return MESSAGEPORT_ERROR_NONE;
 }
 
-static void on_name_appeared(GDBusConnection *connection,
-               const gchar     *name,
-               const gchar     *name_owner,
-               gpointer         user_data)
-{
-       _LOGI("name appeared : %s %s", __app_id, name);
-}
-
-static void on_name_vanished(GDBusConnection *connection,
-               const gchar     *name,
-               gpointer         user_data)
-{
-       _LOGI("name vanished : %s", name);
-       port_list_info_s *pli = (port_list_info_s *)user_data;
-       g_bus_unwatch_name(pli->watcher_id);
-       pli->exist = false;
-}
-
 static int __get_local_port_info(int id, message_port_local_port_info_s **info)
 {
        message_port_local_port_info_s *mi = (message_port_local_port_info_s *)g_hash_table_lookup(__local_port_info, GINT_TO_POINTER(id));
@@ -326,16 +402,12 @@ static port_list_info_s *__set_remote_port_info(const char *remote_app_id, const
                goto out;
        }
        port_info->is_trusted = is_trusted;
-
        port_info->encoded_bus_name = __get_encoded_name(remote_app_id, remote_port, is_trusted);
        if (port_info->encoded_bus_name == NULL) {
                ret_val = MESSAGEPORT_ERROR_OUT_OF_MEMORY;
                goto out;
        }
-
-       port_info->sock_pair[0] = 0;
-       port_info->sock_pair[1] = 0;
-
+       port_info->send_sock_fd = 0;
 out:
        if (ret_val != MESSAGEPORT_ERROR_NONE) {
                if (port_info) {
@@ -350,7 +422,6 @@ out:
 
 static message_port_remote_app_info_s *__set_remote_app_info(const char *remote_app_id, const char *remote_port, bool is_trusted)
 {
-       port_list_info_s *port_info = NULL;
        message_port_remote_app_info_s *remote_app_info = NULL;
        int ret_val = MESSAGEPORT_ERROR_NONE;
 
@@ -366,14 +437,6 @@ static message_port_remote_app_info_s *__set_remote_app_info(const char *remote_
                goto out;
        }
 
-       port_info = __set_remote_port_info(remote_app_id, remote_port, is_trusted);
-       if (port_info == NULL) {
-               ret_val = MESSAGEPORT_ERROR_OUT_OF_MEMORY;
-               goto out;
-       }
-
-       remote_app_info->port_list = g_list_append(remote_app_info->port_list, port_info);
-
 out:
        if (ret_val != MESSAGEPORT_ERROR_NONE) {
                if (remote_app_info) {
@@ -385,6 +448,87 @@ out:
        return remote_app_info;
 }
 
+static void __clear_disconnect_socket(port_list_info_s *port_info)
+{
+       GError *error = NULL;
+
+       if (port_info == NULL)
+               return;
+
+       if (port_info->gio_read != NULL) {
+               g_io_channel_shutdown(port_info->gio_read, TRUE, &error);
+               if (error) {
+                       _LOGE("g_io_channel_shutdown error : %s", error->message);
+                       g_error_free(error);
+               }
+               g_io_channel_unref(port_info->gio_read);
+               port_info->gio_read = NULL;
+       }
+
+       if (port_info->g_src_id != 0) {
+               g_source_remove(port_info->g_src_id);
+               port_info->g_src_id = 0;
+       }
+
+       if (port_info->delay_src_id != 0) {
+               g_source_remove(port_info->delay_src_id);
+               port_info->delay_src_id = 0;
+       }
+
+       if (port_info->delayed_message_list != NULL) {
+               g_list_free_full(port_info->delayed_message_list, __free_list_delay_message_info);
+               /* can be reused */
+               port_info->delayed_message_list = NULL;
+       }
+
+       port_info->delayed_message_size = 0;
+       port_info->send_sock_fd = 0;
+}
+
+/* LCOV_EXCL_START */
+void __free_port_info(gpointer data)
+{
+       port_list_info_s *port_info = (port_list_info_s *)data;
+       message_port_remote_app_info_s *remote_app_info;
+
+       if (port_info == NULL)
+               return;
+
+       remote_app_info = port_info->remote_app_info;
+
+       _LOGI("__free_port_info : remote_app_id : %s port_name : %s",
+                       remote_app_info->remote_app_id,
+                       port_info->port_name);
+
+       remote_app_info->port_list = g_list_remove(remote_app_info->port_list,
+                       port_info);
+
+       __clear_disconnect_socket(port_info);
+
+       if (port_info->encoded_bus_name)
+               free(port_info->encoded_bus_name);
+       if (port_info->port_name)
+               free(port_info->port_name);
+
+       free(port_info);
+
+       if (g_list_length(remote_app_info->port_list) == 0) {
+               g_hash_table_remove(__remote_app_info,
+                               remote_app_info->remote_app_id);
+       }
+}
+/* LCOV_EXCL_STOP */
+
+static gboolean __socket_disconnect_handler(GIOChannel *gio,
+               GIOCondition cond,
+               gpointer data)
+{
+       _LOGI("__socket_disconnect_handler %d", cond);
+       __free_port_info(data);
+
+       return FALSE;
+}
+
 static int __get_remote_port_info(const char *remote_app_id, const char *remote_port, bool is_trusted,
                message_port_remote_app_info_s **mri, port_list_info_s **pli)
 {
@@ -393,7 +537,7 @@ static int __get_remote_port_info(const char *remote_app_id, const char *remote_
        GList *cb_list = NULL;
        int ret_val = MESSAGEPORT_ERROR_NONE;
 
-       remote_app_info = (message_port_remote_app_info_s *)g_hash_table_lookup(__remote_port_info, remote_app_id);
+       remote_app_info = (message_port_remote_app_info_s *)g_hash_table_lookup(__remote_app_info, remote_app_id);
 
        if (remote_app_info == NULL) {
                remote_app_info = __set_remote_app_info(remote_app_id, remote_port, is_trusted);
@@ -402,12 +546,15 @@ static int __get_remote_port_info(const char *remote_app_id, const char *remote_
                        ret_val = MESSAGEPORT_ERROR_OUT_OF_MEMORY;
                        goto out;
                }
-               g_hash_table_insert(__remote_port_info, remote_app_info->remote_app_id, remote_app_info);
-
+               g_hash_table_insert(__remote_app_info, remote_app_info->remote_app_id, remote_app_info);
        }
        *mri = remote_app_info;
 
        port_info.port_name = strdup(remote_port);
+       if (port_info.port_name == NULL) {
+               ret_val = MESSAGEPORT_ERROR_OUT_OF_MEMORY;
+               goto out;
+       }
        port_info.is_trusted = is_trusted;
        cb_list = g_list_find_custom(remote_app_info->port_list, &port_info,
                                        (GCompareFunc)__remote_port_compare_cb);
@@ -415,18 +562,16 @@ static int __get_remote_port_info(const char *remote_app_id, const char *remote_
                free(port_info.port_name);
        if (cb_list == NULL) {
                port_list_info_s *tmp = __set_remote_port_info(remote_app_id, remote_port, is_trusted);
-
                if (tmp == NULL) {
                        ret_val = MESSAGEPORT_ERROR_OUT_OF_MEMORY;
                        goto out;
                }
                remote_app_info->port_list = g_list_append(remote_app_info->port_list, tmp);
+               tmp->remote_app_info = remote_app_info;
                *pli = tmp;
-               g_hash_table_insert(__remote_port_info, (*pli)->encoded_bus_name, *pli);
        } else {
                *pli = (port_list_info_s *)cb_list->data;
        }
-
 out:
 
        return ret_val;
@@ -438,7 +583,6 @@ static bool __is_local_port_registed(const char *local_port, bool trusted, int *
        gpointer key, value;
 
        g_hash_table_iter_init(&iter, __local_port_info);
-
        while (g_hash_table_iter_next(&iter, &key, &value)) {
                message_port_local_port_info_s *mi = (message_port_local_port_info_s *)value;
 
@@ -494,13 +638,30 @@ out:
 static int __write_socket(int fd,
                const char *buffer,
                unsigned int nbytes,
-               unsigned int *bytes_write)
+               unsigned int *bytes_write,
+               int *sequence)
 {
+#define SEND_TIMEOUT 500 /* milliseconds */
+
        unsigned int left = nbytes;
        ssize_t nb;
        int retry_cnt = 0;
+       struct pollfd fds[1];
+       int ret;
 
+       *sequence += 1;
        *bytes_write = 0;
+
+       fds[0].fd = fd;
+       fds[0].events = POLLOUT;
+       fds[0].revents = 0;
+
+       ret = poll(fds, 1, SEND_TIMEOUT);
+       if (ret == 0) {
+               LOGE("__write_socket: : fd %d poll timeout", fd);
+               return MESSAGEPORT_ERROR_RESOURCE_UNAVAILABLE;
+       }
+
        while (left && (retry_cnt < MAX_RETRY_CNT)) {
                nb = write(fd, buffer, left);
                if (nb == -1) {
@@ -510,6 +671,10 @@ static int __write_socket(int fd,
                                continue;
                        }
                        LOGE("__write_socket: ...error fd %d: errno %d\n", fd, errno);
+
+                       if (errno == EWOULDBLOCK || errno == EAGAIN)
+                               return MESSAGEPORT_ERROR_RESOURCE_UNAVAILABLE;
+
                        return MESSAGEPORT_ERROR_IO_ERROR;
                }
 
@@ -521,20 +686,31 @@ static int __write_socket(int fd,
        return MESSAGEPORT_ERROR_NONE;
 }
 
-static int __write_string_to_socket(int fd, const char *buffer, int string_len)
+static int __write_string_to_socket(int fd,
+               const char *buffer,
+               int string_len,
+               unsigned int *bytes_write,
+               int *sequence)
 {
-       unsigned int nb;
-       if (__write_socket(fd, (char *)&string_len, sizeof(string_len), &nb) != MESSAGEPORT_ERROR_NONE) {
+       int ret;
+
+       ret = __write_socket(fd, (char *)&string_len, sizeof(string_len),
+                       bytes_write, sequence);
+       if (ret != MESSAGEPORT_ERROR_NONE) {
                _LOGE("write string_len fail");
-               return MESSAGEPORT_ERROR_IO_ERROR;
+               return ret;
        }
 
        if (string_len > 0) {
-               if (__write_socket(fd, buffer, string_len, &nb) != MESSAGEPORT_ERROR_NONE) {
+               ret = __write_socket(fd, buffer, string_len, bytes_write, sequence);
+               if (ret != MESSAGEPORT_ERROR_NONE) {
                        _LOGE("wirte buffer fail");
-                       return MESSAGEPORT_ERROR_IO_ERROR;
+                       return ret;
                }
+       } else {
+               *sequence += 1;
        }
+
        return MESSAGEPORT_ERROR_NONE;
 }
 
@@ -546,6 +722,7 @@ static int __read_socket(int fd,
        unsigned int left = nbytes;
        ssize_t nb;
        int retry_cnt = 0;
+       const struct timespec TRY_SLEEP_TIME = { 0, 500 * 1000 * 1000 };
 
        *bytes_read = 0;
        while (left && (retry_cnt < MAX_RETRY_CNT)) {
@@ -554,9 +731,11 @@ static int __read_socket(int fd,
                        LOGE("__read_socket: ...read EOF, socket closed %d: nb %d\n", fd, nb);
                        return MESSAGEPORT_ERROR_IO_ERROR;
                } else if (nb == -1) {
-                       if (errno == EINTR) {
-                               LOGE("__read_socket: EINTR error continue ...");
+                       /*  wrt(nodejs) could change socket to none-blocking socket :-( */
+                       if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
+                               LOGE("__read_socket: %d errno, sleep and retry ...", errno);
                                retry_cnt++;
+                               nanosleep(&TRY_SLEEP_TIME, 0);
                                continue;
                        }
                        LOGE("__read_socket: ...error fd %d: errno %d\n", fd, errno);
@@ -578,7 +757,7 @@ static int __read_string_from_socket(int fd, char **buffer, int *string_len)
                LOGE("read socket fail");
                return MESSAGEPORT_ERROR_IO_ERROR;
        }
-       if (*string_len > 0) {
+       if (*string_len > 0 && *string_len < MAX_MESSAGE_SIZE) {
                *buffer = (char *)calloc(*string_len, sizeof(char));
                if (*buffer == NULL) {
                        LOGE("Out of memory.");
@@ -588,6 +767,9 @@ static int __read_string_from_socket(int fd, char **buffer, int *string_len)
                        LOGE("read socket fail");
                        return MESSAGEPORT_ERROR_IO_ERROR;
                }
+       } else {
+               LOGE("Invalid string len %d", *string_len);
+               return MESSAGEPORT_ERROR_IO_ERROR;
        }
        return MESSAGEPORT_ERROR_NONE;
 }
@@ -607,7 +789,6 @@ message_port_pkt_s *__message_port_recv_raw(int fd)
                LOGE("read socket fail: port_name");
                free(pkt->remote_port_name);
                free(pkt);
-               close(fd);
                return NULL;
        }
 
@@ -615,7 +796,6 @@ message_port_pkt_s *__message_port_recv_raw(int fd)
                LOGE("read socket fail: is_bidirection");
                free(pkt->remote_port_name);
                free(pkt);
-               close(fd);
                return NULL;
        }
 
@@ -623,15 +803,15 @@ message_port_pkt_s *__message_port_recv_raw(int fd)
                LOGE("read socket fail: is_trusted");
                free(pkt->remote_port_name);
                free(pkt);
-               close(fd);
                return NULL;
        }
 
        if (__read_string_from_socket(fd, (char **)&pkt->data, &pkt->data_len) != MESSAGEPORT_ERROR_NONE) {
                LOGE("read socket fail: data");
+               if (pkt->data)
+                       free(pkt->data);
                free(pkt->remote_port_name);
                free(pkt);
-               close(fd);
                return NULL;
        }
 
@@ -651,7 +831,7 @@ static gboolean __socket_request_handler(GIOChannel *gio,
        mi = (message_port_callback_info_s *)data;
        if (mi == NULL) {
 
-               g_io_channel_shutdown(gio, FALSE, &error);
+               g_io_channel_shutdown(gio, TRUE, &error);
                if (error) {
                        _LOGE("g_io_channel_shutdown error : %s", error->message);
                        g_error_free(error);
@@ -663,30 +843,30 @@ static gboolean __socket_request_handler(GIOChannel *gio,
        if (cond == G_IO_HUP) {
 
                _LOGI("socket G_IO_HUP");
-               __callback_info_free(mi);
+               __callback_info_free_by_info(mi);
                return FALSE;
 
        } else {
 
                if ((fd = g_io_channel_unix_get_fd(gio)) < 0) {
                        _LOGE("fail to get fd from io channel");
-                       __callback_info_free(mi);
+                       __callback_info_free_by_info(mi);
                        return FALSE;
                }
 
                if ((pkt = __message_port_recv_raw(fd)) == NULL) {
                        _LOGE("recv error on SOCKET");
-                       __callback_info_free(mi);
+                       __callback_info_free_by_info(mi);
                        return FALSE;
                }
 
                kb = bundle_decode(pkt->data, pkt->data_len);
-
                if (pkt->is_bidirection)
                        mi->callback(mi->local_id, mi->remote_app_id, pkt->remote_port_name, pkt->is_trusted, kb, NULL);
                else
                        mi->callback(mi->local_id, mi->remote_app_id, NULL, pkt->is_trusted, kb, NULL);
 
+               bundle_free(kb);
                if (pkt) {
                        if (pkt->remote_port_name)
                                free(pkt->remote_port_name);
@@ -713,10 +893,20 @@ static bool send_message(GVariant *parameters, GDBusMethodInvocation *invocation
        bundle *data = NULL;
        bundle_raw *raw = NULL;
        message_port_local_port_info_s *mi;
-       message_port_callback_info_s *callback_info;
        int local_reg_id = 0;
+       message_port_callback_info_s *callback_info = NULL;
+       message_port_callback_info_s *head_callback_info;
+       GList *callback_info_list = NULL;
+
+       char buf[1024];
+       GDBusMessage *msg;
+       GUnixFDList *fd_list;
+       int fd_len;
+       int *returned_fds = NULL;
+       int fd;
+       bool ret = false;
 
-       g_variant_get(parameters, "(ssbbssbus)", &local_appid, &local_port, &local_trusted, &bi_dir,
+       g_variant_get(parameters, "(&s&sbb&s&sbu&s)", &local_appid, &local_port, &local_trusted, &bi_dir,
                        &remote_appid, &remote_port, &remote_trusted, &len, &raw);
 
        if (!remote_port) {
@@ -754,7 +944,6 @@ static bool send_message(GVariant *parameters, GDBusMethodInvocation *invocation
        if (remote_trusted) {
                if (g_hash_table_lookup(__trusted_app_list_hash, (gpointer)local_appid) == NULL) {
                        if (!__is_preloaded(local_appid, remote_appid)) {
-                               /* Check the certificate */
                                int ret = __check_certificate(local_appid, remote_appid);
                                if (ret == MESSAGEPORT_ERROR_NONE)
                                        g_hash_table_insert(__trusted_app_list_hash, local_appid, "TRUE");
@@ -773,61 +962,88 @@ static bool send_message(GVariant *parameters, GDBusMethodInvocation *invocation
 
        callback_info->local_id = mi->local_id;
        callback_info->remote_app_id = strdup(local_appid);
+       if (callback_info->remote_app_id == NULL) {
+               _LOGE("out of memory");
+               goto out;
+       }
        callback_info->callback = mi->callback;
 
-       GError *error = NULL;
-       GDBusMessage *msg = g_dbus_method_invocation_get_message(invocation);
+       msg = g_dbus_method_invocation_get_message(invocation);
+       fd_list = g_dbus_message_get_unix_fd_list(msg);
 
-       GUnixFDList *fd_list = g_dbus_message_get_unix_fd_list(msg);
-       int fd = g_unix_fd_list_get(fd_list, 0, &error);
-       if (error) {
-               LOGE("g_unix_fd_list_get fail : %s", error->message);
-               g_error_free(error);
-       }
+       /* When application send message to self fd_list is NULL */
+       if (fd_list != NULL) {
+               returned_fds = g_unix_fd_list_steal_fds(fd_list, &fd_len);
+               if (returned_fds == NULL) {
+                       _LOGE("fail to get fds");
+                       goto out;
+               }
+               fd = returned_fds[0];
 
-       LOGI("g_unix_fd_list_get fd: [%d]", fd);
+               LOGI("g_unix_fd_list_get %d fd: [%d]", fd_len, fd);
+               if (fd > 0) {
 
-       if (fd > 0) {
+                       callback_info->gio_read = g_io_channel_unix_new(fd);
+                       if (!callback_info->gio_read) {
+                               _LOGE("Error is %s\n", strerror_r(errno, buf, sizeof(buf)));
+                               goto out;
+                       }
 
-               callback_info->gio_read = g_io_channel_unix_new(fd);
-               if (!callback_info->gio_read) {
-                       _LOGE("Error is %s\n", strerror(errno));
-                       __callback_info_free(callback_info);
-                       return -1;
-               }
+                       callback_info->g_src_id = g_io_add_watch(callback_info->gio_read, G_IO_IN | G_IO_HUP,
+                                       __socket_request_handler, (gpointer)callback_info);
+                       if (callback_info->g_src_id == 0) {
+                               _LOGE("fail to add watch on socket");
+                               goto out;
+                       }
 
-               callback_info->g_src_id = g_io_add_watch(callback_info->gio_read, G_IO_IN | G_IO_HUP,
-                               __socket_request_handler, (gpointer)callback_info);
-               if (callback_info->g_src_id == 0) {
-                       _LOGE("fail to add watch on socket");
-                       __callback_info_free(callback_info);
-                       return -1;
+                       callback_info_list = g_hash_table_lookup(__callback_info_hash, GUINT_TO_POINTER(mi->local_id));
+                       if (callback_info_list == NULL) {
+                               head_callback_info = (message_port_callback_info_s *)calloc(1, sizeof(message_port_callback_info_s));
+                               if (head_callback_info == NULL) {
+                                       _LOGE("fail to alloc head_callback_info");
+                                       goto out;
+                               }
+                               head_callback_info->local_id = 0;
+                               head_callback_info->remote_app_id = NULL;
+                               head_callback_info->callback = NULL;
+                               head_callback_info->gio_read = NULL;
+                               head_callback_info->g_src_id = 0;
+                               callback_info_list = g_list_append(callback_info_list, head_callback_info);
+                               callback_info_list = g_list_append(callback_info_list, callback_info);
+                               g_hash_table_insert(__callback_info_hash, GUINT_TO_POINTER(mi->local_id), callback_info_list);
+                       } else {
+                               callback_info_list = g_list_append(callback_info_list, callback_info);
+                       }
                }
-
        }
 
        data = bundle_decode(raw, len);
-       bundle_free_encoded_rawdata(&raw);
-
        if (!data) {
                _LOGE("Invalid argument : message");
                goto out;
        }
 
-       LOGI("call calback %s", local_appid);
+       LOGD("call calback %s", local_appid);
        if (bi_dir)
                mi->callback(mi->local_id, local_appid, local_port, local_trusted, data, NULL);
        else
                mi->callback(mi->local_id, local_appid, NULL, false, data, NULL);
+       bundle_free(data);
 
+       ret = true;
 out:
+       if (ret == false)
+               __callback_info_free(callback_info);
 
-       return true;
+       if (returned_fds)
+               free(returned_fds);
+
+       return ret;
 }
 
 static int __check_remote_port(const char *remote_app_id, const char *remote_port, bool is_trusted, bool *exist)
 {
-       _LOGI("Check a remote port : [%s:%s]", remote_app_id, remote_port);
+       _LOGD("Check a remote port : [%s:%s]", remote_app_id, remote_port);
 
        GVariant *result = NULL;
        GError *err = NULL;
@@ -839,23 +1055,22 @@ static int __check_remote_port(const char *remote_app_id, const char *remote_por
        message_port_local_port_info_s *mi = NULL;
        gboolean name_exist = false;
 
-       _LOGI("remote_app_id, app_id :[%s : %s] ", remote_app_id, __app_id);
+       _LOGD("remote_app_id, app_id :[%s : %s] ", remote_app_id, __app_id);
 
        ret_val = __get_remote_port_info(remote_app_id, remote_port, is_trusted, &remote_app_info, &port_info);
        if (ret_val != MESSAGEPORT_ERROR_NONE)
                return ret_val;
 
-
        /* self check */
        if (strcmp(remote_app_id, __app_id) == 0) {
 
-               _LOGI("__is_local_port_registed ");
+               _LOGD("__is_local_port_registed ");
                if (!__is_local_port_registed(remote_port, is_trusted, &local_reg_id, &mi))
                        *exist = false;
                else
                        *exist = true;
 
-               _LOGI("__is_local_port_registed : %d ", *exist);
+               _LOGD("__is_local_port_registed : %d ", *exist);
                return MESSAGEPORT_ERROR_NONE;
        }
 
@@ -885,7 +1100,7 @@ static int __check_remote_port(const char *remote_app_id, const char *remote_por
                g_variant_get(result, "(b)", &name_exist);
 
                if (!name_exist) {
-                       LOGE("Name not exist %s", bus_name);
+                       _LOGI("Name not exist %s", bus_name);
                        *exist = false;
                        ret_val = MESSAGEPORT_ERROR_NONE;
                } else {
@@ -901,48 +1116,93 @@ static int __check_remote_port(const char *remote_app_id, const char *remote_por
                                        remote_app_info->certificate_info = CERTIFICATE_MATCH;
                                }
                        }
-
-                       port_info->watcher_id = g_bus_watch_name_on_connection(
-                                       __gdbus_conn,
-                                       port_info->encoded_bus_name,
-                                       G_BUS_NAME_WATCHER_FLAGS_NONE,
-                                       on_name_appeared,
-                                       on_name_vanished,
-                                       port_info,
-                                       NULL);
-
                        port_info->exist = true;
                        *exist = true;
                        ret_val = MESSAGEPORT_ERROR_NONE;
-                       _LOGI("Exist port: %s", bus_name);
                }
-
        }
 out:
        if (result)
                g_variant_unref(result);
 
+       if (ret_val != MESSAGEPORT_ERROR_NONE || !name_exist)
+               __free_port_info((gpointer)port_info);
+
        return ret_val;
 }
 
+static void __on_sender_name_appeared(GDBusConnection *connection,
+               const gchar     *name,
+               const gchar     *name_owner,
+               gpointer         user_data)
+{
+       _LOGI("sender name appeared : %s", name);
+}
+
+static void __on_sender_name_vanished(GDBusConnection *connection,
+               const gchar     *name,
+               gpointer         user_data)
+{
+       gboolean remove_result = FALSE;
+       int *watcher_id = (int *)user_data;
+       remove_result = g_hash_table_remove(__sender_appid_hash, (gpointer)name);
+       if (!remove_result)
+               _LOGE("Fail to remove sender appid from hash : %s", name);
+
+       if (watcher_id) {
+               if (*watcher_id > 0)
+                       g_bus_unwatch_name(*watcher_id);
+               else
+                       LOGE("Invalid watcher_id %d", *watcher_id);
+               free(watcher_id);
+       } else {
+               LOGE("watcher_id is NULL");
+       }
+}
+
 static bool __check_sender_validation(GVariant *parameters, const char *sender, GDBusConnection *conn)
 {
        int ret = 0;
        char buffer[MAX_PACKAGE_STR_SIZE] = {0, };
        char *local_appid = NULL;
        int pid = __get_sender_pid(conn, sender);
+       int *watcher_id = (int *)calloc(1, sizeof(int));
+       char *_sender;
+       retvm_if(!watcher_id, false, "Malloc failed");
 
        ret = aul_app_get_appid_bypid(pid, buffer, sizeof(buffer));
-       retvm_if(ret != AUL_R_OK, false, "Failed to get the sender ID: (%s) (%d)", sender, pid);
+       if (ret != AUL_R_OK) {
+               _LOGE("Failed to get the sender ID: (%s) (%d)", sender, pid);
+               free(watcher_id);
+               return false;
+       }
 
-       g_variant_get_child(parameters, 0, "s", &local_appid);
-       retvm_if(!local_appid, false, "remote_appid is NULL (%s) (%d)", sender, pid);
+       g_variant_get_child(parameters, 0, "&s", &local_appid);
+       if (local_appid == NULL) {
+               _LOGE("appid is NULL : (%s) (%d)", sender, pid);
+               free(watcher_id);
+               return false;
+       }
 
        if (strncmp(buffer, local_appid, MAX_PACKAGE_STR_SIZE) == 0) {
-               g_hash_table_insert(__sender_appid_hash, strdup(sender), GINT_TO_POINTER(pid));
-               g_free(local_appid);
+               _LOGD("insert sender !!!!! %s", sender);
+               _sender = strdup(sender);
+               if (_sender == NULL) {
+                       _LOGE("out of memory");
+                       free(watcher_id);
+                       return false;
+               }
+               g_hash_table_insert(__sender_appid_hash, (gpointer)_sender, GINT_TO_POINTER(pid));
+               *watcher_id = g_bus_watch_name_on_connection(
+                                       __gdbus_conn,
+                                       sender,
+                                       G_BUS_NAME_WATCHER_FLAGS_NONE,
+                                       __on_sender_name_appeared,
+                                       __on_sender_name_vanished,
+                                       watcher_id,
+                                       NULL);
        } else {
-               g_free(local_appid);
+               free(watcher_id);
                return false;
        }
        return true;
@@ -954,16 +1214,16 @@ static void __dbus_method_call_handler(GDBusConnection *conn,
                                GVariant *parameters, GDBusMethodInvocation *invocation,
                                gpointer user_data)
 {
-       _LOGI("method_name: %s", method_name);
+       _LOGI("method_name: %s, sender: %s", method_name, sender);
        gpointer sender_pid = g_hash_table_lookup(__sender_appid_hash, sender);
        if (sender_pid == NULL) {
                if (!__check_sender_validation(parameters, sender, conn))
-                       return;
+                       goto out;
        }
-
        if (g_strcmp0(method_name, "send_message") == 0)
                send_message(parameters, invocation);
-
+out:
+       g_dbus_method_invocation_return_value(invocation, NULL);
 }
 
 static const GDBusInterfaceVTable interface_vtable = {
@@ -996,7 +1256,6 @@ out:
 
 }
 
-
 int __register_dbus_interface(const char *port_name, bool is_trusted)
 {
 
@@ -1064,6 +1323,7 @@ int __register_dbus_interface(const char *port_name, bool is_trusted)
                        &error);
        if (error) {
                _LOGE("RequestName fail : %s", error->message);
+               g_error_free(error);
                goto out;
        }
        if (result == NULL) {
@@ -1076,7 +1336,7 @@ int __register_dbus_interface(const char *port_name, bool is_trusted)
                goto out;
        }
 
-       _LOGI("Acquiring the own name : %d", owner_id);
+       _LOGD("Acquiring the own name : %d", owner_id);
 
        snprintf(introspection_xml, introspection_xml_len, "%s%s%s", introspection_prefix, interface_name, introspection_postfix);
 
@@ -1090,7 +1350,7 @@ int __register_dbus_interface(const char *port_name, bool is_trusted)
                                                MESSAGEPORT_OBJECT_PATH, introspection_data->interfaces[0],
                                                &interface_vtable, NULL, NULL, NULL);
 
-       _LOGI("registration_id %d", registration_id);
+       _LOGD("registration_id %d", registration_id);
 
        if (registration_id == 0) {
                _LOGE("Failed to g_dbus_connection_register_object");
@@ -1111,33 +1371,31 @@ out:
        return registration_id;
 }
 
-
-void __list_free_port_list(gpointer data)
-{
-       port_list_info_s *n = (port_list_info_s *)data;
-
-       FREE_AND_NULL(n->encoded_bus_name);
-       FREE_AND_NULL(n->port_name);
-       FREE_AND_NULL(n);
-}
-
+/* LCOV_EXCL_START */
 static void __hash_destory_local_value(gpointer data)
 {
        message_port_local_port_info_s *mli = (message_port_local_port_info_s *)data;
-       if (mli->port_name)
-               free(mli->port_name);
+       if (mli) {
+               if (mli->port_name)
+                       free(mli->port_name);
+               free(mli);
+       }
 }
+/* LCOV_EXCL_STOP */
+
+/* LCOV_EXCL_START */
 static void __hash_destory_remote_value(gpointer data)
 {
        message_port_remote_app_info_s *mri = (message_port_remote_app_info_s *)data;
-
        if (mri) {
-               FREE_AND_NULL(mri->sender_id);
                FREE_AND_NULL(mri->remote_app_id);
                if (mri->port_list)
-                       g_list_free_full(mri->port_list, __list_free_port_list);
+                       g_list_free_full(mri->port_list, __free_port_info);
+
+               free(mri);
        }
 }
+/* LCOV_EXCL_STOP */
 
 static bool __initialize(void)
 {
@@ -1150,7 +1408,6 @@ static bool __initialize(void)
        int ret = 0;
        char buffer[MAX_PACKAGE_STR_SIZE] = {0, };
 
-       _LOGI("initialize");
        ret = aul_app_get_appid_bypid(pid, buffer, sizeof(buffer));
        retvm_if(ret != AUL_R_OK, false, "Failed to get the application ID: %d", ret);
 
@@ -1163,13 +1420,13 @@ static bool __initialize(void)
                retvm_if(!__local_port_info, false, "fail to create __local_port_info");
        }
 
-       if (__remote_port_info == NULL) {
-               __remote_port_info = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, __hash_destory_remote_value);
-               retvm_if(!__remote_port_info, false, "fail to create __remote_port_info");
+       if (__remote_app_info == NULL) {
+               __remote_app_info = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, __hash_destory_remote_value);
+               retvm_if(!__remote_app_info, false, "fail to create __remote_app_info");
        }
 
        if (__sender_appid_hash == NULL) {
-               __sender_appid_hash = g_hash_table_new(g_str_hash, g_str_equal);
+               __sender_appid_hash = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
                retvm_if(!__sender_appid_hash, false, "fail to create __sender_appid_hash");
        }
 
@@ -1178,6 +1435,11 @@ static bool __initialize(void)
                retvm_if(!__trusted_app_list_hash, false, "fail to create __trusted_app_list_hash");
        }
 
+       if (__callback_info_hash == NULL) {
+               __callback_info_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, __hash_destroy_callback_info);
+               retvm_if(!__callback_info_hash, false, "fail to create __callback_info_hash");
+       }
+
        if (!__dbus_init())
                return false;
        _initialized = true;
@@ -1207,7 +1469,7 @@ static bool __message_port_register_port(const int local_id, const char *local_p
 
 static int __register_message_port(const char *local_port, bool is_trusted, messageport_message_cb callback)
 {
-       _SECURE_LOGI("Register a message port : [%s:%s]", __app_id, local_port);
+       _SECURE_LOGI("local_port : [%s:%s]", local_port, is_trusted ? "trusted" : "non-trusted");
 
        int local_id = 0;
 
@@ -1227,37 +1489,271 @@ static int __register_message_port(const char *local_port, bool is_trusted, mess
        return local_id;
 }
 
-int __message_port_send_async(int sockfd, bundle *kb, const char *local_port,
-               bool local_trusted, bool is_bidirection)
+static void __free_delay_message_info(delay_message_info_s *message)
 {
-       int ret = 0;
-       int data_len;
-       int local_port_len = 0;
-       unsigned int nb;
-       bundle_raw *kb_data = NULL;
+       if (message != NULL) {
+               FREE_AND_NULL(message->local_port_name);
+               FREE_AND_NULL(message->data);
+               FREE_AND_NULL(message);
+       }
+}
 
-       if (local_port != NULL)
-               local_port_len = strlen(local_port) + 1;
+static void __free_list_delay_message_info(gpointer data)
+{
+       delay_message_info_s *message = (delay_message_info_s *)data;
+
+       if (message != NULL)
+               __free_delay_message_info(message);
+}
+
+static int __send_delayed_message(int sockfd, delay_message_info_s *message)
+{
+       unsigned int nb = 0;
+       int sequence = message->sequence - 1;
+       int ret = MESSAGEPORT_ERROR_NONE;
+       bool is_startline = true;
+       int offset = 0;
+
+       _LOGI("send_delayed_message : sockfd (%d) sequence(%d) sent byte(%d)",
+               sockfd, message->sequence, message->sent_bytes);
+
+       switch (message->sequence) {
+       case SEQUENCE_START:
+               sequence++;
+               is_startline = false;
+
+       case SEQUENCE_PORT_LEN:
+               if (is_startline)
+                       offset = message->sent_bytes;
+
+               ret = __write_socket(sockfd, ((char *)&message->local_port_len) + offset,
+                               sizeof(message->local_port_len) - offset, &nb, &sequence);
+               if (ret != MESSAGEPORT_ERROR_NONE) {
+                       _LOGE("write local_port_len fail");
+                       goto out;
+               }
+               offset = 0;
+               is_startline = false;
+
+       case SEQUENCE_PORT_NAME:
+               if (is_startline)
+                       offset = message->sent_bytes;
+
+               if (message->local_port_len > 0)
+                       ret = __write_socket(sockfd, message->local_port_name + offset,
+                               message->local_port_len - offset , &nb, &sequence);
+               else
+                       sequence++;
+
+               if (ret != MESSAGEPORT_ERROR_NONE) {
+                       _LOGE("write local_port fail");
+                       goto out;
+               }
+               offset = 0;
+               is_startline = false;
+
+       case SEQUENCE_BIDIRECTION:
+               if (is_startline)
+                       offset = message->sent_bytes;
+
+               ret = __write_socket(sockfd, ((char *)&message->is_bidirection) + offset,
+                               sizeof(message->is_bidirection) - offset, &nb, &sequence);
+               if (ret != MESSAGEPORT_ERROR_NONE) {
+                       _LOGE("write is_bidirection fail");
+                       goto out;
+               }
+               offset = 0;
+               is_startline = false;
+
+       case SEQUENCE_TRUSTED:
+               if (is_startline)
+                       offset = message->sent_bytes;
+
+               ret = __write_socket(sockfd, ((char *)&message->local_trusted) + offset,
+                               sizeof(message->local_trusted) - offset, &nb, &sequence);
+               if (ret != MESSAGEPORT_ERROR_NONE) {
+                       _LOGE("write local_trusted fail");
+                       goto out;
+               }
+               offset = 0;
+               is_startline = false;
+
+       case SEQUENCE_DTAT_LEN:
+               if (is_startline)
+                       offset = message->sent_bytes;
+
+               ret = __write_socket(sockfd, ((char *)&message->data_len) + offset,
+                               sizeof(message->data_len) - offset, &nb, &sequence);
+               if (ret != MESSAGEPORT_ERROR_NONE) {
+                       _LOGE("write data_len fail");
+                       goto out;
+               }
+               offset = 0;
+               is_startline = false;
+
+       case SEQUENCE_DATA:
+               if (is_startline)
+                       offset = message->sent_bytes;
+
+               ret = __write_socket(sockfd, (char *)message->data + offset,
+                       message->data_len -offset, &nb, &sequence);
+
+               if (ret != MESSAGEPORT_ERROR_NONE) {
+                       _LOGE("write data fail");
+                       goto out;
+               }
+               offset = 0;
+               is_startline = false;
+
+       default:
+               ret = MESSAGEPORT_ERROR_NONE;
 
-       if (__write_string_to_socket(sockfd, local_port, local_port_len) != MESSAGEPORT_ERROR_NONE) {
-               _LOGE("write local_port fail");
-               return MESSAGEPORT_ERROR_IO_ERROR;
        }
 
-       if (__write_socket(sockfd, (char *)&is_bidirection, sizeof(is_bidirection), &nb) != MESSAGEPORT_ERROR_NONE) {
-               _LOGE("write is_bidirection fail");
-               return MESSAGEPORT_ERROR_IO_ERROR;
+out:
+       if (ret == MESSAGEPORT_ERROR_RESOURCE_UNAVAILABLE) {
+               if (is_startline)
+                        message->sent_bytes += nb;
+               else
+                        message->sent_bytes = nb;
+
+               message->sequence = sequence;
+               _LOGE("send_delayed_message fail : sockfd (%d) sequence(%d) sent byte(%d)",
+                       sockfd, message->sequence, message->sent_bytes);
        }
 
-       if (__write_socket(sockfd, (char *)&local_trusted, sizeof(local_trusted), &nb) != MESSAGEPORT_ERROR_NONE) {
-               _LOGE("write local_trusted fail");
-               return MESSAGEPORT_ERROR_IO_ERROR;
+       return ret;
+
+}
+
+static gboolean __process_delayed_message(gint fd, GIOCondition cond, gpointer data)
+{
+       port_list_info_s *port_info = (port_list_info_s *)data;
+       delay_message_info_s *message;
+       int ret;
+
+       if (port_info == NULL)
+               return G_SOURCE_REMOVE;
+
+       pthread_mutex_lock(&mutex);
+
+       if (port_info->delayed_message_list == NULL) {
+               port_info->delayed_message_size = 0;
+               port_info->delay_src_id = 0;
+               pthread_mutex_unlock(&mutex);
+               return G_SOURCE_REMOVE;
+       } else {
+               message = g_list_nth_data(port_info->delayed_message_list, 0);
+               ret = __send_delayed_message(port_info->send_sock_fd, message);
+
+               if (ret == MESSAGEPORT_ERROR_RESOURCE_UNAVAILABLE) {
+                       pthread_mutex_unlock(&mutex);
+                       return G_SOURCE_CONTINUE;
+               } else if (ret == MESSAGEPORT_ERROR_IO_ERROR) {
+                       __free_port_info((gpointer)port_info);
+                       pthread_mutex_unlock(&mutex);
+                       return G_SOURCE_REMOVE;
+               }
+
+               port_info->delayed_message_size -= message->size;
+
+               port_info->delayed_message_list = g_list_remove(port_info->delayed_message_list, message);
+               __free_delay_message_info(message);
+       }
+
+       pthread_mutex_unlock(&mutex);
+
+       return G_SOURCE_CONTINUE;
+}
+
+static int __insert_delayed_message(port_list_info_s *port_info,
+       int sequence,
+       bundle_raw *kb_data,
+       int data_len,
+       unsigned int sent_bytes,
+       const char *local_port,
+       bool local_trusted,
+       bool is_bidirection)
+{
+#define QUEUE_SIZE_MAX (1024 * 1024) /* 1MB per remote port (MAX) */
+
+       unsigned int tmp_size;
+       unsigned int message_size;
+       int ret = MESSAGEPORT_ERROR_NONE;
+
+       if (port_info->delayed_message_size >= QUEUE_SIZE_MAX) {
+               _LOGE("cache fail : delayed_message_size (%d), count(%d)",
+                       port_info->delayed_message_size, g_list_length(port_info->delayed_message_list));
+               return MESSAGEPORT_ERROR_RESOURCE_UNAVAILABLE;
+       }
+
+       delay_message_info_s *message = (delay_message_info_s *)calloc(1, sizeof(delay_message_info_s));
+       retvm_if(!message, MESSAGEPORT_ERROR_OUT_OF_MEMORY, "Malloc failed");
+
+       message_size = sizeof(delay_message_info_s);
+
+       message->sequence = sequence;
+       tmp_size = strlen(local_port) + 1;
+       message_size += tmp_size;
+       message->local_port_len = tmp_size;
+       message->local_port_name = strdup(local_port);
+       if (message->local_port_name == NULL) {
+               _LOGE("local_port_name strdup fail");
+               ret = MESSAGEPORT_ERROR_OUT_OF_MEMORY;
+               goto out;
+       }
+       message->is_bidirection = is_bidirection;
+       message->local_trusted = local_trusted;
+       message_size += data_len;
+       message->data_len = data_len;
+       message->data = (bundle_raw *)strdup((const char *)kb_data);
+       if (message->data == NULL) {
+               _LOGE("data strdup fail");
+               ret = MESSAGEPORT_ERROR_OUT_OF_MEMORY;
+               goto out;
+       }
+
+
+       message->sent_bytes = sent_bytes;
+       message->size = message_size;
+       port_info->delayed_message_size += message_size;
+
+       port_info->delayed_message_list = g_list_append(port_info->delayed_message_list, message);
+
+       if (port_info->delay_src_id == 0) {
+                       port_info->delay_src_id = g_unix_fd_add_full(G_PRIORITY_DEFAULT,
+                                                       port_info->send_sock_fd, G_IO_OUT, __process_delayed_message,
+                                                       port_info, NULL);
        }
 
+       _LOGE("inserted : pm(%s) fd(%d) ms(%d) ds(%d) dlc(%d) sqn(%d) sb (%d)",
+               port_info->port_name, port_info->send_sock_fd, message_size,
+               port_info->delayed_message_size,
+               g_list_length(port_info->delayed_message_list), sequence, sent_bytes);
+
+
+
+out:
+       if (ret != MESSAGEPORT_ERROR_NONE)
+               __free_delay_message_info(message);
+
+       return ret;
+}
+
+int __message_port_send_async(port_list_info_s *port_info, bundle *kb, const char *local_port,
+               bool local_trusted, bool is_bidirection)
+{
+       int ret = 0;
+       int data_len;
+       int local_port_len = 0;
+       unsigned int nb = 0;
+       bundle_raw *kb_data = NULL;
+       int sequence = SEQUENCE_START;
+
        bundle_encode(kb, &kb_data, &data_len);
        if (kb_data == NULL) {
                _LOGE("bundle encode fail");
-               ret = MESSAGEPORT_ERROR_IO_ERROR;
+               ret = MESSAGEPORT_ERROR_INVALID_PARAMETER;
                goto out;
        }
 
@@ -1267,11 +1763,52 @@ int __message_port_send_async(int sockfd, bundle *kb, const char *local_port,
                goto out;
        }
 
-       if (__write_string_to_socket(sockfd, (void *)kb_data, data_len) != MESSAGEPORT_ERROR_NONE) {
+       if (g_list_length(port_info->delayed_message_list) > 0) {
+               ret = MESSAGEPORT_ERROR_RESOURCE_UNAVAILABLE;
+               _LOGE("There are messages in the delayed_message_list (count %d)",
+                       g_list_length(port_info->delayed_message_list));
+               goto out;
+       }
+
+       if (local_port != NULL)
+               local_port_len = strlen(local_port) + 1;
+
+       ret = __write_string_to_socket(port_info->send_sock_fd, local_port,
+                       local_port_len, &nb, &sequence);
+       if (ret != MESSAGEPORT_ERROR_NONE) {
+               _LOGE("write local_port fail");
+               goto out;
+       }
+
+       ret = __write_socket(port_info->send_sock_fd, (char *)&is_bidirection,
+                       sizeof(is_bidirection), &nb, &sequence);
+       if (ret != MESSAGEPORT_ERROR_NONE) {
+               _LOGE("write is_bidirection fail");
+               goto out;
+       }
+
+       ret = __write_socket(port_info->send_sock_fd, (char *)&local_trusted,
+                       sizeof(local_trusted), &nb, &sequence);
+       if (ret != MESSAGEPORT_ERROR_NONE) {
+               _LOGE("write local_trusted fail");
+               goto out;
+       }
+
+       ret = __write_string_to_socket(port_info->send_sock_fd, (void *)kb_data,
+                       data_len, &nb, &sequence);
+       if (ret != MESSAGEPORT_ERROR_NONE) {
                _LOGE("write kb_data fail");
-               ret = MESSAGEPORT_ERROR_IO_ERROR;
+               goto out;
        }
+
 out:
+       if (ret == MESSAGEPORT_ERROR_RESOURCE_UNAVAILABLE) {
+               ret = __insert_delayed_message(port_info, sequence, kb_data, data_len, nb,
+                       local_port, local_trusted, is_bidirection);
+               if (ret != MESSAGEPORT_ERROR_NONE)
+                       ret = MESSAGEPORT_ERROR_IO_ERROR;
+       }
+
        if (kb_data)
                free(kb_data);
 
@@ -1284,7 +1821,6 @@ static int __message_port_send_message(const char *remote_appid, const char *rem
 
        int ret = MESSAGEPORT_ERROR_NONE;
        GUnixFDList *fd_list = NULL;
-       GError *error = NULL;
 
        int len = 0;
        bundle_raw *raw = NULL;
@@ -1296,6 +1832,8 @@ static int __message_port_send_message(const char *remote_appid, const char *rem
        GDBusMessage *msg = NULL;
        GError *err = NULL;
        GVariant *body = NULL;
+       int sock_pair[2] = {0,};
+       char buf[1024];
 
        ret = __get_remote_port_info(remote_appid, remote_port, trusted_message, &remote_app_info, &port_info);
        if (ret != MESSAGEPORT_ERROR_NONE)
@@ -1303,18 +1841,16 @@ static int __message_port_send_message(const char *remote_appid, const char *rem
 
        if (port_info->exist == false) {
                bool exist = false;
-               _LOGI("port exist check !!");
+               _LOGD("port exist check !!");
                ret =  __check_remote_port(remote_appid, remote_port, trusted_message, &exist);
-               if (ret != MESSAGEPORT_ERROR_NONE) {
-                       goto out;
-               } else if (!exist) {
-                       ret = MESSAGEPORT_ERROR_MESSAGEPORT_NOT_FOUND;
-                       goto out;
-               }
+               if (ret != MESSAGEPORT_ERROR_NONE)
+                       return ret;
+               else if (!exist)
+                       return MESSAGEPORT_ERROR_MESSAGEPORT_NOT_FOUND;
        }
 
-       if (port_info->sock_pair[0] > 0) {
-               ret = __message_port_send_async(port_info->sock_pair[0], message,
+       if (port_info->send_sock_fd > 0) {
+               ret = __message_port_send_async(port_info, message,
                                (local_port) ? local_port : "", local_trusted, bi_dir);
        } else {
 
@@ -1329,33 +1865,52 @@ static int __message_port_send_message(const char *remote_appid, const char *rem
                if (MAX_MESSAGE_SIZE < len) {
                        _LOGE("The size of message (%d) has exceeded the maximum limit.", len);
                        ret = MESSAGEPORT_ERROR_MAX_EXCEEDED;
+                       goto out;
                }
 
                body = g_variant_new("(ssbbssbus)", __app_id, (local_port) ? local_port : "", local_trusted, bi_dir,
                                remote_appid, remote_port, trusted_message, len, raw);
-
-
                if (strcmp(remote_appid, __app_id) != 0) { /* self send */
 
                        /*  if message-port fail to get socket pair, communicate using GDBus */
-                       if (aul_request_message_port_socket_pair(port_info->sock_pair) != AUL_R_OK) {
+                       if (aul_request_message_port_socket_pair(sock_pair) != AUL_R_OK) {
                                _LOGE("error create socket pair");
                        } else {
 
-                               _LOGI("sock pair : %d, %d", port_info->sock_pair[0], port_info->sock_pair[1]);
-
+                               _LOGI("sock pair : %d, %d",
+                                               sock_pair[SOCK_PAIR_SENDER], sock_pair[SOCK_PAIR_RECEIVER]);
                                fd_list = g_unix_fd_list_new();
-                               g_unix_fd_list_append(fd_list, port_info->sock_pair[1], &err);
-                               g_unix_fd_list_append(fd_list, port_info->sock_pair[0], &err);
-
+                               g_unix_fd_list_append(fd_list, sock_pair[SOCK_PAIR_RECEIVER], &err);
                                if (err != NULL) {
-                                       _LOGE("g_unix_fd_list_append [%s]", error->message);
+                                       _LOGE("g_unix_fd_list_append [%s]", err->message);
                                        ret = MESSAGEPORT_ERROR_IO_ERROR;
                                        g_error_free(err);
                                        goto out;
                                }
-                       }
 
+                               port_info->send_sock_fd = sock_pair[SOCK_PAIR_SENDER];
+                               close(sock_pair[SOCK_PAIR_RECEIVER]);
+                               sock_pair[SOCK_PAIR_RECEIVER] = 0;
+
+                               port_info->gio_read = g_io_channel_unix_new(port_info->send_sock_fd);
+                               if (!port_info->gio_read) {
+                                       _LOGE("Error is %s\n", strerror_r(errno, buf, sizeof(buf)));
+                                       ret = MESSAGEPORT_ERROR_IO_ERROR;
+                                       goto out;
+                               }
+
+                               port_info->g_src_id = g_io_add_watch(
+                                               port_info->gio_read,
+                                               G_IO_IN | G_IO_HUP,
+                                               __socket_disconnect_handler,
+                                               (gpointer)port_info);
+                               if (port_info->g_src_id == 0) {
+                                       _LOGE("fail to add watch on socket");
+                                       ret = MESSAGEPORT_ERROR_IO_ERROR;
+                                       goto out;
+                               }
+
+                       }
                }
 
                msg = g_dbus_message_new_method_call(bus_name, MESSAGEPORT_OBJECT_PATH, interface_name, "send_message");
@@ -1367,7 +1922,6 @@ static int __message_port_send_message(const char *remote_appid, const char *rem
 
                g_dbus_message_set_unix_fd_list(msg, fd_list);
                g_dbus_message_set_body(msg, body);
-               g_dbus_message_set_flags(msg, G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED);
                g_dbus_connection_send_message(__gdbus_conn, msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &err);
                if (err != NULL) {
                        _LOGE("No reply. error = %s", err->message);
@@ -1375,8 +1929,6 @@ static int __message_port_send_message(const char *remote_appid, const char *rem
                        ret = MESSAGEPORT_ERROR_IO_ERROR;
                        goto out;
                }
-
-
        }
 
 out:
@@ -1387,6 +1939,13 @@ out:
        if (fd_list)
                g_object_unref(fd_list);
 
+       if (ret != MESSAGEPORT_ERROR_NONE) {
+               __free_port_info((gpointer)port_info);
+               if (sock_pair[SOCK_PAIR_SENDER])
+                       close(sock_pair[SOCK_PAIR_SENDER]);
+               if (sock_pair[SOCK_PAIR_RECEIVER])
+                       close(sock_pair[SOCK_PAIR_RECEIVER]);
+       }
 
        return ret;
 }
@@ -1398,11 +1957,99 @@ int __message_send_bidirectional_message(int id, const char *remote_app_id, cons
        if (ret != MESSAGEPORT_ERROR_NONE)
                return ret;
 
-       _LOGI("bidirectional_message %s", local_info->port_name);
+       _LOGD("bidirectional_message %s", local_info->port_name);
        return __message_port_send_message(remote_app_id, remote_port,
                        local_info->port_name, trusted_message, local_info->is_trusted, true, message);
 }
 
+static void __name_registered(GDBusConnection *connection,
+               const gchar *name,
+               const gchar *name_owner,
+               gpointer user_data)
+{
+
+       registered_callback_info_s *info = (registered_callback_info_s *)user_data;
+       if (info == NULL) {
+               LOGE("NULL registered_callback_info");
+               return;
+       }
+
+       _LOGI("watcher_id : %d, appeared name : %s , name_owner : %s\n", info->watcher_id, name, name_owner);
+       if (info->registered_cb)
+               info->registered_cb(info->remote_app_id, info->remote_port, info->is_trusted, info->user_data);
+}
+
+static void __name_unregistered(GDBusConnection *connection,
+               const gchar *name,
+               gpointer user_data)
+{
+
+       registered_callback_info_s *info = (registered_callback_info_s *)user_data;
+       if (info == NULL) {
+               LOGE("NULL registered_callback_info");
+               return;
+       }
+
+       _LOGI("watcher_id : %d, vanished name : %s\n", info->watcher_id, name);
+       if (info->unregistered_cb)
+               info->unregistered_cb(info->remote_app_id, info->remote_port, info->is_trusted, info->user_data);
+}
+
+int __messageport_watch_remote_port(int *watcher_id, const char *remote_app_id, const char *remote_port, bool trusted_remote_port, messageport_registration_event_cb registered_cb, messageport_registration_event_cb unregistered_cb, void *user_data)
+{
+       int ret_val = MESSAGEPORT_ERROR_NONE;
+       message_port_remote_app_info_s *remote_app_info = NULL;
+       port_list_info_s *port_info = NULL;
+
+       _LOGI("remote_app_id, app_id :[%s : %s] ", remote_app_id, __app_id);
+
+       ret_val = __get_remote_port_info(remote_app_id, remote_port, trusted_remote_port, &remote_app_info, &port_info);
+       if (ret_val != MESSAGEPORT_ERROR_NONE)
+               return ret_val;
+
+       if (__registered_callback_info_hash == NULL)
+               __registered_callback_info_hash = g_hash_table_new_full(g_direct_hash,  g_direct_equal, NULL, __registered_callback_info_free);
+
+       registered_callback_info_s *registered_cb_info = (registered_callback_info_s *)calloc(1, sizeof(registered_callback_info_s));
+       retvm_if(!registered_cb_info, MESSAGEPORT_ERROR_OUT_OF_MEMORY, "Malloc failed");
+
+       registered_cb_info->registered_cb = registered_cb;
+       registered_cb_info->unregistered_cb = unregistered_cb;
+       registered_cb_info->user_data = user_data;
+       registered_cb_info->remote_app_id = strdup(remote_app_info->remote_app_id);
+       if (registered_cb_info->remote_app_id == NULL) {
+               free(registered_cb_info);
+               return MESSAGEPORT_ERROR_OUT_OF_MEMORY;
+       }
+       registered_cb_info->remote_port = strdup(port_info->port_name);
+       if (registered_cb_info->remote_port == NULL) {
+               free(registered_cb_info->remote_app_id);
+               free(registered_cb_info);
+               return MESSAGEPORT_ERROR_OUT_OF_MEMORY;
+       }
+
+       registered_cb_info->watcher_id = g_bus_watch_name_on_connection(
+                       __gdbus_conn,
+                       port_info->encoded_bus_name,
+                       G_BUS_NAME_WATCHER_FLAGS_NONE,
+                       __name_registered,
+                       __name_unregistered,
+                       registered_cb_info,
+                       NULL);
+       if (registered_cb_info->watcher_id == 0) {
+               free(registered_cb_info->remote_app_id);
+               free(registered_cb_info->remote_port);
+               free(registered_cb_info);
+               return MESSAGEPORT_ERROR_IO_ERROR;
+       }
+
+       g_hash_table_insert(__registered_callback_info_hash,
+                       GINT_TO_POINTER(registered_cb_info->watcher_id), registered_cb_info);
+
+       *watcher_id = registered_cb_info->watcher_id;
+       return MESSAGEPORT_ERROR_NONE;
+}
+
 int messageport_unregister_local_port(int local_port_id, bool trusted_port)
 {
 
@@ -1422,6 +2069,8 @@ int messageport_unregister_local_port(int local_port_id, bool trusted_port)
        if (mi->is_trusted != trusted_port)
                return MESSAGEPORT_ERROR_INVALID_PARAMETER;
 
+       g_hash_table_remove(__callback_info_hash, GUINT_TO_POINTER(local_port_id));
+
        bus_name = __get_encoded_name(__app_id, mi->port_name, mi->is_trusted);
        if (bus_name == NULL)
                return MESSAGEPORT_ERROR_OUT_OF_MEMORY;
@@ -1565,32 +2214,42 @@ int messageport_send_bidirectional_trusted_message(int id, const char *remote_ap
        return __message_send_bidirectional_message(id, remote_app_id, remote_port, true, message);
 }
 
-int messageport_get_local_port_name(int id, char **name)
+int messageport_add_registered_cb(const char *remote_app_id, const char *remote_port, bool is_trusted, messageport_registration_event_cb registered_cb, void *user_data, int *watcher_id)
 {
-       message_port_local_port_info_s *local_info;
-       int ret = __get_local_port_info(id, &local_info);
+       if (!_initialized) {
+               if (!__initialize())
+                       return MESSAGEPORT_ERROR_IO_ERROR;
+       }
+       return __messageport_watch_remote_port(watcher_id, remote_app_id, remote_port, is_trusted, registered_cb, NULL, user_data);
+}
 
-       if (ret != MESSAGEPORT_ERROR_NONE)
-               return ret;
+int messageport_add_unregistered_cb(const char *remote_app_id, const char *remote_port, bool is_trusted, messageport_registration_event_cb unregistered_cb, void *user_data, int *watcher_id)
+{
+       if (!_initialized) {
+               if (!__initialize())
+                       return MESSAGEPORT_ERROR_IO_ERROR;
+       }
+       return __messageport_watch_remote_port(watcher_id, remote_app_id, remote_port, is_trusted, NULL, unregistered_cb, user_data);
+}
 
-       *name = strdup(local_info->port_name);
 
-       if (*name == NULL)
-               return MESSAGEPORT_ERROR_OUT_OF_MEMORY;
+int messageport_remove_registration_event_cb(int watcher_id)
+{
+       registered_callback_info_s *registered_cb_info = NULL;
+       gboolean remove_result = FALSE;
 
-       return MESSAGEPORT_ERROR_NONE;
-}
+       if (watcher_id < 1)
+               return MESSAGEPORT_ERROR_INVALID_PARAMETER;
 
-int messageport_check_trusted_local_port(int id, bool *trusted)
-{
-       message_port_local_port_info_s *local_info;
-       int ret = __get_local_port_info(id, &local_info);
+       registered_cb_info = g_hash_table_lookup(__registered_callback_info_hash, GINT_TO_POINTER(watcher_id));
+       if (registered_cb_info == NULL)
+               return MESSAGEPORT_ERROR_INVALID_PARAMETER;
 
-       if (ret != MESSAGEPORT_ERROR_NONE)
-               return ret;
+       remove_result = g_hash_table_remove(__registered_callback_info_hash, GINT_TO_POINTER(watcher_id));
+       if (!remove_result)
+               return MESSAGEPORT_ERROR_IO_ERROR;
 
-       *trusted = local_info->is_trusted;
+       g_bus_unwatch_name(watcher_id);
 
-       return MESSAGEPORT_ERROR_NONE;;
+       return MESSAGEPORT_ERROR_NONE;
 }
-