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

Commit 2a580355 authored by Yun-Hao Chung's avatar Yun-Hao Chung Committed by Automerger Merge Worker
Browse files

Floss: Refactor DBus intf and only expose after interal API is ready am: a0c5c54a

parents 6960613e a0c5c54a
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ use dbus::message::MatchRule;
use dbus::nonblock::SyncConnection;
use dbus_crossroads::Crossroads;
use tokio::sync::mpsc;
use tokio::time::timeout;
use tokio::time::{sleep, timeout};

use crate::bt_adv::AdvSet;
use crate::bt_gatt::GattClientContext;
@@ -246,6 +246,9 @@ impl ClientContext {
        let fg = self.fg.clone();
        tokio::spawn(async move {
            let adapter = String::from(format!("adapter{}", idx));
            // Floss won't export the interface until it is ready to be used.
            // Wait 1 second before registering the callbacks.
            sleep(Duration::from_millis(1000)).await;
            let _ = fg.send(ForegroundActions::RegisterAdapterCallback(adapter)).await;
        });
    }
+1 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ impl_dbus_arg_from_into!(BtStatus, u32);

/// A mixin of the several interfaces. The naming of the fields in the mixin must match
/// what is listed in the `generate_dbus_exporter` invocation.
#[derive(Clone)]
pub struct BluetoothMixin {
    pub adapter: Arc<Mutex<Box<Bluetooth>>>,
    pub qa: Arc<Mutex<Box<Bluetooth>>>,
+231 −0
Original line number Diff line number Diff line
use dbus::{channel::MatchingReceiver, message::MatchRule, nonblock::SyncConnection};
use dbus_crossroads::Crossroads;
use dbus_projection::DisconnectWatcher;

use std::sync::{Arc, Mutex};
use tokio::sync::mpsc::{channel, Receiver, Sender};

use btstack::{
    battery_manager::BatteryManager, battery_provider_manager::BatteryProviderManager,
    bluetooth::Bluetooth, bluetooth_admin::BluetoothAdmin, bluetooth_gatt::BluetoothGatt,
    bluetooth_logging::BluetoothLogging, bluetooth_media::BluetoothMedia,
    bluetooth_qa::BluetoothQA, socket_manager::BluetoothSocketManager, suspend::Suspend,
    APIMessage, BluetoothAPI,
};

use crate::iface_battery_manager;
use crate::iface_battery_provider_manager;
use crate::iface_bluetooth;
use crate::iface_bluetooth_admin;
use crate::iface_bluetooth_gatt;
use crate::iface_bluetooth_media;
use crate::iface_bluetooth_qa;
use crate::iface_bluetooth_telephony;
use crate::iface_logging;

pub(crate) struct InterfaceManager {}

impl InterfaceManager {
    fn make_object_name(idx: i32, name: &str) -> String {
        String::from(format!("/org/chromium/bluetooth/hci{}/{}", idx, name))
    }

    /// Creates an mpsc channel for passing messages to the main dispatch loop.
    pub fn create_channel() -> (Sender<APIMessage>, Receiver<APIMessage>) {
        channel::<APIMessage>(1)
    }

