diff options
author | Roshan Pius <rpius@google.com> | 2022-04-04 19:01:03 +0000 |
---|---|---|
committer | Roshan Pius <rpius@google.com> | 2022-04-06 13:48:51 -0700 |
commit | d1ef03161997174b52e1a10ea44d89213849e543 (patch) | |
tree | acc63922538341193f82517b26ee7370196e0057 /src | |
parent | 971353e612ed892e79a8717e0ced7d4aae45abd5 (diff) | |
download | uwb-d1ef03161997174b52e1a10ea44d89213849e543.tar.gz |
uwb(uci_rust): Handle vendor HAL crashes gracefully
Send DeviceStatusNotification with state = Error to the java stack when
there is a fatal error in the HAL (indicated by HAL crash or explicit
HAL event with event = Error).
Bug: 227488208
Test: Manual tests
Test: atest libuwb_uci_rust_tests
Change-Id: I6e8c394c4c27e4173cb25528d0cbf04a2029a2c1
Diffstat (limited to 'src')
-rw-r--r-- | src/rust/adaptation/mod.rs | 50 | ||||
-rw-r--r-- | src/rust/uci/mod.rs | 56 |
2 files changed, 89 insertions, 17 deletions
diff --git a/src/rust/adaptation/mod.rs b/src/rust/adaptation/mod.rs index fbeb639..ca7d814 100644 --- a/src/rust/adaptation/mod.rs +++ b/src/rust/adaptation/mod.rs @@ -11,8 +11,11 @@ use android_hardware_uwb::aidl::android::hardware::uwb::{ UwbEvent::UwbEvent, UwbStatus::UwbStatus, }; -use android_hardware_uwb::binder::{BinderFeatures, Interface, Result as BinderResult, Strong}; +use android_hardware_uwb::binder::{ + BinderFeatures, DeathRecipient, Interface, Result as BinderResult, Strong, +}; use async_trait::async_trait; +use binder::IBinder; use binder_tokio::{Tokio, TokioRuntime}; use log::{error, warn}; use rustutils::system_properties; @@ -134,6 +137,9 @@ pub trait UwbAdaptation { #[derive(Clone)] pub struct UwbAdaptationImpl { hal: Strong<dyn IUwbChipAsync<Tokio>>, + #[allow(dead_code)] + // Need to store the death recipient since link_to_death stores a weak pointer. + hal_death_recipient: Arc<Mutex<DeathRecipient>>, rsp_sender: mpsc::UnboundedSender<HalCallback>, logger: SyncUciLogger, } @@ -142,6 +148,7 @@ impl UwbAdaptationImpl { async fn new_with_args( rsp_sender: mpsc::UnboundedSender<HalCallback>, hal: Strong<dyn IUwbChipAsync<Tokio>>, + hal_death_recipient: Arc<Mutex<DeathRecipient>>, ) -> Result<Self> { let mode = match system_properties::read("persist.uwb.uci_logger_mode") { Ok(Some(logger_mode)) => match logger_mode.as_str() { @@ -160,12 +167,25 @@ impl UwbAdaptationImpl { } }; let logger = UciLoggerImpl::new(mode).await; - Ok(UwbAdaptationImpl { hal, rsp_sender, logger: Arc::new(logger) }) + Ok(UwbAdaptationImpl { hal, rsp_sender, logger: Arc::new(logger), hal_death_recipient }) } pub async fn new(rsp_sender: mpsc::UnboundedSender<HalCallback>) -> Result<Self> { let hal = get_hal_service().await?; - Self::new_with_args(rsp_sender, hal).await + let rsp_sender_clone = rsp_sender.clone(); + let mut hal_death_recipient = DeathRecipient::new(move || { + error!("UWB HAL died. Resetting stack..."); + // Send error HAL event to trigger stack recovery. + rsp_sender_clone + .send(HalCallback::Event { + event: UwbEvent::ERROR, + event_status: UwbStatus::FAILED, + }) + .unwrap_or_else(|e| error!("Error sending error evt callback: {:?}", e)); + }); + // Register for death notification. + hal.as_binder().link_to_death(&mut hal_death_recipient)?; + Self::new_with_args(rsp_sender, hal, Arc::new(Mutex::new(hal_death_recipient))).await } } @@ -216,7 +236,7 @@ pub mod tests { use android_hardware_uwb::aidl::android::hardware::uwb::{ IUwbChip::IUwbChipAsync, IUwbClientCallback::IUwbClientCallback, }; - use android_hardware_uwb::binder::Result as BinderResult; + use android_hardware_uwb::binder::{DeathRecipient, Result as BinderResult}; use binder::{SpIBinder, StatusCode}; use bytes::Bytes; use log::warn; @@ -773,10 +793,13 @@ pub mod tests { let cmd_frag_data_len = cmd_frag_data.len(); mock_hal.expect_send_uci_message(cmd_frag_data, Ok(cmd_frag_data_len.try_into().unwrap())); - let adaptation_impl = - UwbAdaptationImpl::new_with_args(rsp_sender, binder::Strong::new(Box::new(mock_hal))) - .await - .unwrap(); + let adaptation_impl = UwbAdaptationImpl::new_with_args( + rsp_sender, + binder::Strong::new(Box::new(mock_hal)), + Arc::new(Mutex::new(DeathRecipient::new(|| {}))), + ) + .await + .unwrap(); adaptation_impl.send_uci_message(cmd).await.unwrap(); } @@ -869,10 +892,13 @@ pub mod tests { cmd_frag_data_2.to_vec(), Ok(cmd_frag_data_len_2.try_into().unwrap()), ); - let adaptation_impl = - UwbAdaptationImpl::new_with_args(rsp_sender, binder::Strong::new(Box::new(mock_hal))) - .await - .unwrap(); + let adaptation_impl = UwbAdaptationImpl::new_with_args( + rsp_sender, + binder::Strong::new(Box::new(mock_hal)), + Arc::new(Mutex::new(DeathRecipient::new(|| {}))), + ) + .await + .unwrap(); adaptation_impl.send_uci_message(cmd).await.unwrap(); } } diff --git a/src/rust/uci/mod.rs b/src/rust/uci/mod.rs index c53d3cb..b6c38bd 100644 --- a/src/rust/uci/mod.rs +++ b/src/rust/uci/mod.rs @@ -33,10 +33,10 @@ use tokio::runtime::{Builder, Runtime}; use tokio::sync::{mpsc, oneshot, Notify}; use tokio::{select, task}; use uwb_uci_packets::{ - AndroidGetPowerStatsCmdBuilder, GetCapsInfoCmdBuilder, GetDeviceInfoCmdBuilder, - GetDeviceInfoRspPacket, RangeStartCmdBuilder, RangeStopCmdBuilder, SessionDeinitCmdBuilder, - SessionGetAppConfigCmdBuilder, SessionGetCountCmdBuilder, SessionGetStateCmdBuilder, - SessionState, SessionStatusNtfPacket, StatusCode, UciCommandPacket, + AndroidGetPowerStatsCmdBuilder, DeviceState, DeviceStatusNtfBuilder, GetCapsInfoCmdBuilder, + GetDeviceInfoCmdBuilder, GetDeviceInfoRspPacket, RangeStartCmdBuilder, RangeStopCmdBuilder, + SessionDeinitCmdBuilder, SessionGetAppConfigCmdBuilder, SessionGetCountCmdBuilder, + SessionGetStateCmdBuilder, SessionState, SessionStatusNtfPacket, StatusCode, UciCommandPacket, }; pub type Result<T> = std::result::Result<T, UwbErr>; @@ -406,7 +406,13 @@ impl<T: EventManager> Driver<T> { UwbEvent::CLOSE_CPLT => { self.set_state(UwbState::None); } - _ => (), + UwbEvent::ERROR => { + // Send device status notification with error state. + let device_status_ntf = DeviceStatusNtfBuilder { device_state: DeviceState::DeviceStateError}.build(); + self.event_manager.device_status_notification_received(device_status_ntf)?; + self.set_state(UwbState::None); + } + _ => () } }, HalCallback::UciRsp(response) => { @@ -553,6 +559,9 @@ mod tests { use super::*; use crate::adaptation::tests::MockUwbAdaptation; use crate::event_manager::MockEventManager; + use android_hardware_uwb::aidl::android::hardware::uwb::{ + UwbEvent::UwbEvent, UwbStatus::UwbStatus, + }; use uwb_uci_packets::{ DeviceState, DeviceStatusNtfBuilder, GetDeviceInfoRspBuilder, Packet, UciPacketHalPacket, UciPacketPacket, @@ -579,6 +588,27 @@ mod tests { ) } + fn setup_dispatcher_and_return_hal_cb_sender( + config_fn: fn(&mut Arc<MockUwbAdaptation>, &mut MockEventManager), + ) -> Result<(DispatcherImpl, mpsc::UnboundedSender<HalCallback>)> { + // TODO: Remove this once we call it somewhere real. + logger::init( + logger::Config::default().with_tag_on_device("uwb").with_min_level(log::Level::Debug), + ); + + let (rsp_sender, rsp_receiver) = mpsc::unbounded_channel::<HalCallback>(); + let mut mock_adaptation = Arc::new(MockUwbAdaptation::new(rsp_sender.clone())); + let mut mock_event_manager = MockEventManager::new(); + + config_fn(&mut mock_adaptation, &mut mock_event_manager); + let dispatcher = DispatcherImpl::new_for_testing( + mock_event_manager, + mock_adaptation as SyncUwbAdaptation, + rsp_receiver, + )?; + Ok((dispatcher, rsp_sender)) + } + fn generate_fake_cmd_rsp_data() -> (Vec<u8>, Vec<u8>) { let cmd_data = GetDeviceInfoCmdBuilder {}.build().to_vec(); let rsp_packet: UciPacketPacket = GetDeviceInfoRspBuilder { @@ -618,6 +648,22 @@ mod tests { } #[test] + fn test_hal_error_event() -> Result<()> { + let (mut dispatcher, hal_sender) = + setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, mock_event_manager| { + mock_adaptation.expect_hal_open(Ok(())); + mock_adaptation.expect_core_initialization(Ok(())); + mock_event_manager.expect_device_status_notification_received(Ok(())); + })?; + + dispatcher.send_jni_command(JNICommand::Enable)?; + hal_sender + .send(HalCallback::Event { event: UwbEvent::ERROR, event_status: UwbStatus::FAILED }) + .unwrap(); + dispatcher.exit() + } + + #[test] fn test_deinitialize() -> Result<()> { let mut dispatcher = setup_dispatcher(|mock_adaptation, _mock_event_manager| { mock_adaptation.expect_hal_close(Ok(())); |