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