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

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

rusty-gd: GDDI now caches instances & allows injecting config

Bug: 171749953
Tag: #gd-refactor
Test: gd/cert/run --rhost SimpleHalTest
Change-Id: Iac8f6a8edc5aa4ee94c33d20d11a23c9906d0b34
parent 8d7d84ff
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ rust_library {
      "libgrpcio",
      "libprotobuf",
      "libtokio",
      "libgddi",
    ],
    host_supported: true,
}
+36 −19
Original line number Diff line number Diff line
@@ -14,20 +14,31 @@ use rootservice::*;
use rootservice_grpc::{create_root_facade, RootFacade};

use bt_hal::facade::HciHalFacadeService;
use bt_hal::rootcanal_hal::{RootcanalConfig, RootcanalHal};
use bt_hal::hal_facade_module;
use bt_hal::rootcanal_hal::RootcanalConfig;
use bt_hci::facade::HciLayerFacadeService;
use bt_hci::Hci;
use bt_hci::hci_module;

use tokio::runtime::Runtime;
use tokio::sync::mpsc::{channel, Sender};
use tokio::sync::oneshot;

use gddi::{module, Registry, RegistryBuilder};

use grpcio::*;

use std::sync::Arc;

use futures::executor::block_on;

module! {
    stack_module,
    submodules {
        hal_facade_module,
        hci_module,
    }
}

