@@ -8,10 +8,12 @@ use std::sync::Weak;
88use std:: sync:: { Arc , Mutex , RwLock } ;
99use std:: time:: Duration ;
1010
11+ use jni:: objects:: JObject ;
12+ use jni:: refs:: Global ;
1113use libc:: c_void;
1214use log:: { error, trace} ;
1315
14- use jni_sys :: * ;
16+ use jni :: sys :: * ;
1517
1618use ndk_sys:: ALooper_wake ;
1719use ndk_sys:: { ALooper , ALooper_pollAll } ;
@@ -21,9 +23,11 @@ use ndk::configuration::Configuration;
2123use ndk:: native_window:: NativeWindow ;
2224
2325use crate :: error:: InternalResult ;
24- use crate :: input:: { Axis , KeyCharacterMap , KeyCharacterMapBinding } ;
25- use crate :: jni_utils:: { self , CloneJavaVM } ;
26- use crate :: util:: { abort_on_panic, forward_stdio_to_logcat, log_panic, try_get_path_from_ptr} ;
26+ use crate :: input:: { device_key_character_map, Axis , KeyCharacterMap } ;
27+ use crate :: util:: {
28+ abort_on_panic, forward_stdio_to_logcat, init_android_main_thread, log_panic,
29+ try_get_path_from_ptr,
30+ } ;
2731use crate :: {
2832 AndroidApp , ConfigurationRef , InputStatus , MainEvent , PollEvent , Rect , WindowManagerFlags ,
2933} ;
@@ -119,32 +123,31 @@ impl AndroidAppWaker {
119123}
120124
121125impl AndroidApp {
122- pub ( crate ) unsafe fn from_ptr ( ptr : NonNull < ffi:: android_app > , jvm : CloneJavaVM ) -> Self {
123- let mut env = jvm. get_env ( ) . unwrap ( ) ; // We attach to the thread before creating the AndroidApp
124-
125- let key_map_binding = match KeyCharacterMapBinding :: new ( & mut env) {
126- Ok ( b) => b,
127- Err ( err) => {
128- panic ! ( "Failed to create KeyCharacterMap JNI bindings: {err:?}" ) ;
129- }
130- } ;
131-
132- // Note: we don't use from_ptr since we don't own the android_app.config
133- // and need to keep in mind that the Drop handler is going to call
134- // AConfiguration_delete()
135- let config = Configuration :: clone_from_ptr ( NonNull :: new_unchecked ( ( * ptr. as_ptr ( ) ) . config ) ) ;
126+ pub ( crate ) unsafe fn from_ptr ( ptr : NonNull < ffi:: android_app > , jvm : jni:: JavaVM ) -> Self {
127+ // We attach to the thread before creating the AndroidApp
128+ jvm. with_local_frame ( 10 , |env| -> jni:: errors:: Result < _ > {
129+ if let Err ( err) = crate :: input:: jni_init ( env) {
130+ panic ! ( "Failed to init JNI bindings: {err:?}" ) ;
131+ } ;
136132
137- Self {
138- inner : Arc :: new ( RwLock :: new ( AndroidAppInner {
139- jvm,
140- native_app : NativeAppGlue { ptr } ,
141- config : ConfigurationRef :: new ( config) ,
142- native_window : Default :: default ( ) ,
143- key_map_binding : Arc :: new ( key_map_binding) ,
144- key_maps : Mutex :: new ( HashMap :: new ( ) ) ,
145- input_receiver : Mutex :: new ( None ) ,
146- } ) ) ,
147- }
133+ // Note: we don't use from_ptr since we don't own the android_app.config
134+ // and need to keep in mind that the Drop handler is going to call
135+ // AConfiguration_delete()
136+ let config =
137+ Configuration :: clone_from_ptr ( NonNull :: new_unchecked ( ( * ptr. as_ptr ( ) ) . config ) ) ;
138+
139+ Ok ( Self {
140+ inner : Arc :: new ( RwLock :: new ( AndroidAppInner {
141+ jvm : jvm. clone ( ) ,
142+ native_app : NativeAppGlue { ptr } ,
143+ config : ConfigurationRef :: new ( config) ,
144+ native_window : Default :: default ( ) ,
145+ key_maps : Mutex :: new ( HashMap :: new ( ) ) ,
146+ input_receiver : Mutex :: new ( None ) ,
147+ } ) ) ,
148+ } )
149+ } )
150+ . expect ( "Failed to create AndroidApp instance" )
148151 }
149152}
150153
@@ -251,14 +254,11 @@ impl NativeAppGlue {
251254
252255#[ derive( Debug ) ]
253256pub struct AndroidAppInner {
254- pub ( crate ) jvm : CloneJavaVM ,
257+ pub ( crate ) jvm : jni :: JavaVM ,
255258 native_app : NativeAppGlue ,
256259 config : ConfigurationRef ,
257260 native_window : RwLock < Option < NativeWindow > > ,
258261
259- /// Shared JNI bindings for the `KeyCharacterMap` class
260- key_map_binding : Arc < KeyCharacterMapBinding > ,
261-
262262 /// A table of `KeyCharacterMap`s per `InputDevice` ID
263263 /// these are used to be able to map key presses to unicode
264264 /// characters
@@ -533,11 +533,7 @@ impl AndroidAppInner {
533533 let key_map = match guard. entry ( device_id) {
534534 std:: collections:: hash_map:: Entry :: Occupied ( occupied) => occupied. get ( ) . clone ( ) ,
535535 std:: collections:: hash_map:: Entry :: Vacant ( vacant) => {
536- let character_map = jni_utils:: device_key_character_map (
537- self . jvm . clone ( ) ,
538- self . key_map_binding . clone ( ) ,
539- device_id,
540- ) ?;
536+ let character_map = device_key_character_map ( self . jvm . clone ( ) , device_id) ?;
541537 vacant. insert ( character_map. clone ( ) ) ;
542538 character_map
543539 }
@@ -876,7 +872,7 @@ pub unsafe extern "C" fn Java_com_google_androidgamesdk_GameActivity_initializeN
876872 jasset_mgr : jobject ,
877873 saved_state : jbyteArray ,
878874 java_config : jobject ,
879- ) -> jni_sys :: jlong {
875+ ) -> jlong {
880876 Java_com_google_androidgamesdk_GameActivity_initializeNativeCode_C (
881877 env,
882878 java_game_activity,
@@ -910,53 +906,56 @@ pub unsafe extern "C" fn _rust_glue_entry(native_app: *mut ffi::android_app) {
910906 abort_on_panic ( || {
911907 let _join_log_forwarder = forward_stdio_to_logcat ( ) ;
912908
913- let jvm = unsafe {
909+ let ( jvm, jni_activity ) = unsafe {
914910 let jvm = ( * ( * native_app) . activity ) . vm ;
915911 let activity: jobject = ( * ( * native_app) . activity ) . javaGameActivity ;
916912 ndk_context:: initialize_android_context ( jvm. cast ( ) , activity. cast ( ) ) ;
917-
918- let jvm = CloneJavaVM :: from_raw ( jvm) . unwrap ( ) ;
919- // Since this is a newly spawned thread then the JVM hasn't been attached
920- // to the thread yet. Attach before calling the applications main function
921- // so they can safely make JNI calls
922- jvm. attach_current_thread_permanently ( ) . unwrap ( ) ;
923- jvm
913+ ( jni:: JavaVM :: from_raw ( jvm) , activity)
924914 } ;
915+ // Note: At this point we can assume jni::JavaVM::singleton is initialized
916+
917+ // Note: the GameActivity implementation will have already attached the main thread to the
918+ // JVM before calling _rust_glue_entry so we don't to set the thread name via
919+ // attach_current_thread_with_config since that won't actually create a new attachment.
920+ //
921+ // Calling .attach_current_thread will ensure that the `jni` crate knows about the
922+ // attachment, as a convenience.
923+ jvm. attach_current_thread ( |env| -> jni:: errors:: Result < ( ) > {
924+ // SAFETY: We know jni_activity is a valid JNI global ref to an Activity instance
925+ let jni_activity = unsafe { env. as_cast_raw :: < Global < JObject > > ( & jni_activity) ? } ;
926+
927+ if let Err ( err) = init_android_main_thread ( & jvm, & jni_activity) {
928+ eprintln ! ( "Failed to name Java thread and set thread context class loader: {err}" ) ;
929+ }
925930
926- unsafe {
927- // Name thread - this needs to happen here after attaching to a JVM thread,
928- // since that changes the thread name to something like "Thread-2".
929- let thread_name = std:: ffi:: CStr :: from_bytes_with_nul ( b"android_main\0 " ) . unwrap ( ) ;
930- libc:: pthread_setname_np ( libc:: pthread_self ( ) , thread_name. as_ptr ( ) ) ;
931-
932- let app = AndroidApp :: from_ptr ( NonNull :: new ( native_app) . unwrap ( ) , jvm. clone ( ) ) ;
933-
934- // We want to specifically catch any panic from the application's android_main
935- // so we can finish + destroy the Activity gracefully via the JVM
936- catch_unwind ( || {
937- // XXX: If we were in control of the Java Activity subclass then
938- // we could potentially run the android_main function via a Java native method
939- // springboard (e.g. call an Activity subclass method that calls a jni native
940- // method that then just calls android_main()) that would make sure there was
941- // a Java frame at the base of our call stack which would then be recognised
942- // when calling FindClass to lookup a suitable classLoader, instead of
943- // defaulting to the system loader. Without this then it's difficult for native
944- // code to look up non-standard Java classes.
945- android_main ( app) ;
946- } )
947- . unwrap_or_else ( log_panic) ;
948-
949- // Let JVM know that our Activity can be destroyed before detaching from the JVM
950- //
951- // "Note that this method can be called from any thread; it will send a message
952- // to the main thread of the process where the Java finish call will take place"
953- ffi:: GameActivity_finish ( ( * native_app) . activity ) ;
931+ unsafe {
932+ let app = AndroidApp :: from_ptr ( NonNull :: new ( native_app) . unwrap ( ) , jvm. clone ( ) ) ;
933+ // We want to specifically catch any panic from the application's android_main
934+ // so we can finish + destroy the Activity gracefully via the JVM
935+ catch_unwind ( || {
936+ // XXX: If we were in control of the Java Activity subclass then
937+ // we could potentially run the android_main function via a Java native method
938+ // springboard (e.g. call an Activity subclass method that calls a jni native
939+ // method that then just calls android_main()) that would make sure there was
940+ // a Java frame at the base of our call stack which would then be recognised
941+ // when calling FindClass to lookup a suitable classLoader, instead of
942+ // defaulting to the system loader. Without this then it's difficult for native
943+ // code to look up non-standard Java classes.
944+ android_main ( app) ;
945+ } )
946+ . unwrap_or_else ( log_panic) ;
947+
948+ // Let JVM know that our Activity can be destroyed before detaching from the JVM
949+ //
950+ // "Note that this method can be called from any thread; it will send a message
951+ // to the main thread of the process where the Java finish call will take place"
952+ ffi:: GameActivity_finish ( ( * native_app) . activity ) ;
954953
955- // This should detach automatically but lets detach explicitly to avoid depending
956- // on the TLS trickery in `jni-rs`
957- jvm. detach_current_thread ( ) ;
954+ ndk_context:: release_android_context ( ) ;
955+ }
958956
959- ndk_context:: release_android_context ( ) ;
960- }
957+ Ok ( ( ) )
958+ } )
959+ . expect ( "Failed to attach thread to JVM" ) ;
961960 } )
962961}
0 commit comments