    pub async fn dispatch(
        mut rx: Receiver<APIMessage>,
        adapter_index: i32,
        conn: Arc<SyncConnection>,
        disconnect_watcher: Arc<Mutex<DisconnectWatcher>>,
        bluetooth: Arc<Mutex<Box<Bluetooth>>>,
        bluetooth_admin: Arc<Mutex<Box<BluetoothAdmin>>>,
        bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>,
        battery_manager: Arc<Mutex<Box<BatteryManager>>>,
        battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>,
        bluetooth_media: Arc<Mutex<Box<BluetoothMedia>>>,
        bluetooth_qa: Arc<Mutex<Box<BluetoothQA>>>,
        bt_sock_mgr: Arc<Mutex<Box<BluetoothSocketManager>>>,
        suspend: Arc<Mutex<Box<Suspend>>>,
        logging: Arc<Mutex<Box<BluetoothLogging>>>,
    ) {
        // Prepare D-Bus interfaces.
        let cr = Arc::new(Mutex::new(Crossroads::new()));
        cr.lock().unwrap().set_async_support(Some((
            conn.clone(),
            Box::new(|x| {
                tokio::spawn(x);
            }),
        )));

        // Announce the exported adapter objects so that clients can properly detect the readiness
        // of the adapter APIs.
        cr.lock().unwrap().set_object_manager_support(Some(conn.clone()));
        let object_manager = cr.lock().unwrap().object_manager();
        cr.lock().unwrap().insert("/", &[object_manager], {});

        // Set up handling of D-Bus methods. This must be done before exporting interfaces so that
        // clients that rely on InterfacesAdded signal can rely on us being ready to handle methods
        // on those exported interfaces.
        let cr_clone = cr.clone();
        conn.start_receive(
            MatchRule::new_method_call(),
            Box::new(move |msg, conn| {
                cr_clone.lock().unwrap().handle_message(msg, conn).unwrap();
                true
            }),
        );

        // Register D-Bus method handlers of IBluetooth.
        let adapter_iface = iface_bluetooth::export_bluetooth_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );
        let qa_iface = iface_bluetooth_qa::export_bluetooth_qa_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );
        let qa_legacy_iface = iface_bluetooth::export_bluetooth_qa_legacy_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );
        let socket_mgr_iface = iface_bluetooth::export_socket_mgr_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );
        let suspend_iface = iface_bluetooth::export_suspend_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );
        let logging_iface = iface_logging::export_bluetooth_logging_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );

        // Register D-Bus method handlers of IBluetoothGatt.
        let gatt_iface = iface_bluetooth_gatt::export_bluetooth_gatt_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );

        let media_iface = iface_bluetooth_media::export_bluetooth_media_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );

        let telephony_iface = iface_bluetooth_telephony::export_bluetooth_telephony_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );

        let battery_provider_manager_iface =
            iface_battery_provider_manager::export_battery_provider_manager_dbus_intf(
                conn.clone(),
                &mut cr.lock().unwrap(),
                disconnect_watcher.clone(),
            );

        let battery_manager_iface = iface_battery_manager::export_battery_manager_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );

        let admin_iface = iface_bluetooth_admin::export_bluetooth_admin_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );

        // Create mixin object for Bluetooth + Suspend interfaces.
        let mixin = Box::new(iface_bluetooth::BluetoothMixin {
            adapter: bluetooth.clone(),
            qa: bluetooth.clone(),
            suspend: suspend.clone(),
            socket_mgr: bt_sock_mgr.clone(),
        });

        loop {
            let m = rx.recv().await;

            if m.is_none() {
                eprintln!("APIMessage dispatch loop quit");
                break;
            }

            match m.unwrap() {
                APIMessage::IsReady(api) => match api {
                    BluetoothAPI::Adapter => {
                        cr.lock().unwrap().insert(
                            Self::make_object_name(adapter_index, "adapter"),
                            &[adapter_iface, qa_legacy_iface, socket_mgr_iface, suspend_iface],
                            mixin.clone(),
                        );

                        cr.lock().unwrap().insert(
                            Self::make_object_name(adapter_index, "admin"),
                            &[admin_iface],
                            bluetooth_admin.clone(),
                        );

                        cr.lock().unwrap().insert(
                            Self::make_object_name(adapter_index, "logging"),
                            &[logging_iface],
                            logging.clone(),
                        );

                        cr.lock().unwrap().insert(
                            Self::make_object_name(adapter_index, "qa"),
                            &[qa_iface],
                            bluetooth_qa.clone(),
                        );
                    }
                    BluetoothAPI::Gatt => {
                        cr.lock().unwrap().insert(
                            Self::make_object_name(adapter_index, "gatt"),
                            &[gatt_iface],
                            bluetooth_gatt.clone(),
                        );
                    }
                    BluetoothAPI::Media => {
                        cr.lock().unwrap().insert(
                            Self::make_object_name(adapter_index, "media"),
                            &[media_iface],
                            bluetooth_media.clone(),
                        );

                        cr.lock().unwrap().insert(
                            Self::make_object_name(adapter_index, "telephony"),
                            &[telephony_iface],
                            bluetooth_media.clone(),
                        );
                    }
                    BluetoothAPI::Battery => {
                        cr.lock().unwrap().insert(
                            Self::make_object_name(adapter_index, "battery_provider_manager"),
                            &[battery_provider_manager_iface],
                            battery_provider_manager.clone(),
                        );

                        cr.lock().unwrap().insert(
                            Self::make_object_name(adapter_index, "battery_manager"),
                            &[battery_manager_iface],
                            battery_manager.clone(),
                        );
                    }
                },
            }
        }
    }
}
+17 −162
Original line number Diff line number Diff line
use btstack::bluetooth_qa::BluetoothQA;
use clap::{App, AppSettings, Arg};
use dbus::{channel::MatchingReceiver, message::MatchRule};
use dbus_crossroads::Crossroads;
use dbus_projection::DisconnectWatcher;
use dbus_tokio::connection;
use futures::future;
use lazy_static::lazy_static;
@@ -9,6 +7,7 @@ use nix::sys::signal;
use std::error::Error;
use std::sync::{Arc, Condvar, Mutex};
use std::time::Duration;
use tokio::sync::mpsc::Sender;
use tokio::time;

