Skip to content

Commit 1b41573

Browse files
committed
Update to jni 0.22 and jni-sys 0.4
1 parent 984b62d commit 1b41573

File tree

8 files changed

+228
-234
lines changed

8 files changed

+228
-234
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ resolver = "2"
33
members = ["android-activity"]
44

55
exclude = ["examples"]
6+
7+
[patch.crates-io]
8+
jni = { path = "/home/rib/src/jni-rs/jni-git-dev0" }

android-activity/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ api-level-30 = ["ndk/api-level-30"]
3535

3636
[dependencies]
3737
log = "0.4"
38-
jni-sys = "0.3"
3938
cesu8 = "1"
4039
jni = "0.21"
4140
ndk-sys = "0.6.0"

android-activity/src/game_activity/ffi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#![allow(deref_nullptr)]
1313
#![allow(dead_code)]
1414

15-
use jni_sys::*;
15+
use jni::sys::*;
1616
use libc::{pthread_cond_t, pthread_mutex_t, pthread_t};
1717
use ndk_sys::{AAssetManager, AConfiguration, ALooper, ALooper_callbackFunc, ANativeWindow, ARect};
1818

android-activity/src/game_activity/mod.rs

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::time::Duration;
1313
use libc::c_void;
1414
use log::{error, trace};
1515

16-
use jni_sys::*;
16+
use jni::sys::*;
1717

1818
use ndk_sys::ALooper_wake;
1919
use ndk_sys::{ALooper, ALooper_pollAll};
@@ -24,7 +24,7 @@ use ndk::native_window::NativeWindow;
2424

