Updated connman to version 1.35
[platform/upstream/connman.git] / gdbus / client.c
old mode 100644 (file)
new mode 100755 (executable)
index 4d1970b..9748ae2
@@ -25,6 +25,7 @@
 #include <config.h>
 #endif
 
+#include <stdio.h>
 #include <glib.h>
 #include <dbus/dbus.h>
 
 
 #define METHOD_CALL_TIMEOUT (300 * 1000)
 
+#ifndef DBUS_INTERFACE_OBJECT_MANAGER
+#define DBUS_INTERFACE_OBJECT_MANAGER DBUS_INTERFACE_DBUS ".ObjectManager"
+#endif
+
 struct GDBusClient {
-       gint ref_count;
+       int ref_count;
        DBusConnection *dbus_conn;
        char *service_name;
-       char *unique_name;
        char *base_path;
+       char *root_path;
+       guint watch;
+       guint added_watch;
+       guint removed_watch;
        GPtrArray *match_rules;
        DBusPendingCall *pending_call;
+       DBusPendingCall *get_objects_call;
        GDBusWatchFunction connect_func;
        void *connect_data;
        GDBusWatchFunction disconn_func;
+       gboolean connected;
        void *disconn_data;
        GDBusMessageFunction signal_func;
        void *signal_data;
        GDBusProxyFunction proxy_added;
        GDBusProxyFunction proxy_removed;
+#if !defined TIZEN_EXT
+       GDBusClientFunction ready;
+       void *ready_data;
+#endif
        GDBusPropertyFunction property_changed;
        void *user_data;
        GList *proxy_list;
 };
 
 struct GDBusProxy {
-       gint ref_count;
+       int ref_count;
        GDBusClient *client;
        char *obj_path;
        char *interface;
        GHashTable *prop_list;
-       char *match_rule;
+       guint watch;
        GDBusPropertyFunction prop_func;
        void *prop_data;
+       GDBusProxyFunction removed_func;
+       void *removed_data;
 };
 
 struct prop_entry {
@@ -97,7 +113,7 @@ static gboolean modify_match(DBusConnection *conn, const char *member,
        dbus_message_append_args(msg, DBUS_TYPE_STRING, &rule,
                                                DBUS_TYPE_INVALID);
 
-       if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) {
+       if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) {
                dbus_message_unref(msg);
                return FALSE;
        }
@@ -201,8 +217,9 @@ static void prop_entry_free(gpointer data)
 }
 
 static void add_property(GDBusProxy *proxy, const char *name,
-                                               DBusMessageIter *iter)
+                               DBusMessageIter *iter, gboolean send_changed)
 {
+       GDBusClient *client = proxy->client;
        DBusMessageIter value;
        struct prop_entry *prop;
 
@@ -213,20 +230,8 @@ static void add_property(GDBusProxy *proxy, const char *name,
 
        prop = g_hash_table_lookup(proxy->prop_list, name);
        if (prop != NULL) {
-               GDBusClient *client = proxy->client;
-
                prop_entry_update(prop, &value);
-
-               if (proxy->prop_func)
-                       proxy->prop_func(proxy, name, &value, proxy->prop_data);
-
-               if (client == NULL)
-                       return;
-
-               if (client->property_changed)
-                       client->property_changed(proxy, name, &value,
-                                                       client->user_data);
-               return;
+               goto done;
        }
 
        prop = prop_entry_new(name, &value);
@@ -235,11 +240,20 @@ static void add_property(GDBusProxy *proxy, const char *name,
 
        g_hash_table_replace(proxy->prop_list, prop->name, prop);
 
+done:
        if (proxy->prop_func)
                proxy->prop_func(proxy, name, &value, proxy->prop_data);
+
+       if (client == NULL || send_changed == FALSE)
+               return;
+
+       if (client->property_changed)
+               client->property_changed(proxy, name, &value,
+                                                       client->user_data);
 }
 
-static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter)
+static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter,
+                                                       gboolean send_changed)
 {
        DBusMessageIter dict;
 
@@ -260,7 +274,7 @@ static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter)
                dbus_message_iter_get_basic(&entry, &name);
                dbus_message_iter_next(&entry);
 