// Necessary to link right entries.
@@ -25,13 +24,12 @@ use btstack::{
    bluetooth_gatt::BluetoothGatt,
    bluetooth_logging::BluetoothLogging,
    bluetooth_media::BluetoothMedia,
    bluetooth_qa::BluetoothQA,
    dis::DeviceInformation,
    socket_manager::BluetoothSocketManager,
    suspend::Suspend,
    Message, Stack,
};
use dbus_projection::DisconnectWatcher;
use tokio::sync::mpsc::Sender;

mod dbus_arg;
mod iface_battery_manager;
@@ -43,6 +41,7 @@ mod iface_bluetooth_media;
mod iface_bluetooth_qa;
mod iface_bluetooth_telephony;
mod iface_logging;
mod interface_manager;

const DBUS_SERVICE_NAME: &str = "org.chromium.bluetooth";
const ADMIN_SETTINGS_FILE_PATH: &str = "/var/lib/bluetooth/admin_policy.json";
@@ -61,10 +60,6 @@ const VERBOSE_ONLY_LOG_TAGS: &[&str] = &[
    "uipc",      // Userspace IPC implementation
];

fn make_object_name(idx: i32, name: &str) -> String {
    String::from(format!("/org/chromium/bluetooth/hci{}/{}", idx, name))
}

