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