-               add_property(proxy, name, &entry);
+               add_property(proxy, name, &entry, send_changed);
 
                dbus_message_iter_next(&dict);
        }
@@ -283,13 +297,15 @@ static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
 
        dbus_message_iter_init(reply, &iter);
 
-       update_properties(proxy, &iter);
+       update_properties(proxy, &iter, FALSE);
 
 done:
-       if (client->proxy_added)
-               client->proxy_added(proxy, client->user_data);
+       if (g_list_find(client->proxy_list, proxy) == NULL) {
+               if (client->proxy_added)
+                       client->proxy_added(proxy, client->user_data);
 
-       client->proxy_list = g_list_append(client->proxy_list, proxy);
+               client->proxy_list = g_list_append(client->proxy_list, proxy);
+       }
 
        dbus_message_unref(reply);
 
@@ -311,7 +327,7 @@ static void get_all_properties(GDBusProxy *proxy)
        dbus_message_append_args(msg, DBUS_TYPE_STRING, &proxy->interface,
                                                        DBUS_TYPE_INVALID);
 
-       if (dbus_connection_send_with_reply(client->dbus_conn, msg,
+       if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
                                                        &call, -1) == FALSE) {
                dbus_message_unref(msg);
                return;
@@ -343,6 +359,52 @@ static GDBusProxy *proxy_lookup(GDBusClient *client, const char *path,
        return NULL;
 }
 
+static gboolean properties_changed(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       GDBusProxy *proxy = user_data;
+       GDBusClient *client = proxy->client;
+       DBusMessageIter iter, entry;
+       const char *interface;
+
+       if (dbus_message_iter_init(msg, &iter) == FALSE)
+               return TRUE;
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return TRUE;
+
+       dbus_message_iter_get_basic(&iter, &interface);
+       dbus_message_iter_next(&iter);
+
+       update_properties(proxy, &iter, TRUE);
+
+       dbus_message_iter_next(&iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               return TRUE;
+
+       dbus_message_iter_recurse(&iter, &entry);
+
+       while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
+               const char *name;
+
+               dbus_message_iter_get_basic(&entry, &name);
+
+               g_hash_table_remove(proxy->prop_list, name);
+
+               if (proxy->prop_func)
+                       proxy->prop_func(proxy, name, NULL, proxy->prop_data);
+
+               if (client->property_changed)
+                       client->property_changed(proxy, name, NULL,
+                                                       client->user_data);
+
+               dbus_message_iter_next(&entry);
+       }
+
+       return TRUE;
+}
+
 static GDBusProxy *proxy_new(GDBusClient *client, const char *path,
                                                const char *interface)
 {
@@ -358,14 +420,12 @@ static GDBusProxy *proxy_new(GDBusClient *client, const char *path,
 
        proxy->prop_list = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                        NULL, prop_entry_free);
-
-       proxy->match_rule = g_strdup_printf("type='signal',"
-                               "sender='%s',path='%s',interface='%s',"
-                               "member='PropertiesChanged',arg0='%s'",
-                               client->service_name, proxy->obj_path,
-                               DBUS_INTERFACE_PROPERTIES, proxy->interface);
-
-       modify_match(client->dbus_conn, "AddMatch", proxy->match_rule);
+       proxy->watch = g_dbus_add_properties_watch(client->dbus_conn,
+                                                       client->service_name,
+                                                       proxy->obj_path,
+                                                       proxy->interface,
+                                                       properties_changed,
+                                                       proxy, NULL);
 
        return g_dbus_proxy_ref(proxy);
 }
@@ -380,17 +440,16 @@ static void proxy_free(gpointer data)
                if (client->proxy_removed)
                        client->proxy_removed(proxy, client->user_data);
 
-               modify_match(client->dbus_conn, "RemoveMatch",
-                                                       proxy->match_rule);
-
-               g_free(proxy->match_rule);
-               proxy->match_rule = NULL;
+               g_dbus_remove_watch(client->dbus_conn, proxy->watch);
 
                g_hash_table_remove_all(proxy->prop_list);
 
                proxy->client = NULL;
        }
 