/// Runs the Bluetooth daemon serving D-Bus IPC.
fn main() -> Result<(), Box<dyn Error>> {
    let matches = App::new("Bluetooth Adapter Daemon")
@@ -137,6 +132,7 @@ fn main() -> Result<(), Box<dyn Error>> {
    init_flags.push(String::from("INIT_classic_discovery_only=true"));

    let (tx, rx) = Stack::create_channel();
    let (api_tx, api_rx) = interface_manager::InterfaceManager::create_channel();
    let sig_notifier = Arc::new(SigData {
        enabled: Mutex::new(false),
        enabled_notify: Condvar::new(),
@@ -171,6 +167,7 @@ fn main() -> Result<(), Box<dyn Error>> {
        adapter_index,
        hci_index,
        tx.clone(),
        api_tx.clone(),
        sig_notifier.clone(),
        intf.clone(),
        bluetooth_admin.clone(),
@@ -207,21 +204,6 @@ fn main() -> Result<(), Box<dyn Error>> {
        // Request a service name and quit if not able to.
        conn.request_name(DBUS_SERVICE_NAME, false, true, false).await?;

        // Prepare D-Bus interfaces.
        let cr = Arc::new(Mutex::new(Crossroads::new()));
        cr.lock().unwrap().set_async_support(Some((
            conn.clone(),
            Box::new(|x| {
                tokio::spawn(x);
            }),
        )));

        // Announce the exported adapter objects so that clients can properly detect the readiness
        // of the adapter APIs.
        cr.lock().unwrap().set_object_manager_support(Some(conn.clone()));
        let object_manager = cr.lock().unwrap().object_manager();
        cr.lock().unwrap().insert("/", &[object_manager], {});

        // Run the stack main dispatch loop.
        topstack::get_runtime().spawn(Stack::dispatch(
            rx,
@@ -242,149 +224,22 @@ fn main() -> Result<(), Box<dyn Error>> {
        let disconnect_watcher = Arc::new(Mutex::new(DisconnectWatcher::new()));
        disconnect_watcher.lock().unwrap().setup_watch(conn.clone()).await;

        // Set up handling of D-Bus methods. This must be done before exporting interfaces so that
        // clients that rely on InterfacesAdded signal can rely on us being ready to handle methods
        // on those exported interfaces.
        let cr_clone = cr.clone();
        conn.start_receive(
            MatchRule::new_method_call(),
            Box::new(move |msg, conn| {
                cr_clone.lock().unwrap().handle_message(msg, conn).unwrap();
                true
            }),
        );

        // Register D-Bus method handlers of IBluetooth.
        let adapter_iface = iface_bluetooth::export_bluetooth_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );
        let qa_iface = iface_bluetooth_qa::export_bluetooth_qa_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );
        let qa_legacy_iface = iface_bluetooth::export_bluetooth_qa_legacy_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );
        let socket_mgr_iface = iface_bluetooth::export_socket_mgr_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );
        let suspend_iface = iface_bluetooth::export_suspend_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );
        let logging_iface = iface_logging::export_bluetooth_logging_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );

        // Register D-Bus method handlers of IBluetoothGatt.
        let gatt_iface = iface_bluetooth_gatt::export_bluetooth_gatt_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );

        let media_iface = iface_bluetooth_media::export_bluetooth_media_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );

        let telephony_iface = iface_bluetooth_telephony::export_bluetooth_telephony_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );

        let battery_provider_manager_iface =
            iface_battery_provider_manager::export_battery_provider_manager_dbus_intf(
                conn.clone(),
                &mut cr.lock().unwrap(),
                disconnect_watcher.clone(),
            );

        let battery_manager_iface = iface_battery_manager::export_battery_manager_dbus_intf(
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );

        let admin_iface = iface_bluetooth_admin::export_bluetooth_admin_dbus_intf(
        tokio::spawn(interface_manager::InterfaceManager::dispatch(
            api_rx,
            adapter_index,
            conn.clone(),
            &mut cr.lock().unwrap(),
            disconnect_watcher.clone(),
        );

        // Create mixin object for Bluetooth + Suspend interfaces.
        let mixin = Box::new(iface_bluetooth::BluetoothMixin {
            adapter: bluetooth.clone(),
            qa: bluetooth.clone(),
            suspend: suspend.clone(),
            socket_mgr: bt_sock_mgr.clone(),
        });

        cr.lock().unwrap().insert(
            make_object_name(adapter_index, "adapter"),
            &[adapter_iface, qa_legacy_iface, socket_mgr_iface, suspend_iface],
            mixin,
        );

        cr.lock().unwrap().insert(
            make_object_name(adapter_index, "gatt"),
            &[gatt_iface],
            bluetooth.clone(),
            bluetooth_admin.clone(),
            bluetooth_gatt.clone(),
        );

        cr.lock().unwrap().insert(
            make_object_name(adapter_index, "media"),
            &[media_iface],
            bluetooth_media.clone(),
        );

        cr.lock().unwrap().insert(
            make_object_name(adapter_index, "telephony"),
            &[telephony_iface],
            bluetooth_media.clone(),
        );

        cr.lock().unwrap().insert(
            make_object_name(adapter_index, "battery_provider_manager"),
            &[battery_provider_manager_iface],
            battery_provider_manager.clone(),
        );

        cr.lock().unwrap().insert(
            make_object_name(adapter_index, "battery_manager"),
            &[battery_manager_iface],
            battery_manager.clone(),
        );

        cr.lock().unwrap().insert(
            make_object_name(adapter_index, "admin"),
            &[admin_iface],
            bluetooth_admin.clone(),
        );

        cr.lock().unwrap().insert(
            make_object_name(adapter_index, "logging"),
            &[logging_iface],
            logging.clone(),
        );

        cr.lock().unwrap().insert(
            make_object_name(adapter_index, "qa"),
            &[qa_iface],
            battery_provider_manager.clone(),
            bluetooth_media.clone(),
            bluetooth_qa.clone(),
        );
            bt_sock_mgr.clone(),
            suspend.clone(),
            logging.clone(),
        ));

        // Hold locks and initialize all interfaces. This must be done AFTER DBus is
        // initialized so DBus can properly enforce user policies.