/// Bluetooth testing root facade service
#[derive(Clone)]
pub struct RootFacadeService {
@@ -94,13 +105,29 @@ impl FacadeServiceManager {
    fn create(rt: Arc<Runtime>, grpc_port: u16, rootcanal_port: Option<u16>) -> Self {
        let (tx, mut rx) = channel::<LifecycleCommand>(1);
        let local_rt = rt.clone();
        local_rt.spawn(async move {
        rt.spawn(async move {
            let mut server: Option<Server> = None;
            while let Some(cmd) = rx.recv().await {
                match cmd {
                    LifecycleCommand::Start { req, done } => {
                        server =
                            Some(Self::start_internal(&rt, req, grpc_port, rootcanal_port).await);
                        let registry = {
                            let mut builder = RegistryBuilder::new();
                            builder.register_module(stack_module);
                            if rootcanal_port.is_some() {
                                builder.register_module(bt_hal::rootcanal_hal_module);
                            }

                            Arc::new(builder.build())
                        };

                        registry.inject(local_rt.clone()).await;
                        if let Some(rc_port) = rootcanal_port {
                            registry
                                .inject(RootcanalConfig::new(rc_port, "127.0.0.1"))
                                .await;
                        }

                        server = Some(Self::start_internal(&registry, req, grpc_port).await);
                        done.send(()).unwrap();
                    }
                    LifecycleCommand::Stop { done } => {
@@ -135,30 +162,20 @@ impl FacadeServiceManager {
        Ok(())
    }

    // TODO this is messy and needs to be overhauled to support bringing up the stack to partial
    // layers. Will be cleaned up soon.
    async fn start_internal(
        rt: &Arc<Runtime>,
        registry: &Arc<Registry>,
        req: StartStackRequest,
        grpc_port: u16,
        rootcanal_port: Option<u16>,
    ) -> Server {
        let hal_exports = RootcanalHal::start(
            RootcanalConfig::new(rootcanal_port.unwrap(), "127.0.0.1"),
            Arc::clone(&rt),
        )
        .await
        .unwrap();
        let mut services = Vec::new();
        match req.get_module_under_test() {
            BluetoothModule::HAL => {
                services.push(HciHalFacadeService::create(hal_exports, Arc::clone(&rt)));
                services.push(registry.get::<HciHalFacadeService>().await.create_grpc());
            }
            BluetoothModule::HCI => {
                let hci_exports = Hci::start(hal_exports, Arc::clone(&rt));
                services.push(HciLayerFacadeService::create(hci_exports, Arc::clone(&rt)));
                services.push(registry.get::<HciLayerFacadeService>().await.create_grpc());
            }
            _ => unimplemented!()
            _ => unimplemented!(),
        }

        FacadeServiceManager::start_server(services, grpc_port)
+4 −4
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ pub fn provides(_attr: TokenStream, item: TokenStream) -> TokenStream {

    let emitted_code = quote! {
        // Injecting wrapper
        fn #injected_ident(registry: std::sync::Arc<gddi::Registry>) -> std::pin::Pin<Box<dyn std::future::Future<Output = Box<dyn std::any::Any>>>> {
        fn #injected_ident(registry: std::sync::Arc<gddi::Registry>) -> std::pin::Pin<gddi::ProviderFutureBox> {
            Box::pin(async move {
                // Create a local variable for each argument, to ensure they get generated in a
                // deterministic order (compiler complains otherwise)
@@ -139,11 +139,11 @@ pub fn module(item: TokenStream) -> TokenStream {
    let submodule_idents = module.submodules.iter();
    let emitted_code = quote! {
        #[doc(hidden)]
        pub fn #init_ident(registry: &mut gddi::Registry) {
        pub fn #init_ident(builder: &mut gddi::RegistryBuilder) {
            // Register all providers on this module
            #(registry.register_provider::<#types>(Box::new(#provider_idents));)*
            #(builder.register_provider::<#types>(Box::new(#provider_idents));)*
            // Register all submodules on this module
            #(registry.register_module(#submodule_idents);)*
            #(builder.register_module(#submodule_idents);)*
        }
    };
    emitted_code.into()
+1 −0
Original line number Diff line number Diff line
@@ -5,4 +5,5 @@ rust_library {
    host_supported: true,
    edition: "2018",
    proc_macros: ["libgddi_macros"],
    rustlibs: ["libtokio"],
}
+62 −16
Original line number Diff line number Diff line
@@ -8,27 +8,41 @@ use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;

use tokio::sync::Mutex;

pub use gddi_macros::{module, provides};

type InstanceBox = Box<dyn Any + Send + Sync>;
/// A box around a future for a provider that is safe to send between threads
pub type ProviderFutureBox = Box<dyn Future<Output = Box<dyn Any>> + Send + Sync>;
type ProviderFnBox = Box<dyn Fn(Arc<Registry>) -> Pin<ProviderFutureBox> + Send + Sync>;

/// Builder for Registry
pub struct RegistryBuilder {
    providers: HashMap<TypeId, Provider>,
}

/// Keeps track of central injection state
pub struct Registry {
    providers: HashMap<TypeId, Provider>,
    providers: Arc<Mutex<HashMap<TypeId, Provider>>>,
    instances: Arc<Mutex<HashMap<TypeId, InstanceBox>>>,
}

#[derive(Clone)]
struct Provider {
    f: Box<dyn Fn(Arc<Registry>) -> Pin<Box<dyn Future<Output = Box<dyn Any>>>>>,
    f: Arc<ProviderFnBox>,
}

impl Default for Registry {
impl Default for RegistryBuilder {
    fn default() -> Self {
        Self::new()
    }
}

impl Registry {
    /// Creates a new registry
impl RegistryBuilder {
    /// Creates a new RegistryBuilder
    pub fn new() -> Self {
        Registry {
        RegistryBuilder {
            providers: HashMap::new(),
        }
    }
@@ -36,23 +50,55 @@ impl Registry {
    /// Registers a module with this registry
    pub fn register_module<F>(&mut self, init: F)
    where
        F: Fn(&mut Registry),
        F: Fn(&mut Self),
    {
        init(self);
    }

    /// Registers a provider function with this registry
    pub fn register_provider<T: 'static>(
        &mut self,
        f: Box<dyn Fn(Arc<Registry>) -> Pin<Box<dyn Future<Output = Box<dyn Any>>>>>,
    ) {
        self.providers.insert(TypeId::of::<T>(), Provider { f });
    pub fn register_provider<T: 'static>(&mut self, f: ProviderFnBox) {
        self.providers
            .insert(TypeId::of::<T>(), Provider { f: Arc::new(f) });
    }

    /// Construct the Registry from this builder
    pub fn build(self) -> Registry {
        Registry {
            providers: Arc::new(Mutex::new(self.providers)),
            instances: Arc::new(Mutex::new(HashMap::new())),
        }
    }
}

impl Registry {
    /// Gets an instance of a type, implicitly starting any dependencies if necessary
    pub async fn get<T: 'static + Clone>(self: &Arc<Self>) -> T {
        let provider = &self.providers[&TypeId::of::<T>()];
    pub async fn get<T: 'static + Clone + Send + Sync>(self: &Arc<Self>) -> T {
        let typeid = TypeId::of::<T>();
        {
            let instances = self.instances.lock().await;
            if let Some(value) = instances.get(&typeid) {
                return value
                    .downcast_ref::<T>()
                    .expect("was not correct type")
                    .clone();
            }
        }

        let casted = {
            let provider = { self.providers.lock().await[&typeid].clone() };
            let result = (provider.f)(self.clone()).await;
        *result.downcast::<T>().expect("was not correct type")
            (*result.downcast::<T>().expect("was not correct type")).clone()
        };

        let mut instances = self.instances.lock().await;
        instances.insert(typeid, Box::new(casted.clone()));

        casted
    }

    /// Inject an already created instance of T. Useful for config.
    pub async fn inject<T: 'static + Clone + Send + Sync>(self: &Arc<Self>, obj: T) {
        let mut instances = self.instances.lock().await;
        instances.insert(TypeId::of::<T>(), Box::new(obj));
    }
}
Loading