2525
use crate::error::InternalResult;
2626
use crate::input::{Axis, KeyCharacterMap, KeyCharacterMapBinding};
27-
use crate::jni_utils::{self, CloneJavaVM};
27+
use crate::jni_utils;
2828
use crate::util::{abort_on_panic, forward_stdio_to_logcat, log_panic, try_get_path_from_ptr};
2929
use crate::{
3030
AndroidApp, ConfigurationRef, InputStatus, MainEvent, PollEvent, Rect, WindowManagerFlags,
@@ -121,32 +121,35 @@ impl AndroidAppWaker {
121121
}
122122

123123
impl AndroidApp {
124-
pub(crate) unsafe fn from_ptr(ptr: NonNull<ffi::android_app>, jvm: CloneJavaVM) -> Self {
125-
let mut env = jvm.get_env().unwrap(); // We attach to the thread before creating the AndroidApp
126-
127-
let key_map_binding = match KeyCharacterMapBinding::new(&mut env) {
128-
Ok(b) => b,
129-
Err(err) => {
130-
panic!("Failed to create KeyCharacterMap JNI bindings: {err:?}");
131-
}
132-
};
133-
134-
// Note: we don't use from_ptr since we don't own the android_app.config
135-
// and need to keep in mind that the Drop handler is going to call
136-
// AConfiguration_delete()
137-
let config = Configuration::clone_from_ptr(NonNull::new_unchecked((*ptr.as_ptr()).config));
124+
pub(crate) unsafe fn from_ptr(ptr: NonNull<ffi::android_app>, jvm: jni::JavaVM) -> Self {
125+
// We attach to the thread before creating the AndroidApp
126+
jni::JavaVM::with_env::<_, _, jni::errors::Error>(|env| {
127+
let key_map_binding = match KeyCharacterMapBinding::new(env) {
128+
Ok(b) => b,
129+
Err(err) => {
130+
panic!("Failed to create KeyCharacterMap JNI bindings: {err:?}");
131+
}
132+
};
138133

139-
Self {
140-
inner: Arc::new(RwLock::new(AndroidAppInner {
141-
jvm,
142-
native_app: NativeAppGlue { ptr },
143-
config: ConfigurationRef::new(config),
144-
native_window: Default::default(),
145-
key_map_binding: Arc::new(key_map_binding),
146-
key_maps: Mutex::new(HashMap::new()),
147-
input_receiver: Mutex::new(None),
148-
})),
149-
}
134+
// Note: we don't use from_ptr since we don't own the android_app.config
135+
// and need to keep in mind that the Drop handler is going to call
136+
// AConfiguration_delete()
137+
let config =
138+
Configuration::clone_from_ptr(NonNull::new_unchecked((*ptr.as_ptr()).config));
139+
140+
Ok(Self {
141+
inner: Arc::new(RwLock::new(AndroidAppInner {
142+
jvm,
143+
native_app: NativeAppGlue { ptr },
144+
config: ConfigurationRef::new(config),
145+
native_window: Default::default(),
146+
key_map_binding: Arc::new(key_map_binding),
147+
key_maps: Mutex::new(HashMap::new()),
148+
input_receiver: Mutex::new(None),
149+
})),
150+
})
151+
})
152+
.expect("Failed to create AndroidApp instance")
150153
}
151154
}
152155

@@ -253,7 +256,7 @@ impl NativeAppGlue {
253256

254257
#[derive(Debug)]
255258
pub struct AndroidAppInner {
256-
pub(crate) jvm: CloneJavaVM,
259+
pub(crate) jvm: jni::JavaVM,
257260
native_app: NativeAppGlue,
258261
config: ConfigurationRef,
259262
native_window: RwLock<Option<NativeWindow>>,
@@ -875,7 +878,7 @@ pub unsafe extern "C" fn Java_com_google_androidgamesdk_GameActivity_initializeN
875878
jasset_mgr: jobject,
876879
saved_state: jbyteArray,
877880
java_config: jobject,
878-
) -> jni_sys::jlong {
881+
) -> jlong {
879882
Java_com_google_androidgamesdk_GameActivity_initializeNativeCode_C(
880883
env,
881884
java_game_activity,
@@ -914,11 +917,17 @@ pub unsafe extern "C" fn _rust_glue_entry(native_app: *mut ffi::android_app) {
914917
let activity: jobject = (*(*native_app).activity).javaGameActivity;
915918
ndk_context::initialize_android_context(jvm.cast(), activity.cast());
916919

917-
let jvm = CloneJavaVM::from_raw(jvm).unwrap();
918-
// Since this is a newly spawned thread then the JVM hasn't been attached
919-
// to the thread yet. Attach before calling the applications main function
920-
// so they can safely make JNI calls
921-
jvm.attach_current_thread_permanently().unwrap();
920+
let jvm = jni::JavaVM::from_raw(jvm);
921+
// Since this is a newly spawned thread then the JVM hasn't been attached to the
922+
// thread yet.
923+
//
924+
// For compatibility we attach before calling the applications main function to
925+
// allow it to assume the thread is attached before making JNI calls.
926+
jvm.attach_current_thread::<_, _, jni::errors::Error>(
927+
jni::JNIVersion::V1_4,
928+
|_| Ok(()),
929+
)
930+
.expect("Failed to attach thread to JVM");
922931
jvm
923932
};
924933

@@ -953,7 +962,11 @@ pub unsafe extern "C" fn _rust_glue_entry(native_app: *mut ffi::android_app) {
953962

954963
// This should detach automatically but lets detach explicitly to avoid depending
955964
// on the TLS trickery in `jni-rs`
956-
jvm.detach_current_thread();
965+
if let Err(err) = jvm.detach_current_thread() {
966+
log::error!("Failed to detach thread from JVM: {}", err);
967+
} else {
968+
log::debug!("Detached thread from JVM");
969+
}
957970

958971
ndk_context::release_android_context();
959972
}

android-activity/src/input/sdk.rs

Lines changed: 76 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
use std::sync::Arc;
22

3+
use jni::sys::jint;
34
use jni::{
45
objects::{GlobalRef, JClass, JMethodID, JObject, JStaticMethodID, JValue},
56
signature::{Primitive, ReturnType},
6-
JNIEnv,
7+
JNIEnv, JNIVersion, JavaVM,
78
};
8-
use jni_sys::jint;
99

10-
use crate::{
11-
input::{Keycode, MetaState},
12-
jni_utils::CloneJavaVM,
13-
};
10+
use crate::input::{Keycode, MetaState};
1411

1512
use crate::{
1613
error::{AppError, InternalAppError},
@@ -94,7 +91,7 @@ pub enum KeyMapChar {
9491
#[derive(Debug)]
9592
pub(crate) struct KeyCharacterMapBinding {
9693
//vm: JavaVM,
97-
klass: GlobalRef,
94+
klass: GlobalRef<JClass<'static>>,
9895
get_method_id: JMethodID,
9996
get_dead_char_method_id: JStaticMethodID,
10097
get_keyboard_type_method_id: JMethodID,
@@ -213,18 +210,31 @@ impl KeyCharacterMapBinding {
213210
}
214211

215212
/// Describes the keys provided by a keyboard device and their associated labels.
216-
#[derive(Clone, Debug)]
213+
#[derive(Debug)]
217214
pub struct KeyCharacterMap {
218-
jvm: CloneJavaVM,
215+
jvm: JavaVM,
219216
binding: Arc<KeyCharacterMapBinding>,
220-
key_map: GlobalRef,
217+
key_map: GlobalRef<JObject<'static>>,
218+
}
219+
impl Clone for KeyCharacterMap {
220+
fn clone(&self) -> Self {
221+
let jvm = self.jvm.clone();
222+
jvm.attach_current_thread::<_, _, jni::errors::Error>(JNIVersion::V1_4, |env| {
223+
Ok(Self {
224+
jvm: jvm.clone(),
225+
binding: Arc::clone(&self.binding),
226+
key_map: env.new_global_ref(&self.key_map)?,
227+
})
228+
})
229+
.expect("Failed to attach thread to JVM and clone key map")
230+
}
221231
}
222232

223233
impl KeyCharacterMap {
224234
pub(crate) fn new(
225-
jvm: CloneJavaVM,
235+
jvm: JavaVM,
226236
binding: Arc<KeyCharacterMapBinding>,
227-
key_map: GlobalRef,
237+
key_map: GlobalRef<JObject<'static>>,
228238
) -> Self {
229239
Self {
230240
jvm,
@@ -247,41 +257,39 @@ impl KeyCharacterMap {
247257
/// is caught.
248258
pub fn get(&self, key_code: Keycode, meta_state: MetaState) -> Result<KeyMapChar, AppError> {
249259
let key_code: u32 = key_code.into();
250-
let key_code = key_code as jni_sys::jint;
260+
let key_code = key_code as jni::sys::jint;
251261
let meta_state: u32 = meta_state.0;
252-
let meta_state = meta_state as jni_sys::jint;
262+
let meta_state = meta_state as jni::sys::jint;
253263

254-
// Since we expect this API to be called from the `main` thread then we expect to already be
255-
// attached to the JVM
256-
//
257-
// Safety: there's no other JNIEnv in scope so this env can't be used to subvert the mutable
258-
// borrow rules that ensure we can only add local references to the top JNI frame.
259-
let mut env = self.jvm.get_env().map_err(|err| {
260-
let err: InternalAppError = err.into();
261-
err
262-
})?;
263-
let unicode = self
264-
.binding
265-
.get(&mut env, self.key_map.as_obj(), key_code, meta_state)?;
266-
let unicode = unicode as u32;
264+
let vm = self.jvm.clone();
265+
vm.attach_current_thread::<_, _, InternalAppError>(JNIVersion::V1_4, |env| {
266+
let unicode = self
267+
.binding
268+
.get(env, self.key_map.as_obj(), key_code, meta_state)?;
269+
let unicode = unicode as u32;
267270

268-
const COMBINING_ACCENT: u32 = 0x80000000;
269-
const COMBINING_ACCENT_MASK: u32 = !COMBINING_ACCENT;
271+
const COMBINING_ACCENT: u32 = 0x80000000;
272+
const COMBINING_ACCENT_MASK: u32 = !COMBINING_ACCENT;
270273

271-
if unicode == 0 {
272-
Ok(KeyMapChar::None)
273-
} else if unicode & COMBINING_ACCENT == COMBINING_ACCENT {
274-
let accent = unicode & COMBINING_ACCENT_MASK;
275-
// Safety: assumes Android key maps don't contain invalid unicode characters
276-
Ok(KeyMapChar::CombiningAccent(unsafe {
277-
char::from_u32_unchecked(accent)
278-
}))
279-
} else {
280-
// Safety: assumes Android key maps don't contain invalid unicode characters
281-
Ok(KeyMapChar::Unicode(unsafe {
282-
char::from_u32_unchecked(unicode)
283-
}))
284-
}
274+
if unicode == 0 {
275+
Ok(KeyMapChar::None)
276+
} else if unicode & COMBINING_ACCENT == COMBINING_ACCENT {
277+
let accent = unicode & COMBINING_ACCENT_MASK;
278+
// Safety: assumes Android key maps don't contain invalid unicode characters
279+
Ok(KeyMapChar::CombiningAccent(unsafe {
280+
char::from_u32_unchecked(accent)
281+
}))
282+
} else {
283+
// Safety: assumes Android key maps don't contain invalid unicode characters
284+
Ok(KeyMapChar::Unicode(unsafe {
285+
char::from_u32_unchecked(unicode)
286+
}))
287+
}
288+
})
289+
.map_err(|err| {
290+
let err: InternalAppError = err.into();
291+
err.into()
292+
})
285293
}
286294

287295
/// Get the character that is produced by combining the dead key producing accent with the key producing character c.
@@ -297,28 +305,24 @@ impl KeyCharacterMap {
297305
accent_char: char,
298306
base_char: char,
299307
) -> Result<Option<char>, AppError> {
300-
let accent_char = accent_char as jni_sys::jint;
301-
let base_char = base_char as jni_sys::jint;
308+
let accent_char = accent_char as jni::sys::jint;
309+
let base_char = base_char as jni::sys::jint;
302310

303-
// Since we expect this API to be called from the `main` thread then we expect to already be
304-
// attached to the JVM
305-
//
306-
// Safety: there's no other JNIEnv in scope so this env can't be used to subvert the mutable
307-
// borrow rules that ensure we can only add local references to the top JNI frame.
308-
let mut env = self.jvm.get_env().map_err(|err| {
309-
let err: InternalAppError = err.into();
310-
err
311-
})?;
312-
let unicode = self
313-
.binding
314-
.get_dead_char(&mut env, accent_char, base_char)?;
315-
let unicode = unicode as u32;
311+
let vm = self.jvm.clone();
312+
vm.attach_current_thread::<_, _, InternalAppError>(JNIVersion::V1_4, |env| {
313+
let unicode = self.binding.get_dead_char(env, accent_char, base_char)?;
314+
let unicode = unicode as u32;
316315

317-
// Safety: assumes Android key maps don't contain invalid unicode characters
318-
Ok(if unicode == 0 {
319-
None
320-
} else {
321-
Some(unsafe { char::from_u32_unchecked(unicode) })
316+
// Safety: assumes Android key maps don't contain invalid unicode characters
317+
Ok(if unicode == 0 {
318+
None
319+
} else {
320+
Some(unsafe { char::from_u32_unchecked(unicode) })
321+
})
322+
})
323+
.map_err(|err| {
324+
let err: InternalAppError = err.into();
325+
err.into()
322326
})
323327
}
324328

@@ -332,19 +336,15 @@ impl KeyCharacterMap {
332336
/// a [`AppError::JavaError`] in case there is a spurious JNI error or an exception
333337
/// is caught.
334338
pub fn get_keyboard_type(&self) -> Result<KeyboardType, AppError> {
335-
// Since we expect this API to be called from the `main` thread then we expect to already be
336-
// attached to the JVM
337-
//
338-
// Safety: there's no other JNIEnv in scope so this env can't be used to subvert the mutable
339-
// borrow rules that ensure we can only add local references to the top JNI frame.
340-
let mut env = self.jvm.get_env().map_err(|err| {
339+
let vm = self.jvm.clone();
340+
vm.attach_current_thread::<_, _, InternalAppError>(JNIVersion::V1_4, |env| {
341+
let keyboard_type = self.binding.get_keyboard_type(env, self.key_map.as_obj())?;
342+
let keyboard_type = keyboard_type as u32;
343+
Ok(keyboard_type.into())
344+
})
345+
.map_err(|err| {
341346
let err: InternalAppError = err.into();
342-
err
343-
})?;
344-
let keyboard_type = self
345-
.binding
346-
.get_keyboard_type(&mut env, self.key_map.as_obj())?;
347-
let keyboard_type = keyboard_type as u32;
348-
Ok(keyboard_type.into())
347+
err.into()
348+
})
349349
}
350350
}

0 commit comments

Comments
 (0)