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

Commit fe474d83 authored by Zach Johnson's avatar Zach Johnson
Browse files

rusty-gd: wire through classic ACL API for disconnect

also, since we are unregistering implicitly upon disconnect, no need to
expose that in the core

Bug: 171749953
Tag: #gd-refactor
Test: gd/cert/run --rhost
Change-Id: I1df3c852ecda68977c89aaa0377189cc7a746c27
parent 645e508c
Loading
Loading
Loading
Loading
+65 −5
Original line number Diff line number Diff line
@@ -6,7 +6,8 @@ use bt_hci::{Address, CommandSender, EventRegistry};
use bt_packets::hci::EventChild::ConnectionComplete;
use bt_packets::hci::{
    ClockOffsetValid, CreateConnectionBuilder, CreateConnectionCancelBuilder,
    CreateConnectionRoleSwitch, ErrorCode, EventCode, PageScanRepetitionMode, Role,
    CreateConnectionRoleSwitch, DisconnectBuilder, DisconnectReason, ErrorCode, EventCode,
    PageScanRepetitionMode, Role,
};
use bytes::Bytes;
use gddi::{module, provides, Stoppable};
@@ -54,6 +55,29 @@ pub struct Connection {
    rx: Receiver<Bytes>,
    tx: Sender<Bytes>,
    shared: Arc<Mutex<ConnectionShared>>,
    requests: Sender<ConnectionRequest>,
    evt_rx: Receiver<ConnectionEvent>,
}

/// Events generated by Connection
#[derive(Debug)]
pub enum ConnectionEvent {
    /// Connection was disconnected with the specified code.
    Disconnected(ErrorCode),
}

impl Connection {
    /// Disconnect the connection with the specified reason.
    pub async fn disconnect(&mut self, reason: DisconnectReason) {
        let (tx, rx) = oneshot::channel();
        self.requests.send(ConnectionRequest::Disconnect { reason, fut: tx }).await.unwrap();
        rx.await.unwrap()
    }
}

#[derive(Debug)]
enum ConnectionRequest {
    Disconnect { reason: DisconnectReason, fut: oneshot::Sender<()> },
}