+       if (proxy->removed_func)
+               proxy->removed_func(proxy, proxy->removed_data);
+
        g_dbus_proxy_unref(proxy);
 }
 
@@ -439,7 +498,7 @@ GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy)
        if (proxy == NULL)
                return NULL;
 
-       g_atomic_int_inc(&proxy->ref_count);
+       __sync_fetch_and_add(&proxy->ref_count, 1);
 
        return proxy;
 }
@@ -449,7 +508,7 @@ void g_dbus_proxy_unref(GDBusProxy *proxy)
        if (proxy == NULL)
                return;
 
-       if (g_atomic_int_dec_and_test(&proxy->ref_count) == FALSE)
+       if (__sync_sub_and_fetch(&proxy->ref_count, 1) > 0)
                return;
 
        g_hash_table_destroy(proxy->prop_list);
@@ -523,7 +582,7 @@ static void refresh_property_reply(DBusPendingCall *call, void *user_data)
 
                dbus_message_iter_init(reply, &iter);
 
-               add_property(data->proxy, data->name, &iter);
+               add_property(data->proxy, data->name, &iter, TRUE);
        } else
                dbus_error_free(&error);
 
@@ -564,7 +623,7 @@ gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name)
                                                        &proxy->interface);
        dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
 
-       if (dbus_connection_send_with_reply(client->dbus_conn, msg,
+       if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
                                                        &call, -1) == FALSE) {
                dbus_message_unref(msg);
                refresh_property_free(data);
@@ -657,7 +716,95 @@ gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
        dbus_message_iter_append_basic(&variant, type, value);
        dbus_message_iter_close_container(&iter, &variant);
 
-       if (dbus_connection_send_with_reply(client->dbus_conn, msg,
+       if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
+                                                       &call, -1) == FALSE) {
+               dbus_message_unref(msg);
+               g_free(data);
+               return FALSE;
+       }
+
+       dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
+       dbus_pending_call_unref(call);
+
+       dbus_message_unref(msg);
+
+       return TRUE;
+}
+
+#if !defined TIZEN_EXT
+gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy,
+                               const char *name, int type, const void *value,
+                               size_t size, GDBusResultFunction function,
+                               void *user_data, GDBusDestroyFunction destroy)
+{
+       struct set_property_data *data;
+       GDBusClient *client;
+       DBusMessage *msg;
+       DBusMessageIter iter, variant, array;
+       DBusPendingCall *call;
+       char array_sig[3];
+       char type_sig[2];
+
+       if (!proxy || !name || !value)
+               return FALSE;
+
+       if (!dbus_type_is_basic(type))
+               return FALSE;
+
+       client = proxy->client;
+       if (!client)
+               return FALSE;
+
+       data = g_try_new0(struct set_property_data, 1);
+       if (!data)
+               return FALSE;
+
+       data->function = function;
+       data->user_data = user_data;
+       data->destroy = destroy;
+
+       msg = dbus_message_new_method_call(client->service_name,
+                                               proxy->obj_path,
+                                               DBUS_INTERFACE_PROPERTIES,
+                                               "Set");
+       if (!msg) {
+               g_free(data);
+               return FALSE;
+       }
+
+       array_sig[0] = DBUS_TYPE_ARRAY;
+       array_sig[1] = (char) type;
+       array_sig[2] = '\0';
+
+       type_sig[0] = (char) type;
+       type_sig[1] = '\0';
+
+       dbus_message_iter_init_append(msg, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+                                                       &proxy->interface);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+                                                       array_sig, &variant);
+
+       dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+                                                       type_sig, &array);
+
+       if (dbus_type_is_fixed(type))
+               dbus_message_iter_append_fixed_array(&array, type, &value,
+                                                                       size);
+       else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
+               const char **str = (const char **) value;
+               size_t i;
+
+               for (i = 0; i < size; i++)
+                       dbus_message_iter_append_basic(&array, type, &str[i]);
+       }
+
+       dbus_message_iter_close_container(&variant, &array);
+       dbus_message_iter_close_container(&iter, &variant);
+
+       if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
                                                        &call, -1) == FALSE) {
                dbus_message_unref(msg);
                g_free(data);
@@ -671,6 +818,7 @@ gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
 
        return TRUE;
 }
