如何使用 Bluez Profile1 DBus API 注册连接回调
Posted
技术标签:
【中文标题】如何使用 Bluez Profile1 DBus API 注册连接回调【英文标题】:How to register connection callbacks with Bluez Profile1 DBus API 【发布时间】:2019-12-21 23:52:44 【问题描述】:我正在尝试更新我们的 android 应用程序使用 rfcomm 套接字连接到的计算机上的蓝牙代码。到目前为止,我们已经使用了 bluetoothd 的 --compat 选项和一些 SDP 功能来注册我们的蓝牙服务。现在我想在 Bluez 5 中使用 DBus API 来减少它的不稳定,并可能在第一次配对后使自动连接和自动信任工作。
我可以使用 org.bluez.ProfileManager1 中的 RegisterProfile 方法注册配置文件,然后使用 bluetoothctl 在控制器上看到我的自定义 uuid,Android 应用程序也会看到它。然后我需要一些回调来触发设备连接到有一个我可以写入的套接字。我可以在 org.bluez.Device1 注册 PropertiesChanged 信号,这会在连接和断开连接时触发,但它没有给我一个套接字。我尝试在 org.bluez.Profile1 注册一个带有回调的对象,但这不会触发。我也不太确定应该如何处理 UUID,因为我们将使用具有众所周知的 UUID 的 SPP,但我也想避免与使用它的其他设备产生噪音和混淆,它应该只与我们的应用程序对话。
static const gchar btp_introspection_xml[] =
"<node>"
" <interface name='org.bluez.Profile1'>"
" <method name='Release' />"
" <method name='NewConnection'>"
" <arg type='o' name='device' direction='in' />"
" <arg type='h' name='fd' direction='in' />"
" <arg type='asv' name='fd_properties' direction='in' />"
" </method>"
" <method name='RequestDisconnection'>"
" <arg type='o' name='device' direction='in' />"
" </method>"
" </interface>"
"</node>";
int register_profile(GDBusProxy *proxy)
GVariant *profile;
GVariantBuilder profile_builder;
GError *error = NULL;
printf("register_profile called!\n");
g_variant_builder_init(&profile_builder, G_VARIANT_TYPE("(osasv)"));
if (g_variant_is_object_path("/org/bluez/customprofile"))
printf("object path is good!\n");
g_variant_builder_add (&profile_builder, "o",
"/org/bluez/customprofile");
g_variant_builder_add (&profile_builder, "s", SERIAL_PORT_PROFILE_UUID);
g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("asv"));
g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("sv"));
g_variant_builder_add (&profile_builder, "s", "Channel");
g_variant_builder_add (&profile_builder, "v", g_variant_new_uint16(22));
g_variant_builder_close(&profile_builder);
g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("sv"));
g_variant_builder_add (&profile_builder, "s", "Service");
g_variant_builder_add (&profile_builder, "v",
g_variant_new_string(CUSTOM_UUID));
g_variant_builder_close(&profile_builder);
g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("sv"));
g_variant_builder_add (&profile_builder, "s", "Name");
g_variant_builder_add (&profile_builder, "v",
g_variant_new_string("Custom Serial Port"));
g_variant_builder_close(&profile_builder);
g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("sv"));
g_variant_builder_add (&profile_builder, "s", "Role");
g_variant_builder_add (&profile_builder, "v",
g_variant_new_string("server"));
g_variant_builder_close(&profile_builder);
g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("sv"));
g_variant_builder_add (&profile_builder, "s", "RequireAuthentication");
g_variant_builder_add (&profile_builder, "v",
g_variant_new_boolean(FALSE));
g_variant_builder_close(&profile_builder);
g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("sv"));
g_variant_builder_add (&profile_builder, "s", "RequireAuthorization");
g_variant_builder_add (&profile_builder, "v",
g_variant_new_boolean(FALSE));
g_variant_builder_close(&profile_builder);
g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("sv"));
g_variant_builder_add (&profile_builder, "s", "AutoConnect");
g_variant_builder_add (&profile_builder, "v",
g_variant_new_boolean(TRUE));
g_variant_builder_close(&profile_builder);
g_variant_builder_close(&profile_builder);
profile = g_variant_builder_end(&profile_builder);
GVariant * ret = g_dbus_proxy_call_sync (proxy,
"RegisterProfile",
profile,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
g_assert_no_error(error);
if(ret != NULL && error==NULL)
return 0;
else
return 1;
static void connection_callback(GDBusConnection *conn, const char *sender,
const char *path, const char *interface, const char *method, GVariant *params,
GDBusMethodInvocation *invocation, void *userdata)
g_print("Called: %s.%s()", interface, method);
(void)conn;
(void)sender;
(void)path;
(void)params;
if (strcmp(method, "NewConnection") == 0)
g_print("connected");
else if (strcmp(method, "RequestDisconnection") == 0)
g_print("disconnected");
else if (strcmp(method, "Release") == 0)
g_print("released?");
static void bluez_signal_device_changed(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
gpointer userdata)
(void)conn;
(void)sender;
(void)path;
(void)interface;
GVariantIter *properties = NULL;
GVariantIter *unknown = NULL;
const char *iface;
const char *key;
GVariant *value = NULL;
const gchar *signature = g_variant_get_type_string(params);
if(strcmp(signature, "(sasvas)") != 0)
g_print("Invalid signature for %s: %s != %s", signal, signature, "(sasvas)");
goto done;
g_variant_get(params, "(&sasvas)", &iface, &properties, &unknown);
while(g_variant_iter_next(properties, "&sv", &key, &value))
g_print("key: %s | value: %s\n",key,value);
if(!g_strcmp0(key, "Connected"))
if(!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN))
g_print("Invalid argument type for %s: %s != %s", key,
g_variant_get_type_string(value), "b");
goto done;
gboolean status = g_variant_get_boolean(value);
g_print("Device is \"%s\"\n", status ? "Connected" : "Disconnected");
if (status)
//handle connection here instead?
else
g_print("stopping writer");
stop_bt_writer();
destroy_json_handler();
done:
if(properties != NULL)
g_variant_iter_free(properties);
if(value != NULL)
g_variant_unref(value);
void init_server()
GDBusProxy *proxy;
GDBusConnection *conn;
GError *error = NULL;
OrgBluezProfile1 *interface;
GMainLoop *loop = g_main_loop_new (NULL, FALSE);
conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
g_assert_no_error (error);
proxy = g_dbus_proxy_new_sync (conn,
G_DBUS_PROXY_FLAGS_NONE,
NULL,/* GDBusInterfaceInfo */
"org.bluez",/* name */
"/org/bluez",/* object path */
"org.bluez.ProfileManager1",/* interface */
NULL,/* GCancellable */
&error);
g_assert_no_error (error);
error=NULL;
if (register_profile (proxy))
printf("profile register failed\n");
return;
printf("SPP profile registered");
//register device property callback (connect/disconnect)
guint sub_id = g_dbus_connection_signal_subscribe(conn,
"org.bluez",
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
NULL,
"org.bluez.Device1",
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_signal_device_changed,
NULL,
NULL);
static GDBusInterfaceVTable vtable =
.method_call = connection_callback,
;
GDBusNodeInfo *introspection = g_dbus_node_info_new_for_xml(btp_introspection_xml, &error);
GDBusInterfaceInfo *interface_info = g_dbus_node_info_lookup_interface(introspection, "org.bluez.Profile1");
g_assert_no_error (error);
error=NULL;
guint regid = g_dbus_connection_register_object(conn,
"/org/bluez/customprofile",
interface_info,
&vtable,
NULL,
NULL,
&error);
g_assert_no_error (error);
printf("connection callback registered, id: %d;",regid);
g_main_loop_run (loop);
g_object_unref (proxy);
g_object_unref (conn);
return;
回调注册成功完成,输出如下:
register_profile called!
object path is good!
SPP profile registered
connection callback registered, id: 1;
所以我不明白为什么我的函数 connection_callback 永远不会触发。 感谢所有输入,我对 DBus 和蓝牙都没有经验
【问题讨论】:
【参考方案1】:我的解决方案是将 bluez 从 5.37 升级到 5.50。 我也关注了How do I register a profile with bluez using dbus/gio?上的解决方案 并且升级后没有尝试过没有这个。如果不升级,仅此一项也无济于事
【讨论】:
以上是关于如何使用 Bluez Profile1 DBus API 注册连接回调的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 dbus-send 调用 org.bluez.Adapter1.StartDiscovery?