Skip to content

Commit 432801e

Browse files
committed
fix: Propagate JNI callback failures instead of silently discarding them
Replace the deprecated `into_outcome()` pattern with jni-rs 0.22's `resolve::<ThrowRuntimeExAndDefault>()` for scan result reporting, FnAdapter call/close callbacks, and test initialization. In `adapter_on_connection_state_changed`, errors were previously swallowed with `let _ =`. Now Rust-side errors are thrown as Java RuntimeExceptions when no JNI exception is already pending.
1 parent d81b3b4 commit 432801e

3 files changed

Lines changed: 24 additions & 24 deletions

File tree

src/droidplug/jni/mod.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub mod objects;
22

33
use ::jni::{Env, EnvUnowned, NativeMethod, jni_str, native_method, objects::{JObject, Reference}};
4+
use ::jni::errors::ThrowRuntimeExAndDefault;
45
use jni::{objects::JString, sys::jboolean};
56
use std::ffi::c_void;
67
use std::sync::Once;
@@ -105,11 +106,8 @@ extern "C" fn adapter_report_scan_result<'local>(
105106
obj: JObject<'local>,
106107
scan_result: JObject<'local>,
107108
) {
108-
let outcome = env.with_env(|env| {
109-
let _ = super::adapter::adapter_report_scan_result_internal(env, &obj, scan_result);
110-
Ok::<_, jni::errors::Error>(())
111-
});
112-
let _ = outcome.into_outcome();
109+
env.with_env(|env| super::adapter::adapter_report_scan_result_internal(env, &obj, scan_result))
110+
.resolve::<ThrowRuntimeExAndDefault>();
113111
}
114112

115113
fn adapter_on_connection_state_changed<'local>(
@@ -118,6 +116,12 @@ fn adapter_on_connection_state_changed<'local>(
118116
addr: JString<'local>,
119117
connected: jboolean,
120118
) -> jni::errors::Result<()> {
121-
let _ = super::adapter::adapter_on_connection_state_changed_internal(env, &obj, addr, connected);
119+
if let Err(e) =
120+
super::adapter::adapter_on_connection_state_changed_internal(env, &obj, addr, connected)
121+
{
122+
if !env.exception_check() {
123+
let _ = env.throw(format!("Rust error: {e}"));
124+
}
125+
}
122126
Ok(())
123127
}

src/droidplug/jni_utils/ops.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use ::jni::{
55
jni_sig, jni_str,
66
objects::{JObject, Reference},
77
};
8+
use ::jni::errors::ThrowRuntimeExAndDefault;
89
use std::sync::{Arc, Mutex};
910

1011
bind_java_type! {
@@ -313,7 +314,7 @@ pub(crate) extern "C" fn fn_adapter_call_internal<'local>(
313314
) -> JObject<'local> {
314315
use std::panic::{AssertUnwindSafe, catch_unwind};
315316

316-
let outcome = env.with_env(|env| -> std::result::Result<JObject<'local>, jni::errors::Error> {
317+
env.with_env(|env| -> std::result::Result<JObject<'local>, jni::errors::Error> {
317318
let arc =
318319
if let Ok(f) = unsafe { env.get_rust_field::<_, _, FnWrapper>(&obj1, jni_str!("data")) } {
319320
AssertUnwindSafe(f.0.clone())
@@ -327,24 +328,21 @@ pub(crate) extern "C" fn fn_adapter_call_internal<'local>(
327328
Ok(JObject::null())
328329
}
329330
}
330-
});
331-
match outcome.into_outcome() {
332-
jni::Outcome::Ok(obj) => obj,
333-
_ => JObject::null(),
334-
}
331+
})
332+
.resolve::<ThrowRuntimeExAndDefault>()
335333
}
336334

337335
pub(crate) extern "C" fn fn_adapter_close_internal(mut env: EnvUnowned, obj: JObject) {
338336
use std::panic::{AssertUnwindSafe, catch_unwind};
339337

340-
let outcome = env.with_env(|env| {
338+
env.with_env(|env| {
341339
let result = catch_unwind(AssertUnwindSafe(|| {
342340
let _ = unsafe { env.take_rust_field::<_, _, FnWrapper>(&obj, jni_str!("data")) };
343341
}));
344342
if let Err(panic) = result {
345-
let _ = super::exceptions::throw_panic(env, panic);
343+
super::exceptions::throw_panic(env, panic)?;
346344
}
347345
Ok::<(), jni::errors::Error>(())
348-
});
349-
let _ = outcome.into_outcome();
346+
})
347+
.resolve::<ThrowRuntimeExAndDefault>();
350348
}

tests/android/rust/src/lib.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub fn find_descriptor(
4242

4343
use jni::objects::JClass;
4444
use jni::{Env, EnvUnowned, jni_str};
45+
use jni::errors::ThrowRuntimeExAndDefault;
4546
use std::sync::OnceLock;
4647
use tokio::runtime::Runtime;
4748

@@ -95,11 +96,8 @@ pub extern "system" fn Java_com_nonpolynomial_btleplug_test_NativeTests_initBtle
9596
.with_max_level(log::LevelFilter::Debug)
9697
.with_tag("btleplug-test"),
9798
);
98-
let outcome = env.with_env(|env| {
99-
btleplug::platform::init(env).expect("failed to initialize btleplug");
100-
Ok::<_, jni::errors::Error>(())
101-
});
102-
let _ = outcome.into_outcome();
99+
env.with_env(|env| btleplug::platform::init(env))
100+
.resolve::<ThrowRuntimeExAndDefault>();
103101
}
104102

105103
// ── Test JNI exports ────────────────────────────────────────────────
@@ -111,11 +109,11 @@ macro_rules! jni_test {
111109
($jni_name:ident, $test_fn:path) => {
112110
#[unsafe(no_mangle)]
113111
pub extern "system" fn $jni_name(mut env: EnvUnowned, _class: JClass) {
114-
let outcome = env.with_env(|env| {
112+
env.with_env(|env| {
115113
run_test(env, stringify!($test_fn), $test_fn());
116114
Ok::<_, jni::errors::Error>(())
117-
});
118-
let _ = outcome.into_outcome();
115+
})
116+
.resolve::<ThrowRuntimeExAndDefault>();
119117
}
120118
};
121119
}

0 commit comments

Comments
 (0)