Blob Blame History Raw
From 88118b332abb4325d79a88fcc18db31109f0e307 Mon Sep 17 00:00:00 2001
From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
Date: Sat, 24 May 2014 12:56:35 +0300
Subject: [PATCH 13/31] bluetooth: Refactor device validity management

There are several intertwined changes that I couldn't separate into
nicer commits. This is mostly just refactoring, but this also fixes
a bug: the old code set the device valid in parse_device_properties()
even if the device's adapter was invalid (had NULL address).

To improve the clarity of the code, I split the device_info_valid
variable into two booleans: properties_received and valid.

I added function device_update_valid() that checks all conditions that
affect the device validity. The function can then be called from any
place where something changes that potentially affects the device
validity. However, currently the only validity-affecting thing that
can change is the device adapter, so device_update_valid() is only
called from set_device_adapter().

I added the aforementioned set_device_adapter() function so that
whenever the adapter is set, the device validity gets updated
automatically.

The new properties_received variable allowed me to remove the
is_property_update function parameters.
---
 src/modules/bluetooth/bluez5-util.c | 119 ++++++++++++++++++++----------------
 src/modules/bluetooth/bluez5-util.h |   4 +-
 2 files changed, 71 insertions(+), 52 deletions(-)

diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c
index fd58ee6..2478c32 100644
--- a/src/modules/bluetooth/bluez5-util.c
+++ b/src/modules/bluetooth/bluez5-util.c
@@ -278,7 +278,7 @@ bool pa_bluetooth_device_any_transport_connected(const pa_bluetooth_device *d) {
 
     pa_assert(d);
 
-    if (d->device_info_valid != 1)
+    if (!d->valid)
         return false;
 
     for (i = 0; i < PA_BLUETOOTH_PROFILE_COUNT; i++)
@@ -378,9 +378,8 @@ pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_path(pa_bluetooth_disc
     pa_assert(PA_REFCNT_VALUE(y) > 0);
     pa_assert(path);
 
-    if ((d = pa_hashmap_get(y->devices, path)))
-        if (d->device_info_valid == 1)
-            return d;
+    if ((d = pa_hashmap_get(y->devices, path)) && d->valid)
+        return d;
 
     return NULL;
 }
@@ -395,7 +394,7 @@ pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_address(pa_bluetooth_d
     pa_assert(local);
 
     while ((d = pa_hashmap_iterate(y->devices, &state, NULL)))
-        if (d->device_info_valid == 1 && pa_streq(d->address, remote) && pa_streq(d->adapter->address, local))
+        if (d->valid && pa_streq(d->address, remote) && pa_streq(d->adapter->address, local))
             return d;
 
     return NULL;
@@ -437,22 +436,54 @@ static void device_remove(pa_bluetooth_discovery *y, const char *path) {
     }
 }
 
-static void set_device_info_valid(pa_bluetooth_device *device, int valid) {
+static void device_set_valid(pa_bluetooth_device *device, bool valid) {
     bool old_any_connected;
 
     pa_assert(device);
-    pa_assert(valid == -1 || valid == 0 || valid == 1);
 
-    if (valid == device->device_info_valid)
+    if (valid == device->valid)
         return;
 
     old_any_connected = pa_bluetooth_device_any_transport_connected(device);
-    device->device_info_valid = valid;
+    device->valid = valid;
 
     if (pa_bluetooth_device_any_transport_connected(device) != old_any_connected)
         pa_hook_fire(&device->discovery->hooks[PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED], device);
 }
 
+static void device_update_valid(pa_bluetooth_device *d) {
+    pa_assert(d);
+
+    if (!d->properties_received) {
+        pa_assert(!d->valid);
+        return;
+    }
+
+    /* Check if mandatory properties are set. */
+    if (!d->address || !d->adapter_path || !d->alias) {
+        device_set_valid(d, false);
+        return;
+    }
+
+    if (!d->adapter || !d->adapter->valid) {
+        device_set_valid(d, false);
+        return;
+    }
+
+    device_set_valid(d, true);
+}
+
+static void device_set_adapter(pa_bluetooth_device *device, pa_bluetooth_adapter *adapter) {
+    pa_assert(device);
+
+    if (adapter == device->adapter)
+        return;
+
+    device->adapter = adapter;
+
+    device_update_valid(device);
+}
+
 static pa_bluetooth_adapter* adapter_create(pa_bluetooth_discovery *y, const char *path) {
     pa_bluetooth_adapter *a;
 
@@ -476,10 +507,8 @@ static void adapter_free(pa_bluetooth_adapter *a) {
     pa_assert(a->discovery);
 
     PA_HASHMAP_FOREACH(d, a->discovery->devices, state)
-        if (d->adapter == a) {
-            set_device_info_valid(d, -1);
-            d->adapter = NULL;
-        }
+        if (d->adapter == a)
+            device_set_adapter(d, NULL);
 
     pa_xfree(a->path);
     pa_xfree(a->address);
@@ -497,7 +526,7 @@ static void adapter_remove(pa_bluetooth_discovery *y, const char *path) {
     }
 }
 
-static void parse_device_property(pa_bluetooth_device *d, DBusMessageIter *i, bool is_property_change) {
+static void parse_device_property(pa_bluetooth_device *d, DBusMessageIter *i) {
     const char *key;
     DBusMessageIter variant_i;
 
@@ -522,7 +551,7 @@ static void parse_device_property(pa_bluetooth_device *d, DBusMessageIter *i, bo
                 d->alias = pa_xstrdup(value);
                 pa_log_debug("%s: %s", key, value);
             } else if (pa_streq(key, "Address")) {
-                if (is_property_change) {
+                if (d->properties_received) {
                     pa_log_warn("Device property 'Address' expected to be constant but changed for %s, ignoring", d->path);
                     return;
                 }
@@ -545,7 +574,7 @@ static void parse_device_property(pa_bluetooth_device *d, DBusMessageIter *i, bo
 
             if (pa_streq(key, "Adapter")) {
 
-                if (is_property_change) {
+                if (d->properties_received) {
                     pa_log_warn("Device property 'Adapter' expected to be constant but changed for %s, ignoring", d->path);
                     return;
                 }
@@ -556,11 +585,6 @@ static void parse_device_property(pa_bluetooth_device *d, DBusMessageIter *i, bo
                 }
 
                 d->adapter_path = pa_xstrdup(value);
-
-                d->adapter = pa_hashmap_get(d->discovery->adapters, value);
-                if (!d->adapter)
-                    pa_log_info("Device %s: 'Adapter' property references an unknown adapter %s.", d->path, value);
-
                 pa_log_debug("%s: %s", key, value);
             }
 
@@ -610,7 +634,7 @@ static void parse_device_property(pa_bluetooth_device *d, DBusMessageIter *i, bo
     }
 }
 
-static int parse_device_properties(pa_bluetooth_device *d, DBusMessageIter *i, bool is_property_change) {
+static void parse_device_properties(pa_bluetooth_device *d, DBusMessageIter *i) {
     DBusMessageIter element_i;
 
     dbus_message_iter_recurse(i, &element_i);
@@ -619,23 +643,16 @@ static int parse_device_properties(pa_bluetooth_device *d, DBusMessageIter *i, b
         DBusMessageIter dict_i;
 
         dbus_message_iter_recurse(&element_i, &dict_i);
-        parse_device_property(d, &dict_i, is_property_change);
+        parse_device_property(d, &dict_i);
         dbus_message_iter_next(&element_i);
     }
 
-    if (!d->address || !d->adapter_path || !d->alias) {
-        pa_log_error("Non-optional information missing for device %s", d->path);
-        set_device_info_valid(d, -1);
-        return -1;
-    }
-
-    if (!is_property_change && d->adapter)
-        set_device_info_valid(d, 1);
+    if (!d->properties_received) {
+        d->properties_received = true;
 
-    /* If d->adapter is NULL, device_info_valid will be left as 0, and updated
-     * after all interfaces have been parsed. */
-
-    return 0;
+        if (!d->address || !d->adapter_path || !d->alias)
+            pa_log_error("Non-optional information missing for device %s", d->path);
+    }
 }
 
 static void parse_adapter_properties(pa_bluetooth_adapter *a, DBusMessageIter *i, bool is_property_change) {
@@ -788,6 +805,7 @@ static void parse_interfaces_and_properties(pa_bluetooth_discovery *y, DBusMessa
             pa_log_debug("Adapter %s found", path);
 
             parse_adapter_properties(a, &iface_i, false);
+
             if (!a->valid)
                 return;
 
@@ -797,7 +815,7 @@ static void parse_interfaces_and_properties(pa_bluetooth_discovery *y, DBusMessa
         } else if (pa_streq(interface, BLUEZ_DEVICE_INTERFACE)) {
 
             if ((d = pa_hashmap_get(y->devices, path))) {
-                if (d->device_info_valid != 0) {
+                if (d->properties_received) {
                     pa_log_error("Found duplicated D-Bus path for device %s", path);
                     return;
                 }
@@ -806,7 +824,7 @@ static void parse_interfaces_and_properties(pa_bluetooth_discovery *y, DBusMessa
 
             pa_log_debug("Device %s found", d->path);
 
-            parse_device_properties(d, &iface_i, false);
+            parse_device_properties(d, &iface_i);
 
         } else
             pa_log_debug("Unknown interface %s found, skipping", interface);
@@ -815,16 +833,17 @@ static void parse_interfaces_and_properties(pa_bluetooth_discovery *y, DBusMessa
     }
 
     PA_HASHMAP_FOREACH(d, y->devices, state) {
-        if (d->device_info_valid != 0)
-            continue;
+        if (d->properties_received && !d->tried_to_link_with_adapter) {
+            if (d->adapter_path) {
+                device_set_adapter(d, pa_hashmap_get(d->discovery->adapters, d->adapter_path));
 
-        if (!d->adapter && d->adapter_path) {
-            d->adapter = pa_hashmap_get(d->discovery->adapters, d->adapter_path);
-            if (!d->adapter || !d->adapter->valid) {
-                pa_log_error("Device %s is child of nonexistent or corrupted adapter %s", d->path, d->adapter_path);
-                set_device_info_valid(d, -1);
-            } else
-                set_device_info_valid(d, 1);
+                if (!d->adapter)
+                    pa_log("Device %s points to a nonexistent adapter %s.", d->path, d->adapter_path);
+                else if (!d->adapter->valid)
+                    pa_log("Device %s points to an invalid adapter %s.", d->path, d->adapter_path);
+            }
+
+            d->tried_to_link_with_adapter = true;
         }
     }
 
@@ -1018,12 +1037,10 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
             }
 
-            if (d->device_info_valid != 1) {
-                pa_log_warn("Properties changed in a device which information is unknown or invalid");
+            if (!d->properties_received)
                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-            }
 
-            parse_device_properties(d, &arg_i, true);
+            parse_device_properties(d, &arg_i);
         } else if (pa_streq(iface, BLUEZ_MEDIA_TRANSPORT_INTERFACE)) {
             pa_bluetooth_transport *t;
 
@@ -1227,7 +1244,7 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
     }
 
     if ((d = pa_hashmap_get(y->devices, dev_path))) {
-        if (d->device_info_valid == -1) {
+        if (!d->valid) {
             pa_log_error("Information about device %s is invalid", dev_path);
             goto fail2;
         }
diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h
index e0b1be8..63bae35 100644
--- a/src/modules/bluetooth/bluez5-util.h
+++ b/src/modules/bluetooth/bluez5-util.h
@@ -76,7 +76,9 @@ struct pa_bluetooth_device {
     pa_bluetooth_discovery *discovery;
     pa_bluetooth_adapter *adapter;
 
-    int device_info_valid;      /* 0: no results yet; 1: good results; -1: bad results ... */
+    bool properties_received;
+    bool tried_to_link_with_adapter;
+    bool valid;
 
     /* Device information */
     char *path;
-- 
1.9.3