1use anyhow::{Context as _, Error};
6use fidl_fuchsia_testing_sl4f::{
7 FacadeIteratorMarker, FacadeIteratorSynchronousProxy, FacadeProviderMarker, FacadeProviderProxy,
8};
9use fuchsia_component::client::connect_to_protocol;
10use fuchsia_sync::RwLock;
11use http_body_util::{BodyExt as _, Full};
12use log::{error, info, warn};
13use maplit::{convert_args, hashmap};
14use serde_json::{Value, json};
15use std::collections::{HashMap, HashSet};
16use std::sync::Arc;
17pub type Body = Full<hyper::body::Bytes>;
18
19use crate::bluetooth::avrcp_facade::AvrcpFacade;
21use crate::server::sl4f_types::{
22 AsyncCommandRequest, AsyncRequest, ClientData, CommandRequest, CommandResponse, Facade,
23 MethodId, RequestId,
24};
25
26use crate::audio::commands::AudioFacade;
28
29use crate::modular::facade::ModularFacade;
31
32use crate::bluetooth::a2dp_facade::A2dpFacade;
34use crate::bluetooth::avdtp_facade::AvdtpFacade;
35use crate::bluetooth::ble_advertise_facade::BleAdvertiseFacade;
36use crate::bluetooth::bt_sys_facade::BluetoothSysFacade;
37use crate::bluetooth::gatt_client_facade::GattClientFacade;
38use crate::bluetooth::gatt_server_facade::GattServerFacade;
39use test_call_manager::TestCallManager as HfpFacade;
40use test_rfcomm_client::RfcommManager as RfcommFacade;
41
42use crate::bluetooth::profile_server_facade::ProfileServerFacade;
43
44use crate::common_utils::common::{read_json_from_vmo, write_json_to_vmo};
46use crate::common_utils::error::Sl4fError;
47
48use crate::component::facade::ComponentFacade;
50
51use crate::device::facade::DeviceFacade;
53
54use crate::diagnostics::facade::DiagnosticsFacade;
56
57use crate::factory_reset::facade::FactoryResetFacade;
59
60use crate::factory_store::facade::FactoryStoreFacade;
62
63use crate::feedback_data_provider::facade::FeedbackDataProviderFacade;
65
66use crate::file::facade::FileFacade;
68
69use crate::hardware_power_statecontrol::facade::HardwarePowerStatecontrolFacade;
71
72use crate::hwinfo::facade::HwinfoFacade;
74
75use crate::input::facade::InputFacade;
77
78use crate::location::emergency_provider_facade::EmergencyProviderFacade;
80use crate::location::regulatory_region_facade::RegulatoryRegionFacade;
81
82use crate::logging::facade::LoggingFacade;
84
85use crate::media_session::facade::MediaSessionFacade;
87
88use crate::netstack::facade::NetstackFacade;
90
91use crate::paver::facade::PaverFacade;
93
94use crate::power::facade::PowerFacade;
96
97use crate::proxy::facade::ProxyFacade;
99
100use crate::scenic::facade::ScenicFacade;
102
103use crate::setui::facade::SetUiFacade;
105
106use crate::system_metrics::facade::SystemMetricsFacade;
108
109use crate::temperature::facade::TemperatureFacade;
111
112use crate::time::facade::TimeFacade;
114
115use crate::traceutil::facade::TraceutilFacade;
117
118use crate::tracing::facade::TracingFacade;
120
121use crate::virtual_camera::facade::VirtualCameraFacade;
123
124use crate::weave::facade::WeaveFacade;
126
127use crate::webdriver::facade::WebdriverFacade;
129
130use crate::wlan::facade::WlanFacade;
132
133use crate::wlan_policy::facade::WlanPolicyFacade;
135
136use crate::wpan::facade::WpanFacade;
138
139#[derive(Debug)]
143pub struct Sl4f {
144 facades: HashMap<String, Arc<dyn Facade>>,
146
147 facade_provider: FacadeProviderProxy,
151
152 proxied_facades: HashSet<String>,
154
155 clients: Arc<RwLock<Sl4fClients>>,
157}
158
159impl Sl4f {
160 pub fn new(clients: Arc<RwLock<Sl4fClients>>) -> Result<Sl4f, Error> {
161 fn to_arc_trait_object<'a, T: Facade + 'a>(facade: T) -> Arc<dyn Facade + 'a> {
162 Arc::new(facade) as Arc<dyn Facade>
163 }
164 let facades = convert_args!(
169 keys = String::from,
170 values = to_arc_trait_object,
171 hashmap!(
172 "a2dp_facade" => A2dpFacade::new(),
173 "audio_facade" => AudioFacade::new()?,
174 "avdtp_facade" => AvdtpFacade::new(),
175 "avrcp_facade" => AvrcpFacade::new(),
176 "basemgr_facade" => ModularFacade::new(),
178 "modular_facade" => ModularFacade::new(),
179 "ble_advertise_facade" => BleAdvertiseFacade::new(),
180 "bt_sys_facade" => BluetoothSysFacade::new(),
181 "component_facade" => ComponentFacade::new(),
182 "diagnostics_facade" => DiagnosticsFacade::new(),
183 "device_facade" => DeviceFacade::new(),
184 "factory_reset_facade" => FactoryResetFacade::new(),
185 "factory_store_facade" => FactoryStoreFacade::new(),
186 "feedback_data_provider_facade" => FeedbackDataProviderFacade::new(),
187 "file_facade" => FileFacade::new(),
188 "gatt_client_facade" => GattClientFacade::new(),
189 "gatt_server_facade" => GattServerFacade::new(),
190 "hardware_power_statecontrol_facade" => HardwarePowerStatecontrolFacade::new(),
191 "hfp_facade" => HfpFacade::new(),
192 "hwinfo_facade" => HwinfoFacade::new(),
193 "input_facade" => InputFacade::new(),
194 "location_emergency_provider_facade" => EmergencyProviderFacade::new()?,
195 "location_regulatory_region_facade" => RegulatoryRegionFacade::new()?,
196 "logging_facade" => LoggingFacade::new(),
197 "media_session_facade" => MediaSessionFacade::new(),
198 "netstack_facade" => NetstackFacade::default(),
199 "rfcomm_facade" => RfcommFacade::new()?,
200 "paver" => PaverFacade::new(),
201 "power_facade" => PowerFacade::new(),
202 "profile_server_facade" => ProfileServerFacade::new(),
203 "proxy_facade" => ProxyFacade::new(),
204 "scenic_facade" => ScenicFacade::new(),
205 "setui_facade" => SetUiFacade::new(),
206 "system_metrics_facade" => SystemMetricsFacade::new(),
207 "temperature_facade" => TemperatureFacade::new(),
208 "time_facade" => TimeFacade::new(),
209 "traceutil_facade" => TraceutilFacade::new(),
210 "tracing_facade" => TracingFacade::new(),
211 "virtual_camera_facade" => VirtualCameraFacade::new(),
212 "weave_facade" => WeaveFacade::new(),
213 "webdriver_facade" => WebdriverFacade::new(),
214 "wlan" => WlanFacade::new()?,
215 "wlan_policy" => WlanPolicyFacade::new()?,
216 "wpan_facade" => WpanFacade::new(),
217 )
218 );
219
220 let mut proxied_facades = HashSet::<String>::new();
222 let facade_provider = match connect_to_protocol::<FacadeProviderMarker>() {
223 Ok(proxy) => proxy,
224 Err(error) => {
225 error!(error:%; "Failed to connect to FacadeProvider");
226 return Err(error.into());
227 }
228 };
229 let (client_end, server_end) = fidl::endpoints::create_endpoints::<FacadeIteratorMarker>();
234 match facade_provider.get_facades(server_end) {
235 Ok(_) => {
236 let facade_iter = FacadeIteratorSynchronousProxy::new(client_end.into_channel());
237 loop {
238 match facade_iter.get_next(zx::MonotonicInstant::INFINITE) {
239 Ok(facades) if facades.is_empty() => break, Ok(facades) => proxied_facades.extend(facades.into_iter()),
241 Err(error) if error.is_closed() && proxied_facades.is_empty() => {
244 break;
245 }
246 Err(error) => {
247 error!(error:%; "Failed to get proxied facade list");
248 proxied_facades.clear();
249 break;
250 }
251 };
252 }
253 }
254 Err(error) if error.is_closed() => (),
256 Err(error) => {
257 error!(error:%; "Failed to get FacadeIterator");
258 return Err(error.into());
259 }
260 };
261
262 Ok(Sl4f { facades, facade_provider, proxied_facades, clients })
263 }
264
265 pub fn get_facade(&self, name: &str) -> Option<Arc<dyn Facade>> {
267 self.facades.get(name).map(Arc::clone)
268 }
269
270 pub async fn cleanup(&self) {
272 for facade in self.facades.values() {
273 facade.cleanup();
274 }
275 if !self.proxied_facades.is_empty() {
277 if let Err(error) = self.facade_provider.cleanup().await {
278 error!(error:%; "Failed to execute Cleanup()");
279 }
280 }
281 self.clients.write().cleanup_clients();
282 }
283
284 pub fn print_clients(&self) {
285 self.clients.read().print_clients();
286 }
287
288 pub async fn print(&self) {
290 for facade in self.facades.values() {
291 facade.print();
292 }
293 if !self.proxied_facades.is_empty() {
295 if let Err(error) = self.facade_provider.print().await {
296 error!(error:%; "Failed to execute Print()");
297 }
298 }
299 }
300
301 pub fn has_proxy_facade(&self, name: &str) -> bool {
305 self.proxied_facades.contains(name)
306 }
307
308 pub async fn handle_proxy_request(
315 &self,
316 facade: String,
317 command: String,
318 args: Value,
319 ) -> Result<Value, Error> {
320 let encode_params = async {
322 let params_blob = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, 0)?;
323 write_json_to_vmo(¶ms_blob, &args)?;
324 Ok::<zx::Vmo, Error>(params_blob)
325 };
326 let params_blob = match encode_params.await {
327 Ok(params_blob) => params_blob,
328 Err(error) => {
329 return Err(
330 Sl4fError::new(&format!("Failed to write params with: {}", error)).into()
331 );
332 }
333 };
334
335 match self.facade_provider.execute(&facade, &command, params_blob).await {
337 Ok((None, None)) => Ok(Value::Null),
339 Ok((Some(vmo), None)) => match read_json_from_vmo(&vmo) {
341 Ok(result) => Ok(result),
342 Err(error) => {
343 Err(Sl4fError::new(&format!("Failed to read result with: {}", error)).into())
344 }
345 },
346 Ok((_, Some(string))) => Err(Sl4fError::new(&string).into()),
348 Err(error) => {
349 Err(Sl4fError::new(&format!("Failed to send command with {}", error)).into())
350 }
351 }
352 }
353}
354
355#[derive(Debug)]
357pub struct Sl4fClients {
358 clients: HashMap<String, Vec<ClientData>>,
362}
363
364impl Sl4fClients {
365 pub fn new() -> Self {
366 Self { clients: HashMap::new() }
367 }
368
369 fn init_client(&mut self, id: String) -> bool {
371 use std::collections::hash_map::Entry::*;
372 match self.clients.entry(id) {
373 Occupied(entry) => {
374 warn!(tag = "client_init"; "Key: {:?} already exists in clients. ", entry.key());
375 true
376 }
377 Vacant(entry) => {
378 entry.insert(Vec::new());
379 info!(tag = "client_init"; "Updated clients: {:?}", self.clients);
380 false
381 }
382 }
383 }
384
385 fn cleanup_clients(&mut self) {
386 self.clients.clear();
387 }
388
389 fn print_clients(&self) {
390 info!("SL4F Clients: {:?}", self.clients);
391 }
392}
393
394fn json<T>(content: &T) -> hyper::Response<Body>
395where
396 T: serde::Serialize,
397{
398 use std::convert::TryInto as _;
399
400 let application_json = "application/json".try_into().expect("json header value");
401 let data = serde_json::to_string(content).expect("encode json");
402
403 let mut response = hyper::Response::new(Full::new(data.into()));
404 assert_eq!(response.headers_mut().insert(hyper::header::CONTENT_TYPE, application_json), None);
405 response
406}
407
408pub async fn serve(
410 request: hyper::Request<hyper::body::Incoming>,
411 clients: Arc<RwLock<Sl4fClients>>,
412 sender: async_channel::Sender<AsyncRequest>,
413) -> hyper::Response<Body> {
414 use hyper::Method;
415
416 match (request.method(), request.uri().path()) {
417 (&Method::GET, "/") => {
418 info!(tag = "serve"; "Received command request via GET.");
420 client_request(request, &sender).await
421 }
422 (&Method::POST, "/") => {
423 info!(tag = "serve"; "Received command request via POST.");
425 client_request(request, &sender).await
426 }
427 (&Method::GET, "/init") => {
428 info!(tag = "serve"; "Received init request.");
430 client_init(request, &clients).await
431 }
432 (&Method::GET, "/print_clients") => {
433 info!(tag = "serve"; "Received print client request.");
435 const PRINT_ACK: &str = "Successfully printed clients.";
436 json(&PRINT_ACK)
437 }
438 (&Method::GET, "/cleanup") => {
439 info!(tag = "serve"; "Received server cleanup request.");
440 server_cleanup(request, &sender).await
441 }
442 _ => {
443 error!(tag = "serve"; "Received unknown server request.");
444 const FAIL_REQUEST_ACK: &str = "Unknown GET request.";
445 let res = CommandResponse::new(json!(""), None, Some(FAIL_REQUEST_ACK.to_string()));
446 json(&res)
447 }
448 }
449}
450
451async fn client_request(
454 request: hyper::Request<hyper::body::Incoming>,
455 sender: &async_channel::Sender<AsyncRequest>,
456) -> hyper::Response<Body> {
457 const FAIL_TEST_ACK: &str = "Command failed";
458
459 let (request_id, method_id, method_params) = match parse_request(request).await {
460 Ok(res) => res,
461 Err(error) => {
462 error!(tag = "client_request", error:?; "Failed to parse request");
463 return json(&FAIL_TEST_ACK);
464 }
465 };
466
467 let (async_sender, receiver) = futures::channel::oneshot::channel();
470 let req = AsyncCommandRequest::new(async_sender, method_id.clone(), method_params);
471 sender.send(AsyncRequest::Command(req)).await.expect("Failed to send request to async thread.");
472 let resp = receiver.await.expect("Async thread dropped responder.");
473
474 info!(
475 tag = "client_request",
476 method:? = method_id.method,
477 response:? = resp;
478 "Received async thread response"
479 );
480
481 match resp.result {
483 Some(async_res) => {
484 let res = CommandResponse::new(request_id.into_response_id(), Some(async_res), None);
485 json(&res)
486 }
487 None => {
488 let res = CommandResponse::new(request_id.into_response_id(), None, resp.error);
489 json(&res)
490 }
491 }
492}
493
494async fn client_init(
496 request: hyper::Request<hyper::body::Incoming>,
497 clients: &Arc<RwLock<Sl4fClients>>,
498) -> hyper::Response<Body> {
499 const INIT_ACK: &str = "Recieved init request.";
500 const FAIL_INIT_ACK: &str = "Failed to init client.";
501
502 let (_, _, method_params) = match parse_request(request).await {
503 Ok(res) => res,
504 Err(_) => return json(&FAIL_INIT_ACK),
505 };
506
507 let client_id_raw = match method_params.get("client_id") {
508 Some(id) => Some(id).unwrap().clone(),
509 None => return json(&FAIL_INIT_ACK),
510 };
511
512 let client_id = client_id_raw.as_str().map(String::from).unwrap();
514
515 if clients.write().init_client(client_id) { json(&FAIL_INIT_ACK) } else { json(&INIT_ACK) }
516}
517
518async fn parse_request(
521 request: hyper::Request<hyper::body::Incoming>,
522) -> Result<(RequestId, MethodId, Value), Error> {
523 use bytes::Buf as _;
524
525 let body = request.into_body().collect().await.context("read request")?.aggregate();
526
527 let request_data: CommandRequest = match serde_json::from_reader(body.reader()) {
529 Ok(tdata) => tdata,
530 Err(_) => return Err(Sl4fError::new("Failed to unpack request data.").into()),
531 };
532
533 let request_id_raw = request_data.id;
534 let method_id_raw = request_data.method;
535 let method_params = request_data.params;
536 info!(tag = "parse_request",
537 request_id:? = request_id_raw,
538 name:? = method_id_raw,
539 args:? = method_params;
540 ""
541 );
542
543 let request_id = RequestId::new(request_id_raw);
544 let method_id = method_id_raw.parse().unwrap_or_default();
547 Ok((request_id, method_id, method_params))
548}
549
550async fn server_cleanup(
551 request: hyper::Request<hyper::body::Incoming>,
552 sender: &async_channel::Sender<AsyncRequest>,
553) -> hyper::Response<Body> {
554 const FAIL_CLEANUP_ACK: &str = "Failed to cleanup SL4F resources.";
555 const CLEANUP_ACK: &str = "Successful cleanup of SL4F resources.";
556
557 info!(tag = "server_cleanup"; "Cleaning up server state");
558 let (request_id, _, _) = match parse_request(request).await {
559 Ok(res) => res,
560 Err(_) => return json(&FAIL_CLEANUP_ACK),
561 };
562
563 let (async_sender, receiver) = futures::channel::oneshot::channel();
565
566 sender
568 .send(AsyncRequest::Cleanup(async_sender))
569 .await
570 .expect("Failed to send request to async thread.");
571 let () = receiver.await.expect("Async thread dropped responder.");
572
573 let ack = CommandResponse::new(request_id.into_response_id(), Some(json!(CLEANUP_ACK)), None);
574 json(&ack)
575}