• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 bt_common::init_flags::rust_event_loop_is_enabled;
19 use connection::le_manager::InactiveLeAclManager;
20 use gatt::{channel::AttTransport, GattCallbacks};
21 use log::{info, warn};
22 use tokio::task::LocalSet;
23 
24 use self::core::shared_box::SharedBox;
25 use std::{rc::Rc, sync::Mutex};
26 use tokio::runtime::Builder;
27 
28 use tokio::sync::mpsc;
29 
30 #[cfg(feature = "via_android_bp")]
31 mod do_not_use {
32     // DO NOT USE
33     #[allow(unused)]
34     use bt_shim::*;
35 }
36 
37 pub mod connection;
38 pub mod core;
39 pub mod gatt;
40 pub mod packets;
41 pub mod utils;
42 
43 /// The owner of the main Rust thread on which all Rust modules run
44 struct GlobalModuleRegistry {
45     pub task_tx: MainThreadTx,
46 }
47 
48 /// The ModuleViews lets us access all publicly accessible Rust modules from
49 /// Java / C++ while the stack is running. If a module should not be exposed
50 /// outside of Rust GD, there is no need to include it here.
51 pub struct ModuleViews<'a> {
52     /// Lets us call out into C++
53     pub gatt_outgoing_callbacks: Rc<dyn GattCallbacks>,
54     /// Receives synchronous callbacks from JNI
55     pub gatt_incoming_callbacks: Rc<gatt::callbacks::CallbackTransactionManager>,
56     /// Proxies calls into GATT server
57     pub gatt_module: &'a mut gatt::server::GattModule,
58     /// Proxies calls into connection manager
59     pub connection_manager: SharedBox<connection::ConnectionManager>,
60 }
61 
62 static GLOBAL_MODULE_REGISTRY: Mutex<Option<GlobalModuleRegistry>> = Mutex::new(None);
63 
64 impl GlobalModuleRegistry {
65     /// Handles bringup of all Rust modules. This occurs after GD C++ modules
66     /// have started, but before the legacy stack has initialized.
67     /// Must be invoked from the Rust thread after JNI initializes it and passes
68     /// in JNI modules.
start( gatt_callbacks: Rc<dyn GattCallbacks>, att_transport: Rc<dyn AttTransport>, le_acl_manager: impl InactiveLeAclManager, on_started: impl FnOnce(), )69     pub fn start(
70         gatt_callbacks: Rc<dyn GattCallbacks>,
71         att_transport: Rc<dyn AttTransport>,
72         le_acl_manager: impl InactiveLeAclManager,
73         on_started: impl FnOnce(),
74     ) {
75         info!("starting Rust modules");
76         let rt = Builder::new_current_thread()
77             .enable_all()
78             .build()
79             .expect("failed to start tokio runtime");
80         let local = LocalSet::new();
81 
82         let (tx, mut rx) = mpsc::unbounded_channel();
83         let prev_registry = GLOBAL_MODULE_REGISTRY.lock().unwrap().replace(Self { task_tx: tx });
84 
85         // initialization should only happen once
86         assert!(prev_registry.is_none());
87 
88         // First, setup FFI and C++ modules
89         gatt::arbiter::initialize_arbiter();
90         connection::register_callbacks();
91 
92         // Now enter the runtime
93         local.block_on(&rt, async {
94             // Then follow the pure-Rust modules
95             let gatt_incoming_callbacks =
96                 Rc::new(gatt::callbacks::CallbackTransactionManager::new(gatt_callbacks.clone()));
97             let gatt_module = &mut gatt::server::GattModule::new(att_transport.clone());
98 
99             let connection_manager = connection::ConnectionManager::new(le_acl_manager);
100 
101             // All modules that are visible from incoming JNI / top-level interfaces should
102             // be exposed here
103             let mut modules = ModuleViews {
104                 gatt_outgoing_callbacks: gatt_callbacks,
105                 gatt_incoming_callbacks,
106                 gatt_module,
107                 connection_manager,
108             };
109 
110             // notify upper layer that we are ready to receive messages
111             on_started();
112 
113             // This is the core event loop that serializes incoming requests into the Rust
114             // thread do_in_rust_thread lets us post into here from foreign
115             // threads
116             info!("starting Tokio event loop");
117             while let Some(message) = rx.recv().await {
118                 match message {
119                     MainThreadTxMessage::Callback(f) => f(&mut modules),
120                     MainThreadTxMessage::Stop => {
121                         GLOBAL_MODULE_REGISTRY.lock().unwrap().take();
122                         break;
123                     }
124                 }
125             }
126         });
127         warn!("Rust thread queue has stopped, shutting down executor thread");
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     if !rust_event_loop_is_enabled() {
163         warn!("ignoring do_in_rust_thread() invocation since Rust loop is inactive");
164         return;
165     }
166     let ret = MAIN_THREAD_TX.with(|tx| tx.send(MainThreadTxMessage::Callback(Box::new(f))));
167     if ret.is_err() {
168         panic!("Rust call failed");
169     }
170 }
171