adv_monitor: Invoke DeviceFound/Lost on tracked monitors

This patch delivers DeviceFound/DeviceLost events to apps over D-Bus
whenever controller starts/stops tracking a device.

Tests performed:
- Add a monitor and verify that DeviceFound/DeviceLost events are
  received whenever controller starts/stops monitoring.
- Verify from logs that only one Adv Report is received from the
  controller when Sampling_Period is set to 0xFF and the
  DeviceFound/DeviceLost functionality still works as intended.
- Verify that DeviceFound/DeviceLost is reported appropriately even
  when the Active Scanning is in progress.
- Verify that the reconnection also works properly with and without
  any active Advertisement Monitor.

Reviewed-by: Miao-chen Chou <mcchou@google.com>
This commit is contained in:
Manish Mandlik 2021-11-20 07:29:39 -08:00 committed by Luiz Augusto von Dentz
parent da253c54d1
commit f618084077

View File

@ -174,6 +174,11 @@ struct adv_rssi_filter_info {
int8_t rssi;
};
struct monitored_device_info {
uint16_t monitor_handle; /* Kernel Monitor Handle */
struct btd_device *device;
};
static void monitor_device_free(void *data);
static void adv_monitor_filter_rssi(struct adv_monitor *monitor,
struct btd_device *device, int8_t rssi);
@ -1531,6 +1536,39 @@ static void adv_monitor_removed_callback(uint16_t index, uint16_t length,
ev->monitor_handle);
}
/* Includes found/lost device's object path into the dbus message */
static void report_device_state_setup(DBusMessageIter *iter, void *user_data)
{
const char *path = device_get_path(user_data);
dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
}
/* Invokes DeviceFound on the matched monitor */
static void notify_device_found_per_monitor(void *data, void *user_data)
{
struct adv_monitor *monitor = data;
struct monitored_device_info *info = user_data;
if (monitor->merged_pattern->monitor_handle == info->monitor_handle) {
DBG("Calling DeviceFound() on Adv Monitor of owner %s "
"at path %s", monitor->app->owner, monitor->path);
g_dbus_proxy_method_call(monitor->proxy, "DeviceFound",
report_device_state_setup, NULL,
info->device, NULL);
}
}
/* Checks all monitors for match in the app to invoke DeviceFound */
static void notify_device_found_per_app(void *data, void *user_data)
{
struct adv_monitor_app *app = data;
queue_foreach(app->monitors, notify_device_found_per_monitor,
user_data);
}
/* Processes Adv Monitor Device Found event from kernel */
static void adv_monitor_device_found_callback(uint16_t index, uint16_t length,
const void *param,
@ -1540,6 +1578,8 @@ static void adv_monitor_device_found_callback(uint16_t index, uint16_t length,
struct btd_adv_monitor_manager *manager = user_data;
const uint16_t adapter_id = manager->adapter_id;
struct btd_adapter *adapter = manager->adapter;
uint16_t handle = le16_to_cpu(ev->monitor_handle);
struct monitored_device_info info;
const uint8_t *ad_data = NULL;
uint16_t ad_data_len;
uint32_t flags;
@ -1578,6 +1618,49 @@ static void adv_monitor_device_found_callback(uint16_t index, uint16_t length,
ev->addr.type, ev->rssi, confirm_name,
legacy, not_connectable, ad_data,
ad_data_len, true);
if (handle) {
DBG("Adv Monitor with handle 0x%04x started tracking "
"the device %s", handle, addr);
info.device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!info.device) {
btd_error(adapter_id, "Device object not found for %s",
addr);
return;
}
/* Check for matched monitor in all apps */
info.monitor_handle = handle;
queue_foreach(manager->apps, notify_device_found_per_app,
&info);
}
}
/* Invokes DeviceLost on the matched monitor */
static void notify_device_lost_per_monitor(void *data, void *user_data)
{
struct adv_monitor *monitor = data;
struct monitored_device_info *info = user_data;
if (monitor->merged_pattern->monitor_handle == info->monitor_handle) {
DBG("Calling DeviceLost() on Adv Monitor of owner %s "
"at path %s", monitor->app->owner, monitor->path);
g_dbus_proxy_method_call(monitor->proxy, "DeviceLost",
report_device_state_setup, NULL,
info->device, NULL);
}
}
/* Checks all monitors for match in the app to invoke DeviceLost */
static void notify_device_lost_per_app(void *data, void *user_data)
{
struct adv_monitor_app *app = data;
queue_foreach(app->monitors, notify_device_lost_per_monitor,
user_data);
}
/* Processes Adv Monitor Device Lost event from kernel */
@ -1589,6 +1672,8 @@ static void adv_monitor_device_lost_callback(uint16_t index, uint16_t length,
const struct mgmt_ev_adv_monitor_device_lost *ev = param;
uint16_t handle = le16_to_cpu(ev->monitor_handle);
const uint16_t adapter_id = manager->adapter_id;
struct btd_adapter *adapter = manager->adapter;
struct monitored_device_info info;
char addr[18];
if (length < sizeof(*ev)) {
@ -1600,6 +1685,17 @@ static void adv_monitor_device_lost_callback(uint16_t index, uint16_t length,
ba2str(&ev->addr.bdaddr, addr);
DBG("Adv Monitor with handle 0x%04x stopped tracking the device %s",
handle, addr);
info.device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!info.device) {
btd_error(adapter_id, "Device object not found for %s", addr);
return;
}
/* Check for matched monitor in all apps */
info.monitor_handle = handle;
queue_foreach(manager->apps, notify_device_lost_per_app, &info);
}
/* Allocates a manager object */
@ -1961,14 +2057,6 @@ static struct adv_monitor_device *monitor_device_create(
return dev;
}
/* Includes found/lost device's object path into the dbus message */
static void report_device_state_setup(DBusMessageIter *iter, void *user_data)
{
const char *path = device_get_path(user_data);
dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
}
/* Handles a situation where the device goes offline/out-of-range */
static bool handle_device_lost_timeout(gpointer user_data)
{