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

Commit c2920684 authored by Hsin-chen Chuang's avatar Hsin-chen Chuang
Browse files

floss: Refactor btstack initialization order (1/4 SocketManager)

This patch does:
- Move SocketManager creation later than Bluetooth init, so we can
  obtain the socket profile interface right there. This helps avoid
  `Option` in SocketManager.
- Move the btstack construct/init code closer - They don't need to be
  separated in 2 places.

Some backgrounds:
  We want to get rid of the redundant `Option` of the topshim objects
  that is causing many verbosities and confusing snippets (We all know
  we can't do anything without the objects... Then why is it optional?).
  The overall direction is to remove all Bluetooth's dependencies on
  initialization, because the Bluetooth topshim object needs to be
  initialized first before all other topshim objects can be obtained.

Bug: 254870880
Tag: #floss
Test: mmm packages/modules/Bluetooth
Test: manual NearbyShare / PhoneHub / Allegro WCA
Flag: EXEMPT, Floss-only changes
Change-Id: I3293d0970dd20e751da928fab09b560e448410c8
parent 37f2ef2c
Loading
Loading
Loading
Loading
+86 −78
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ use nix::sys::signal;
use std::error::Error;
use std::sync::{Arc, Condvar, Mutex};
use std::time::Duration;
use tokio::runtime::Builder;
use tokio::sync::mpsc::Sender;

// Necessary to link right entries.
@@ -129,6 +130,42 @@ fn main() -> Result<(), Box<dyn Error>> {
        thread_notify: Condvar::new(),
    });

    // This needs to be built before any |topstack::get_runtime()| call!
    let bt_sock_mgr_runtime = Arc::new(
        Builder::new_multi_thread()
            .worker_threads(1)
            .max_blocking_threads(1)
            .enable_all()
            .build()
            .expect("Failed to make socket runtime."),
    );

    topstack::get_runtime().block_on(async {
        // Connect to D-Bus system bus.
        let (resource, conn) = connection::new_system_sync()?;

        // The `resource` is a task that should be spawned onto a tokio compatible
        // reactor ASAP. If the resource ever finishes, we lost connection to D-Bus.
        let conn_join_handle = tokio::spawn(async {
            let err = resource.await;
            panic!("Lost connection to D-Bus: {}", err);
        });

        // Request a service name and quit if not able to.
        conn.request_name(DBUS_SERVICE_NAME, false, true, false).await?;

        // Install SIGTERM handler so that we can properly shutdown
        *SIG_DATA.lock().unwrap() = Some((tx.clone(), sig_notifier.clone()));
        let sig_action_term = signal::SigAction::new(
            signal::SigHandler::Handler(handle_sigterm),
            signal::SaFlags::empty(),
            signal::SigSet::empty(),
        );
        unsafe {
            signal::sigaction(signal::SIGTERM, &sig_action_term).unwrap();
        }

        // Construct btstack profiles.
        let intf = Arc::new(Mutex::new(get_btinterface().unwrap()));
        let bluetooth_gatt =
            Arc::new(Mutex::new(Box::new(BluetoothGatt::new(intf.clone(), tx.clone()))));
@@ -171,28 +208,27 @@ fn main() -> Result<(), Box<dyn Error>> {
            bluetooth_media.clone(),
            tx.clone(),
        ))));
    let bt_sock_mgr = Arc::new(Mutex::new(Box::new(BluetoothSocketManager::new(
        let bluetooth_qa = Arc::new(Mutex::new(Box::new(BluetoothQA::new(tx.clone()))));
        let dis = Arc::new(Mutex::new(Box::new(DeviceInformation::new(
            bluetooth_gatt.clone(),
            tx.clone(),
        bluetooth_admin.clone(),
        ))));
    let bluetooth_qa = Arc::new(Mutex::new(Box::new(BluetoothQA::new(tx.clone()))));

    let dis =
        Arc::new(Mutex::new(Box::new(DeviceInformation::new(bluetooth_gatt.clone(), tx.clone()))));
        bluetooth_media.lock().unwrap().set_adapter(bluetooth.clone());
        bluetooth_admin.lock().unwrap().set_adapter(bluetooth.clone());

    topstack::get_runtime().block_on(async {
        // Connect to D-Bus system bus.
        let (resource, conn) = connection::new_system_sync()?;
        bluetooth.lock().unwrap().init(init_flags, hci_index);
        bluetooth.lock().unwrap().enable();

        // The `resource` is a task that should be spawned onto a tokio compatible
        // reactor ASAP. If the resource ever finishes, we lost connection to D-Bus.
        let conn_join_handle = tokio::spawn(async {
            let err = resource.await;
            panic!("Lost connection to D-Bus: {}", err);
        });
        bluetooth_gatt.lock().unwrap().init_profiles(tx.clone(), api_tx.clone());

        // Request a service name and quit if not able to.
        conn.request_name(DBUS_SERVICE_NAME, false, true, false).await?;
        // This construction requires |intf| to be already init-ed.
        let bt_sock_mgr = Arc::new(Mutex::new(Box::new(BluetoothSocketManager::new(
            tx.clone(),
            bt_sock_mgr_runtime,
            intf.clone(),
            bluetooth_admin.clone(),
        ))));

        // Run the stack main dispatch loop.
        topstack::get_runtime().spawn(Stack::dispatch(
@@ -237,34 +273,6 @@ fn main() -> Result<(), Box<dyn Error>> {
            logging.clone(),
        ));

        // Hold locks and initialize all interfaces. This must be done AFTER DBus is
        // initialized so DBus can properly enforce user policies.
        {
            let adapter = bluetooth.clone();
            bluetooth_media.lock().unwrap().set_adapter(adapter.clone());
            bluetooth_admin.lock().unwrap().set_adapter(adapter.clone());

            let mut bluetooth = bluetooth.lock().unwrap();
            bluetooth.init(init_flags, hci_index);
            bluetooth.enable();

            bluetooth_gatt.lock().unwrap().init_profiles(tx.clone(), api_tx.clone());
            bt_sock_mgr.lock().unwrap().initialize(intf.clone());

            // Install SIGTERM handler so that we can properly shutdown
            *SIG_DATA.lock().unwrap() = Some((tx.clone(), sig_notifier.clone()));

            let sig_action_term = signal::SigAction::new(
                signal::SigHandler::Handler(handle_sigterm),
                signal::SaFlags::empty(),
                signal::SigSet::empty(),
            );

            unsafe {
                signal::sigaction(signal::SIGTERM, &sig_action_term).unwrap();
            }
        }

        // Serve clients forever.
        future::pending::<()>().await;
        unreachable!()
+33 −49
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use tokio::net::UnixStream;
use tokio::runtime::{Builder, Runtime};
use tokio::runtime::Runtime;
use tokio::sync::mpsc::{channel, Receiver, Sender};
use tokio::task::JoinHandle;
use tokio::time;
@@ -507,7 +507,7 @@ pub struct BluetoothSocketManager {
    runtime: Arc<Runtime>,

    /// Topshim interface for socket. Must call initialize for this to be valid.
    sock: Option<socket::BtSocket>,
    sock: socket::BtSocket,

    /// Monotonically increasing counter for socket id. Always access using
    /// `next_socket_id`.
@@ -522,39 +522,29 @@ pub struct BluetoothSocketManager {

impl BluetoothSocketManager {
    /// Constructs the IBluetooth implementation.
    pub fn new(tx: Sender<Message>, admin: Arc<Mutex<Box<BluetoothAdmin>>>) -> Self {
    pub fn new(
        tx: Sender<Message>,
        runtime: Arc<Runtime>,
        intf: Arc<Mutex<BluetoothInterface>>,
        admin: Arc<Mutex<Box<BluetoothAdmin>>>,
    ) -> Self {
        let callbacks = Callbacks::new(tx.clone(), Message::SocketManagerCallbackDisconnected);
        let socket_counter: u64 = 1000;
        let connecting = HashMap::new();
        let listening = HashMap::new();
        let runtime = Arc::new(
            Builder::new_multi_thread()
                .worker_threads(1)
                .max_blocking_threads(1)
                .enable_all()
                .build()
                .expect("Failed to make socket runtime."),
        );

        BluetoothSocketManager {
            callbacks,
            connecting,
            listening,
            runtime,
            sock: None,
            sock: socket::BtSocket::new(&intf.lock().unwrap()),
            socket_counter,
            tx,
            admin,
        }
    }

    /// In order to access the underlying socket apis, we must initialize after
    /// the btif layer has initialized. Thus, this must be called after intf is
    /// init.
    pub fn initialize(&mut self, intf: Arc<Mutex<BluetoothInterface>>) {
        self.sock = Some(socket::BtSocket::new(&intf.lock().unwrap()));
    }

    /// Check if there is any listening socket.
    pub fn is_listening(&self) -> bool {
        self.listening.values().any(|vs| !vs.is_empty())
@@ -605,8 +595,7 @@ impl BluetoothSocketManager {
        }

        // Create listener socket pair
        let (mut status, result) =
            self.sock.as_ref().expect("Socket Manager not initialized").listen(
        let (mut status, result) = self.sock.listen(
            socket_info.sock_type.clone(),
            socket_info.name.as_ref().unwrap_or(&String::new()).clone(),
            socket_info.uuid,
@@ -696,8 +685,7 @@ impl BluetoothSocketManager {
        }

        // Create connecting socket pair.
        let (mut status, result) =
            self.sock.as_ref().expect("Socket manager not initialized").connect(
        let (mut status, result) = self.sock.connect(
            socket_info.remote_device.address,
            socket_info.sock_type.clone(),
            socket_info.uuid,
@@ -1190,7 +1178,7 @@ impl BluetoothSocketManager {
            }

            SocketActions::DisconnectAll(addr) => {
                self.sock.as_ref().expect("Socket Manager not initialized").disconnect_all(addr);
                self.sock.disconnect_all(addr);
            }
        }
    }
@@ -1251,11 +1239,7 @@ impl BluetoothSocketManager {
    // libbluetooth auto starts the control request only when it is the client.
    // This function allows the host to start the control request while as a server.
    pub fn rfcomm_send_msc(&mut self, dlci: u8, addr: RawAddress) {
        let Some(sock) = self.sock.as_ref() else {
            log::warn!("Socket Manager not initialized when starting control request");
            return;
        };
        if sock.send_msc(dlci, addr) != BtStatus::Success {
        if self.sock.send_msc(dlci, addr) != BtStatus::Success {
            log::warn!("Failed to start control request");
        }
    }
+3 −0
Original line number Diff line number Diff line
@@ -140,6 +140,9 @@ pub fn try_from_fd(fd: i32) -> Result<File, FdError> {
impl BtSocket {
    pub fn new(intf: &BluetoothInterface) -> Self {
        let r = intf.get_profile_interface(SupportedProfiles::Socket);
        if r.is_null() {
            panic!("Failed to get Socket interface");
        }
        BtSocket { internal: RawBtSockWrapper { raw: r as *const bindings::btsock_interface_t } }
    }