1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! The core event loop for Rust modules. Here Rust modules are started in
16 //! dependency order.
17 
18 use connection::le_manager::InactiveLeAclManager;
19 use gatt::{channel::AttTransport, GattCallbacks};
20 use log::{info, warn};
21 use tokio::task::LocalSet;
22 
23 use self::core::shared_box::SharedBox;
24 use std::{rc::Rc, sync::Mutex};
25 use tokio::runtime::Builder;
26 
27 use tokio::sync::mpsc;
28 
29 #[cfg(feature = "via_android_bp")]
30 mod do_not_use {
31     // DO NOT USE
32     #[allow(unused)]
33     use bt_shim::*;
34 }
35 
36 pub mod connection;
37 pub mod core;
38 pub mod gatt;
39 pub mod packets;
40 pub mod utils;
41 
42 /// The owner of the main Rust thread on which all Rust modules run
43 struct GlobalModuleRegistry {
44     pub task_tx: MainThreadTx,
45 }
46 
47 /// The ModuleViews lets us access all publicly accessible Rust modules from
48 /// Java / C++ while the stack is running. If a module should not be exposed
49 /// outside of Rust GD, there is no need to include it here.
50 pub struct ModuleViews<'a> {
51     /// Lets us call out into C++
52     pub gatt_outgoing_callbacks: Rc<dyn GattCallbacks>,
53     /// Receives synchronous callbacks from JNI
54     pub gatt_incoming_callbacks: Rc<gatt::callbacks::CallbackTransactionManager>,
55     /// Proxies calls into GATT server
56     pub gatt_module: &'a mut gatt::server::GattModule,
57     /// Proxies calls into connection manager
58     pub connection_manager: SharedBox<connection::ConnectionManager>,
59 }
60 
61 static GLOBAL_MODULE_REGISTRY: Mutex<Option<GlobalModuleRegistry>> = Mutex::new(None);
62 
63 impl GlobalModuleRegistry {
64     /// Handles bringup of all Rust modules. This occurs after GD C++ modules
65     /// have started, but before the legacy stack has initialized.
66     /// Must be invoked from the Rust thread after JNI initializes it and passes
67     /// in JNI modules.
start( gatt_callbacks: Rc<dyn GattCallbacks>, att_transport: Rc<dyn AttTransport>, le_acl_manager: impl InactiveLeAclManager, on_started: impl FnOnce(), )68     pub fn start(
69         gatt_callbacks: Rc<dyn GattCallbacks>,
70         att_transport: Rc<dyn AttTransport>,
71         le_acl_manager: impl InactiveLeAclManager,
72         on_started: impl FnOnce(),
73     ) {
74         info!("starting Rust modules");
75         let rt = Builder::new_current_thread()
76             .enable_all()
77             .build()
78             .expect("failed to start tokio runtime");
79         let local = LocalSet::new();
80 
81         let (tx, mut rx) = mpsc::unbounded_channel();
82         let prev_registry = GLOBAL_MODULE_REGISTRY.lock().unwrap().replace(Self { task_tx: tx });
83 
84         // initialization should only happen once
85         assert!(prev_registry.is_none());
86 
87         // First, setup FFI and C++ modules
88         let arbiter = gatt::arbiter::initialize_arbiter();
89         connection::register_callbacks();
90 
91         // Now enter the runtime
92         local.block_on(&rt, async move {
93             // Then follow the pure-Rust modules
94             let gatt_incoming_callbacks =
95                 Rc::new(gatt::callbacks::CallbackTransactionManager::new(gatt_callbacks.clone()));
96             let gatt_module = &mut gatt::server::GattModule::new(att_transport.clone(), arbiter);
97 
98             let connection_manager = connection::ConnectionManager::new(le_acl_manager);
99 
100             // All modules that are visible from incoming JNI / top-level interfaces should
101             // be exposed here
102             let mut modules = ModuleViews {
103                 gatt_outgoing_callbacks: gatt_callbacks,
104                 gatt_incoming_callbacks,
105                 gatt_module,
106                 connection_manager,
107             };
108 
109             // notify upper layer that we are ready to receive messages
110             on_started();
111 
112             // This is the core event loop that serializes incoming requests into the Rust
113             // thread do_in_rust_thread lets us post into here from foreign
114             // threads
115             info!("starting Tokio event loop");
116             while let Some(message) = rx.recv().await {
117                 match message {
118                     MainThreadTxMessage::Callback(f) => f(&mut modules),
119                     MainThreadTxMessage::Stop => {
120                         break;
121                     }
122                 }
123             }
124         });
125         warn!("Rust thread queue has stopped, shutting down executor thread");
126         GLOBAL_MODULE_REGISTRY.lock().unwrap().take();
127         gatt::arbiter::clean_arbiter();
128     }
129 }
130 
131 type BoxedMainThreadCallback = Box<dyn for<'a> FnOnce(&'a mut ModuleViews) + Send + 'static>;
132 enum MainThreadTxMessage {
133     Callback(BoxedMainThreadCallback),
134     Stop,
135 }
136 type MainThreadTx = mpsc::UnboundedSender<MainThreadTxMessage>;
137 
138 thread_local! {
139     /// The TX end of a channel into the Rust thread, so external callers can
140     /// access Rust modules. JNI / direct FFI should use do_in_rust_thread for
141     /// convenience, but objects passed into C++ as callbacks should
142     /// clone this channel to fail loudly if it's not yet initialized.
143     ///
144     /// This will be lazily initialized on first use from each client thread
145     static MAIN_THREAD_TX: MainThreadTx =
146         GLOBAL_MODULE_REGISTRY.lock().unwrap().as_ref().expect("stack not initialized").task_tx.clone();
147 }
148 
149 /// Posts a callback to the Rust thread and gives it access to public Rust
150 /// modules, used from JNI.
151 ///
152 /// Do not call this from Rust modules / the Rust thread! Instead, Rust modules
153 /// should receive references to their dependent modules at startup. If passing
154 /// callbacks into C++, don't use this method either - instead, acquire a clone
155 /// of MAIN_THREAD_TX when the callback is created. This ensures that there
156 /// never are "invalid" callbacks that may still work depending on when the
157 /// GLOBAL_MODULE_REGISTRY is initialized.
do_in_rust_thread<F>(f: F) where F: for<'a> FnOnce(&'a mut ModuleViews) + Send + 'static,158 pub fn do_in_rust_thread<F>(f: F)
159 where
160     F: for<'a> FnOnce(&'a mut ModuleViews) + Send + 'static,
161 {
162     let ret = MAIN_THREAD_TX.with(|tx| tx.send(MainThreadTxMessage::Callback(Box::new(f))));
163     if ret.is_err() {
164         panic!("Rust call failed");
165     }
166 }
167