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 //! This module defines the UwbService and its related components. 16 17 use log::{debug, error, warn}; 18 use tokio::runtime::{Builder, Handle}; 19 use tokio::sync::{mpsc, oneshot}; 20 use tokio::task; 21 22 use crate::error::{Error, Result}; 23 use crate::params::app_config_params::AppConfigParams; 24 use crate::params::uci_packets::{ 25 Controlee, CountryCode, DeviceState, PowerStats, RawUciMessage, ReasonCode, SessionId, 26 SessionState, SessionType, UpdateMulticastListAction, 27 }; 28 use crate::session::session_manager::{SessionManager, SessionNotification}; 29 use crate::uci::notification::{CoreNotification, SessionRangeData}; 30 use crate::uci::uci_logger::UciLoggerMode; 31 use crate::uci::uci_manager::UciManager; 32 use crate::utils::clean_mpsc_receiver; 33 34 /// Callback builder 35 pub trait UwbServiceCallbackBuilder<C: UwbServiceCallback>: 'static + Send { 36 /// Builds UwbServiceCallback. The build operation Consumes Builder. build(self) -> Option<C>37 fn build(self) -> Option<C>; 38 } 39 40 /// The callback of the UwbService which is used to send the notification to UwbService's caller. 41 pub trait UwbServiceCallback: 'static { 42 /// Notify the UWB service has been reset due to internal error. All the sessions are closed. 43 /// `success` indicates the reset is successful or not. on_service_reset(&mut self, success: bool)44 fn on_service_reset(&mut self, success: bool); 45 46 /// Notify the status of the UCI device. on_uci_device_status_changed(&mut self, state: DeviceState)47 fn on_uci_device_status_changed(&mut self, state: DeviceState); 48 49 /// Notify the state of the session with the id |session_id| is changed. on_session_state_changed( &mut self, session_id: SessionId, session_state: SessionState, reason_code: ReasonCode, )50 fn on_session_state_changed( 51 &mut self, 52 session_id: SessionId, 53 session_state: SessionState, 54 reason_code: ReasonCode, 55 ); 56 57 /// Notify the ranging data of the session with the id |session_id| is received. on_range_data_received(&mut self, session_id: SessionId, range_data: SessionRangeData)58 fn on_range_data_received(&mut self, session_id: SessionId, range_data: SessionRangeData); 59 60 /// Notify the vendor notification is received. on_vendor_notification_received(&mut self, gid: u32, oid: u32, payload: Vec<u8>)61 fn on_vendor_notification_received(&mut self, gid: u32, oid: u32, payload: Vec<u8>); 62 63 // TODO(b/270443790): In the future, add a callback here to notify the Data Rx packet. 64 } 65 66 /// A placeholder implementation for UwbServiceCallback that does nothing. 67 pub struct NopUwbServiceCallback {} 68 impl UwbServiceCallback for NopUwbServiceCallback { on_service_reset(&mut self, _success: bool)69 fn on_service_reset(&mut self, _success: bool) {} on_uci_device_status_changed(&mut self, _state: DeviceState)70 fn on_uci_device_status_changed(&mut self, _state: DeviceState) {} on_session_state_changed( &mut self, _session_id: SessionId, _session_state: SessionState, _reason_code: ReasonCode, )71 fn on_session_state_changed( 72 &mut self, 73 _session_id: SessionId, 74 _session_state: SessionState, 75 _reason_code: ReasonCode, 76 ) { 77 } on_range_data_received(&mut self, _session_id: SessionId, _range_data: SessionRangeData)78 fn on_range_data_received(&mut self, _session_id: SessionId, _range_data: SessionRangeData) {} on_vendor_notification_received(&mut self, _gid: u32, _oid: u32, _payload: Vec<u8>)79 fn on_vendor_notification_received(&mut self, _gid: u32, _oid: u32, _payload: Vec<u8>) {} 80 } 81 82 /// The entry class (a.k.a top shim) of the core library. The class accepts requests from the 83 /// client, and delegates the requests to other components. It should provide the 84 /// backward-compatible interface for the client of the library. 85 pub struct UwbService { 86 /// The handle of the working runtime. All the commands are executed inside the runtime. 87 /// 88 /// Note that the caller should guarantee that the working runtime outlives the UwbService. 89 runtime_handle: Handle, 90 /// Used to send the command to UwbServiceActor. 91 cmd_sender: mpsc::UnboundedSender<(Command, ResponseSender)>, 92 } 93 94 impl UwbService { 95 /// Create a new UwbService instance. new<C, B, U>( runtime_handle: Handle, callback_builder: B, uci_manager: U, ) -> Option<Self> where C: UwbServiceCallback, B: UwbServiceCallbackBuilder<C>, U: UciManager,96 pub(super) fn new<C, B, U>( 97 runtime_handle: Handle, 98 callback_builder: B, 99 uci_manager: U, 100 ) -> Option<Self> 101 where 102 C: UwbServiceCallback, 103 B: UwbServiceCallbackBuilder<C>, 104 U: UciManager, 105 { 106 let (cmd_sender, cmd_receiver) = mpsc::unbounded_channel(); 107 let (service_status_sender, mut service_status_receiver) = 108 mpsc::unbounded_channel::<bool>(); 109 std::thread::spawn(move || { 110 let actor_runtime = match Builder::new_current_thread().enable_all().build() { 111 Ok(ar) => ar, 112 Err(err) => { 113 error!("Failed to build Tokio Runtime! {:?}", err); 114 // unwrap safe since receiver is in scope 115 service_status_sender.send(false).unwrap(); 116 return; 117 } 118 }; 119 120 let callback = match callback_builder.build() { 121 Some(cb) => { 122 // unwrap safe since receiver is in scope 123 service_status_sender.send(true).unwrap(); 124 cb 125 } 126 None => { 127 error!("Unable to build callback"); 128 service_status_sender.send(false).unwrap(); 129 return; 130 } 131 }; 132 133 let mut actor = UwbServiceActor::new(cmd_receiver, callback, uci_manager); 134 let local = task::LocalSet::new(); 135 local.spawn_local(async move { 136 task::spawn_local(async move { actor.run().await }).await.unwrap(); 137 }); 138 actor_runtime.block_on(local); 139 }); 140 141 match service_status_receiver.blocking_recv() { 142 Some(true) => Some(Self { runtime_handle, cmd_sender }), 143 _ => None, 144 } 145 } 146 147 /// Set UCI log mode. set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()>148 pub fn set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()> { 149 self.block_on_cmd(Command::SetLoggerMode { logger_mode })?; 150 Ok(()) 151 } 152 153 /// Enable the UWB service. enable(&self) -> Result<()>154 pub fn enable(&self) -> Result<()> { 155 self.block_on_cmd(Command::Enable)?; 156 Ok(()) 157 } 158 159 /// Disable the UWB service. disable(&self) -> Result<()>160 pub fn disable(&self) -> Result<()> { 161 self.block_on_cmd(Command::Disable)?; 162 Ok(()) 163 } 164 165 /// Initialize a new ranging session with the given parameters. init_session( &self, session_id: SessionId, session_type: SessionType, params: AppConfigParams, ) -> Result<()>166 pub fn init_session( 167 &self, 168 session_id: SessionId, 169 session_type: SessionType, 170 params: AppConfigParams, 171 ) -> Result<()> { 172 self.block_on_cmd(Command::InitSession { session_id, session_type, params })?; 173 Ok(()) 174 } 175 176 /// Destroy the session. deinit_session(&self, session_id: SessionId) -> Result<()>177 pub fn deinit_session(&self, session_id: SessionId) -> Result<()> { 178 self.block_on_cmd(Command::DeinitSession { session_id })?; 179 Ok(()) 180 } 181 182 /// Start ranging of the session. start_ranging(&self, session_id: SessionId) -> Result<AppConfigParams>183 pub fn start_ranging(&self, session_id: SessionId) -> Result<AppConfigParams> { 184 match self.block_on_cmd(Command::StartRanging { session_id })? { 185 Response::AppConfigParams(params) => Ok(params), 186 _ => panic!("start_ranging() should return AppConfigParams"), 187 } 188 } 189 190 /// Stop ranging. stop_ranging(&self, session_id: SessionId) -> Result<()>191 pub fn stop_ranging(&self, session_id: SessionId) -> Result<()> { 192 self.block_on_cmd(Command::StopRanging { session_id })?; 193 Ok(()) 194 } 195 196 /// Reconfigure the parameters of the session. reconfigure(&self, session_id: SessionId, params: AppConfigParams) -> Result<()>197 pub fn reconfigure(&self, session_id: SessionId, params: AppConfigParams) -> Result<()> { 198 self.block_on_cmd(Command::Reconfigure { session_id, params })?; 199 Ok(()) 200 } 201 202 /// Update the list of the controlees to the ongoing session. update_controller_multicast_list( &self, session_id: SessionId, action: UpdateMulticastListAction, controlees: Vec<Controlee>, ) -> Result<()>203 pub fn update_controller_multicast_list( 204 &self, 205 session_id: SessionId, 206 action: UpdateMulticastListAction, 207 controlees: Vec<Controlee>, 208 ) -> Result<()> { 209 self.block_on_cmd(Command::UpdateControllerMulticastList { 210 session_id, 211 action, 212 controlees, 213 })?; 214 Ok(()) 215 } 216 217 /// Set the country code. Android-specific method. android_set_country_code(&self, country_code: CountryCode) -> Result<()>218 pub fn android_set_country_code(&self, country_code: CountryCode) -> Result<()> { 219 self.block_on_cmd(Command::AndroidSetCountryCode { country_code })?; 220 Ok(()) 221 } 222 223 /// Get the power statistics. Android-specific method. android_get_power_stats(&self) -> Result<PowerStats>224 pub fn android_get_power_stats(&self) -> Result<PowerStats> { 225 match self.block_on_cmd(Command::AndroidGetPowerStats)? { 226 Response::PowerStats(stats) => Ok(stats), 227 _ => panic!("android_get_power_stats() should return PowerStats"), 228 } 229 } 230 231 /// Send a raw UCI message. raw_uci_cmd( &self, mt: u32, gid: u32, oid: u32, payload: Vec<u8>, ) -> Result<RawUciMessage>232 pub fn raw_uci_cmd( 233 &self, 234 mt: u32, 235 gid: u32, 236 oid: u32, 237 payload: Vec<u8>, 238 ) -> Result<RawUciMessage> { 239 match self.block_on_cmd(Command::RawUciCmd { mt, gid, oid, payload })? { 240 Response::RawUciMessage(msg) => Ok(msg), 241 _ => panic!("raw_uci_cmd() should return RawUciMessage"), 242 } 243 } 244 245 /// Get app config params for the given session id session_params(&self, session_id: SessionId) -> Result<AppConfigParams>246 pub fn session_params(&self, session_id: SessionId) -> Result<AppConfigParams> { 247 match self.block_on_cmd(Command::GetParams { session_id })? { 248 Response::AppConfigParams(params) => Ok(params), 249 _ => panic!("session_params() should return AppConfigParams"), 250 } 251 } 252 253 /// Send the |cmd| to UwbServiceActor and wait until receiving the response. block_on_cmd(&self, cmd: Command) -> Result<Response>254 fn block_on_cmd(&self, cmd: Command) -> Result<Response> { 255 let (result_sender, result_receiver) = oneshot::channel(); 256 self.cmd_sender.send((cmd, result_sender)).map_err(|cmd| { 257 error!("Failed to send cmd: {:?}", cmd.0); 258 Error::Unknown 259 })?; 260 261 self.runtime_handle.block_on(async move { 262 result_receiver.await.unwrap_or_else(|e| { 263 error!("Failed to receive the result for cmd: {:?}", e); 264 Err(Error::Unknown) 265 }) 266 }) 267 } 268 269 /// Run an future task on the runtime. This method is only exposed for the testing. 270 #[cfg(test)] block_on_for_testing<F: std::future::Future>(&self, future: F) -> F::Output271 fn block_on_for_testing<F: std::future::Future>(&self, future: F) -> F::Output { 272 self.runtime_handle.block_on(future) 273 } 274 } 275 276 struct UwbServiceActor<C: UwbServiceCallback, U: UciManager> { 277 cmd_receiver: mpsc::UnboundedReceiver<(Command, ResponseSender)>, 278 callback: C, 279 uci_manager: U, 280 session_manager: Option<SessionManager>, 281 core_notf_receiver: mpsc::UnboundedReceiver<CoreNotification>, 282 session_notf_receiver: mpsc::UnboundedReceiver<SessionNotification>, 283 vendor_notf_receiver: mpsc::UnboundedReceiver<RawUciMessage>, 284 } 285 286 impl<C: UwbServiceCallback, U: UciManager> UwbServiceActor<C, U> { new( cmd_receiver: mpsc::UnboundedReceiver<(Command, ResponseSender)>, callback: C, uci_manager: U, ) -> Self287 fn new( 288 cmd_receiver: mpsc::UnboundedReceiver<(Command, ResponseSender)>, 289 callback: C, 290 uci_manager: U, 291 ) -> Self { 292 Self { 293 cmd_receiver, 294 callback, 295 uci_manager, 296 session_manager: None, 297 core_notf_receiver: mpsc::unbounded_channel().1, 298 session_notf_receiver: mpsc::unbounded_channel().1, 299 vendor_notf_receiver: mpsc::unbounded_channel().1, 300 } 301 } 302 run(&mut self)303 async fn run(&mut self) { 304 loop { 305 tokio::select! { 306 cmd = self.cmd_receiver.recv() => { 307 match cmd { 308 None => { 309 debug!("UwbService is about to drop."); 310 break; 311 }, 312 Some((cmd, result_sender)) => { 313 let result = self.handle_cmd(cmd).await; 314 let timeout_occurs = matches!(result, Err(Error::Timeout)); 315 let _ = result_sender.send(result); 316 317 // The UCI HAL might be stuck at a weird state when the timeout occurs. 318 // Reset the HAL and clear the internal state, and hope the HAL goes 319 // back to the normal situation. 320 if timeout_occurs { 321 warn!("The command timeout, reset the service."); 322 self.reset_service().await; 323 } 324 } 325 } 326 } 327 Some(core_notf) = self.core_notf_receiver.recv() => { 328 self.handle_core_notification(core_notf).await; 329 } 330 Some(session_notf) = self.session_notf_receiver.recv() => { 331 self.handle_session_notification(session_notf).await; 332 } 333 Some(vendor_notf) = self.vendor_notf_receiver.recv() => { 334 self.handle_vendor_notification(vendor_notf).await; 335 } 336 } 337 } 338 } 339 handle_cmd(&mut self, cmd: Command) -> Result<Response>340 async fn handle_cmd(&mut self, cmd: Command) -> Result<Response> { 341 match cmd { 342 Command::SetLoggerMode { logger_mode } => { 343 self.uci_manager.set_logger_mode(logger_mode).await?; 344 Ok(Response::Null) 345 } 346 Command::Enable => { 347 self.enable_service().await?; 348 Ok(Response::Null) 349 } 350 Command::Disable => { 351 self.disable_service(false).await?; 352 Ok(Response::Null) 353 } 354 Command::InitSession { session_id, session_type, params } => { 355 if let Some(session_manager) = self.session_manager.as_mut() { 356 session_manager.init_session(session_id, session_type, params).await?; 357 Ok(Response::Null) 358 } else { 359 error!("The service is not enabled yet"); 360 Err(Error::BadParameters) 361 } 362 } 363 Command::DeinitSession { session_id } => { 364 if let Some(session_manager) = self.session_manager.as_mut() { 365 session_manager.deinit_session(session_id).await?; 366 Ok(Response::Null) 367 } else { 368 error!("The service is not enabled yet"); 369 Err(Error::BadParameters) 370 } 371 } 372 Command::StartRanging { session_id } => { 373 if let Some(session_manager) = self.session_manager.as_mut() { 374 let params = session_manager.start_ranging(session_id).await?; 375 Ok(Response::AppConfigParams(params)) 376 } else { 377 error!("The service is not enabled yet"); 378 Err(Error::BadParameters) 379 } 380 } 381 Command::StopRanging { session_id } => { 382 if let Some(session_manager) = self.session_manager.as_mut() { 383 session_manager.stop_ranging(session_id).await?; 384 Ok(Response::Null) 385 } else { 386 error!("The service is not enabled yet"); 387 Err(Error::BadParameters) 388 } 389 } 390 Command::Reconfigure { session_id, params } => { 391 if let Some(session_manager) = self.session_manager.as_mut() { 392 session_manager.reconfigure(session_id, params).await?; 393 Ok(Response::Null) 394 } else { 395 error!("The service is not enabled yet"); 396 Err(Error::BadParameters) 397 } 398 } 399 Command::UpdateControllerMulticastList { session_id, action, controlees } => { 400 if let Some(session_manager) = self.session_manager.as_mut() { 401 session_manager 402 .update_controller_multicast_list(session_id, action, controlees) 403 .await?; 404 Ok(Response::Null) 405 } else { 406 error!("The service is not enabled yet"); 407 Err(Error::BadParameters) 408 } 409 } 410 Command::AndroidSetCountryCode { country_code } => { 411 self.uci_manager.android_set_country_code(country_code).await?; 412 Ok(Response::Null) 413 } 414 Command::AndroidGetPowerStats => { 415 let stats = self.uci_manager.android_get_power_stats().await?; 416 Ok(Response::PowerStats(stats)) 417 } 418 Command::RawUciCmd { mt, gid, oid, payload } => { 419 let msg = self.uci_manager.raw_uci_cmd(mt, gid, oid, payload).await?; 420 Ok(Response::RawUciMessage(msg)) 421 } 422 Command::GetParams { session_id } => { 423 if let Some(session_manager) = self.session_manager.as_mut() { 424 let params = session_manager.session_params(session_id).await?; 425 Ok(Response::AppConfigParams(params)) 426 } else { 427 error!("The service is not enabled yet"); 428 Err(Error::BadParameters) 429 } 430 } 431 } 432 } 433 handle_core_notification(&mut self, notf: CoreNotification)434 async fn handle_core_notification(&mut self, notf: CoreNotification) { 435 debug!("Receive core notification: {:?}", notf); 436 match notf { 437 CoreNotification::DeviceStatus(state) => { 438 if state == DeviceState::DeviceStateError { 439 warn!("Received DeviceStateError notification, reset the service"); 440 self.reset_service().await; 441 } else { 442 self.callback.on_uci_device_status_changed(state); 443 } 444 } 445 CoreNotification::GenericError(_status) => {} 446 } 447 } 448 handle_session_notification(&mut self, notf: SessionNotification)449 async fn handle_session_notification(&mut self, notf: SessionNotification) { 450 match notf { 451 SessionNotification::SessionState { session_id, session_state, reason_code } => { 452 self.callback.on_session_state_changed(session_id, session_state, reason_code); 453 } 454 SessionNotification::RangeData { session_id, range_data } => { 455 self.callback.on_range_data_received(session_id, range_data); 456 } 457 } 458 } 459 handle_vendor_notification(&mut self, notf: RawUciMessage)460 async fn handle_vendor_notification(&mut self, notf: RawUciMessage) { 461 self.callback.on_vendor_notification_received(notf.gid, notf.oid, notf.payload); 462 } 463 enable_service(&mut self) -> Result<()>464 async fn enable_service(&mut self) -> Result<()> { 465 if self.session_manager.is_some() { 466 debug!("The service is already enabled, skip."); 467 return Ok(()); 468 } 469 470 let (core_notf_sender, core_notf_receiver) = mpsc::unbounded_channel(); 471 let (uci_session_notf_sender, uci_session_notf_receiver) = mpsc::unbounded_channel(); 472 let (vendor_notf_sender, vendor_notf_receiver) = mpsc::unbounded_channel(); 473 self.uci_manager.set_core_notification_sender(core_notf_sender).await; 474 self.uci_manager.set_session_notification_sender(uci_session_notf_sender).await; 475 self.uci_manager.set_vendor_notification_sender(vendor_notf_sender).await; 476 self.uci_manager.open_hal().await?; 477 478 let (session_notf_sender, session_notf_receiver) = mpsc::unbounded_channel(); 479 self.core_notf_receiver = core_notf_receiver; 480 self.session_notf_receiver = session_notf_receiver; 481 self.vendor_notf_receiver = vendor_notf_receiver; 482 self.session_manager = Some(SessionManager::new( 483 self.uci_manager.clone(), 484 uci_session_notf_receiver, 485 session_notf_sender, 486 )); 487 Ok(()) 488 } 489 disable_service(&mut self, force: bool) -> Result<()>490 async fn disable_service(&mut self, force: bool) -> Result<()> { 491 self.core_notf_receiver = mpsc::unbounded_channel().1; 492 self.session_notf_receiver = mpsc::unbounded_channel().1; 493 self.vendor_notf_receiver = mpsc::unbounded_channel().1; 494 self.session_manager = None; 495 self.uci_manager.close_hal(force).await?; 496 Ok(()) 497 } 498 reset_service(&mut self)499 async fn reset_service(&mut self) { 500 let _ = self.disable_service(true).await; 501 let result = self.enable_service().await; 502 if result.is_err() { 503 error!("Failed to reset the service."); 504 } 505 self.callback.on_service_reset(result.is_ok()); 506 } 507 } 508 509 impl<C: UwbServiceCallback, U: UciManager> Drop for UwbServiceActor<C, U> { drop(&mut self)510 fn drop(&mut self) { 511 // mpsc receivers are about to be dropped. Clean shutdown the mpsc message. 512 clean_mpsc_receiver(&mut self.core_notf_receiver); 513 clean_mpsc_receiver(&mut self.session_notf_receiver); 514 clean_mpsc_receiver(&mut self.vendor_notf_receiver); 515 } 516 } 517 518 #[derive(Debug)] 519 enum Command { 520 SetLoggerMode { 521 logger_mode: UciLoggerMode, 522 }, 523 Enable, 524 Disable, 525 InitSession { 526 session_id: SessionId, 527 session_type: SessionType, 528 params: AppConfigParams, 529 }, 530 DeinitSession { 531 session_id: SessionId, 532 }, 533 StartRanging { 534 session_id: SessionId, 535 }, 536 StopRanging { 537 session_id: SessionId, 538 }, 539 Reconfigure { 540 session_id: SessionId, 541 params: AppConfigParams, 542 }, 543 UpdateControllerMulticastList { 544 session_id: SessionId, 545 action: UpdateMulticastListAction, 546 controlees: Vec<Controlee>, 547 }, 548 AndroidSetCountryCode { 549 country_code: CountryCode, 550 }, 551 AndroidGetPowerStats, 552 RawUciCmd { 553 mt: u32, 554 gid: u32, 555 oid: u32, 556 payload: Vec<u8>, 557 }, 558 GetParams { 559 session_id: SessionId, 560 }, 561 } 562 563 #[derive(Debug)] 564 enum Response { 565 Null, 566 AppConfigParams(AppConfigParams), 567 PowerStats(PowerStats), 568 RawUciMessage(RawUciMessage), 569 } 570 type ResponseSender = oneshot::Sender<Result<Response>>; 571 572 #[cfg(test)] 573 mod tests { 574 use super::*; 575 576 use tokio::runtime::Runtime; 577 578 use crate::params::uci_packets::{SessionState, SetAppConfigResponse, StatusCode}; 579 use crate::params::GetDeviceInfoResponse; 580 use crate::service::mock_uwb_service_callback::MockUwbServiceCallback; 581 use crate::service::uwb_service_builder::default_runtime; 582 use crate::service::uwb_service_callback_builder::UwbServiceCallbackSendBuilder; 583 use crate::session::session_manager::test_utils::{ 584 generate_params, range_data_notf, session_range_data, session_status_notf, 585 }; 586 use crate::uci::mock_uci_manager::MockUciManager; 587 use crate::uci::notification::UciNotification; 588 use uwb_uci_packets::StatusCode::UciStatusOk; 589 590 const GET_DEVICE_INFO_RSP: GetDeviceInfoResponse = GetDeviceInfoResponse { 591 status: UciStatusOk, 592 uci_version: 0, 593 mac_version: 0, 594 phy_version: 0, 595 uci_test_version: 0, 596 vendor_spec_info: vec![], 597 }; 598 setup_uwb_service( uci_manager: MockUciManager, ) -> (UwbService, MockUwbServiceCallback, Runtime)599 fn setup_uwb_service( 600 uci_manager: MockUciManager, 601 ) -> (UwbService, MockUwbServiceCallback, Runtime) { 602 let runtime = default_runtime().unwrap(); 603 let callback = MockUwbServiceCallback::new(); 604 let callback_builder = UwbServiceCallbackSendBuilder::new(callback.clone()); 605 let service = 606 UwbService::new(runtime.handle().to_owned(), callback_builder, uci_manager).unwrap(); 607 (service, callback, runtime) 608 } 609 610 #[test] test_open_close_uci()611 fn test_open_close_uci() { 612 let mut uci_manager = MockUciManager::new(); 613 uci_manager.expect_open_hal(vec![], Ok(GET_DEVICE_INFO_RSP)); 614 uci_manager.expect_close_hal(false, Ok(())); 615 let (service, _, _runtime) = setup_uwb_service(uci_manager); 616 617 let result = service.enable(); 618 assert!(result.is_ok()); 619 let result = service.disable(); 620 assert!(result.is_ok()); 621 } 622 623 #[test] test_session_e2e()624 fn test_session_e2e() { 625 let session_id = 0x123; 626 let session_type = SessionType::FiraRangingSession; 627 let params = generate_params(); 628 let tlvs = params.generate_tlvs(); 629 let range_data = session_range_data(session_id); 630 631 let mut uci_manager = MockUciManager::new(); 632 uci_manager.expect_open_hal(vec![], Ok(GET_DEVICE_INFO_RSP)); 633 uci_manager.expect_session_init( 634 session_id, 635 session_type, 636 vec![session_status_notf(session_id, SessionState::SessionStateInit)], 637 Ok(()), 638 ); 639 uci_manager.expect_session_set_app_config( 640 session_id, 641 tlvs, 642 vec![session_status_notf(session_id, SessionState::SessionStateIdle)], 643 Ok(SetAppConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] }), 644 ); 645 uci_manager.expect_range_start( 646 session_id, 647 vec![ 648 session_status_notf(session_id, SessionState::SessionStateActive), 649 range_data_notf(range_data.clone()), 650 ], 651 Ok(()), 652 ); 653 uci_manager.expect_range_stop( 654 session_id, 655 vec![session_status_notf(session_id, SessionState::SessionStateIdle)], 656 Ok(()), 657 ); 658 uci_manager.expect_session_deinit( 659 session_id, 660 vec![session_status_notf(session_id, SessionState::SessionStateDeinit)], 661 Ok(()), 662 ); 663 664 let (service, mut callback, _runtime) = setup_uwb_service(uci_manager.clone()); 665 service.enable().unwrap(); 666 667 // Initialize a normal session. 668 callback.expect_on_session_state_changed( 669 session_id, 670 SessionState::SessionStateInit, 671 ReasonCode::StateChangeWithSessionManagementCommands, 672 ); 673 callback.expect_on_session_state_changed( 674 session_id, 675 SessionState::SessionStateIdle, 676 ReasonCode::StateChangeWithSessionManagementCommands, 677 ); 678 let result = service.init_session(session_id, session_type, params); 679 assert!(result.is_ok()); 680 assert!(service.block_on_for_testing(callback.wait_expected_calls_done())); 681 682 // Start the ranging process, and should receive the range data. 683 callback.expect_on_session_state_changed( 684 session_id, 685 SessionState::SessionStateActive, 686 ReasonCode::StateChangeWithSessionManagementCommands, 687 ); 688 callback.expect_on_range_data_received(session_id, range_data); 689 let result = service.start_ranging(session_id); 690 assert!(result.is_ok()); 691 assert!(service.block_on_for_testing(callback.wait_expected_calls_done())); 692 693 // Stop the ranging process. 694 callback.expect_on_session_state_changed( 695 session_id, 696 SessionState::SessionStateIdle, 697 ReasonCode::StateChangeWithSessionManagementCommands, 698 ); 699 let result = service.stop_ranging(session_id); 700 assert!(result.is_ok()); 701 assert!(service.block_on_for_testing(callback.wait_expected_calls_done())); 702 703 // Deinitialize the session, and should receive the deinitialized notification. 704 callback.expect_on_session_state_changed( 705 session_id, 706 SessionState::SessionStateDeinit, 707 ReasonCode::StateChangeWithSessionManagementCommands, 708 ); 709 let result = service.deinit_session(session_id); 710 assert!(result.is_ok()); 711 assert!(service.block_on_for_testing(callback.wait_expected_calls_done())); 712 713 // Verify if all of the expected uci_manager method are called. 714 assert!(service.block_on_for_testing(uci_manager.wait_expected_calls_done())); 715 } 716 717 #[test] test_session_api_without_enabled()718 fn test_session_api_without_enabled() { 719 let session_id = 0x123; 720 let session_type = SessionType::FiraRangingSession; 721 let params = generate_params(); 722 let action = UpdateMulticastListAction::AddControlee; 723 let short_address: [u8; 2] = [0x12, 0x34]; 724 let controlees = vec![Controlee { short_address, subsession_id: 0x24 }]; 725 726 let uci_manager = MockUciManager::new(); 727 let (service, _, _runtime) = setup_uwb_service(uci_manager); 728 729 let result = service.init_session(session_id, session_type, params.clone()); 730 assert!(result.is_err()); 731 let result = service.deinit_session(session_id); 732 assert!(result.is_err()); 733 let result = service.start_ranging(session_id); 734 assert!(result.is_err()); 735 let result = service.stop_ranging(session_id); 736 assert!(result.is_err()); 737 let result = service.reconfigure(session_id, params); 738 assert!(result.is_err()); 739 let result = service.update_controller_multicast_list(session_id, action, controlees); 740 assert!(result.is_err()); 741 } 742 743 #[test] test_android_set_country_code()744 fn test_android_set_country_code() { 745 let country_code = CountryCode::new(b"US").unwrap(); 746 let mut uci_manager = MockUciManager::new(); 747 uci_manager.expect_android_set_country_code(country_code.clone(), Ok(())); 748 let (service, _, _runtime) = setup_uwb_service(uci_manager); 749 750 let result = service.android_set_country_code(country_code); 751 assert!(result.is_ok()); 752 } 753 754 #[test] test_android_get_power_stats()755 fn test_android_get_power_stats() { 756 let stats = PowerStats { 757 status: StatusCode::UciStatusOk, 758 idle_time_ms: 123, 759 tx_time_ms: 456, 760 rx_time_ms: 789, 761 total_wake_count: 5, 762 }; 763 let mut uci_manager = MockUciManager::new(); 764 uci_manager.expect_android_get_power_stats(Ok(stats.clone())); 765 let (service, _, _runtime) = setup_uwb_service(uci_manager); 766 767 let result = service.android_get_power_stats().unwrap(); 768 assert_eq!(result, stats); 769 } 770 771 #[test] test_send_raw_cmd()772 fn test_send_raw_cmd() { 773 let mt = 0x01; 774 let gid = 0x09; 775 let oid = 0x35; 776 let cmd_payload = vec![0x12, 0x34]; 777 let resp_payload = vec![0x56, 0x78]; 778 779 let mut uci_manager = MockUciManager::new(); 780 uci_manager.expect_raw_uci_cmd( 781 mt, 782 gid, 783 oid, 784 cmd_payload.clone(), 785 Ok(RawUciMessage { gid, oid, payload: resp_payload.clone() }), 786 ); 787 let (service, _, _runtime) = setup_uwb_service(uci_manager); 788 789 let result = service.raw_uci_cmd(mt, gid, oid, cmd_payload).unwrap(); 790 assert_eq!(result, RawUciMessage { gid, oid, payload: resp_payload }); 791 } 792 793 #[test] test_vendor_notification()794 fn test_vendor_notification() { 795 let gid = 5; 796 let oid = 7; 797 let payload = vec![0x13, 0x47]; 798 799 let mut uci_manager = MockUciManager::new(); 800 uci_manager.expect_open_hal( 801 vec![UciNotification::Vendor(RawUciMessage { gid, oid, payload: payload.clone() })], 802 Ok(GET_DEVICE_INFO_RSP), 803 ); 804 let (service, mut callback, _runtime) = setup_uwb_service(uci_manager); 805 806 callback.expect_on_vendor_notification_received(gid, oid, payload); 807 service.enable().unwrap(); 808 assert!(service.block_on_for_testing(callback.wait_expected_calls_done())); 809 } 810 811 #[test] test_core_device_status_notification()812 fn test_core_device_status_notification() { 813 let state = DeviceState::DeviceStateReady; 814 815 let mut uci_manager = MockUciManager::new(); 816 uci_manager.expect_open_hal( 817 vec![UciNotification::Core(CoreNotification::DeviceStatus(state))], 818 Ok(GET_DEVICE_INFO_RSP), 819 ); 820 let (service, mut callback, _runtime) = setup_uwb_service(uci_manager); 821 callback.expect_on_uci_device_status_changed(state); 822 service.enable().unwrap(); 823 assert!(service.block_on_for_testing(callback.wait_expected_calls_done())); 824 } 825 826 #[test] test_reset_service_after_timeout()827 fn test_reset_service_after_timeout() { 828 let mut uci_manager = MockUciManager::new(); 829 // The first open_hal() returns timeout. 830 uci_manager.expect_open_hal(vec![], Err(Error::Timeout)); 831 // Then UwbService should close_hal() and open_hal() to reset the HAL. 832 uci_manager.expect_close_hal(true, Ok(())); 833 uci_manager.expect_open_hal(vec![], Ok(GET_DEVICE_INFO_RSP)); 834 let (service, mut callback, _runtime) = setup_uwb_service(uci_manager.clone()); 835 836 callback.expect_on_service_reset(true); 837 let result = service.enable(); 838 assert_eq!(result, Err(Error::Timeout)); 839 assert!(service.block_on_for_testing(callback.wait_expected_calls_done())); 840 841 assert!(service.block_on_for_testing(uci_manager.wait_expected_calls_done())); 842 } 843 844 #[test] test_reset_service_when_error_state()845 fn test_reset_service_when_error_state() { 846 let mut uci_manager = MockUciManager::new(); 847 // The first open_hal() send DeviceStateError notification. 848 uci_manager.expect_open_hal( 849 vec![UciNotification::Core(CoreNotification::DeviceStatus( 850 DeviceState::DeviceStateError, 851 ))], 852 Ok(GET_DEVICE_INFO_RSP), 853 ); 854 // Then UwbService should close_hal() and open_hal() to reset the HAL. 855 uci_manager.expect_close_hal(true, Ok(())); 856 uci_manager.expect_open_hal(vec![], Ok(GET_DEVICE_INFO_RSP)); 857 let (service, mut callback, _runtime) = setup_uwb_service(uci_manager.clone()); 858 859 callback.expect_on_service_reset(true); 860 let result = service.enable(); 861 assert_eq!(result, Ok(())); 862 assert!(service.block_on_for_testing(callback.wait_expected_calls_done())); 863 assert!(service.block_on_for_testing(uci_manager.wait_expected_calls_done())); 864 } 865 } 866