+14 −1
Original line number Diff line number Diff line
@@ -47,7 +47,7 @@ use crate::bluetooth_media::{BluetoothMedia, IBluetoothMedia, MediaActions};
use crate::callbacks::Callbacks;
use crate::socket_manager::SocketActions;
use crate::uuid::{Profile, UuidHelper, HOGP};
use crate::{Message, RPCProxy, SuspendMode};
use crate::{APIMessage, BluetoothAPI, Message, RPCProxy, SuspendMode};

pub(crate) const FLOSS_VER: u16 = 0x0001;
const DEFAULT_DISCOVERY_TIMEOUT_MS: u64 = 12800;
@@ -507,6 +507,7 @@ pub struct Bluetooth {
    sdp: Option<Sdp>,
    state: BtState,
    tx: Sender<Message>,
    api_tx: Sender<APIMessage>,
    // Internal API members
    discoverable_timeout: Option<JoinHandle<()>>,
    cancelling_devices: HashSet<RawAddress>,
@@ -524,6 +525,7 @@ impl Bluetooth {
        adapter_index: i32,
        hci_index: i32,
        tx: Sender<Message>,
        api_tx: Sender<APIMessage>,
        sig_notifier: Arc<SigData>,
        intf: Arc<Mutex<BluetoothInterface>>,
        bluetooth_admin: Arc<Mutex<Box<BluetoothAdmin>>>,
@@ -561,6 +563,7 @@ impl Bluetooth {
            sdp: None,
            state: BtState::Off,
            tx,
            api_tx,
            // Internal API members
            discoverable_timeout: None,
            cancelling_devices: HashSet::new(),
@@ -1336,9 +1339,19 @@ impl BtifBluetoothCallbacks for Bluetooth {

                // Inform the rest of the stack we're ready.
                let txl = self.tx.clone();
                let api_txl = self.api_tx.clone();
                tokio::spawn(async move {
                    let _ = txl.send(Message::AdapterReady).await;
                });
                tokio::spawn(async move {
                    let _ = api_txl.send(APIMessage::IsReady(BluetoothAPI::Adapter)).await;
                    // TODO(b:300202052) make sure media interface is exposed after initialized
                    let _ = api_txl.send(APIMessage::IsReady(BluetoothAPI::Media)).await;
                    // TODO(b:300202055) make sure GATT interface is exposed after initialized
                    let _ = api_txl.send(APIMessage::IsReady(BluetoothAPI::Gatt)).await;
                    // TODO(b:300202503) make sure battery interface is exposed after initialized
                    let _ = api_txl.send(APIMessage::IsReady(BluetoothAPI::Battery)).await;
                });
            }
        }
    }
Loading