1 //! Starts the facade services that allow us to test the Bluetooth stack
2
3 use bt_topshim::btif;
4
5 use clap::{value_parser, Arg, Command};
6 use futures::channel::mpsc;
7 use futures::executor::block_on;
8 use futures::stream::StreamExt;
9 use grpcio::*;
10 use log::debug;
11 use nix::sys::signal;
12 use std::sync::{Arc, Mutex};
13 use tokio::runtime::Runtime;
14
15 mod adapter_service;
16 mod gatt_service;
17 mod hf_client_service;
18 mod hfp_service;
19 mod media_service;
20 mod security_service;
21 mod utils;
22
23 // This is needed for linking, libbt_shim_bridge needs symbols defined by
24 // bt_shim, however bt_shim depends on rust crates (future, tokio) that
25 // we use too, if we build and link them separately we ends with duplicate
26 // symbols. To solve that we build bt_shim with bt_topshim_facade so the rust
27 // compiler share the transitive dependencies.
28 //
29 // The `::*` is here to circuvent the single_component_path_imports from
30 // clippy that is denied on the rust command line so we can't just allow it.
31 // This is fine for now since bt_shim doesn't export anything
32 #[allow(unused)]
33 use bluetooth_core_rs_for_facade::*;
34
main()35 fn main() {
36 // SAFETY: There is no signal handler installed before this.
37 let sigint = unsafe { install_sigint() };
38 bt_common::init_logging();
39 let rt = Arc::new(Runtime::new().unwrap());
40 rt.block_on(async_main(Arc::clone(&rt), sigint));
41 }
42
clap_command() -> Command43 fn clap_command() -> Command {
44 Command::new("bluetooth_topshim_facade")
45 .about("The bluetooth topshim stack, with testing facades enabled and exposed via gRPC.")
46 .arg(
47 Arg::new("grpc-port")
48 .long("grpc-port")
49 .value_parser(value_parser!(u16))
50 .default_value("8899"),
51 )
52 .arg(
53 Arg::new("root-server-port")
54 .long("root-server-port")
55 .value_parser(value_parser!(u16))
56 .default_value("8897"),
57 )
58 .arg(
59 Arg::new("signal-port")
60 .long("signal-port")
61 .value_parser(value_parser!(u16))
62 .default_value("8895"),
63 )
64 .arg(Arg::new("rootcanal-port").long("rootcanal-port").value_parser(value_parser!(u16)))
65 .arg(Arg::new("btsnoop").long("btsnoop"))
66 .arg(Arg::new("btsnooz").long("btsnooz"))
67 .arg(Arg::new("btconfig").long("btconfig"))
68 .arg(
69 Arg::new("start-stack-now")
70 .long("start-stack-now")
71 .value_parser(value_parser!(bool))
72 .default_value("true"),
73 )
74 }
75
async_main(rt: Arc<Runtime>, mut sigint: mpsc::UnboundedReceiver<()>)76 async fn async_main(rt: Arc<Runtime>, mut sigint: mpsc::UnboundedReceiver<()>) {
77 let matches = clap_command().get_matches();
78
79 let grpc_port = *matches.get_one::<u16>("grpc-port").unwrap();
80 let _rootcanal_port = matches.get_one::<u16>("rootcanal-port").cloned();
81 let env = Arc::new(Environment::new(2));
82
83 let btif_intf = Arc::new(Mutex::new(btif::get_btinterface()));
84
85 // AdapterServiceImpl::create initializes the stack; not the best practice because the side effect is hidden
86 let adapter_service_impl =
87 adapter_service::AdapterServiceImpl::create(rt.clone(), btif_intf.clone());
88
89 let security_service_impl =
90 security_service::SecurityServiceImpl::create(rt.clone(), btif_intf.clone());
91
92 let gatt_service_impl = gatt_service::GattServiceImpl::create(rt.clone(), btif_intf.clone());
93
94 let hf_client_service_impl =
95 hf_client_service::HfClientServiceImpl::create(rt.clone(), btif_intf.clone());
96
97 let hfp_service_impl = hfp_service::HfpServiceImpl::create(rt.clone(), btif_intf.clone());
98
99 let media_service_impl = media_service::MediaServiceImpl::create(rt.clone(), btif_intf.clone());
100
101 let start_stack_now = *matches.get_one::<bool>("start-stack-now").unwrap();
102
103 if start_stack_now {
104 btif_intf.clone().lock().unwrap().enable();
105 }
106
107 let mut server = ServerBuilder::new(env)
108 .register_service(adapter_service_impl)
109 .register_service(security_service_impl)
110 .register_service(gatt_service_impl)
111 .register_service(hf_client_service_impl)
112 .register_service(hfp_service_impl)
113 .register_service(media_service_impl)
114 .build()
115 .unwrap();
116 let addr = format!("0.0.0.0:{}", grpc_port);
117 let creds = ServerCredentials::insecure();
118 server.add_listening_port(addr, creds).unwrap();
119 server.start();
120
121 sigint.next().await;
122 block_on(server.shutdown()).unwrap();
123 }
124
125 // TODO: remove as this is a temporary nix-based hack to catch SIGINT
126 /// # Safety
127 ///
128 /// The old signal handler, if any, must be installed correctly.
install_sigint() -> mpsc::UnboundedReceiver<()>129 unsafe fn install_sigint() -> mpsc::UnboundedReceiver<()> {
130 let (tx, rx) = mpsc::unbounded();
131 *SIGINT_TX.lock().unwrap() = Some(tx);
132
133 let sig_action = signal::SigAction::new(
134 signal::SigHandler::Handler(handle_sigint),
135 signal::SaFlags::empty(),
136 signal::SigSet::empty(),
137 );
138 // SAFETY: The caller guarantees that the old signal handler was installed correctly.
139 // TODO(b/292218119): Make sure `handle_sigint` only makes system calls that are safe for signal
140 // handlers, and only accesses global state through atomics. In particular, it must not take any
141 // shared locks.
142 unsafe {
143 signal::sigaction(signal::SIGINT, &sig_action).unwrap();
144 }
145
146 rx
147 }
148
149 static SIGINT_TX: Mutex<Option<mpsc::UnboundedSender<()>>> = Mutex::new(None);
150
handle_sigint(_: i32)151 extern "C" fn handle_sigint(_: i32) {
152 let mut sigint_tx = SIGINT_TX.lock().unwrap();
153 if let Some(tx) = &*sigint_tx {
154 debug!("Stopping gRPC root server due to SIGINT");
155 tx.unbounded_send(()).unwrap();
156 }
157 *sigint_tx = None;
158 }
159
160 #[cfg(test)]
161 mod tests {
162 use super::*;
163
164 #[test]
verify_comand()165 fn verify_comand() {
166 clap_command().debug_assert();
167 }
168 }
169