前一篇文章主要介绍了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);
}
来源:CSDN
作者:henry860916
链接:https://blog.csdn.net/henry860916/article/details/71276412