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

Commit 9066159c authored by Rahul Arya's avatar Rahul Arya
Browse files

[GATT Server] Expose IsolationManager from GATT server module

The IsolationManager is made a submodule of the GATT server, so we can
query it to figure out what services are exposed to each connection. It
is temporarily also available directly from FFI, solely for the purpose
of arbitration. This will be removed once the Rust server is used for
100% of GATT server operations.

Test: unit + CTS multi-device
Bug: 274945531
Change-Id: Idc3cdd78ec2435a7a286413d7b1ebaae83a8f07a
parent 34ecd8fe
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ rust_defaults {
        "libbt_common",
        "libcxx",
        "liblog_rust",
        "libonce_cell",
        "libscopeguard",

        // needed to work around duplicate symbols
+1 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ async-trait = "*"
tokio-test = "0.4.2"
tokio = { version = "1.23.0", features = ["macros"] }
scopeguard = "1.1.0"
once_cell = "1.17.1"

[lib]
crate-type = ["rlib"]
+14 −16
Original line number Diff line number Diff line
//! This module handles "arbitration" of ATT packets, to determine whether they
//! should be handled by the primary stack or by the Rust stack

use std::sync::Mutex;
use std::sync::{Arc, Mutex};

use log::{error, trace};
use once_cell::sync::OnceCell;

use crate::{
    do_in_rust_thread,
@@ -18,11 +19,12 @@ use super::{
    server::isolation_manager::IsolationManager,
};

static ARBITER: Mutex<Option<IsolationManager>> = Mutex::new(None);
static ARBITER: OnceCell<Arc<Mutex<IsolationManager>>> = OnceCell::new();

/// Initialize the Arbiter
pub fn initialize_arbiter() {
    *ARBITER.lock().unwrap() = Some(IsolationManager::new());
pub fn initialize_arbiter() -> Arc<Mutex<IsolationManager>> {
    let arbiter = Arc::new(Mutex::new(IsolationManager::new()));
    ARBITER.set(arbiter.clone()).unwrap_or_else(|_| panic!("Rust stack should only start up once"));

    StoreCallbacksFromRust(
        on_le_connect,
@@ -32,12 +34,14 @@ pub fn initialize_arbiter() {
        |tcb_idx, mtu| on_mtu_event(TransportIndex(tcb_idx), MtuEvent::IncomingResponse(mtu)),
        |tcb_idx, mtu| on_mtu_event(TransportIndex(tcb_idx), MtuEvent::IncomingRequest(mtu)),
    );

    arbiter
}

/// Acquire the mutex holding the Arbiter and provide a mutable reference to the
/// supplied closure
pub fn with_arbiter<T>(f: impl FnOnce(&mut IsolationManager) -> T) -> T {
    f(ARBITER.lock().unwrap().as_mut().unwrap())
    f(ARBITER.get().unwrap().lock().as_mut().unwrap())
}

/// Test to see if a buffer contains a valid ATT packet with an opcode we
@@ -66,12 +70,10 @@ fn try_parse_att_server_packet(
fn on_le_connect(tcb_idx: u8, advertiser: u8) {
    let tcb_idx = TransportIndex(tcb_idx);
    let advertiser = AdvertiserId(advertiser);
    if let Some(conn_id) = with_arbiter(|arbiter| {
        arbiter.on_le_connect(tcb_idx, advertiser);
        arbiter.get_conn_id(tcb_idx)
    }) {
    let is_isolated = with_arbiter(|arbiter| arbiter.is_advertiser_isolated(advertiser));
    if is_isolated {
        do_in_rust_thread(move |modules| {
            if let Err(err) = modules.gatt_module.on_le_connect(conn_id) {
            if let Err(err) = modules.gatt_module.on_le_connect(tcb_idx, Some(advertiser)) {
                error!("{err:?}")
            }
        })
@@ -80,11 +82,7 @@ fn on_le_connect(tcb_idx: u8, advertiser: u8) {

fn on_le_disconnect(tcb_idx: u8) {
    let tcb_idx = TransportIndex(tcb_idx);
    let was_isolated = with_arbiter(|arbiter| {
        let was_isolated = arbiter.get_conn_id(tcb_idx).is_some();
        arbiter.on_le_disconnect(tcb_idx);
        was_isolated
    });
    let was_isolated = with_arbiter(|arbiter| arbiter.get_conn_id(tcb_idx).is_some());
    if was_isolated {
        do_in_rust_thread(move |modules| {
            if let Err(err) = modules.gatt_module.on_le_disconnect(tcb_idx) {
@@ -149,7 +147,7 @@ mod test {
    ) -> IsolationManager {
        let mut isolation_manager = IsolationManager::new();
        isolation_manager.associate_server_with_advertiser(server_id, ADVERTISER_ID);
        isolation_manager.on_le_connect(tcb_idx, ADVERTISER_ID);
        isolation_manager.on_le_connect(tcb_idx, Some(ADVERTISER_ID));
        isolation_manager
    }

+19 −14
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ use crate::{
};

use super::{
    arbiter::{self, with_arbiter},
    arbiter::with_arbiter,
    callbacks::{GattWriteRequestType, GattWriteType, TransactionDecision},
    channel::AttTransport,
    ids::{AdvertiserId, AttHandle, ConnectionId, ServerId, TransactionId, TransportIndex},
@@ -288,13 +288,13 @@ fn open_server(server_id: u8) {

    let server_id = ServerId(server_id);

    do_in_rust_thread(move |modules| {
        if always_use_private_gatt_for_debugging_is_enabled() {
        with_arbiter(|arbiter| {
            arbiter.associate_server_with_advertiser(server_id, AdvertiserId(0))
        });
            modules
                .gatt_module
                .get_isolation_manager()
                .associate_server_with_advertiser(server_id, AdvertiserId(0))
        }

    do_in_rust_thread(move |modules| {
        if let Err(err) = modules.gatt_module.open_gatt_server(server_id) {
            error!("{err:?}")
        }
@@ -308,10 +308,6 @@ fn close_server(server_id: u8) {

    let server_id = ServerId(server_id);

    if !always_use_private_gatt_for_debugging_is_enabled() {
        with_arbiter(move |arbiter| arbiter.clear_server(server_id));
    }

    do_in_rust_thread(move |modules| {
        if let Err(err) = modules.gatt_module.close_gatt_server(server_id) {
            error!("{err:?}")
@@ -495,8 +491,13 @@ fn associate_server_with_advertiser(server_id: u8, advertiser_id: u8) {
        return;
    }

    arbiter::with_arbiter(move |arbiter| {
        arbiter.associate_server_with_advertiser(ServerId(server_id), AdvertiserId(advertiser_id))
    let server_id = ServerId(server_id);
    let advertiser_id = AdvertiserId(advertiser_id);
    do_in_rust_thread(move |modules| {
        modules
            .gatt_module
            .get_isolation_manager()
            .associate_server_with_advertiser(server_id, advertiser_id);
    })
}

@@ -505,7 +506,11 @@ fn clear_advertiser(advertiser_id: u8) {
        return;
    }

    arbiter::with_arbiter(move |arbiter| arbiter.clear_advertiser(AdvertiserId(advertiser_id)))
    let advertiser_id = AdvertiserId(advertiser_id);

    do_in_rust_thread(move |modules| {
        modules.gatt_module.get_isolation_manager().clear_advertiser(advertiser_id);
    })
}

#[cfg(test)]
+44 −10
Original line number Diff line number Diff line
@@ -14,26 +14,32 @@ pub mod isolation_manager;
#[cfg(test)]
mod test;

use std::{collections::HashMap, rc::Rc};
use std::{
    collections::HashMap,
    rc::Rc,
    sync::{Arc, Mutex, MutexGuard},
};

use crate::{
    core::shared_box::{SharedBox, WeakBox, WeakBoxRef},
    gatt::{ids::ConnectionId, server::gatt_database::GattDatabase},
    gatt::server::gatt_database::GattDatabase,
};

use self::{
    super::ids::ServerId,
    att_server_bearer::AttServerBearer,
    gatt_database::{AttDatabaseImpl, GattServiceWithHandle},
    isolation_manager::IsolationManager,
    services::register_builtin_services,
};

use super::{
    callbacks::RawGattDatastore,
    channel::AttTransport,
    ids::{AttHandle, TransportIndex},
    ids::{AdvertiserId, AttHandle, TransportIndex},
};
use anyhow::{anyhow, bail, Result};
use bt_common::init_flags::always_use_private_gatt_for_debugging_is_enabled;
use log::info;

pub use indication_handler::IndicationError;
@@ -43,6 +49,10 @@ pub struct GattModule {
    connections: HashMap<TransportIndex, GattConnection>,
    databases: HashMap<ServerId, SharedBox<GattDatabase>>,
    transport: Rc<dyn AttTransport>,
    // NOTE: this is logically owned by the GattModule. We share it behind a Mutex just so we
    // can use it as part of the Arbiter. Once the Arbiter is removed, this should be owned
    // fully by the GattModule.
    isolation_manager: Arc<Mutex<IsolationManager>>,
}

struct GattConnection {
@@ -52,13 +62,30 @@ struct GattConnection {

impl GattModule {
    /// Constructor.
    pub fn new(transport: Rc<dyn AttTransport>) -> Self {
        Self { connections: HashMap::new(), databases: HashMap::new(), transport }
    pub fn new(
        transport: Rc<dyn AttTransport>,
        isolation_manager: Arc<Mutex<IsolationManager>>,
    ) -> Self {
        Self {
            connections: HashMap::new(),
            databases: HashMap::new(),
            transport,
            isolation_manager,
        }
    }

    /// Handle LE link connect
    pub fn on_le_connect(&mut self, conn_id: ConnectionId) -> Result<()> {
        info!("connected on conn_id {conn_id:?}");
    pub fn on_le_connect(
        &mut self,
        tcb_idx: TransportIndex,
        advertiser_id: Option<AdvertiserId>,
    ) -> Result<()> {
        info!("connected on tcb_idx {tcb_idx:?}");
        self.isolation_manager.lock().unwrap().on_le_connect(tcb_idx, advertiser_id);

        let Some(conn_id) = self.isolation_manager.lock().unwrap().get_conn_id(tcb_idx) else {
            bail!("non-isolated servers are not yet supported (b/274945531)")
        };
        let database = self.databases.get(&conn_id.get_server_id());
        let Some(database) = database else {
            bail!(
@@ -67,9 +94,6 @@ impl GattModule {
            );
        };

        // TODO(aryarahul): do not pass in conn_id at all, derive it using the IsolationManager instead
        let tcb_idx = conn_id.get_tcb_idx();

        let transport = self.transport.clone();
        let bearer = SharedBox::new(AttServerBearer::new(
            database.get_att_database(tcb_idx),
@@ -83,6 +107,7 @@ impl GattModule {
    /// Handle an LE link disconnect
    pub fn on_le_disconnect(&mut self, tcb_idx: TransportIndex) -> Result<()> {
        info!("disconnected conn_id {tcb_idx:?}");
        self.isolation_manager.lock().unwrap().on_le_disconnect(tcb_idx);
        let connection = self.connections.remove(&tcb_idx);
        let Some(connection) = connection else {
            bail!("got disconnection from {tcb_idx:?} but bearer does not exist");
@@ -135,6 +160,10 @@ impl GattModule {
            bail!("GATT server {server_id:?} did not exist")
        };

        if !always_use_private_gatt_for_debugging_is_enabled() {
            self.isolation_manager.lock().unwrap().clear_server(server_id);
        }

        Ok(())
    }

@@ -145,4 +174,9 @@ impl GattModule {
    ) -> Option<WeakBoxRef<AttServerBearer<AttDatabaseImpl>>> {
        self.connections.get(&tcb_idx).map(|x| x.bearer.as_ref())
    }

    /// Get the IsolationManager to manage associations between servers + advertisers
    pub fn get_isolation_manager(&mut self) -> MutexGuard<'_, IsolationManager> {
        self.isolation_manager.lock().unwrap()
    }
}
Loading