diff options
| author | 2024-10-09 22:08:28 +0200 | |
|---|---|---|
| committer | 2024-10-09 22:13:04 +0200 | |
| commit | 8adbe408d3a34728796c4f1050df62d3a7fb56bc (patch) | |
| tree | 58b51090bc762a31b5f7c0a4d11284f35f47f283 | |
| parent | 9a5b6b8dab52df8fbd99c57357fd03c7f080a1d6 (diff) | |
use_unified_connection_manager removal
Unused, out of date
Test: mma -j32
Bug: 290846969
Bug: 349469413
Bug: 372202918
Flag: EXEMPT, just delting unused code under flag
Change-Id: Ie01c56f81d81affeed5c7285bcf8d712b6af59b0
24 files changed, 40 insertions, 2201 deletions
diff --git a/flags/hci.aconfig b/flags/hci.aconfig index 8c5180a298..9c6d21d3a9 100644 --- a/flags/hci.aconfig +++ b/flags/hci.aconfig @@ -2,16 +2,6 @@ package: "com.android.bluetooth.flags" container: "com.android.btservices" flag { - name: "unified_connection_manager" - namespace: "bluetooth" - description: "Manage connections centrally and remove the ACL shim layer" - bug: "349469413" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "encryption_change_v2" namespace: "bluetooth" description: "Enable encryption change V2 event" diff --git a/system/main/shim/acl.cc b/system/main/shim/acl.cc index 79d6032095..7f33da446f 100644 --- a/system/main/shim/acl.cc +++ b/system/main/shim/acl.cc @@ -1009,9 +1009,7 @@ struct shim::Acl::impl { auto connection = handle_to_le_connection_map_.find(handle); if (connection != handle_to_le_connection_map_.end()) { auto remote_address_with_type = connection->second->GetRemoteAddressWithType(); - if (!com::android::bluetooth::flags::unified_connection_manager()) { - GetAclManager()->RemoveFromBackgroundList(remote_address_with_type); - } + GetAclManager()->RemoveFromBackgroundList(remote_address_with_type); connection->second->InitiateDisconnect(ToDisconnectReasonFromLegacy(reason)); log::debug("Disconnection initiated le remote:{} handle:{}", remote_address_with_type, handle); diff --git a/system/rust/Android.bp b/system/rust/Android.bp index f3fddcd3b9..9e4cca0736 100644 --- a/system/rust/Android.bp +++ b/system/rust/Android.bp @@ -108,7 +108,6 @@ cc_library_static { "-Wno-missing-prototypes", ], srcs: [ - "src/connection/ffi/connection_shim.cc", "src/core/ffi/module.cc", "src/gatt/ffi/gatt_shim.cc", ], @@ -169,7 +168,6 @@ cc_library_static { filegroup { name: "libbluetooth_core_rs_ffi", srcs: [ - "src/connection/ffi.rs", "src/core/ffi.rs", "src/gatt/ffi.rs", ], diff --git a/system/rust/BUILD.gn b/system/rust/BUILD.gn index 5c386e5a0f..f9c63f4986 100644 --- a/system/rust/BUILD.gn +++ b/system/rust/BUILD.gn @@ -22,7 +22,6 @@ cxxbridge_libheader("cxxlibheader") { static_library("core_rs") { sources = [ - "src/connection/ffi/connection_shim.cc", "src/core/ffi/module.cc", "src/gatt/ffi/gatt_shim.cc", ] diff --git a/system/rust/src/connection.rs b/system/rust/src/connection.rs deleted file mode 100644 index 99dc4c6cb3..0000000000 --- a/system/rust/src/connection.rs +++ /dev/null @@ -1,431 +0,0 @@ -//! This module manages LE connection requests and active -//! LE connections. In particular, it de-duplicates connection requests, -//! avoids duplicate connections to the same devices (even with different RPAs), -//! and retries failed connections - -use std::{ - cell::RefCell, collections::HashSet, fmt::Debug, future::Future, hash::Hash, ops::Deref, - time::Duration, -}; - -use crate::{ - core::{ - address::AddressWithType, - shared_box::{SharedBox, WeakBox, WeakBoxRef}, - }, - gatt::ids::ServerId, -}; - -use self::{ - acceptlist_manager::{determine_target_state, LeAcceptlistManager}, - attempt_manager::{ConnectionAttempts, ConnectionMode}, - le_manager::{ErrorCode, InactiveLeAclManager, LeAclManagerConnectionCallbacks}, -}; - -mod acceptlist_manager; -mod attempt_manager; -mod ffi; -pub mod le_manager; -mod mocks; - -pub use ffi::{register_callbacks, LeAclManagerImpl, LeAclManagerShim}; -use log::info; -use scopeguard::ScopeGuard; -use tokio::{task::spawn_local, time::timeout}; - -/// Possible errors returned when making a connection attempt -#[derive(Debug, PartialEq, Eq)] -pub enum CreateConnectionFailure { - /// This client is already making a connection of the same type - /// to the same address. - ConnectionAlreadyPending, -} - -/// Errors returned if a connection successfully starts but fails afterwards. -#[derive(Debug, PartialEq, Eq)] -pub enum ConnectionFailure { - /// The connection attempt was cancelled - Cancelled, - /// The connection completed but with an HCI error code - Error(ErrorCode), -} - -/// Errors returned if the client fails to cancel their connection attempt -#[derive(Debug, PartialEq, Eq)] -pub enum CancelConnectFailure { - /// The connection attempt does not exist - ConnectionNotPending, -} - -/// Unique identifiers for a client of the connection manager -#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] -pub enum ConnectionManagerClient { - /// A GATT client with given client ID - GattClient(u8), - /// A GATT server with given server ID - GattServer(ServerId), -} - -/// An active connection -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct LeConnection { - /// The address of the peer device, as reported in the connection complete event - /// This is guaranteed to be unique across active connections, so we can implement - /// PartialEq/Eq on this. - pub remote_address: AddressWithType, -} - -/// Responsible for managing the initiator state and the list of -/// devices on the filter accept list -#[derive(Debug)] -pub struct ConnectionManager { - state: RefCell<ConnectionManagerState>, -} - -#[derive(Debug)] -struct ConnectionManagerState { - /// All pending connection attempts (unresolved direct + all background) - attempts: ConnectionAttempts, - /// The addresses we are currently connected to - current_connections: HashSet<AddressWithType>, - /// Tracks the state of the LE connect list, and updates it to drive to a - /// specified target state - acceptlist_manager: LeAcceptlistManager, -} - -struct ConnectionManagerCallbackHandler(WeakBox<ConnectionManager>); - -const DIRECT_CONNECTION_TIMEOUT: Duration = Duration::from_secs( - 29, /* ugly hack to avoid fighting with le_impl timeout, until I remove that timeout */ -); - -impl LeAclManagerConnectionCallbacks for ConnectionManagerCallbackHandler { - fn on_le_connect(&self, address: AddressWithType, result: Result<LeConnection, ErrorCode>) { - self.with_manager(|manager| manager.on_le_connect(address, result)) - } - - fn on_disconnect(&self, address: AddressWithType) { - self.with_manager(|manager| manager.on_disconnect(address)) - } -} - -impl ConnectionManagerCallbackHandler { - fn with_manager(&self, f: impl FnOnce(&ConnectionManager)) { - self.0.with(|manager| f(manager.expect("got connection event after stack died").deref())) - } -} - -impl ConnectionManager { - /// Constructor - pub fn new(le_manager: impl InactiveLeAclManager) -> SharedBox<Self> { - SharedBox::new_cyclic(|weak| Self { - state: RefCell::new(ConnectionManagerState { - attempts: ConnectionAttempts::new(), - current_connections: HashSet::new(), - acceptlist_manager: LeAcceptlistManager::new( - le_manager.register_callbacks(ConnectionManagerCallbackHandler(weak)), - ), - }), - }) - } -} - -/// Make the state of the LeAcceptlistManager consistent with the attempts tracked in ConnectionAttempts -fn reconcile_state(state: &mut ConnectionManagerState) { - state - .acceptlist_manager - .drive_to_state(determine_target_state(&state.attempts.active_attempts())); -} - -impl WeakBoxRef<'_, ConnectionManager> { - /// Start a direct connection to a peer device from a specified client. If the peer - /// is connected, immediately resolve the attempt. - pub fn start_direct_connection( - &self, - client: ConnectionManagerClient, - address: AddressWithType, - ) -> Result<(), CreateConnectionFailure> { - spawn_local(timeout(DIRECT_CONNECTION_TIMEOUT, self.direct_connection(client, address)?)); - Ok(()) - } - - /// Start a direct connection to a peer device from a specified client. - /// - /// # Cancellation Safety - /// If this future is dropped, the connection attempt will be cancelled. It can also be cancelled - /// from the separate API ConnectionManager#cancel_connection. - fn direct_connection( - &self, - client: ConnectionManagerClient, - address: AddressWithType, - ) -> Result< - impl Future<Output = Result<LeConnection, ConnectionFailure>>, - CreateConnectionFailure, - > { - let mut state = self.state.borrow_mut(); - - // if connected, this is a no-op - let attempt_and_guard = if state.current_connections.contains(&address) { - None - } else { - let pending_attempt = state.attempts.register_direct_connection(client, address)?; - let attempt_id = pending_attempt.id; - reconcile_state(&mut state); - Some(( - pending_attempt, - scopeguard::guard(self.downgrade(), move |this| { - // remove the attempt after we are cancelled - this.with(|this| { - this.map(|this| { - info!("Cancelling attempt {attempt_id:?}"); - let mut state = this.state.borrow_mut(); - state.attempts.cancel_attempt_with_id(attempt_id); - reconcile_state(&mut state); - }) - }); - }), - )) - }; - - Ok(async move { - let Some((attempt, guard)) = attempt_and_guard else { - // if we did not make an attempt, the connection must be ready - return Ok(LeConnection { remote_address: address }); - }; - // otherwise, wait until the attempt resolves - let ret = attempt.await; - // defuse scopeguard (no need to cancel now) - ScopeGuard::into_inner(guard); - ret - }) - } -} - -impl ConnectionManager { - /// Start a background connection to a peer device with given parameters from a specified client. - pub fn add_background_connection( - &self, - client: ConnectionManagerClient, - address: AddressWithType, - ) -> Result<(), CreateConnectionFailure> { - let mut state = self.state.borrow_mut(); - state.attempts.register_background_connection(client, address)?; - reconcile_state(&mut state); - Ok(()) - } - - /// Cancel connection attempt from this client to the specified address with the specified mode. - pub fn cancel_connection( - &self, - client: ConnectionManagerClient, - address: AddressWithType, - mode: ConnectionMode, - ) -> Result<(), CancelConnectFailure> { - let mut state = self.state.borrow_mut(); - state.attempts.cancel_attempt(client, address, mode)?; - reconcile_state(&mut state); - Ok(()) - } - - /// Cancel all connection attempts to this address - pub fn cancel_unconditionally(&self, address: AddressWithType) { - let mut state = self.state.borrow_mut(); - state.attempts.remove_unconditionally(address); - reconcile_state(&mut state); - } - - /// Cancel all connection attempts from this client - pub fn remove_client(&self, client: ConnectionManagerClient) { - let mut state = self.state.borrow_mut(); - state.attempts.remove_client(client); - reconcile_state(&mut state); - } - - fn on_le_connect(&self, address: AddressWithType, result: Result<LeConnection, ErrorCode>) { - let mut state = self.state.borrow_mut(); - // record this connection while it exists - state.current_connections.insert(address); - // all completed connections remove the address from the direct list - state.acceptlist_manager.on_connect_complete(address); - // invoke any pending callbacks, update set of attempts - state.attempts.process_connection(address, result); - // update the acceptlist - reconcile_state(&mut state); - } - - fn on_disconnect(&self, address: AddressWithType) { - let mut state = self.state.borrow_mut(); - state.current_connections.remove(&address); - reconcile_state(&mut state); - } -} - -#[cfg(test)] -mod test { - use crate::{core::address::AddressType, utils::task::block_on_locally}; - - use super::{mocks::mock_le_manager::MockLeAclManager, *}; - - const CLIENT_1: ConnectionManagerClient = ConnectionManagerClient::GattClient(1); - const CLIENT_2: ConnectionManagerClient = ConnectionManagerClient::GattClient(2); - - const ADDRESS_1: AddressWithType = - AddressWithType { address: [1, 2, 3, 4, 5, 6], address_type: AddressType::Public }; - - const ERROR: ErrorCode = ErrorCode(1); - - #[test] - fn test_single_direct_connection() { - block_on_locally(async { - // arrange - let mock_le_manager = MockLeAclManager::new(); - let connection_manager = ConnectionManager::new(mock_le_manager.clone()); - - // act: initiate a direct connection - connection_manager.as_ref().start_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - - // assert: the direct connection is pending - assert_eq!(mock_le_manager.current_connection_mode(), Some(ConnectionMode::Direct)); - assert_eq!(mock_le_manager.current_acceptlist().len(), 1); - assert!(mock_le_manager.current_acceptlist().contains(&ADDRESS_1)); - }); - } - - #[test] - fn test_failed_direct_connection() { - block_on_locally(async { - // arrange: one pending direct connection - let mock_le_manager = MockLeAclManager::new(); - let connection_manager = ConnectionManager::new(mock_le_manager.clone()); - connection_manager.as_ref().start_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - - // act: the connection attempt fails - mock_le_manager.on_le_connect(ADDRESS_1, ERROR); - - // assert: the direct connection has stopped - assert_eq!(mock_le_manager.current_connection_mode(), None); - }); - } - - #[test] - fn test_single_background_connection() { - block_on_locally(async { - // arrange - let mock_le_manager = MockLeAclManager::new(); - let connection_manager = ConnectionManager::new(mock_le_manager.clone()); - - // act: initiate a background connection - connection_manager.as_ref().add_background_connection(CLIENT_1, ADDRESS_1).unwrap(); - - // assert: the background connection is pending - assert_eq!(mock_le_manager.current_connection_mode(), Some(ConnectionMode::Background)); - assert_eq!(mock_le_manager.current_acceptlist().len(), 1); - assert!(mock_le_manager.current_acceptlist().contains(&ADDRESS_1)); - }); - } - - #[test] - fn test_resolved_connection() { - block_on_locally(async { - // arrange - let mock_le_manager = MockLeAclManager::new(); - let connection_manager = ConnectionManager::new(mock_le_manager.clone()); - - // act: initiate a direct connection, that succeeds - connection_manager.as_ref().start_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - mock_le_manager.on_le_connect(ADDRESS_1, ErrorCode::SUCCESS); - - // assert: no connection is pending - assert_eq!(mock_le_manager.current_connection_mode(), None); - }); - } - - #[test] - fn test_resolved_background_connection() { - block_on_locally(async { - // arrange - let mock_le_manager = MockLeAclManager::new(); - let connection_manager = ConnectionManager::new(mock_le_manager.clone()); - - // act: initiate a background connection, that succeeds - connection_manager.as_ref().add_background_connection(CLIENT_1, ADDRESS_1).unwrap(); - mock_le_manager.on_le_connect(ADDRESS_1, ErrorCode::SUCCESS); - - // assert: no connection is pending - assert_eq!(mock_le_manager.current_connection_mode(), None); - }); - } - - #[test] - fn test_resolved_direct_connection_after_disconnect() { - block_on_locally(async { - // arrange - let mock_le_manager = MockLeAclManager::new(); - let connection_manager = ConnectionManager::new(mock_le_manager.clone()); - - // act: initiate a direct connection, that succeeds, then disconnects - connection_manager.as_ref().start_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - mock_le_manager.on_le_connect(ADDRESS_1, ErrorCode::SUCCESS); - mock_le_manager.on_le_disconnect(ADDRESS_1); - - // assert: no connection is pending - assert_eq!(mock_le_manager.current_connection_mode(), None); - }); - } - - #[test] - fn test_resolved_background_connection_after_disconnect() { - block_on_locally(async { - // arrange - let mock_le_manager = MockLeAclManager::new(); - let connection_manager = ConnectionManager::new(mock_le_manager.clone()); - - // act: initiate a background connection, that succeeds, then disconnects - connection_manager.as_ref().add_background_connection(CLIENT_1, ADDRESS_1).unwrap(); - mock_le_manager.on_le_connect(ADDRESS_1, ErrorCode::SUCCESS); - mock_le_manager.on_le_disconnect(ADDRESS_1); - - // assert: the background connection has resumed - assert_eq!(mock_le_manager.current_connection_mode(), Some(ConnectionMode::Background)); - }); - } - - #[test] - fn test_direct_connection_timeout() { - block_on_locally(async { - // arrange: a pending direct connection - let mock_le_manager = MockLeAclManager::new(); - let connection_manager = ConnectionManager::new(mock_le_manager.clone()); - connection_manager.as_ref().start_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - - // act: let it timeout - tokio::time::sleep(DIRECT_CONNECTION_TIMEOUT).await; - // go forward one tick to ensure all timers are fired - // (since we are using fake time, this is not a race condition) - tokio::time::sleep(Duration::from_millis(1)).await; - - // assert: it is cancelled and we are idle again - assert_eq!(mock_le_manager.current_connection_mode(), None); - }); - } - - #[test] - fn test_stacked_direct_connections_timeout() { - block_on_locally(async { - // arrange - let mock_le_manager = MockLeAclManager::new(); - let connection_manager = ConnectionManager::new(mock_le_manager.clone()); - - // act: start a direct connection - connection_manager.as_ref().start_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - tokio::time::sleep(DIRECT_CONNECTION_TIMEOUT * 3 / 4).await; - // act: after some time, start a second one - connection_manager.as_ref().start_direct_connection(CLIENT_2, ADDRESS_1).unwrap(); - // act: wait for the first one (but not the second) to time out - tokio::time::sleep(DIRECT_CONNECTION_TIMEOUT * 3 / 4).await; - - // assert: we are still doing a direct connection - assert_eq!(mock_le_manager.current_connection_mode(), Some(ConnectionMode::Direct)); - }); - } -} diff --git a/system/rust/src/connection/acceptlist_manager.rs b/system/rust/src/connection/acceptlist_manager.rs deleted file mode 100644 index 4810640f3a..0000000000 --- a/system/rust/src/connection/acceptlist_manager.rs +++ /dev/null @@ -1,366 +0,0 @@ -//! This module takes the set of attempts from the AttemptManager, determines -//! the target state of the LE manager, and drives it to this target state - -use std::collections::HashSet; - -use log::info; - -use crate::core::address::AddressWithType; - -use super::{ - attempt_manager::{ConnectionAttempt, ConnectionMode}, - le_manager::LeAclManager, -}; - -/// This struct represents the target state of the LeManager based on the -/// set of all active connection attempts -pub struct TargetState { - /// These addresses should go to the LE background connect list - pub background_list: HashSet<AddressWithType>, - /// These addresses should go to the direct list (we are not connected to any of them) - pub direct_list: HashSet<AddressWithType>, -} - -/// Takes a list of connection attempts, and determines the target state of the LE ACL manager -pub fn determine_target_state(attempts: &[ConnectionAttempt]) -> TargetState { - let background_list = attempts - .iter() - .filter(|attempt| attempt.mode == ConnectionMode::Background) - .map(|attempt| attempt.remote_address) - .collect(); - - let direct_list = attempts - .iter() - .filter(|attempt| attempt.mode == ConnectionMode::Direct) - .map(|attempt| attempt.remote_address) - .collect(); - - TargetState { background_list, direct_list } -} - -/// This struct monitors the state of the LE connect list, -/// and drives it to the target state. -#[derive(Debug)] -pub struct LeAcceptlistManager { - /// The connect list in the ACL manager - direct_list: HashSet<AddressWithType>, - /// The background connect list in the ACL manager - background_list: HashSet<AddressWithType>, - /// An interface into the LE ACL manager (le_impl.h) - le_manager: Box<dyn LeAclManager>, -} - -impl LeAcceptlistManager { - /// Constructor - pub fn new(le_manager: impl LeAclManager + 'static) -> Self { - Self { - direct_list: HashSet::new(), - background_list: HashSet::new(), - le_manager: Box::new(le_manager), - } - } - - /// The state of the LE connect list (as per le_impl.h) updates on a completed connection - pub fn on_connect_complete(&mut self, address: AddressWithType) { - if address == AddressWithType::EMPTY { - return; - } - // le_impl pulls the device out of the direct connect list (but not the background list) on connection (regardless of status) - self.direct_list.remove(&address); - } - - /// Drive the state of the connect list to the target state - pub fn drive_to_state(&mut self, target: TargetState) { - // First, pull out anything in the ACL manager that we don't need - // recall that cancel_connect() removes addresses from *both* lists (!) - for address in self.direct_list.difference(&target.direct_list) { - info!("Cancelling connection attempt to {address:?}"); - self.le_manager.remove_from_all_lists(*address); - self.background_list.remove(address); - } - self.direct_list = self.direct_list.intersection(&target.direct_list).copied().collect(); - - for address in self.background_list.difference(&target.background_list) { - info!("Cancelling connection attempt to {address:?}"); - self.le_manager.remove_from_all_lists(*address); - self.direct_list.remove(address); - } - self.background_list = - self.background_list.intersection(&target.background_list).copied().collect(); - - // now everything extra has been removed, we can put things back in - for address in target.direct_list.difference(&self.direct_list) { - info!("Starting direct connection to {address:?}"); - self.le_manager.add_to_direct_list(*address); - } - for address in target.background_list.difference(&self.background_list) { - info!("Starting background connection to {address:?}"); - self.le_manager.add_to_background_list(*address); - } - - // we should now be in a consistent state! - self.direct_list = target.direct_list; - self.background_list = target.background_list; - } -} - -#[cfg(test)] -mod test { - use crate::{ - connection::{ - le_manager::ErrorCode, mocks::mock_le_manager::MockActiveLeAclManager, - ConnectionManagerClient, - }, - core::address::AddressType, - }; - - use super::*; - - const CLIENT: ConnectionManagerClient = ConnectionManagerClient::GattClient(1); - - const ADDRESS_1: AddressWithType = - AddressWithType { address: [1, 2, 3, 4, 5, 6], address_type: AddressType::Public }; - const ADDRESS_2: AddressWithType = - AddressWithType { address: [1, 2, 3, 4, 5, 6], address_type: AddressType::Random }; - const ADDRESS_3: AddressWithType = - AddressWithType { address: [1, 2, 3, 4, 5, 7], address_type: AddressType::Random }; - - #[test] - fn test_determine_target_state() { - let target = determine_target_state(&[ - ConnectionAttempt { - client: CLIENT, - mode: ConnectionMode::Background, - remote_address: ADDRESS_1, - }, - ConnectionAttempt { - client: CLIENT, - mode: ConnectionMode::Background, - remote_address: ADDRESS_1, - }, - ConnectionAttempt { - client: CLIENT, - mode: ConnectionMode::Background, - remote_address: ADDRESS_2, - }, - ConnectionAttempt { - client: CLIENT, - mode: ConnectionMode::Direct, - remote_address: ADDRESS_2, - }, - ConnectionAttempt { - client: CLIENT, - mode: ConnectionMode::Direct, - remote_address: ADDRESS_3, - }, - ]); - - assert_eq!(target.background_list.len(), 2); - assert!(target.background_list.contains(&ADDRESS_1)); - assert!(target.background_list.contains(&ADDRESS_2)); - assert_eq!(target.direct_list.len(), 2); - assert!(target.direct_list.contains(&ADDRESS_2)); - assert!(target.direct_list.contains(&ADDRESS_3)); - } - - #[test] - fn test_add_to_direct_list() { - // arrange - let mock_le_manager = MockActiveLeAclManager::new(); - let mut manager = LeAcceptlistManager::new(mock_le_manager.clone()); - - // act: request a device to be present in the direct list - manager.drive_to_state(TargetState { - background_list: [].into(), - direct_list: [ADDRESS_1].into(), - }); - - // assert: that the device has been added - assert_eq!(mock_le_manager.current_connection_mode(), Some(ConnectionMode::Direct)); - assert_eq!(mock_le_manager.current_acceptlist().len(), 1); - assert!(mock_le_manager.current_acceptlist().contains(&ADDRESS_1)); - } - - #[test] - fn test_add_to_background_list() { - // arrange - let mock_le_manager = MockActiveLeAclManager::new(); - let mut manager = LeAcceptlistManager::new(mock_le_manager.clone()); - - // act: request a device to be present in the direct list - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [].into(), - }); - - // assert: that the device has been added - assert_eq!(mock_le_manager.current_connection_mode(), Some(ConnectionMode::Background)); - assert_eq!(mock_le_manager.current_acceptlist().len(), 1); - assert!(mock_le_manager.current_acceptlist().contains(&ADDRESS_1)); - } - - #[test] - fn test_background_connection_upgrade_to_direct() { - // arrange: a pending background connection - let mock_le_manager = MockActiveLeAclManager::new(); - let mut manager = LeAcceptlistManager::new(mock_le_manager.clone()); - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [].into(), - }); - - // act: initiate a direct connection to the same device - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [ADDRESS_1].into(), - }); - - // assert: we are now doing a direct connection - assert_eq!(mock_le_manager.current_connection_mode(), Some(ConnectionMode::Direct)); - } - - #[test] - fn test_direct_connection_cancel_while_background() { - // arrange: a pending background connection - let mock_le_manager = MockActiveLeAclManager::new(); - let mut manager = LeAcceptlistManager::new(mock_le_manager.clone()); - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [].into(), - }); - - // act: initiate a direct connection to the same device, then remove it - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [ADDRESS_1].into(), - }); - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [].into(), - }); - - // assert: we have returned to a background connection - assert_eq!(mock_le_manager.current_connection_mode(), Some(ConnectionMode::Background)); - } - - #[test] - fn test_direct_connection_cancel_then_resume_while_background() { - // arrange: a pending background connection - let mock_le_manager = MockActiveLeAclManager::new(); - let mut manager = LeAcceptlistManager::new(mock_le_manager.clone()); - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [].into(), - }); - - // act: initiate a direct connection to the same device, cancel it, then resume - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [ADDRESS_1].into(), - }); - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [].into(), - }); - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [ADDRESS_1].into(), - }); - - // assert: we have returned to a direct connection - assert_eq!(mock_le_manager.current_connection_mode(), Some(ConnectionMode::Direct)); - } - - #[test] - fn test_remove_background_connection_then_add() { - // arrange - let mock_le_manager = MockActiveLeAclManager::new(); - let mut manager = LeAcceptlistManager::new(mock_le_manager.clone()); - - // act: add then remove a background connection - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [].into(), - }); - manager.drive_to_state(TargetState { background_list: [].into(), direct_list: [].into() }); - - // assert: we have stopped our connection - assert_eq!(mock_le_manager.current_connection_mode(), None); - } - - #[test] - fn test_background_connection_remove_then_add() { - // arrange - let mock_le_manager = MockActiveLeAclManager::new(); - let mut manager = LeAcceptlistManager::new(mock_le_manager.clone()); - - // act: add, remove, then re-add a background connection - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [].into(), - }); - manager.drive_to_state(TargetState { background_list: [].into(), direct_list: [].into() }); - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [].into(), - }); - - // assert: we resume our background connection - assert_eq!(mock_le_manager.current_connection_mode(), Some(ConnectionMode::Background)); - } - #[test] - fn test_retry_direct_connection_after_disconnect() { - // arrange - let mock_le_manager = MockActiveLeAclManager::new(); - let mut manager = LeAcceptlistManager::new(mock_le_manager.clone()); - - // act: initiate a direct connection - manager.drive_to_state(TargetState { - background_list: [].into(), - direct_list: [ADDRESS_1].into(), - }); - // act: the connection succeeds (and later disconnects) - mock_le_manager.on_le_connect(ADDRESS_1, ErrorCode::SUCCESS); - manager.on_connect_complete(ADDRESS_1); - // the peer later disconnects - mock_le_manager.on_le_disconnect(ADDRESS_1); - // act: retry the direct connection - manager.drive_to_state(TargetState { - background_list: [].into(), - direct_list: [ADDRESS_1].into(), - }); - - // assert: we have resumed the direct connection - assert_eq!(mock_le_manager.current_connection_mode(), Some(ConnectionMode::Direct)); - assert_eq!(mock_le_manager.current_acceptlist().len(), 1); - assert!(mock_le_manager.current_acceptlist().contains(&ADDRESS_1)); - } - - #[test] - fn test_background_connection_remove_then_add_while_direct() { - // arrange: a pending direct connection - let mock_le_manager = MockActiveLeAclManager::new(); - let mut manager = LeAcceptlistManager::new(mock_le_manager.clone()); - manager.drive_to_state(TargetState { - background_list: [].into(), - direct_list: [ADDRESS_1].into(), - }); - - // act: add, remove, then re-add a background connection - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [ADDRESS_1].into(), - }); - manager.drive_to_state(TargetState { - background_list: [].into(), - direct_list: [ADDRESS_1].into(), - }); - manager.drive_to_state(TargetState { - background_list: [ADDRESS_1].into(), - direct_list: [ADDRESS_1].into(), - }); - - // assert: we remain doing our direct connection - assert_eq!(mock_le_manager.current_connection_mode(), Some(ConnectionMode::Direct)); - } -} diff --git a/system/rust/src/connection/attempt_manager.rs b/system/rust/src/connection/attempt_manager.rs deleted file mode 100644 index 54a2e66240..0000000000 --- a/system/rust/src/connection/attempt_manager.rs +++ /dev/null @@ -1,501 +0,0 @@ -use std::{ - collections::{hash_map::Entry, HashMap}, - future::{Future, IntoFuture}, -}; - -use tokio::sync::oneshot; - -use crate::core::address::AddressWithType; - -use super::{ - le_manager::ErrorCode, CancelConnectFailure, ConnectionFailure, ConnectionManagerClient, - CreateConnectionFailure, LeConnection, -}; - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub enum ConnectionMode { - Background, - Direct, -} - -#[derive(Debug)] -struct ConnectionAttemptData { - id: AttemptId, - conn_tx: Option<oneshot::Sender<Result<LeConnection, ErrorCode>>>, -} - -#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] -pub struct ConnectionAttempt { - pub client: ConnectionManagerClient, - pub mode: ConnectionMode, - pub remote_address: AddressWithType, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct AttemptId(u64); - -#[derive(Debug)] -pub struct ConnectionAttempts { - attempt_id: AttemptId, - attempts: HashMap<ConnectionAttempt, ConnectionAttemptData>, -} - -#[derive(Debug)] -pub struct PendingConnectionAttempt<F> { - pub id: AttemptId, - f: F, -} - -impl<F> IntoFuture for PendingConnectionAttempt<F> -where - F: Future<Output = Result<LeConnection, ConnectionFailure>>, -{ - type Output = F::Output; - type IntoFuture = F; - - fn into_future(self) -> Self::IntoFuture { - self.f - } -} - -impl ConnectionAttempts { - /// Constructor - pub fn new() -> Self { - Self { attempt_id: AttemptId(0), attempts: HashMap::new() } - } - - fn new_attempt_id(&mut self) -> AttemptId { - let AttemptId(id) = self.attempt_id; - self.attempt_id = AttemptId(id.wrapping_add(1)); - AttemptId(id) - } - - /// Register a pending direct connection to the peer. Note that the peer MUST NOT be connected at this point. - /// Returns the AttemptId of this attempt, as well as a future resolving with the connection (once created) or an - /// error. - /// - /// Note that only one connection attempt from the same (client, address, mode) tuple can be pending at any time. - /// - /// # Cancellation Safety - /// If this future is cancelled, the attempt will NOT BE REMOVED! It must be cancelled explicitly. To avoid - /// cancelling the wrong future, the returned ID should be used. - pub fn register_direct_connection( - &mut self, - client: ConnectionManagerClient, - address: AddressWithType, - ) -> Result< - PendingConnectionAttempt<impl Future<Output = Result<LeConnection, ConnectionFailure>>>, - CreateConnectionFailure, - > { - let attempt = - ConnectionAttempt { client, mode: ConnectionMode::Direct, remote_address: address }; - - let id = self.new_attempt_id(); - let Entry::Vacant(entry) = self.attempts.entry(attempt) else { - return Err(CreateConnectionFailure::ConnectionAlreadyPending); - }; - let (tx, rx) = oneshot::channel(); - entry.insert(ConnectionAttemptData { conn_tx: Some(tx), id }); - - Ok(PendingConnectionAttempt { - id, - f: async move { - rx.await - .map_err(|_| ConnectionFailure::Cancelled)? - .map_err(ConnectionFailure::Error) - }, - }) - } - - /// Register a pending background connection to the peer. Returns the AttemptId of this attempt. - /// - /// Note that only one connection attempt from the same (client, address, mode) tuple can be pending at any time. - pub fn register_background_connection( - &mut self, - client: ConnectionManagerClient, - address: AddressWithType, - ) -> Result<AttemptId, CreateConnectionFailure> { - let attempt = - ConnectionAttempt { client, mode: ConnectionMode::Background, remote_address: address }; - - let id = self.new_attempt_id(); - let Entry::Vacant(entry) = self.attempts.entry(attempt) else { - return Err(CreateConnectionFailure::ConnectionAlreadyPending); - }; - entry.insert(ConnectionAttemptData { conn_tx: None, id }); - - Ok(id) - } - - /// Cancel connection attempts with the specified mode from this client to the specified address. - pub fn cancel_attempt( - &mut self, - client: ConnectionManagerClient, - address: AddressWithType, - mode: ConnectionMode, - ) -> Result<(), CancelConnectFailure> { - let existing = - self.attempts.remove(&ConnectionAttempt { client, mode, remote_address: address }); - - if existing.is_some() { - // note: dropping the ConnectionAttemptData is sufficient to close the channel and send a cancellation error - Ok(()) - } else { - Err(CancelConnectFailure::ConnectionNotPending) - } - } - - /// Cancel the connection attempt with the given ID. - pub fn cancel_attempt_with_id(&mut self, id: AttemptId) { - self.attempts.retain(|_, attempt| attempt.id != id); - } - - /// Cancel all connection attempts to this address - pub fn remove_unconditionally(&mut self, address: AddressWithType) { - self.attempts.retain(|attempt, _| attempt.remote_address != address); - } - - /// Cancel all connection attempts from this client - pub fn remove_client(&mut self, client: ConnectionManagerClient) { - self.attempts.retain(|attempt, _| attempt.client != client); - } - - /// List all active connection attempts. Note that we can have active background (but NOT) direct - /// connection attempts to connected devices, as we will resume the connection attempt when the - /// peer disconnects from us. - pub fn active_attempts(&self) -> Vec<ConnectionAttempt> { - self.attempts.keys().cloned().collect() - } - - /// Handle a successful connection by notifying clients and resolving direct connect attempts - pub fn process_connection( - &mut self, - address: AddressWithType, - result: Result<LeConnection, ErrorCode>, - ) { - let interested_clients = self - .attempts - .keys() - .filter(|attempt| attempt.remote_address == address) - .copied() - .collect::<Vec<_>>(); - - for attempt in interested_clients { - if attempt.mode == ConnectionMode::Direct { - // TODO(aryarahul): clean up these unwraps - let _ = self.attempts.remove(&attempt).unwrap().conn_tx.unwrap().send(result); - } else { - // TODO(aryarahul): inform background clients of the connection - } - } - } -} - -#[cfg(test)] -mod test { - use crate::{ - core::address::AddressType, - utils::task::{block_on_locally, try_await}, - }; - - use super::*; - - const CLIENT_1: ConnectionManagerClient = ConnectionManagerClient::GattClient(1); - const CLIENT_2: ConnectionManagerClient = ConnectionManagerClient::GattClient(2); - - const ADDRESS_1: AddressWithType = - AddressWithType { address: [1, 2, 3, 4, 5, 6], address_type: AddressType::Public }; - const ADDRESS_2: AddressWithType = - AddressWithType { address: [1, 2, 3, 4, 5, 6], address_type: AddressType::Random }; - - const CONNECTION_1: LeConnection = LeConnection { remote_address: ADDRESS_1 }; - const CONNECTION_2: LeConnection = LeConnection { remote_address: ADDRESS_2 }; - - #[test] - fn test_direct_connection() { - block_on_locally(async { - // arrange - let mut attempts = ConnectionAttempts::new(); - - // act: start a pending direct connection - let _ = attempts.register_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - - // assert: this attempt is pending - assert_eq!(attempts.active_attempts().len(), 1); - assert_eq!(attempts.active_attempts()[0].client, CLIENT_1); - assert_eq!(attempts.active_attempts()[0].mode, ConnectionMode::Direct); - assert_eq!(attempts.active_attempts()[0].remote_address, ADDRESS_1); - }); - } - - #[test] - fn test_cancel_direct_connection() { - block_on_locally(async { - // arrange: one pending direct connection - let mut attempts = ConnectionAttempts::new(); - let pending_direct_connection = - attempts.register_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - - // act: cancel it - attempts.cancel_attempt(CLIENT_1, ADDRESS_1, ConnectionMode::Direct).unwrap(); - let resp = pending_direct_connection.await; - - // assert: the original future resolved, and the attempt is cleared - assert_eq!(resp, Err(ConnectionFailure::Cancelled)); - assert!(attempts.active_attempts().is_empty()); - }); - } - - #[test] - fn test_multiple_direct_connections() { - block_on_locally(async { - // arrange - let mut attempts = ConnectionAttempts::new(); - - // act: start two direct connections - attempts.register_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - attempts.register_direct_connection(CLIENT_2, ADDRESS_1).unwrap(); - - // assert: both attempts are pending - assert_eq!(attempts.active_attempts().len(), 2); - }); - } - - #[test] - fn test_two_direct_connection_cancel_one() { - block_on_locally(async { - // arrange: two pending direct connections - let mut attempts = ConnectionAttempts::new(); - attempts.register_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - attempts.register_direct_connection(CLIENT_2, ADDRESS_1).unwrap(); - - // act: cancel one - attempts.cancel_attempt(CLIENT_1, ADDRESS_1, ConnectionMode::Direct).unwrap(); - - // assert: one attempt is still pending - assert_eq!(attempts.active_attempts().len(), 1); - assert_eq!(attempts.active_attempts()[0].client, CLIENT_2); - }); - } - - #[test] - fn test_drop_pending_connection_after_cancel_and_restart() { - // arrange - let mut attempts = ConnectionAttempts::new(); - - // act: start one pending direct connection, cancel it, restart it, and then drop the first future - let pending_1 = attempts.register_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - attempts.cancel_attempt(CLIENT_1, ADDRESS_1, ConnectionMode::Direct).unwrap(); - let _pending_2 = attempts.register_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - drop(pending_1); - - // assert: the restart is still pending - assert_eq!(attempts.active_attempts().len(), 1); - } - - #[test] - fn test_background_connection() { - block_on_locally(async { - // arrange - let mut attempts = ConnectionAttempts::new(); - - // act: start a pending background connection - attempts.register_background_connection(CLIENT_1, ADDRESS_1).unwrap(); - - // assert: this attempt is pending - assert_eq!(attempts.active_attempts().len(), 1); - assert_eq!(attempts.active_attempts()[0].client, CLIENT_1); - assert_eq!(attempts.active_attempts()[0].mode, ConnectionMode::Background); - assert_eq!(attempts.active_attempts()[0].remote_address, ADDRESS_1); - }); - } - - #[test] - fn test_reject_duplicate_direct_connection() { - block_on_locally(async { - // arrange - let mut attempts = ConnectionAttempts::new(); - - // act: start two background connections with the same parameters - let _fut = attempts.register_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - let ret = attempts.register_direct_connection(CLIENT_1, ADDRESS_1); - - // assert: this attempt is pending - assert!(matches!(ret, Err(CreateConnectionFailure::ConnectionAlreadyPending))); - }); - } - - #[test] - fn test_reject_duplicate_background_connection() { - block_on_locally(async { - // arrange - let mut attempts = ConnectionAttempts::new(); - - // act: start two background connections with the same parameters - attempts.register_background_connection(CLIENT_1, ADDRESS_1).unwrap(); - let ret = attempts.register_background_connection(CLIENT_1, ADDRESS_1); - - // assert: this attempt is pending - assert_eq!(ret, Err(CreateConnectionFailure::ConnectionAlreadyPending)); - }); - } - - #[test] - fn test_resolved_direct_connection() { - block_on_locally(async { - // arrange: one pending direct connection - let mut attempts = ConnectionAttempts::new(); - let pending_conn = attempts.register_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - - // act: resolve with an incoming connection - attempts.process_connection(ADDRESS_1, Ok(CONNECTION_1)); - - // assert: the attempt is resolved and is no longer active - assert_eq!(pending_conn.await.unwrap(), CONNECTION_1); - assert!(attempts.active_attempts().is_empty()); - }); - } - - #[test] - fn test_failed_direct_connection() { - block_on_locally(async { - // arrange: one pending direct connection - let mut attempts = ConnectionAttempts::new(); - let pending_conn = attempts.register_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - - // act: resolve with an incoming connection - attempts.process_connection(ADDRESS_1, Err(ErrorCode(1))); - - // assert: the attempt is resolved and is no longer active - assert_eq!(pending_conn.await, Err(ConnectionFailure::Error(ErrorCode(1)))); - assert!(attempts.active_attempts().is_empty()); - }); - } - - #[test] - fn test_resolved_background_connection() { - block_on_locally(async { - // arrange: one pending direct connection - let mut attempts = ConnectionAttempts::new(); - attempts.register_background_connection(CLIENT_1, ADDRESS_1).unwrap(); - - // act: resolve with an incoming connection - attempts.process_connection(ADDRESS_1, Ok(CONNECTION_1)); - - // assert: the attempt is still active - assert_eq!(attempts.active_attempts().len(), 1); - }); - } - - #[test] - fn test_incoming_connection_while_another_is_pending() { - block_on_locally(async { - // arrange: one pending direct connection - let mut attempts = ConnectionAttempts::new(); - let pending_conn = attempts.register_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - - // act: an incoming connection arrives to a different address - attempts.process_connection(ADDRESS_2, Ok(CONNECTION_2)); - - // assert: the attempt is still pending - assert!(try_await(pending_conn).await.is_err()); - assert_eq!(attempts.active_attempts().len(), 1); - }); - } - - #[test] - fn test_incoming_connection_resolves_some_but_not_all() { - block_on_locally(async { - // arrange: one pending direct connection and one background connection to each of two addresses - let mut attempts = ConnectionAttempts::new(); - let pending_conn_1 = attempts.register_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - let pending_conn_2 = attempts.register_direct_connection(CLIENT_1, ADDRESS_2).unwrap(); - attempts.register_background_connection(CLIENT_1, ADDRESS_1).unwrap(); - attempts.register_background_connection(CLIENT_1, ADDRESS_2).unwrap(); - - // act: an incoming connection arrives to the first address - attempts.process_connection(ADDRESS_1, Ok(CONNECTION_1)); - - // assert: one direct attempt is completed, one is still pending - assert_eq!(pending_conn_1.await, Ok(CONNECTION_1)); - assert!(try_await(pending_conn_2).await.is_err()); - // three attempts remain (the unresolved direct, and both background attempts) - assert_eq!(attempts.active_attempts().len(), 3); - }); - } - - #[test] - fn test_remove_background_connection() { - block_on_locally(async { - // arrange: one pending background connection - let mut attempts = ConnectionAttempts::new(); - attempts.register_background_connection(CLIENT_1, ADDRESS_1).unwrap(); - - // act: remove it - attempts.cancel_attempt(CLIENT_1, ADDRESS_1, ConnectionMode::Background).unwrap(); - - // assert: no pending attempts - assert!(attempts.active_attempts().is_empty()); - }); - } - - #[test] - fn test_cancel_nonexistent_connection() { - block_on_locally(async { - // arrange - let mut attempts = ConnectionAttempts::new(); - - // act: cancel a nonexistent direct connection - let resp = attempts.cancel_attempt(CLIENT_1, ADDRESS_1, ConnectionMode::Direct); - - // assert: got an error - assert_eq!(resp, Err(CancelConnectFailure::ConnectionNotPending)); - }); - } - - #[test] - fn test_remove_unconditionally() { - block_on_locally(async { - // arrange: one pending direct connection, and one background connection, to each address - let mut attempts = ConnectionAttempts::new(); - let pending_conn_1 = attempts.register_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - let pending_conn_2 = attempts.register_direct_connection(CLIENT_1, ADDRESS_2).unwrap(); - attempts.register_background_connection(CLIENT_1, ADDRESS_1).unwrap(); - attempts.register_background_connection(CLIENT_1, ADDRESS_2).unwrap(); - - // act: cancel all connections to the first address - attempts.remove_unconditionally(ADDRESS_1); - - // assert: one direct attempt is completed, one is still pending - assert_eq!(pending_conn_1.await, Err(ConnectionFailure::Cancelled)); - assert!(try_await(pending_conn_2).await.is_err()); - // assert: two attempts remain, both to the other address - assert_eq!(attempts.active_attempts().len(), 2); - assert_eq!(attempts.active_attempts()[0].remote_address, ADDRESS_2); - assert_eq!(attempts.active_attempts()[1].remote_address, ADDRESS_2); - }); - } - - #[test] - fn test_remove_client() { - block_on_locally(async { - // arrange: one pending direct connection, and one background connection, from each address - let mut attempts = ConnectionAttempts::new(); - let pending_conn_1 = attempts.register_direct_connection(CLIENT_1, ADDRESS_1).unwrap(); - let pending_conn_2 = attempts.register_direct_connection(CLIENT_2, ADDRESS_1).unwrap(); - attempts.register_background_connection(CLIENT_1, ADDRESS_1).unwrap(); - attempts.register_background_connection(CLIENT_2, ADDRESS_1).unwrap(); - - // act: remove the first client - attempts.remove_client(CLIENT_1); - - // assert: one direct attempt is completed, one is still pending - assert_eq!(pending_conn_1.await, Err(ConnectionFailure::Cancelled)); - assert!(try_await(pending_conn_2).await.is_err()); - // assert: two attempts remain, both from the second client - assert_eq!(attempts.active_attempts().len(), 2); - assert_eq!(attempts.active_attempts()[0].client, CLIENT_2); - assert_eq!(attempts.active_attempts()[1].client, CLIENT_2); - }); - } -} diff --git a/system/rust/src/connection/ffi.rs b/system/rust/src/connection/ffi.rs deleted file mode 100644 index 82a98582de..0000000000 --- a/system/rust/src/connection/ffi.rs +++ /dev/null @@ -1,242 +0,0 @@ -//! FFI interfaces for the Connection module. - -use std::{fmt::Debug, pin::Pin}; - -use cxx::UniquePtr; -pub use inner::*; -use log::warn; -use tokio::{ - sync::mpsc::{unbounded_channel, UnboundedSender}, - task::spawn_local, -}; - -use crate::do_in_rust_thread; - -use super::{ - attempt_manager::ConnectionMode, - le_manager::{ErrorCode, InactiveLeAclManager, LeAclManager, LeAclManagerConnectionCallbacks}, - ConnectionManagerClient, LeConnection, -}; - -// SAFETY: `LeAclManagerShim` can be passed between threads. -unsafe impl Send for LeAclManagerShim {} - -#[cxx::bridge] -#[allow(clippy::needless_lifetimes)] -#[allow(clippy::needless_maybe_sized)] -#[allow(clippy::too_many_arguments)] -#[allow(missing_docs)] -#[allow(unsafe_op_in_unsafe_fn)] -mod inner { - impl UniquePtr<LeAclManagerShim> {} - - #[namespace = "bluetooth::core"] - extern "C++" { - type AddressWithType = crate::core::address::AddressWithType; - } - - #[namespace = "bluetooth::connection"] - unsafe extern "C++" { - include!("src/connection/ffi/connection_shim.h"); - - /// This lets us send HCI commands, either directly, - /// or via the address manager - type LeAclManagerShim; - - /// Add address to direct/background connect list, if not already connected - /// If connected, then adding to direct list is a no-op, but adding to the - /// background list will still take place. - #[cxx_name = "CreateLeConnection"] - fn create_le_connection(&self, address: AddressWithType, is_direct: bool); - - /// Remove address from both direct + background connect lists - #[cxx_name = "CancelLeConnect"] - fn cancel_le_connect(&self, address: AddressWithType); - - /// Register Rust callbacks for connection events - /// - /// # Safety - /// - /// `callbacks` must be Send + Sync, since C++ moves it to a different thread and - /// invokes it from several others (GD + legacy threads). - #[allow(clippy::missing_safety_doc)] - #[cxx_name = "RegisterRustCallbacks"] - unsafe fn unchecked_register_rust_callbacks( - self: Pin<&mut Self>, - callbacks: Box<LeAclManagerCallbackShim>, - ); - } - - #[namespace = "bluetooth::connection"] - extern "Rust" { - type LeAclManagerCallbackShim; - #[cxx_name = "OnLeConnectSuccess"] - fn on_le_connect_success(&self, address: AddressWithType); - #[cxx_name = "OnLeConnectFail"] - fn on_le_connect_fail(&self, address: AddressWithType, status: u8); - #[cxx_name = "OnLeDisconnection"] - fn on_disconnect(&self, address: AddressWithType); - } - - #[namespace = "bluetooth::connection"] - unsafe extern "C++" { - include!("stack/arbiter/acl_arbiter.h"); - - /// Register APIs exposed by Rust - fn RegisterRustApis( - start_direct_connection: fn(client_id: u8, address: AddressWithType), - stop_direct_connection: fn(client_id: u8, address: AddressWithType), - add_background_connection: fn(client_id: u8, address: AddressWithType), - remove_background_connection: fn(client_id: u8, address: AddressWithType), - remove_client: fn(client_id: u8), - stop_all_connections_to_device: fn(address: AddressWithType), - ); - } -} - -impl LeAclManagerShim { - fn register_rust_callbacks( - self: Pin<&mut LeAclManagerShim>, - callbacks: Box<LeAclManagerCallbackShim>, - ) where - Box<LeAclManagerCallbackShim>: Send + Sync, - { - // SAFETY: The requirements of this method are enforced - // by our own trait bounds. - unsafe { - self.unchecked_register_rust_callbacks(callbacks); - } - } -} - -/// Implementation of HciConnectProxy wrapping the corresponding C++ methods -pub struct LeAclManagerImpl(pub UniquePtr<LeAclManagerShim>); - -pub struct LeAclManagerCallbackShim( - UnboundedSender<Box<dyn FnOnce(&dyn LeAclManagerConnectionCallbacks) + Send>>, -); - -impl LeAclManagerCallbackShim { - fn on_le_connect_success(&self, address: AddressWithType) { - let _ = self.0.send(Box::new(move |callback| { - callback.on_le_connect(address, Ok(LeConnection { remote_address: address })) - })); - } - - fn on_le_connect_fail(&self, address: AddressWithType, status: u8) { - let _ = self.0.send(Box::new(move |callback| { - callback.on_le_connect(address, Err(ErrorCode(status))) - })); - } - - fn on_disconnect(&self, address: AddressWithType) { - let _ = self.0.send(Box::new(move |callback| { - callback.on_disconnect(address); - })); - } -} - -impl InactiveLeAclManager for LeAclManagerImpl { - type ActiveManager = Self; - - fn register_callbacks( - mut self, - callbacks: impl LeAclManagerConnectionCallbacks + 'static, - ) -> Self::ActiveManager { - let (tx, mut rx) = unbounded_channel(); - - // only register callbacks if the feature is enabled - if bluetooth_aconfig_flags_rust::unified_connection_manager() { - self.0.pin_mut().register_rust_callbacks(Box::new(LeAclManagerCallbackShim(tx))); - } - - spawn_local(async move { - while let Some(f) = rx.recv().await { - f(&callbacks) - } - }); - self - } -} - -impl LeAclManager for LeAclManagerImpl { - fn add_to_direct_list(&self, address: AddressWithType) { - self.0.create_le_connection(address, /* is_direct= */ true) - } - - fn add_to_background_list(&self, address: AddressWithType) { - self.0.create_le_connection(address, /* is_direct= */ false) - } - - fn remove_from_all_lists(&self, address: AddressWithType) { - self.0.cancel_le_connect(address) - } -} - -impl Debug for LeAclManagerImpl { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("LeAclManagerImpl").finish() - } -} - -/// Registers all connection-manager callbacks into C++ dependencies -pub fn register_callbacks() { - RegisterRustApis( - |client, address| { - let client = ConnectionManagerClient::GattClient(client); - do_in_rust_thread(move |modules| { - let result = - modules.connection_manager.as_ref().start_direct_connection(client, address); - if let Err(err) = result { - warn!("Failed to start direct connection from {client:?} to {address:?} ({err:?})") - } - }); - }, - |client, address| { - let client = ConnectionManagerClient::GattClient(client); - do_in_rust_thread(move |modules| { - let result = modules.connection_manager.cancel_connection( - client, - address, - ConnectionMode::Direct, - ); - if let Err(err) = result { - warn!("Failed to cancel direct connection from {client:?} to {address:?} ({err:?})") - } - }) - }, - |client, address| { - let client = ConnectionManagerClient::GattClient(client); - do_in_rust_thread(move |modules| { - let result = modules.connection_manager.add_background_connection(client, address); - if let Err(err) = result { - warn!("Failed to add background connection from {client:?} to {address:?} ({err:?})") - } - }) - }, - |client, address| { - let client = ConnectionManagerClient::GattClient(client); - do_in_rust_thread(move |modules| { - let result = modules.connection_manager.cancel_connection( - client, - address, - ConnectionMode::Background, - ); - if let Err(err) = result { - warn!("Failed to remove background connection from {client:?} to {address:?} ({err:?})") - } - }) - }, - |client| { - let client = ConnectionManagerClient::GattClient(client); - do_in_rust_thread(move |modules| { - modules.connection_manager.remove_client(client); - }) - }, - |address| { - do_in_rust_thread(move |modules| { - modules.connection_manager.cancel_unconditionally(address); - }) - }, - ) -} diff --git a/system/rust/src/connection/ffi/connection_shim.cc b/system/rust/src/connection/ffi/connection_shim.cc deleted file mode 100644 index 1ff23b9629..0000000000 --- a/system/rust/src/connection/ffi/connection_shim.cc +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2023, The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "connection_shim.h" - -#include <bluetooth/log.h> - -#include <algorithm> -#include <cstdint> -#include <iterator> -#include <optional> - -#include "hci/acl_manager.h" -#include "hci/address_with_type.h" -#include "hci/hci_packets.h" -#include "main/shim/entry.h" -#ifndef TARGET_FLOSS -#include "src/connection/ffi.rs.h" -#endif -#include "src/core/ffi/types.h" -#include "stack/btm/btm_dev.h" - -namespace bluetooth { -namespace connection { - -#ifdef TARGET_FLOSS -struct LeAclManagerCallbackShim { - void OnLeConnectSuccess(core::AddressWithType addr) const { - log::fatal("system/rust not available in Floss"); - } - void OnLeConnectFail(core::AddressWithType addr, uint8_t status) const { - log::fatal("system/rust not available in Floss"); - } - void OnLeDisconnection(core::AddressWithType addr) const { - log::fatal("system/rust not available in Floss"); - } -}; - -using BoxedLeAclManagerCallbackShim = std::unique_ptr<LeAclManagerCallbackShim>; - -#else - -using BoxedLeAclManagerCallbackShim = ::rust::Box<LeAclManagerCallbackShim>; - -#endif - -namespace { -hci::AddressWithType ToCppAddress(core::AddressWithType address) { - auto hci_address = hci::Address(); - hci_address.FromOctets(address.address.data()); - return hci::AddressWithType(hci_address, (hci::AddressType)address.address_type); -} - -core::AddressWithType ToRustAddress(hci::AddressWithType address) { - return core::AddressWithType{address.GetAddress().address, - (core::AddressType)address.GetAddressType()}; -} -} // namespace - -struct LeAclManagerShim::impl : hci::acl_manager::LeAcceptlistCallbacks { -public: - impl() { acl_manager_ = shim::GetAclManager(); } - - ~impl() { - if (callbacks_.has_value()) { - callbacks_.reset(); - auto promise = std::promise<void>(); - auto future = promise.get_future(); - acl_manager_->UnregisterLeAcceptlistCallbacks(this, std::move(promise)); - future.wait(); - } - } - - void CreateLeConnection(core::AddressWithType address, bool is_direct) { - acl_manager_->CreateLeConnection(ToCppAddress(address), is_direct); - } - - void CancelLeConnect(core::AddressWithType address) { - acl_manager_->CancelLeConnect(ToCppAddress(address)); - } - -#ifndef TARGET_FLOSS - void RegisterRustCallbacks(BoxedLeAclManagerCallbackShim callbacks) { - callbacks_ = std::move(callbacks); - acl_manager_->RegisterLeAcceptlistCallbacks(this); - } -#endif - - // hci::acl_manager::LeAcceptlistCallbacks - virtual void OnLeConnectSuccess(hci::AddressWithType address) { - callbacks_.value()->OnLeConnectSuccess(ToRustAddress(address)); - } - - // hci::acl_manager::LeAcceptlistCallbacks - virtual void OnLeConnectFail(hci::AddressWithType address, hci::ErrorCode reason) { - callbacks_.value()->OnLeConnectFail(ToRustAddress(address), static_cast<uint8_t>(reason)); - } - - // hci::acl_manager::LeAcceptlistCallbacks - virtual void OnLeDisconnection(hci::AddressWithType address) { - callbacks_.value()->OnLeDisconnection(ToRustAddress(address)); - } - - // hci::acl_manager::LeAcceptlistCallbacks - virtual void OnResolvingListChange() {} - -private: - std::optional<BoxedLeAclManagerCallbackShim> callbacks_; - hci::AclManager* acl_manager_{}; -}; - -LeAclManagerShim::LeAclManagerShim() { pimpl_ = std::make_unique<LeAclManagerShim::impl>(); } - -LeAclManagerShim::~LeAclManagerShim() = default; - -void LeAclManagerShim::CreateLeConnection(core::AddressWithType address, bool is_direct) const { - pimpl_->CreateLeConnection(address, is_direct); -} - -void LeAclManagerShim::CancelLeConnect(core::AddressWithType address) const { - pimpl_->CancelLeConnect(address); -} - -#ifndef TARGET_FLOSS -void LeAclManagerShim::RegisterRustCallbacks(BoxedLeAclManagerCallbackShim callbacks) { - pimpl_->RegisterRustCallbacks(std::move(callbacks)); -} -#endif - -namespace { - -std::optional<RustConnectionManager> connection_manager; - -} // namespace - -RustConnectionManager& GetConnectionManager() { return connection_manager.value(); } - -void RegisterRustApis( - ::rust::Fn<void(uint8_t client_id, core::AddressWithType address)> start_direct_connection, - ::rust::Fn<void(uint8_t client_id, core::AddressWithType address)> stop_direct_connection, - ::rust::Fn<void(uint8_t client_id, core::AddressWithType address)> - add_background_connection, - ::rust::Fn<void(uint8_t client_id, core::AddressWithType address)> - remove_background_connection, - ::rust::Fn<void(uint8_t client_id)> remove_client, - ::rust::Fn<void(core::AddressWithType address)> stop_all_connections_to_device) { - connection_manager = { - start_direct_connection, stop_direct_connection, add_background_connection, - remove_background_connection, remove_client, stop_all_connections_to_device}; -} - -core::AddressWithType ResolveRawAddress(RawAddress bd_addr) { - tBLE_BD_ADDR address = BTM_Sec_GetAddressWithType(bd_addr); - return core::ToRustAddress(address); -} - -} // namespace connection -} // namespace bluetooth diff --git a/system/rust/src/connection/ffi/connection_shim.h b/system/rust/src/connection/ffi/connection_shim.h deleted file mode 100644 index 5346c07db9..0000000000 --- a/system/rust/src/connection/ffi/connection_shim.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2023, The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include <cstdint> -#include <memory> - -#include "rust/cxx.h" -#include "rust/src/core/ffi/types.h" -#include "types/ble_address_with_type.h" - -namespace bluetooth { - -namespace connection { - -struct LeAclManagerCallbackShim; - -class LeAclManagerShim { -public: - LeAclManagerShim(); - ~LeAclManagerShim(); - - void CreateLeConnection(core::AddressWithType address, bool is_direct) const; - - void CancelLeConnect(core::AddressWithType address) const; - -#ifndef TARGET_FLOSS - void RegisterRustCallbacks(::rust::Box<LeAclManagerCallbackShim> callbacks); -#endif - -private: - struct impl; - std::unique_ptr<impl> pimpl_; -}; - -void RegisterRustApis( - ::rust::Fn<void(uint8_t client_id, core::AddressWithType address)> start_direct_connection, - ::rust::Fn<void(uint8_t client_id, core::AddressWithType address)> stop_direct_connection, - ::rust::Fn<void(uint8_t client_id, core::AddressWithType address)> - add_background_connection, - ::rust::Fn<void(uint8_t client_id, core::AddressWithType address)> - remove_background_connection, - ::rust::Fn<void(uint8_t client_id)> remove_client, - ::rust::Fn<void(core::AddressWithType address)> stop_all_connections_to_device); - -struct RustConnectionManager { - ::rust::Fn<void(uint8_t client_id, core::AddressWithType address)> start_direct_connection; - ::rust::Fn<void(uint8_t client_id, core::AddressWithType address)> stop_direct_connection; - ::rust::Fn<void(uint8_t client_id, core::AddressWithType address)> add_background_connection; - ::rust::Fn<void(uint8_t client_id, core::AddressWithType address)> remove_background_connection; - ::rust::Fn<void(uint8_t client_id)> remove_client; - ::rust::Fn<void(core::AddressWithType address)> stop_all_connections_to_device; -}; - -RustConnectionManager& GetConnectionManager(); - -core::AddressWithType ResolveRawAddress(RawAddress bd_addr); - -} // namespace connection -} // namespace bluetooth diff --git a/system/rust/src/connection/le_manager.rs b/system/rust/src/connection/le_manager.rs deleted file mode 100644 index fa55118d08..0000000000 --- a/system/rust/src/connection/le_manager.rs +++ /dev/null @@ -1,63 +0,0 @@ -//! This trait represents the lower-level operations -//! made available to the connection manager. In particular, -//! we can add devices to either the "direct" or "background" -//! connect list, which are in turn mapped to an appropriate choice -//! of scan parameters / the filter accept list. -//! -//! Note that the ACL manager is unaware of address resolution, -//! so this must be handled by the connection manager. Conversely, the connection -//! manager does not need to consider the HCI state machine, and can send requests -//! at any time. -//! -//! In addition to the supplied API, when a connection completes to a peer device, -//! it is removed from the "direct" connect list (based on exact address match). - -use std::fmt::Debug; - -use crate::core::address::AddressWithType; - -use super::LeConnection; - -/// An HCI Error Code from the controller -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct ErrorCode(pub u8); - -impl ErrorCode { - /// Operation completed successfully - pub const SUCCESS: Self = ErrorCode(0); -} - -/// The LeAclManager before callbacks are registered -pub trait InactiveLeAclManager { - /// The type implementing LeAclManager once callbacks are registered - type ActiveManager: LeAclManager + 'static; - - /// Register callbacks for connection events, and produuce an ActiveManager - fn register_callbacks( - self, - callbacks: impl LeAclManagerConnectionCallbacks + 'static, - ) -> Self::ActiveManager; -} - -/// The operations provided by GD AclManager to the connection manager -pub trait LeAclManager: Debug { - /// Adds an address to the direct connect list, if not already connected. - /// WARNING: the connection timeout is set the FIRST time the address is added, and is - /// NOT RESET! TODO(aryarahul): remove connection timeout from le_impl since it belongs here instead - /// Precondition: Must NOT be currently connected to this adddress (if connected due to race, is a no-op) - fn add_to_direct_list(&self, address: AddressWithType); // CreateLeConnection(is_direct=true) - /// Adds an address to the background connect list - fn add_to_background_list(&self, address: AddressWithType); // CreateLeConnection(is_direct=false) - /// Removes address from both the direct + background connect lists - /// Due to races, it is possible to call this, and THEN get a connection complete with us as central - fn remove_from_all_lists(&self, address: AddressWithType); // CancelLeConnect -} - -/// The callbacks invoked by the LeAclManager in response to events from the controller -pub trait LeAclManagerConnectionCallbacks { - /// Invoked when an LE connection to a given address completes - fn on_le_connect(&self, address: AddressWithType, result: Result<LeConnection, ErrorCode>); - /// Invoked when a peer device disconnects from us. The address must match the address - /// supplied on the initial connection. - fn on_disconnect(&self, address: AddressWithType); -} diff --git a/system/rust/src/connection/mocks.rs b/system/rust/src/connection/mocks.rs deleted file mode 100644 index b50e621a89..0000000000 --- a/system/rust/src/connection/mocks.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -pub mod mock_le_manager; diff --git a/system/rust/src/connection/mocks/mock_le_manager.rs b/system/rust/src/connection/mocks/mock_le_manager.rs deleted file mode 100644 index 879acfac28..0000000000 --- a/system/rust/src/connection/mocks/mock_le_manager.rs +++ /dev/null @@ -1,174 +0,0 @@ -//! This module mocks the behavior of le_impl in GD (excluding timers). -//! It tracks both the internal state of le_impl, as well as the connect list in the controller. -//! It also enforces all (implicit) invariants of le_impl as documented in le_manager.rs, and -//! asserts on violation. - -use std::{cell::RefCell, collections::HashSet, fmt::Debug, rc::Rc}; - -use crate::{ - connection::{ - attempt_manager::ConnectionMode, - le_manager::{ - ErrorCode, InactiveLeAclManager, LeAclManager, LeAclManagerConnectionCallbacks, - }, - LeConnection, - }, - core::address::AddressWithType, -}; - -#[derive(Clone)] -pub struct MockLeAclManager { - active: Rc<RefCell<Option<Rc<MockActiveLeAclManager>>>>, - callbacks: Rc<RefCell<Option<Box<dyn LeAclManagerConnectionCallbacks>>>>, -} - -impl MockLeAclManager { - pub fn new() -> Self { - Self { active: Rc::new(RefCell::new(None)), callbacks: Rc::new(RefCell::new(None)) } - } - - fn inner(&self) -> Rc<MockActiveLeAclManager> { - self.active.borrow().as_ref().unwrap().clone() - } - - pub fn current_acceptlist(&self) -> HashSet<AddressWithType> { - self.inner().current_acceptlist() - } - - pub fn current_connection_mode(&self) -> Option<ConnectionMode> { - self.inner().current_connection_mode() - } - - pub fn on_le_connect(&self, address: AddressWithType, status: ErrorCode) { - let inner = self.inner(); - inner.on_le_connect(address, status); - drop(inner); - - if status == ErrorCode::SUCCESS { - self.callbacks - .borrow() - .as_deref() - .unwrap() - .on_le_connect(address, Ok(LeConnection { remote_address: address })); - } else { - self.callbacks.borrow().as_deref().unwrap().on_le_connect(address, Err(status)); - } - } - - pub fn on_le_disconnect(&self, address: AddressWithType) { - let inner = self.inner(); - inner.on_le_disconnect(address); - drop(inner); - - self.callbacks.borrow().as_deref().unwrap().on_disconnect(address); - } -} - -impl InactiveLeAclManager for MockLeAclManager { - type ActiveManager = Rc<MockActiveLeAclManager>; - - fn register_callbacks( - self, - callbacks: impl LeAclManagerConnectionCallbacks + 'static, - ) -> Self::ActiveManager { - let out = MockActiveLeAclManager::new(); - *self.active.borrow_mut() = Some(out.clone()); - *self.callbacks.borrow_mut() = Some(Box::new(callbacks)); - out - } -} - -#[derive(Debug)] -pub struct MockActiveLeAclManager { - state: RefCell<MockLeManagerInternalState>, -} - -#[derive(Clone, Debug)] -struct MockLeManagerInternalState { - direct_connect_list: HashSet<AddressWithType>, - background_connect_list: HashSet<AddressWithType>, - currently_connected: HashSet<AddressWithType>, -} - -impl MockActiveLeAclManager { - pub fn new() -> Rc<Self> { - Rc::new(MockActiveLeAclManager { - state: RefCell::new(MockLeManagerInternalState { - direct_connect_list: HashSet::new(), - background_connect_list: HashSet::new(), - currently_connected: HashSet::new(), - }), - }) - } - - pub fn current_acceptlist(&self) -> HashSet<AddressWithType> { - let state = self.state.borrow(); - &(&state.direct_connect_list | &state.background_connect_list) - - (&state.currently_connected) - } - - pub fn current_connection_mode(&self) -> Option<ConnectionMode> { - let state = self.state.borrow(); - - if !state.direct_connect_list.is_empty() { - Some(ConnectionMode::Direct) - } else if state - .background_connect_list - .difference(&state.currently_connected) - .next() - .is_some() - { - Some(ConnectionMode::Background) - } else { - None - } - } - - pub fn on_le_connect(&self, address: AddressWithType, status: ErrorCode) { - let mut state = self.state.borrow_mut(); - state.direct_connect_list.remove(&address); - if status == ErrorCode::SUCCESS { - let ok = state.currently_connected.insert(address); - assert!(ok, "Already connected"); - } - } - - pub fn on_le_disconnect(&self, address: AddressWithType) { - let mut state = self.state.borrow_mut(); - let ok = state.currently_connected.remove(&address); - assert!(ok, "Not connected"); - } -} - -impl LeAclManager for Rc<MockActiveLeAclManager> { - fn add_to_direct_list(&self, address: AddressWithType) { - let mut state = self.state.borrow_mut(); - assert!( - !state.currently_connected.contains(&address), - "Must NOT be currently connected to this address" - ); - let ok = state.direct_connect_list.insert(address); - assert!(ok, "Already in direct connect list"); - } - - fn add_to_background_list(&self, address: AddressWithType) { - let mut state = self.state.borrow_mut(); - assert!( - !state.currently_connected.contains(&address), - "Must NOT be currently connected to this address" - ); - let ok = state.background_connect_list.insert(address); - assert!(ok, "Already in background connect list"); - } - - fn remove_from_all_lists(&self, address: AddressWithType) { - let mut state = self.state.borrow_mut(); - assert!( - !state.currently_connected.contains(&address), - "Must NOT be currently connected to this address" - ); - let ok1 = state.direct_connect_list.remove(&address); - let ok2 = state.background_connect_list.remove(&address); - assert!(ok1 || ok2, "Present in neither direct nor background connect list"); - } -} diff --git a/system/rust/src/core/ffi.rs b/system/rust/src/core/ffi.rs index e69002def9..c81235d7f1 100644 --- a/system/rust/src/core/ffi.rs +++ b/system/rust/src/core/ffi.rs @@ -75,17 +75,10 @@ mod inner { type GattServerCallbacks = crate::gatt::GattServerCallbacks; } - #[namespace = "bluetooth::connection"] - unsafe extern "C++" { - include!("src/connection/ffi/connection_shim.h"); - type LeAclManagerShim = crate::connection::LeAclManagerShim; - } - #[namespace = "bluetooth::rust_shim"] extern "Rust" { fn start( gatt_server_callbacks: UniquePtr<GattServerCallbacks>, - le_acl_manager: UniquePtr<LeAclManagerShim>, on_started: Pin<&'static mut Future>, ); diff --git a/system/rust/src/core/ffi/module.cc b/system/rust/src/core/ffi/module.cc index f43e19a1f8..5e79d143fa 100644 --- a/system/rust/src/core/ffi/module.cc +++ b/system/rust/src/core/ffi/module.cc @@ -22,7 +22,6 @@ #include "btcore/include/module.h" #include "os/log.h" #ifndef TARGET_FLOSS -#include "src/connection/ffi/connection_shim.h" #include "src/core/ffi.rs.h" #include "src/gatt/ffi.rs.h" #endif @@ -65,8 +64,7 @@ future_t* Start() { return fut; } bluetooth::rust_shim::start( - std::make_unique<bluetooth::gatt::GattServerCallbacks>(*callbacks->server), - std::make_unique<bluetooth::connection::LeAclManagerShim>(), *fut); + std::make_unique<bluetooth::gatt::GattServerCallbacks>(*callbacks->server), *fut); return fut; } diff --git a/system/rust/src/core/mod.rs b/system/rust/src/core/mod.rs index 2f48f19619..3d25dae585 100644 --- a/system/rust/src/core/mod.rs +++ b/system/rust/src/core/mod.rs @@ -11,7 +11,6 @@ use std::{pin::Pin, rc::Rc, thread}; use cxx::UniquePtr; use crate::{ - connection::{LeAclManagerImpl, LeAclManagerShim}, gatt::ffi::{AttTransportImpl, GattCallbacksImpl}, GlobalModuleRegistry, MainThreadTxMessage, GLOBAL_MODULE_REGISTRY, }; @@ -20,14 +19,12 @@ use self::ffi::{future_ready, Future, GattServerCallbacks}; fn start( gatt_server_callbacks: UniquePtr<GattServerCallbacks>, - le_acl_manager: UniquePtr<LeAclManagerShim>, on_started: Pin<&'static mut Future>, ) { thread::spawn(move || { GlobalModuleRegistry::start( Rc::new(GattCallbacksImpl(gatt_server_callbacks)), Rc::new(AttTransportImpl()), - LeAclManagerImpl(le_acl_manager), || { future_ready(on_started); }, diff --git a/system/rust/src/lib.rs b/system/rust/src/lib.rs index b8154a1cd9..adfb665de3 100644 --- a/system/rust/src/lib.rs +++ b/system/rust/src/lib.rs @@ -15,18 +15,15 @@ //! The core event loop for Rust modules. Here Rust modules are started in //! dependency order. -use connection::le_manager::InactiveLeAclManager; use gatt::{channel::AttTransport, GattCallbacks}; use log::{info, warn}; use tokio::task::LocalSet; -use self::core::shared_box::SharedBox; use std::{rc::Rc, sync::Mutex}; use tokio::runtime::Builder; use tokio::sync::mpsc; -pub mod connection; pub mod core; pub mod gatt; pub mod packets; @@ -47,8 +44,6 @@ pub struct ModuleViews<'a> { pub gatt_incoming_callbacks: Rc<gatt::callbacks::CallbackTransactionManager>, /// Proxies calls into GATT server pub gatt_module: &'a mut gatt::server::GattModule, - /// Proxies calls into connection manager - pub connection_manager: SharedBox<connection::ConnectionManager>, } static GLOBAL_MODULE_REGISTRY: Mutex<Option<GlobalModuleRegistry>> = Mutex::new(None); @@ -61,7 +56,6 @@ impl GlobalModuleRegistry { pub fn start( gatt_callbacks: Rc<dyn GattCallbacks>, att_transport: Rc<dyn AttTransport>, - le_acl_manager: impl InactiveLeAclManager, on_started: impl FnOnce(), ) { info!("starting Rust modules"); @@ -79,7 +73,6 @@ impl GlobalModuleRegistry { // First, setup FFI and C++ modules let arbiter = gatt::arbiter::initialize_arbiter(); - connection::register_callbacks(); // Now enter the runtime local.block_on(&rt, async move { @@ -88,15 +81,12 @@ impl GlobalModuleRegistry { Rc::new(gatt::callbacks::CallbackTransactionManager::new(gatt_callbacks.clone())); let gatt_module = &mut gatt::server::GattModule::new(att_transport.clone(), arbiter); - let connection_manager = connection::ConnectionManager::new(le_acl_manager); - // All modules that are visible from incoming JNI / top-level interfaces should // be exposed here let mut modules = ModuleViews { gatt_outgoing_callbacks: gatt_callbacks, gatt_incoming_callbacks, gatt_module, - connection_manager, }; // notify upper layer that we are ready to receive messages diff --git a/system/stack/acl/ble_acl.cc b/system/stack/acl/ble_acl.cc index c7ad2adbbd..1f5d5b580c 100644 --- a/system/stack/acl/ble_acl.cc +++ b/system/stack/acl/ble_acl.cc @@ -52,9 +52,7 @@ static bool acl_ble_common_connection(const tBLE_BD_ADDR& address_with_type, uin } // Inform any applications that a connection has completed. - if (!com::android::bluetooth::flags::unified_connection_manager()) { - connection_manager::on_connection_complete(address_with_type.bda); - } + connection_manager::on_connection_complete(address_with_type.bda); // Allocate or update the security device record for this device btm_ble_connected(address_with_type.bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, @@ -111,9 +109,7 @@ void acl_ble_enhanced_connection_complete_from_shim( uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout, const RawAddress& local_rpa, const RawAddress& peer_rpa, tBLE_ADDR_TYPE peer_addr_type, bool can_read_discoverable_characteristics) { - if (!com::android::bluetooth::flags::unified_connection_manager()) { - connection_manager::on_connection_complete(address_with_type.bda); - } + connection_manager::on_connection_complete(address_with_type.bda); tBLE_BD_ADDR resolved_address_with_type; const bool is_in_security_db = @@ -139,9 +135,7 @@ void acl_ble_connection_fail(const tBLE_BD_ADDR& address_with_type, uint16_t /* btm_ble_clear_topology_mask(BTM_BLE_STATE_INIT_BIT); tBLE_BD_ADDR resolved_address_with_type; maybe_resolve_received_address(address_with_type, &resolved_address_with_type); - if (!com::android::bluetooth::flags::unified_connection_manager()) { - connection_manager::on_connection_timed_out_from_shim(resolved_address_with_type.bda); - } + connection_manager::on_connection_timed_out_from_shim(resolved_address_with_type.bda); log::warn("LE connection fail peer:{} bd_addr:{} hci_status:{}", address_with_type, resolved_address_with_type.bda, hci_status_code_text(status)); } else { diff --git a/system/stack/acl/btm_acl.cc b/system/stack/acl/btm_acl.cc index d88f447160..fc4a4dcd6c 100644 --- a/system/stack/acl/btm_acl.cc +++ b/system/stack/acl/btm_acl.cc @@ -54,8 +54,6 @@ #include "osi/include/allocator.h" #include "osi/include/properties.h" #include "osi/include/stack_power_telemetry.h" -#include "rust/src/connection/ffi/connection_shim.h" -#include "rust/src/core/ffi/types.h" #include "stack/acl/acl.h" #include "stack/acl/peer_packet_types.h" #include "stack/btm/btm_ble_int.h" @@ -2464,7 +2462,7 @@ void acl_write_automatic_flush_timeout(const RawAddress& bd_addr, uint16_t flush btsnd_hcic_write_auto_flush_tout(p_acl->hci_handle, flush_timeout_in_ticks); } -bool acl_create_le_connection_with_id(uint8_t id, const RawAddress& bd_addr, +bool acl_create_le_connection_with_id(uint8_t /* id */, const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type) { tBLE_BD_ADDR address_with_type{ .type = addr_type, @@ -2484,13 +2482,8 @@ bool acl_create_le_connection_with_id(uint8_t id, const RawAddress& bd_addr, return false; } - if (com::android::bluetooth::flags::unified_connection_manager()) { - bluetooth::connection::GetConnectionManager().start_direct_connection( - id, bluetooth::core::ToRustAddress(address_with_type)); - } else { - bluetooth::shim::ACL_AcceptLeConnectionFrom(address_with_type, - /* is_direct */ true); - } + bluetooth::shim::ACL_AcceptLeConnectionFrom(address_with_type, + /* is_direct */ true); return true; } diff --git a/system/stack/btm/btm_dev.cc b/system/stack/btm/btm_dev.cc index af7869423f..cdc7e27f91 100644 --- a/system/stack/btm/btm_dev.cc +++ b/system/stack/btm/btm_dev.cc @@ -39,7 +39,6 @@ #include "main/shim/acl_api.h" #include "main/shim/dumpsys.h" #include "osi/include/allocator.h" -#include "rust/src/connection/ffi/connection_shim.h" #include "stack/btm/btm_sec.h" #include "stack/include/acl_api.h" #include "stack/include/bt_octets.h" @@ -182,12 +181,7 @@ bool BTM_SecDeleteDevice(const RawAddress& bd_addr) { RawAddress bda = p_dev_rec->bd_addr; log::info("Remove device {} from filter accept list before delete record", bd_addr); - if (com::android::bluetooth::flags::unified_connection_manager()) { - bluetooth::connection::GetConnectionManager().stop_all_connections_to_device( - bluetooth::connection::ResolveRawAddress(bda)); - } else { - bluetooth::shim::ACL_IgnoreLeConnectionFrom(BTM_Sec_GetAddressWithType(bda)); - } + bluetooth::shim::ACL_IgnoreLeConnectionFrom(BTM_Sec_GetAddressWithType(bda)); const auto device_type = p_dev_rec->device_type; const auto bond_type = p_dev_rec->sec_rec.bond_type; diff --git a/system/stack/gatt/gatt_api.cc b/system/stack/gatt/gatt_api.cc index a5a863708f..cf723d1e1e 100644 --- a/system/stack/gatt/gatt_api.cc +++ b/system/stack/gatt/gatt_api.cc @@ -35,7 +35,6 @@ #include "internal_include/stack_config.h" #include "os/system_properties.h" #include "osi/include/allocator.h" -#include "rust/src/connection/ffi/connection_shim.h" #include "stack/arbiter/acl_arbiter.h" #include "stack/btm/btm_dev.h" #include "stack/gatt/connection_manager.h" @@ -1378,11 +1377,7 @@ void GATT_Deregister(tGATT_IF gatt_if) { } } - if (com::android::bluetooth::flags::unified_connection_manager()) { - bluetooth::connection::GetConnectionManager().remove_client(gatt_if); - } else { - connection_manager::on_app_deregistered(gatt_if); - } + connection_manager::on_app_deregistered(gatt_if); if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { gatt_cb.cl_rcb_map.erase(gatt_if); @@ -1506,20 +1501,10 @@ bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, tBLE_ADDR_TYPE ad ret = false; } else { log::debug("Adding to background connect to device:{}", bd_addr); - if (com::android::bluetooth::flags::unified_connection_manager()) { - if (connection_type == BTM_BLE_BKG_CONNECT_ALLOW_LIST) { - bluetooth::connection::GetConnectionManager().add_background_connection( - gatt_if, bluetooth::connection::ResolveRawAddress(bd_addr)); - ret = true; // TODO(aryarahul): error handling - } else { - log::fatal("unimplemented, TODO(aryarahul)"); - } + if (connection_type == BTM_BLE_BKG_CONNECT_ALLOW_LIST) { + ret = connection_manager::background_connect_add(gatt_if, bd_addr); } else { - if (connection_type == BTM_BLE_BKG_CONNECT_ALLOW_LIST) { - ret = connection_manager::background_connect_add(gatt_if, bd_addr); - } else { - ret = connection_manager::background_connect_targeted_announcement_add(gatt_if, bd_addr); - } + ret = connection_manager::background_connect_targeted_announcement_add(gatt_if, bd_addr); } } } @@ -1602,14 +1587,9 @@ bool GATT_CancelConnect(tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_dir } } - if (com::android::bluetooth::flags::unified_connection_manager()) { - bluetooth::connection::GetConnectionManager().stop_all_connections_to_device( - bluetooth::connection::ResolveRawAddress(bd_addr)); - } else { - if (!connection_manager::remove_unconditional(bd_addr)) { - log::error("no app associated with the bg device for unconditional removal"); - return false; - } + if (!connection_manager::remove_unconditional(bd_addr)) { + log::error("no app associated with the bg device for unconditional removal"); + return false; } return true; diff --git a/system/stack/gatt/gatt_main.cc b/system/stack/gatt/gatt_main.cc index 299b847c5a..7c8a256610 100644 --- a/system/stack/gatt/gatt_main.cc +++ b/system/stack/gatt/gatt_main.cc @@ -35,7 +35,6 @@ #include "main/shim/acl_api.h" #include "osi/include/allocator.h" #include "osi/include/properties.h" -#include "rust/src/connection/ffi/connection_shim.h" #include "stack/arbiter/acl_arbiter.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_sec.h" @@ -261,20 +260,14 @@ void gatt_cancel_connect(const RawAddress& bd_addr, tBT_TRANSPORT transport) { /* This shall be call only when device is not connected */ log::debug("{}, transport {}", bd_addr, transport); - if (com::android::bluetooth::flags::unified_connection_manager()) { - // TODO(aryarahul): this might not be necessary now that the connection - // manager handles GATT client closure correctly in GATT_Deregister - bluetooth::connection::GetConnectionManager().stop_all_connections_to_device( - bluetooth::connection::ResolveRawAddress(bd_addr)); - } else { - if (!connection_manager::direct_connect_remove(CONN_MGR_ID_L2CAP, bd_addr)) { - bluetooth::shim::ACL_IgnoreLeConnectionFrom(BTM_Sec_GetAddressWithType(bd_addr)); - log::info( - "GATT connection manager has no record but removed filter " - "acceptlist gatt_if:{} peer:{}", - static_cast<uint8_t>(CONN_MGR_ID_L2CAP), bd_addr); - } + if (!connection_manager::direct_connect_remove(CONN_MGR_ID_L2CAP, bd_addr)) { + bluetooth::shim::ACL_IgnoreLeConnectionFrom(BTM_Sec_GetAddressWithType(bd_addr)); + log::info( + "GATT connection manager has no record but removed filter " + "acceptlist gatt_if:{} peer:{}", + static_cast<uint8_t>(CONN_MGR_ID_L2CAP), bd_addr); } + gatt_cleanup_upon_disc(bd_addr, GATT_CONN_TERMINATE_LOCAL_HOST, transport); } @@ -1010,14 +1003,7 @@ static void gatt_send_conn_cback(tGATT_TCB* p_tcb) { tGATT_REG* p_reg; tCONN_ID conn_id; - std::set<tGATT_IF> apps = {}; - if (com::android::bluetooth::flags::unified_connection_manager()) { - // TODO(aryarahul): this should be done via callbacks passed into the - // connection manager - apps = {}; - } else { - apps = connection_manager::get_apps_connecting_to(p_tcb->peer_bda); - } + std::set<tGATT_IF> apps = connection_manager::get_apps_connecting_to(p_tcb->peer_bda); /* notifying all applications for the connection up event */ @@ -1070,9 +1056,7 @@ static void gatt_send_conn_cback(tGATT_TCB* p_tcb) { } /* Remove the direct connection */ - if (!com::android::bluetooth::flags::unified_connection_manager()) { - connection_manager::on_connection_complete(p_tcb->peer_bda); - } + connection_manager::on_connection_complete(p_tcb->peer_bda); if (p_tcb->att_lcid == L2CAP_ATT_CID) { if (!p_tcb->app_hold_link.empty()) { diff --git a/system/stack/gatt/gatt_utils.cc b/system/stack/gatt/gatt_utils.cc index ec449c0ecd..57dbb6e71a 100644 --- a/system/stack/gatt/gatt_utils.cc +++ b/system/stack/gatt/gatt_utils.cc @@ -36,7 +36,6 @@ #include "main/shim/dumpsys.h" #include "osi/include/allocator.h" #include "osi/include/properties.h" -#include "rust/src/connection/ffi/connection_shim.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_sec.h" #include "stack/eatt/eatt.h" @@ -1661,26 +1660,21 @@ bool gatt_cancel_open(tGATT_IF gatt_if, const RawAddress& bda) { gatt_disconnect(p_tcb); } - if (com::android::bluetooth::flags::unified_connection_manager()) { - bluetooth::connection::GetConnectionManager().stop_direct_connection( - gatt_if, bluetooth::connection::ResolveRawAddress(bda)); - } else { - if (!connection_manager::direct_connect_remove(gatt_if, bda)) { - if (!connection_manager::is_background_connection(bda)) { - if (!com::android::bluetooth::flags::gatt_fix_multiple_direct_connect() || - p_tcb->app_hold_link.empty()) { - bluetooth::shim::ACL_IgnoreLeConnectionFrom(BTM_Sec_GetAddressWithType(bda)); - } - log::info( - "Gatt connection manager has no background record but removed " - "filter acceptlist gatt_if:{} peer:{}", - gatt_if, bda); - } else { - log::info( - "Gatt connection manager maintains a background record preserving " - "filter acceptlist gatt_if:{} peer:{}", - gatt_if, bda); + if (!connection_manager::direct_connect_remove(gatt_if, bda)) { + if (!connection_manager::is_background_connection(bda)) { + if (!com::android::bluetooth::flags::gatt_fix_multiple_direct_connect() || + p_tcb->app_hold_link.empty()) { + bluetooth::shim::ACL_IgnoreLeConnectionFrom(BTM_Sec_GetAddressWithType(bda)); } + log::info( + "Gatt connection manager has no background record but removed " + "filter acceptlist gatt_if:{} peer:{}", + gatt_if, bda); + } else { + log::info( + "Gatt connection manager maintains a background record preserving " + "filter acceptlist gatt_if:{} peer:{}", + gatt_if, bda); } } @@ -1979,14 +1973,7 @@ bool gatt_auto_connect_dev_remove(tGATT_IF gatt_if, const RawAddress& bd_addr) { if (p_tcb) { gatt_update_app_use_link_flag(gatt_if, p_tcb, false, false); } - if (com::android::bluetooth::flags::unified_connection_manager()) { - bluetooth::connection::GetConnectionManager().remove_background_connection( - gatt_if, bluetooth::connection::ResolveRawAddress(bd_addr)); - // TODO(aryarahul): handle failure case - return true; - } else { - return connection_manager::background_connect_remove(gatt_if, bd_addr); - } + return connection_manager::background_connect_remove(gatt_if, bd_addr); } tCONN_ID gatt_create_conn_id(tTCB_IDX tcb_idx, tGATT_IF gatt_if) { diff --git a/system/test/mock/mock_rust_ffi_connection_shim.cc b/system/test/mock/mock_rust_ffi_connection_shim.cc deleted file mode 100644 index aeb62182ba..0000000000 --- a/system/test/mock/mock_rust_ffi_connection_shim.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "rust/src/connection/ffi/connection_shim.h" -#include "test/common/mock_functions.h" - -namespace bluetooth { - -namespace connection { - -RustConnectionManager& GetConnectionManager() { - static RustConnectionManager manager = {}; - inc_func_call_count(__func__); - return manager; -} - -core::AddressWithType ResolveRawAddress(RawAddress /* bd_addr */) { - inc_func_call_count(__func__); - return {}; -} - -} // namespace connection -} // namespace bluetooth |