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