summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoshan Pius <rpius@google.com>2022-04-04 19:01:03 +0000
committerRoshan Pius <rpius@google.com>2022-04-06 13:48:51 -0700
commitd1ef03161997174b52e1a10ea44d89213849e543 (patch)
treeacc63922538341193f82517b26ee7370196e0057 /src
parent971353e612ed892e79a8717e0ced7d4aae45abd5 (diff)
downloaduwb-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.rs50
-rw-r--r--src/rust/uci/mod.rs56
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(()));