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