+#endif
 
 struct method_call_data {
        GDBusReturnFunction function;
@@ -709,29 +857,31 @@ gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
        if (client == NULL)
                return FALSE;
 
-       data = g_try_new0(struct method_call_data, 1);
-       if (data == NULL)
-               return FALSE;
-
-       data->function = function;
-       data->user_data = user_data;
-       data->destroy = destroy;
-
        msg = dbus_message_new_method_call(client->service_name,
                                proxy->obj_path, proxy->interface, method);
-       if (msg == NULL) {
-               g_free(data);
+       if (msg == NULL)
                return FALSE;
-       }
 
        if (setup) {
                DBusMessageIter iter;
 
                dbus_message_iter_init_append(msg, &iter);
-               setup(&iter, data->user_data);
+               setup(&iter, user_data);
        }
 
-       if (dbus_connection_send_with_reply(client->dbus_conn, msg,
+       if (!function)
+               return g_dbus_send_message(client->dbus_conn, msg);
+
+       data = g_try_new0(struct method_call_data, 1);
+       if (data == NULL)
+               return FALSE;
+
+       data->function = function;
+       data->user_data = user_data;
+       data->destroy = destroy;
+
+
+       if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
                                        &call, METHOD_CALL_TIMEOUT) == FALSE) {
                dbus_message_unref(msg);
                g_free(data);
@@ -758,62 +908,28 @@ gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
        return TRUE;
 }
 
-static void properties_changed(GDBusClient *client, const char *path,
-                                                       DBusMessage *msg)
+gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
+                               GDBusProxyFunction function, void *user_data)
 {
-       GDBusProxy *proxy = NULL;
-       DBusMessageIter iter, entry;
-       const char *interface;
-       GList *list;
+       if (proxy == NULL)
+               return FALSE;
 
-       if (dbus_message_iter_init(msg, &iter) == FALSE)
-               return;
+       proxy->removed_func = function;
+       proxy->removed_data = user_data;
 
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-               return;
+       return TRUE;
+}
 
