* [PATCH v1] gdbus: Skip BLE random-address devices and remove broad match rule @ 2026-07-10 7:55 Xiuzhuo Shang 2026-07-10 8:35 ` [v1] " bluez.test.bot 2026-07-10 14:12 ` [PATCH v1] " Luiz Augusto von Dentz 0 siblings, 2 replies; 7+ messages in thread From: Xiuzhuo Shang @ 2026-07-10 7:55 UTC (permalink / raw) To: luiz.dentz, denkenz Cc: ofono, linux-bluetooth, cheng.jiang, quic_chezhou, wei.deng, shuai.zhang, mengshi.wu, jinwang.li, xiuzhuo.shang Two related changes to reduce dbus-daemon load caused by high-rate BLE advertising signals: 1. In parse_properties(), skip creating a GDBusProxy for Device1 objects whose AddressType is 'random' (BLE-only devices). Each proxy registers a per-device PropertiesChanged watch via g_dbus_add_properties_watch(); with hundreds of BLE peripherals advertising simultaneously, this results in hundreds of match rules and dbus-daemon routing thousands of RSSI PropertiesChanged signals per second to ofono, none of which ofono processes. The AddressType property is available in the InterfacesAdded dict at the time parse_properties() is called, so the check is reliable and race-free. BR/EDR devices (AddressType='public') are unaffected: their proxies are created as before, and the property_changed callback continues to receive Paired and ServicesResolved updates needed for HFP/HSP. 2. In g_dbus_client_new_full(), remove the broad type='signal',sender=<service>,path_namespace=<path> match rule. 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 (including all BLE PropertiesChanged) to ofono. InterfacesAdded and InterfacesRemoved are already covered by the precise watches registered via g_dbus_add_signal_watch() earlier in g_dbus_client_new_full(), so no functionality is lost. Together these two changes prevent dbus-daemon from routing BLE advertising PropertiesChanged signals to ofono entirely, eliminating the dbus-daemon memory growth and bluetoothd socket backpressure seen after hours of BLE scanning. Signed-off-by: Xiuzhuo Shang <xiuzhuo.shang@oss.qualcomm.com> --- gdbus/client.c | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/gdbus/client.c b/gdbus/client.c index 48711ae8..dd3c17f9 100644 --- a/gdbus/client.c +++ b/gdbus/client.c @@ -937,6 +937,44 @@ static void parse_properties(GDBusClient *client, const char *path, if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) return; + /* + * Skip BLE devices (AddressType='random') to avoid registering a + * per-device PropertiesChanged watch for every advertising BLE + * peripheral. ofono only needs BR/EDR devices for HFP/HSP; the + * high-rate RSSI PropertiesChanged signals from BLE scanners cause + * dbus-daemon memory bloat and socket backpressure in bluetoothd. + * + * The AddressType property is present in the InterfacesAdded dict + * (iter) at this point, so it can be checked before proxy_new(). + */ + if (g_str_equal(interface, "org.bluez.Device1") == TRUE) { + DBusMessageIter props, entry; + DBusMessageIter copy = *iter; + + if (dbus_message_iter_get_arg_type(©) == DBUS_TYPE_ARRAY) { + dbus_message_iter_recurse(©, &props); + while (dbus_message_iter_get_arg_type(&props) == + DBUS_TYPE_DICT_ENTRY) { + const char *key; + dbus_message_iter_recurse(&props, &entry); + dbus_message_iter_get_basic(&entry, &key); + if (g_str_equal(key, "AddressType") == 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); + if (g_str_equal(addr_type, + "random") == TRUE) + return; + break; + } + dbus_message_iter_next(&props); + } + } + } + proxy = proxy_lookup(client, path, interface); if (proxy) { update_properties(proxy, iter, FALSE); @@ -1255,14 +1293,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='signal'," - "sender='%s',path_namespace='%s'", - client->service_name, client->base_path)); - - for (i = 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); } -- 2.43.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* RE: [v1] gdbus: Skip BLE random-address devices and remove broad match rule 2026-07-10 7:55 [PATCH v1] gdbus: Skip BLE random-address devices and remove broad match rule Xiuzhuo Shang @ 2026-07-10 8:35 ` bluez.test.bot 2026-07-10 14:12 ` [PATCH v1] " Luiz Augusto von Dentz 1 sibling, 0 replies; 7+ messages in thread From: bluez.test.bot @ 2026-07-10 8:35 UTC (permalink / raw) To: linux-bluetooth, xiuzhuo.shang [-- Attachment #1: Type: text/plain, Size: 530 bytes --] This is an automated email and please do not reply to this email. Dear Submitter, Thank you for submitting the patches to the linux bluetooth mailing list. While preparing the CI tests, the patches you submitted couldn't be applied to the current HEAD of the repository. ----- Output ----- error: patch failed: gdbus/client.c:937 error: gdbus/client.c: patch does not apply hint: Use 'git am --show-current-patch' to see the failed patch Please resolve the issue and submit the patches again. --- Regards, Linux Bluetooth ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v1] gdbus: Skip BLE random-address devices and remove broad match rule 2026-07-10 7:55 [PATCH v1] gdbus: Skip BLE random-address devices and remove broad match rule Xiuzhuo Shang 2026-07-10 8:35 ` [v1] " bluez.test.bot @ 2026-07-10 14:12 ` Luiz Augusto von Dentz 2026-07-13 6:03 ` Xiuzhuo Shang 1 sibling, 1 reply; 7+ messages in thread From: Luiz Augusto von Dentz @ 2026-07-10 14:12 UTC (permalink / raw) To: Xiuzhuo Shang Cc: denkenz, ofono, linux-bluetooth, cheng.jiang, quic_chezhou, wei.deng, shuai.zhang, mengshi.wu, jinwang.li Hi Xiuzhuo, On Fri, Jul 10, 2026 at 3:55 AM Xiuzhuo Shang <xiuzhuo.shang@oss.qualcomm.com> wrote: > > Two related changes to reduce dbus-daemon load caused by high-rate > BLE advertising signals: > > 1. In parse_properties(), skip creating a GDBusProxy for Device1 > objects whose AddressType is 'random' (BLE-only devices). Each > proxy registers a per-device PropertiesChanged watch via > g_dbus_add_properties_watch(); with hundreds of BLE peripherals > advertising simultaneously, this results in hundreds of match rules > and dbus-daemon routing thousands of RSSI PropertiesChanged signals > per second to ofono, none of which ofono processes. The > AddressType property is available in the InterfacesAdded dict at > the time parse_properties() is called, so the check is reliable > and race-free. > > BR/EDR devices (AddressType='public') are unaffected: their proxies > are created as before, and the property_changed callback continues > to receive Paired and ServicesResolved updates needed for HFP/HSP. > > 2. In g_dbus_client_new_full(), remove the broad > type='signal',sender=<service>,path_namespace=<path> match rule. > 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 > (including all BLE PropertiesChanged) to ofono. > > InterfacesAdded and InterfacesRemoved are already covered by the > precise watches registered via g_dbus_add_signal_watch() earlier in > g_dbus_client_new_full(), so no functionality is lost. Looks like this is on ofono though, why are you chaning the BlueZ side? > Together these two changes prevent dbus-daemon from routing BLE > advertising PropertiesChanged signals to ofono entirely, eliminating > the dbus-daemon memory growth and bluetoothd socket backpressure seen > after hours of BLE scanning. > > Signed-off-by: Xiuzhuo Shang <xiuzhuo.shang@oss.qualcomm.com> > --- > gdbus/client.c | 46 ++++++++++++++++++++++++++++++++++++++-------- > 1 file changed, 38 insertions(+), 8 deletions(-) > > diff --git a/gdbus/client.c b/gdbus/client.c > index 48711ae8..dd3c17f9 100644 > --- a/gdbus/client.c > +++ b/gdbus/client.c > @@ -937,6 +937,44 @@ static void parse_properties(GDBusClient *client, const char *path, > if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) > return; > > + /* > + * Skip BLE devices (AddressType='random') to avoid registering a > + * per-device PropertiesChanged watch for every advertising BLE > + * peripheral. ofono only needs BR/EDR devices for HFP/HSP; the > + * high-rate RSSI PropertiesChanged signals from BLE scanners cause > + * dbus-daemon memory bloat and socket backpressure in bluetoothd. > + * > + * The AddressType property is present in the InterfacesAdded dict > + * (iter) at this point, so it can be checked before proxy_new(). > + */ > + if (g_str_equal(interface, "org.bluez.Device1") == TRUE) { > + DBusMessageIter props, entry; > + DBusMessageIter copy = *iter; > + > + if (dbus_message_iter_get_arg_type(©) == DBUS_TYPE_ARRAY) { > + dbus_message_iter_recurse(©, &props); > + while (dbus_message_iter_get_arg_type(&props) == > + DBUS_TYPE_DICT_ENTRY) { > + const char *key; > + dbus_message_iter_recurse(&props, &entry); > + dbus_message_iter_get_basic(&entry, &key); > + if (g_str_equal(key, "AddressType") == 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); > + if (g_str_equal(addr_type, > + "random") == TRUE) > + return; > + break; > + } > + dbus_message_iter_next(&props); > + } > + } > + } Nack, not going to introduce BlueZ specific logic into gdbus like this. If we need to rate limit the RSSI notification then it means it's not suitable to be a property, but I believe we have a threshold logic in the likes of device_set_rssi_with_delta so perhaps we shall check why it is not working in your case. > proxy = proxy_lookup(client, path, interface); > if (proxy) { > update_properties(proxy, iter, FALSE); > @@ -1255,14 +1293,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='signal'," > - "sender='%s',path_namespace='%s'", > - client->service_name, client->base_path)); > - > - for (i = 0; i < client->match_rules->len; i++) { > - modify_match(client->dbus_conn, "AddMatch", > - g_ptr_array_index(client->match_rules, i)); > - } This perhaps has a merit, but I can't recall what this watch was for. Is it matching every signal from the sender? It seems it was introduce before the watch infra existed, so if we can safely remove it we can perhaps remove the whole client-->match_rules. > return g_dbus_client_ref(client); > } > -- > 2.43.0 > -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v1] gdbus: Skip BLE random-address devices and remove broad match rule 2026-07-10 14:12 ` [PATCH v1] " Luiz Augusto von Dentz @ 2026-07-13 6:03 ` Xiuzhuo Shang 2026-07-13 14:00 ` Luiz Augusto von Dentz 0 siblings, 1 reply; 7+ messages in thread From: Xiuzhuo Shang @ 2026-07-13 6:03 UTC (permalink / raw) To: Luiz Augusto von Dentz Cc: denkenz, ofono, linux-bluetooth, cheng.jiang, quic_chezhou, wei.deng, shuai.zhang, mengshi.wu, jinwang.li On 7/10/2026 10:12 PM, Luiz Augusto von Dentz wrote: > Hi Xiuzhuo, > > On Fri, Jul 10, 2026 at 3:55 AM Xiuzhuo Shang > <xiuzhuo.shang@oss.qualcomm.com> wrote: >> >> Two related changes to reduce dbus-daemon load caused by high-rate >> BLE advertising signals: >> >> 1. In parse_properties(), skip creating a GDBusProxy for Device1 >> objects whose AddressType is 'random' (BLE-only devices). Each >> proxy registers a per-device PropertiesChanged watch via >> g_dbus_add_properties_watch(); with hundreds of BLE peripherals >> advertising simultaneously, this results in hundreds of match rules >> and dbus-daemon routing thousands of RSSI PropertiesChanged signals >> per second to ofono, none of which ofono processes. The >> AddressType property is available in the InterfacesAdded dict at >> the time parse_properties() is called, so the check is reliable >> and race-free. >> >> BR/EDR devices (AddressType='public') are unaffected: their proxies >> are created as before, and the property_changed callback continues >> to receive Paired and ServicesResolved updates needed for HFP/HSP. >> >> 2. In g_dbus_client_new_full(), remove the broad >> type='signal',sender=<service>,path_namespace=<path> match rule. >> 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 >> (including all BLE PropertiesChanged) to ofono. >> >> InterfacesAdded and InterfacesRemoved are already covered by the >> precise watches registered via g_dbus_add_signal_watch() earlier in >> g_dbus_client_new_full(), so no functionality is lost. > > Looks like this is on ofono though, why are you chaning the BlueZ side? Regarding your suggestion to move the BLE filter to hfp_hf_bluez5.c: filtering in proxy_added() would only prevent ofono from processing BLE devices at the application level. The per-device PropertiesChanged watch is registered inside proxy_new(), which is called before proxy_added(). So dbus-daemon would still route all RSSI signals to the process — the D-Bus pressure problem would remain unchanged. I will drop the change from the gdbus patch per your feedback > >> Together these two changes prevent dbus-daemon from routing BLE >> advertising PropertiesChanged signals to ofono entirely, eliminating >> the dbus-daemon memory growth and bluetoothd socket backpressure seen >> after hours of BLE scanning. >> >> Signed-off-by: Xiuzhuo Shang <xiuzhuo.shang@oss.qualcomm.com> >> --- >> gdbus/client.c | 46 ++++++++++++++++++++++++++++++++++++++-------- >> 1 file changed, 38 insertions(+), 8 deletions(-) >> >> diff --git a/gdbus/client.c b/gdbus/client.c >> index 48711ae8..dd3c17f9 100644 >> --- a/gdbus/client.c >> +++ b/gdbus/client.c >> @@ -937,6 +937,44 @@ static void parse_properties(GDBusClient *client, const char *path, >> if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) >> return; >> >> + /* >> + * Skip BLE devices (AddressType='random') to avoid registering a >> + * per-device PropertiesChanged watch for every advertising BLE >> + * peripheral. ofono only needs BR/EDR devices for HFP/HSP; the >> + * high-rate RSSI PropertiesChanged signals from BLE scanners cause >> + * dbus-daemon memory bloat and socket backpressure in bluetoothd. >> + * >> + * The AddressType property is present in the InterfacesAdded dict >> + * (iter) at this point, so it can be checked before proxy_new(). >> + */ >> + if (g_str_equal(interface, "org.bluez.Device1") == TRUE) { >> + DBusMessageIter props, entry; >> + DBusMessageIter copy = *iter; >> + >> + if (dbus_message_iter_get_arg_type(©) == DBUS_TYPE_ARRAY) { >> + dbus_message_iter_recurse(©, &props); >> + while (dbus_message_iter_get_arg_type(&props) == >> + DBUS_TYPE_DICT_ENTRY) { >> + const char *key; >> + dbus_message_iter_recurse(&props, &entry); >> + dbus_message_iter_get_basic(&entry, &key); >> + if (g_str_equal(key, "AddressType") == 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); >> + if (g_str_equal(addr_type, >> + "random") == TRUE) >> + return; >> + break; >> + } >> + dbus_message_iter_next(&props); >> + } >> + } >> + } > > Nack, not going to introduce BlueZ specific logic into gdbus like > this. If we need to rate limit the RSSI notification then it means > it's not suitable to be a property, but I believe we have a threshold > logic in the likes of device_set_rssi_with_delta so perhaps we shall > check why it is not working in your case. I investigated why device_set_rssi_with_delta is not working in our case. Root cause in BlueZ The customer scans with the following bluetoothctl sequence: menu scan → transport le → duplicate-data off → back → scan le scan le calls SetDiscoveryFilter({'Transport': 'le'}) — a transport-only filter with no RSSI or pathloss condition. In btd_adapter_device_found() (src/adapter.c): if (adapter->filtered_discovery) device_set_rssi_with_delta(dev, rssi, 0); /* delta forced to 0 */ else device_set_rssi(dev, rssi); /* delta = RSSI_THRESHOLD = 8 */ filtered_discovery is set true whenever current_discovery_filter is non-NULL (adapter.c:1872), which happens for any SetDiscoveryFilter() call — including a transport-only filter. With delta_threshold=0, the condition delta < 0 is never true, so g_dbus_emit_property_changed("RSSI") fires on every BLE advertisement regardless of whether the RSSI value changed. With 280+ BLE devices advertising continuously, this produces ~95 PropertiesChanged(RSSI) signals per second that flood dbus-daemon. The delta=0 path was presumably intended for clients that set RSSI/pathloss proximity filters, so that is_filter_match() gets precise RSSI tracking. A transport-only filter does not involve any proximity condition, so forcing delta=0 is unnecessary in that case. Proposed BlueZ fix direction Only apply delta=0 when at least one active client filter has a real proximity condition (RSSI or pathloss): static bool discovery_filter_has_proximity(struct btd_adapter *adapter) { GSList *l; for (l = adapter->discovery_list; l; l = g_slist_next(l)) { struct discovery_client *client = l->data; struct discovery_filter *item = client->discovery_filter; if (item && (item->rssi != DISTANCE_VAL_INVALID || item->pathloss != DISTANCE_VAL_INVALID)) return true; } return false; } /* in btd_adapter_device_found() */ if (adapter->filtered_discovery && discovery_filter_has_proximity(adapter)) device_set_rssi_with_delta(dev, rssi, 0); else device_set_rssi(dev, rssi); Could you advise whether this is the right approach, or if there is a better place to fix this? then I will Submit a separate BlueZ patch for the delta=0 fix once we agree on the approach. > >> proxy = proxy_lookup(client, path, interface); >> if (proxy) { >> update_properties(proxy, iter, FALSE); >> @@ -1255,14 +1293,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='signal'," >> - "sender='%s',path_namespace='%s'", >> - client->service_name, client->base_path)); >> - >> - for (i = 0; i < client->match_rules->len; i++) { >> - modify_match(client->dbus_conn, "AddMatch", >> - g_ptr_array_index(client->match_rules, i)); >> - } > > This perhaps has a merit, but I can't recall what this watch was for. > Is it matching every signal from the sender? It seems it was introduce > before the watch infra existed, so if we can safely remove it we can > perhaps remove the whole client-->match_rules. > >> return g_dbus_client_ref(client); >> } >> -- >> 2.43.0 >> > > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v1] gdbus: Skip BLE random-address devices and remove broad match rule 2026-07-13 6:03 ` Xiuzhuo Shang @ 2026-07-13 14:00 ` Luiz Augusto von Dentz 2026-07-14 11:04 ` Xiuzhuo Shang 0 siblings, 1 reply; 7+ messages in thread From: Luiz Augusto von Dentz @ 2026-07-13 14:00 UTC (permalink / raw) To: Xiuzhuo Shang Cc: denkenz, ofono, linux-bluetooth, cheng.jiang, quic_chezhou, wei.deng, shuai.zhang, mengshi.wu, jinwang.li Hi Xiuzhuo, On Mon, Jul 13, 2026 at 3:03 AM Xiuzhuo Shang <xiuzhuo.shang@oss.qualcomm.com> wrote: > > > > On 7/10/2026 10:12 PM, Luiz Augusto von Dentz wrote: > > Hi Xiuzhuo, > > > > On Fri, Jul 10, 2026 at 3:55 AM Xiuzhuo Shang > > <xiuzhuo.shang@oss.qualcomm.com> wrote: > >> > >> Two related changes to reduce dbus-daemon load caused by high-rate > >> BLE advertising signals: > >> > >> 1. In parse_properties(), skip creating a GDBusProxy for Device1 > >> objects whose AddressType is 'random' (BLE-only devices). Each > >> proxy registers a per-device PropertiesChanged watch via > >> g_dbus_add_properties_watch(); with hundreds of BLE peripherals > >> advertising simultaneously, this results in hundreds of match rules > >> and dbus-daemon routing thousands of RSSI PropertiesChanged signals > >> per second to ofono, none of which ofono processes. The > >> AddressType property is available in the InterfacesAdded dict at > >> the time parse_properties() is called, so the check is reliable > >> and race-free. > >> > >> BR/EDR devices (AddressType='public') are unaffected: their proxies > >> are created as before, and the property_changed callback continues > >> to receive Paired and ServicesResolved updates needed for HFP/HSP. > >> > >> 2. In g_dbus_client_new_full(), remove the broad > >> type='signal',sender=<service>,path_namespace=<path> match rule. > >> 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 > >> (including all BLE PropertiesChanged) to ofono. > >> > >> InterfacesAdded and InterfacesRemoved are already covered by the > >> precise watches registered via g_dbus_add_signal_watch() earlier in > >> g_dbus_client_new_full(), so no functionality is lost. > > > > Looks like this is on ofono though, why are you chaning the BlueZ side? > > Regarding your suggestion to move the BLE filter to hfp_hf_bluez5.c: filtering in proxy_added() > would only prevent ofono from processing BLE devices at the application level. The per-device > PropertiesChanged watch is registered inside proxy_new(), which is called before proxy_added(). So > dbus-daemon would still route all RSSI signals to the process — the D-Bus pressure problem would > remain unchanged. > > I will drop the change from the gdbus patch per your feedback > > > > >> Together these two changes prevent dbus-daemon from routing BLE > >> advertising PropertiesChanged signals to ofono entirely, eliminating > >> the dbus-daemon memory growth and bluetoothd socket backpressure seen > >> after hours of BLE scanning. > >> > >> Signed-off-by: Xiuzhuo Shang <xiuzhuo.shang@oss.qualcomm.com> > >> --- > >> gdbus/client.c | 46 ++++++++++++++++++++++++++++++++++++++-------- > >> 1 file changed, 38 insertions(+), 8 deletions(-) > >> > >> diff --git a/gdbus/client.c b/gdbus/client.c > >> index 48711ae8..dd3c17f9 100644 > >> --- a/gdbus/client.c > >> +++ b/gdbus/client.c > >> @@ -937,6 +937,44 @@ static void parse_properties(GDBusClient *client, const char *path, > >> if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) > >> return; > >> > >> + /* > >> + * Skip BLE devices (AddressType='random') to avoid registering a > >> + * per-device PropertiesChanged watch for every advertising BLE > >> + * peripheral. ofono only needs BR/EDR devices for HFP/HSP; the > >> + * high-rate RSSI PropertiesChanged signals from BLE scanners cause > >> + * dbus-daemon memory bloat and socket backpressure in bluetoothd. > >> + * > >> + * The AddressType property is present in the InterfacesAdded dict > >> + * (iter) at this point, so it can be checked before proxy_new(). > >> + */ > >> + if (g_str_equal(interface, "org.bluez.Device1") == TRUE) { > >> + DBusMessageIter props, entry; > >> + DBusMessageIter copy = *iter; > >> + > >> + if (dbus_message_iter_get_arg_type(©) == DBUS_TYPE_ARRAY) { > >> + dbus_message_iter_recurse(©, &props); > >> + while (dbus_message_iter_get_arg_type(&props) == > >> + DBUS_TYPE_DICT_ENTRY) { > >> + const char *key; > >> + dbus_message_iter_recurse(&props, &entry); > >> + dbus_message_iter_get_basic(&entry, &key); > >> + if (g_str_equal(key, "AddressType") == 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); > >> + if (g_str_equal(addr_type, > >> + "random") == TRUE) > >> + return; > >> + break; > >> + } > >> + dbus_message_iter_next(&props); > >> + } > >> + } > >> + } > > > > Nack, not going to introduce BlueZ specific logic into gdbus like > > this. If we need to rate limit the RSSI notification then it means > > it's not suitable to be a property, but I believe we have a threshold > > logic in the likes of device_set_rssi_with_delta so perhaps we shall > > check why it is not working in your case. > > I investigated why device_set_rssi_with_delta is not working in our case. > > Root cause in BlueZ > > The customer scans with the following bluetoothctl sequence: > > menu scan → transport le → duplicate-data off → back → scan le Ok, that is 1 not the default behavior and 2 if they are setting duplicate-data off that means they want to see all advertisements, so this is working as intended. > scan le calls SetDiscoveryFilter({'Transport': 'le'}) — a transport-only filter with no RSSI or > pathloss condition. In btd_adapter_device_found() (src/adapter.c): > > if (adapter->filtered_discovery) > device_set_rssi_with_delta(dev, rssi, 0); /* delta forced to 0 */ > else > device_set_rssi(dev, rssi); /* delta = RSSI_THRESHOLD = 8 */ > > filtered_discovery is set true whenever current_discovery_filter is non-NULL (adapter.c:1872), which > happens for any SetDiscoveryFilter() call — including a transport-only filter. With > delta_threshold=0, the condition delta < 0 is never true, so g_dbus_emit_property_changed("RSSI") > fires on every BLE advertisement regardless of whether the RSSI value changed. With 280+ BLE devices > advertising continuously, this produces ~95 PropertiesChanged(RSSI) signals per second that flood > dbus-daemon. Yeah, that is what you get to set duplicate-data off, that said ~95 PropertiesChanged per seconds in not a lot of data, perhaps you are hitting a process that don't consume the events immediately as it should then the D-Bus daemon have to queue more and more memory? > The delta=0 path was presumably intended for clients that set RSSI/pathloss proximity filters, so > that is_filter_match() gets precise RSSI tracking. A transport-only filter does not involve any > proximity condition, so forcing delta=0 is unnecessary in that case. > > Proposed BlueZ fix direction > > Only apply delta=0 when at least one active client filter has a real proximity condition (RSSI or > pathloss): > > static bool discovery_filter_has_proximity(struct btd_adapter *adapter) > { > GSList *l; > for (l = adapter->discovery_list; l; l = g_slist_next(l)) { > struct discovery_client *client = l->data; > struct discovery_filter *item = client->discovery_filter; > if (item && (item->rssi != DISTANCE_VAL_INVALID || > item->pathloss != DISTANCE_VAL_INVALID)) > return true; > } > return false; > } Duplicate data does consider RSSI as well, so the real problem seems to be why disabling duplicate filtering is required since that is what causes the RSSI threshold logic not to be used. Or perhaps you don't trust your controller to do duplicate filtering. If so, we've gone full circle because if something causes too much spamming, it's also bad at the HCI driver, into the mgmt interface, etc, until it reaches D-Bus, which is why BlueZ defaults to duplicate filtering. > /* in btd_adapter_device_found() */ > if (adapter->filtered_discovery && > discovery_filter_has_proximity(adapter)) > device_set_rssi_with_delta(dev, rssi, 0); > else > device_set_rssi(dev, rssi); > > Could you advise whether this is the right approach, or if there is a better place to fix this? > > then I will Submit a separate BlueZ patch for the delta=0 fix once we agree on the approach. > > > > >> proxy = proxy_lookup(client, path, interface); > >> if (proxy) { > >> update_properties(proxy, iter, FALSE); > >> @@ -1255,14 +1293,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='signal'," > >> - "sender='%s',path_namespace='%s'", > >> - client->service_name, client->base_path)); > >> - > >> - for (i = 0; i < client->match_rules->len; i++) { > >> - modify_match(client->dbus_conn, "AddMatch", > >> - g_ptr_array_index(client->match_rules, i)); > >> - } > > > > This perhaps has a merit, but I can't recall what this watch was for. > > Is it matching every signal from the sender? It seems it was introduce > > before the watch infra existed, so if we can safely remove it we can > > perhaps remove the whole client-->match_rules. > > > >> return g_dbus_client_ref(client); > >> } > >> -- > >> 2.43.0 > >> > > > > > -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v1] gdbus: Skip BLE random-address devices and remove broad match rule 2026-07-13 14:00 ` Luiz Augusto von Dentz @ 2026-07-14 11:04 ` Xiuzhuo Shang 2026-07-14 14:01 ` Luiz Augusto von Dentz 0 siblings, 1 reply; 7+ messages in thread From: Xiuzhuo Shang @ 2026-07-14 11:04 UTC (permalink / raw) To: Luiz Augusto von Dentz Cc: denkenz, ofono, linux-bluetooth, cheng.jiang, quic_chezhou, wei.deng, shuai.zhang, mengshi.wu, jinwang.li On 7/13/2026 10:00 PM, Luiz Augusto von Dentz wrote: > Hi Xiuzhuo, > > On Mon, Jul 13, 2026 at 3:03 AM Xiuzhuo Shang > <xiuzhuo.shang@oss.qualcomm.com> wrote: >> >> >> >> On 7/10/2026 10:12 PM, Luiz Augusto von Dentz wrote: >>> Hi Xiuzhuo, >>> >>> On Fri, Jul 10, 2026 at 3:55 AM Xiuzhuo Shang >>> <xiuzhuo.shang@oss.qualcomm.com> wrote: >>>> >>>> Two related changes to reduce dbus-daemon load caused by high-rate >>>> BLE advertising signals: >>>> >>>> 1. In parse_properties(), skip creating a GDBusProxy for Device1 >>>> objects whose AddressType is 'random' (BLE-only devices). Each >>>> proxy registers a per-device PropertiesChanged watch via >>>> g_dbus_add_properties_watch(); with hundreds of BLE peripherals >>>> advertising simultaneously, this results in hundreds of match rules >>>> and dbus-daemon routing thousands of RSSI PropertiesChanged signals >>>> per second to ofono, none of which ofono processes. The >>>> AddressType property is available in the InterfacesAdded dict at >>>> the time parse_properties() is called, so the check is reliable >>>> and race-free. >>>> >>>> BR/EDR devices (AddressType='public') are unaffected: their proxies >>>> are created as before, and the property_changed callback continues >>>> to receive Paired and ServicesResolved updates needed for HFP/HSP. >>>> >>>> 2. In g_dbus_client_new_full(), remove the broad >>>> type='signal',sender=<service>,path_namespace=<path> match rule. >>>> 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 >>>> (including all BLE PropertiesChanged) to ofono. >>>> >>>> InterfacesAdded and InterfacesRemoved are already covered by the >>>> precise watches registered via g_dbus_add_signal_watch() earlier in >>>> g_dbus_client_new_full(), so no functionality is lost. >>> >>> Looks like this is on ofono though, why are you chaning the BlueZ side? >> >> Regarding your suggestion to move the BLE filter to hfp_hf_bluez5.c: filtering in proxy_added() >> would only prevent ofono from processing BLE devices at the application level. The per-device >> PropertiesChanged watch is registered inside proxy_new(), which is called before proxy_added(). So >> dbus-daemon would still route all RSSI signals to the process — the D-Bus pressure problem would >> remain unchanged. >> >> I will drop the change from the gdbus patch per your feedback >> >>> >>>> Together these two changes prevent dbus-daemon from routing BLE >>>> advertising PropertiesChanged signals to ofono entirely, eliminating >>>> the dbus-daemon memory growth and bluetoothd socket backpressure seen >>>> after hours of BLE scanning. >>>> >>>> Signed-off-by: Xiuzhuo Shang <xiuzhuo.shang@oss.qualcomm.com> >>>> --- >>>> gdbus/client.c | 46 ++++++++++++++++++++++++++++++++++++++-------- >>>> 1 file changed, 38 insertions(+), 8 deletions(-) >>>> >>>> diff --git a/gdbus/client.c b/gdbus/client.c >>>> index 48711ae8..dd3c17f9 100644 >>>> --- a/gdbus/client.c >>>> +++ b/gdbus/client.c >>>> @@ -937,6 +937,44 @@ static void parse_properties(GDBusClient *client, const char *path, >>>> if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) >>>> return; >>>> >>>> + /* >>>> + * Skip BLE devices (AddressType='random') to avoid registering a >>>> + * per-device PropertiesChanged watch for every advertising BLE >>>> + * peripheral. ofono only needs BR/EDR devices for HFP/HSP; the >>>> + * high-rate RSSI PropertiesChanged signals from BLE scanners cause >>>> + * dbus-daemon memory bloat and socket backpressure in bluetoothd. >>>> + * >>>> + * The AddressType property is present in the InterfacesAdded dict >>>> + * (iter) at this point, so it can be checked before proxy_new(). >>>> + */ >>>> + if (g_str_equal(interface, "org.bluez.Device1") == TRUE) { >>>> + DBusMessageIter props, entry; >>>> + DBusMessageIter copy = *iter; >>>> + >>>> + if (dbus_message_iter_get_arg_type(©) == DBUS_TYPE_ARRAY) { >>>> + dbus_message_iter_recurse(©, &props); >>>> + while (dbus_message_iter_get_arg_type(&props) == >>>> + DBUS_TYPE_DICT_ENTRY) { >>>> + const char *key; >>>> + dbus_message_iter_recurse(&props, &entry); >>>> + dbus_message_iter_get_basic(&entry, &key); >>>> + if (g_str_equal(key, "AddressType") == 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); >>>> + if (g_str_equal(addr_type, >>>> + "random") == TRUE) >>>> + return; >>>> + break; >>>> + } >>>> + dbus_message_iter_next(&props); >>>> + } >>>> + } >>>> + } >>> >>> Nack, not going to introduce BlueZ specific logic into gdbus like >>> this. If we need to rate limit the RSSI notification then it means >>> it's not suitable to be a property, but I believe we have a threshold >>> logic in the likes of device_set_rssi_with_delta so perhaps we shall >>> check why it is not working in your case. >> >> I investigated why device_set_rssi_with_delta is not working in our case. >> >> Root cause in BlueZ >> >> The customer scans with the following bluetoothctl sequence: >> >> menu scan → transport le → duplicate-data off → back → scan le > > Ok, that is 1 not the default behavior and 2 if they are setting > duplicate-data off that means they want to see all advertisements, so > this is working as intended. Hi Luiz, Thank you for the clarification. I need to correct some points regarding duplicate-data off and the actual signal rate. What DuplicateData does in BlueZ vs. the controller BlueZ's DuplicateData parameter in SetDiscoveryFilter and the controller's hardware duplicate filter are two independent mechanisms: - The controller hardware duplicate filter (filter_dup in hci_le_set_scan_enable) is controlled by the kernel (hci_sync.c), defaulting to LE_SCAN_FILTER_DUP_ENABLE. It is only disabled for specific cases (AdvMonitor, Mesh, or HCI_QUIRK_STRICT_DUPLICATE_FILTER). SetDiscoveryFilter.DuplicateData does NOT directly control this. - BlueZ's DuplicateData=true flag (parse_duplicate_data() in src/adapter.c:2680) controls only whether device EIR data (manufacturer data, service data) is updated on duplicate advertisements at the application layer (device_set_manufacturer_data(), device_set_service_data(), src/adapter.c:7392). duplicate-data off has no effect In bluetoothctl, duplicate-data off sets filter.duplicate = false (client/main.c:1449). In set_discovery_filter_setup() (client/main.c:1251): if (args->duplicate) /* false -> DuplicateData is NOT sent */ g_dbus_dict_append_entry(&dict, "DuplicateData", ...); Since false is the default, DuplicateData is never included in the SetDiscoveryFilter call. The customer's duplicate-data off step has no effect — the controller hardware duplicate filter remains enabled throughout. Why RSSI delta=0 occurs The root cause is Transport=le on a dual-mode adapter (src/adapter.c:85): #define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM)) /* = 6 */ #define SCAN_TYPE_DUAL (SCAN_TYPE_BREDR | SCAN_TYPE_LE) /* = 7 */ get_scan_type(adapter) returns 7 (DUAL) since the adapter supports both BR/EDR and LE. When Transport=le is set, filter->type = 6. In merge_discovery_filters() (src/adapter.c:2254): item->type == adapter_scan_type /* 6 != 7 -> condition fails */ This triggers has_filtered_discovery = true -> filtered_discovery = true -> device_set_rssi_with_delta(dev, rssi, 0) (src/adapter.c:7362). With delta_threshold=0, every advertisement emits PropertiesChanged(RSSI) regardless of RSSI change. We have captured a bluetoothd debug log (QCS6490 board, BlueZ 5.72) that directly confirms this sequence. The following lines are from the log with the customer's exact scan sequence (menu scan -> transport le -> duplicate-data off -> back -> scan le): # SetDiscoveryFilter called with Transport=le only, no RSSI/pathloss adapter.c:parse_discovery_filter_dict() filtered discovery params: transport: 6 rssi: 32767 pathloss: 32767 duplicate data: false discoverable false pattern (null) # current_discovery_filter is non-NULL — confirms filtered_discovery # will be set to true in start_discovery_complete() adapter.c:start_discovery_timeout() adapter->current_discovery_filter == 1 # filtered_discovery=1 directly confirmed by our added debug print adapter.c:start_discovery_complete() filtered_discovery=1 (current_discovery_filter=set) # delta_threshold=0 directly confirmed — every advertisement emits # PropertiesChanged(RSSI) regardless of whether RSSI changed device.c:device_set_rssi_with_delta() rssi=-86 delta_threshold=0 device.c:device_set_rssi_with_delta() rssi=-79 delta_threshold=0 device.c:device_set_rssi_with_delta() rssi=-72 delta_threshold=0 ... The log shows delta_threshold=0 on every single call. With hundreds of BLE devices advertising, this produces an unthrottled stream of PropertiesChanged(RSSI) signals. > >> scan le calls SetDiscoveryFilter({'Transport': 'le'}) — a transport-only filter with no RSSI or >> pathloss condition. In btd_adapter_device_found() (src/adapter.c): >> >> if (adapter->filtered_discovery) >> device_set_rssi_with_delta(dev, rssi, 0); /* delta forced to 0 */ >> else >> device_set_rssi(dev, rssi); /* delta = RSSI_THRESHOLD = 8 */ >> >> filtered_discovery is set true whenever current_discovery_filter is non-NULL (adapter.c:1872), which >> happens for any SetDiscoveryFilter() call — including a transport-only filter. With >> delta_threshold=0, the condition delta < 0 is never true, so g_dbus_emit_property_changed("RSSI") >> fires on every BLE advertisement regardless of whether the RSSI value changed. With 280+ BLE devices >> advertising continuously, this produces ~95 PropertiesChanged(RSSI) signals per second that flood >> dbus-daemon. > > Yeah, that is what you get to set duplicate-data off, that said ~95 > PropertiesChanged per seconds in not a lot of data, perhaps you are > hitting a process that don't consume the events immediately as it > should then the D-Bus daemon have to queue more and more memory? Actual signal rate from the captured log The log (30_Jun_2026/bluetooth.log.gz) shows duplicate data: true with Transport=le. The device_found_callback distribution over 1200 active seconds is: 0-99 events/s : 69 seconds (6%) 100-199 events/s : 187 seconds (16%) 200-299 events/s : 75 seconds (6%) 300+ events/s : 869 seconds (72%) <- burst, peak 392/s The average is ~95/s but that conceals the burst pattern: 72% of the time the rate exceeds 300/s. With 280+ BLE devices advertising, delta=0 means every single device_found_callback unconditionally emits a PropertiesChanged(RSSI) signal — including during bursts at 392/s. The actual bottleneck As you pointed out, ~95/s average may not seem large. The real bottleneck is that WirePlumber and ofono both register a broad path_namespace='/' match rule, causing dbus-daemon to route all these signals to processes that immediately discard them (message_filter() drops PropertiesChanged silently). Over 8 hours, dbus-daemon's routing table grows to 357 MB, making routing progressively slower until bluetoothd's socket fills and its GMainLoop stalls. How do you think the logic of bluez about delta_threshold = 0 when just Transport=le? > >> The delta=0 path was presumably intended for clients that set RSSI/pathloss proximity filters, so >> that is_filter_match() gets precise RSSI tracking. A transport-only filter does not involve any >> proximity condition, so forcing delta=0 is unnecessary in that case. >> >> Proposed BlueZ fix direction >> >> Only apply delta=0 when at least one active client filter has a real proximity condition (RSSI or >> pathloss): >> >> static bool discovery_filter_has_proximity(struct btd_adapter *adapter) >> { >> GSList *l; >> for (l = adapter->discovery_list; l; l = g_slist_next(l)) { >> struct discovery_client *client = l->data; >> struct discovery_filter *item = client->discovery_filter; >> if (item && (item->rssi != DISTANCE_VAL_INVALID || >> item->pathloss != DISTANCE_VAL_INVALID)) >> return true; >> } >> return false; >> } > > Duplicate data does consider RSSI as well, so the real problem seems > to be why disabling duplicate filtering is required since that is what > causes the RSSI threshold logic not to be used. Or perhaps you don't > trust your controller to do duplicate filtering. If so, we've gone > full circle because if something causes too much spamming, it's also > bad at the HCI driver, into the mgmt interface, etc, until it reaches > D-Bus, which is why BlueZ defaults to duplicate filtering. > >> /* in btd_adapter_device_found() */ >> if (adapter->filtered_discovery && >> discovery_filter_has_proximity(adapter)) >> device_set_rssi_with_delta(dev, rssi, 0); >> else >> device_set_rssi(dev, rssi); >> >> Could you advise whether this is the right approach, or if there is a better place to fix this? >> >> then I will Submit a separate BlueZ patch for the delta=0 fix once we agree on the approach. >> >>> >>>> proxy = proxy_lookup(client, path, interface); >>>> if (proxy) { >>>> update_properties(proxy, iter, FALSE); >>>> @@ -1255,14 +1293,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='signal'," >>>> - "sender='%s',path_namespace='%s'", >>>> - client->service_name, client->base_path)); >>>> - >>>> - for (i = 0; i < client->match_rules->len; i++) { >>>> - modify_match(client->dbus_conn, "AddMatch", >>>> - g_ptr_array_index(client->match_rules, i)); >>>> - } >>> >>> This perhaps has a merit, but I can't recall what this watch was for. >>> Is it matching every signal from the sender? It seems it was introduce >>> before the watch infra existed, so if we can safely remove it we can >>> perhaps remove the whole client-->match_rules. >>> >>>> return g_dbus_client_ref(client); >>>> } >>>> -- >>>> 2.43.0 >>>> >>> >>> >> > > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v1] gdbus: Skip BLE random-address devices and remove broad match rule 2026-07-14 11:04 ` Xiuzhuo Shang @ 2026-07-14 14:01 ` Luiz Augusto von Dentz 0 siblings, 0 replies; 7+ messages in thread From: Luiz Augusto von Dentz @ 2026-07-14 14:01 UTC (permalink / raw) To: Xiuzhuo Shang Cc: denkenz, ofono, linux-bluetooth, cheng.jiang, quic_chezhou, wei.deng, shuai.zhang, mengshi.wu, jinwang.li Hi Xiuzhuo, On Tue, Jul 14, 2026 at 7:04 AM Xiuzhuo Shang <xiuzhuo.shang@oss.qualcomm.com> wrote: > > > > On 7/13/2026 10:00 PM, Luiz Augusto von Dentz wrote: > > Hi Xiuzhuo, > > > > On Mon, Jul 13, 2026 at 3:03 AM Xiuzhuo Shang > > <xiuzhuo.shang@oss.qualcomm.com> wrote: > >> > >> > >> > >> On 7/10/2026 10:12 PM, Luiz Augusto von Dentz wrote: > >>> Hi Xiuzhuo, > >>> > >>> On Fri, Jul 10, 2026 at 3:55 AM Xiuzhuo Shang > >>> <xiuzhuo.shang@oss.qualcomm.com> wrote: > >>>> > >>>> Two related changes to reduce dbus-daemon load caused by high-rate > >>>> BLE advertising signals: > >>>> > >>>> 1. In parse_properties(), skip creating a GDBusProxy for Device1 > >>>> objects whose AddressType is 'random' (BLE-only devices). Each > >>>> proxy registers a per-device PropertiesChanged watch via > >>>> g_dbus_add_properties_watch(); with hundreds of BLE peripherals > >>>> advertising simultaneously, this results in hundreds of match rules > >>>> and dbus-daemon routing thousands of RSSI PropertiesChanged signals > >>>> per second to ofono, none of which ofono processes. The > >>>> AddressType property is available in the InterfacesAdded dict at > >>>> the time parse_properties() is called, so the check is reliable > >>>> and race-free. > >>>> > >>>> BR/EDR devices (AddressType='public') are unaffected: their proxies > >>>> are created as before, and the property_changed callback continues > >>>> to receive Paired and ServicesResolved updates needed for HFP/HSP. > >>>> > >>>> 2. In g_dbus_client_new_full(), remove the broad > >>>> type='signal',sender=<service>,path_namespace=<path> match rule. > >>>> 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 > >>>> (including all BLE PropertiesChanged) to ofono. > >>>> > >>>> InterfacesAdded and InterfacesRemoved are already covered by the > >>>> precise watches registered via g_dbus_add_signal_watch() earlier in > >>>> g_dbus_client_new_full(), so no functionality is lost. > >>> > >>> Looks like this is on ofono though, why are you chaning the BlueZ side? > >> > >> Regarding your suggestion to move the BLE filter to hfp_hf_bluez5.c: filtering in proxy_added() > >> would only prevent ofono from processing BLE devices at the application level. The per-device > >> PropertiesChanged watch is registered inside proxy_new(), which is called before proxy_added(). So > >> dbus-daemon would still route all RSSI signals to the process — the D-Bus pressure problem would > >> remain unchanged. > >> > >> I will drop the change from the gdbus patch per your feedback > >> > >>> > >>>> Together these two changes prevent dbus-daemon from routing BLE > >>>> advertising PropertiesChanged signals to ofono entirely, eliminating > >>>> the dbus-daemon memory growth and bluetoothd socket backpressure seen > >>>> after hours of BLE scanning. > >>>> > >>>> Signed-off-by: Xiuzhuo Shang <xiuzhuo.shang@oss.qualcomm.com> > >>>> --- > >>>> gdbus/client.c | 46 ++++++++++++++++++++++++++++++++++++++-------- > >>>> 1 file changed, 38 insertions(+), 8 deletions(-) > >>>> > >>>> diff --git a/gdbus/client.c b/gdbus/client.c > >>>> index 48711ae8..dd3c17f9 100644 > >>>> --- a/gdbus/client.c > >>>> +++ b/gdbus/client.c > >>>> @@ -937,6 +937,44 @@ static void parse_properties(GDBusClient *client, const char *path, > >>>> if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) > >>>> return; > >>>> > >>>> + /* > >>>> + * Skip BLE devices (AddressType='random') to avoid registering a > >>>> + * per-device PropertiesChanged watch for every advertising BLE > >>>> + * peripheral. ofono only needs BR/EDR devices for HFP/HSP; the > >>>> + * high-rate RSSI PropertiesChanged signals from BLE scanners cause > >>>> + * dbus-daemon memory bloat and socket backpressure in bluetoothd. > >>>> + * > >>>> + * The AddressType property is present in the InterfacesAdded dict > >>>> + * (iter) at this point, so it can be checked before proxy_new(). > >>>> + */ > >>>> + if (g_str_equal(interface, "org.bluez.Device1") == TRUE) { > >>>> + DBusMessageIter props, entry; > >>>> + DBusMessageIter copy = *iter; > >>>> + > >>>> + if (dbus_message_iter_get_arg_type(©) == DBUS_TYPE_ARRAY) { > >>>> + dbus_message_iter_recurse(©, &props); > >>>> + while (dbus_message_iter_get_arg_type(&props) == > >>>> + DBUS_TYPE_DICT_ENTRY) { > >>>> + const char *key; > >>>> + dbus_message_iter_recurse(&props, &entry); > >>>> + dbus_message_iter_get_basic(&entry, &key); > >>>> + if (g_str_equal(key, "AddressType") == 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); > >>>> + if (g_str_equal(addr_type, > >>>> + "random") == TRUE) > >>>> + return; > >>>> + break; > >>>> + } > >>>> + dbus_message_iter_next(&props); > >>>> + } > >>>> + } > >>>> + } > >>> > >>> Nack, not going to introduce BlueZ specific logic into gdbus like > >>> this. If we need to rate limit the RSSI notification then it means > >>> it's not suitable to be a property, but I believe we have a threshold > >>> logic in the likes of device_set_rssi_with_delta so perhaps we shall > >>> check why it is not working in your case. > >> > >> I investigated why device_set_rssi_with_delta is not working in our case. > >> > >> Root cause in BlueZ > >> > >> The customer scans with the following bluetoothctl sequence: > >> > >> menu scan → transport le → duplicate-data off → back → scan le > > > > Ok, that is 1 not the default behavior and 2 if they are setting > > duplicate-data off that means they want to see all advertisements, so > > this is working as intended. > > Hi Luiz, > > Thank you for the clarification. I need to correct some points > regarding duplicate-data off and the actual signal rate. > > What DuplicateData does in BlueZ vs. the controller > > BlueZ's DuplicateData parameter in SetDiscoveryFilter and the > controller's hardware duplicate filter are two independent mechanisms: > > - The controller hardware duplicate filter (filter_dup in > hci_le_set_scan_enable) is controlled by the kernel (hci_sync.c), > defaulting to LE_SCAN_FILTER_DUP_ENABLE. It is only disabled for > specific cases (AdvMonitor, Mesh, or > HCI_QUIRK_STRICT_DUPLICATE_FILTER). > SetDiscoveryFilter.DuplicateData does NOT directly control this. > > - BlueZ's DuplicateData=true flag (parse_duplicate_data() in > src/adapter.c:2680) controls only whether device EIR data > (manufacturer data, service data) is updated on duplicate > advertisements at the application layer > (device_set_manufacturer_data(), device_set_service_data(), > src/adapter.c:7392). > > duplicate-data off has no effect > > In bluetoothctl, duplicate-data off sets filter.duplicate = false > (client/main.c:1449). In set_discovery_filter_setup() > (client/main.c:1251): > > if (args->duplicate) /* false -> DuplicateData is NOT sent */ > g_dbus_dict_append_entry(&dict, "DuplicateData", ...); > > Since false is the default, DuplicateData is never included in the > SetDiscoveryFilter call. The customer's duplicate-data off step has > no effect — the controller hardware duplicate filter remains enabled > throughout. > > Why RSSI delta=0 occurs > > The root cause is Transport=le on a dual-mode adapter > (src/adapter.c:85): > > #define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | > (1 << BDADDR_LE_RANDOM)) /* = 6 */ > #define SCAN_TYPE_DUAL (SCAN_TYPE_BREDR | SCAN_TYPE_LE) /* = 7 */ > > get_scan_type(adapter) returns 7 (DUAL) since the adapter supports > both BR/EDR and LE. When Transport=le is set, filter->type = 6. In > merge_discovery_filters() (src/adapter.c:2254): > > item->type == adapter_scan_type /* 6 != 7 -> condition fails */ > > This triggers has_filtered_discovery = true -> filtered_discovery = > true -> device_set_rssi_with_delta(dev, rssi, 0) > (src/adapter.c:7362). With delta_threshold=0, every advertisement > emits PropertiesChanged(RSSI) regardless of RSSI change. > > We have captured a bluetoothd debug log (QCS6490 board, BlueZ 5.72) > that directly confirms this sequence. The following lines are from > the log with the customer's exact scan sequence > (menu scan -> transport le -> duplicate-data off -> back -> scan le): > > # SetDiscoveryFilter called with Transport=le only, no RSSI/pathloss > adapter.c:parse_discovery_filter_dict() filtered discovery params: > transport: 6 rssi: 32767 pathloss: 32767 > duplicate data: false discoverable false pattern (null) > > # current_discovery_filter is non-NULL — confirms filtered_discovery > # will be set to true in start_discovery_complete() > adapter.c:start_discovery_timeout() adapter->current_discovery_filter == 1 > > # filtered_discovery=1 directly confirmed by our added debug print > adapter.c:start_discovery_complete() filtered_discovery=1 (current_discovery_filter=set) > > # delta_threshold=0 directly confirmed — every advertisement emits > # PropertiesChanged(RSSI) regardless of whether RSSI changed > device.c:device_set_rssi_with_delta() rssi=-86 delta_threshold=0 > device.c:device_set_rssi_with_delta() rssi=-79 delta_threshold=0 > device.c:device_set_rssi_with_delta() rssi=-72 delta_threshold=0 > ... > > The log shows delta_threshold=0 on every single call. With hundreds > of BLE devices advertising, this produces an unthrottled stream of > PropertiesChanged(RSSI) signals. > > > > > >> scan le calls SetDiscoveryFilter({'Transport': 'le'}) — a transport-only filter with no RSSI or > >> pathloss condition. In btd_adapter_device_found() (src/adapter.c): > >> > >> if (adapter->filtered_discovery) > >> device_set_rssi_with_delta(dev, rssi, 0); /* delta forced to 0 */ > >> else > >> device_set_rssi(dev, rssi); /* delta = RSSI_THRESHOLD = 8 */ > >> > >> filtered_discovery is set true whenever current_discovery_filter is non-NULL (adapter.c:1872), which > >> happens for any SetDiscoveryFilter() call — including a transport-only filter. With > >> delta_threshold=0, the condition delta < 0 is never true, so g_dbus_emit_property_changed("RSSI") > >> fires on every BLE advertisement regardless of whether the RSSI value changed. With 280+ BLE devices > >> advertising continuously, this produces ~95 PropertiesChanged(RSSI) signals per second that flood > >> dbus-daemon. > > > > Yeah, that is what you get to set duplicate-data off, that said ~95 > > PropertiesChanged per seconds in not a lot of data, perhaps you are > > hitting a process that don't consume the events immediately as it > > should then the D-Bus daemon have to queue more and more memory? > > > Actual signal rate from the captured log > > The log (30_Jun_2026/bluetooth.log.gz) shows duplicate data: true > with Transport=le. The device_found_callback distribution over 1200 > active seconds is: > > 0-99 events/s : 69 seconds (6%) > 100-199 events/s : 187 seconds (16%) > 200-299 events/s : 75 seconds (6%) > 300+ events/s : 869 seconds (72%) <- burst, peak 392/s > > The average is ~95/s but that conceals the burst pattern: 72% of the > time the rate exceeds 300/s. With 280+ BLE devices advertising, > delta=0 means every single device_found_callback unconditionally > emits a PropertiesChanged(RSSI) signal — including during bursts at > 392/s. Are we talking about an embedded device here? How come it takes seconds to process hundreds of events, or is it simply running out of memory and lacking swap space? If this were a general problem we would have seen this before. Even with hundreds of devices in the vicinity, it never took this much time to process. > The actual bottleneck > > As you pointed out, ~95/s average may not seem large. The real > bottleneck is that WirePlumber and ofono both register a broad > path_namespace='/' match rule, causing dbus-daemon to route all > these signals to processes that immediately discard them > (message_filter() drops PropertiesChanged silently). Over 8 hours, > dbus-daemon's routing table grows to 357 MB, making routing > progressively slower until bluetoothd's socket fills and its > GMainLoop stalls. That sounds like a process that is not dropping its messages; even if we generate fewer messages, it will eventually stop working because too many messages are cached or something similar. > How do you think the logic of bluez about delta_threshold = 0 > when just Transport=le? It sounds like another problem is at hand—not just too many signals but them not being consumed. Over time, this issue will recur if not fixed properly. ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-07-14 14:02 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-10 7:55 [PATCH v1] gdbus: Skip BLE random-address devices and remove broad match rule Xiuzhuo Shang 2026-07-10 8:35 ` [v1] " bluez.test.bot 2026-07-10 14:12 ` [PATCH v1] " Luiz Augusto von Dentz 2026-07-13 6:03 ` Xiuzhuo Shang 2026-07-13 14:00 ` Luiz Augusto von Dentz 2026-07-14 11:04 ` Xiuzhuo Shang 2026-07-14 14:01 ` Luiz Augusto von Dentz
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.