struct ConnectionInternal {
@@ -111,8 +135,8 @@ async fn provide_acl_manager(
    let (req_tx, mut req_rx) = channel::<Request>(10);
    let (conn_evt_tx, conn_evt_rx) = channel::<Event>(10);

    rt.spawn(async move {
        let mut connections: HashMap<u16, ConnectionInternal> = HashMap::new();
    rt.clone().spawn(async move {
        let connections: Arc<Mutex<HashMap<u16, ConnectionInternal>>> = Arc::new(Mutex::new(HashMap::new()));
        let mut connect_queue: Vec<Address> = Vec::new();
        let mut pending = PendingConnect::None;

@@ -124,7 +148,7 @@ async fn provide_acl_manager(
                Some(req) = req_rx.recv() => {
                    match req {
                        Request::Connect { addr } => {
                            if connections.values().any(|c| c.addr == addr) {
                            if connections.lock().await.values().any(|c| c.addr == addr) {
                                warn!("already connected: {}", addr);
                            }
                            if let PendingConnect::None = pending {
@@ -159,18 +183,23 @@ async fn provide_acl_manager(
                                ErrorCode::Success => {
                                    let mut core_conn = dispatch.register(handle, Bluetooth::Classic).await;
                                    let shared = Arc::new(Mutex::new(ConnectionShared { role }));
                                    let (evt_tx, evt_rx) = channel(10);
                                    let (req_tx, req_rx) = channel(10);
                                    let connection = Connection {
                                        addr,
                                        shared: shared.clone(),
                                        rx: core_conn.rx.take().unwrap(),
                                        tx: core_conn.tx.take().unwrap(),
                                        requests: req_tx,
                                        evt_rx,
                                    };
                                    let connection_internal = ConnectionInternal {
                                        addr,
                                        shared,
                                    };

                                    assert!(connections.insert(handle, connection_internal).is_none());
                                    assert!(connections.lock().await.insert(handle, connection_internal).is_none());
                                    rt.spawn(run_connection(handle, evt_tx, req_rx, core_conn, connections.clone(), hci.clone()));
                                    conn_evt_tx.send(Event::ConnectSuccess(connection)).await.unwrap();
                                },
                                _ => conn_evt_tx.send(Event::ConnectFail { addr, reason: status }).await.unwrap(),
@@ -196,3 +225,34 @@ fn build_create_connection(bd_addr: Address) -> CreateConnectionBuilder {
        allow_role_switch: CreateConnectionRoleSwitch::AllowRoleSwitch,
    }
}

async fn run_connection(
    handle: u16,
    evt_tx: Sender<ConnectionEvent>,
    mut req_rx: Receiver<ConnectionRequest>,
    mut core: core::Connection,
    connections: Arc<Mutex<HashMap<u16, ConnectionInternal>>>,
    mut hci: CommandSender,
) {
    loop {
        select! {
            Some(evt) = core.evt_rx.recv() => {
                match evt {
                    core::Event::Disconnected(reason) => {
                        connections.lock().await.remove(&handle);
                        evt_tx.send(ConnectionEvent::Disconnected(reason)).await.unwrap();
                        return; // At this point, there is nothing more to run on the connection.
                    }
                }
            },
            Some(req) = req_rx.recv() => {
                match req {
                    ConnectionRequest::Disconnect{reason, fut} => {
                        hci.send(DisconnectBuilder { connection_handle: handle, reason }).await;
                        fut.send(()).unwrap();
                    }
                }
            },
        }
    }
}
+4 −21
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ pub struct Connection {
    pub tx: Option<Sender<Bytes>>,
    handle: u16,
    requests: Sender<Request>,
    evt_rx: Receiver<Event>,
    pub evt_rx: Receiver<Event>,
}

struct ConnectionInternal {
@@ -41,21 +41,11 @@ struct ConnectionInternal {
    evt_tx: Sender<Event>,
}

impl Connection {
    /// Close this connection. Consumes self.
    #[allow(dead_code)]
    pub async fn close(self) {
        let (tx, rx) = oneshot::channel();
        self.requests.send(Request::Unregister { handle: self.handle, fut: tx }).await.unwrap();
        rx.await.unwrap()
    }
}

/// Events that can be generated by the underlying layer
#[derive(Debug)]
pub enum Event {
    /// Underlying connection was closed. Reports reason why.
    Closed(ErrorCode),
    /// Underlying connection was disconnected. Reports reason why.
    Disconnected(ErrorCode),
}

/// Manages rx and tx for open ACL connections
@@ -77,7 +67,6 @@ impl AclDispatch {
#[derive(Debug)]
enum Request {
    Register { handle: u16, bt: Bluetooth, fut: oneshot::Sender<Connection> },
    Unregister { handle: u16, fut: oneshot::Sender<()> },
}

const QCOM_DEBUG_HANDLE: u16 = 0xedc;
@@ -141,12 +130,6 @@ async fn provide_acl_dispatch(
                                evt_rx
                            }).unwrap();
                        },
                        Request::Unregister { handle, fut } => {
                            if let Some(connection) = connections.remove(&handle) {
                                connection.close_tx.send(()).unwrap();
                            }
                            fut.send(()).unwrap();
                        }
                    }
                },
                Some(packet) = consume(&acl.rx) => {
@@ -189,7 +172,7 @@ async fn provide_acl_dispatch(
                        DisconnectionComplete(evt) => {
                            if let Some(connection) = connections.remove(&evt.get_connection_handle()) {
                                connection.close_tx.send(()).unwrap();
                                connection.evt_tx.send(Event::Closed(evt.get_reason())).await.unwrap();
                                connection.evt_tx.send(Event::Disconnected(evt.get_reason())).await.unwrap();
                            }
                        },
                        _ => unimplemented!(),