Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a3b27ea0 authored by Hansong Zhang's avatar Hansong Zhang
Browse files

Fix BluetoothManager and add integration test

Fix some deadlock issues.
 - Fix some timer deadlock issue in aosp/1727697.
 - Fix a deadlock where we send to tx from rx context, by increasing
 mpsc channel size to at least 2, and use send_timeout() instead of
 send().

Use async for some state machine fn to allow waiting for mutex lock.

Add a python script to do some basic testing.

In next iteration, we will test DBUS callbacks, and handle multi-hci
case better.

Tag: #floss
Test: btmanagerd_test.py with btmanagerd running
Bug: 190012236
Change-Id: Ia8fe6c0f36105657577a5e458787f39dc3bd69b7
parent 56fa0870
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -82,7 +82,6 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
                    println!("Config is not successfully modified");
                }
                let proxy = cr.data_mut::<ManagerContext>(ctx.path()).unwrap().proxy.clone();
                println!("Incoming Start call for hci {}!", hci_interface);
                async move {
                    let result = proxy.start_bluetooth(hci_interface).await;
                    match result {
@@ -188,7 +187,9 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
                            .expect("failed to stop bluetoothd");
                        // TODO: Implement multi-hci case
                        let default_device = config_util::list_hci_devices()[0];
                        if config_util::is_hci_n_enabled(default_device) {
                            let _ = proxy.start_bluetooth(default_device).await;
                        }
                    } else if prev != enabled {
                        // TODO: Implement multi-hci case
                        let default_device = config_util::list_hci_devices()[0];
+167 −126

File changed.

Preview size limit exceeded, changes collapsed.

+122 −0
Original line number Diff line number Diff line
#!/usr/bin/python3

#%%

import dbus
import dbus.service
import dbus.mainloop.glib
import time
import unittest

HCI_DEVICES_DIR = "/sys/class/bluetooth"

# File to store the Bluetooth daemon to use (bluez or floss)
BLUETOOTH_DAEMON_CURRENT = "/var/lib/misc/bluetooth-daemon.current"

# File to store the config for BluetoothManager
BTMANAGERD_CONF = "/var/lib/bluetooth/btmanagerd.json"

# D-BUS bus name
BUS_NAME = "org.chromium.bluetooth.Manager"

# D-Bus Bluetooth Manager object path
MANAGER_OBJECT_PATH = "/org/chromium/bluetooth/Manager"

# D-Bus Bluetooth Manager interface name
MANAGER_INTERFACE_NAME = "org.chromium.bluetooth.Manager"

# D-Bus Bluetooth Manager client (this test) object path
CLIENT_OBJECT_PATH = "/test_client"


def use_floss():
  with open(BLUETOOTH_DAEMON_CURRENT, "w") as f:
    f.write("floss")

def use_bluez():
  with open(BLUETOOTH_DAEMON_CURRENT, "w") as f:
    f.write("floss")

class BtmanagerdTest(unittest.TestCase):

    def setUp(self):
      self.bus = dbus.SystemBus()
      self.manager_object = self.bus.get_object(BUS_NAME, MANAGER_OBJECT_PATH)
      self.client_object = self.bus.get_object(BUS_NAME, CLIENT_OBJECT_PATH)
      self.manager_object.Stop(0, dbus_interface=MANAGER_INTERFACE_NAME)
      time.sleep(2.5)
      self.assertEqual(self._get_state(), 0)

    def _start_hci(self, hci=0):
      self.manager_object.Start(hci, dbus_interface=MANAGER_INTERFACE_NAME)
      time.sleep(2.5)

    def _stop_hci(self, hci=0):
      self.manager_object.Stop(hci, dbus_interface=MANAGER_INTERFACE_NAME)
      time.sleep(2.5)

    def _get_state(self):
      return self.manager_object.GetState(dbus_interface=MANAGER_INTERFACE_NAME)

    def _register_hci_device_change_observer(self):
      return self.manager_object.RegisterStateChangeObserver(self.client_object_path, dbus_interface=MANAGER_INTERFACE_NAME)

    def _unregister_hci_device_change_observer(self):
      return self.manager_object.UnregisterHciDeviceChangeObserver(self.client_object_path, dbus_interface=MANAGER_INTERFACE_NAME)

    def _get_floss_enabled(self):
      return self.manager_object.GetFlossEnabled(dbus_interface=MANAGER_INTERFACE_NAME)

    def _set_floss_enabled(self, enabled=True):
      return self.manager_object.SetFlossEnabled(enabled, dbus_interface=MANAGER_INTERFACE_NAME)

    def _list_hci_devices(self):
      return self.manager_object.ListHciDevices(dbus_interface=MANAGER_INTERFACE_NAME)

    def _register_hci_device_change_observer(self):
      return self.manager_object.RegisterHciDeviceChangeObserver(self.client_object_path, dbus_interface=MANAGER_INTERFACE_NAME)

    def _unregister_hci_device_change_observer(self):
      return self.manager_object.UnregisterHciDeviceChangeObserver(self.client_object_path, dbus_interface=MANAGER_INTERFACE_NAME)

    def test_list_hci_devices(self):
      self.assertTrue(len(self._list_hci_devices()) > 0)

    def test_floss_enabled(self):
      self.assertTrue(self._get_floss_enabled())

    def test_disable_floss(self):
      self._set_floss_enabled(False)
      self.assertFalse(self._get_floss_enabled())
      with open(BLUETOOTH_DAEMON_CURRENT, "r") as f:
        self.assertEqual(f.read(), "bluez")

      self._set_floss_enabled(True)
      self.assertTrue(self._get_floss_enabled())

    def test_start(self):
      self._start_hci()
      self.assertEqual(self._get_state(), 2)

    def test_astart_and_start(self):
      self._start_hci()
      self._start_hci()
      self.assertEqual(self._get_state(), 2)

    def test_stop(self):
      self._start_hci()
      self._stop_hci()
      self.assertEqual(self._get_state(), 0)

    def test_stop_and_stop(self):
      self._start_hci()
      self._stop_hci()
      self._stop_hci()
      self.assertEqual(self._get_state(), 0)


# %%
if __name__ == '__main__':
  dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
  use_floss()
  unittest.main()