xref: /aosp_15_r20/external/uwb/src/rust/uwb_core/src/service/uwb_service.rs (revision e0df40009cb5d71e642272d38ba1bb7ffccfce41)
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