从废弃dbus-glib迁移至GDBus后AFPStats对象导出失败求助
DBus-glib迁移GDBus后对象导出失败排查方案
问题背景
将基于废弃dbus-glib绑定的Glib代码迁移至GDBus后,总线代理创建、DBus名称获取均无报错,但运行时触发错误:
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.UnknownMethod: Object does not exist at path “/org/netatalk/AFPStats”
说明/org/netatalk/AFPStats路径下的对象未成功导出,以下是原代码与迁移后代码及排查解决思路:
原dbus-glib实现代码
static gpointer afpstats_thread(gpointer _data) { DBusGConnection *bus; DBusGProxy *bus_proxy; GError *error = NULL; GMainContext *ctxt; GMainLoop *thread_loop; guint request_name_result; sigset_t sigs; /* Block all signals in this thread */ sigfillset(&sigs); pthread_sigmask(SIG_BLOCK, &sigs, NULL); ctxt = g_main_context_new(); thread_loop = g_main_loop_new(ctxt, FALSE); dbus_g_object_type_install_info(AFPSTATS_TYPE_OBJECT, &dbus_glib_afpstats_obj_object_info); if (!(bus = dbus_g_bus_get_private(DBUS_BUS_SYSTEM, ctxt, &error))) { LOG(log_error, logtype_afpd,"Couldn't connect to system bus: %s", error->message); return NULL; } if (!(bus_proxy = dbus_g_proxy_new_for_name(bus, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus"))) { LOG(log_error, logtype_afpd,"Couldn't create bus proxy"); return NULL; } if (!dbus_g_proxy_call(bus_proxy, "RequestName", &error, G_TYPE_STRING, "org.netatalk.AFPStats", G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &request_name_result, G_TYPE_INVALID)) { LOG(log_error, logtype_afpd, "Failed to acquire DBUS name: %s", error->message); return NULL; } AFPStatsObj *obj = g_object_new(AFPSTATS_TYPE_OBJECT, NULL); dbus_g_connection_register_g_object(bus, "/org/netatalk/AFPStats", G_OBJECT(obj)); g_main_loop_run(thread_loop); return thread_loop; }
迁移后的GDBus代码(含修正点标注)
static gpointer afpstats_thread(gpointer _data) { // 修正:原代码拼写错误GDBusGonnection → GDBusConnection GDBusConnection *bus; GDBusProxy *bus_proxy; GError *error = NULL; GMainContext *ctxt; GMainLoop *thread_loop; guint request_name_result; sigset_t sigs; /* Block all signals in this thread */ sigfillset(&sigs); pthread_sigmask(SIG_BLOCK, &sigs, NULL); ctxt = g_main_context_new(); thread_loop = g_main_loop_new(ctxt, FALSE); if (!(bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error))) { LOG(log_error, logtype_afpd,"Couldn't connect to system bus: %s", error->message); return NULL; } if (!(bus_proxy = g_dbus_proxy_new_sync(bus, G_DBUS_PROXY_FLAGS_NONE, NULL, /* GDBusInterfaceInfo */ "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", NULL, /* GCancellable */ &error))) { LOG(log_error, logtype_afpd,"Couldn't create bus proxy"); return NULL; } if (!g_dbus_proxy_call_sync(bus_proxy, "RequestName", g_variant_new("(su)", "org.netatalk.AFPStats", 0), G_DBUS_CALL_FLAGS_NONE, -1, /* timeout */ NULL, &error)) { LOG(log_error, logtype_afpd, "Failed to acquire DBUS name: %s", error->message); return NULL; } static const gchar introspection_xml[] = "<node>" " <interface name='org.netatalk.AFPStats'>" " <method name='GetUsers'>" " <arg name='ret' type='as' direction='out'/>" " </method>" " </interface>" "</node>"; // 修正:添加变量类型声明 GDBusNodeInfo *introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); g_assert (introspection_data != NULL); AFPStatsObj *obj = g_object_new(AFPSTATS_TYPE_OBJECT, NULL); // 修正:添加接口方法实现的VTable,原代码传NULL导致方法无绑定 static void get_users_handler(GDBusConnection *conn, const gchar *sender, const gchar *obj_path, const gchar *iface_name, const gchar *method_name, GVariant *params, GDBusMethodInvocation *invocation, gpointer user_data) { AFPStatsObj *stats_obj = AFPSTATS_OBJ(user_data); // 这里替换为实际的GetUsers业务逻辑,生成as类型的返回值 GVariant *result = g_variant_new_strv((const gchar*[]){"test_user"}, -1); g_dbus_method_invocation_return_value(invocation, g_variant_new("(as)", result)); } static const GDBusInterfaceVTable stats_vtable = { get_users_handler, NULL, // 忽略属性获取 NULL // 忽略属性设置 }; // 修正:添加注册错误检查,原代码未判断是否注册成功 if (!g_dbus_connection_register_object(bus, "/org/netatalk/AFPStats", introspection_data->interfaces[0], &stats_vtable, // 绑定方法实现 G_OBJECT(obj), NULL, &error)) { LOG(log_error, logtype_afpd, "Failed to register AFPStats object: %s", error->message); g_error_free(error); g_dbus_node_info_unref(introspection_data); return NULL; } g_main_loop_run(thread_loop); // 修正:添加资源清理,避免内存泄漏 g_dbus_node_info_unref(introspection_data); return thread_loop; }
核心问题与解决要点
- 拼写错误导致总线连接无效:迁移代码中
GDBusGonnection是笔误,正确类型为GDBusConnection,这会导致编译警告或运行时连接对象异常。 - 缺失接口方法实现绑定:
g_dbus_connection_register_object的第四个参数是方法回调表(GDBusInterfaceVTable),原代码传NULL意味着没有绑定GetUsers的处理逻辑,DBus无法找到对应方法,触发“对象不存在”错误。必须实现对应方法的回调并传入VTable。 - 未检查对象注册结果:原迁移代码未判断
g_dbus_connection_register_object的返回值,也未处理error,即使注册失败也无法感知,添加错误日志可直接定位注册阶段的问题。 - 主线程上下文不匹配:原dbus-glib代码使用
dbus_g_bus_get_private传入自定义线程的GMainContext,但g_bus_get_sync默认使用主线程上下文。如果需要在自定义线程运行事件循环,应确保总线连接与当前线程的上下文绑定,可改用g_dbus_connection_new_for_address_sync并指定上下文,或者在调用g_bus_get_sync前切换当前线程的上下文。 - 资源泄漏风险:
GDBusNodeInfo需要调用g_dbus_node_info_unref释放,否则会造成内存泄漏。
内容的提问来源于stack exchange,提问作者dgsga
相关产品推荐
相关产品推荐

