summaryrefslogtreecommitdiff
path: root/src/rust/event_manager/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/rust/event_manager/mod.rs')
-rw-r--r--src/rust/event_manager/mod.rs501
1 files changed, 467 insertions, 34 deletions
diff --git a/src/rust/event_manager/mod.rs b/src/rust/event_manager/mod.rs
index c83fb68..2499f45 100644
--- a/src/rust/event_manager/mod.rs
+++ b/src/rust/event_manager/mod.rs
@@ -15,17 +15,26 @@
*/
use crate::uci::uci_hrcv::UciNotification;
-use jni::errors::Result;
-use jni::objects::{GlobalRef, JObject, JValue};
+use jni::errors::{Error, Result};
+use jni::objects::{GlobalRef, JClass, JMethodID, JObject, JValue, JValue::Void};
+use jni::signature::JavaType;
+use jni::sys::jobjectArray;
use jni::{AttachGuard, JNIEnv, JavaVM};
use log::error;
use num_traits::ToPrimitive;
use std::convert::TryInto;
+use std::vec::Vec;
use uwb_uci_packets::{
- DeviceStatusNtfPacket, GenericErrorPacket, SessionStatusNtfPacket,
- ShortMacTwoWayRangeDataNtfPacket,
+ DeviceStatusNtfPacket, ExtendedAddressTwoWayRangingMeasurement,
+ ExtendedMacTwoWayRangeDataNtfPacket, GenericErrorPacket, RangeDataNtfPacket,
+ SessionStatusNtfPacket, ShortAddressTwoWayRangingMeasurement, ShortMacTwoWayRangeDataNtfPacket,
};
+const UWB_RANGING_DATA_CLASS: &str = "com/android/uwb/data/UwbRangingData";
+const UWB_TWO_WAY_MEASUREMENT_CLASS: &str = "com/android/uwb/data/UwbTwoWayMeasurement";
+const SHORT_MAC_ADDRESS_LEN: usize = 2;
+const EXTENDED_MAC_ADDRESS_LEN: usize = 8;
+
// TODO: Reconsider the best way to cache the JNIEnv. We currently attach and detach for every
// call, which the documentation warns could be expensive. We could attach the thread permanently,
// but that would not allow us to detach when we drop this structure. We could cache the
@@ -40,6 +49,8 @@ use uwb_uci_packets::{
pub struct EventManager {
jvm: JavaVM,
obj: GlobalRef,
+ // cache used to lookup uwb classes in callback.
+ class_loader_obj: GlobalRef,
}
impl EventManager {
@@ -47,58 +58,480 @@ impl EventManager {
pub fn new(env: JNIEnv, obj: JObject) -> Result<Self> {
let jvm = env.get_java_vm()?;
let obj = env.new_global_ref(obj)?;
- Ok(EventManager { jvm, obj })
+ let class_loader_obj = EventManager::get_classloader_obj(&env)?;
+ let class_loader_obj = env.new_global_ref(class_loader_obj)?;
+ Ok(EventManager { jvm, obj, class_loader_obj })
}
- pub fn device_status_notification_received(&self, data: DeviceStatusNtfPacket) -> Result<()> {
- let state = data.get_device_state().to_u8().expect("Failed converting device_state to u8");
- let env = self.jvm.attach_current_thread()?;
- let result = env.call_method(
+ fn get_classloader_obj<'a>(env: &'a JNIEnv) -> Result<JObject<'a>> {
+ // Use UwbRangingData class to find the classloader used by the java service.
+ let ranging_data_class = env.find_class(&UWB_RANGING_DATA_CLASS)?;
+ let ranging_data_class_class = env.get_object_class(ranging_data_class)?;
+ let get_class_loader_method = env.get_method_id(
+ ranging_data_class_class,
+ "getClassLoader",
+ "()Ljava/lang/ClassLoader;",
+ )?;
+ let class_loader = env.call_method_unchecked(
+ ranging_data_class,
+ get_class_loader_method,
+ JavaType::Object("java/lang/ClassLoader".into()),
+ &[Void],
+ )?;
+ class_loader.l()
+ }
+
+ fn find_class<'a>(&'a self, env: &'a JNIEnv, class_name: &'a str) -> Result<JClass<'a>> {
+ let class_value = env.call_method(
+ self.class_loader_obj.as_obj(),
+ "findClass",
+ "(Ljava/lang/String;)Ljava/lang/Class;",
+ &[JValue::Object(JObject::from(env.new_string(class_name)?))],
+ )?;
+ class_value.l().map(|value| JClass::from(value))
+ }
+
+ fn handle_device_status_notification_received(
+ &self,
+ env: &JNIEnv,
+ data: DeviceStatusNtfPacket,
+ ) -> Result<()> {
+ let state =
+ data.get_device_state().to_i32().expect("Failed converting device_state to i32");
+ env.call_method(
self.obj.as_obj(),
"onDeviceStatusNotificationReceived",
"(I)V",
- &[JValue::Int(state.try_into().expect("Could not convert device_state"))],
- );
- self.cleanup_and_return(env, result)
+ &[JValue::Int(state)],
+ )
+ .map(|_| ()) // drop void method return
}
- pub fn session_status_notification_received(&self, data: SessionStatusNtfPacket) -> Result<()> {
+ pub fn device_status_notification_received(&self, data: DeviceStatusNtfPacket) -> Result<()> {
+ let env = self.jvm.attach_current_thread()?;
+ let result = self.handle_device_status_notification_received(&env, data);
+ self.clear_exception(env);
+ result
+ }
+
+ fn handle_session_status_notification_received(
+ &self,
+ env: &JNIEnv,
+ data: SessionStatusNtfPacket,
+ ) -> Result<()> {
let session_id =
- data.get_session_id().to_u32().expect("Failed converting session_id to u32");
+ data.get_session_id().to_i64().expect("Failed converting session_id to i64");
let state =
- data.get_session_state().to_u8().expect("Failed converting session_state to u8");
+ data.get_session_state().to_i32().expect("Failed converting session_state to i32");
let reason_code =
- data.get_reason_code().to_u8().expect("Failed coverting reason_code to u32");
- let env = self.jvm.attach_current_thread()?;
- let result = env.call_method(
+ data.get_reason_code().to_i32().expect("Failed coverting reason_code to i32");
+ env.call_method(
self.obj.as_obj(),
"onSessionStatusNotificationReceived",
"(JII)V",
- &[
- JValue::Long(session_id.try_into().expect("Could not convert session_id")),
- JValue::Int(state.try_into().expect("Could not convert session_state")),
- JValue::Int(reason_code.try_into().expect("Could not convert reason_code")),
- ],
- );
- self.cleanup_and_return(env, result)
+ &[JValue::Long(session_id), JValue::Int(state), JValue::Int(reason_code)],
+ )
+ .map(|_| ()) // drop void method return
}
- pub fn core_generic_error_notification_received(&self, data: GenericErrorPacket) -> Result<()> {
- let status = data.get_status().to_u8().expect("Failed converting status to u8");
+ pub fn session_status_notification_received(&self, data: SessionStatusNtfPacket) -> Result<()> {
let env = self.jvm.attach_current_thread()?;
- let result = env.call_method(
+ let result = self.handle_session_status_notification_received(&env, data);
+ self.clear_exception(env);
+ result
+ }
+
+ fn handle_core_generic_error_notification_received(
+ &self,
+ env: &JNIEnv,
+ data: GenericErrorPacket,
+ ) -> Result<()> {
+ let status = data.get_status().to_i32().expect("Failed converting status to i32");
+ env.call_method(
self.obj.as_obj(),
"onCoreGenericErrorNotificationReceived",
"(I)V",
- &[JValue::Int(status.try_into().expect("Could not convert status"))],
- );
- self.cleanup_and_return(env, result)
+ &[JValue::Int(status)],
+ )
+ .map(|_| ()) // drop void method return
+ }
+
+ pub fn core_generic_error_notification_received(&self, data: GenericErrorPacket) -> Result<()> {
+ let env = self.jvm.attach_current_thread()?;
+ let result = self.handle_core_generic_error_notification_received(&env, data);
+ self.clear_exception(env);
+ result
+ }
+
+ fn create_zeroed_two_way_measurement_java<'a>(
+ env: &'a JNIEnv,
+ two_way_measurement_class: JClass,
+ mac_address_java: jobjectArray,
+ ) -> Result<JObject<'a>> {
+ env.new_object(
+ two_way_measurement_class,
+ "([BIIIIIIIIIIII)V",
+ &[
+ JValue::Object(JObject::from(mac_address_java)),
+ JValue::Int(0),
+ JValue::Int(0),
+ JValue::Int(0),
+ JValue::Int(0),
+ JValue::Int(0),
+ JValue::Int(0),
+ JValue::Int(0),
+ JValue::Int(0),
+ JValue::Int(0),
+ JValue::Int(0),
+ JValue::Int(0),
+ JValue::Int(0),
+ ],
+ )
+ }
+
+ fn create_short_mac_two_way_measurement_java<'a>(
+ env: &'a JNIEnv,
+ two_way_measurement_class: JClass,
+ two_way_measurement: &'a ShortAddressTwoWayRangingMeasurement,
+ ) -> Result<JObject<'a>> {
+ let mac_address_arr = two_way_measurement.mac_address.to_ne_bytes();
+ let mac_address_java = env.new_byte_array(
+ SHORT_MAC_ADDRESS_LEN.to_i32().expect("Failed converting mac address len to i32"),
+ )?;
+ // Convert from [u8] to [i8] since java does not support unsigned byte.
+ let mac_address_arr_i8 = mac_address_arr.map(|x| x as i8);
+ env.set_byte_array_region(mac_address_java, 0, &mac_address_arr_i8)?;
+ env.new_object(
+ two_way_measurement_class,
+ "([BIIIIIIIIIIII)V",
+ &[
+ JValue::Object(JObject::from(mac_address_java)),
+ JValue::Int(
+ two_way_measurement.status.to_i32().expect("Failed converting status to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement.nlos.to_i32().expect("Failed converting nlos to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .distance
+ .to_i32()
+ .expect("Failed converting distance to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_azimuth
+ .to_i32()
+ .expect("Failed converting aoa azimuth to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_azimuth_fom
+ .to_i32()
+ .expect("Failed converting aoa azimuth fom to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_elevation
+ .to_i32()
+ .expect("Failed converting aoa elevation to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_elevation_fom
+ .to_i32()
+ .expect("Failed converting aoa elevaion fom to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_destination_azimuth
+ .to_i32()
+ .expect("Failed converting dest aoa azimuth to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_destination_azimuth_fom
+ .to_i32()
+ .expect("Failed converting dest aoa azimuth fom to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_destination_elevation
+ .to_i32()
+ .expect("Failed converting dest aoa elevation to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_destination_elevation_fom
+ .to_i32()
+ .expect("Failed converting dest aoa elevation azimuth to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .slot_index
+ .to_i32()
+ .expect("Failed converting slot index to i32"),
+ ),
+ ],
+ )
+ }
+
+ fn create_extended_mac_two_way_measurement_java<'a>(
+ env: &'a JNIEnv,
+ two_way_measurement_class: JClass,
+ two_way_measurement: &'a ExtendedAddressTwoWayRangingMeasurement,
+ ) -> Result<JObject<'a>> {
+ let mac_address_arr = two_way_measurement.mac_address.to_ne_bytes();
+ let mac_address_java = env.new_byte_array(
+ EXTENDED_MAC_ADDRESS_LEN.to_i32().expect("Failed converting mac address len to i32"),
+ )?;
+ // Convert from [u8] to [i8] since java does not support unsigned byte.
+ let mac_address_arr_i8 = mac_address_arr.map(|x| x as i8);
+ env.set_byte_array_region(mac_address_java, 0, &mac_address_arr_i8)?;
+ env.new_object(
+ two_way_measurement_class,
+ "([BIIIIIIIIIIII)V",
+ &[
+ JValue::Object(JObject::from(mac_address_java)),
+ JValue::Int(
+ two_way_measurement.status.to_i32().expect("Failed converting status to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement.nlos.to_i32().expect("Failed converting nlos to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .distance
+ .to_i32()
+ .expect("Failed converting distance to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_azimuth
+ .to_i32()
+ .expect("Failed converting aoa azimuth to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_azimuth_fom
+ .to_i32()
+ .expect("Failed converting aoa azimuth fom to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_elevation
+ .to_i32()
+ .expect("Failed converting aoa elevation to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_elevation_fom
+ .to_i32()
+ .expect("Failed converting aoa elevaion fom to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_destination_azimuth
+ .to_i32()
+ .expect("Failed converting dest aoa azimuth to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_destination_azimuth_fom
+ .to_i32()
+ .expect("Failed converting dest aoa azimuth fom to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_destination_elevation
+ .to_i32()
+ .expect("Failed converting dest aoa elevation to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .aoa_destination_elevation_fom
+ .to_i32()
+ .expect("Failed converting dest aoa elevation azimuth to i32"),
+ ),
+ JValue::Int(
+ two_way_measurement
+ .slot_index
+ .to_i32()
+ .expect("Failed converting slot index to i32"),
+ ),
+ ],
+ )
+ }
+
+ fn create_range_data_java<'a>(
+ &'a self,
+ env: &'a JNIEnv,
+ data: RangeDataNtfPacket,
+ two_way_measurements_java: jobjectArray,
+ num_two_way_measurements: i32,
+ ) -> Result<JObject<'a>> {
+ let ranging_data_class = self.find_class(env, &UWB_RANGING_DATA_CLASS)?;
+ env.new_object(
+ ranging_data_class,
+ "(JJIJIII[Lcom/android/uwb/data/UwbTwoWayMeasurement;)V",
+ &[
+ JValue::Long(
+ data.get_sequence_number().to_i64().expect("Failed converting seq num to i64"),
+ ),
+ JValue::Long(
+ data.get_session_id().to_i64().expect("Failed converting session id to i64"),
+ ),
+ JValue::Int(
+ data.get_rcr_indicator()
+ .to_i32()
+ .expect("Failed converting rcr indicator to i32"),
+ ),
+ JValue::Long(
+ data.get_current_ranging_interval()
+ .to_i64()
+ .expect("Failed converting curr ranging interval to i32"),
+ ),
+ JValue::Int(
+ data.get_ranging_measurement_type()
+ .to_i32()
+ .expect("Failed converting ranging measurement type to i32"),
+ ),
+ JValue::Int(
+ data.get_mac_address_indicator()
+ .to_i32()
+ .expect("Failed converting mac address indicator to i32"),
+ ),
+ JValue::Int(num_two_way_measurements),
+ JValue::Object(JObject::from(two_way_measurements_java)),
+ ],
+ )
+ }
+
+ fn handle_short_range_data_notification(
+ &self,
+ env: &JNIEnv,
+ data: ShortMacTwoWayRangeDataNtfPacket,
+ ) -> Result<()> {
+ let two_way_measurement_class = self.find_class(&env, &UWB_TWO_WAY_MEASUREMENT_CLASS)?;
+ let two_way_measurement_initial_java =
+ EventManager::create_zeroed_two_way_measurement_java(
+ &env,
+ two_way_measurement_class,
+ env.new_byte_array(
+ EXTENDED_MAC_ADDRESS_LEN
+ .to_i32()
+ .expect("Failed converting mac address len to i32"),
+ )?,
+ )?;
+ let num_two_way_measurements: i32 = data
+ .get_two_way_ranging_measurements()
+ .len()
+ .to_i32()
+ .expect("Failed converting len to i32");
+ let two_way_measurements_java = env.new_object_array(
+ num_two_way_measurements,
+ two_way_measurement_class,
+ two_way_measurement_initial_java,
+ )?;
+ for (i, two_way_measurement) in data.get_two_way_ranging_measurements().iter().enumerate() {
+ let two_way_measurement_java = EventManager::create_short_mac_two_way_measurement_java(
+ &env,
+ two_way_measurement_class,
+ two_way_measurement,
+ )?;
+ env.set_object_array_element(
+ two_way_measurements_java,
+ i.to_i32().expect("Failed converting idx to i32"),
+ two_way_measurement_java,
+ )?
+ }
+ let ranging_data_java = self.create_range_data_java(
+ &env,
+ data.into(),
+ two_way_measurements_java,
+ num_two_way_measurements,
+ )?;
+ env.call_method(
+ self.obj.as_obj(),
+ "onRangeDataNotificationReceived",
+ "(Lcom/android/uwb/data/UwbRangingData;)V",
+ &[JValue::Object(JObject::from(ranging_data_java))],
+ )
+ .map(|_| ()) // drop void method return
+ }
+
+ pub fn short_range_data_notification(
+ &self,
+ data: ShortMacTwoWayRangeDataNtfPacket,
+ ) -> Result<()> {
+ let env = self.jvm.attach_current_thread()?;
+ let result = self.handle_short_range_data_notification(&env, data);
+ self.clear_exception(env);
+ result
}
- fn cleanup_and_return<T>(&self, env: AttachGuard, result: Result<T>) -> Result<()> {
+ fn handle_extended_range_data_notification(
+ &self,
+ env: &JNIEnv,
+ data: ExtendedMacTwoWayRangeDataNtfPacket,
+ ) -> Result<()> {
+ let two_way_measurement_class = self.find_class(&env, &UWB_TWO_WAY_MEASUREMENT_CLASS)?;
+ let two_way_measurement_initial_java =
+ EventManager::create_zeroed_two_way_measurement_java(
+ &env,
+ two_way_measurement_class,
+ env.new_byte_array(
+ EXTENDED_MAC_ADDRESS_LEN
+ .to_i32()
+ .expect("Failed converting mac address len to i32"),
+ )?,
+ )?;
+ let num_two_way_measurements: i32 = data
+ .get_two_way_ranging_measurements()
+ .len()
+ .to_i32()
+ .expect("Failed converting len to i32");
+ let two_way_measurements_java = env.new_object_array(
+ num_two_way_measurements,
+ two_way_measurement_class,
+ two_way_measurement_initial_java,
+ )?;
+ for (i, two_way_measurement) in data.get_two_way_ranging_measurements().iter().enumerate() {
+ let two_way_measurement_java =
+ EventManager::create_extended_mac_two_way_measurement_java(
+ &env,
+ two_way_measurement_class,
+ two_way_measurement,
+ )?;
+ env.set_object_array_element(
+ two_way_measurements_java,
+ i.to_i32().expect("Failed converting idx to i32"),
+ two_way_measurement_java,
+ )?;
+ }
+ let ranging_data_java = self.create_range_data_java(
+ &env,
+ data.into(),
+ two_way_measurements_java,
+ num_two_way_measurements,
+ )?;
+ env.call_method(
+ self.obj.as_obj(),
+ "onRangeDataNotificationReceived",
+ "(Lcom/android/uwb/data/UwbRangingData;)V",
+ &[JValue::Object(JObject::from(ranging_data_java))],
+ )
+ .map(|_| ()) // drop void method return
+ }
+
+ pub fn extended_range_data_notification(
+ &self,
+ data: ExtendedMacTwoWayRangeDataNtfPacket,
+ ) -> Result<()> {
+ let env = self.jvm.attach_current_thread()?;
+ let result = self.handle_extended_range_data_notification(&env, data);
self.clear_exception(env);
- // Discard the value returned by the call.
- result.map(|_| ())
+ result
}
// Attempts to clear an exception. If we do not do this, the exception continues being thrown