Re: [PATCH v2] gdbus: Remove broad match rule and add proxy filter support
Luiz Augusto von Dentz <[email protected]> Mon, 20 Jul 2026 14:42:14 -0400
| Newsgroups | dev.linux.lists.ofono,org.kernel.vger.linux-bluetooth |
|---|---|
| Message-ID | <CABBYNZ+D8BhV_-3n+JV3715CAfZcsteAD14xyVmjpvrvwouo_g@mail.gmail.com> |
Hi Xiuzhuo, On Wed, Jul 15, 2026 at 4:59=E2=80=AFAM Xiuzhuo Shang <[email protected]> wrote: > > Problem > ------- > On embedded platforms running continuous BLE scanning, bluetoothd > eventually stalls with its D-Bus socket to dbus-daemon full. strace > on a hung bluetoothd shows a repeating pattern: > > sendmsg(7, {org.bluez.Device1 PropertiesChanged}, MSG_NOSIGNAL) > =3D -1 EAGAIN (Resource temporarily unavailable) > ppoll([{fd=3D7, events=3DPOLLOUT}], 1, {tv_sec=3D0, tv_nsec=3D0}) =3D 0= (Timeout) > > fd=3D7 never becomes writable; bluetoothd's GMainLoop remains stuck > waiting for POLLOUT and cannot dispatch any further D-Bus events, > making the daemon appear hung and unresponsive to commands. > > The backpressure chain that causes this: > 1. BLE scanning generates high-rate PropertiesChanged(RSSI) signals > (~400/s with typical BLE traffic). > 2. ofono's broad path_namespace=3D'/' match rule causes dbus-daemon to > route all these signals to ofono even though ofono has no use for > BLE RSSI data. > 3. ofono's single-threaded GLib loop cannot consume them fast enough; > undelivered messages accumulate inside dbus-daemon (457 MB > observed after ~3 hours of scanning). > 4. dbus-daemon, busy draining its write queue toward ofono, stops > reading from bluetoothd's socket in time; bluetoothd's kernel > send buffer fills up and sendmsg() returns EAGAIN. > 5. With POLLOUT registered on fd=3D7, bluetoothd's GMainLoop stalls > and can no longer send D-Bus replies or signals. > > Fix > --- > Three related changes: > > 1. Remove the broad type=3D'signal',sender=3D<svc>,path_namespace=3D<path= > > match rule from g_dbus_client_new_full(). This rule was the sole > feeder for the signal_func path in message_filter(). ofono never > calls g_dbus_client_set_signal_watch() so signal_func is always > NULL; the broad rule therefore served no purpose and caused > dbus-daemon to route every bluetoothd signal to ofono. > > 2. Remove the now-empty match_rules GPtrArray infrastructure > (field declaration, init, AddMatch loop, RemoveMatch loop, free). > No match rules are added to this array any more. > > 3. Add a generic GDBusProxyFilterFunction callback and > g_dbus_client_set_proxy_filter() API to GDBusClient. The filter > is called from parse_properties() before proxy_new(), so a FALSE > return prevents both proxy creation and per-device > PropertiesChanged watch registration. This keeps all BlueZ- > specific logic out of the gdbus layer. > > Use this in hfp_hf_bluez5.c to skip Device1 proxies for BLE > random-address devices: ofono only needs BR/EDR (AddressType=3D > 'public') devices for HFP/HSP. Skipping BLE proxies prevents > dbus-daemon from registering per-device PropertiesChanged match > rules for advertising peripherals and eliminates the remaining > RSSI signal delivery to ofono. > Together these changes prevent dbus-daemon from routing BLE > advertising signals to ofono, breaking the backpressure chain: > dbus-daemon memory stops growing, its write queue drains, and > bluetoothd's send buffer clears so that sendmsg() no longer returns > EAGAIN and the GMainLoop stall is resolved. > > Signed-off-by: Xiuzhuo Shang <[email protected]> > --- > Changes in v2: > - Drop Change 1 (BLE address-type filter in parse_properties()) per > review feedback; BlueZ-specific logic does not belong in the gdbus > layer. > - Add generic GDBusProxyFilterFunction callback and > g_dbus_client_set_proxy_filter() API to GDBusClient. The filter is > invoked before proxy_new() so a FALSE return prevents both proxy > creation and per-device PropertiesChanged watch registration. > - Use the new filter in hfp_hf_bluez5.c to skip Device1 proxies for > BLE random-address devices, keeping all BlueZ-specific logic in the > plugin as suggested. > - Remove now-empty match_rules GPtrArray infrastructure (field, > init, AddMatch loop, RemoveMatch loop, free) and unused variables. > - Link to v1: > https://lore.kernel.org/ofono/20260710075548.1072741-1-xiuzhuo.shang@o= ss.qualcomm.com/ > > gdbus/client.c | 45 +++++++++++++++++++++-------------------- > gdbus/gdbus.h | 8 ++++++++ > plugins/hfp_hf_bluez5.c | 38 ++++++++++++++++++++++++++++++++++ > 3 files changed, 69 insertions(+), 22 deletions(-) > > diff --git a/gdbus/client.c b/gdbus/client.c > index 48711ae8..fa2e75c0 100644 > --- a/gdbus/client.c > +++ b/gdbus/client.c > @@ -46,7 +46,6 @@ struct GDBusClient { > guint watch; > guint added_watch; > guint removed_watch; > - GPtrArray *match_rules; > DBusPendingCall *pending_call; > DBusPendingCall *get_objects_call; > GDBusWatchFunction connect_func; > @@ -61,6 +60,8 @@ struct GDBusClient { > GDBusClientFunction ready; > void *ready_data; > GDBusPropertyFunction property_changed; > + GDBusProxyFilterFunction proxy_filter; > + void *filter_user_data; > void *user_data; > GList *proxy_list; > }; > @@ -943,6 +944,14 @@ static void parse_properties(GDBusClient *client, co= nst char *path, > return; > } > > + if (client->proxy_filter) { > + DBusMessageIter copy =3D *iter; > + > + if (!client->proxy_filter(client, path, interface, > + ©, client->filter_user_data)) > + return; > + } > + > proxy =3D proxy_new(client, path, interface); > if (proxy =3D=3D NULL) > return; > @@ -1211,7 +1220,6 @@ GDBusClient *g_dbus_client_new_full(DBusConnection = *connection, > const char *root_= path) > { > GDBusClient *client; > - unsigned int i; > > if (!connection || !service) > return NULL; > @@ -1232,9 +1240,6 @@ GDBusClient *g_dbus_client_new_full(DBusConnection = *connection, > client->root_path =3D g_strdup(root_path); > client->connected =3D FALSE; > > - client->match_rules =3D g_ptr_array_sized_new(1); > - g_ptr_array_set_free_func(client->match_rules, g_free); > - > client->watch =3D g_dbus_add_service_watch(connection, service, > service_connect, > service_disconnect, > @@ -1255,14 +1260,6 @@ GDBusClient *g_dbus_client_new_full(DBusConnection= *connection, > "InterfacesRemoved", > interfaces_removed, > client, NULL); > - g_ptr_array_add(client->match_rules, g_strdup_printf("type=3D'sig= nal'," > - "sender=3D'%s',path_namespace=3D'%s'", > - client->service_name, client->base_path))= ; > - > - for (i =3D 0; i < client->match_rules->len; i++) { > - modify_match(client->dbus_conn, "AddMatch", > - g_ptr_array_index(client->match_rules, i)= ); > - } > > return g_dbus_client_ref(client); > } > @@ -1279,8 +1276,6 @@ GDBusClient *g_dbus_client_ref(GDBusClient *client) > > void g_dbus_client_unref(GDBusClient *client) > { > - unsigned int i; > - > if (client =3D=3D NULL) > return; > > @@ -1297,13 +1292,6 @@ void g_dbus_client_unref(GDBusClient *client) > dbus_pending_call_unref(client->get_objects_call); > } > > - for (i =3D 0; i < client->match_rules->len; i++) { > - modify_match(client->dbus_conn, "RemoveMatch", > - g_ptr_array_index(client->match_rules, i)= ); > - } > - > - g_ptr_array_free(client->match_rules, TRUE); > - > dbus_connection_remove_filter(client->dbus_conn, > message_filter, client); > > @@ -1396,3 +1384,16 @@ gboolean g_dbus_client_set_proxy_handlers(GDBusCli= ent *client, > > return TRUE; > } > + > +gboolean g_dbus_client_set_proxy_filter(GDBusClient *client, > + GDBusProxyFilterFunction proxy_fi= lter, > + void *user_data) > +{ > + if (client =3D=3D NULL) > + return FALSE; > + > + client->proxy_filter =3D proxy_filter; > + client->filter_user_data =3D user_data; > + > + return TRUE; > +} > diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h > index d99c2549..cc3c4e16 100644 > --- a/gdbus/gdbus.h > +++ b/gdbus/gdbus.h > @@ -347,6 +347,11 @@ typedef void (* GDBusClientFunction) (GDBusClient *c= lient, void *user_data); > typedef void (* GDBusProxyFunction) (GDBusProxy *proxy, void *user_data)= ; > typedef void (* GDBusPropertyFunction) (GDBusProxy *proxy, const char *n= ame, > DBusMessageIter *iter, void *user= _data); > +typedef gboolean (* GDBusProxyFilterFunction) (GDBusClient *client, > + const char *path, > + const char *interface, > + DBusMessageIter *iter, > + void *user_data); > > gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy, > GDBusPropertyFunction function, void *user_data); > @@ -377,6 +382,9 @@ gboolean g_dbus_client_set_proxy_handlers(GDBusClient= *client, > GDBusProxyFunction proxy_removed, > GDBusPropertyFunction property_ch= anged, > void *user_data); > +gboolean g_dbus_client_set_proxy_filter(GDBusClient *client, > + GDBusProxyFilterFunction proxy_fi= lter, > + void *user_data); > > #ifdef __cplusplus > } > diff --git a/plugins/hfp_hf_bluez5.c b/plugins/hfp_hf_bluez5.c > index 5ad1674f..141dc5c4 100644 > --- a/plugins/hfp_hf_bluez5.c > +++ b/plugins/hfp_hf_bluez5.c > @@ -791,6 +791,43 @@ static void proxy_added(GDBusProxy *proxy, void *use= r_data) > device_changed(proxy, path); > } > > +static gboolean proxy_filter(GDBusClient *client, const char *path, > + const char *interface, DBusMessageIter *i= ter, > + void *user_data) > +{ > + DBusMessageIter props, entry; > + > + if (g_str_equal(BLUEZ_DEVICE_INTERFACE, interface) =3D=3D FALSE) > + return TRUE; > + > + if (dbus_message_iter_get_arg_type(iter) !=3D DBUS_TYPE_ARRAY) > + return TRUE; > + > + dbus_message_iter_recurse(iter, &props); > + > + while (dbus_message_iter_get_arg_type(&props) =3D=3D DBUS_TYPE_DI= CT_ENTRY) { > + const char *key; > + > + dbus_message_iter_recurse(&props, &entry); > + dbus_message_iter_get_basic(&entry, &key); > + > + if (g_str_equal(key, "AddressType") =3D=3D TRUE) { > + DBusMessageIter var; > + const char *addr_type; > + > + dbus_message_iter_next(&entry); > + dbus_message_iter_recurse(&entry, &var); > + dbus_message_iter_get_basic(&var, &addr_type); > + > + return !g_str_equal(addr_type, "random"); > + } > + > + dbus_message_iter_next(&props); > + } > + > + return TRUE; > +} > + > static void property_changed(GDBusProxy *proxy, const char *name, > DBusMessageIter *iter, void *user= _data) > { > @@ -844,6 +881,7 @@ static int hfp_init(void) > g_dbus_client_set_connect_watch(bluez, connect_handler, NULL); > g_dbus_client_set_proxy_handlers(bluez, proxy_added, NULL, > property_changed, NULL); > + g_dbus_client_set_proxy_filter(bluez, proxy_filter, NULL); I don't really follow; would this register a proxy filter and automatically remove it on the first match of an AddressType=3Drandom?? Sounds not really useful to me, what is the difference if we don't use set_proxy_filter above? > > ofono_handsfree_audio_ref(); > > -- > 2.43.0 > --=20 Luiz Augusto von Dentz