summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/Android.bp39
-rw-r--r--src/rust/uci_hal_android/error.rs128
-rw-r--r--src/rust/uci_hal_android/lib.rs18
-rw-r--r--src/rust/uci_hal_android/uci_hal_android.rs253
4 files changed, 438 insertions, 0 deletions
diff --git a/src/Android.bp b/src/Android.bp
index 23e147d..7496b61 100755
--- a/src/Android.bp
+++ b/src/Android.bp
@@ -246,6 +246,45 @@ rust_fuzz {
},
}
+rust_library {
+ name: "libuci_hal_android",
+ crate_name: "uci_hal_android",
+ lints: "android",
+ clippy_lints: "android",
+ rustlibs: [
+ "android.hardware.uwb-V1-rust",
+ "libanyhow",
+ "libbinder_ndk_sys",
+ "libbinder_rs",
+ "libbinder_tokio_rs",
+ "libbytes",
+ "libjni",
+ "liblog_rust",
+ "libthiserror",
+ "libtokio",
+ "libuwb_core",
+ "libuwb_uci_packets",
+ ],
+ target: {
+ android: {
+ rustlibs: [
+ "librustutils",
+ ],
+ },
+ },
+ proc_macros: [
+ "libasync_trait",
+ ],
+ apex_available: [
+ "com.android.ucihal",
+ ],
+ min_sdk_version: "Tiramisu",
+ host_supported: true,
+ srcs: [
+ "rust/uci_hal_android/lib.rs",
+ ],
+}
+
// Generate the artifacts zip for uwb_core library and its dependencies.
genrule {
name: "uwb_core_artifacts",
diff --git a/src/rust/uci_hal_android/error.rs b/src/rust/uci_hal_android/error.rs
new file mode 100644
index 0000000..ede1b99
--- /dev/null
+++ b/src/rust/uci_hal_android/error.rs
@@ -0,0 +1,128 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Defines error type for uci_hal_android
+
+use android_hardware_uwb::binder::{ExceptionCode, Status as BinderStatus, StatusCode};
+use uwb_core::error::Error as UwbCoreError;
+
+/// Union of the different errors with into implementations that project the error to the nearest
+/// equivalent in each error type.
+#[derive(Debug, thiserror::Error, PartialEq, Eq)]
+pub enum Error {
+ /// uwb_core::error::Error
+ #[error("UwbCore error: {0:?}")]
+ UwbCoreError(#[from] UwbCoreError),
+ /// android_hardware_uwb::binder::StatusCode
+ #[error("Binder StatusCode error: {0:?}")]
+ StatusCode(#[from] StatusCode),
+ /// android_hardware_uwb::binder::Status
+ #[error("Binder Status error: {0:?}")]
+ BinderStatus(#[from] BinderStatus),
+}
+
+/// The From traits allow conversion of Result types and ? macro.
+impl From<Error> for BinderStatus {
+ fn from(error: Error) -> BinderStatus {
+ match error {
+ Error::BinderStatus(a) => a,
+ Error::StatusCode(StatusCode::OK) => BinderStatus::ok(),
+ Error::StatusCode(e) => {
+ BinderStatus::new_exception(status_code_to_exception_code(e), None)
+ }
+ Error::UwbCoreError(e) => {
+ BinderStatus::new_exception(uwb_core_error_to_exception_code(e), None)
+ }
+ }
+ }
+}
+
+impl From<Error> for UwbCoreError {
+ fn from(error: Error) -> UwbCoreError {
+ match error {
+ Error::BinderStatus(e) => exception_code_to_uwb_error(e.exception_code()),
+ Error::StatusCode(e) => status_code_to_uwb_core_error(e),
+ Error::UwbCoreError(a) => a,
+ }
+ }
+}
+
+fn status_code_to_exception_code(status_code: StatusCode) -> ExceptionCode {
+ match status_code {
+ // StatusCode::OK should not be reached from a Result type.
+ StatusCode::OK => ExceptionCode::NONE,
+ StatusCode::NO_MEMORY => ExceptionCode::TRANSACTION_FAILED,
+ StatusCode::INVALID_OPERATION => ExceptionCode::ILLEGAL_ARGUMENT,
+ StatusCode::BAD_VALUE => ExceptionCode::ILLEGAL_ARGUMENT,
+ StatusCode::BAD_TYPE => ExceptionCode::ILLEGAL_ARGUMENT,
+ StatusCode::NAME_NOT_FOUND => ExceptionCode::ILLEGAL_ARGUMENT,
+ StatusCode::PERMISSION_DENIED => ExceptionCode::SECURITY,
+ StatusCode::NO_INIT => ExceptionCode::ILLEGAL_ARGUMENT,
+ StatusCode::ALREADY_EXISTS => ExceptionCode::ILLEGAL_ARGUMENT,
+ StatusCode::DEAD_OBJECT => ExceptionCode::ILLEGAL_ARGUMENT,
+ StatusCode::FAILED_TRANSACTION => ExceptionCode::TRANSACTION_FAILED,
+ StatusCode::BAD_INDEX => ExceptionCode::ILLEGAL_ARGUMENT,
+ StatusCode::NOT_ENOUGH_DATA => ExceptionCode::ILLEGAL_ARGUMENT,
+ StatusCode::WOULD_BLOCK => ExceptionCode::TRANSACTION_FAILED,
+ StatusCode::TIMED_OUT => ExceptionCode::TRANSACTION_FAILED,
+ StatusCode::UNKNOWN_TRANSACTION => ExceptionCode::ILLEGAL_ARGUMENT,
+ StatusCode::FDS_NOT_ALLOWED => ExceptionCode::ILLEGAL_ARGUMENT,
+ StatusCode::UNEXPECTED_NULL => ExceptionCode::ILLEGAL_ARGUMENT,
+ _ => ExceptionCode::TRANSACTION_FAILED,
+ }
+}
+
+fn status_code_to_uwb_core_error(status_code: StatusCode) -> UwbCoreError {
+ match status_code {
+ // StatusCode::OK should not be reached from a Result type.
+ StatusCode::OK => UwbCoreError::Unknown,
+ StatusCode::NO_MEMORY => UwbCoreError::Unknown,
+ StatusCode::INVALID_OPERATION => UwbCoreError::BadParameters,
+ StatusCode::BAD_VALUE => UwbCoreError::BadParameters,
+ StatusCode::BAD_TYPE => UwbCoreError::BadParameters,
+ StatusCode::NAME_NOT_FOUND => UwbCoreError::BadParameters,
+ StatusCode::PERMISSION_DENIED => UwbCoreError::BadParameters,
+ StatusCode::NO_INIT => UwbCoreError::BadParameters,
+ StatusCode::ALREADY_EXISTS => UwbCoreError::Unknown,
+ StatusCode::DEAD_OBJECT => UwbCoreError::Unknown,
+ StatusCode::FAILED_TRANSACTION => UwbCoreError::Unknown,
+ StatusCode::BAD_INDEX => UwbCoreError::BadParameters,
+ StatusCode::NOT_ENOUGH_DATA => UwbCoreError::BadParameters,
+ StatusCode::WOULD_BLOCK => UwbCoreError::Unknown,
+ StatusCode::TIMED_OUT => UwbCoreError::Timeout,
+ StatusCode::UNKNOWN_TRANSACTION => UwbCoreError::BadParameters,
+ StatusCode::FDS_NOT_ALLOWED => UwbCoreError::Unknown,
+ StatusCode::UNEXPECTED_NULL => UwbCoreError::Unknown,
+ _ => UwbCoreError::Unknown,
+ }
+}
+
+fn uwb_core_error_to_exception_code(uwb_core_error: UwbCoreError) -> ExceptionCode {
+ match uwb_core_error {
+ UwbCoreError::BadParameters => ExceptionCode::ILLEGAL_ARGUMENT,
+ _ => ExceptionCode::TRANSACTION_FAILED,
+ }
+}
+
+fn exception_code_to_uwb_error(exception_code: ExceptionCode) -> UwbCoreError {
+ match exception_code {
+ ExceptionCode::ILLEGAL_ARGUMENT
+ | ExceptionCode::ILLEGAL_STATE
+ | ExceptionCode::UNSUPPORTED_OPERATION
+ | ExceptionCode::NULL_POINTER => UwbCoreError::BadParameters,
+ _ => UwbCoreError::Unknown,
+ }
+}
+/// Result type associated with Error:
+pub type Result<T> = std::result::Result<T, Error>;
diff --git a/src/rust/uci_hal_android/lib.rs b/src/rust/uci_hal_android/lib.rs
new file mode 100644
index 0000000..2de9c94
--- /dev/null
+++ b/src/rust/uci_hal_android/lib.rs
@@ -0,0 +1,18 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! This library provides adaptation to UWB core from Android UCI HAL library.
+
+pub mod error;
+pub mod uci_hal_android;
diff --git a/src/rust/uci_hal_android/uci_hal_android.rs b/src/rust/uci_hal_android/uci_hal_android.rs
new file mode 100644
index 0000000..1b3d297
--- /dev/null
+++ b/src/rust/uci_hal_android/uci_hal_android.rs
@@ -0,0 +1,253 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Implements UciHal trait for Android.
+
+use std::sync::Arc;
+
+use android_hardware_uwb::aidl::android::hardware::uwb::{
+ IUwb::IUwbAsync,
+ IUwbChip::IUwbChipAsync,
+ IUwbClientCallback::{BnUwbClientCallback, IUwbClientCallbackAsyncServer},
+ UwbEvent::UwbEvent,
+ UwbStatus::UwbStatus,
+};
+use android_hardware_uwb::binder::{
+ BinderFeatures, DeathRecipient, ExceptionCode, IBinder, Interface, Result as BinderResult,
+ Status as BinderStatus, Strong,
+};
+use async_trait::async_trait;
+use binder_tokio::{Tokio, TokioRuntime};
+use log::error;
+use tokio::runtime::Handle;
+use tokio::sync::{mpsc, Mutex};
+use uwb_core::error::{Error as UwbCoreError, Result as UwbCoreResult};
+use uwb_core::params::uci_packets::SessionId;
+use uwb_core::uci::uci_hal::{RawUciMessage, UciHal};
+use uwb_uci_packets::{DeviceState, DeviceStatusNtfBuilder};
+
+use crate::error::{Error, Result};
+
+fn into_raw_messages<T: Into<uwb_uci_packets::UciPacketPacket>>(builder: T) -> Vec<RawUciMessage> {
+ let packets: Vec<uwb_uci_packets::UciPacketHalPacket> = builder.into().into();
+ packets.into_iter().map(|packet| packet.into()).collect()
+}
+
+/// Send device status notification with error state.
+fn send_device_state_error_notification(
+ uci_sender: &mpsc::UnboundedSender<RawUciMessage>,
+) -> UwbCoreResult<()> {
+ let raw_message_packets =
+ into_raw_messages(DeviceStatusNtfBuilder { device_state: DeviceState::DeviceStateError });
+ for raw_message_packet in raw_message_packets {
+ if let Err(e) = uci_sender.send(raw_message_packet) {
+ error!("Error sending device state error notification: {:?}", e);
+ return Err(UwbCoreError::BadParameters);
+ }
+ }
+ Ok(())
+}
+
+/// Redirects the raw UCI callbacks to UciHalAndroid and manages the HalEvent.
+///
+/// RawUciCallback Redirects Raw UCI callbacks upstream, and manages HalEvent.
+/// RawUciCallback is declared as a seprate struct as a struct with IUwbClientCallbackAsyncServer
+/// trait is consumed by BnUwbClientCallback, thus it cannot be implemented for UciHalAndroid.
+#[derive(Clone, Debug)]
+struct RawUciCallback {
+ uci_sender: mpsc::UnboundedSender<RawUciMessage>,
+ hal_open_result_sender: mpsc::Sender<Result<()>>,
+ hal_close_result_sender: mpsc::Sender<Result<()>>,
+}
+
+impl RawUciCallback {
+ pub fn new(
+ uci_sender: mpsc::UnboundedSender<RawUciMessage>,
+ hal_open_result_sender: mpsc::Sender<Result<()>>,
+ hal_close_result_sender: mpsc::Sender<Result<()>>,
+ ) -> Self {
+ Self { uci_sender, hal_open_result_sender, hal_close_result_sender }
+ }
+}
+
+impl Interface for RawUciCallback {}
+
+#[async_trait]
+impl IUwbClientCallbackAsyncServer for RawUciCallback {
+ async fn onHalEvent(&self, event: UwbEvent, _event_status: UwbStatus) -> BinderResult<()> {
+ match event {
+ // UwbEvent::ERROR is processed differently by UciHalAndroid depending on its state.
+ //
+ // If error occurs before POST_INIT_CPLT received: UciHalAndroid handles the error.
+ // If error occurs after POST_INIT_CPLT received: UciHalAndroid redirects the error
+ // upstream by converting it to UCI DeviceStatusNtf.
+ // Both are attempted as RawUciCallback is not aware of the state for UciHalAndroid.
+ // Similarly, error due to close of hal cannot be reported as both the reason of the
+ // error and expectation of UciHalAndroid are unknown.
+ UwbEvent::ERROR => {
+ // Error sending hal_open_result_sender is not meaningful, as RawUciCallback do not
+ // know the reason for UwbEvent::ERROR. The receiving end only listens to
+ // hal_open_result_sender when it is expecting POST_INIT_CPLT or ERROR.
+ let _ = self.hal_open_result_sender.try_send(Err(Error::BinderStatus(
+ BinderStatus::new_exception(ExceptionCode::TRANSACTION_FAILED, None),
+ )));
+
+ send_device_state_error_notification(&self.uci_sender)
+ .map_err(|e| BinderStatus::from(Error::from(e)))
+ }
+ UwbEvent::POST_INIT_CPLT => self.hal_open_result_sender.try_send(Ok(())).map_err(|e| {
+ error!("Failed sending POST_INIT_CPLT: {:?}", e);
+ BinderStatus::new_exception(ExceptionCode::TRANSACTION_FAILED, None)
+ }),
+ UwbEvent::CLOSE_CPLT => self.hal_close_result_sender.try_send(Ok(())).map_err(|e| {
+ error!("Failed sending CLOSE_CPLT: {:?}", e);
+ BinderStatus::new_exception(ExceptionCode::TRANSACTION_FAILED, None)
+ }),
+ _ => Ok(()),
+ }
+ }
+
+ async fn onUciMessage(&self, data: &[u8]) -> BinderResult<()> {
+ self.uci_sender.send(data.to_owned()).map_err(|e| {
+ error!("Failed sending UCI response or notification: {:?}", e);
+ BinderStatus::new_exception(ExceptionCode::TRANSACTION_FAILED, None)
+ })
+ }
+}
+
+/// Implentation of UciHal trait for Android.
+#[derive(Default)]
+pub struct UciHalAndroid {
+ // Has a copy of msg_sender via RawUciCallback.
+ hal_uci_recipient: Option<Strong<dyn IUwbChipAsync<Tokio>>>,
+ hal_death_recipient: Option<Arc<Mutex<DeathRecipient>>>,
+ hal_close_result_receiver: Option<mpsc::Receiver<Result<()>>>,
+}
+
+#[allow(dead_code)]
+impl UciHalAndroid {
+ /// Constructor for empty UciHal.
+ pub fn new() -> Self {
+ Self { hal_uci_recipient: None, hal_death_recipient: None, hal_close_result_receiver: None }
+ }
+}
+
+#[async_trait]
+impl UciHal for UciHalAndroid {
+ /// Open the UCI HAL and power on the UWBS.
+ async fn open(
+ &mut self,
+ msg_sender: mpsc::UnboundedSender<RawUciMessage>,
+ ) -> UwbCoreResult<()> {
+ // Returns error if UciHalAndroid is already open.
+ if self.hal_uci_recipient.is_some() {
+ return Err(UwbCoreError::BadParameters);
+ }
+
+ // Get hal service.
+ let service_name = "android.hardware.uwb.IUwb/default";
+ let i_uwb: Strong<dyn IUwbAsync<Tokio>> =
+ binder_tokio::get_interface(service_name)
+ .await
+ .map_err(|e| UwbCoreError::from(Error::from(e)))?;
+ let chip_names = i_uwb.getChips().await.map_err(|e| UwbCoreError::from(Error::from(e)))?;
+ let i_uwb_chip = i_uwb
+ .getChip(&chip_names[0])
+ .await
+ .map_err(|e| UwbCoreError::from(Error::from(e)))?
+ .into_async();
+
+ // If the binder object unexpectedly goes away (typically because its hosting process has
+ // been killed), then the `DeathRecipient`'s callback will be called.
+ let msg_sender_clone = msg_sender.clone();
+ let mut bare_death_recipient = DeathRecipient::new(move || {
+ send_device_state_error_notification(&msg_sender_clone).unwrap_or_else(|e| {
+ error!("Error sending device state error notification: {:?}", e);
+ });
+ });
+ i_uwb_chip
+ .as_binder()
+ .link_to_death(&mut bare_death_recipient)
+ .map_err(|e| UwbCoreError::from(Error::from(e)))?;
+
+ // Connect callback to msg_sender.
+ let (hal_open_result_sender, mut hal_open_result_receiver) = mpsc::channel::<Result<()>>(1);
+ let (hal_close_result_sender, hal_close_result_receiver) = mpsc::channel::<Result<()>>(1);
+ let m_cback = BnUwbClientCallback::new_async_binder(
+ RawUciCallback::new(msg_sender, hal_open_result_sender, hal_close_result_sender),
+ TokioRuntime(Handle::current()),
+ BinderFeatures::default(),
+ );
+ i_uwb_chip.open(&m_cback).await.map_err(|e| UwbCoreError::from(Error::from(e)))?;
+ match hal_open_result_receiver.recv().await {
+ Some(Ok(())) => {
+ self.hal_uci_recipient.replace(i_uwb_chip);
+ self.hal_death_recipient.replace(Arc::new(Mutex::new(bare_death_recipient)));
+ self.hal_close_result_receiver.replace(hal_close_result_receiver);
+ Ok(())
+ }
+ _ => {
+ error!("POST_INIT_CPLT event is not received");
+ Err(UwbCoreError::Unknown)
+ }
+ }
+ }
+
+ async fn close(&mut self) -> UwbCoreResult<()> {
+ // Reset UciHalAndroid regardless of whether hal_close is successful or not.
+ let hal_uci_recipient = self.hal_uci_recipient.take();
+ let _hal_death_recipient = self.hal_death_recipient.take();
+ let hal_close_result_receiver = self.hal_close_result_receiver.take();
+ match hal_uci_recipient {
+ Some(i_uwb_chip) => {
+ i_uwb_chip.close().await.map_err(|e| UwbCoreError::from(Error::from(e)))
+ }
+ None => Err(UwbCoreError::BadParameters),
+ }?;
+ match hal_close_result_receiver.unwrap().recv().await {
+ // When RawUciCallback received an error due to this close() function, currently none of
+ // the error messages will be triggered, and this close() will be pending until timeout,
+ // as the reason for the UwbEvent::ERROR cannot be determined.
+ Some(result) => result.map_err(|_| UwbCoreError::Unknown),
+ None => Err(UwbCoreError::Unknown),
+ }
+ }
+
+ async fn send_command(&mut self, cmd: RawUciMessage) -> UwbCoreResult<()> {
+ match &self.hal_uci_recipient {
+ Some(i_uwb_chip) => {
+ i_uwb_chip
+ .sendUciMessage(&cmd)
+ .await
+ .map_err(|e| UwbCoreError::from(Error::from(e)))?;
+ Ok(())
+ }
+ None => Err(UwbCoreError::BadParameters),
+ }
+ }
+
+ async fn notify_session_initialized(&mut self, session_id: SessionId) -> UwbCoreResult<()> {
+ match &self.hal_uci_recipient {
+ Some(i_uwb_chip) => {
+ i_uwb_chip
+ // HAL API accepts signed int, so cast received session_id as i32.
+ .sessionInit(session_id as i32)
+ .await
+ .map_err(|e| UwbCoreError::from(Error::from(e)))?;
+ Ok(())
+ }
+ None => Err(UwbCoreError::BadParameters),
+ }
+ }
+}