You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从废弃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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 14:07:00