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 log::{error, info, warn};
12use maplit::{convert_args, hashmap};
13use serde_json::{json, Value};
14use std::collections::{HashMap, HashSet};
15use std::sync::Arc;
16
17use crate::bluetooth::avrcp_facade::AvrcpFacade;
19use crate::server::sl4f_types::{
20 AsyncCommandRequest, AsyncRequest, ClientData, CommandRequest, CommandResponse, Facade,
21 MethodId, RequestId,
22};
23
24use crate::audio::commands::AudioFacade;
26
27use crate::modular::facade::ModularFacade;
29
30use crate::bluetooth::a2dp_facade::A2dpFacade;
32use crate::bluetooth::avdtp_facade::AvdtpFacade;
33use crate::bluetooth::ble_advertise_facade::BleAdvertiseFacade;
34use crate::bluetooth::bt_sys_facade::BluetoothSysFacade;
35use crate::bluetooth::gatt_client_facade::GattClientFacade;
36use crate::bluetooth::gatt_server_facade::GattServerFacade;
37use test_call_manager::TestCallManager as HfpFacade;
38use test_rfcomm_client::RfcommManager as RfcommFacade;
39
40use crate::bluetooth::profile_server_facade::ProfileServerFacade;
41
42use crate::common_utils::common::{read_json_from_vmo, write_json_to_vmo};
44use crate::common_utils::error::Sl4fError;
45
46use crate::component::facade::ComponentFacade;
48
49use crate::device::facade::DeviceFacade;
51
52use crate::diagnostics::facade::DiagnosticsFacade;
54
55use crate::factory_reset::facade::FactoryResetFacade;
57
58use crate::factory_store::facade::FactoryStoreFacade;
60
61use crate::feedback_data_provider::facade::FeedbackDataProviderFacade;
63
64use crate::file::facade::FileFacade;
66
67use crate::hardware_power_statecontrol::facade::HardwarePowerStatecontrolFacade;
69
70use crate::hwinfo::facade::HwinfoFacade;
72
73use crate::input::facade::InputFacade;
75
76use crate::location::emergency_provider_facade::EmergencyProviderFacade;
78use crate::location::regulatory_region_facade::RegulatoryRegionFacade;
79
80use crate::logging::facade::LoggingFacade;
82
83use crate::media_session::facade::MediaSessionFacade;
85
86use crate::netstack::facade::NetstackFacade;
88
89use crate::paver::facade::PaverFacade;
91
92use crate::power::facade::PowerFacade;
94
95use crate::proxy::facade::ProxyFacade;
97
98use crate::scenic::facade::ScenicFacade;
100
101use crate::setui::facade::SetUiFacade;
103
104use crate::system_metrics::facade::SystemMetricsFacade;
106
107use crate::temperature::facade::TemperatureFacade;
109
110use crate::time::facade::TimeFacade;
112
113use crate::traceutil::facade::TraceutilFacade;
115
116use crate::tracing::facade::TracingFacade;
118
119use crate::virtual_camera::facade::VirtualCameraFacade;
121
122use crate::weave::facade::WeaveFacade;
124
125use crate::webdriver::facade::WebdriverFacade;
127
128use crate::wlan::facade::WlanFacade;
130
131use crate::wlan_deprecated::facade::WlanDeprecatedConfigurationFacade;
133
134use crate::wlan_phy::facade::WlanPhyFacade;
136
137use crate::wlan_policy::ap_facade::WlanApPolicyFacade;
139use crate::wlan_policy::facade::WlanPolicyFacade;
140
141use crate::wpan::facade::WpanFacade;
143
144#[derive(Debug)]
148pub struct Sl4f {
149 facades: HashMap<String, Arc<dyn Facade>>,
151
152 facade_provider: FacadeProviderProxy,
156
157 proxied_facades: HashSet<String>,
159
160 clients: Arc<RwLock<Sl4fClients>>,
162}
163
164impl Sl4f {
165 pub fn new(clients: Arc<RwLock<Sl4fClients>>) -> Result<Sl4f, Error> {
166 fn to_arc_trait_object<'a, T: Facade + 'a>(facade: T) -> Arc<dyn Facade + 'a> {
167 Arc::new(facade) as Arc<dyn Facade>
168 }
169 let facades = convert_args!(
174 keys = String::from,
175 values = to_arc_trait_object,
176 hashmap!(
177 "a2dp_facade" => A2dpFacade::new(),
178 "audio_facade" => AudioFacade::new()?,
179 "avdtp_facade" => AvdtpFacade::new(),
180 "avrcp_facade" => AvrcpFacade::new(),
181 "basemgr_facade" => ModularFacade::new(),
183 "modular_facade" => ModularFacade::new(),
184 "ble_advertise_facade" => BleAdvertiseFacade::new(),
185 "bt_sys_facade" => BluetoothSysFacade::new(),
186 "component_facade" => ComponentFacade::new(),
187 "diagnostics_facade" => DiagnosticsFacade::new(),
188 "device_facade" => DeviceFacade::new(),
189 "factory_reset_facade" => FactoryResetFacade::new(),
190 "factory_store_facade" => FactoryStoreFacade::new(),
191 "feedback_data_provider_facade" => FeedbackDataProviderFacade::new(),
192 "file_facade" => FileFacade::new(),
193 "gatt_client_facade" => GattClientFacade::new(),
194 "gatt_server_facade" => GattServerFacade::new(),
195 "hardware_power_statecontrol_facade" => HardwarePowerStatecontrolFacade::new(),
196 "hfp_facade" => HfpFacade::new(),
197 "hwinfo_facade" => HwinfoFacade::new(),
198 "input_facade" => InputFacade::new(),
199 "location_emergency_provider_facade" => EmergencyProviderFacade::new()?,
200 "location_regulatory_region_facade" => RegulatoryRegionFacade::new()?,
201 "logging_facade" => LoggingFacade::new(),
202 "media_session_facade" => MediaSessionFacade::new(),
203 "netstack_facade" => NetstackFacade::default(),
204 "rfcomm_facade" => RfcommFacade::new()?,
205 "paver" => PaverFacade::new(),
206 "power_facade" => PowerFacade::new(),
207 "profile_server_facade" => ProfileServerFacade::new(),
208 "proxy_facade" => ProxyFacade::new(),
209 "scenic_facade" => ScenicFacade::new(),
210 "setui_facade" => SetUiFacade::new(),
211 "system_metrics_facade" => SystemMetricsFacade::new(),
212 "temperature_facade" => TemperatureFacade::new(),
213 "time_facade" => TimeFacade::new(),
214 "traceutil_facade" => TraceutilFacade::new(),
215 "tracing_facade" => TracingFacade::new(),
216 "virtual_camera_facade" => VirtualCameraFacade::new(),
217 "weave_facade" => WeaveFacade::new(),
218 "webdriver_facade" => WebdriverFacade::new(),
219 "wlan" => WlanFacade::new()?,
220 "wlan_ap_policy" => WlanApPolicyFacade::new()?,
221 "wlan_deprecated" => WlanDeprecatedConfigurationFacade::new()?,
222 "wlan_phy" => WlanPhyFacade::new()?,
223 "wlan_policy" => WlanPolicyFacade::new()?,
224 "wpan_facade" => WpanFacade::new(),
225 )
226 );
227
228 let mut proxied_facades = HashSet::<String>::new();
230 let facade_provider = match connect_to_protocol::<FacadeProviderMarker>() {
231 Ok(proxy) => proxy,
232 Err(error) => {
233 error!(error:%; "Failed to connect to FacadeProvider");
234 return Err(error.into());
235 }
236 };
237 let (client_end, server_end) = fidl::endpoints::create_endpoints::<FacadeIteratorMarker>();
242 match facade_provider.get_facades(server_end) {
243 Ok(_) => {
244 let facade_iter = FacadeIteratorSynchronousProxy::new(client_end.into_channel());
245 loop {
246 match facade_iter.get_next(zx::MonotonicInstant::INFINITE) {
247 Ok(facades) if facades.is_empty() => break, Ok(facades) => proxied_facades.extend(facades.into_iter()),
249 Err(error) if error.is_closed() && proxied_facades.is_empty() => {
252 break;
253 }
254 Err(error) => {
255 error!(error:%; "Failed to get proxied facade list");
256 proxied_facades.clear();
257 break;
258 }
259 };
260 }
261 }
262 Err(error) if error.is_closed() => (),
264 Err(error) => {
265 error!(error:%; "Failed to get FacadeIterator");
266 return Err(error.into());
267 }
268 };
269
270 Ok(Sl4f { facades, facade_provider, proxied_facades, clients })
271 }
272
273 pub fn get_facade(&self, name: &str) -> Option<Arc<dyn Facade>> {
275 self.facades.get(name).map(Arc::clone)
276 }
277
278 pub async fn cleanup(&self) {
280 for facade in self.facades.values() {
281 facade.cleanup();
282 }
283 if !self.proxied_facades.is_empty() {
285 if let Err(error) = self.facade_provider.cleanup().await {
286 error!(error:%; "Failed to execute Cleanup()");
287 }
288 }
289 self.clients.write().cleanup_clients();
290 }
291
292 pub fn print_clients(&self) {
293 self.clients.read().print_clients();
294 }
295
296 pub async fn print(&self) {
298 for facade in self.facades.values() {
299 facade.print();
300 }
301 if !self.proxied_facades.is_empty() {
303 if let Err(error) = self.facade_provider.print().await {
304 error!(error:%; "Failed to execute Print()");
305 }
306 }
307 }
308
309 pub fn has_proxy_facade(&self, name: &str) -> bool {
313 self.proxied_facades.contains(name)
314 }
315
316 pub async fn handle_proxy_request(
323 &self,
324 facade: String,
325 command: String,
326 args: Value,
327 ) -> Result<Value, Error> {
328 let encode_params = async {
330 let params_blob = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, 0)?;
331 write_json_to_vmo(¶ms_blob, &args)?;
332 Ok::<zx::Vmo, Error>(params_blob)
333 };
334 let params_blob = match encode_params.await {
335 Ok(params_blob) => params_blob,
336 Err(error) => {
337 return Err(
338 Sl4fError::new(&format!("Failed to write params with: {}", error)).into()
339 );
340 }
341 };
342
343 match self.facade_provider.execute(&facade, &command, params_blob).await {
345 Ok((None, None)) => Ok(Value::Null),
347 Ok((Some(vmo), None)) => match read_json_from_vmo(&vmo) {
349 Ok(result) => Ok(result),
350 Err(error) => {
351 Err(Sl4fError::new(&format!("Failed to read result with: {}", error)).into())
352 }
353 },
354 Ok((_, Some(string))) => Err(Sl4fError::new(&string).into()),
356 Err(error) => {
357 Err(Sl4fError::new(&format!("Failed to send command with {}", error)).into())
358 }
359 }
360 }
361}
362
363#[derive(Debug)]
365pub struct Sl4fClients {
366 clients: HashMap<String, Vec<ClientData>>,
370}
371
372impl Sl4fClients {
373 pub fn new() -> Self {
374 Self { clients: HashMap::new() }
375 }
376
377 fn init_client(&mut self, id: String) -> bool {
379 use std::collections::hash_map::Entry::*;
380 match self.clients.entry(id) {
381 Occupied(entry) => {
382 warn!(tag = "client_init"; "Key: {:?} already exists in clients. ", entry.key());
383 true
384 }
385 Vacant(entry) => {
386 entry.insert(Vec::new());
387 info!(tag = "client_init"; "Updated clients: {:?}", self.clients);
388 false
389 }
390 }
391 }
392
393 fn cleanup_clients(&mut self) {
394 self.clients.clear();
395 }
396
397 fn print_clients(&self) {
398 info!("SL4F Clients: {:?}", self.clients);
399 }
400}
401
402fn json<T>(content: &T) -> hyper::Response<hyper::Body>
403where
404 T: serde::Serialize,
405{
406 use std::convert::TryInto as _;
407
408 let application_json = "application/json".try_into().expect("json header value");
409 let data = serde_json::to_string(content).expect("encode json");
410
411 let mut response = hyper::Response::new(data.into());
412 assert_eq!(response.headers_mut().insert(hyper::header::CONTENT_TYPE, application_json), None);
413 response
414}
415
416pub async fn serve(
418 request: hyper::Request<hyper::Body>,
419 clients: Arc<RwLock<Sl4fClients>>,
420 sender: async_channel::Sender<AsyncRequest>,
421) -> hyper::Response<hyper::Body> {
422 use hyper::Method;
423
424 match (request.method(), request.uri().path()) {
425 (&Method::GET, "/") => {
426 info!(tag = "serve"; "Received command request via GET.");
428 client_request(request, &sender).await
429 }
430 (&Method::POST, "/") => {
431 info!(tag = "serve"; "Received command request via POST.");
433 client_request(request, &sender).await
434 }
435 (&Method::GET, "/init") => {
436 info!(tag = "serve"; "Received init request.");
438 client_init(request, &clients).await
439 }
440 (&Method::GET, "/print_clients") => {
441 info!(tag = "serve"; "Received print client request.");
443 const PRINT_ACK: &str = "Successfully printed clients.";
444 json(&PRINT_ACK)
445 }
446 (&Method::GET, "/cleanup") => {
447 info!(tag = "serve"; "Received server cleanup request.");
448 server_cleanup(request, &sender).await
449 }
450 _ => {
451 error!(tag = "serve"; "Received unknown server request.");
452 const FAIL_REQUEST_ACK: &str = "Unknown GET request.";
453 let res = CommandResponse::new(json!(""), None, Some(FAIL_REQUEST_ACK.to_string()));
454 json(&res)
455 }
456 }
457}
458
459async fn client_request(
462 request: hyper::Request<hyper::Body>,
463 sender: &async_channel::Sender<AsyncRequest>,
464) -> hyper::Response<hyper::Body> {
465 const FAIL_TEST_ACK: &str = "Command failed";
466
467 let (request_id, method_id, method_params) = match parse_request(request).await {
468 Ok(res) => res,
469 Err(error) => {
470 error!(tag = "client_request", error:?; "Failed to parse request");
471 return json(&FAIL_TEST_ACK);
472 }
473 };
474
475 let (async_sender, receiver) = futures::channel::oneshot::channel();
478 let req = AsyncCommandRequest::new(async_sender, method_id.clone(), method_params);
479 sender.send(AsyncRequest::Command(req)).await.expect("Failed to send request to async thread.");
480 let resp = receiver.await.expect("Async thread dropped responder.");
481
482 info!(
483 tag = "client_request",
484 method:? = method_id.method,
485 response:? = resp;
486 "Received async thread response"
487 );
488
489 match resp.result {
491 Some(async_res) => {
492 let res = CommandResponse::new(request_id.into_response_id(), Some(async_res), None);
493 json(&res)
494 }
495 None => {
496 let res = CommandResponse::new(request_id.into_response_id(), None, resp.error);
497 json(&res)
498 }
499 }
500}
501
502async fn client_init(
504 request: hyper::Request<hyper::Body>,
505 clients: &Arc<RwLock<Sl4fClients>>,
506) -> hyper::Response<hyper::Body> {
507 const INIT_ACK: &str = "Recieved init request.";
508 const FAIL_INIT_ACK: &str = "Failed to init client.";
509
510 let (_, _, method_params) = match parse_request(request).await {
511 Ok(res) => res,
512 Err(_) => return json(&FAIL_INIT_ACK),
513 };
514
515 let client_id_raw = match method_params.get("client_id") {
516 Some(id) => Some(id).unwrap().clone(),
517 None => return json(&FAIL_INIT_ACK),
518 };
519
520 let client_id = client_id_raw.as_str().map(String::from).unwrap();
522
523 if clients.write().init_client(client_id) {
524 json(&FAIL_INIT_ACK)
525 } else {
526 json(&INIT_ACK)
527 }
528}
529
530async fn parse_request(
533 request: hyper::Request<hyper::Body>,
534) -> Result<(RequestId, MethodId, Value), Error> {
535 use bytes::Buf as _;
536
537 let body = hyper::body::aggregate(request.into_body()).await.context("read request")?;
538
539 let request_data: CommandRequest = match serde_json::from_reader(body.reader()) {
541 Ok(tdata) => tdata,
542 Err(_) => return Err(Sl4fError::new("Failed to unpack request data.").into()),
543 };
544
545 let request_id_raw = request_data.id;
546 let method_id_raw = request_data.method;
547 let method_params = request_data.params;
548 info!(tag = "parse_request",
549 request_id:? = request_id_raw,
550 name:? = method_id_raw,
551 args:? = method_params;
552 ""
553 );
554
555 let request_id = RequestId::new(request_id_raw);
556 let method_id = method_id_raw.parse().unwrap_or_default();
559 Ok((request_id, method_id, method_params))
560}
561
562async fn server_cleanup(
563 request: hyper::Request<hyper::Body>,
564 sender: &async_channel::Sender<AsyncRequest>,
565) -> hyper::Response<hyper::Body> {
566 const FAIL_CLEANUP_ACK: &str = "Failed to cleanup SL4F resources.";
567 const CLEANUP_ACK: &str = "Successful cleanup of SL4F resources.";
568
569 info!(tag = "server_cleanup"; "Cleaning up server state");
570 let (request_id, _, _) = match parse_request(request).await {
571 Ok(res) => res,
572 Err(_) => return json(&FAIL_CLEANUP_ACK),
573 };
574
575 let (async_sender, receiver) = futures::channel::oneshot::channel();
577
578 sender
580 .send(AsyncRequest::Cleanup(async_sender))
581 .await
582 .expect("Failed to send request to async thread.");
583 let () = receiver.await.expect("Async thread dropped responder.");
584
585 let ack = CommandResponse::new(request_id.into_response_id(), Some(json!(CLEANUP_ACK)), None);
586 json(&ack)
587}