-       dbus_message_iter_get_basic(&iter, &interface);
-       dbus_message_iter_next(&iter);
+static void refresh_properties(GDBusClient *client)
+{
+       GList *list;
 
        for (list = g_list_first(client->proxy_list); list;
                                                list = g_list_next(list)) {
-               GDBusProxy *data = list->data;
-
-               if (g_str_equal(data->interface, interface) == TRUE &&
-                               g_str_equal(data->obj_path, path) == TRUE) {
-                       proxy = data;
-                       break;
-               }
-       }
-
-       if (proxy == NULL)
-               return;
-
-       update_properties(proxy, &iter);
-
-       dbus_message_iter_next(&iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
-               return;
-
-       dbus_message_iter_recurse(&iter, &entry);
-
-       while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
-               const char *name;
-
-               dbus_message_iter_get_basic(&entry, &name);
-
-               g_hash_table_remove(proxy->prop_list, name);
-
-               if (proxy->prop_func)
-                       proxy->prop_func(proxy, name, NULL, proxy->prop_data);
-
-               if (client->property_changed)
-                       client->property_changed(proxy, name, NULL,
-                                                       client->user_data);
+               GDBusProxy *proxy = list->data;
 
-               dbus_message_iter_next(&entry);
-       }
+               get_all_properties(proxy);
+        }
 }
 
 static void parse_properties(GDBusClient *client, const char *path,
@@ -829,7 +945,7 @@ static void parse_properties(GDBusClient *client, const char *path,
 
        proxy = proxy_lookup(client, path, interface);
        if (proxy) {
-               update_properties(proxy, iter);
+               update_properties(proxy, iter, FALSE);
                return;
        }
 
@@ -837,7 +953,7 @@ static void parse_properties(GDBusClient *client, const char *path,
        if (proxy == NULL)
                return;
 
-       update_properties(proxy, iter);
+       update_properties(proxy, iter, FALSE);
 
        if (client->proxy_added)
                client->proxy_added(proxy, client->user_data);
@@ -873,16 +989,18 @@ static void parse_interfaces(GDBusClient *client, const char *path,
        }
 }
 
-static void interfaces_added(GDBusClient *client, DBusMessage *msg)
+static gboolean interfaces_added(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
 {
+       GDBusClient *client = user_data;
        DBusMessageIter iter;
        const char *path;
 
        if (dbus_message_iter_init(msg, &iter) == FALSE)
-               return;
+               return TRUE;
 
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
-               return;
+               return TRUE;
 
        dbus_message_iter_get_basic(&iter, &path);
        dbus_message_iter_next(&iter);
@@ -892,24 +1010,28 @@ static void interfaces_added(GDBusClient *client, DBusMessage *msg)
        parse_interfaces(client, path, &iter);
 
        g_dbus_client_unref(client);
+
+       return TRUE;
 }
 
-static void interfaces_removed(GDBusClient *client, DBusMessage *msg)
+static gboolean interfaces_removed(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
 {
+       GDBusClient *client = user_data;
        DBusMessageIter iter, entry;
        const char *path;
 
        if (dbus_message_iter_init(msg, &iter) == FALSE)
-               return;
+               return TRUE;
 
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
-               return;
+               return TRUE;
 
        dbus_message_iter_get_basic(&iter, &path);
        dbus_message_iter_next(&iter);
 
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
-               return;
+               return TRUE;
 
        dbus_message_iter_recurse(&iter, &entry);
 
@@ -924,6 +1046,8 @@ static void interfaces_removed(GDBusClient *client, DBusMessage *msg)
        }
 
        g_dbus_client_unref(client);
+
+       return TRUE;
 }
 
 static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
@@ -963,6 +1087,8 @@ static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
        DBusMessage *reply = dbus_pending_call_steal_reply(call);
        DBusError error;
 
+       g_dbus_client_ref(client);
+
        dbus_error_init(&error);
 
        if (dbus_set_error_from_message(&error, reply) == TRUE) {
@@ -973,197 +1099,110 @@ static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
        parse_managed_objects(client, reply);
 
 done:
+#if !defined TIZEN_EXT
+       if (client->ready)
+               client->ready(client, client->ready_data);
+#endif
+
        dbus_message_unref(reply);
 
+       dbus_pending_call_unref(client->get_objects_call);
+       client->get_objects_call = NULL;
+
        g_dbus_client_unref(client);
 }
 
 static void get_managed_objects(GDBusClient *client)
 {
        DBusMessage *msg;
-       DBusPendingCall *call;
 
-       if (!client->proxy_added && !client->proxy_removed)
+       if (!client->connected)
+               return;
+
+       if ((!client->proxy_added && !client->proxy_removed) ||
+                                                       !client->root_path) {
+               refresh_properties(client);
+               return;
+       }
+
+       if (client->get_objects_call != NULL)
                return;
 
-       msg = dbus_message_new_method_call(client->service_name, "/",
-                                       DBUS_INTERFACE_DBUS ".ObjectManager",
-                                                       "GetManagedObjects");
+       msg = dbus_message_new_method_call(client->service_name,
+                                               client->root_path,
+                                               DBUS_INTERFACE_OBJECT_MANAGER,
+                                               "GetManagedObjects");
        if (msg == NULL)
                return;
 
        dbus_message_append_args(msg, DBUS_TYPE_INVALID);
 
-       if (dbus_connection_send_with_reply(client->dbus_conn, msg,
-                                                       &call, -1) == FALSE) {
+       if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
+                               &client->get_objects_call, -1) == FALSE) {
                dbus_message_unref(msg);
                return;
        }
 
-       g_dbus_client_ref(client);
-
-       dbus_pending_call_set_notify(call, get_managed_objects_reply,
-                                                       client, NULL);
-       dbus_pending_call_unref(call);
+       dbus_pending_call_set_notify(client->get_objects_call,
+                                               get_managed_objects_reply,
+                                               client, NULL);
 
        dbus_message_unref(msg);
 }
 
-static void get_name_owner_reply(DBusPendingCall *call, void *user_data)
+static void service_connect(DBusConnection *conn, void *user_data)
 {
        GDBusClient *client = user_data;
-       DBusMessage *reply = dbus_pending_call_steal_reply(call);
-       DBusError error;
-       const char *name;
 
-       dbus_error_init(&error);
-
-       if (dbus_set_error_from_message(&error, reply) == TRUE) {
-               dbus_error_free(&error);
-               goto done;
-       }
-
-       if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &name,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               goto done;
+       g_dbus_client_ref(client);
 
-       if (client->unique_name == NULL) {
-               client->unique_name = g_strdup(name);
+       client->connected = TRUE;
 
-               if (client->connect_func)
-                       client->connect_func(client->dbus_conn,
-                                                       client->connect_data);
-       }
+       if (client->connect_func)
+               client->connect_func(conn, client->connect_data);
 
-done:
-       dbus_message_unref(reply);
+       get_managed_objects(client);
 
-       dbus_pending_call_unref(client->pending_call);
-       client->pending_call = NULL;
+       g_dbus_client_unref(client);
 }
 
-static void get_name_owner(GDBusClient *client, const char *name)
+static void service_disconnect(DBusConnection *conn, void *user_data)
 {
-       DBusMessage *msg;
-
-       msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
-                                       DBUS_INTERFACE_DBUS, "GetNameOwner");
-       if (msg == NULL)
-               return;
-
-       dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
-                                               DBUS_TYPE_INVALID);
+       GDBusClient *client = user_data;
 
-       if (dbus_connection_send_with_reply(client->dbus_conn, msg,
-                                       &client->pending_call, -1) == FALSE) {
-               dbus_message_unref(msg);
-               return;
-       }
+       client->connected = FALSE;
 
-       dbus_pending_call_set_notify(client->pending_call,
-                                       get_name_owner_reply, client, NULL);
+       g_list_free_full(client->proxy_list, proxy_free);
+       client->proxy_list = NULL;
 
-       dbus_message_unref(msg);
+       if (client->disconn_func)
+               client->disconn_func(conn, client->disconn_data);
 }
 
 static DBusHandlerResult message_filter(DBusConnection *connection,
                                        DBusMessage *message, void *user_data)
 {
        GDBusClient *client = user_data;
-       const char *sender;
+       const char *sender, *path, *interface;
 
        if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
        sender = dbus_message_get_sender(message);
+       if (sender == NULL)
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-       if (g_str_equal(sender, DBUS_SERVICE_DBUS) == TRUE) {
-               const char *interface, *member;
-               const char *name, *old, *new;
-
-               interface = dbus_message_get_interface(message);
-
-               if (g_str_equal(interface, DBUS_INTERFACE_DBUS) == FALSE)
-                       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-               member = dbus_message_get_member(message);
-
-               if (g_str_equal(member, "NameOwnerChanged") == FALSE)
-                       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-               if (dbus_message_get_args(message, NULL,
-                                               DBUS_TYPE_STRING, &name,
-                                               DBUS_TYPE_STRING, &old,
-                                               DBUS_TYPE_STRING, &new,
-                                               DBUS_TYPE_INVALID) == FALSE)
-                       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-               if (g_str_equal(name, client->service_name) == FALSE)
-                       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-               if (*new == '\0' && client->unique_name != NULL &&
-                               g_str_equal(old, client->unique_name) == TRUE) {
-                       if (client->disconn_func)
-                               client->disconn_func(client->dbus_conn,
-                                                       client->disconn_data);
-
-                       g_free(client->unique_name);
-                       client->unique_name = NULL;
-               } else if (*old == '\0' && client->unique_name == NULL) {
-                       client->unique_name = g_strdup(new);
-
-                       if (client->connect_func)
-                               client->connect_func(client->dbus_conn,
-                                                       client->connect_data);
-
-                       get_managed_objects(client);
-               }
+       path = dbus_message_get_path(message);
+       interface = dbus_message_get_interface(message);
 
+       if (g_str_has_prefix(path, client->base_path) == FALSE)
                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
 
-       if (client->unique_name == NULL)
+       if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-       if (g_str_equal(sender, client->unique_name) == TRUE) {
-               const char *path, *interface, *member;
-
-               path = dbus_message_get_path(message);
-               interface = dbus_message_get_interface(message);
-               member = dbus_message_get_member(message);
-
-               if (g_str_equal(path, "/") == TRUE) {
-                       if (g_str_equal(interface, DBUS_INTERFACE_DBUS
-                                               ".ObjectManager") == FALSE)
-                               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-                       if (g_str_equal(member, "InterfacesAdded") == TRUE) {
-                               interfaces_added(client, message);
-                               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-                       }
-
-                       if (g_str_equal(member, "InterfacesRemoved") == TRUE) {
-                               interfaces_removed(client, message);
-                               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-                       }
-
-                       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-               }
-
-               if (g_str_has_prefix(path, client->base_path) == FALSE)
-                       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-               if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) {
-                       if (g_str_equal(member, "PropertiesChanged") == TRUE)
-                               properties_changed(client, path, message);
-
-                       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-               }
-
-               if (client->signal_func)
-                       client->signal_func(client->dbus_conn,
-                                       message, client->signal_data);
-       }
+       if (client->signal_func)
+               client->signal_func(connection, message, client->signal_data);
 
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
@@ -1171,10 +1210,18 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 GDBusClient *g_dbus_client_new(DBusConnection *connection,
                                        const char *service, const char *path)
 {
+       return g_dbus_client_new_full(connection, service, path, "/");
+}
+
+GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
+                                                       const char *service,
+                                                       const char *path,
+                                                       const char *root_path)
+{
        GDBusClient *client;
        unsigned int i;
 
-       if (connection == NULL)
+       if (!connection || !service)
                return NULL;
 
        client = g_try_new0(GDBusClient, 1);
@@ -1190,27 +1237,32 @@ GDBusClient *g_dbus_client_new(DBusConnection *connection,
        client->dbus_conn = dbus_connection_ref(connection);
        client->service_name = g_strdup(service);
        client->base_path = g_strdup(path);
+       client->root_path = g_strdup(root_path);
+       client->connected = FALSE;
 
-       get_name_owner(client, client->service_name);
-
-       client->match_rules = g_ptr_array_sized_new(4);
+       client->match_rules = g_ptr_array_sized_new(1);
        g_ptr_array_set_free_func(client->match_rules, g_free);
 
-       g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
-                               "sender='%s',path='%s',interface='%s',"
-                               "member='NameOwnerChanged',arg0='%s'",
-                               DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
-                               DBUS_INTERFACE_DBUS, client->service_name));
-       g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
-                               "sender='%s',"
-                               "path='/',interface='%s.ObjectManager',"
-                               "member='InterfacesAdded'",
-                               client->service_name, DBUS_INTERFACE_DBUS));
-       g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
-                               "sender='%s',"
-                               "path='/',interface='%s.ObjectManager',"
-                               "member='InterfacesRemoved'",
-                               client->service_name, DBUS_INTERFACE_DBUS));
+       client->watch = g_dbus_add_service_watch(connection, service,
+                                               service_connect,
+                                               service_disconnect,
+                                               client, NULL);
+
+       if (!root_path)
+               return g_dbus_client_ref(client);
+
+       client->added_watch = g_dbus_add_signal_watch(connection, service,
+                                               client->root_path,
+                                               DBUS_INTERFACE_OBJECT_MANAGER,
+                                               "InterfacesAdded",
+                                               interfaces_added,
+                                               client, NULL);
+       client->removed_watch = g_dbus_add_signal_watch(connection, service,
+                                               client->root_path,
+                                               DBUS_INTERFACE_OBJECT_MANAGER,
+                                               "InterfacesRemoved",
+                                               interfaces_removed,
+                                               client, NULL);
        g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
                                "sender='%s',path_namespace='%s'",
                                client->service_name, client->base_path));
