前一篇文章主要介绍了dbus调用的流程,及简单的单工通信,这里记录下双工通信的流程,供后续参考。
定义dbus名称,路径,接口,方法等。
额外注意点:
1. 所有的全局资源必须加锁
2. handle-method-call中 从g_variant_get获得的字符串,不需要自己释放,系统会自动释放,注意如果后续需要使用,必须strdump出来。
#define TEST_DBUS_A "methodA" #define TEST_DBUS_B "methodB" #define TEST_DBUS_INTERFACE "com.test.hello" #define TEST_DBUS_OBJPATH "/com/test/hello" #define TEST_DBUS_NAME "com.test.hello" #define TEST_DBUS_TIMEOUT 100000
client
static GDBusConnection *test_client_conn = NULL; static GDBusNodeInfo *dbus_node_info = NULL; static pthread_mutex_t callback_info_list_mutex; GHashTable *g_callback_info_list = NULL; typedef struct { void *callback; void *user_data; } dbus_client_data; static void __handle_method_call(GDBusConnection *conn, const gchar *sender, const gchar *obj_path, const gchar *iface, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { printf("sender[%s],obj_path[%s],iface[%s],method_name[%s]", sender,obj_path,iface,method_name); void* callback_addr = NULL; void* ud = NULL; dbus_client_data *dcd = NULL; pthread_mutex_lock(&callback_info_list_mutex); dcd = g_hash_table_lookup(g_callback_info_list, method_name); g_hash_table_remove(g_callback_info_list, dcd); pthread_mutex_unlock(&callback_info_list_mutex); if (dcd) { callback_addr = dcd->callback; ud = dcd->user_data; } if (0 == g_strcmp0(method_name, TEST_DBUS_A)) { int ret = 0; char *string1 = NULL; if (parameters) { g_variant_get(parameters, "(&s)", &string1); } if (callback_addr != NULL) { ((cb)callback_addr)(string1, ud); } else { printf("callback address is NULL"); } g_dbus_method_invocation_return_value(invocation, g_variant_new ("(i)", ret)); } else { g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Method %s is not implemented on interface %s", method_name, iface); } if (parameters) { g_variant_unref(parameters); } g_free(dcd); } int _set_cb(void* callback, void *user_data) { dbus_client_data *dcd = calloc(1, sizeof(dbus_client_data)); dcd->callback = callback; dcd->user_data = user_data; pthread_mutex_lock(&callback_info_list_mutex); g_hash_table_insert(g_callback_info_list, TEST_DBUS_A, dcd); pthread_mutex_unlock(&callback_info_list_mutex); return ret; } int __trigger_methodB() { GError *gerr = NULL; g_dbus_connection_call_sync(test_client_conn, TEST_DBUS_NAME, TEST_DBUS_OBJPATH, TEST_DBUS_INTERFACE, TEST_DBUS_B, g_variant_new("(is)", 1, "hello"), NULL, G_DBUS_CALL_FLAGS_NONE, TEST_DBUS_TIMEOUT, NULL, &gerr); if (gerr) { printf("g_dbus_connection_call_sync() Fail(%s)", gerr->message); g_error_free (gerr); return false; } return 0; } bool _test_dbus_client_init() { if (test_client_conn) { return true; } GError *gerr = NULL; const gchar introspection_xml[] = "<node>" " <interface name='"TEST_DBUS_INTERFACE"'>" " <method name='"TEST_DBUS_A"'>" " <arg type='s' name='data' direction='in'/>" " <arg type='i' name='ret' direction='out'/>" " </method>" " </interface>" "</node>"; dbus_node_info = g_dbus_node_info_new_for_xml(introspection_xml, NULL); if (dbus_node_info == NULL) { printf("Initialization failed"); return false; } gchar *addr = g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SESSION, NULL, &gerr); if (gerr) { printf("Getting address failed (%s)", gerr->message); g_error_free(gerr); return false; } test_client_conn = g_dbus_connection_new_for_address_sync(addr, (GDBusConnectionFlags)(G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION), NULL, NULL, &gerr); g_free(addr); if (gerr) { printf("Connection failed (%s)", gerr->message); g_error_free(gerr); return false; } GDBusInterfaceVTable vtable; vtable.method_call = __handle_method_call; vtable.get_property = NULL; vtable.set_property = NULL; guint reg_id = -1; reg_id = g_dbus_connection_register_object(test_client_conn, TEST_DBUS_OBJPATH, dbus_node_info->interfaces[0], &vtable, NULL, NULL, &gerr); if (gerr) { printf("g_dbus_connection_register_object() Fail(%s)", gerr->message); g_error_free(gerr); return false; } printf("reg_id[%d]", reg_id); if (reg_id == 0) { printf("Failed to g_dbus_connection_register_object"); return false; } printf("Dbus connection established: %s", g_dbus_connection_get_unique_name(test_client_conn)); g_callback_info_list = g_hash_table_new(g_str_hash, g_str_equal); pthread_mutex_init(&callback_info_list_mutex, NULL); return true; } void _test_dbus_client_deinit(void) { if (test_client_conn) { g_dbus_connection_flush_sync(test_client_conn, NULL, NULL); g_dbus_connection_close_sync(test_client_conn, NULL, NULL); g_object_unref(test_client_conn); test_client_conn = NULL; } if (g_callback_info_list) { g_hash_table_destroy(g_callback_info_list); g_callback_info_list = NULL; } if (dbus_node_info) { g_dbus_node_info_unref(dbus_node_info); dbus_node_info = NULL; } pthread_mutex_destroy(&callback_info_list_mutex); }
server
static pthread_mutex_t callback_list_mutex; GHashTable *g_sender_info_list = NULL; static GDBusConnection *test_dbus_conn = NULL; GHashTable *g_callback_list = NULL; static void __dbus_handle_method_call(GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { printf("sender[%s],object_path[%s],interface_name[%s],method_name[%s]", sender,object_path,interface_name,method_name); if (0 == g_strcmp0(method_name, TEST_DBUS_B)) { int res = 0; char *data_str = NULL; if (parameters) { g_variant_get(parameters, "(i&s)", res, &data_str); printf("res[%d], data_str[%s]", res, data_str); } g_free(data_str); g_dbus_method_invocation_return_value(invocation, g_variant_new ("(i)", ret)); } else { g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Method %s is not implemented on interface %s", method_name, interface_name); } if (parameters) { g_variant_unref(parameters); } } static const GDBusInterfaceVTable interface_vtable = { __dbus_handle_method_call, NULL, NULL }; static void __dbus_on_bus_acquired(GDBusConnection *conn, const gchar *name, gpointer user_data) { guint registration_id = 0; GError *error = NULL; GDBusNodeInfo *introspection_data = (GDBusNodeInfo *)user_data; test_dbus_conn = conn; registration_id = g_dbus_connection_register_object(conn, TEST_DBUS_OBJPATH, introspection_data->interfaces[0], &interface_vtable, NULL,/* user_data */ NULL,/* user_data_free_func */ &error); if (0 == registration_id) { printf("g_dbus_connection_register_object() Fail(%s)", error->message); g_error_free(error); } printf("g_dbus_connection_register_object() succeed"); } static void __dbus_on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data) { printf("Lost the name %s", name); } static void __dbus_on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { printf("Acquired the name %s", name); } int _test_dbus_server_trigger_methodA(char *sender, char *data) { GError *error = NULL; GVariant *result; result = g_dbus_connection_call_sync(test_dbus_conn, sender, TEST_DBUS_OBJPATH, TEST_DBUS_INTERFACE, TEST_DBUS_A, g_variant_new("(s)", data), NULL, G_DBUS_CALL_FLAGS_NONE, TEST_DBUS_TIMEOUT, NULL, &error); if (error) { printf("g_dbus_connection_call_sync() Fail(%s)", error->message); ret = SAMSUNG_CLOUD_ERROR_UNKNOWN; goto FINISH_OFF; } if (!result) { printf ("g_dbus_connection_call_sync 'Launch' error"); ret = SAMSUNG_CLOUD_ERROR_UNKNOWN; goto FINISH_OFF; } g_variant_get(result, "(i)", &ret); printf("ret[%d]", ret); FINISH_OFF: if (error) { g_error_free (error); } if (result) { g_variant_unref(result); } return ret; } static void __hash_table_free_cb(gpointer data) { g_free(data); } unsigned int _test_dbus_server_init(CB cb) { guint id; GError *error = NULL; GDBusNodeInfo *introspection_data = NULL; const gchar introspection_xml[] = "<node>" " <interface name='"TEST_DBUS_INTERFACE"'>" " <method name='"TEST_DBUS_B"'>" " <arg type='i' name='res' direction='in'/>" " <arg type='s' name='data' direction='in'/>" " <arg type='i' name='ret' direction='out'/>" " </method>" " </interface>" "</node>"; introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, &error); if (NULL == introspection_data) { printf("g_dbus_node_info_new_for_xml() Fail(%s)", error->message); g_error_free(error); return -1; } id = g_bus_own_name(G_BUS_TYPE_SESSION, TEST_DBUS_NAME, G_BUS_NAME_OWNER_FLAGS_REPLACE, __dbus_on_bus_acquired, __dbus_on_name_acquired, __dbus_on_name_lost, introspection_data, (GDestroyNotify)g_dbus_node_info_unref); if (0 == id) { printf("g_bus_own_name() Fail"); return 0; } g_sender_info_list = g_hash_table_new_full(g_str_hash, g_str_equal, __hash_table_free_cb, __hash_table_free_cb); g_callback_list = g_hash_table_new(g_str_hash, g_str_equal); pthread_mutex_init(&callback_list_mutex, NULL); pthread_mutex_lock(&callback_list_mutex); g_hash_table_insert(g_callback_list, TEST_DBUS_C, cb); pthread_mutex_unlock(&callback_list_mutex); return id; } void _sc_dbus_server_deinit(unsigned int id) { g_bus_unown_name(id); if (g_callback_list) { g_hash_table_destroy(g_callback_list); g_callback_list = NULL; } if (g_sender_info_list) { g_hash_table_destroy(g_sender_info_list); g_sender_info_list = NULL; } pthread_mutex_destroy(&callback_list_mutex); }