* [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.