@@ -1228,7 +1280,7 @@ GDBusClient *g_dbus_client_ref(GDBusClient *client)
        if (client == NULL)
                return NULL;
 
-       g_atomic_int_inc(&client->ref_count);
+       __sync_fetch_and_add(&client->ref_count, 1);
 
        return client;
 }
@@ -1240,7 +1292,7 @@ void g_dbus_client_unref(GDBusClient *client)
        if (client == NULL)
                return;
 
-       if (g_atomic_int_dec_and_test(&client->ref_count) == FALSE)
+       if (__sync_sub_and_fetch(&client->ref_count, 1) > 0)
                return;
 
        if (client->pending_call != NULL) {
@@ -1248,6 +1300,11 @@ void g_dbus_client_unref(GDBusClient *client)
                dbus_pending_call_unref(client->pending_call);
        }
 
+       if (client->get_objects_call != NULL) {
+               dbus_pending_call_cancel(client->get_objects_call);
+               dbus_pending_call_unref(client->get_objects_call);
+       }
+
        for (i = 0; i < client->match_rules->len; i++) {
                modify_match(client->dbus_conn, "RemoveMatch",
                                g_ptr_array_index(client->match_rules, i));
@@ -1260,14 +1317,22 @@ void g_dbus_client_unref(GDBusClient *client)
 
        g_list_free_full(client->proxy_list, proxy_free);
 
-       if (client->disconn_func)
+       /*
+        * Don't call disconn_func twice if disconnection
+        * was previously reported.
+        */
+       if (client->disconn_func && client->connected)
                client->disconn_func(client->dbus_conn, client->disconn_data);
 
+       g_dbus_remove_watch(client->dbus_conn, client->watch);
+       g_dbus_remove_watch(client->dbus_conn, client->added_watch);
+       g_dbus_remove_watch(client->dbus_conn, client->removed_watch);
+
        dbus_connection_unref(client->dbus_conn);
 
        g_free(client->service_name);
-       g_free(client->unique_name);
        g_free(client->base_path);
+       g_free(client->root_path);
 
        g_free(client);
 }
@@ -1308,6 +1373,20 @@ gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
        return TRUE;
 }
 
+#if !defined TIZEN_EXT
+gboolean g_dbus_client_set_ready_watch(GDBusClient *client,
+                               GDBusClientFunction ready, void *user_data)
+{
+       if (client == NULL)
+               return FALSE;
+
+       client->ready = ready;
+       client->ready_data = user_data;
+
+       return TRUE;
+}
+#endif
+
 gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
                                        GDBusProxyFunction proxy_added,
                                        GDBusProxyFunction proxy_removed,
@@ -1322,7 +1401,8 @@ gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
        client->property_changed = property_changed;
        client->user_data = user_data;
 
-       get_managed_objects(client);
+       if (proxy_added || proxy_removed || property_changed)
+               get_managed_objects(client);
 
        return TRUE;
 }