• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Implementation of JNI functions.
16 
17 use crate::dispatcher::Dispatcher;
18 use crate::helper::{boolean_result_helper, byte_result_helper, option_result_helper};
19 use crate::jclass_name::{
20     CONFIG_STATUS_DATA_CLASS, DT_RANGING_ROUNDS_STATUS_CLASS, MULTICAST_LIST_UPDATE_STATUS_CLASS,
21     POWER_STATS_CLASS, TLV_DATA_CLASS, UWB_DEVICE_INFO_RESPONSE_CLASS, UWB_RANGING_DATA_CLASS,
22     VENDOR_RESPONSE_CLASS,
23 };
24 use crate::unique_jvm;
25 
26 use std::convert::TryInto;
27 use std::iter::zip;
28 
29 use jni::errors::Error as JNIError;
30 use jni::objects::{GlobalRef, JObject, JString, JValue};
31 use jni::signature::ReturnType;
32 use jni::sys::{
33     jboolean, jbyte, jbyteArray, jint, jintArray, jlong, jobject, jobjectArray, jshort, jvalue,
34 };
35 use jni::JNIEnv;
36 use log::{debug, error};
37 use uwb_core::error::{Error, Result};
38 use uwb_core::params::{
39     AndroidRadarConfigResponse, AppConfigTlv, ControllerPhaseList, CountryCode,
40     GetDeviceInfoResponse, RadarConfigTlv, RawAppConfigTlv, RawUciMessage, RfTestConfigResponse,
41     RfTestConfigTlv, SessionUpdateControllerMulticastResponse,
42     SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse,
43 };
44 use uwb_uci_packets::{
45     AppConfigTlvType, CapTlv, Controlee, ControleePhaseList, Controlee_V2_0_16_Byte_Version,
46     Controlee_V2_0_32_Byte_Version, Controlees, MacAddressIndicator, PowerStats, ResetConfig,
47     SessionState, SessionType, StatusCode, UpdateMulticastListAction,
48 };
49 
50 /// Macro capturing the name of the function calling this macro.
51 ///
52 /// function_name()! -> &'static str
53 /// Returns the function name as 'static reference.
54 macro_rules! function_name {
55     () => {{
56         // Declares function f inside current function.
57         fn f() {}
58         fn type_name_of<T>(_: T) -> &'static str {
59             std::any::type_name::<T>()
60         }
61         // type name of f is struct_or_crate_name::calling_function_name::f
62         let name = type_name_of(f);
63         // Find and cut the rest of the path:
64         // Third to last character, up to the first semicolon: is calling_function_name
65         match &name[..name.len() - 3].rfind(':') {
66             Some(pos) => &name[pos + 1..name.len() - 3],
67             None => &name[..name.len() - 3],
68         }
69     }};
70 }
71 
72 /// Initialize native library. Captures VM:
73 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeInit( env: JNIEnv, _obj: JObject, ) -> jboolean74 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeInit(
75     env: JNIEnv,
76     _obj: JObject,
77 ) -> jboolean {
78     logger::init(
79         logger::Config::default()
80             .with_tag_on_device("uwb")
81             .with_max_level(log::LevelFilter::Trace)
82             .with_filter("trace,jni=info"),
83     );
84     debug!("{}: enter", function_name!());
85     boolean_result_helper(native_init(env), function_name!())
86 }
87 
native_init(env: JNIEnv) -> Result<()>88 fn native_init(env: JNIEnv) -> Result<()> {
89     let jvm = env.get_java_vm().map_err(|_| Error::ForeignFunctionInterface)?;
90     unique_jvm::set_once(jvm)
91 }
92 
create_device_info_response(rsp: GetDeviceInfoResponse, env: JNIEnv) -> Result<jobject>93 fn create_device_info_response(rsp: GetDeviceInfoResponse, env: JNIEnv) -> Result<jobject> {
94     let device_info_response_class = env
95         .find_class(UWB_DEVICE_INFO_RESPONSE_CLASS)
96         .map_err(|_| Error::ForeignFunctionInterface)?;
97 
98     let vendor_spec_info_jbytearray = env
99         .byte_array_from_slice(rsp.vendor_spec_info.as_ref())
100         .map_err(|_| Error::ForeignFunctionInterface)?;
101     // Safety: vendor_spec_info_jbytearray is safely instantiated above.
102     let vendor_spec_info_jobject = unsafe { JObject::from_raw(vendor_spec_info_jbytearray) };
103 
104     match env.new_object(
105         device_info_response_class,
106         "(IIIII[B)V",
107         &[
108             JValue::Int(i32::from(rsp.status)),
109             JValue::Int(rsp.uci_version as i32),
110             JValue::Int(rsp.mac_version as i32),
111             JValue::Int(rsp.phy_version as i32),
112             JValue::Int(rsp.uci_test_version as i32),
113             JValue::Object(vendor_spec_info_jobject),
114         ],
115     ) {
116         Ok(o) => Ok(*o),
117         Err(_) => Err(Error::ForeignFunctionInterface),
118     }
119 }
120 
121 /// Turn on Single UWB chip.
122 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoInitialize( env: JNIEnv, obj: JObject, chip_id: JString, ) -> jobject123 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoInitialize(
124     env: JNIEnv,
125     obj: JObject,
126     chip_id: JString,
127 ) -> jobject {
128     debug!("{}: enter", function_name!());
129     match option_result_helper(native_do_initialize(env, obj, chip_id), function_name!()) {
130         Some(rsp) => create_device_info_response(rsp, env)
131             .inspect_err(|e| {
132                 error!("{} failed with {:?}", function_name!(), &e);
133             })
134             .unwrap_or(*JObject::null()),
135         None => *JObject::null(),
136     }
137 }
138 
native_do_initialize( env: JNIEnv, obj: JObject, chip_id: JString, ) -> Result<GetDeviceInfoResponse>139 fn native_do_initialize(
140     env: JNIEnv,
141     obj: JObject,
142     chip_id: JString,
143 ) -> Result<GetDeviceInfoResponse> {
144     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
145     uci_manager.open_hal()
146 }
147 
148 /// Turn off single UWB chip.
149 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoDeinitialize( env: JNIEnv, obj: JObject, chip_id: JString, ) -> jboolean150 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoDeinitialize(
151     env: JNIEnv,
152     obj: JObject,
153     chip_id: JString,
154 ) -> jboolean {
155     debug!("{}: enter", function_name!());
156     boolean_result_helper(native_do_deinitialize(env, obj, chip_id), function_name!())
157 }
158 
native_do_deinitialize(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<()>159 fn native_do_deinitialize(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<()> {
160     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
161     uci_manager.close_hal(true)
162 }
163 
164 /// Get nanos. Not currently used and returns placeholder value.
165 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetTimestampResolutionNanos( _env: JNIEnv, _obj: JObject, ) -> jlong166 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetTimestampResolutionNanos(
167     _env: JNIEnv,
168     _obj: JObject,
169 ) -> jlong {
170     debug!("{}: enter", function_name!());
171     0
172 }
173 
174 /// Reset a single UWB device by sending UciDeviceReset command. Return value defined by
175 /// <AndroidRoot>/external/uwb/src/rust/uwb_uci_packets/uci_packets.pdl
176 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDeviceReset( env: JNIEnv, obj: JObject, _reset_config: jbyte, chip_id: JString, ) -> jbyte177 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDeviceReset(
178     env: JNIEnv,
179     obj: JObject,
180     _reset_config: jbyte,
181     chip_id: JString,
182 ) -> jbyte {
183     debug!("{}: enter", function_name!());
184     byte_result_helper(native_device_reset(env, obj, chip_id), function_name!())
185 }
186 
native_device_reset(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<()>187 fn native_device_reset(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<()> {
188     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
189     uci_manager.device_reset(ResetConfig::UwbsReset)
190 }
191 
192 /// Init the session on a single UWB device. Return value defined by uci_packets.pdl
193 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionInit( env: JNIEnv, obj: JObject, session_id: jint, session_type: jbyte, chip_id: JString, ) -> jbyte194 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionInit(
195     env: JNIEnv,
196     obj: JObject,
197     session_id: jint,
198     session_type: jbyte,
199     chip_id: JString,
200 ) -> jbyte {
201     debug!("{}: enter", function_name!());
202     byte_result_helper(
203         native_session_init(env, obj, session_id, session_type, chip_id),
204         function_name!(),
205     )
206 }
207 
native_session_init( env: JNIEnv, obj: JObject, session_id: jint, session_type: jbyte, chip_id: JString, ) -> Result<()>208 fn native_session_init(
209     env: JNIEnv,
210     obj: JObject,
211     session_id: jint,
212     session_type: jbyte,
213     chip_id: JString,
214 ) -> Result<()> {
215     let session_type =
216         SessionType::try_from(session_type as u8).map_err(|_| Error::BadParameters)?;
217     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
218     uci_manager.session_init(session_id as u32, session_type)
219 }
220 
221 /// DeInit the session on a single UWB device. Return value defined by uci_packets.pdl
222 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionDeInit( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> jbyte223 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionDeInit(
224     env: JNIEnv,
225     obj: JObject,
226     session_id: jint,
227     chip_id: JString,
228 ) -> jbyte {
229     debug!("{}: enter", function_name!());
230     byte_result_helper(native_session_deinit(env, obj, session_id, chip_id), function_name!())
231 }
232 
native_session_deinit( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> Result<()>233 fn native_session_deinit(
234     env: JNIEnv,
235     obj: JObject,
236     session_id: jint,
237     chip_id: JString,
238 ) -> Result<()> {
239     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
240     uci_manager.session_deinit(session_id as u32)
241 }
242 
243 /// Get session count on a single UWB device. return -1 if failed
244 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionCount( env: JNIEnv, obj: JObject, chip_id: JString, ) -> jbyte245 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionCount(
246     env: JNIEnv,
247     obj: JObject,
248     chip_id: JString,
249 ) -> jbyte {
250     debug!("{}: enter", function_name!());
251     match option_result_helper(native_get_session_count(env, obj, chip_id), function_name!()) {
252         // Max session count is 5, will not overflow i8
253         Some(c) => c as i8,
254         None => -1,
255     }
256 }
257 
native_get_session_count(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<u8>258 fn native_get_session_count(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<u8> {
259     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
260     uci_manager.session_get_count()
261 }
262 
263 /// Start ranging on a single UWB device. Return value defined by uci_packets.pdl
264 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStart( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> jbyte265 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStart(
266     env: JNIEnv,
267     obj: JObject,
268     session_id: jint,
269     chip_id: JString,
270 ) -> jbyte {
271     debug!("{}: enter", function_name!());
272     byte_result_helper(native_ranging_start(env, obj, session_id, chip_id), function_name!())
273 }
274 
native_ranging_start( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> Result<()>275 fn native_ranging_start(
276     env: JNIEnv,
277     obj: JObject,
278     session_id: jint,
279     chip_id: JString,
280 ) -> Result<()> {
281     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
282     uci_manager.range_start(session_id as u32)
283 }
284 
285 /// Stop ranging on a single UWB device. Return value defined by uci_packets.pdl
286 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStop( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> jbyte287 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStop(
288     env: JNIEnv,
289     obj: JObject,
290     session_id: jint,
291     chip_id: JString,
292 ) -> jbyte {
293     debug!("{}: enter", function_name!());
294     byte_result_helper(native_ranging_stop(env, obj, session_id, chip_id), function_name!())
295 }
296 
native_ranging_stop( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> Result<()>297 fn native_ranging_stop(
298     env: JNIEnv,
299     obj: JObject,
300     session_id: jint,
301     chip_id: JString,
302 ) -> Result<()> {
303     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
304     uci_manager.range_stop(session_id as u32)
305 }
306 
307 /// Get session stateon a single UWB device. Return -1 if failed
308 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionState( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> jbyte309 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionState(
310     env: JNIEnv,
311     obj: JObject,
312     session_id: jint,
313     chip_id: JString,
314 ) -> jbyte {
315     debug!("{}: enter", function_name!());
316     match option_result_helper(
317         native_get_session_state(env, obj, session_id, chip_id),
318         function_name!(),
319     ) {
320         // SessionState does not overflow i8
321         Some(s) => s as i8,
322         None => -1,
323     }
324 }
325 
native_get_session_state( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> Result<SessionState>326 fn native_get_session_state(
327     env: JNIEnv,
328     obj: JObject,
329     session_id: jint,
330     chip_id: JString,
331 ) -> Result<SessionState> {
332     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
333     uci_manager.session_get_state(session_id as u32)
334 }
335 
parse_app_config_tlv_vec(no_of_params: i32, mut byte_array: &[u8]) -> Result<Vec<AppConfigTlv>>336 fn parse_app_config_tlv_vec(no_of_params: i32, mut byte_array: &[u8]) -> Result<Vec<AppConfigTlv>> {
337     let mut parsed_tlvs_len = 0;
338     let received_tlvs_len = byte_array.len();
339     let mut tlvs = Vec::<AppConfigTlv>::new();
340     for _ in 0..no_of_params {
341         // The tlv consists of the type of payload in 1 byte, the length of payload as u8
342         // in 1 byte, and the payload.
343         const TLV_HEADER_SIZE: usize = 2;
344         let tlv = RawAppConfigTlv::parse(byte_array).map_err(|_| Error::BadParameters)?;
345         byte_array = byte_array.get(tlv.v.len() + TLV_HEADER_SIZE..).ok_or(Error::BadParameters)?;
346         parsed_tlvs_len += tlv.v.len() + TLV_HEADER_SIZE;
347         tlvs.push(tlv.into());
348     }
349     if parsed_tlvs_len != received_tlvs_len {
350         return Err(Error::BadParameters);
351     };
352     Ok(tlvs)
353 }
354 
parse_radar_config_tlv_vec( no_of_params: i32, mut byte_array: &[u8], ) -> Result<Vec<RadarConfigTlv>>355 fn parse_radar_config_tlv_vec(
356     no_of_params: i32,
357     mut byte_array: &[u8],
358 ) -> Result<Vec<RadarConfigTlv>> {
359     let mut parsed_tlvs_len = 0;
360     let received_tlvs_len = byte_array.len();
361     let mut tlvs = Vec::<RadarConfigTlv>::new();
362     for _ in 0..no_of_params {
363         // The tlv consists of the type of payload in 1 byte, the length of payload as u8
364         // in 1 byte, and the payload.
365         const TLV_HEADER_SIZE: usize = 2;
366         let tlv = RadarConfigTlv::parse(byte_array).map_err(|_| Error::BadParameters)?;
367         byte_array = byte_array.get(tlv.v.len() + TLV_HEADER_SIZE..).ok_or(Error::BadParameters)?;
368         parsed_tlvs_len += tlv.v.len() + TLV_HEADER_SIZE;
369         tlvs.push(tlv);
370     }
371     if parsed_tlvs_len != received_tlvs_len {
372         return Err(Error::BadParameters);
373     };
374     Ok(tlvs)
375 }
376 
create_radar_config_response( response: AndroidRadarConfigResponse, env: JNIEnv, ) -> Result<jbyteArray>377 fn create_radar_config_response(
378     response: AndroidRadarConfigResponse,
379     env: JNIEnv,
380 ) -> Result<jbyteArray> {
381     let uwb_config_status_class =
382         env.find_class(CONFIG_STATUS_DATA_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
383     let mut buf = Vec::<u8>::new();
384     for config_status in &response.config_status {
385         buf.push(u8::from(config_status.cfg_id));
386         buf.push(u8::from(config_status.status));
387     }
388     let config_status_jbytearray =
389         env.byte_array_from_slice(&buf).map_err(|_| Error::ForeignFunctionInterface)?;
390 
391     // Safety: config_status_jbytearray is safely instantiated above.
392     let config_status_jobject = unsafe { JObject::from_raw(config_status_jbytearray) };
393     let config_status_jobject = env
394         .new_object(
395             uwb_config_status_class,
396             "(II[B)V",
397             &[
398                 JValue::Int(i32::from(response.status)),
399                 JValue::Int(response.config_status.len() as i32),
400                 JValue::Object(config_status_jobject),
401             ],
402         )
403         .map_err(|_| Error::ForeignFunctionInterface)?;
404     Ok(*config_status_jobject)
405 }
406 
create_set_config_response(response: SetAppConfigResponse, env: JNIEnv) -> Result<jbyteArray>407 fn create_set_config_response(response: SetAppConfigResponse, env: JNIEnv) -> Result<jbyteArray> {
408     let uwb_config_status_class =
409         env.find_class(CONFIG_STATUS_DATA_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
410     let mut buf = Vec::<u8>::new();
411     for config_status in &response.config_status {
412         buf.push(u8::from(config_status.cfg_id));
413         buf.push(u8::from(config_status.status));
414     }
415     let config_status_jbytearray =
416         env.byte_array_from_slice(&buf).map_err(|_| Error::ForeignFunctionInterface)?;
417 
418     // Safety: config_status_jbytearray is safely instantiated above.
419     let config_status_jobject = unsafe { JObject::from_raw(config_status_jbytearray) };
420     let config_status_jobject = env
421         .new_object(
422             uwb_config_status_class,
423             "(II[B)V",
424             &[
425                 JValue::Int(i32::from(response.status)),
426                 JValue::Int(response.config_status.len() as i32),
427                 JValue::Object(config_status_jobject),
428             ],
429         )
430         .map_err(|_| Error::ForeignFunctionInterface)?;
431     Ok(*config_status_jobject)
432 }
433 
434 /// Set app configurations on a single UWB device. Return null JObject if failed.
435 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetAppConfigurations( env: JNIEnv, obj: JObject, session_id: jint, no_of_params: jint, _app_config_param_len: jint, app_config_params: jbyteArray, chip_id: JString, ) -> jbyteArray436 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetAppConfigurations(
437     env: JNIEnv,
438     obj: JObject,
439     session_id: jint,
440     no_of_params: jint,
441     _app_config_param_len: jint, // TODO(ningyuan): Obsolete parameter
442     app_config_params: jbyteArray,
443     chip_id: JString,
444 ) -> jbyteArray {
445     debug!("{}: enter", function_name!());
446     match option_result_helper(
447         native_set_app_configurations(
448             env,
449             obj,
450             session_id,
451             no_of_params,
452             app_config_params,
453             chip_id,
454         ),
455         function_name!(),
456     ) {
457         Some(config_response) => create_set_config_response(config_response, env)
458             .inspect_err(|e| {
459                 error!("{} failed with {:?}", function_name!(), &e);
460             })
461             .unwrap_or(*JObject::null()),
462         None => *JObject::null(),
463     }
464 }
465 
native_set_app_configurations( env: JNIEnv, obj: JObject, session_id: jint, no_of_params: jint, app_config_params: jbyteArray, chip_id: JString, ) -> Result<SetAppConfigResponse>466 fn native_set_app_configurations(
467     env: JNIEnv,
468     obj: JObject,
469     session_id: jint,
470     no_of_params: jint,
471     app_config_params: jbyteArray,
472     chip_id: JString,
473 ) -> Result<SetAppConfigResponse> {
474     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
475     let config_byte_array =
476         env.convert_byte_array(app_config_params).map_err(|_| Error::ForeignFunctionInterface)?;
477     let tlvs = parse_app_config_tlv_vec(no_of_params, &config_byte_array)?;
478     uci_manager.session_set_app_config(session_id as u32, tlvs)
479 }
480 
parse_rf_test_config_tlv_vec( no_of_params: i32, mut byte_array: &[u8], ) -> Result<Vec<RfTestConfigTlv>>481 fn parse_rf_test_config_tlv_vec(
482     no_of_params: i32,
483     mut byte_array: &[u8],
484 ) -> Result<Vec<RfTestConfigTlv>> {
485     let mut parsed_tlvs_len = 0;
486     let received_tlvs_len = byte_array.len();
487     let mut tlvs = Vec::<RfTestConfigTlv>::new();
488     for _ in 0..no_of_params {
489         // The tlv consists of the type of payload in 1 byte, the length of payload as u8
490         // in 1 byte, and the payload.
491         const TLV_HEADER_SIZE: usize = 2;
492         let tlv = RfTestConfigTlv::parse(byte_array).map_err(|_| Error::BadParameters)?;
493         byte_array = byte_array.get(tlv.v.len() + TLV_HEADER_SIZE..).ok_or(Error::BadParameters)?;
494         parsed_tlvs_len += tlv.v.len() + TLV_HEADER_SIZE;
495         tlvs.push(tlv);
496     }
497     if parsed_tlvs_len != received_tlvs_len {
498         return Err(Error::BadParameters);
499     };
500     Ok(tlvs)
501 }
502 
create_rf_test_config_response( response: RfTestConfigResponse, env: JNIEnv, ) -> Result<jbyteArray>503 fn create_rf_test_config_response(
504     response: RfTestConfigResponse,
505     env: JNIEnv,
506 ) -> Result<jbyteArray> {
507     let uwb_config_status_class =
508         env.find_class(CONFIG_STATUS_DATA_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
509     let mut buf = Vec::<u8>::new();
510     for config_status in &response.config_status {
511         buf.push(u8::from(config_status.cfg_id));
512         buf.push(u8::from(config_status.status));
513     }
514     let config_status_jbytearray =
515         env.byte_array_from_slice(&buf).map_err(|_| Error::ForeignFunctionInterface)?;
516 
517     // Safety: config_status_jbytearray is safely instantiated above.
518     let config_status_jobject = unsafe { JObject::from_raw(config_status_jbytearray) };
519     let config_status_jobject = env
520         .new_object(
521             uwb_config_status_class,
522             "(II[B)V",
523             &[
524                 JValue::Int(i32::from(response.status)),
525                 JValue::Int(response.config_status.len() as i32),
526                 JValue::Object(config_status_jobject),
527             ],
528         )
529         .map_err(|_| Error::ForeignFunctionInterface)?;
530     Ok(*config_status_jobject)
531 }
532 
533 /// Set Test configurations on a single UWB device. Return null JObject if failed.
534 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetRfTestAppConfigurations( env: JNIEnv, obj: JObject, session_id: jint, no_of_params: jint, _rf_test_app_config_param_len: jint, rf_test_app_config_params: jbyteArray, chip_id: JString, ) -> jbyteArray535 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetRfTestAppConfigurations(
536     env: JNIEnv,
537     obj: JObject,
538     session_id: jint,
539     no_of_params: jint,
540     _rf_test_app_config_param_len: jint,
541     rf_test_app_config_params: jbyteArray,
542     chip_id: JString,
543 ) -> jbyteArray {
544     debug!("{}: enter", function_name!());
545     match option_result_helper(
546         native_set_rf_test_app_configurations(
547             env,
548             obj,
549             session_id,
550             no_of_params,
551             rf_test_app_config_params,
552             chip_id,
553         ),
554         function_name!(),
555     ) {
556         Some(config_response) => create_rf_test_config_response(config_response, env)
557             .inspect_err(|e| {
558                 error!("{} failed with {:?}", function_name!(), &e);
559             })
560             .unwrap_or(*JObject::null()),
561         None => *JObject::null(),
562     }
563 }
564 
native_set_rf_test_app_configurations( env: JNIEnv, obj: JObject, session_id: jint, no_of_params: jint, app_config_params: jbyteArray, chip_id: JString, ) -> Result<RfTestConfigResponse>565 fn native_set_rf_test_app_configurations(
566     env: JNIEnv,
567     obj: JObject,
568     session_id: jint,
569     no_of_params: jint,
570     app_config_params: jbyteArray,
571     chip_id: JString,
572 ) -> Result<RfTestConfigResponse> {
573     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
574     let config_byte_array =
575         env.convert_byte_array(app_config_params).map_err(|_| Error::ForeignFunctionInterface)?;
576     let tlvs = parse_rf_test_config_tlv_vec(no_of_params, &config_byte_array)?;
577     uci_manager.session_set_rf_test_app_config(session_id as u32, tlvs)
578 }
579 
580 /// Stop rf test session on a single UWB device. Return value defined by uci_packets.pdl
581 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeStopRfTest( env: JNIEnv, obj: JObject, chip_id: JString, ) -> jbyte582 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeStopRfTest(
583     env: JNIEnv,
584     obj: JObject,
585     chip_id: JString,
586 ) -> jbyte {
587     debug!("{}: enter", function_name!());
588     byte_result_helper(native_stop_rf_test(env, obj, chip_id), function_name!())
589 }
590 
native_stop_rf_test(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<()>591 fn native_stop_rf_test(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<()> {
592     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
593     uci_manager.stop_rf_test()
594 }
595 
596 /// Test RF periodic tx test. Return value defined by uci_packets.pdl
597 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeTestPeriodicTx( env: JNIEnv, obj: JObject, psdu_data: jbyteArray, chip_id: JString, ) -> jbyte598 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeTestPeriodicTx(
599     env: JNIEnv,
600     obj: JObject,
601     psdu_data: jbyteArray,
602     chip_id: JString,
603 ) -> jbyte {
604     debug!("{}: enter", function_name!());
605     byte_result_helper(native_rf_test_periodic_tx(env, obj, psdu_data, chip_id), function_name!())
606 }
607 
native_rf_test_periodic_tx( env: JNIEnv, obj: JObject, psdu_data: jbyteArray, chip_id: JString, ) -> Result<()>608 fn native_rf_test_periodic_tx(
609     env: JNIEnv,
610     obj: JObject,
611     psdu_data: jbyteArray,
612     chip_id: JString,
613 ) -> Result<()> {
614     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
615     let psdu_data_bytearray =
616         env.convert_byte_array(psdu_data).map_err(|_| Error::ForeignFunctionInterface)?;
617     uci_manager.rf_test_periodic_tx(psdu_data_bytearray)
618 }
619 
620 /// Test RF per rx test. Return value defined by uci_packets.pdl
621 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeTestPerRx( env: JNIEnv, obj: JObject, psdu_data: jbyteArray, chip_id: JString, ) -> jbyte622 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeTestPerRx(
623     env: JNIEnv,
624     obj: JObject,
625     psdu_data: jbyteArray,
626     chip_id: JString,
627 ) -> jbyte {
628     debug!("{}: enter", function_name!());
629     byte_result_helper(native_rf_test_per_rx(env, obj, psdu_data, chip_id), function_name!())
630 }
631 
native_rf_test_per_rx( env: JNIEnv, obj: JObject, psdu_data: jbyteArray, chip_id: JString, ) -> Result<()>632 fn native_rf_test_per_rx(
633     env: JNIEnv,
634     obj: JObject,
635     psdu_data: jbyteArray,
636     chip_id: JString,
637 ) -> Result<()> {
638     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
639     let psdu_data_bytearray =
640         env.convert_byte_array(psdu_data).map_err(|_| Error::ForeignFunctionInterface)?;
641     uci_manager.rf_test_per_rx(psdu_data_bytearray)
642 }
643 
644 /// Set radar app configurations on a single UWB device. Return null JObject if failed.
645 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetRadarAppConfigurations( env: JNIEnv, obj: JObject, session_id: jint, no_of_params: jint, _radar_config_param_len: jint, radar_config_params: jbyteArray, chip_id: JString, ) -> jbyteArray646 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetRadarAppConfigurations(
647     env: JNIEnv,
648     obj: JObject,
649     session_id: jint,
650     no_of_params: jint,
651     _radar_config_param_len: jint,
652     radar_config_params: jbyteArray,
653     chip_id: JString,
654 ) -> jbyteArray {
655     debug!("{}: enter", function_name!());
656     match option_result_helper(
657         native_set_radar_app_configurations(
658             env,
659             obj,
660             session_id,
661             no_of_params,
662             radar_config_params,
663             chip_id,
664         ),
665         function_name!(),
666     ) {
667         Some(config_response) => create_radar_config_response(config_response, env)
668             .inspect_err(|e| {
669                 error!("{} failed with {:?}", function_name!(), &e);
670             })
671             .unwrap_or(*JObject::null()),
672         None => *JObject::null(),
673     }
674 }
675 
native_set_radar_app_configurations( env: JNIEnv, obj: JObject, session_id: jint, no_of_params: jint, radar_config_params: jbyteArray, chip_id: JString, ) -> Result<AndroidRadarConfigResponse>676 fn native_set_radar_app_configurations(
677     env: JNIEnv,
678     obj: JObject,
679     session_id: jint,
680     no_of_params: jint,
681     radar_config_params: jbyteArray,
682     chip_id: JString,
683 ) -> Result<AndroidRadarConfigResponse> {
684     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
685     let config_byte_array =
686         env.convert_byte_array(radar_config_params).map_err(|_| Error::ForeignFunctionInterface)?;
687     let tlvs = parse_radar_config_tlv_vec(no_of_params, &config_byte_array)?;
688     uci_manager.android_set_radar_config(session_id as u32, tlvs)
689 }
690 
parse_hybrid_controller_config_phase_list( number_of_phases: usize, byte_array: &[u8], ) -> Result<Vec<ControllerPhaseList>>691 fn parse_hybrid_controller_config_phase_list(
692     number_of_phases: usize,
693     byte_array: &[u8],
694 ) -> Result<Vec<ControllerPhaseList>> {
695     let mut controller_phase_list: Vec<ControllerPhaseList> = vec![];
696     let mut i = 0;
697     while i < byte_array.len() {
698         let session_token = u32::from_le_bytes(byte_array[i..(i + 4)].try_into().unwrap());
699         let start_slot_index = u16::from_le_bytes(byte_array[(i + 4)..(i + 6)].try_into().unwrap());
700         let end_slot_index = u16::from_le_bytes(byte_array[(i + 6)..(i + 8)].try_into().unwrap());
701         let control = byte_array[i + 8];
702         const MAC_ADDRESS_BIT_MASK: u8 = 0x01;
703 
704         match MacAddressIndicator::try_from(control & MAC_ADDRESS_BIT_MASK)
705             .map_err(|_| Error::BadParameters)?
706         {
707             MacAddressIndicator::ShortAddress => {
708                 let mut short_mac_address = [0; 2];
709                 const PHASE_LIST_SHORT_ADDRESS_SIZE: usize = 11;
710                 short_mac_address.copy_from_slice(&byte_array[(i + 9)..(i + 11)]);
711                 let phase_list = ControllerPhaseList {
712                     session_token,
713                     start_slot_index,
714                     end_slot_index,
715                     control,
716                     mac_address: short_mac_address.to_vec(),
717                 };
718                 i += PHASE_LIST_SHORT_ADDRESS_SIZE;
719                 controller_phase_list.push(phase_list);
720             }
721             MacAddressIndicator::ExtendedAddress => {
722                 let mut extended_mac_address = [0; 8];
723                 const PHASE_LIST_EXTENDED_ADDRESS_SIZE: usize = 17;
724                 extended_mac_address.copy_from_slice(&byte_array[(i + 9)..(i + 17)]);
725                 let phase_list = ControllerPhaseList {
726                     session_token,
727                     start_slot_index,
728                     end_slot_index,
729                     control,
730                     mac_address: extended_mac_address.to_vec(),
731                 };
732                 i += PHASE_LIST_EXTENDED_ADDRESS_SIZE;
733                 controller_phase_list.push(phase_list);
734             }
735         };
736     }
737     if controller_phase_list.len() != number_of_phases {
738         return Err(Error::BadParameters);
739     }
740     Ok(controller_phase_list)
741 }
742 
743 /// Set hybrid session controller configurations. Return null JObject if failed.
744 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetHybridSessionControllerConfigurations( env: JNIEnv, obj: JObject, session_id: jint, number_of_phases: jint, phase_list: jbyteArray, chip_id: JString, ) -> jbyte745 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetHybridSessionControllerConfigurations(
746     env: JNIEnv,
747     obj: JObject,
748     session_id: jint,
749     number_of_phases: jint,
750     phase_list: jbyteArray,
751     chip_id: JString,
752 ) -> jbyte {
753     debug!("{}: enter", function_name!());
754     byte_result_helper(
755         native_set_hybrid_session_controller_configurations(
756             env,
757             obj,
758             session_id,
759             number_of_phases,
760             phase_list,
761             chip_id,
762         ),
763         function_name!(),
764     )
765 }
766 
native_set_hybrid_session_controller_configurations( env: JNIEnv, obj: JObject, session_id: jint, number_of_phases: jint, phase_list: jbyteArray, chip_id: JString, ) -> Result<()>767 fn native_set_hybrid_session_controller_configurations(
768     env: JNIEnv,
769     obj: JObject,
770     session_id: jint,
771     number_of_phases: jint,
772     phase_list: jbyteArray,
773     chip_id: JString,
774 ) -> Result<()> {
775     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
776     let phase_list_bytes =
777         env.convert_byte_array(phase_list).map_err(|_| Error::ForeignFunctionInterface)?;
778     let phase_list =
779         parse_hybrid_controller_config_phase_list(number_of_phases as usize, &phase_list_bytes)?;
780 
781     uci_manager.session_set_hybrid_controller_config(
782         session_id as u32,
783         number_of_phases as u8,
784         phase_list,
785     )
786 }
787 
parse_hybrid_controlee_config_phase_list( number_of_phases: usize, byte_array: &[u8], ) -> Result<Vec<ControleePhaseList>>788 fn parse_hybrid_controlee_config_phase_list(
789     number_of_phases: usize,
790     byte_array: &[u8],
791 ) -> Result<Vec<ControleePhaseList>> {
792     const CONTROLEE_PHASE_LIST_SIZE: usize = 4;
793     let controlee_phase_list = byte_array
794         .chunks(CONTROLEE_PHASE_LIST_SIZE)
795         .filter(|chunk| chunk.len() == CONTROLEE_PHASE_LIST_SIZE)
796         .map(|chunk| {
797             let session_token = u32::from_le_bytes(chunk[0..4].try_into().unwrap());
798             ControleePhaseList { session_token }
799         })
800         .collect::<Vec<ControleePhaseList>>();
801     if controlee_phase_list.len() != number_of_phases {
802         return Err(Error::BadParameters);
803     }
804 
805     Ok(controlee_phase_list)
806 }
807 
808 /// Set hybrid session controlee configurations. Return null JObject if failed.
809 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetHybridSessionControleeConfigurations( env: JNIEnv, obj: JObject, session_id: jint, number_of_phases: jint, phase_list: jbyteArray, chip_id: JString, ) -> jbyte810 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetHybridSessionControleeConfigurations(
811     env: JNIEnv,
812     obj: JObject,
813     session_id: jint,
814     number_of_phases: jint,
815     phase_list: jbyteArray,
816     chip_id: JString,
817 ) -> jbyte {
818     debug!("{}: enter", function_name!());
819     byte_result_helper(
820         native_set_hybrid_session_controlee_configurations(
821             env,
822             obj,
823             session_id,
824             number_of_phases,
825             phase_list,
826             chip_id,
827         ),
828         function_name!(),
829     )
830 }
831 
native_set_hybrid_session_controlee_configurations( env: JNIEnv, obj: JObject, session_id: jint, number_of_phases: jint, phase_list: jbyteArray, chip_id: JString, ) -> Result<()>832 fn native_set_hybrid_session_controlee_configurations(
833     env: JNIEnv,
834     obj: JObject,
835     session_id: jint,
836     number_of_phases: jint,
837     phase_list: jbyteArray,
838     chip_id: JString,
839 ) -> Result<()> {
840     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
841     let phase_list_bytes =
842         env.convert_byte_array(phase_list).map_err(|_| Error::ForeignFunctionInterface)?;
843     let controlee_phase_list =
844         parse_hybrid_controlee_config_phase_list(number_of_phases as usize, &phase_list_bytes)?;
845 
846     uci_manager.session_set_hybrid_controlee_config(session_id as u32, controlee_phase_list)
847 }
848 
create_get_config_response(tlvs: Vec<AppConfigTlv>, env: JNIEnv) -> Result<jbyteArray>849 fn create_get_config_response(tlvs: Vec<AppConfigTlv>, env: JNIEnv) -> Result<jbyteArray> {
850     let tlv_data_class =
851         env.find_class(TLV_DATA_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
852     let tlvs_len = tlvs.len();
853     let mut buf = Vec::<u8>::new();
854     for tlv in tlvs.into_iter() {
855         let tlv = tlv.into_inner();
856         buf.push(u8::from(tlv.cfg_id));
857         buf.push(tlv.v.len() as u8);
858         buf.extend(&tlv.v);
859     }
860     let tlvs_jbytearray =
861         env.byte_array_from_slice(&buf).map_err(|_| Error::ForeignFunctionInterface)?;
862 
863     // Safety: tlvs_jbytearray is safely instantiated above.
864     let tlvs_jobject = unsafe { JObject::from_raw(tlvs_jbytearray) };
865     let tlvs_jobject_env = env
866         .new_object(
867             tlv_data_class,
868             "(II[B)V",
869             &[
870                 JValue::Int(i32::from(StatusCode::UciStatusOk)),
871                 JValue::Int(tlvs_len as i32),
872                 JValue::Object(tlvs_jobject),
873             ],
874         )
875         .map_err(|_| Error::ForeignFunctionInterface)?;
876     Ok(*tlvs_jobject_env)
877 }
878 
879 /// Get app configurations on a single UWB device. Return null JObject if failed.
880 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetAppConfigurations( env: JNIEnv, obj: JObject, session_id: jint, _no_of_params: jint, _app_config_param_len: jint, app_config_params: jbyteArray, chip_id: JString, ) -> jbyteArray881 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetAppConfigurations(
882     env: JNIEnv,
883     obj: JObject,
884     session_id: jint,
885     _no_of_params: jint,
886     _app_config_param_len: jint,
887     app_config_params: jbyteArray,
888     chip_id: JString,
889 ) -> jbyteArray {
890     debug!("{}: enter", function_name!());
891     match option_result_helper(
892         native_get_app_configurations(env, obj, session_id, app_config_params, chip_id),
893         function_name!(),
894     ) {
895         Some(v) => create_get_config_response(v, env)
896             .inspect_err(|e| {
897                 error!("{} failed with {:?}", function_name!(), &e);
898             })
899             .unwrap_or(*JObject::null()),
900         None => *JObject::null(),
901     }
902 }
903 
native_get_app_configurations( env: JNIEnv, obj: JObject, session_id: jint, app_config_params: jbyteArray, chip_id: JString, ) -> Result<Vec<AppConfigTlv>>904 fn native_get_app_configurations(
905     env: JNIEnv,
906     obj: JObject,
907     session_id: jint,
908     app_config_params: jbyteArray,
909     chip_id: JString,
910 ) -> Result<Vec<AppConfigTlv>> {
911     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)
912         .map_err(|_| Error::ForeignFunctionInterface)?;
913     let app_config_bytearray =
914         env.convert_byte_array(app_config_params).map_err(|_| Error::ForeignFunctionInterface)?;
915     uci_manager.session_get_app_config(
916         session_id as u32,
917         app_config_bytearray
918             .into_iter()
919             .map(AppConfigTlvType::try_from)
920             .map(std::result::Result::ok)
921             .collect::<Option<Vec<_>>>()
922             .ok_or(Error::BadParameters)?,
923     )
924 }
925 
create_cap_response(tlvs: Vec<CapTlv>, env: JNIEnv) -> Result<jbyteArray>926 fn create_cap_response(tlvs: Vec<CapTlv>, env: JNIEnv) -> Result<jbyteArray> {
927     let tlv_data_class =
928         env.find_class(TLV_DATA_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
929     let mut buf = Vec::<u8>::new();
930     for tlv in &tlvs {
931         buf.push(u8::from(tlv.t));
932         buf.push(tlv.v.len() as u8);
933         buf.extend(&tlv.v);
934     }
935     let tlvs_jbytearray =
936         env.byte_array_from_slice(&buf).map_err(|_| Error::ForeignFunctionInterface)?;
937 
938     // Safety: tlvs_jbytearray is safely instantiated above.
939     let tlvs_jobject = unsafe { JObject::from_raw(tlvs_jbytearray) };
940     let tlvs_jobject_env = env
941         .new_object(
942             tlv_data_class,
943             "(II[B)V",
944             &[
945                 JValue::Int(i32::from(StatusCode::UciStatusOk)),
946                 JValue::Int(tlvs.len() as i32),
947                 JValue::Object(tlvs_jobject),
948             ],
949         )
950         .map_err(|_| Error::ForeignFunctionInterface)?;
951     Ok(*tlvs_jobject_env)
952 }
953 
954 /// Get capability info on a single UWB device. Return null JObject if failed.
955 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetCapsInfo( env: JNIEnv, obj: JObject, chip_id: JString, ) -> jbyteArray956 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetCapsInfo(
957     env: JNIEnv,
958     obj: JObject,
959     chip_id: JString,
960 ) -> jbyteArray {
961     debug!("{}: enter", function_name!());
962     match option_result_helper(native_get_caps_info(env, obj, chip_id), function_name!()) {
963         Some(v) => create_cap_response(v, env)
964             .inspect_err(|e| {
965                 error!("{} failed with {:?}", function_name!(), &e);
966             })
967             .unwrap_or(*JObject::null()),
968         None => *JObject::null(),
969     }
970 }
971 
native_get_caps_info(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<Vec<CapTlv>>972 fn native_get_caps_info(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<Vec<CapTlv>> {
973     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
974     uci_manager.core_get_caps_info()
975 }
976 
create_session_update_controller_multicast_response( response: SessionUpdateControllerMulticastResponse, env: JNIEnv, ) -> Result<jobject>977 fn create_session_update_controller_multicast_response(
978     response: SessionUpdateControllerMulticastResponse,
979     env: JNIEnv,
980 ) -> Result<jobject> {
981     let session_update_controller_multicast_data_class = env
982         .find_class(MULTICAST_LIST_UPDATE_STATUS_CLASS)
983         .map_err(|_| Error::ForeignFunctionInterface)?;
984 
985     let (count, mac_address_jobject, status_jobject) = if response.status == StatusCode::UciStatusOk
986     {
987         (0, JObject::null(), JObject::null())
988     } else {
989         let count = response.status_list.len() as i32;
990         let (mac_address_vec, status_vec): (Vec<[u8; 2]>, Vec<_>) = response
991             .status_list
992             .into_iter()
993             .map(|cs| (cs.mac_address, i32::from(cs.status)))
994             .unzip();
995 
996         let mac_address_vec_i8 =
997             mac_address_vec.iter().flat_map(|&[a, b]| vec![a as i8, b as i8]).collect::<Vec<i8>>();
998 
999         let mac_address_jbytearray = env
1000             .new_byte_array(mac_address_vec_i8.len() as i32)
1001             .map_err(|_| Error::ForeignFunctionInterface)?;
1002 
1003         let _ = env.set_byte_array_region(mac_address_jbytearray, 0, &mac_address_vec_i8);
1004         // Safety: mac_address_jobject is safely instantiated above.
1005         let mac_address_jobject = unsafe { JObject::from_raw(mac_address_jbytearray) };
1006 
1007         let status_jintarray =
1008             env.new_int_array(count).map_err(|_| Error::ForeignFunctionInterface)?;
1009 
1010         let _ = env.set_int_array_region(status_jintarray, 0, &status_vec);
1011 
1012         // Safety: status_jintarray is safely instantiated above.
1013         let status_jobject = unsafe { JObject::from_raw(status_jintarray) };
1014         (count, mac_address_jobject, status_jobject)
1015     };
1016     match env.new_object(
1017         session_update_controller_multicast_data_class,
1018         "(JII[B[J[I)V",
1019         &[
1020             JValue::Long(0_i64),
1021             JValue::Int(0_i32),
1022             JValue::Int(count),
1023             JValue::Object(mac_address_jobject),
1024             JValue::Object(JObject::null()),
1025             JValue::Object(status_jobject),
1026         ],
1027     ) {
1028         Ok(o) => Ok(*o),
1029         Err(_) => Err(Error::ForeignFunctionInterface),
1030     }
1031 }
1032 
1033 /// Update multicast list on a single UWB device. Return value defined by uci_packets.pdl
1034 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeControllerMulticastListUpdate( env: JNIEnv, obj: JObject, session_id: jint, action: jbyte, no_of_controlee: jbyte, addresses: jbyteArray, sub_session_ids: jintArray, sub_session_keys: jbyteArray, chip_id: JString, is_multicast_list_ntf_v2_supported: jboolean, is_multicast_list_rsp_v2_supported: jboolean, ) -> jobject1035 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeControllerMulticastListUpdate(
1036     env: JNIEnv,
1037     obj: JObject,
1038     session_id: jint,
1039     action: jbyte,
1040     no_of_controlee: jbyte,
1041     addresses: jbyteArray,
1042     sub_session_ids: jintArray,
1043     sub_session_keys: jbyteArray,
1044     chip_id: JString,
1045     is_multicast_list_ntf_v2_supported: jboolean,
1046     is_multicast_list_rsp_v2_supported: jboolean,
1047 ) -> jobject {
1048     debug!("{}: enter", function_name!());
1049     match option_result_helper(
1050         native_controller_multicast_list_update(
1051             env,
1052             obj,
1053             session_id,
1054             action,
1055             no_of_controlee,
1056             addresses,
1057             sub_session_ids,
1058             sub_session_keys,
1059             chip_id,
1060             is_multicast_list_ntf_v2_supported,
1061             is_multicast_list_rsp_v2_supported,
1062         ),
1063         function_name!(),
1064     ) {
1065         Some(v) => create_session_update_controller_multicast_response(v, env)
1066             .inspect_err(|e| {
1067                 error!("{} failed with {:?}", function_name!(), &e);
1068             })
1069             .unwrap_or(*JObject::null()),
1070         None => *JObject::null(),
1071     }
1072 }
1073 
1074 // Function is used only once that copies arguments from JNI
1075 #[allow(clippy::too_many_arguments)]
native_controller_multicast_list_update( env: JNIEnv, obj: JObject, session_id: jint, action: jbyte, no_of_controlee: jbyte, addresses: jbyteArray, sub_session_ids: jintArray, sub_session_keys: jbyteArray, chip_id: JString, is_multicast_list_ntf_v2_supported: jboolean, is_multicast_list_rsp_v2_supported: jboolean, ) -> Result<SessionUpdateControllerMulticastResponse>1076 fn native_controller_multicast_list_update(
1077     env: JNIEnv,
1078     obj: JObject,
1079     session_id: jint,
1080     action: jbyte,
1081     no_of_controlee: jbyte,
1082     addresses: jbyteArray,
1083     sub_session_ids: jintArray,
1084     sub_session_keys: jbyteArray,
1085     chip_id: JString,
1086     is_multicast_list_ntf_v2_supported: jboolean,
1087     is_multicast_list_rsp_v2_supported: jboolean,
1088 ) -> Result<SessionUpdateControllerMulticastResponse> {
1089     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
1090 
1091     let addresses_bytes =
1092         env.convert_byte_array(addresses).map_err(|_| Error::ForeignFunctionInterface)?;
1093 
1094     let address_list: Vec<[u8; 2]> =
1095         addresses_bytes.chunks_exact(2).map(|chunk| [chunk[0], chunk[1]]).collect();
1096 
1097     let mut sub_session_id_list = vec![
1098         0i32;
1099         env.get_array_length(sub_session_ids)
1100             .map_err(|_| Error::ForeignFunctionInterface)?
1101             .try_into()
1102             .map_err(|_| Error::BadParameters)?
1103     ];
1104     env.get_int_array_region(sub_session_ids, 0, &mut sub_session_id_list)
1105         .map_err(|_| Error::ForeignFunctionInterface)?;
1106     if address_list.len() != sub_session_id_list.len()
1107         || address_list.len() != no_of_controlee as usize
1108     {
1109         return Err(Error::BadParameters);
1110     }
1111     let controlee_list = match UpdateMulticastListAction::try_from(action as u8)
1112         .map_err(|_| Error::BadParameters)?
1113     {
1114         UpdateMulticastListAction::AddControlee | UpdateMulticastListAction::RemoveControlee => {
1115             Controlees::NoSessionKey(
1116                 zip(address_list, sub_session_id_list)
1117                     .map(|(a, s)| Controlee { short_address: a, subsession_id: s as u32 })
1118                     .collect::<Vec<Controlee>>(),
1119             )
1120         }
1121         UpdateMulticastListAction::AddControleeWithShortSubSessionKey => {
1122             if sub_session_keys.is_null() {
1123                 Controlees::NoSessionKey(
1124                     zip(address_list, sub_session_id_list)
1125                         .map(|(a, s)| Controlee { short_address: a, subsession_id: s as u32 })
1126                         .collect::<Vec<Controlee>>(),
1127                 )
1128             } else {
1129                 Controlees::ShortSessionKey(
1130                     zip(
1131                         zip(address_list, sub_session_id_list),
1132                         env.convert_byte_array(sub_session_keys)
1133                             .map_err(|_| Error::ForeignFunctionInterface)?
1134                             .chunks(16),
1135                     )
1136                     .map(|((address, id), key)| {
1137                         Ok(Controlee_V2_0_16_Byte_Version {
1138                             short_address: address,
1139                             subsession_id: id as u32,
1140                             subsession_key: key.try_into().map_err(|_| Error::BadParameters)?,
1141                         })
1142                     })
1143                     .collect::<Result<Vec<Controlee_V2_0_16_Byte_Version>>>()?,
1144                 )
1145             }
1146         }
1147         UpdateMulticastListAction::AddControleeWithLongSubSessionKey => {
1148             if sub_session_keys.is_null() {
1149                 Controlees::NoSessionKey(
1150                     zip(address_list, sub_session_id_list)
1151                         .map(|(a, s)| Controlee { short_address: a, subsession_id: s as u32 })
1152                         .collect::<Vec<Controlee>>(),
1153                 )
1154             } else {
1155                 Controlees::LongSessionKey(
1156                     zip(
1157                         zip(address_list, sub_session_id_list),
1158                         env.convert_byte_array(sub_session_keys)
1159                             .map_err(|_| Error::ForeignFunctionInterface)?
1160                             .chunks(32),
1161                     )
1162                     .map(|((address, id), key)| {
1163                         Ok(Controlee_V2_0_32_Byte_Version {
1164                             short_address: address,
1165                             subsession_id: id as u32,
1166                             subsession_key: key.try_into().map_err(|_| Error::BadParameters)?,
1167                         })
1168                     })
1169                     .collect::<Result<Vec<Controlee_V2_0_32_Byte_Version>>>()?,
1170                 )
1171             }
1172         }
1173     };
1174     uci_manager.session_update_controller_multicast_list(
1175         session_id as u32,
1176         UpdateMulticastListAction::try_from(action as u8).map_err(|_| Error::BadParameters)?,
1177         controlee_list,
1178         is_multicast_list_ntf_v2_supported != 0,
1179         is_multicast_list_rsp_v2_supported != 0,
1180     )
1181 }
1182 
1183 /// Set country code on a single UWB device. Return value defined by uci_packets.pdl
1184 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetCountryCode( env: JNIEnv, obj: JObject, country_code: jbyteArray, chip_id: JString, ) -> jbyte1185 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetCountryCode(
1186     env: JNIEnv,
1187     obj: JObject,
1188     country_code: jbyteArray,
1189     chip_id: JString,
1190 ) -> jbyte {
1191     debug!("{}: enter", function_name!());
1192     byte_result_helper(native_set_country_code(env, obj, country_code, chip_id), function_name!())
1193 }
1194 
native_set_country_code( env: JNIEnv, obj: JObject, country_code: jbyteArray, chip_id: JString, ) -> Result<()>1195 fn native_set_country_code(
1196     env: JNIEnv,
1197     obj: JObject,
1198     country_code: jbyteArray,
1199     chip_id: JString,
1200 ) -> Result<()> {
1201     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
1202     let country_code =
1203         env.convert_byte_array(country_code).map_err(|_| Error::ForeignFunctionInterface)?;
1204     debug!("Country code: {:?}", country_code);
1205     if country_code.len() != 2 {
1206         return Err(Error::BadParameters);
1207     }
1208     uci_manager.android_set_country_code(
1209         CountryCode::new(&[country_code[0], country_code[1]]).ok_or(Error::BadParameters)?,
1210     )
1211 }
1212 
1213 /// Set log mode.
1214 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetLogMode( env: JNIEnv, obj: JObject, log_mode_jstring: JString, ) -> jboolean1215 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetLogMode(
1216     env: JNIEnv,
1217     obj: JObject,
1218     log_mode_jstring: JString,
1219 ) -> jboolean {
1220     debug!("{}: enter", function_name!());
1221     boolean_result_helper(native_set_log_mode(env, obj, log_mode_jstring), function_name!())
1222 }
1223 
native_set_log_mode(env: JNIEnv, obj: JObject, log_mode_jstring: JString) -> Result<()>1224 fn native_set_log_mode(env: JNIEnv, obj: JObject, log_mode_jstring: JString) -> Result<()> {
1225     let dispatcher = Dispatcher::get_dispatcher(env, obj)?;
1226     let logger_mode_str = String::from(
1227         env.get_string(log_mode_jstring).map_err(|_| Error::ForeignFunctionInterface)?,
1228     );
1229     debug!("UCI log: log started in {} mode", &logger_mode_str);
1230     let logger_mode = logger_mode_str.try_into()?;
1231     dispatcher.set_logger_mode(logger_mode)
1232 }
1233 
1234 // # Safety
1235 //
1236 // For this to be safe, the validity of msg should be checked before calling.
create_vendor_response(msg: RawUciMessage, env: JNIEnv) -> Result<jobject>1237 unsafe fn create_vendor_response(msg: RawUciMessage, env: JNIEnv) -> Result<jobject> {
1238     let vendor_response_class =
1239         env.find_class(VENDOR_RESPONSE_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
1240 
1241     // Safety: the byte array jobject is just constructed so it must be valid.
1242     let payload_jobject = unsafe {
1243         JObject::from_raw(
1244             env.byte_array_from_slice(&msg.payload).map_err(|_| Error::ForeignFunctionInterface)?,
1245         )
1246     };
1247 
1248     match env.new_object(
1249         vendor_response_class,
1250         "(BII[B)V",
1251         &[
1252             JValue::Byte(u8::from(StatusCode::UciStatusOk) as i8),
1253             JValue::Int(msg.gid as i32),
1254             JValue::Int(msg.oid as i32),
1255             JValue::Object(payload_jobject),
1256         ],
1257     ) {
1258         Ok(obj) => Ok(*obj),
1259         Err(_) => Err(Error::ForeignFunctionInterface),
1260     }
1261 }
1262 
create_invalid_vendor_response(env: JNIEnv) -> Result<jobject>1263 fn create_invalid_vendor_response(env: JNIEnv) -> Result<jobject> {
1264     let vendor_response_class =
1265         env.find_class(VENDOR_RESPONSE_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
1266     match env.new_object(
1267         vendor_response_class,
1268         "(BII[B)V",
1269         &[
1270             JValue::Byte(u8::from(StatusCode::UciStatusFailed) as i8),
1271             JValue::Int(-1),
1272             JValue::Int(-1),
1273             JValue::Object(JObject::null()),
1274         ],
1275     ) {
1276         Ok(obj) => Ok(*obj),
1277         Err(_) => Err(Error::ForeignFunctionInterface),
1278     }
1279 }
1280 
1281 /// # Safety
1282 ///
1283 /// `response` should be checked before calling to ensure safety.
create_ranging_round_status( response: SessionUpdateDtTagRangingRoundsResponse, env: JNIEnv, ) -> Result<jobject>1284 unsafe fn create_ranging_round_status(
1285     response: SessionUpdateDtTagRangingRoundsResponse,
1286     env: JNIEnv,
1287 ) -> Result<jobject> {
1288     let dt_ranging_rounds_update_status_class = env
1289         .find_class(DT_RANGING_ROUNDS_STATUS_CLASS)
1290         .map_err(|_| Error::ForeignFunctionInterface)?;
1291     let indexes = response.ranging_round_indexes;
1292 
1293     // Safety: the byte array jobject is just constructed so it must be valid.
1294     let indexes_jobject = unsafe {
1295         JObject::from_raw(
1296             env.byte_array_from_slice(indexes.as_ref())
1297                 .map_err(|_| Error::ForeignFunctionInterface)?,
1298         )
1299     };
1300 
1301     match env.new_object(
1302         dt_ranging_rounds_update_status_class,
1303         "(II[B)V",
1304         &[
1305             JValue::Int(i32::from(response.status)),
1306             JValue::Int(indexes.len() as i32),
1307             JValue::Object(indexes_jobject),
1308         ],
1309     ) {
1310         Ok(o) => Ok(*o),
1311         Err(_) => Err(Error::ForeignFunctionInterface),
1312     }
1313 }
1314 
1315 /// Send Raw vendor command on a single UWB device. Returns an invalid response if failed.
1316 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSendRawVendorCmd( env: JNIEnv, obj: JObject, mt: jint, gid: jint, oid: jint, payload_jarray: jbyteArray, chip_id: JString, ) -> jobject1317 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSendRawVendorCmd(
1318     env: JNIEnv,
1319     obj: JObject,
1320     mt: jint,
1321     gid: jint,
1322     oid: jint,
1323     payload_jarray: jbyteArray,
1324     chip_id: JString,
1325 ) -> jobject {
1326     debug!("{}: enter", function_name!());
1327     match option_result_helper(
1328         native_send_raw_vendor_cmd(env, obj, mt, gid, oid, payload_jarray, chip_id),
1329         function_name!(),
1330     ) {
1331         // Note: unwrap() here is not desirable, but unavoidable given non-null object is returned
1332         // even for failing cases.
1333 
1334         // Safety: create_vendor_response is unsafe, however msg is safely returned from
1335         // native_send_raw_vendor_cmd.
1336         Some(msg) => unsafe {
1337             create_vendor_response(msg, env)
1338                 .inspect_err(|e| {
1339                     error!("{} failed with {:?}", function_name!(), &e);
1340                 })
1341                 .unwrap_or_else(|_| create_invalid_vendor_response(env).unwrap())
1342         },
1343         None => create_invalid_vendor_response(env).unwrap(),
1344     }
1345 }
1346 
native_send_raw_vendor_cmd( env: JNIEnv, obj: JObject, mt: jint, gid: jint, oid: jint, payload_jarray: jbyteArray, chip_id: JString, ) -> Result<RawUciMessage>1347 fn native_send_raw_vendor_cmd(
1348     env: JNIEnv,
1349     obj: JObject,
1350     mt: jint,
1351     gid: jint,
1352     oid: jint,
1353     payload_jarray: jbyteArray,
1354     chip_id: JString,
1355 ) -> Result<RawUciMessage> {
1356     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
1357     let payload =
1358         env.convert_byte_array(payload_jarray).map_err(|_| Error::ForeignFunctionInterface)?;
1359     uci_manager.raw_uci_cmd(mt as u32, gid as u32, oid as u32, payload)
1360 }
1361 
create_power_stats(power_stats: PowerStats, env: JNIEnv) -> Result<jobject>1362 fn create_power_stats(power_stats: PowerStats, env: JNIEnv) -> Result<jobject> {
1363     let power_stats_class =
1364         env.find_class(POWER_STATS_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
1365     match env.new_object(
1366         power_stats_class,
1367         "(IIII)V",
1368         &[
1369             JValue::Int(power_stats.idle_time_ms as i32),
1370             JValue::Int(power_stats.tx_time_ms as i32),
1371             JValue::Int(power_stats.rx_time_ms as i32),
1372             JValue::Int(power_stats.total_wake_count as i32),
1373         ],
1374     ) {
1375         Ok(o) => Ok(*o),
1376         Err(_) => Err(Error::ForeignFunctionInterface),
1377     }
1378 }
1379 
1380 /// Get UWB power stats on a single UWB device. Returns a null object if failed.
1381 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetPowerStats( env: JNIEnv, obj: JObject, chip_id: JString, ) -> jobject1382 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetPowerStats(
1383     env: JNIEnv,
1384     obj: JObject,
1385     chip_id: JString,
1386 ) -> jobject {
1387     debug!("{}: enter", function_name!());
1388     match option_result_helper(native_get_power_stats(env, obj, chip_id), function_name!()) {
1389         Some(ps) => create_power_stats(ps, env)
1390             .inspect_err(|e| {
1391                 error!("{} failed with {:?}", function_name!(), &e);
1392             })
1393             .unwrap_or(*JObject::null()),
1394         None => *JObject::null(),
1395     }
1396 }
1397 
native_get_power_stats(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<PowerStats>1398 fn native_get_power_stats(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<PowerStats> {
1399     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
1400     uci_manager.android_get_power_stats()
1401 }
1402 
1403 /// Update ranging rounds for DT-TAG
1404 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionUpdateDtTagRangingRounds( env: JNIEnv, obj: JObject, session_id: jint, _ranging_rounds: jint, ranging_round_indexes: jbyteArray, chip_id: JString, ) -> jobject1405 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionUpdateDtTagRangingRounds(
1406     env: JNIEnv,
1407     obj: JObject,
1408     session_id: jint,
1409     _ranging_rounds: jint,
1410     ranging_round_indexes: jbyteArray,
1411     chip_id: JString,
1412 ) -> jobject {
1413     debug!("{}: enter", function_name!());
1414     match option_result_helper(
1415         native_set_ranging_rounds_dt_tag(
1416             env,
1417             obj,
1418             session_id as u32,
1419             ranging_round_indexes,
1420             chip_id,
1421         ),
1422         function_name!(),
1423     ) {
1424         // Safety: rr is safely returned from native_set_ranging_rounds_dt_tag
1425         Some(rr) => unsafe {
1426             create_ranging_round_status(rr, env)
1427                 .inspect_err(|e| {
1428                     error!("{} failed with {:?}", function_name!(), &e);
1429                 })
1430                 .unwrap_or(*JObject::null())
1431         },
1432         None => *JObject::null(),
1433     }
1434 }
1435 
native_set_ranging_rounds_dt_tag( env: JNIEnv, obj: JObject, session_id: u32, ranging_round_indexes: jbyteArray, chip_id: JString, ) -> Result<SessionUpdateDtTagRangingRoundsResponse>1436 fn native_set_ranging_rounds_dt_tag(
1437     env: JNIEnv,
1438     obj: JObject,
1439     session_id: u32,
1440     ranging_round_indexes: jbyteArray,
1441     chip_id: JString,
1442 ) -> Result<SessionUpdateDtTagRangingRoundsResponse> {
1443     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
1444     let indexes = env
1445         .convert_byte_array(ranging_round_indexes)
1446         .map_err(|_| Error::ForeignFunctionInterface)?;
1447     uci_manager.session_update_dt_tag_ranging_rounds(session_id, indexes)
1448 }
1449 
1450 /// Send a data packet to the remote device.
1451 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSendData( env: JNIEnv, obj: JObject, session_id: jint, address: jbyteArray, uci_sequence_number: jshort, app_payload_data: jbyteArray, chip_id: JString, ) -> jbyte1452 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSendData(
1453     env: JNIEnv,
1454     obj: JObject,
1455     session_id: jint,
1456     address: jbyteArray,
1457     uci_sequence_number: jshort,
1458     app_payload_data: jbyteArray,
1459     chip_id: JString,
1460 ) -> jbyte {
1461     debug!("{}: enter", function_name!());
1462     byte_result_helper(
1463         native_send_data(
1464             env,
1465             obj,
1466             session_id,
1467             address,
1468             uci_sequence_number,
1469             app_payload_data,
1470             chip_id,
1471         ),
1472         function_name!(),
1473     )
1474 }
1475 
1476 #[allow(clippy::too_many_arguments)]
native_send_data( env: JNIEnv, obj: JObject, session_id: jint, address: jbyteArray, uci_sequence_number: jshort, app_payload_data: jbyteArray, chip_id: JString, ) -> Result<()>1477 fn native_send_data(
1478     env: JNIEnv,
1479     obj: JObject,
1480     session_id: jint,
1481     address: jbyteArray,
1482     uci_sequence_number: jshort,
1483     app_payload_data: jbyteArray,
1484     chip_id: JString,
1485 ) -> Result<()> {
1486     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)
1487         .map_err(|_| Error::ForeignFunctionInterface)?;
1488     let address_bytearray =
1489         env.convert_byte_array(address).map_err(|_| Error::ForeignFunctionInterface)?;
1490     let app_payload_data_bytearray =
1491         env.convert_byte_array(app_payload_data).map_err(|_| Error::ForeignFunctionInterface)?;
1492     uci_manager.send_data_packet(
1493         session_id as u32,
1494         address_bytearray,
1495         uci_sequence_number as u16,
1496         app_payload_data_bytearray,
1497     )
1498 }
1499 
1500 /// Get max application data size, that can be sent by the UWBS. Return 0 if failed.
1501 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeQueryDataSize( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> jshort1502 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeQueryDataSize(
1503     env: JNIEnv,
1504     obj: JObject,
1505     session_id: jint,
1506     chip_id: JString,
1507 ) -> jshort {
1508     debug!("{}: enter", function_name!());
1509     match option_result_helper(
1510         native_query_data_size(env, obj, session_id, chip_id),
1511         function_name!(),
1512     ) {
1513         Some(s) => s.try_into().unwrap(),
1514         None => 0,
1515     }
1516 }
1517 
native_query_data_size( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> Result<u16>1518 fn native_query_data_size(
1519     env: JNIEnv,
1520     obj: JObject,
1521     session_id: jint,
1522     chip_id: JString,
1523 ) -> Result<u16> {
1524     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)
1525         .map_err(|_| Error::ForeignFunctionInterface)?;
1526     uci_manager.session_query_max_data_size(session_id as u32)
1527 }
1528 
1529 /// Set data transfer phase configuration
1530 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionDataTransferPhaseConfig( env: JNIEnv, obj: JObject, session_id: jint, dtpcm_repetition: jbyte, data_transfer_control: jbyte, dtpml_size: jbyte, mac_address: jbyteArray, slot_bitmap: jbyteArray, stop_data_transfer: jbyteArray, chip_id: JString, ) -> jbyte1531 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionDataTransferPhaseConfig(
1532     env: JNIEnv,
1533     obj: JObject,
1534     session_id: jint,
1535     dtpcm_repetition: jbyte,
1536     data_transfer_control: jbyte,
1537     dtpml_size: jbyte,
1538     mac_address: jbyteArray,
1539     slot_bitmap: jbyteArray,
1540     stop_data_transfer: jbyteArray,
1541     chip_id: JString,
1542 ) -> jbyte {
1543     debug!("{}: enter", function_name!());
1544     byte_result_helper(
1545         native_session_data_transfer_phase_config(
1546             env,
1547             obj,
1548             session_id,
1549             dtpcm_repetition,
1550             data_transfer_control,
1551             dtpml_size,
1552             mac_address,
1553             slot_bitmap,
1554             stop_data_transfer,
1555             chip_id,
1556         ),
1557         function_name!(),
1558     )
1559 }
1560 
1561 #[allow(clippy::too_many_arguments)]
native_session_data_transfer_phase_config( env: JNIEnv, obj: JObject, session_id: jint, dtpcm_repetition: jbyte, data_transfer_control: jbyte, dtpml_size: jbyte, mac_address: jbyteArray, slot_bitmap: jbyteArray, stop_data_transfer: jbyteArray, chip_id: JString, ) -> Result<()>1562 fn native_session_data_transfer_phase_config(
1563     env: JNIEnv,
1564     obj: JObject,
1565     session_id: jint,
1566     dtpcm_repetition: jbyte,
1567     data_transfer_control: jbyte,
1568     dtpml_size: jbyte,
1569     mac_address: jbyteArray,
1570     slot_bitmap: jbyteArray,
1571     stop_data_transfer: jbyteArray,
1572     chip_id: JString,
1573 ) -> Result<()> {
1574     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)
1575         .map_err(|_| Error::ForeignFunctionInterface)?;
1576     uci_manager.session_data_transfer_phase_config(
1577         session_id as u32,
1578         dtpcm_repetition as u8,
1579         data_transfer_control as u8,
1580         dtpml_size as u8,
1581         env.convert_byte_array(mac_address).map_err(|_| Error::ForeignFunctionInterface)?,
1582         env.convert_byte_array(slot_bitmap).map_err(|_| Error::ForeignFunctionInterface)?,
1583         env.convert_byte_array(stop_data_transfer).map_err(|_| Error::ForeignFunctionInterface)?,
1584     )
1585 }
1586 
1587 /// Get UWBS timestamp, Return 0 if failed.
1588 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeQueryUwbTimestamp( env: JNIEnv, obj: JObject, chip_id: JString, ) -> jlong1589 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeQueryUwbTimestamp(
1590     env: JNIEnv,
1591     obj: JObject,
1592     chip_id: JString,
1593 ) -> jlong {
1594     debug!("{}: enter", function_name!());
1595     match option_result_helper(native_query_time_stamp(env, obj, chip_id), function_name!()) {
1596         Some(s) => s.try_into().unwrap(),
1597         None => 0,
1598     }
1599 }
1600 
native_query_time_stamp(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<u64>1601 fn native_query_time_stamp(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<u64> {
1602     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)
1603         .map_err(|_| Error::ForeignFunctionInterface)?;
1604     uci_manager.core_query_uwb_timestamp()
1605 }
1606 
1607 /// Get session token for the UWB session.
1608 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionToken( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> jlong1609 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionToken(
1610     env: JNIEnv,
1611     obj: JObject,
1612     session_id: jint,
1613     chip_id: JString,
1614 ) -> jlong {
1615     debug!("{}: enter", function_name!());
1616     match option_result_helper(
1617         native_get_session_token(env, obj, session_id, chip_id),
1618         function_name!(),
1619     ) {
1620         Some(s) => s.try_into().unwrap(),
1621         None => 0,
1622     }
1623 }
1624 
native_get_session_token( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> Result<u32>1625 fn native_get_session_token(
1626     env: JNIEnv,
1627     obj: JObject,
1628     session_id: jint,
1629     chip_id: JString,
1630 ) -> Result<u32> {
1631     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)
1632         .map_err(|_| Error::ForeignFunctionInterface)?;
1633     uci_manager.get_session_token(session_id as u32)
1634 }
1635 
1636 /// Get the class loader object. Has to be called from a JNIEnv where the local java classes are
1637 /// loaded. Results in a global reference to the class loader object that can be used to look for
1638 /// classes in other native thread.
get_class_loader_obj(env: &JNIEnv) -> Result<GlobalRef>1639 fn get_class_loader_obj(env: &JNIEnv) -> Result<GlobalRef> {
1640     let ranging_data_class =
1641         env.find_class(UWB_RANGING_DATA_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
1642     let ranging_data_class_class =
1643         env.get_object_class(ranging_data_class).map_err(|_| Error::ForeignFunctionInterface)?;
1644     let get_class_loader_method = env
1645         .get_method_id(ranging_data_class_class, "getClassLoader", "()Ljava/lang/ClassLoader;")
1646         .map_err(|_| Error::ForeignFunctionInterface)?;
1647     let class_loader = env
1648         .call_method_unchecked(
1649             ranging_data_class,
1650             get_class_loader_method,
1651             ReturnType::Object,
1652             &[jvalue::from(JValue::Void)],
1653         )
1654         .map_err(|_| Error::ForeignFunctionInterface)?;
1655     let class_loader_jobject = class_loader.l().map_err(|_| Error::ForeignFunctionInterface)?;
1656     env.new_global_ref(class_loader_jobject).map_err(|_| Error::ForeignFunctionInterface)
1657 }
1658 
1659 /// Create the dispatcher. Returns pointer to Dispatcher casted as jlong that owns the dispatcher.
1660 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherNew( env: JNIEnv, obj: JObject, chip_ids_jarray: jobjectArray, ) -> jlong1661 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherNew(
1662     env: JNIEnv,
1663     obj: JObject,
1664     chip_ids_jarray: jobjectArray,
1665 ) -> jlong {
1666     debug!("{}: enter", function_name!());
1667     match option_result_helper(native_dispatcher_new(env, obj, chip_ids_jarray), function_name!()) {
1668         Some(ptr) => ptr as jlong,
1669         None => *JObject::null() as jlong,
1670     }
1671 }
1672 
native_dispatcher_new( env: JNIEnv, obj: JObject, chip_ids_jarray: jobjectArray, ) -> Result<*const Dispatcher>1673 fn native_dispatcher_new(
1674     env: JNIEnv,
1675     obj: JObject,
1676     chip_ids_jarray: jobjectArray,
1677 ) -> Result<*const Dispatcher> {
1678     let chip_ids_len: i32 =
1679         env.get_array_length(chip_ids_jarray).map_err(|_| Error::ForeignFunctionInterface)?;
1680     let chip_ids = (0..chip_ids_len)
1681         .map(|i| env.get_string(env.get_object_array_element(chip_ids_jarray, i)?.into()))
1682         .collect::<std::result::Result<Vec<_>, JNIError>>()
1683         .map_err(|_| Error::ForeignFunctionInterface)?;
1684     let chip_ids = chip_ids.into_iter().map(String::from).collect::<Vec<String>>();
1685     let class_loader_obj = get_class_loader_obj(&env)?;
1686     Dispatcher::new_dispatcher(
1687         unique_jvm::get_static_ref().ok_or(Error::Unknown)?,
1688         class_loader_obj,
1689         env.new_global_ref(obj).map_err(|_| Error::ForeignFunctionInterface)?,
1690         &chip_ids,
1691     )?;
1692     Dispatcher::get_dispatcher_ptr()
1693 }
1694 
1695 /// Destroys the dispatcher.
1696 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherDestroy( env: JNIEnv, obj: JObject, )1697 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherDestroy(
1698     env: JNIEnv,
1699     obj: JObject,
1700 ) {
1701     debug!("{}: enter", function_name!());
1702     if option_result_helper(native_dispatcher_destroy(env, obj), function_name!()).is_some() {
1703         debug!("The dispatcher is successfully destroyed.");
1704     }
1705 }
1706 
native_dispatcher_destroy(env: JNIEnv, obj: JObject) -> Result<()>1707 fn native_dispatcher_destroy(env: JNIEnv, obj: JObject) -> Result<()> {
1708     let dispatcher_ptr_long = env
1709         .get_field(obj, "mDispatcherPointer", "J")
1710         .map_err(|_| Error::ForeignFunctionInterface)?
1711         .j()
1712         .map_err(|_| Error::ForeignFunctionInterface)?;
1713     if Dispatcher::get_dispatcher_ptr()? as jlong == dispatcher_ptr_long {
1714         Dispatcher::destroy_dispatcher()
1715     } else {
1716         Err(Error::BadParameters)
1717     }
1718 }
1719 
1720 #[cfg(test)]
1721 mod tests {
1722     use super::*;
1723 
1724     use tokio::runtime::Builder;
1725     use uwb_core::uci::mock_uci_manager::MockUciManager;
1726     use uwb_core::uci::uci_manager_sync::{
1727         NotificationManager, NotificationManagerBuilder, UciManagerSync,
1728     };
1729     use uwb_core::uci::{
1730         CoreNotification, DataRcvNotification, RadarDataRcvNotification, SessionNotification,
1731     };
1732     use uwb_uci_packets::RadarConfigTlvType;
1733 
1734     struct NullNotificationManager {}
1735     impl NotificationManager for NullNotificationManager {
on_core_notification(&mut self, _core_notification: CoreNotification) -> Result<()>1736         fn on_core_notification(&mut self, _core_notification: CoreNotification) -> Result<()> {
1737             Ok(())
1738         }
on_session_notification( &mut self, _session_notification: SessionNotification, ) -> Result<()>1739         fn on_session_notification(
1740             &mut self,
1741             _session_notification: SessionNotification,
1742         ) -> Result<()> {
1743             Ok(())
1744         }
on_vendor_notification(&mut self, _vendor_notification: RawUciMessage) -> Result<()>1745         fn on_vendor_notification(&mut self, _vendor_notification: RawUciMessage) -> Result<()> {
1746             Ok(())
1747         }
on_data_rcv_notification(&mut self, _data_rcv_notf: DataRcvNotification) -> Result<()>1748         fn on_data_rcv_notification(&mut self, _data_rcv_notf: DataRcvNotification) -> Result<()> {
1749             Ok(())
1750         }
1751         /// Callback for RadarDataRcvNotification.
on_radar_data_rcv_notification( &mut self, _radar_data_rcv_notification: RadarDataRcvNotification, ) -> Result<()>1752         fn on_radar_data_rcv_notification(
1753             &mut self,
1754             _radar_data_rcv_notification: RadarDataRcvNotification,
1755         ) -> Result<()> {
1756             Ok(())
1757         }
1758 
on_rf_test_notification( &mut self, _: uwb_core::uci::RfTestNotification, ) -> std::result::Result<(), uwb_core::error::Error>1759         fn on_rf_test_notification(
1760             &mut self,
1761             _: uwb_core::uci::RfTestNotification,
1762         ) -> std::result::Result<(), uwb_core::error::Error> {
1763             Ok(())
1764         }
1765     }
1766 
1767     struct NullNotificationManagerBuilder {}
1768 
1769     impl NullNotificationManagerBuilder {
new() -> Self1770         fn new() -> Self {
1771             Self {}
1772         }
1773     }
1774 
1775     impl NotificationManagerBuilder for NullNotificationManagerBuilder {
1776         type NotificationManager = NullNotificationManager;
1777 
build(self) -> Option<Self::NotificationManager>1778         fn build(self) -> Option<Self::NotificationManager> {
1779             Some(NullNotificationManager {})
1780         }
1781     }
1782 
1783     /// Checks validity of the function_name! macro.
1784     #[test]
test_function_name()1785     fn test_function_name() {
1786         assert_eq!(function_name!(), "test_function_name");
1787     }
1788 
1789     /// Checks native_set_app_configurations by mocking non-jni logic.
1790     #[test]
test_native_set_app_configurations()1791     fn test_native_set_app_configurations() {
1792         // Constructs mock UciManagerSync.
1793         let test_rt = Builder::new_multi_thread().enable_all().build().unwrap();
1794         let mut uci_manager_impl = MockUciManager::new();
1795         uci_manager_impl.expect_session_set_app_config(
1796             42, // Session id
1797             vec![
1798                 AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![1]),
1799                 AppConfigTlv::new(AppConfigTlvType::RangingRoundUsage, vec![1]),
1800             ],
1801             vec![],
1802             Ok(SetAppConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] }),
1803         );
1804         let uci_manager_sync = UciManagerSync::new_mock(
1805             uci_manager_impl,
1806             test_rt.handle().to_owned(),
1807             NullNotificationManagerBuilder::new(),
1808         )
1809         .unwrap();
1810 
1811         let app_config_byte_array: Vec<u8> = vec![
1812             0, 1, 1, // DeviceType: controller
1813             1, 1, 1, // RangingRoundUsage: DS_TWR
1814         ];
1815         let tlvs = parse_app_config_tlv_vec(2, &app_config_byte_array).unwrap();
1816         assert!(uci_manager_sync.session_set_app_config(42, tlvs).is_ok());
1817     }
1818 
1819     #[test]
test_parse_radar_config_tlv_vec()1820     fn test_parse_radar_config_tlv_vec() {
1821         let radar_config_tlv_vec: Vec<u8> = vec![
1822             0x0, 0x2, 0x0, 0x1, // The first tlv
1823             0x1, 0x1, 0x1, // The second tlv
1824         ];
1825         let tlvs = parse_radar_config_tlv_vec(2, &radar_config_tlv_vec).unwrap();
1826         assert_eq!(
1827             tlvs[0],
1828             RadarConfigTlv { cfg_id: RadarConfigTlvType::RadarTimingParams, v: vec![0x0, 0x1] }
1829         );
1830         assert_eq!(
1831             tlvs[1],
1832             RadarConfigTlv { cfg_id: RadarConfigTlvType::SamplesPerSweep, v: vec![0x1] }
1833         );
1834     }
1835 
1836     #[test]
test_parse_hybrid_controller_config_phase_list()1837     fn test_parse_hybrid_controller_config_phase_list() {
1838         let mut raw_controller_config_phase_list = vec![
1839             0x1, 0x0, 0x0, 0x0, // session token
1840             0x1, 0x0, // start slot index
1841             0x2, 0x0, // end slot index
1842             0x0, //control
1843             0x1, 0x2, // mac address
1844         ];
1845         let mut phase_list =
1846             parse_hybrid_controller_config_phase_list(1, &raw_controller_config_phase_list)
1847                 .unwrap();
1848         assert_eq!(
1849             vec![uwb_uci_packets::ControllerPhaseList {
1850                 session_token: 1,
1851                 start_slot_index: 1,
1852                 end_slot_index: 2,
1853                 control: 0,
1854                 mac_address: [0x1, 0x2].to_vec()
1855             }],
1856             phase_list
1857         );
1858 
1859         raw_controller_config_phase_list = vec![
1860             0x1, 0x0, 0x0, 0x0, // session token
1861             0x1, 0x0, // start slot index
1862             0x2, 0x0, // end slot index
1863             0x1, //control
1864             0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, // mac address
1865         ];
1866         phase_list =
1867             parse_hybrid_controller_config_phase_list(1, &raw_controller_config_phase_list)
1868                 .unwrap();
1869         assert_eq!(
1870             vec![uwb_uci_packets::ControllerPhaseList {
1871                 session_token: 1,
1872                 start_slot_index: 1,
1873                 end_slot_index: 2,
1874                 control: 1,
1875                 mac_address: [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8].to_vec()
1876             }],
1877             phase_list
1878         );
1879     }
1880 
1881     #[test]
test_parse_hybrid_controlee_config_phase_list()1882     fn test_parse_hybrid_controlee_config_phase_list() {
1883         let raw_controlee_config_phase_list = vec![
1884             0x1, 0x0, 0x0, 0x0, // session token
1885         ];
1886         let phase_list =
1887             parse_hybrid_controlee_config_phase_list(1, &raw_controlee_config_phase_list).unwrap();
1888         assert_eq!(vec![ControleePhaseList { session_token: 1 }], phase_list);
1889     }
1890 }
1891