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