• 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, POWER_STATS_CLASS, TLV_DATA_CLASS,
21     UWB_RANGING_DATA_CLASS, VENDOR_RESPONSE_CLASS,
22 };
23 use crate::unique_jvm;
24 
25 use std::convert::TryInto;
26 use std::iter::zip;
27 
28 use jni::errors::Error as JNIError;
29 use jni::objects::{GlobalRef, JObject, JString, JValue};
30 use jni::signature::ReturnType;
31 use jni::sys::{
32     jboolean, jbyte, jbyteArray, jint, jintArray, jlong, jobject, jobjectArray, jshort, jvalue,
33 };
34 use jni::JNIEnv;
35 use log::{debug, error};
36 use uwb_core::error::{Error, Result};
37 use uwb_core::params::{
38     AppConfigTlv, CountryCode, RawAppConfigTlv, RawUciMessage,
39     SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse,
40 };
41 use uwb_uci_packets::{
42     AppConfigTlvType, CapTlv, Controlee, Controlee_V2_0_16_Byte_Version,
43     Controlee_V2_0_32_Byte_Version, Controlees, FiraComponent, PowerStats, ResetConfig,
44     SessionState, SessionType, StatusCode, UpdateMulticastListAction,
45 };
46 
47 /// Macro capturing the name of the function calling this macro.
48 ///
49 /// function_name()! -> &'static str
50 /// Returns the function name as 'static reference.
51 macro_rules! function_name {
52     () => {{
53         // Declares function f inside current function.
54         fn f() {}
55         fn type_name_of<T>(_: T) -> &'static str {
56             std::any::type_name::<T>()
57         }
58         // type name of f is struct_or_crate_name::calling_function_name::f
59         let name = type_name_of(f);
60         // Find and cut the rest of the path:
61         // Third to last character, up to the first semicolon: is calling_function_name
62         match &name[..name.len() - 3].rfind(':') {
63             Some(pos) => &name[pos + 1..name.len() - 3],
64             None => &name[..name.len() - 3],
65         }
66     }};
67 }
68 
69 /// Initialize native library. Captures VM:
70 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeInit( env: JNIEnv, _obj: JObject, ) -> jboolean71 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeInit(
72     env: JNIEnv,
73     _obj: JObject,
74 ) -> jboolean {
75     logger::init(
76         logger::Config::default()
77             .with_tag_on_device("uwb")
78             .with_min_level(log::Level::Trace)
79             .with_filter("trace,jni=info"),
80     );
81     debug!("{}: enter", function_name!());
82     boolean_result_helper(native_init(env), function_name!())
83 }
84 
native_init(env: JNIEnv) -> Result<()>85 fn native_init(env: JNIEnv) -> Result<()> {
86     let jvm = env.get_java_vm().map_err(|_| Error::ForeignFunctionInterface)?;
87     unique_jvm::set_once(jvm)
88 }
89 
90 /// Turn on Single UWB chip.
91 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoInitialize( env: JNIEnv, obj: JObject, chip_id: JString, ) -> jboolean92 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoInitialize(
93     env: JNIEnv,
94     obj: JObject,
95     chip_id: JString,
96 ) -> jboolean {
97     debug!("{}: enter", function_name!());
98     boolean_result_helper(native_do_initialize(env, obj, chip_id), function_name!())
99 }
100 
native_do_initialize(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<()>101 fn native_do_initialize(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<()> {
102     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
103     uci_manager.open_hal()
104 }
105 
106 /// Turn off single UWB chip.
107 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoDeinitialize( env: JNIEnv, obj: JObject, chip_id: JString, ) -> jboolean108 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoDeinitialize(
109     env: JNIEnv,
110     obj: JObject,
111     chip_id: JString,
112 ) -> jboolean {
113     debug!("{}: enter", function_name!());
114     boolean_result_helper(native_do_deinitialize(env, obj, chip_id), function_name!())
115 }
116 
native_do_deinitialize(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<()>117 fn native_do_deinitialize(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<()> {
118     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
119     uci_manager.close_hal(true)
120 }
121 
122 /// Get nanos. Not currently used and returns placeholder value.
123 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetTimestampResolutionNanos( _env: JNIEnv, _obj: JObject, ) -> jlong124 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetTimestampResolutionNanos(
125     _env: JNIEnv,
126     _obj: JObject,
127 ) -> jlong {
128     debug!("{}: enter", function_name!());
129     0
130 }
131 
132 /// Reset a single UWB device by sending UciDeviceReset command. Return value defined by
133 /// <AndroidRoot>/external/uwb/src/rust/uwb_uci_packets/uci_packets.pdl
134 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDeviceReset( env: JNIEnv, obj: JObject, _reset_config: jbyte, chip_id: JString, ) -> jbyte135 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDeviceReset(
136     env: JNIEnv,
137     obj: JObject,
138     _reset_config: jbyte,
139     chip_id: JString,
140 ) -> jbyte {
141     debug!("{}: enter", function_name!());
142     byte_result_helper(native_device_reset(env, obj, chip_id), function_name!())
143 }
144 
native_device_reset(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<()>145 fn native_device_reset(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<()> {
146     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
147     uci_manager.device_reset(ResetConfig::UwbsReset)
148 }
149 
150 /// Init the session on a single UWB device. Return value defined by uci_packets.pdl
151 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionInit( env: JNIEnv, obj: JObject, session_id: jint, session_type: jbyte, chip_id: JString, ) -> jbyte152 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionInit(
153     env: JNIEnv,
154     obj: JObject,
155     session_id: jint,
156     session_type: jbyte,
157     chip_id: JString,
158 ) -> jbyte {
159     debug!("{}: enter", function_name!());
160     byte_result_helper(
161         native_session_init(env, obj, session_id, session_type, chip_id),
162         function_name!(),
163     )
164 }
165 
native_session_init( env: JNIEnv, obj: JObject, session_id: jint, session_type: jbyte, chip_id: JString, ) -> Result<()>166 fn native_session_init(
167     env: JNIEnv,
168     obj: JObject,
169     session_id: jint,
170     session_type: jbyte,
171     chip_id: JString,
172 ) -> Result<()> {
173     let session_type =
174         SessionType::try_from(session_type as u8).map_err(|_| Error::BadParameters)?;
175     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
176     uci_manager.session_init(session_id as u32, session_type)
177 }
178 
179 /// DeInit the session on a single UWB device. Return value defined by uci_packets.pdl
180 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionDeInit( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> jbyte181 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionDeInit(
182     env: JNIEnv,
183     obj: JObject,
184     session_id: jint,
185     chip_id: JString,
186 ) -> jbyte {
187     debug!("{}: enter", function_name!());
188     byte_result_helper(native_session_deinit(env, obj, session_id, chip_id), function_name!())
189 }
190 
native_session_deinit( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> Result<()>191 fn native_session_deinit(
192     env: JNIEnv,
193     obj: JObject,
194     session_id: jint,
195     chip_id: JString,
196 ) -> Result<()> {
197     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
198     uci_manager.session_deinit(session_id as u32)
199 }
200 
201 /// Get session count on a single UWB device. return -1 if failed
202 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionCount( env: JNIEnv, obj: JObject, chip_id: JString, ) -> jbyte203 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionCount(
204     env: JNIEnv,
205     obj: JObject,
206     chip_id: JString,
207 ) -> jbyte {
208     debug!("{}: enter", function_name!());
209     match option_result_helper(native_get_session_count(env, obj, chip_id), function_name!()) {
210         // Max session count is 5, will not overflow i8
211         Some(c) => c as i8,
212         None => -1,
213     }
214 }
215 
native_get_session_count(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<u8>216 fn native_get_session_count(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<u8> {
217     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
218     uci_manager.session_get_count()
219 }
220 
221 /// Start ranging on a single UWB device. Return value defined by uci_packets.pdl
222 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStart( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> jbyte223 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStart(
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_ranging_start(env, obj, session_id, chip_id), function_name!())
231 }
232 
native_ranging_start( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> Result<()>233 fn native_ranging_start(
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.range_start(session_id as u32)
241 }
242 
243 /// Stop ranging on a single UWB device. Return value defined by uci_packets.pdl
244 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStop( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> jbyte245 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStop(
246     env: JNIEnv,
247     obj: JObject,
248     session_id: jint,
249     chip_id: JString,
250 ) -> jbyte {
251     debug!("{}: enter", function_name!());
252     byte_result_helper(native_ranging_stop(env, obj, session_id, chip_id), function_name!())
253 }
254 
native_ranging_stop( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> Result<()>255 fn native_ranging_stop(
256     env: JNIEnv,
257     obj: JObject,
258     session_id: jint,
259     chip_id: JString,
260 ) -> Result<()> {
261     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
262     uci_manager.range_stop(session_id as u32)
263 }
264 
265 /// Get session stateon a single UWB device. Return -1 if failed
266 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionState( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> jbyte267 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionState(
268     env: JNIEnv,
269     obj: JObject,
270     session_id: jint,
271     chip_id: JString,
272 ) -> jbyte {
273     debug!("{}: enter", function_name!());
274     match option_result_helper(
275         native_get_session_state(env, obj, session_id, chip_id),
276         function_name!(),
277     ) {
278         // SessionState does not overflow i8
279         Some(s) => s as i8,
280         None => -1,
281     }
282 }
283 
native_get_session_state( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> Result<SessionState>284 fn native_get_session_state(
285     env: JNIEnv,
286     obj: JObject,
287     session_id: jint,
288     chip_id: JString,
289 ) -> Result<SessionState> {
290     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
291     uci_manager.session_get_state(session_id as u32)
292 }
293 
parse_app_config_tlv_vec(no_of_params: i32, mut byte_array: &[u8]) -> Result<Vec<AppConfigTlv>>294 fn parse_app_config_tlv_vec(no_of_params: i32, mut byte_array: &[u8]) -> Result<Vec<AppConfigTlv>> {
295     let mut parsed_tlvs_len = 0;
296     let received_tlvs_len = byte_array.len();
297     let mut tlvs = Vec::<AppConfigTlv>::new();
298     for _ in 0..no_of_params {
299         // The tlv consists of the type of payload in 1 byte, the length of payload as u8
300         // in 1 byte, and the payload.
301         const TLV_HEADER_SIZE: usize = 2;
302         let tlv = RawAppConfigTlv::parse(byte_array).map_err(|_| Error::BadParameters)?;
303         byte_array = byte_array.get(tlv.v.len() + TLV_HEADER_SIZE..).ok_or(Error::BadParameters)?;
304         parsed_tlvs_len += tlv.v.len() + TLV_HEADER_SIZE;
305         tlvs.push(tlv.into());
306     }
307     if parsed_tlvs_len != received_tlvs_len {
308         return Err(Error::BadParameters);
309     };
310     Ok(tlvs)
311 }
312 
create_set_config_response(response: SetAppConfigResponse, env: JNIEnv) -> Result<jbyteArray>313 fn create_set_config_response(response: SetAppConfigResponse, env: JNIEnv) -> Result<jbyteArray> {
314     let uwb_config_status_class =
315         env.find_class(CONFIG_STATUS_DATA_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
316     let mut buf = Vec::<u8>::new();
317     for config_status in &response.config_status {
318         buf.push(u8::from(config_status.cfg_id));
319         buf.push(u8::from(config_status.status));
320     }
321     let config_status_jbytearray =
322         env.byte_array_from_slice(&buf).map_err(|_| Error::ForeignFunctionInterface)?;
323 
324     // Safety: config_status_jbytearray is safely instantiated above.
325     let config_status_jobject = unsafe { JObject::from_raw(config_status_jbytearray) };
326     let config_status_jobject = env
327         .new_object(
328             uwb_config_status_class,
329             "(II[B)V",
330             &[
331                 JValue::Int(i32::from(response.status)),
332                 JValue::Int(response.config_status.len() as i32),
333                 JValue::Object(config_status_jobject),
334             ],
335         )
336         .map_err(|_| Error::ForeignFunctionInterface)?;
337     Ok(*config_status_jobject)
338 }
339 
340 /// Set app configurations on a single UWB device. Return null JObject if failed.
341 #[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, ) -> jbyteArray342 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetAppConfigurations(
343     env: JNIEnv,
344     obj: JObject,
345     session_id: jint,
346     no_of_params: jint,
347     _app_config_param_len: jint, // TODO(ningyuan): Obsolete parameter
348     app_config_params: jbyteArray,
349     chip_id: JString,
350 ) -> jbyteArray {
351     debug!("{}: enter", function_name!());
352     match option_result_helper(
353         native_set_app_configurations(
354             env,
355             obj,
356             session_id,
357             no_of_params,
358             app_config_params,
359             chip_id,
360         ),
361         function_name!(),
362     ) {
363         Some(config_response) => create_set_config_response(config_response, env)
364             .map_err(|e| {
365                 error!("{} failed with {:?}", function_name!(), &e);
366                 e
367             })
368             .unwrap_or(*JObject::null()),
369         None => *JObject::null(),
370     }
371 }
372 
native_set_app_configurations( env: JNIEnv, obj: JObject, session_id: jint, no_of_params: jint, app_config_params: jbyteArray, chip_id: JString, ) -> Result<SetAppConfigResponse>373 fn native_set_app_configurations(
374     env: JNIEnv,
375     obj: JObject,
376     session_id: jint,
377     no_of_params: jint,
378     app_config_params: jbyteArray,
379     chip_id: JString,
380 ) -> Result<SetAppConfigResponse> {
381     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
382     let config_byte_array =
383         env.convert_byte_array(app_config_params).map_err(|_| Error::ForeignFunctionInterface)?;
384     let tlvs = parse_app_config_tlv_vec(no_of_params, &config_byte_array)?;
385     uci_manager.session_set_app_config(session_id as u32, tlvs)
386 }
387 
create_get_config_response(tlvs: Vec<AppConfigTlv>, env: JNIEnv) -> Result<jbyteArray>388 fn create_get_config_response(tlvs: Vec<AppConfigTlv>, env: JNIEnv) -> Result<jbyteArray> {
389     let tlv_data_class =
390         env.find_class(TLV_DATA_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
391     let tlvs_len = tlvs.len();
392     let mut buf = Vec::<u8>::new();
393     for tlv in tlvs.into_iter() {
394         let tlv = tlv.into_inner();
395         buf.push(u8::from(tlv.cfg_id));
396         buf.push(tlv.v.len() as u8);
397         buf.extend(&tlv.v);
398     }
399     let tlvs_jbytearray =
400         env.byte_array_from_slice(&buf).map_err(|_| Error::ForeignFunctionInterface)?;
401 
402     // Safety: tlvs_jbytearray is safely instantiated above.
403     let tlvs_jobject = unsafe { JObject::from_raw(tlvs_jbytearray) };
404     let tlvs_jobject_env = env
405         .new_object(
406             tlv_data_class,
407             "(II[B)V",
408             &[
409                 JValue::Int(i32::from(StatusCode::UciStatusOk)),
410                 JValue::Int(tlvs_len as i32),
411                 JValue::Object(tlvs_jobject),
412             ],
413         )
414         .map_err(|_| Error::ForeignFunctionInterface)?;
415     Ok(*tlvs_jobject_env)
416 }
417 
418 /// Get app configurations on a single UWB device. Return null JObject if failed.
419 #[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, ) -> jbyteArray420 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetAppConfigurations(
421     env: JNIEnv,
422     obj: JObject,
423     session_id: jint,
424     _no_of_params: jint,
425     _app_config_param_len: jint,
426     app_config_params: jbyteArray,
427     chip_id: JString,
428 ) -> jbyteArray {
429     debug!("{}: enter", function_name!());
430     match option_result_helper(
431         native_get_app_configurations(env, obj, session_id, app_config_params, chip_id),
432         function_name!(),
433     ) {
434         Some(v) => create_get_config_response(v, env)
435             .map_err(|e| {
436                 error!("{} failed with {:?}", function_name!(), &e);
437                 e
438             })
439             .unwrap_or(*JObject::null()),
440         None => *JObject::null(),
441     }
442 }
443 
native_get_app_configurations( env: JNIEnv, obj: JObject, session_id: jint, app_config_params: jbyteArray, chip_id: JString, ) -> Result<Vec<AppConfigTlv>>444 fn native_get_app_configurations(
445     env: JNIEnv,
446     obj: JObject,
447     session_id: jint,
448     app_config_params: jbyteArray,
449     chip_id: JString,
450 ) -> Result<Vec<AppConfigTlv>> {
451     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)
452         .map_err(|_| Error::ForeignFunctionInterface)?;
453     let app_config_bytearray =
454         env.convert_byte_array(app_config_params).map_err(|_| Error::ForeignFunctionInterface)?;
455     uci_manager.session_get_app_config(
456         session_id as u32,
457         app_config_bytearray
458             .into_iter()
459             .map(AppConfigTlvType::try_from)
460             .map(std::result::Result::ok)
461             .collect::<Option<Vec<_>>>()
462             .ok_or(Error::BadParameters)?,
463     )
464 }
465 
create_cap_response(tlvs: Vec<CapTlv>, env: JNIEnv) -> Result<jbyteArray>466 fn create_cap_response(tlvs: Vec<CapTlv>, env: JNIEnv) -> Result<jbyteArray> {
467     let tlv_data_class =
468         env.find_class(TLV_DATA_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
469     let mut buf = Vec::<u8>::new();
470     for tlv in &tlvs {
471         buf.push(u8::from(tlv.t));
472         buf.push(tlv.v.len() as u8);
473         buf.extend(&tlv.v);
474     }
475     let tlvs_jbytearray =
476         env.byte_array_from_slice(&buf).map_err(|_| Error::ForeignFunctionInterface)?;
477 
478     // Safety: tlvs_jbytearray is safely instantiated above.
479     let tlvs_jobject = unsafe { JObject::from_raw(tlvs_jbytearray) };
480     let tlvs_jobject_env = env
481         .new_object(
482             tlv_data_class,
483             "(II[B)V",
484             &[
485                 JValue::Int(i32::from(StatusCode::UciStatusOk)),
486                 JValue::Int(tlvs.len() as i32),
487                 JValue::Object(tlvs_jobject),
488             ],
489         )
490         .map_err(|_| Error::ForeignFunctionInterface)?;
491     Ok(*tlvs_jobject_env)
492 }
493 
494 /// Get capability info on a single UWB device. Return null JObject if failed.
495 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetCapsInfo( env: JNIEnv, obj: JObject, chip_id: JString, ) -> jbyteArray496 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetCapsInfo(
497     env: JNIEnv,
498     obj: JObject,
499     chip_id: JString,
500 ) -> jbyteArray {
501     debug!("{}: enter", function_name!());
502     match option_result_helper(native_get_caps_info(env, obj, chip_id), function_name!()) {
503         Some(v) => create_cap_response(v, env)
504             .map_err(|e| {
505                 error!("{} failed with {:?}", function_name!(), &e);
506                 e
507             })
508             .unwrap_or(*JObject::null()),
509         None => *JObject::null(),
510     }
511 }
512 
native_get_caps_info(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<Vec<CapTlv>>513 fn native_get_caps_info(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<Vec<CapTlv>> {
514     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
515     uci_manager.core_get_caps_info()
516 }
517 
518 /// Update multicast list on a single UWB device. Return value defined by uci_packets.pdl
519 #[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, ) -> jbyte520 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeControllerMulticastListUpdate(
521     env: JNIEnv,
522     obj: JObject,
523     session_id: jint,
524     action: jbyte,
525     no_of_controlee: jbyte,
526     addresses: jbyteArray,
527     sub_session_ids: jintArray,
528     sub_session_keys: jbyteArray,
529     chip_id: JString,
530 ) -> jbyte {
531     debug!("{}: enter", function_name!());
532     byte_result_helper(
533         native_controller_multicast_list_update(
534             env,
535             obj,
536             session_id,
537             action,
538             no_of_controlee,
539             addresses,
540             sub_session_ids,
541             sub_session_keys,
542             chip_id,
543         ),
544         function_name!(),
545     )
546 }
547 
548 // Function is used only once that copies arguments from JNI
549 #[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, ) -> Result<()>550 fn native_controller_multicast_list_update(
551     env: JNIEnv,
552     obj: JObject,
553     session_id: jint,
554     action: jbyte,
555     no_of_controlee: jbyte,
556     addresses: jbyteArray,
557     sub_session_ids: jintArray,
558     sub_session_keys: jbyteArray,
559     chip_id: JString,
560 ) -> Result<()> {
561     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
562 
563     let addresses_bytes =
564         env.convert_byte_array(addresses).map_err(|_| Error::ForeignFunctionInterface)?;
565 
566     let address_list: Vec<[u8; 2]> =
567         addresses_bytes.chunks_exact(2).map(|chunk| [chunk[0], chunk[1]]).collect();
568 
569     let mut sub_session_id_list = vec![
570         0i32;
571         env.get_array_length(sub_session_ids)
572             .map_err(|_| Error::ForeignFunctionInterface)?
573             .try_into()
574             .map_err(|_| Error::BadParameters)?
575     ];
576     env.get_int_array_region(sub_session_ids, 0, &mut sub_session_id_list)
577         .map_err(|_| Error::ForeignFunctionInterface)?;
578     if address_list.len() != sub_session_id_list.len()
579         || address_list.len() != no_of_controlee as usize
580     {
581         return Err(Error::BadParameters);
582     }
583     let controlee_list = match UpdateMulticastListAction::try_from(action as u8)
584         .map_err(|_| Error::BadParameters)?
585     {
586         UpdateMulticastListAction::AddControlee | UpdateMulticastListAction::RemoveControlee => {
587             Controlees::NoSessionKey(
588                 zip(address_list, sub_session_id_list)
589                     .map(|(a, s)| Controlee { short_address: a, subsession_id: s as u32 })
590                     .collect::<Vec<Controlee>>(),
591             )
592         }
593         UpdateMulticastListAction::AddControleeWithShortSubSessionKey => {
594             Controlees::ShortSessionKey(
595                 zip(
596                     zip(address_list, sub_session_id_list),
597                     env.convert_byte_array(sub_session_keys)
598                         .map_err(|_| Error::ForeignFunctionInterface)?
599                         .chunks(16),
600                 )
601                 .map(|((address, id), key)| {
602                     Ok(Controlee_V2_0_16_Byte_Version {
603                         short_address: address,
604                         subsession_id: id as u32,
605                         subsession_key: key.try_into().map_err(|_| Error::BadParameters)?,
606                     })
607                 })
608                 .collect::<Result<Vec<Controlee_V2_0_16_Byte_Version>>>()?,
609             )
610         }
611         UpdateMulticastListAction::AddControleeWithLongSubSessionKey => Controlees::LongSessionKey(
612             zip(
613                 zip(address_list, sub_session_id_list),
614                 env.convert_byte_array(sub_session_keys)
615                     .map_err(|_| Error::ForeignFunctionInterface)?
616                     .chunks(32),
617             )
618             .map(|((address, id), key)| {
619                 Ok(Controlee_V2_0_32_Byte_Version {
620                     short_address: address,
621                     subsession_id: id as u32,
622                     subsession_key: key.try_into().map_err(|_| Error::BadParameters)?,
623                 })
624             })
625             .collect::<Result<Vec<Controlee_V2_0_32_Byte_Version>>>()?,
626         ),
627     };
628     uci_manager.session_update_controller_multicast_list(
629         session_id as u32,
630         UpdateMulticastListAction::try_from(action as u8).map_err(|_| Error::BadParameters)?,
631         controlee_list,
632     )
633 }
634 
635 /// Set country code on a single UWB device. Return value defined by uci_packets.pdl
636 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetCountryCode( env: JNIEnv, obj: JObject, country_code: jbyteArray, chip_id: JString, ) -> jbyte637 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetCountryCode(
638     env: JNIEnv,
639     obj: JObject,
640     country_code: jbyteArray,
641     chip_id: JString,
642 ) -> jbyte {
643     debug!("{}: enter", function_name!());
644     byte_result_helper(native_set_country_code(env, obj, country_code, chip_id), function_name!())
645 }
646 
native_set_country_code( env: JNIEnv, obj: JObject, country_code: jbyteArray, chip_id: JString, ) -> Result<()>647 fn native_set_country_code(
648     env: JNIEnv,
649     obj: JObject,
650     country_code: jbyteArray,
651     chip_id: JString,
652 ) -> Result<()> {
653     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
654     let country_code =
655         env.convert_byte_array(country_code).map_err(|_| Error::ForeignFunctionInterface)?;
656     debug!("Country code: {:?}", country_code);
657     if country_code.len() != 2 {
658         return Err(Error::BadParameters);
659     }
660     uci_manager.android_set_country_code(
661         CountryCode::new(&[country_code[0], country_code[1]]).ok_or(Error::BadParameters)?,
662     )
663 }
664 
665 /// Set log mode.
666 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetLogMode( env: JNIEnv, obj: JObject, log_mode_jstring: JString, ) -> jboolean667 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetLogMode(
668     env: JNIEnv,
669     obj: JObject,
670     log_mode_jstring: JString,
671 ) -> jboolean {
672     debug!("{}: enter", function_name!());
673     boolean_result_helper(native_set_log_mode(env, obj, log_mode_jstring), function_name!())
674 }
675 
native_set_log_mode(env: JNIEnv, obj: JObject, log_mode_jstring: JString) -> Result<()>676 fn native_set_log_mode(env: JNIEnv, obj: JObject, log_mode_jstring: JString) -> Result<()> {
677     let dispatcher = Dispatcher::get_dispatcher(env, obj)?;
678     let logger_mode_str = String::from(
679         env.get_string(log_mode_jstring).map_err(|_| Error::ForeignFunctionInterface)?,
680     );
681     debug!("UCI log: log started in {} mode", &logger_mode_str);
682     let logger_mode = logger_mode_str.try_into()?;
683     dispatcher.set_logger_mode(logger_mode)
684 }
685 
686 // # Safety
687 //
688 // For this to be safe, the validity of msg should be checked before calling.
create_vendor_response(msg: RawUciMessage, env: JNIEnv) -> Result<jobject>689 unsafe fn create_vendor_response(msg: RawUciMessage, env: JNIEnv) -> Result<jobject> {
690     let vendor_response_class =
691         env.find_class(VENDOR_RESPONSE_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
692 
693     // Unsafe from_raw call
694     let payload_jobject = JObject::from_raw(
695         env.byte_array_from_slice(&msg.payload).map_err(|_| Error::ForeignFunctionInterface)?,
696     );
697 
698     match env.new_object(
699         vendor_response_class,
700         "(BII[B)V",
701         &[
702             JValue::Byte(u8::from(StatusCode::UciStatusOk) as i8),
703             JValue::Int(msg.gid as i32),
704             JValue::Int(msg.oid as i32),
705             JValue::Object(payload_jobject),
706         ],
707     ) {
708         Ok(obj) => Ok(*obj),
709         Err(_) => Err(Error::ForeignFunctionInterface),
710     }
711 }
712 
create_invalid_vendor_response(env: JNIEnv) -> Result<jobject>713 fn create_invalid_vendor_response(env: JNIEnv) -> Result<jobject> {
714     let vendor_response_class =
715         env.find_class(VENDOR_RESPONSE_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
716     match env.new_object(
717         vendor_response_class,
718         "(BII[B)V",
719         &[
720             JValue::Byte(u8::from(StatusCode::UciStatusFailed) as i8),
721             JValue::Int(-1),
722             JValue::Int(-1),
723             JValue::Object(JObject::null()),
724         ],
725     ) {
726         Ok(obj) => Ok(*obj),
727         Err(_) => Err(Error::ForeignFunctionInterface),
728     }
729 }
730 
731 /// Safety:
732 ///
733 /// response should be checked before calling to ensure safety.
create_ranging_round_status( response: SessionUpdateDtTagRangingRoundsResponse, env: JNIEnv, ) -> Result<jobject>734 unsafe fn create_ranging_round_status(
735     response: SessionUpdateDtTagRangingRoundsResponse,
736     env: JNIEnv,
737 ) -> Result<jobject> {
738     let dt_ranging_rounds_update_status_class = env
739         .find_class(DT_RANGING_ROUNDS_STATUS_CLASS)
740         .map_err(|_| Error::ForeignFunctionInterface)?;
741     let indexes = response.ranging_round_indexes;
742 
743     // Unsafe from_raw call
744     let indexes_jobject = JObject::from_raw(
745         env.byte_array_from_slice(indexes.as_ref()).map_err(|_| Error::ForeignFunctionInterface)?,
746     );
747 
748     match env.new_object(
749         dt_ranging_rounds_update_status_class,
750         "(II[B)V",
751         &[
752             JValue::Int(i32::from(response.status)),
753             JValue::Int(indexes.len() as i32),
754             JValue::Object(indexes_jobject),
755         ],
756     ) {
757         Ok(o) => Ok(*o),
758         Err(_) => Err(Error::ForeignFunctionInterface),
759     }
760 }
761 
762 /// Send Raw vendor command on a single UWB device. Returns an invalid response if failed.
763 #[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, ) -> jobject764 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSendRawVendorCmd(
765     env: JNIEnv,
766     obj: JObject,
767     mt: jint,
768     gid: jint,
769     oid: jint,
770     payload_jarray: jbyteArray,
771     chip_id: JString,
772 ) -> jobject {
773     debug!("{}: enter", function_name!());
774     match option_result_helper(
775         native_send_raw_vendor_cmd(env, obj, mt, gid, oid, payload_jarray, chip_id),
776         function_name!(),
777     ) {
778         // Note: unwrap() here is not desirable, but unavoidable given non-null object is returned
779         // even for failing cases.
780 
781         // Safety: create_vendor_response is unsafe, however msg is safely returned from
782         // native_send_raw_vendor_cmd.
783         Some(msg) => unsafe {
784             create_vendor_response(msg, env)
785                 .map_err(|e| {
786                     error!("{} failed with {:?}", function_name!(), &e);
787                     e
788                 })
789                 .unwrap_or_else(|_| create_invalid_vendor_response(env).unwrap())
790         },
791         None => create_invalid_vendor_response(env).unwrap(),
792     }
793 }
794 
native_send_raw_vendor_cmd( env: JNIEnv, obj: JObject, mt: jint, gid: jint, oid: jint, payload_jarray: jbyteArray, chip_id: JString, ) -> Result<RawUciMessage>795 fn native_send_raw_vendor_cmd(
796     env: JNIEnv,
797     obj: JObject,
798     mt: jint,
799     gid: jint,
800     oid: jint,
801     payload_jarray: jbyteArray,
802     chip_id: JString,
803 ) -> Result<RawUciMessage> {
804     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
805     let payload =
806         env.convert_byte_array(payload_jarray).map_err(|_| Error::ForeignFunctionInterface)?;
807     uci_manager.raw_uci_cmd(mt as u32, gid as u32, oid as u32, payload)
808 }
809 
create_power_stats(power_stats: PowerStats, env: JNIEnv) -> Result<jobject>810 fn create_power_stats(power_stats: PowerStats, env: JNIEnv) -> Result<jobject> {
811     let power_stats_class =
812         env.find_class(POWER_STATS_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
813     match env.new_object(
814         power_stats_class,
815         "(IIII)V",
816         &[
817             JValue::Int(power_stats.idle_time_ms as i32),
818             JValue::Int(power_stats.tx_time_ms as i32),
819             JValue::Int(power_stats.rx_time_ms as i32),
820             JValue::Int(power_stats.total_wake_count as i32),
821         ],
822     ) {
823         Ok(o) => Ok(*o),
824         Err(_) => Err(Error::ForeignFunctionInterface),
825     }
826 }
827 
828 /// Get UWB power stats on a single UWB device. Returns a null object if failed.
829 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetPowerStats( env: JNIEnv, obj: JObject, chip_id: JString, ) -> jobject830 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetPowerStats(
831     env: JNIEnv,
832     obj: JObject,
833     chip_id: JString,
834 ) -> jobject {
835     debug!("{}: enter", function_name!());
836     match option_result_helper(native_get_power_stats(env, obj, chip_id), function_name!()) {
837         Some(ps) => create_power_stats(ps, 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_power_stats(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<PowerStats>847 fn native_get_power_stats(env: JNIEnv, obj: JObject, chip_id: JString) -> Result<PowerStats> {
848     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
849     uci_manager.android_get_power_stats()
850 }
851 
852 /// Update ranging rounds for DT-TAG
853 #[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, ) -> jobject854 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionUpdateDtTagRangingRounds(
855     env: JNIEnv,
856     obj: JObject,
857     session_id: jint,
858     _ranging_rounds: jint,
859     ranging_round_indexes: jbyteArray,
860     chip_id: JString,
861 ) -> jobject {
862     debug!("{}: enter", function_name!());
863     match option_result_helper(
864         native_set_ranging_rounds_dt_tag(
865             env,
866             obj,
867             session_id as u32,
868             ranging_round_indexes,
869             chip_id,
870         ),
871         function_name!(),
872     ) {
873         // Safety: rr is safely returned from native_set_ranging_rounds_dt_tag
874         Some(rr) => unsafe {
875             create_ranging_round_status(rr, env)
876                 .map_err(|e| {
877                     error!("{} failed with {:?}", function_name!(), &e);
878                     e
879                 })
880                 .unwrap_or(*JObject::null())
881         },
882         None => *JObject::null(),
883     }
884 }
885 
native_set_ranging_rounds_dt_tag( env: JNIEnv, obj: JObject, session_id: u32, ranging_round_indexes: jbyteArray, chip_id: JString, ) -> Result<SessionUpdateDtTagRangingRoundsResponse>886 fn native_set_ranging_rounds_dt_tag(
887     env: JNIEnv,
888     obj: JObject,
889     session_id: u32,
890     ranging_round_indexes: jbyteArray,
891     chip_id: JString,
892 ) -> Result<SessionUpdateDtTagRangingRoundsResponse> {
893     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)?;
894     let indexes = env
895         .convert_byte_array(ranging_round_indexes)
896         .map_err(|_| Error::ForeignFunctionInterface)?;
897     uci_manager.session_update_dt_tag_ranging_rounds(session_id, indexes)
898 }
899 
900 /// Send a data packet to the remote device.
901 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSendData( env: JNIEnv, obj: JObject, session_id: jint, address: jbyteArray, dest_fira_component: jbyte, uci_sequence_number: jbyte, app_payload_data: jbyteArray, chip_id: JString, ) -> jbyte902 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSendData(
903     env: JNIEnv,
904     obj: JObject,
905     session_id: jint,
906     address: jbyteArray,
907     dest_fira_component: jbyte,
908     uci_sequence_number: jbyte,
909     app_payload_data: jbyteArray,
910     chip_id: JString,
911 ) -> jbyte {
912     debug!("{}: enter", function_name!());
913     byte_result_helper(
914         native_send_data(
915             env,
916             obj,
917             session_id,
918             address,
919             dest_fira_component,
920             uci_sequence_number,
921             app_payload_data,
922             chip_id,
923         ),
924         function_name!(),
925     )
926 }
927 
928 #[allow(clippy::too_many_arguments)]
native_send_data( env: JNIEnv, obj: JObject, session_id: jint, address: jbyteArray, dest_fira_component: jbyte, uci_sequence_number: jbyte, app_payload_data: jbyteArray, chip_id: JString, ) -> Result<()>929 fn native_send_data(
930     env: JNIEnv,
931     obj: JObject,
932     session_id: jint,
933     address: jbyteArray,
934     dest_fira_component: jbyte,
935     uci_sequence_number: jbyte,
936     app_payload_data: jbyteArray,
937     chip_id: JString,
938 ) -> Result<()> {
939     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)
940         .map_err(|_| Error::ForeignFunctionInterface)?;
941     let address_bytearray =
942         env.convert_byte_array(address).map_err(|_| Error::ForeignFunctionInterface)?;
943     let app_payload_data_bytearray =
944         env.convert_byte_array(app_payload_data).map_err(|_| Error::ForeignFunctionInterface)?;
945     let destination_fira_component =
946         FiraComponent::try_from(dest_fira_component as u8).map_err(|_| Error::BadParameters)?;
947     uci_manager.send_data_packet(
948         session_id as u32,
949         address_bytearray,
950         destination_fira_component,
951         uci_sequence_number as u8,
952         app_payload_data_bytearray,
953     )
954 }
955 
956 /// Get max application data size, that can be sent by the UWBS. Return 0 if failed.
957 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeQueryDataSize( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> jshort958 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeQueryDataSize(
959     env: JNIEnv,
960     obj: JObject,
961     session_id: jint,
962     chip_id: JString,
963 ) -> jshort {
964     debug!("{}: enter", function_name!());
965     match option_result_helper(
966         native_query_data_size(env, obj, session_id, chip_id),
967         function_name!(),
968     ) {
969         Some(s) => s.try_into().unwrap(),
970         None => 0,
971     }
972 }
973 
native_query_data_size( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> Result<u16>974 fn native_query_data_size(
975     env: JNIEnv,
976     obj: JObject,
977     session_id: jint,
978     chip_id: JString,
979 ) -> Result<u16> {
980     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)
981         .map_err(|_| Error::ForeignFunctionInterface)?;
982     uci_manager.session_query_max_data_size(session_id as u32)
983 }
984 
985 /// Get session token for the UWB session.
986 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionToken( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> jlong987 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionToken(
988     env: JNIEnv,
989     obj: JObject,
990     session_id: jint,
991     chip_id: JString,
992 ) -> jlong {
993     debug!("{}: enter", function_name!());
994     match option_result_helper(
995         native_get_session_token(env, obj, session_id, chip_id),
996         function_name!(),
997     ) {
998         Some(s) => s.try_into().unwrap(),
999         None => 0,
1000     }
1001 }
1002 
native_get_session_token( env: JNIEnv, obj: JObject, session_id: jint, chip_id: JString, ) -> Result<u32>1003 fn native_get_session_token(
1004     env: JNIEnv,
1005     obj: JObject,
1006     session_id: jint,
1007     chip_id: JString,
1008 ) -> Result<u32> {
1009     let uci_manager = Dispatcher::get_uci_manager(env, obj, chip_id)
1010         .map_err(|_| Error::ForeignFunctionInterface)?;
1011     uci_manager.get_session_token(session_id as u32)
1012 }
1013 
1014 /// Get the class loader object. Has to be called from a JNIEnv where the local java classes are
1015 /// loaded. Results in a global reference to the class loader object that can be used to look for
1016 /// classes in other native thread.
get_class_loader_obj(env: &JNIEnv) -> Result<GlobalRef>1017 fn get_class_loader_obj(env: &JNIEnv) -> Result<GlobalRef> {
1018     let ranging_data_class =
1019         env.find_class(UWB_RANGING_DATA_CLASS).map_err(|_| Error::ForeignFunctionInterface)?;
1020     let ranging_data_class_class =
1021         env.get_object_class(ranging_data_class).map_err(|_| Error::ForeignFunctionInterface)?;
1022     let get_class_loader_method = env
1023         .get_method_id(ranging_data_class_class, "getClassLoader", "()Ljava/lang/ClassLoader;")
1024         .map_err(|_| Error::ForeignFunctionInterface)?;
1025     let class_loader = env
1026         .call_method_unchecked(
1027             ranging_data_class,
1028             get_class_loader_method,
1029             ReturnType::Object,
1030             &[jvalue::from(JValue::Void)],
1031         )
1032         .map_err(|_| Error::ForeignFunctionInterface)?;
1033     let class_loader_jobject = class_loader.l().map_err(|_| Error::ForeignFunctionInterface)?;
1034     env.new_global_ref(class_loader_jobject).map_err(|_| Error::ForeignFunctionInterface)
1035 }
1036 
1037 /// Create the dispatcher. Returns pointer to Dispatcher casted as jlong that owns the dispatcher.
1038 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherNew( env: JNIEnv, obj: JObject, chip_ids_jarray: jobjectArray, ) -> jlong1039 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherNew(
1040     env: JNIEnv,
1041     obj: JObject,
1042     chip_ids_jarray: jobjectArray,
1043 ) -> jlong {
1044     debug!("{}: enter", function_name!());
1045     match option_result_helper(native_dispatcher_new(env, obj, chip_ids_jarray), function_name!()) {
1046         Some(ptr) => ptr as jlong,
1047         None => *JObject::null() as jlong,
1048     }
1049 }
1050 
native_dispatcher_new( env: JNIEnv, obj: JObject, chip_ids_jarray: jobjectArray, ) -> Result<*const Dispatcher>1051 fn native_dispatcher_new(
1052     env: JNIEnv,
1053     obj: JObject,
1054     chip_ids_jarray: jobjectArray,
1055 ) -> Result<*const Dispatcher> {
1056     let chip_ids_len: i32 =
1057         env.get_array_length(chip_ids_jarray).map_err(|_| Error::ForeignFunctionInterface)?;
1058     let chip_ids = (0..chip_ids_len)
1059         .map(|i| env.get_string(env.get_object_array_element(chip_ids_jarray, i)?.into()))
1060         .collect::<std::result::Result<Vec<_>, JNIError>>()
1061         .map_err(|_| Error::ForeignFunctionInterface)?;
1062     let chip_ids = chip_ids.into_iter().map(String::from).collect::<Vec<String>>();
1063     let class_loader_obj = get_class_loader_obj(&env)?;
1064     Dispatcher::new_dispatcher(
1065         unique_jvm::get_static_ref().ok_or(Error::Unknown)?,
1066         class_loader_obj,
1067         env.new_global_ref(obj).map_err(|_| Error::ForeignFunctionInterface)?,
1068         &chip_ids,
1069     )?;
1070     Dispatcher::get_dispatcher_ptr()
1071 }
1072 
1073 /// Destroys the dispatcher.
1074 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherDestroy( env: JNIEnv, obj: JObject, )1075 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherDestroy(
1076     env: JNIEnv,
1077     obj: JObject,
1078 ) {
1079     debug!("{}: enter", function_name!());
1080     if option_result_helper(native_dispatcher_destroy(env, obj), function_name!()).is_some() {
1081         debug!("The dispatcher is successfully destroyed.");
1082     }
1083 }
1084 
native_dispatcher_destroy(env: JNIEnv, obj: JObject) -> Result<()>1085 fn native_dispatcher_destroy(env: JNIEnv, obj: JObject) -> Result<()> {
1086     let dispatcher_ptr_long = env
1087         .get_field(obj, "mDispatcherPointer", "J")
1088         .map_err(|_| Error::ForeignFunctionInterface)?
1089         .j()
1090         .map_err(|_| Error::ForeignFunctionInterface)?;
1091     if Dispatcher::get_dispatcher_ptr()? as jlong == dispatcher_ptr_long {
1092         Dispatcher::destroy_dispatcher()
1093     } else {
1094         Err(Error::BadParameters)
1095     }
1096 }
1097 
1098 #[cfg(test)]
1099 mod tests {
1100     use super::*;
1101 
1102     use tokio::runtime::Builder;
1103     use uwb_core::uci::mock_uci_manager::MockUciManager;
1104     use uwb_core::uci::uci_manager_sync::{
1105         NotificationManager, NotificationManagerBuilder, UciManagerSync,
1106     };
1107     use uwb_core::uci::{CoreNotification, DataRcvNotification, SessionNotification};
1108 
1109     struct NullNotificationManager {}
1110     impl NotificationManager for NullNotificationManager {
on_core_notification(&mut self, _core_notification: CoreNotification) -> Result<()>1111         fn on_core_notification(&mut self, _core_notification: CoreNotification) -> Result<()> {
1112             Ok(())
1113         }
on_session_notification( &mut self, _session_notification: SessionNotification, ) -> Result<()>1114         fn on_session_notification(
1115             &mut self,
1116             _session_notification: SessionNotification,
1117         ) -> Result<()> {
1118             Ok(())
1119         }
on_vendor_notification(&mut self, _vendor_notification: RawUciMessage) -> Result<()>1120         fn on_vendor_notification(&mut self, _vendor_notification: RawUciMessage) -> Result<()> {
1121             Ok(())
1122         }
on_data_rcv_notification(&mut self, _data_rcv_notf: DataRcvNotification) -> Result<()>1123         fn on_data_rcv_notification(&mut self, _data_rcv_notf: DataRcvNotification) -> Result<()> {
1124             Ok(())
1125         }
1126     }
1127 
1128     struct NullNotificationManagerBuilder {}
1129 
1130     impl NullNotificationManagerBuilder {
new() -> Self1131         fn new() -> Self {
1132             Self {}
1133         }
1134     }
1135 
1136     impl NotificationManagerBuilder for NullNotificationManagerBuilder {
1137         type NotificationManager = NullNotificationManager;
1138 
build(self) -> Option<Self::NotificationManager>1139         fn build(self) -> Option<Self::NotificationManager> {
1140             Some(NullNotificationManager {})
1141         }
1142     }
1143 
1144     /// Checks validity of the function_name! macro.
1145     #[test]
test_function_name()1146     fn test_function_name() {
1147         assert_eq!(function_name!(), "test_function_name");
1148     }
1149 
1150     /// Checks native_set_app_configurations by mocking non-jni logic.
1151     #[test]
test_native_set_app_configurations()1152     fn test_native_set_app_configurations() {
1153         // Constructs mock UciManagerSync.
1154         let test_rt = Builder::new_multi_thread().enable_all().build().unwrap();
1155         let mut uci_manager_impl = MockUciManager::new();
1156         uci_manager_impl.expect_session_set_app_config(
1157             42, // Session id
1158             vec![
1159                 AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![1]),
1160                 AppConfigTlv::new(AppConfigTlvType::RangingRoundUsage, vec![1]),
1161             ],
1162             vec![],
1163             Ok(SetAppConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] }),
1164         );
1165         let uci_manager_sync = UciManagerSync::new_mock(
1166             uci_manager_impl,
1167             test_rt.handle().to_owned(),
1168             NullNotificationManagerBuilder::new(),
1169         )
1170         .unwrap();
1171 
1172         let app_config_byte_array: Vec<u8> = vec![
1173             0, 1, 1, // DeviceType: controller
1174             1, 1, 1, // RangingRoundUsage: DS_TWR
1175         ];
1176         let tlvs = parse_app_config_tlv_vec(2, &app_config_byte_array).unwrap();
1177         assert!(uci_manager_sync.session_set_app_config(42, tlvs).is_ok());
1178     }
1179 }
1180