1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 use jni::errors::{Error, JniError, Result}; 18 use jni::objects::{GlobalRef, JClass, JObject, JValue, JValue::Void}; 19 use jni::signature::JavaType; 20 use jni::sys::jobjectArray; 21 use jni::{AttachGuard, JNIEnv, JavaVM}; 22 use log::error; 23 use num_traits::ToPrimitive; 24 use std::convert::TryInto; 25 use std::vec::Vec; 26 use uwb_uci_packets::{ 27 DeviceStatusNtfPacket, ExtendedAddressTwoWayRangingMeasurement, 28 ExtendedMacTwoWayRangeDataNtfPacket, GenericErrorPacket, Packet, RangeDataNtfPacket, 29 SessionStatusNtfPacket, SessionUpdateControllerMulticastListNtfPacket, 30 ShortAddressTwoWayRangingMeasurement, ShortMacTwoWayRangeDataNtfPacket, UciNotificationChild, 31 UciNotificationPacket, UciVendor_9_NotificationChild, UciVendor_A_NotificationChild, 32 UciVendor_B_NotificationChild, UciVendor_E_NotificationChild, UciVendor_F_NotificationChild, 33 }; 34 35 const UWB_RANGING_DATA_CLASS: &str = "com/android/server/uwb/data/UwbRangingData"; 36 const UWB_TWO_WAY_MEASUREMENT_CLASS: &str = "com/android/server/uwb/data/UwbTwoWayMeasurement"; 37 const MULTICAST_LIST_UPDATE_STATUS_CLASS: &str = 38 "com/android/server/uwb/data/UwbMulticastListUpdateStatus"; 39 const SHORT_MAC_ADDRESS_LEN: usize = 2; 40 const EXTENDED_MAC_ADDRESS_LEN: usize = 8; 41 42 // TODO: Reconsider the best way to cache the JNIEnv. We currently attach and detach for every 43 // call, which the documentation warns could be expensive. We could attach the thread permanently, 44 // but that would not allow us to detach when we drop this structure. We could cache the 45 // AttachGuard in the EventManager, but it is not Send, so we should wait to see how this is used 46 // and how expensive the current approach is. We can call JavaVM's get_env method if we're already 47 // attached. 48 49 // TODO: We could consider caching the method ids rather than recomputing them each time at the cost 50 // of less safety. 51 52 pub trait EventManager { device_status_notification_received(&self, data: DeviceStatusNtfPacket) -> Result<()>53 fn device_status_notification_received(&self, data: DeviceStatusNtfPacket) -> Result<()>; core_generic_error_notification_received(&self, data: GenericErrorPacket) -> Result<()>54 fn core_generic_error_notification_received(&self, data: GenericErrorPacket) -> Result<()>; session_status_notification_received(&self, data: SessionStatusNtfPacket) -> Result<()>55 fn session_status_notification_received(&self, data: SessionStatusNtfPacket) -> Result<()>; short_range_data_notification_received( &self, data: ShortMacTwoWayRangeDataNtfPacket, ) -> Result<()>56 fn short_range_data_notification_received( 57 &self, 58 data: ShortMacTwoWayRangeDataNtfPacket, 59 ) -> Result<()>; extended_range_data_notification_received( &self, data: ExtendedMacTwoWayRangeDataNtfPacket, ) -> Result<()>60 fn extended_range_data_notification_received( 61 &self, 62 data: ExtendedMacTwoWayRangeDataNtfPacket, 63 ) -> Result<()>; session_update_controller_multicast_list_notification_received( &self, data: SessionUpdateControllerMulticastListNtfPacket, ) -> Result<()>64 fn session_update_controller_multicast_list_notification_received( 65 &self, 66 data: SessionUpdateControllerMulticastListNtfPacket, 67 ) -> Result<()>; vendor_uci_notification_received(&self, data: UciNotificationPacket) -> Result<()>68 fn vendor_uci_notification_received(&self, data: UciNotificationPacket) -> Result<()>; 69 } 70 71 // Manages calling Java callbacks through the JNI. 72 pub struct EventManagerImpl { 73 jvm: JavaVM, 74 obj: GlobalRef, 75 // cache used to lookup uwb classes in callback. 76 class_loader_obj: GlobalRef, 77 } 78 79 impl EventManager for EventManagerImpl { device_status_notification_received(&self, data: DeviceStatusNtfPacket) -> Result<()>80 fn device_status_notification_received(&self, data: DeviceStatusNtfPacket) -> Result<()> { 81 let env = self.jvm.attach_current_thread()?; 82 let result = self.handle_device_status_notification_received(&env, data); 83 self.clear_exception(env); 84 result 85 } 86 core_generic_error_notification_received(&self, data: GenericErrorPacket) -> Result<()>87 fn core_generic_error_notification_received(&self, data: GenericErrorPacket) -> Result<()> { 88 let env = self.jvm.attach_current_thread()?; 89 let result = self.handle_core_generic_error_notification_received(&env, data); 90 self.clear_exception(env); 91 result 92 } 93 session_status_notification_received(&self, data: SessionStatusNtfPacket) -> Result<()>94 fn session_status_notification_received(&self, data: SessionStatusNtfPacket) -> Result<()> { 95 let env = self.jvm.attach_current_thread()?; 96 let result = self.handle_session_status_notification_received(&env, data); 97 self.clear_exception(env); 98 result 99 } 100 short_range_data_notification_received( &self, data: ShortMacTwoWayRangeDataNtfPacket, ) -> Result<()>101 fn short_range_data_notification_received( 102 &self, 103 data: ShortMacTwoWayRangeDataNtfPacket, 104 ) -> Result<()> { 105 let env = self.jvm.attach_current_thread()?; 106 let result = self.handle_short_range_data_notification_received(&env, data); 107 self.clear_exception(env); 108 result 109 } 110 extended_range_data_notification_received( &self, data: ExtendedMacTwoWayRangeDataNtfPacket, ) -> Result<()>111 fn extended_range_data_notification_received( 112 &self, 113 data: ExtendedMacTwoWayRangeDataNtfPacket, 114 ) -> Result<()> { 115 let env = self.jvm.attach_current_thread()?; 116 let result = self.handle_extended_range_data_notification_received(&env, data); 117 self.clear_exception(env); 118 result 119 } 120 session_update_controller_multicast_list_notification_received( &self, data: SessionUpdateControllerMulticastListNtfPacket, ) -> Result<()>121 fn session_update_controller_multicast_list_notification_received( 122 &self, 123 data: SessionUpdateControllerMulticastListNtfPacket, 124 ) -> Result<()> { 125 let env = self.jvm.attach_current_thread()?; 126 let result = 127 self.handle_session_update_controller_multicast_list_notification_received(&env, data); 128 self.clear_exception(env); 129 result 130 } vendor_uci_notification_received(&self, data: UciNotificationPacket) -> Result<()>131 fn vendor_uci_notification_received(&self, data: UciNotificationPacket) -> Result<()> { 132 let env = self.jvm.attach_current_thread()?; 133 let result = self.handle_vendor_uci_notification_received(&env, data); 134 self.clear_exception(env); 135 result 136 } 137 } 138 139 impl EventManagerImpl { 140 /// Creates a new EventManagerImpl. new(env: JNIEnv, obj: JObject) -> Result<Self>141 pub fn new(env: JNIEnv, obj: JObject) -> Result<Self> { 142 let jvm = env.get_java_vm()?; 143 let obj = env.new_global_ref(obj)?; 144 let class_loader_obj = EventManagerImpl::get_classloader_obj(&env)?; 145 let class_loader_obj = env.new_global_ref(class_loader_obj)?; 146 Ok(EventManagerImpl { jvm, obj, class_loader_obj }) 147 } 148 get_classloader_obj<'a>(env: &'a JNIEnv) -> Result<JObject<'a>>149 fn get_classloader_obj<'a>(env: &'a JNIEnv) -> Result<JObject<'a>> { 150 // Use UwbRangingData class to find the classloader used by the java service. 151 let ranging_data_class = env.find_class(&UWB_RANGING_DATA_CLASS)?; 152 let ranging_data_class_class = env.get_object_class(ranging_data_class)?; 153 let get_class_loader_method = env.get_method_id( 154 ranging_data_class_class, 155 "getClassLoader", 156 "()Ljava/lang/ClassLoader;", 157 )?; 158 let class_loader = env.call_method_unchecked( 159 ranging_data_class, 160 get_class_loader_method, 161 JavaType::Object("java/lang/ClassLoader".into()), 162 &[Void], 163 )?; 164 class_loader.l() 165 } 166 find_class<'a>(&'a self, env: &'a JNIEnv, class_name: &'a str) -> Result<JClass<'a>>167 fn find_class<'a>(&'a self, env: &'a JNIEnv, class_name: &'a str) -> Result<JClass<'a>> { 168 let class_value = env.call_method( 169 self.class_loader_obj.as_obj(), 170 "findClass", 171 "(Ljava/lang/String;)Ljava/lang/Class;", 172 &[JValue::Object(JObject::from(env.new_string(class_name)?))], 173 )?; 174 class_value.l().map(JClass::from) 175 } 176 handle_device_status_notification_received( &self, env: &JNIEnv, data: DeviceStatusNtfPacket, ) -> Result<()>177 fn handle_device_status_notification_received( 178 &self, 179 env: &JNIEnv, 180 data: DeviceStatusNtfPacket, 181 ) -> Result<()> { 182 let state = data.get_device_state().to_i32().ok_or_else(|| { 183 error!("Failed converting device_state to i32"); 184 Error::JniCall(JniError::Unknown) 185 })?; 186 env.call_method( 187 self.obj.as_obj(), 188 "onDeviceStatusNotificationReceived", 189 "(I)V", 190 &[JValue::Int(state)], 191 ) 192 .map(|_| ()) // drop void method return 193 } 194 handle_session_status_notification_received( &self, env: &JNIEnv, data: SessionStatusNtfPacket, ) -> Result<()>195 fn handle_session_status_notification_received( 196 &self, 197 env: &JNIEnv, 198 data: SessionStatusNtfPacket, 199 ) -> Result<()> { 200 let session_id = data.get_session_id().to_i64().ok_or_else(|| { 201 error!("Failed converting session_id to i64"); 202 Error::JniCall(JniError::Unknown) 203 })?; 204 let state = data.get_session_state().to_i32().ok_or_else(|| { 205 error!("Failed converting session_state to i32"); 206 Error::JniCall(JniError::Unknown) 207 })?; 208 let reason_code = data.get_reason_code().to_i32().ok_or_else(|| { 209 error!("Failed converting reason_code to i32"); 210 Error::JniCall(JniError::Unknown) 211 })?; 212 env.call_method( 213 self.obj.as_obj(), 214 "onSessionStatusNotificationReceived", 215 "(JII)V", 216 &[JValue::Long(session_id), JValue::Int(state), JValue::Int(reason_code)], 217 ) 218 .map(|_| ()) // drop void method return 219 } 220 handle_core_generic_error_notification_received( &self, env: &JNIEnv, data: GenericErrorPacket, ) -> Result<()>221 fn handle_core_generic_error_notification_received( 222 &self, 223 env: &JNIEnv, 224 data: GenericErrorPacket, 225 ) -> Result<()> { 226 let status = data.get_status().to_i32().ok_or_else(|| { 227 error!("Failed converting status to i32"); 228 Error::JniCall(JniError::Unknown) 229 })?; 230 env.call_method( 231 self.obj.as_obj(), 232 "onCoreGenericErrorNotificationReceived", 233 "(I)V", 234 &[JValue::Int(status)], 235 ) 236 .map(|_| ()) // drop void method return 237 } 238 create_zeroed_two_way_measurement_java<'a>( env: &'a JNIEnv, two_way_measurement_class: JClass, mac_address_java: jobjectArray, ) -> Result<JObject<'a>>239 fn create_zeroed_two_way_measurement_java<'a>( 240 env: &'a JNIEnv, 241 two_way_measurement_class: JClass, 242 mac_address_java: jobjectArray, 243 ) -> Result<JObject<'a>> { 244 env.new_object( 245 two_way_measurement_class, 246 "([BIIIIIIIIIIII)V", 247 &[ 248 JValue::Object(JObject::from(mac_address_java)), 249 JValue::Int(0), 250 JValue::Int(0), 251 JValue::Int(0), 252 JValue::Int(0), 253 JValue::Int(0), 254 JValue::Int(0), 255 JValue::Int(0), 256 JValue::Int(0), 257 JValue::Int(0), 258 JValue::Int(0), 259 JValue::Int(0), 260 JValue::Int(0), 261 ], 262 ) 263 } 264 create_short_mac_two_way_measurement_java<'a>( env: &'a JNIEnv, two_way_measurement_class: JClass, two_way_measurement: &'a ShortAddressTwoWayRangingMeasurement, ) -> Result<JObject<'a>>265 fn create_short_mac_two_way_measurement_java<'a>( 266 env: &'a JNIEnv, 267 two_way_measurement_class: JClass, 268 two_way_measurement: &'a ShortAddressTwoWayRangingMeasurement, 269 ) -> Result<JObject<'a>> { 270 let mac_address_arr = two_way_measurement.mac_address.to_ne_bytes(); 271 let mac_address_java = 272 env.new_byte_array(SHORT_MAC_ADDRESS_LEN.to_i32().ok_or_else(|| { 273 error!("Failed converting mac address len to i32"); 274 Error::JniCall(JniError::Unknown) 275 })?)?; 276 // Convert from [u8] to [i8] since java does not support unsigned byte. 277 let mac_address_arr_i8 = mac_address_arr.map(|x| x as i8); 278 env.set_byte_array_region(mac_address_java, 0, &mac_address_arr_i8)?; 279 env.new_object( 280 two_way_measurement_class, 281 "([BIIIIIIIIIIII)V", 282 &[ 283 JValue::Object(JObject::from(mac_address_java)), 284 JValue::Int(two_way_measurement.status.to_i32().ok_or_else(|| { 285 error!("Failed converting status to i32"); 286 Error::JniCall(JniError::Unknown) 287 })?), 288 JValue::Int(two_way_measurement.nlos.to_i32().ok_or_else(|| { 289 error!("Failed converting nlos to i32"); 290 Error::JniCall(JniError::Unknown) 291 })?), 292 JValue::Int(two_way_measurement.distance.to_i32().ok_or_else(|| { 293 error!("Failed converting distance to i32"); 294 Error::JniCall(JniError::Unknown) 295 })?), 296 JValue::Int(two_way_measurement.aoa_azimuth.to_i32().ok_or_else(|| { 297 error!("Failed converting aoa azimuth to i32"); 298 Error::JniCall(JniError::Unknown) 299 })?), 300 JValue::Int(two_way_measurement.aoa_azimuth_fom.to_i32().ok_or_else(|| { 301 error!("Failed converting aoa azimuth fom to i32"); 302 Error::JniCall(JniError::Unknown) 303 })?), 304 JValue::Int(two_way_measurement.aoa_elevation.to_i32().ok_or_else(|| { 305 error!("Failed converting aoa elevation to i32"); 306 Error::JniCall(JniError::Unknown) 307 })?), 308 JValue::Int(two_way_measurement.aoa_elevation_fom.to_i32().ok_or_else(|| { 309 error!("Failed converting aoa elevation fom to i32"); 310 Error::JniCall(JniError::Unknown) 311 })?), 312 JValue::Int(two_way_measurement.aoa_destination_azimuth.to_i32().ok_or_else( 313 || { 314 error!("Failed converting dest aoa azimuth to i32"); 315 Error::JniCall(JniError::Unknown) 316 }, 317 )?), 318 JValue::Int(two_way_measurement.aoa_destination_azimuth_fom.to_i32().ok_or_else( 319 || { 320 error!("Failed converting dest aoa azimuth fom to i32"); 321 Error::JniCall(JniError::Unknown) 322 }, 323 )?), 324 JValue::Int(two_way_measurement.aoa_destination_elevation.to_i32().ok_or_else( 325 || { 326 error!("Failed converting dest aoa elevation to i32"); 327 Error::JniCall(JniError::Unknown) 328 }, 329 )?), 330 JValue::Int( 331 two_way_measurement.aoa_destination_elevation_fom.to_i32().ok_or_else( 332 || { 333 error!("Failed converting dest aoa elevation azimuth to i32"); 334 Error::JniCall(JniError::Unknown) 335 }, 336 )?, 337 ), 338 JValue::Int(two_way_measurement.slot_index.to_i32().ok_or_else(|| { 339 error!("Failed converting slot index to i32"); 340 Error::JniCall(JniError::Unknown) 341 })?), 342 ], 343 ) 344 } 345 create_extended_mac_two_way_measurement_java<'a>( env: &'a JNIEnv, two_way_measurement_class: JClass, two_way_measurement: &'a ExtendedAddressTwoWayRangingMeasurement, ) -> Result<JObject<'a>>346 fn create_extended_mac_two_way_measurement_java<'a>( 347 env: &'a JNIEnv, 348 two_way_measurement_class: JClass, 349 two_way_measurement: &'a ExtendedAddressTwoWayRangingMeasurement, 350 ) -> Result<JObject<'a>> { 351 let mac_address_arr = two_way_measurement.mac_address.to_ne_bytes(); 352 let mac_address_java = 353 env.new_byte_array(EXTENDED_MAC_ADDRESS_LEN.to_i32().ok_or_else(|| { 354 error!("Failed converting mac address len to i32"); 355 Error::JniCall(JniError::Unknown) 356 })?)?; 357 // Convert from [u8] to [i8] since java does not support unsigned byte. 358 let mac_address_arr_i8 = mac_address_arr.map(|x| x as i8); 359 env.set_byte_array_region(mac_address_java, 0, &mac_address_arr_i8)?; 360 env.new_object( 361 two_way_measurement_class, 362 "([BIIIIIIIIIIII)V", 363 &[ 364 JValue::Object(JObject::from(mac_address_java)), 365 JValue::Int(two_way_measurement.status.to_i32().ok_or_else(|| { 366 error!("Failed converting status to i32"); 367 Error::JniCall(JniError::Unknown) 368 })?), 369 JValue::Int(two_way_measurement.nlos.to_i32().ok_or_else(|| { 370 error!("Failed converting nlos to i32"); 371 Error::JniCall(JniError::Unknown) 372 })?), 373 JValue::Int(two_way_measurement.distance.to_i32().ok_or_else(|| { 374 error!("Failed converting distance to i32"); 375 Error::JniCall(JniError::Unknown) 376 })?), 377 JValue::Int(two_way_measurement.aoa_azimuth.to_i32().ok_or_else(|| { 378 error!("Failed converting aoa azimuth to i32"); 379 Error::JniCall(JniError::Unknown) 380 })?), 381 JValue::Int(two_way_measurement.aoa_azimuth_fom.to_i32().ok_or_else(|| { 382 error!("Failed converting aoa azimuth fom to i32"); 383 Error::JniCall(JniError::Unknown) 384 })?), 385 JValue::Int(two_way_measurement.aoa_elevation.to_i32().ok_or_else(|| { 386 error!("Failed converting aoa elevation to i32"); 387 Error::JniCall(JniError::Unknown) 388 })?), 389 JValue::Int(two_way_measurement.aoa_elevation_fom.to_i32().ok_or_else(|| { 390 error!("Failed converting aoa elevation fom to i32"); 391 Error::JniCall(JniError::Unknown) 392 })?), 393 JValue::Int(two_way_measurement.aoa_destination_azimuth.to_i32().ok_or_else( 394 || { 395 error!("Failed converting dest aoa azimuth to i32"); 396 Error::JniCall(JniError::Unknown) 397 }, 398 )?), 399 JValue::Int(two_way_measurement.aoa_destination_azimuth_fom.to_i32().ok_or_else( 400 || { 401 error!("Failed converting dest aoa azimuth fom to i32"); 402 Error::JniCall(JniError::Unknown) 403 }, 404 )?), 405 JValue::Int(two_way_measurement.aoa_destination_elevation.to_i32().ok_or_else( 406 || { 407 error!("Failed converting dest aoa elevation to i32"); 408 Error::JniCall(JniError::Unknown) 409 }, 410 )?), 411 JValue::Int( 412 two_way_measurement.aoa_destination_elevation_fom.to_i32().ok_or_else( 413 || { 414 error!("Failed converting dest aoa elevation azimuth to i32"); 415 Error::JniCall(JniError::Unknown) 416 }, 417 )?, 418 ), 419 JValue::Int(two_way_measurement.slot_index.to_i32().ok_or_else(|| { 420 error!("Failed converting slot index to i32"); 421 Error::JniCall(JniError::Unknown) 422 })?), 423 ], 424 ) 425 } 426 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>>427 fn create_range_data_java<'a>( 428 &'a self, 429 env: &'a JNIEnv, 430 data: RangeDataNtfPacket, 431 two_way_measurements_java: jobjectArray, 432 num_two_way_measurements: i32, 433 ) -> Result<JObject<'a>> { 434 let ranging_data_class = self.find_class(env, UWB_RANGING_DATA_CLASS)?; 435 env.new_object( 436 ranging_data_class, 437 "(JJIJIII[Lcom/android/server/uwb/data/UwbTwoWayMeasurement;)V", 438 &[ 439 JValue::Long(data.get_sequence_number().to_i64().ok_or_else(|| { 440 error!("Failed converting seq num to i64"); 441 Error::JniCall(JniError::Unknown) 442 })?), 443 JValue::Long(data.get_session_id().to_i64().ok_or_else(|| { 444 error!("Failed converting session id to i64"); 445 Error::JniCall(JniError::Unknown) 446 })?), 447 JValue::Int(data.get_rcr_indicator().to_i32().ok_or_else(|| { 448 error!("Failed converting rcr indicator to i32"); 449 Error::JniCall(JniError::Unknown) 450 })?), 451 JValue::Long(data.get_current_ranging_interval().to_i64().ok_or_else(|| { 452 error!("Failed converting current ranging interval to i32"); 453 Error::JniCall(JniError::Unknown) 454 })?), 455 JValue::Int(data.get_ranging_measurement_type().to_i32().ok_or_else(|| { 456 error!("Failed converting ranging measurement type to i32"); 457 Error::JniCall(JniError::Unknown) 458 })?), 459 JValue::Int(data.get_mac_address_indicator().to_i32().ok_or_else(|| { 460 error!("Failed converting mac address indicator to i32"); 461 Error::JniCall(JniError::Unknown) 462 })?), 463 JValue::Int(num_two_way_measurements), 464 JValue::Object(JObject::from(two_way_measurements_java)), 465 ], 466 ) 467 } 468 handle_short_range_data_notification_received( &self, env: &JNIEnv, data: ShortMacTwoWayRangeDataNtfPacket, ) -> Result<()>469 fn handle_short_range_data_notification_received( 470 &self, 471 env: &JNIEnv, 472 data: ShortMacTwoWayRangeDataNtfPacket, 473 ) -> Result<()> { 474 let two_way_measurement_class = self.find_class(env, UWB_TWO_WAY_MEASUREMENT_CLASS)?; 475 let two_way_measurement_initial_java = 476 EventManagerImpl::create_zeroed_two_way_measurement_java( 477 env, 478 two_way_measurement_class, 479 env.new_byte_array(EXTENDED_MAC_ADDRESS_LEN.to_i32().ok_or_else(|| { 480 error!("Failed converting mac address len to i32"); 481 Error::JniCall(JniError::Unknown) 482 })?)?, 483 )?; 484 let num_two_way_measurements: i32 = 485 data.get_two_way_ranging_measurements().len().to_i32().ok_or_else(|| { 486 error!("Failed converting len to i32"); 487 Error::JniCall(JniError::Unknown) 488 })?; 489 let two_way_measurements_java = env.new_object_array( 490 num_two_way_measurements, 491 two_way_measurement_class, 492 two_way_measurement_initial_java, 493 )?; 494 for (i, two_way_measurement) in data.get_two_way_ranging_measurements().iter().enumerate() { 495 let two_way_measurement_java = 496 EventManagerImpl::create_short_mac_two_way_measurement_java( 497 env, 498 two_way_measurement_class, 499 two_way_measurement, 500 )?; 501 env.set_object_array_element( 502 two_way_measurements_java, 503 i.to_i32().ok_or_else(|| { 504 error!("Failed converting idx to i32"); 505 Error::JniCall(JniError::Unknown) 506 })?, 507 two_way_measurement_java, 508 )? 509 } 510 let ranging_data_java = self.create_range_data_java( 511 env, 512 data.into(), 513 two_way_measurements_java, 514 num_two_way_measurements, 515 )?; 516 env.call_method( 517 self.obj.as_obj(), 518 "onRangeDataNotificationReceived", 519 "(Lcom/android/server/uwb/data/UwbRangingData;)V", 520 &[JValue::Object(ranging_data_java)], 521 ) 522 .map(|_| ()) // drop void method return 523 } 524 handle_extended_range_data_notification_received( &self, env: &JNIEnv, data: ExtendedMacTwoWayRangeDataNtfPacket, ) -> Result<()>525 fn handle_extended_range_data_notification_received( 526 &self, 527 env: &JNIEnv, 528 data: ExtendedMacTwoWayRangeDataNtfPacket, 529 ) -> Result<()> { 530 let two_way_measurement_class = self.find_class(env, UWB_TWO_WAY_MEASUREMENT_CLASS)?; 531 let two_way_measurement_initial_java = 532 EventManagerImpl::create_zeroed_two_way_measurement_java( 533 env, 534 two_way_measurement_class, 535 env.new_byte_array(EXTENDED_MAC_ADDRESS_LEN.to_i32().ok_or_else(|| { 536 error!("Failed converting mac address len to i32"); 537 Error::JniCall(JniError::Unknown) 538 })?)?, 539 )?; 540 let num_two_way_measurements: i32 = 541 data.get_two_way_ranging_measurements().len().to_i32().ok_or_else(|| { 542 error!("Failed converting len to i32"); 543 Error::JniCall(JniError::Unknown) 544 })?; 545 let two_way_measurements_java = env.new_object_array( 546 num_two_way_measurements, 547 two_way_measurement_class, 548 two_way_measurement_initial_java, 549 )?; 550 for (i, two_way_measurement) in data.get_two_way_ranging_measurements().iter().enumerate() { 551 let two_way_measurement_java = 552 EventManagerImpl::create_extended_mac_two_way_measurement_java( 553 env, 554 two_way_measurement_class, 555 two_way_measurement, 556 )?; 557 env.set_object_array_element( 558 two_way_measurements_java, 559 i.to_i32().ok_or_else(|| { 560 error!("Failed converting idx to i32"); 561 Error::JniCall(JniError::Unknown) 562 })?, 563 two_way_measurement_java, 564 )?; 565 } 566 let ranging_data_java = self.create_range_data_java( 567 env, 568 data.into(), 569 two_way_measurements_java, 570 num_two_way_measurements, 571 )?; 572 env.call_method( 573 self.obj.as_obj(), 574 "onRangeDataNotificationReceived", 575 "(Lcom/android/server/uwb/data/UwbRangingData;)V", 576 &[JValue::Object(ranging_data_java)], 577 ) 578 .map(|_| ()) // drop void method return 579 } 580 handle_session_update_controller_multicast_list_notification_received( &self, env: &JNIEnv, data: SessionUpdateControllerMulticastListNtfPacket, ) -> Result<()>581 pub fn handle_session_update_controller_multicast_list_notification_received( 582 &self, 583 env: &JNIEnv, 584 data: SessionUpdateControllerMulticastListNtfPacket, 585 ) -> Result<()> { 586 let uwb_multicast_update_class = 587 self.find_class(env, MULTICAST_LIST_UPDATE_STATUS_CLASS)?; 588 589 let controlee_status = data.get_controlee_status(); 590 let count: i32 = controlee_status.len().try_into().map_err(|_| { 591 error!("Failed to convert controlee status length"); 592 Error::JniCall(JniError::Unknown) 593 })?; 594 let mut mac_address_list: Vec<i32> = Vec::new(); 595 let mut subsession_id_list: Vec<i64> = Vec::new(); 596 let mut status_list: Vec<i32> = Vec::new(); 597 598 for iter in controlee_status { 599 mac_address_list.push(iter.mac_address.into()); 600 subsession_id_list.push(iter.subsession_id.into()); 601 status_list.push(iter.status.to_i32().ok_or_else(|| { 602 error!("Failed to convert controlee_status's status field: {:?}", iter.status); 603 Error::JniCall(JniError::Unknown) 604 })?); 605 } 606 607 let mac_address_jintarray = env.new_int_array(count)?; 608 env.set_int_array_region(mac_address_jintarray, 0, mac_address_list.as_ref())?; 609 let subsession_id_jlongarray = env.new_long_array(count)?; 610 env.set_long_array_region(subsession_id_jlongarray, 0, subsession_id_list.as_ref())?; 611 let status_jintarray = env.new_int_array(count)?; 612 env.set_int_array_region(status_jintarray, 0, status_list.as_ref())?; 613 614 let uwb_multicast_update_object = env.new_object( 615 uwb_multicast_update_class, 616 "(JII[I[J[I)V", 617 &[ 618 JValue::Long(data.get_session_id().try_into().map_err(|_| { 619 error!("Could not convert session_id"); 620 Error::JniCall(JniError::Unknown) 621 })?), 622 JValue::Int(data.get_remaining_multicast_list_size().try_into().map_err(|_| { 623 error!("Could not convert remaining multicast list size"); 624 Error::JniCall(JniError::Unknown) 625 })?), 626 JValue::Int(count), 627 JValue::Object(JObject::from(mac_address_jintarray)), 628 JValue::Object(JObject::from(subsession_id_jlongarray)), 629 JValue::Object(JObject::from(status_jintarray)), 630 ], 631 )?; 632 633 env.call_method( 634 self.obj.as_obj(), 635 "onMulticastListUpdateNotificationReceived", 636 "(Lcom/android/server/uwb/data/UwbMulticastListUpdateStatus;)V", 637 &[JValue::Object(uwb_multicast_update_object)], 638 ) 639 .map(|_| ()) // drop void method return 640 } 641 get_vendor_uci_payload(data: UciNotificationPacket) -> Result<Vec<u8>>642 fn get_vendor_uci_payload(data: UciNotificationPacket) -> Result<Vec<u8>> { 643 match data.specialize() { 644 UciNotificationChild::UciVendor_9_Notification(evt) => match evt.specialize() { 645 UciVendor_9_NotificationChild::Payload(payload) => Ok(payload.to_vec()), 646 UciVendor_9_NotificationChild::None => Ok(Vec::new()), 647 }, 648 UciNotificationChild::UciVendor_A_Notification(evt) => match evt.specialize() { 649 UciVendor_A_NotificationChild::Payload(payload) => Ok(payload.to_vec()), 650 UciVendor_A_NotificationChild::None => Ok(Vec::new()), 651 }, 652 UciNotificationChild::UciVendor_B_Notification(evt) => match evt.specialize() { 653 UciVendor_B_NotificationChild::Payload(payload) => Ok(payload.to_vec()), 654 UciVendor_B_NotificationChild::None => Ok(Vec::new()), 655 }, 656 UciNotificationChild::UciVendor_E_Notification(evt) => match evt.specialize() { 657 UciVendor_E_NotificationChild::Payload(payload) => Ok(payload.to_vec()), 658 UciVendor_E_NotificationChild::None => Ok(Vec::new()), 659 }, 660 UciNotificationChild::UciVendor_F_Notification(evt) => match evt.specialize() { 661 UciVendor_F_NotificationChild::Payload(payload) => Ok(payload.to_vec()), 662 UciVendor_F_NotificationChild::None => Ok(Vec::new()), 663 }, 664 _ => { 665 error!("Invalid vendor notification with gid {:?}", data.to_vec()); 666 Err(Error::JniCall(JniError::Unknown)) 667 } 668 } 669 } 670 handle_vendor_uci_notification_received( &self, env: &JNIEnv, data: UciNotificationPacket, ) -> Result<()>671 pub fn handle_vendor_uci_notification_received( 672 &self, 673 env: &JNIEnv, 674 data: UciNotificationPacket, 675 ) -> Result<()> { 676 let gid: i32 = data.get_group_id().to_i32().ok_or_else(|| { 677 error!("Failed to convert gid"); 678 Error::JniCall(JniError::Unknown) 679 })?; 680 let oid: i32 = data.get_opcode().to_i32().ok_or_else(|| { 681 error!("Failed to convert gid"); 682 Error::JniCall(JniError::Unknown) 683 })?; 684 let payload: Vec<u8> = EventManagerImpl::get_vendor_uci_payload(data)?; 685 let payload_jbytearray = env.byte_array_from_slice(payload.as_ref())?; 686 687 env.call_method( 688 self.obj.as_obj(), 689 "onVendorUciNotificationReceived", 690 "(IIB])V", 691 &[ 692 JValue::Int(gid), 693 JValue::Int(oid), 694 JValue::Object(JObject::from(payload_jbytearray)), 695 ], 696 ) 697 .map(|_| ()) // drop void method return 698 } 699 700 // Attempts to clear an exception. If we do not do this, the exception continues being thrown 701 // when the control flow returns to Java. We discard errors here (after logging them) rather 702 // than propagating them to the caller since there's nothing they can do with that information. clear_exception(&self, env: AttachGuard)703 fn clear_exception(&self, env: AttachGuard) { 704 match env.exception_check() { 705 Ok(true) => match env.exception_clear() { 706 Ok(()) => {} // We successfully cleared the exception. 707 Err(e) => error!("Error clearing JNI exception: {:?}", e), 708 }, 709 Ok(false) => {} // No exception found. 710 Err(e) => error!("Error checking JNI exception: {:?}", e), 711 } 712 } 713 } 714 715 #[cfg(any(test, fuzzing))] 716 pub mod mock_event_manager; 717